@fortawesome/free-solid-svg-icons#faPlus TypeScript Examples
The following examples show how to use
@fortawesome/free-solid-svg-icons#faPlus.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.tsx From bad-cards-game with GNU Affero General Public License v3.0 | 6 votes |
library.add( faDotCircle, faCircle, faBars, faTimes, faInfoCircle, faTrophy, faShareSquare, faHeart, faInstagram, faTwitter, faGithub, faFacebook, faHandPointRight, faEdit, faSave, faCamera, faPlus, faMinus, faRandom, );
Example #2
Source File: ComponentsPanel.tsx From MagicUI with Apache License 2.0 | 6 votes |
function NewPageButton(props: { onClick: () => void }) {
return (
<div className={style.new_page_button} onClick={props.onClick}>
<button>
<FontAwesomeIcon icon={faPlus}/>
</button>
</div>
);
}
Example #3
Source File: AddTask.tsx From knboard with MIT License | 6 votes |
AddTask = ({ columnId, index }: Props) => {
const dispatch = useDispatch();
const handleOnClick = () => {
dispatch(setCreateDialogColumn(columnId));
dispatch(setCreateDialogOpen(true));
};
return (
<Button
css={css`
text-transform: inherit;
color: ${N80A};
padding: 4px 0;
margin-top: 6px;
margin-bottom: 6px;
&:hover {
color: ${N900};
}
&:focus {
outline: 2px solid #aaa;
}
.MuiButton-iconSizeMedium > *:first-of-type {
font-size: 12px;
}
`}
startIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={handleOnClick}
fullWidth
>
Add card
</Button>
);
}
Example #4
Source File: shared.module.ts From enterprise-ng-2020-workshop with MIT License | 6 votes |
constructor(faIconLibrary: FaIconLibrary) {
faIconLibrary.addIcons(
faGithub,
faMediumM,
faPlus,
faEdit,
faTrash,
faTimes,
faCaretUp,
faCaretDown,
faExclamationTriangle,
faFilter,
faTasks,
faCheck,
faSquare,
faLanguage,
faPaintBrush,
faLightbulb,
faWindowMaximize,
faStream,
faBook
);
}
Example #5
Source File: index.tsx From genshin-optimizer with MIT License | 6 votes |
function NewArtifactCard() {
const [show, setshow] = useState(false)
const onShow = useCallback(() => setshow(true), [setshow])
const onHide = useCallback(() => setshow(false), [setshow])
return <CardDark sx={{ height: "100%", width: "100%", minHeight: 300, display: "flex", flexDirection: "column" }}>
<Suspense fallback={false}><ArtifactEditor
artifactIdToEdit={show ? "new" : ""}
cancelEdit={onHide}
allowUpload
allowEmpty
/></Suspense>
<CardContent>
<Typography sx={{ textAlign: "center" }}>Add New Artifact</Typography>
</CardContent>
<Box sx={{
flexGrow: 1,
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<Button onClick={onShow} color="info" sx={{ borderRadius: "1em" }}>
<Typography variant="h1"><FontAwesomeIcon icon={faPlus} className="fa-fw" /></Typography>
</Button>
</Box>
</CardDark>
}
Example #6
Source File: index.tsx From excalideck with MIT License | 6 votes |
export default function AddEmptySlideButton({ onClick }: Props) {
return (
<button
className="AddEmptySlideButton"
title="Add slide"
onClick={() => onClick()}
>
<FontAwesomeIcon icon={faPlus} />
</button>
);
}
Example #7
Source File: AddGoalButton.tsx From calculate-my-odds with MIT License | 6 votes |
render() {
return (
<div className="add-goal-button-component">
<ButtonWithDropdown
icon={faPlus}
content="Add goal"
onClick={() => this.props.onNewGoal?.(this.createSingleCompletionGoal())}
dropdownItems={[
{
name: "Single completion goal",
onClick: () => this.props.onNewGoal?.(this.createSingleCompletionGoal())
},
{
name: "Full completion goal",
onClick: () => this.props.onNewGoal?.(this.createFullCompletionGoal())
},
{
name: "Partial completion goal",
onClick: () => this.props.onNewGoal?.(this.createPartialCompletionGoal())
}
]}
dropdownWidth="11em"
/>
</div>
);
}
Example #8
Source File: AddFailureButton.tsx From calculate-my-odds with MIT License | 6 votes |
render() {
return (
<div className="add-failure-button-component">
<ButtonWithDropdown
icon={faPlus}
content="Add failure condition"
onClick={() => this.props.onNewFailure?.(this.createSingleCompletionFailure())}
dropdownItems={[
{
name: "Single completion condition",
onClick: () => this.props.onNewFailure?.(this.createSingleCompletionFailure())
},
{
name: "Full completion condition",
onClick: () => this.props.onNewFailure?.(this.createFullCompletionFailure())
},
{
name: "Partial completion condition",
onClick: () => this.props.onNewFailure?.(this.createPartialCompletionFailure())
}
]}
dropdownWidth="13em"
/>
</div>
);
}
Example #9
Source File: WriteLessonLink.tsx From frontend.ro with MIT License | 6 votes |
function WriteLessonLink() {
return (
<Link href="/intro/despre-noi#cum-pot-sa-ajut">
<a className={`${styles['write-lesson-link']} d-flex justify-content-center align-items-center no-underline`}>
<FontAwesomeIcon icon={faPlus} width="32" height="32" />
<p>Contribuie și tu cu o lecție</p>
</a>
</Link>
);
}
Example #10
Source File: OrganizationDropdown.tsx From argo-react with MIT License | 5 votes |
OrganizationDropdown: React.FC<IOrganizationDropdownProps> = ({
setShowDropdown,
}) => {
const history = useHistory();
const { setSelectedOrganization } = useContext<IActionModel>(ActionContext);
const { user } = useContext(StateContext);
return (
<>
<div
className="organization-dropdown-overlay"
onClick={(e) => setShowDropdown(false)}
></div>
<div className="organization-dropdown-box">
<label>Teams</label>
{user?.organizations?.map((org: IOrganization, index: number) => (
<OrganizationDropdownItem
orgDetails={{
name: org.profile.name,
avatar: org.profile.image
? org.profile.image
: require("../../../../../assets/png/default_icon.png"),
}}
key={index}
onClick={(e: Event) => {
setSelectedOrganization(org);
// history.push("/dashboard");
setShowDropdown(false);
}}
/>
))}
<div
className="create-team-item-container"
onClick={(e) => history.push("/org/new")}
>
<div className="create-team-item">
<div className="create-team-title">Create a Organization</div>
<div className="create-team-icon">
<FontAwesomeIcon icon={faPlus}></FontAwesomeIcon>
</div>
</div>
</div>
</div>
</>
);
}
Example #11
Source File: tableColumns.tsx From solo with MIT License | 5 votes |
createColumns: CreateColumns = () => [
{
Header: "Details",
Cell: ({ row }) => (
<span {...row.getToggleRowExpandedProps()}>
<FontAwesomeIcon icon={row.isExpanded ? faMinus : faPlus} />
</span>
)
},
{
Header: "SDN",
accessor: "sdn"
},
{
Header: "Service Request #",
accessor: "serviceRequest",
id: "service_request"
},
{
Header: "Commodity",
id: "suppadd__code",
accessor: "commodityName"
},
{
Header: "Status",
disableSortBy: true,
id: "currentStatus",
accessor: ({ mostRecentStatusIdx, statuses }) =>
statuses[mostRecentStatusIdx].dic
},
{
Header: "Nomenclature",
id: "part__nomen",
accessor: "part.nomen"
},
{
Header: "Last Updated",
id: "statuses__status_date",
disableSortBy: true,
accessor: ({ mostRecentStatusIdx, statuses }) =>
`${formatDistanceToNow(
parseISO(statuses[mostRecentStatusIdx].status_date)
)} ago`
}
]
Example #12
Source File: Tabs.tsx From calculate-my-odds with MIT License | 5 votes |
render() {
return (
<div className="tabs-component">
<div className="tabs-header-effects">
<div className={`tab-header-fade-left ${this.state.hideLeftFade ? "tab-fade-hidden" : ""}`}></div>
<div className={`tab-header-fade-right ${this.state.hideRightFade ? "tab-fade-hidden" : ""}`}></div>
</div>
<div
ref={this.headerContainerRef}
className="tab-header-container"
onWheel={e => {
const direction = e.deltaY < 0 ? -1 : e.deltaY > 0 ? 1 : 0;
this.headerContainerRef.current!.scrollLeft += direction * 20;
if (e.cancelable) {
e.preventDefault();
}
}}
>
{this.props.tabs.map((tab, index) => (
<div
key={tab.id}
className={`tab-header ${this.props.selectedIndex === index ? "tab-selected" : ""}`}
onClick={() => this.props.onTabSelected?.(index)}
>
<div className="tab-header-name">
{tab.name}
</div>
{this.props.tabs.length >= 2 && this.props.onTabRemovalRequest &&
<div className="tab-header-actions">
<div
className="tab-header-remove"
onClick={e => {
e.stopPropagation();
this.props.onTabRemovalRequest?.(index);
}}
>
<FontAwesomeIcon icon={faTimes} />
</div>
</div>
}
</div>
))}
{this.props.onRequestNewTab &&
<div
className="tab-header"
onClick={() => this.props.onRequestNewTab?.()}
>
<FontAwesomeIcon icon={faPlus} className="new-tab-icon" />
</div>
}
</div>
<div className="tab-content-container">
{this.props.tabs.map((tab, index) => (
<div key={tab.id} className={`tab-content ${index === this.props.selectedIndex ? "" : "tab-content-hidden"}`}>
{tab.content}
</div>
))}
</div>
</div>
);
}
Example #13
Source File: transactions-table.component.ts From thorchain-explorer-singlechain with MIT License | 5 votes |
constructor() {
this.swapIcon = faExchangeAlt;
this.depositIcon = faLevelDownAlt;
this.withdrawIcon = faLevelUpAlt;
this.refundIcon = faUndoAlt;
this.addIcon = faPlus;
this.timesIcon = faTimes;
}
Example #14
Source File: UserActivity.tsx From frontend.ro with MIT License | 5 votes |
CreatedExercises = () => {
const [createdExercises, setCreatedExercises] = useState([]);
useEffect(() => {
ExerciseService
.getCreatedExercises()
.then((exercises) => {
setCreatedExercises(exercises);
})
.catch((err) => {
console.error('[CreatedExercises.getCreatedExercises] Failed to get exercises.', err);
});
}, []);
return (
<section>
<h2> Exerciții create </h2>
<div className={styles['exercises-wrapper']}>
{createdExercises.map((ex) => (
<ExercisePreview
key={ex._id}
exercise={ex}
href={`exercitii/${ex._id}`}
isPrivate={ex.private}
viewMode="TEACHER"
feedbackCount={0}
isApproved={false}
readOnly={false}
/>
))}
<Link href="/exercitii/creeaza">
<a className="d-flex align-items-center justify-content-center no-underline text-center">
<FontAwesomeIcon icon={faPlus} width="32" height="32" />
<span> Creează un nou exercițiu </span>
</a>
</Link>
</div>
</section>
);
}
Example #15
Source File: ComplexList.example.tsx From hacker-ui with MIT License | 5 votes |
function ComplexListExample(props: Props) {
const { Root, styles } = useStyles(props);
const [quantities, setQuantities] = useState({} as { [id: string]: number });
return (
<Root>
<List className={styles.list}>
{products.map(({ id, imgUrl, title, price }) => {
const quantity = quantities[id] ?? 0;
const handleDec = () => {
setQuantities((quantities) => ({
...quantities,
[id]: Math.max(0, quantity - 1),
}));
};
const handleInc = () => {
setQuantities((quantities) => ({
...quantities,
[id]: quantity + 1,
}));
};
return (
<ListItem className={styles.listItem}>
<img className={styles.img} src={imgUrl} alt={title} />
<div className={styles.info}>
<h3 className={styles.title}>{title}</h3>
<p className={styles.subtitle}>
${(price / 100).toLocaleString()}
</p>
</div>
<div className={styles.buttonSection}>
<div className={styles.buttons}>
<Button shape="icon" size="small" onClick={handleDec}>
<FontAwesomeIcon icon={faMinus} />
</Button>
<div className={styles.quantityCount}>{quantity}</div>
<Button shape="icon" size="small" onClick={handleInc}>
<FontAwesomeIcon icon={faPlus} />
</Button>
</div>
<div className={styles.subLabel}>Quantity</div>
</div>
<div className={styles.subtotalSection}>
<div className={styles.subtotal}>
${((quantity * price) / 100).toLocaleString()}
</div>
<div className={styles.subLabel}>Subtotal</div>
</div>
</ListItem>
);
})}
</List>
</Root>
);
}
Example #16
Source File: FileSystem.tsx From MagicUI with Apache License 2.0 | 5 votes |
function ProjectManageTools() {
const user = useSelector((state: IStoreState) => state.user);
const dslFile = useSelector((state: IStoreState) => state.dslFile);
const openFileItems = useSelector((state: IStoreState) => state.openFileItems);
const dispatch = useDispatch();
const handleCreateFile = () => {
modal(cancel => (
<NewFileOrFolderModal fileType="file" cancel={cancel} email={user.email} folder={dslFile.folder}
dispatch={dispatch}/>
));
};
const handleCreateFolder = () => {
modal(cancel => (
<NewFileOrFolderModal fileType="folder" cancel={cancel} email={user.email} folder={dslFile.folder}
dispatch={dispatch}/>
));
};
const handleDeleteFile = () => {
modal(cancel => <Confirm title={`Do you want to delete ${dslFile.filename}`} cancel={cancel} confirm={() => {
deleteDslFile(user.email, dslFile.id, dslFile.fileId).then(v => {
if (!v.err) {
toast('delete file!');
dispatch(localDeleteFile(dslFile.id));
let i = 0, check = false;
for (let item of openFileItems.items) {
if (v.id === item.id) {
check = true;
break
}
i++;
}
console.log(check, i - 1);
check && dispatch(closeFile(i - 1, dslFile.id, dslFile.fileId));
cancel();
}
});
}}/>);
};
return (
<div className={style.project_manage_tools}>
<button className={style.mk_file_btn} onClick={handleCreateFile}>
<FontAwesomeIcon icon={faPlus}/>
</button>
<button className={style.mk_dir_btn} onClick={handleCreateFolder}>
<FontAwesomeIcon icon={faFolderPlus}/>
</button>
<button className={style.delete_btn} onClick={handleDeleteFile}>
<FontAwesomeIcon icon={faTrash}/>
</button>
</div>
);
}
Example #17
Source File: ProbabilityTableContainer.tsx From calculate-my-odds with MIT License | 4 votes |
render() {
return (
<SpaceContainer className="probability-table-component">
{this.props.table.items.length > 0 &&
<div>
{this.props.table.items.map((item, index) => (
<ProbabilityInput
key={item.id}
item={item}
onChange={item => this.updateItem(index, item)}
onDeleteRequest={() => this.deleteItem(item)}
requestTabFocus={this.props.requestTabFocus}
showDeleteButton={this.props.table.items.length >= 2}
validator={this.props.validator}
/>
))}
</div>
}
{this.state.showProbabilitiesExceedOneError &&
<div>
<ErrorDisplay>
The sum of all probabilities in the table should not exceed 100%.
</ErrorDisplay>
</div>
}
<ButtonContainer>
<Button
icon={faPlus}
content="Add option"
onClick={() => this.addNewItem()}
/>
<Button
icon={faList}
content="Properties"
onClick={() => this.setState({
showTableProperties: !this.state.showTableProperties
})}
/>
</ButtonContainer>
{this.state.showTableProperties &&
<SpaceContainer>
<div>
<label>Table name</label>
<Input
value={this.props.table.name}
onChange={e => this.props.onChange?.({
...this.props.table,
name: e.target.value
})}
/>
</div>
<div>
<label>Table rolls per iteration</label>
<TooltipContainer
tooltipContent="Enter a value."
show={this.state.showEmptyTableRollsPerIterationError}
side={TooltipSide.Right}
>
<IntegerInput
value={this.props.table.rollsPerIteration}
onChange={value => {
this.props.onChange?.({
...this.props.table,
rollsPerIteration: value
});
this.setState({
showEmptyTableRollsPerIterationError: false
});
}}
onFocus={() => this.setState({
showEmptyTableRollsPerIterationError: false
})}
markError={this.state.showEmptyTableRollsPerIterationError}
/>
</TooltipContainer>
</div>
</SpaceContainer>
}
</SpaceContainer>
);
}
Example #18
Source File: FileSwitcher.tsx From frontend.ro with MIT License | 4 votes |
render() {
const {
readOnly,
maxHeight,
folderStructure,
selectedFileKey,
feedbacks: feedbacksProp,
} = this.props;
const {
ctxMenuKey,
isCollapsed,
ctxMenuType,
dropdownStyle,
isGeneratingArchive,
} = this.state;
let { renamedAsset } = this.state;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
renamedAsset = renamedAsset || { key: null };
const files = folderStructure.files.map((f) => ({ ...f, icon: FileIcons.getIcon(f.name) }));
const feedbacks = new Feedbacks(null, feedbacksProp || []).getTypesByFileKey();
return (
<div
className={`
${styles['file-switcher']}
${readOnly ? styles['is--read-only'] : ''}
${isCollapsed ? styles['is--collapsed'] : ''}`}
ref={this.fileSwitcherRef}
style={{ width: `${INITIAL_WIDTH_PX}px`, minWidth: `${MIN_WIDTH_PX}px`, maxHeight: `${maxHeight}px` }}
>
{isCollapsed && (
<Button onClick={this.toggleCollapse} title="Browse files" className={`${styles['toggle-button']}`}>
<img src={FileIcons.getIconUrl('svg')} alt="File SVG icon" />
</Button>
)}
<div className={styles.controls}>
<div>
{!readOnly && (
<Button onClick={() => this.newFile()} title="New file">
<FontAwesomeIcon icon={faPlus} width="18" height="18" />
</Button>
)}
{!readOnly && (
<Button onClick={() => this.newFolder()} title="New folder">
<FontAwesomeIcon icon={faFolderPlus} width="18" height="18" />
</Button>
)}
<Button
onClick={this.onDownload}
loading={isGeneratingArchive}
title="Download to device"
>
<FontAwesomeIcon icon={faCloudDownloadAlt} width="18" height="18" />
</Button>
</div>
<Button onClick={this.toggleCollapse} title="Collapse panel">
<FontAwesomeIcon icon={faChevronLeft} width="18" height="18" />
</Button>
</div>
{/* <Scroll className="is--fliped-x"> */}
<div>
{folderStructure.folders.map((folder, index) => (
<FolderBrowse
key={folder.key}
folderKey={folder.key}
folderStructure={folderStructure}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
feedbacks={feedbacks}
readOnly={readOnly}
selectFile={this.selectFile}
selectedFileKey={selectedFileKey}
renamedAsset={renamedAsset}
ctxMenuKey={ctxMenuKey}
openMenu={this.openMenu}
enterEditMode={this.enterEditMode}
onRename={this.onRename}
saveAsset={this.saveAsset}
/>
))}
<FilesList
readOnly={readOnly}
files={files}
feedbacks={feedbacks}
selectedFileKey={selectedFileKey}
ctxMenuKey={ctxMenuKey}
selectFile={this.selectFile}
enterEditMode={this.enterEditMode}
openMenu={this.openMenu}
renamedAsset={renamedAsset}
onRename={this.onRename}
saveAsset={this.saveAsset}
/>
</div>
{/* </Scroll> */}
<List className={styles['dropdown-menu']} style={dropdownStyle}>
{ctxMenuType === 'FOLDER' && (
<>
<li>
<Button onClick={() => this.newFile(ctxMenuKey)}>
<FontAwesomeIcon icon={faFileAlt} width="18" height="18" />
New file
</Button>
</li>
<li>
<Button onClick={() => this.newFolder(ctxMenuKey)}>
<FontAwesomeIcon icon={faFolder} width="18" height="18" />
New folder
</Button>
</li>
</>
)}
<li>
<Button onClick={() => this.enterEditMode(ctxMenuKey)}>
<FontAwesomeIcon icon={faEdit} width="18" height="18" />
Rename
</Button>
</li>
<li>
<Button onClick={() => this.deleteFileOrFolder(ctxMenuKey)}>
<FontAwesomeIcon icon={faTrashAlt} width="18" height="18" />
Delete
</Button>
</li>
</List>
<HResizable onResize={this.onResize} />
</div>
);
}
Example #19
Source File: index.tsx From genshin-optimizer with MIT License | 4 votes |
export default function PageCharacter(props) {
// TODO: #412 We shouldn't be loading all the character translation files. Should have a separate lookup file for character name.
const { t } = useTranslation(["page_character", ...allCharacterKeys.map(k => `char_${k}_gen`)])
const { database } = useContext(DatabaseContext)
const [state, stateDispatch] = useDBState("CharacterDisplay", initialState)
const [searchTerm, setSearchTerm] = useState("")
const deferredSearchTerm = useDeferredValue(searchTerm)
const [pageIdex, setpageIdex] = useState(0)
const invScrollRef = useRef<HTMLDivElement>(null)
const setPage = useCallback(
(e, value) => {
invScrollRef.current?.scrollIntoView({ behavior: "smooth" })
setpageIdex(value - 1);
},
[setpageIdex, invScrollRef],
)
const brPt = useMediaQueryUp()
const maxNumToDisplay = numToShowMap[brPt]
const [newCharacter, setnewCharacter] = useState(false)
const [dbDirty, forceUpdate] = useForceUpdate()
//set follow, should run only once
useEffect(() => {
ReactGA.send({ hitType: "pageview", page: '/characters' })
return database.followAnyChar(forceUpdate)
}, [forceUpdate, database])
const characterSheets = usePromise(CharacterSheet.getAll, [])
const deleteCharacter = useCallback(async (cKey: CharacterKey) => {
const chararcterSheet = await CharacterSheet.get(cKey)
let name = chararcterSheet?.name
//use translated string
if (typeof name === "object")
name = i18next.t(`char_${cKey}_gen:name`)
if (!window.confirm(t("removeCharacter", { value: name }))) return
database.removeChar(cKey)
}, [database, t])
const editCharacter = useCharSelectionCallback()
const navigate = useNavigate()
const { element, weaponType } = state
const sortConfigs = useMemo(() => characterSheets && characterSortConfigs(database, characterSheets), [database, characterSheets])
const filterConfigs = useMemo(() => characterSheets && characterFilterConfigs(database, characterSheets), [database, characterSheets])
const { charKeyList, totalCharNum } = useMemo(() => {
const chars = database._getCharKeys()
const totalCharNum = chars.length
if (!sortConfigs || !filterConfigs) return { charKeyList: [], totalCharNum }
const charKeyList = database._getCharKeys()
.filter(filterFunction({ element, weaponType, favorite: "yes", name: deferredSearchTerm }, filterConfigs))
.sort(sortFunction(state.sortType, state.ascending, sortConfigs))
.concat(
database._getCharKeys()
.filter(filterFunction({ element, weaponType, favorite: "no", name: deferredSearchTerm }, filterConfigs))
.sort(sortFunction(state.sortType, state.ascending, sortConfigs)))
return dbDirty && { charKeyList, totalCharNum }
},
[dbDirty, database, sortConfigs, state.sortType, state.ascending, element, filterConfigs, weaponType, deferredSearchTerm])
const { charKeyListToShow, numPages, currentPageIndex } = useMemo(() => {
const numPages = Math.ceil(charKeyList.length / maxNumToDisplay)
const currentPageIndex = clamp(pageIdex, 0, numPages - 1)
return { charKeyListToShow: charKeyList.slice(currentPageIndex * maxNumToDisplay, (currentPageIndex + 1) * maxNumToDisplay), numPages, currentPageIndex }
}, [charKeyList, pageIdex, maxNumToDisplay])
const totalShowing = charKeyList.length !== totalCharNum ? `${charKeyList.length}/${totalCharNum}` : `${totalCharNum}`
return <Box my={1} display="flex" flexDirection="column" gap={1}>
<CardDark ref={invScrollRef} ><CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
<Grid container spacing={1}>
<Grid item>
<WeaponToggle sx={{ height: "100%" }} onChange={weaponType => stateDispatch({ weaponType })} value={state.weaponType} size="small" />
</Grid>
<Grid item>
<ElementToggle sx={{ height: "100%" }} onChange={element => stateDispatch({ element })} value={state.element} size="small" />
</Grid>
<Grid item flexGrow={1}>
<TextField
autoFocus
value={searchTerm}
onChange={(e: ChangeEvent<HTMLTextAreaElement>) => setSearchTerm(e.target.value)}
label={t("characterName")}
/>
</Grid>
<Grid item >
<SortByButton sx={{ height: "100%" }}
sortKeys={characterSortKeys} value={state.sortType} onChange={sortType => stateDispatch({ sortType })}
ascending={state.ascending} onChangeAsc={ascending => stateDispatch({ ascending })} />
</Grid>
</Grid>
<Grid container alignItems="flex-end">
<Grid item flexGrow={1}>
<Pagination count={numPages} page={currentPageIndex + 1} onChange={setPage} />
</Grid>
<Grid item>
<ShowingCharacter numShowing={charKeyListToShow.length} total={totalShowing} t={t} />
</Grid>
</Grid>
</CardContent></CardDark>
<Suspense fallback={<Skeleton variant="rectangular" sx={{ width: "100%", height: "100%", minHeight: 5000 }} />}>
<Grid container spacing={1} columns={columns}>
<Grid item xs={1} >
<CardDark sx={{ height: "100%", minHeight: 400, width: "100%", display: "flex", flexDirection: "column" }}>
<CardContent>
<Typography sx={{ textAlign: "center" }}><Trans t={t} i18nKey="addNew" /></Typography>
</CardContent>
<CharacterSelectionModal newFirst show={newCharacter} onHide={() => setnewCharacter(false)} onSelect={editCharacter} />
<Box sx={{
flexGrow: 1,
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<Button onClick={() => setnewCharacter(true)} color="info" sx={{ borderRadius: "1em" }}>
<Typography variant="h1"><FontAwesomeIcon icon={faPlus} className="fa-fw" /></Typography>
</Button>
</Box>
</CardDark>
</Grid>
{charKeyListToShow.map(charKey =>
<Grid item key={charKey} xs={1} >
<CharacterCard
characterKey={charKey}
onClick={() => navigate(`${charKey}`)}
footer={<><Divider /><Box sx={{ py: 1, px: 2, display: "flex", gap: 1, justifyContent: "space-between" }}>
<BootstrapTooltip placement="top" title={<Typography>{t("tabs.talent")}</Typography>}>
<IconButton onClick={() => navigate(`${charKey}/talent`)}>
<FactCheck />
</IconButton>
</BootstrapTooltip>
<BootstrapTooltip placement="top" title={<Typography>{t("tabs.equip")}</Typography>}>
<IconButton onClick={() => navigate(`${charKey}/equip`)} >
<Checkroom />
</IconButton>
</BootstrapTooltip>
<BootstrapTooltip placement="top" title={<Typography>{t("tabs.teambuffs")}</Typography>}>
<IconButton onClick={() => navigate(`${charKey}/teambuffs`)} >
<Groups />
</IconButton>
</BootstrapTooltip>
<BootstrapTooltip placement="top" title={<Typography>{t("tabs.optimize")}</Typography>}>
<IconButton onClick={() => navigate(`${charKey}/optimize`)} >
<Calculate />
</IconButton>
</BootstrapTooltip>
<Divider orientation="vertical" />
<BootstrapTooltip placement="top" title={<Typography>{t("delete")}</Typography>}>
<IconButton color="error" onClick={() => deleteCharacter(charKey)}>
<DeleteForever />
</IconButton>
</BootstrapTooltip>
</Box></>}
/>
</Grid>)}
</Grid>
</Suspense>
{numPages > 1 && <CardDark ><CardContent>
<Grid container alignItems="flex-end">
<Grid item flexGrow={1}>
<Pagination count={numPages} page={currentPageIndex + 1} onChange={setPage} />
</Grid>
<Grid item>
<ShowingCharacter numShowing={charKeyListToShow.length} total={totalShowing} t={t} />
</Grid>
</Grid>
</CardContent></CardDark>}
</Box>
}
Example #20
Source File: index.tsx From genshin-optimizer with MIT License | 4 votes |
export default function PageWeapon() {
const { t } = useTranslation(["page_weapon", "ui"]);
const { database } = useContext(DatabaseContext)
const [state, stateDisplatch] = useDBState("WeaponDisplay", initialState)
const [newWeaponModalShow, setnewWeaponModalShow] = useState(false)
const [dbDirty, forceUpdate] = useForceUpdate()
const invScrollRef = useRef<HTMLDivElement>(null)
const [pageIdex, setpageIdex] = useState(0)
//set follow, should run only once
useEffect(() => {
ReactGA.send({ hitType: "pageview", page: '/weapon' })
return database.followAnyWeapon(forceUpdate)
}, [forceUpdate, database])
const brPt = useMediaQueryUp()
const maxNumToDisplay = numToShowMap[brPt]
const weaponSheets = usePromise(WeaponSheet.getAll, [])
const deleteWeapon = useCallback(async (key) => {
const weapon = database._getWeapon(key)
if (!weapon) return
const name = i18next.t(`weapon_${weapon.key}_gen:name`)
if (!window.confirm(`Are you sure you want to remove ${name}?`)) return
database.removeWeapon(key)
if (state.editWeaponId === key)
stateDisplatch({ editWeaponId: "" })
}, [state.editWeaponId, stateDisplatch, database])
const editWeapon = useCallback(key => {
stateDisplatch({ editWeaponId: key })
}, [stateDisplatch])
const newWeapon = useCallback(
(weaponKey: WeaponKey) => {
editWeapon(database.createWeapon(initialWeapon(weaponKey)))
},
[database, editWeapon])
const { sortType, ascending, weaponType, rarity } = state
const sortConfigs = useMemo(() => weaponSheets && weaponSortConfigs(weaponSheets), [weaponSheets])
const filterConfigs = useMemo(() => weaponSheets && weaponFilterConfigs(weaponSheets), [weaponSheets])
const { weaponIdList, totalWeaponNum } = useMemo(() => {
const weapons = database._getWeapons()
const totalWeaponNum = weapons.length
if (!sortConfigs || !filterConfigs) return { weaponIdList: [], totalWeaponNum }
const weaponIdList = weapons.filter(filterFunction({ weaponType, rarity }, filterConfigs))
.sort(sortFunction(sortType, ascending, sortConfigs)).map(weapon => weapon.id);
return dbDirty && { weaponIdList, totalWeaponNum }
}, [dbDirty, database, sortConfigs, filterConfigs, sortType, ascending, rarity, weaponType])
const { weaponIdsToShow, numPages, currentPageIndex } = useMemo(() => {
const numPages = Math.ceil(weaponIdList.length / maxNumToDisplay)
const currentPageIndex = clamp(pageIdex, 0, numPages - 1)
return { weaponIdsToShow: weaponIdList.slice(currentPageIndex * maxNumToDisplay, (currentPageIndex + 1) * maxNumToDisplay), numPages, currentPageIndex }
}, [weaponIdList, pageIdex, maxNumToDisplay])
//for pagination
const totalShowing = weaponIdList.length !== totalWeaponNum ? `${weaponIdList.length}/${totalWeaponNum}` : `${totalWeaponNum}`
const setPage = useCallback(
(e, value) => {
invScrollRef.current?.scrollIntoView({ behavior: "smooth" })
setpageIdex(value - 1);
},
[setpageIdex, invScrollRef],
)
const resetEditWeapon = useCallback(() => stateDisplatch({ editWeaponId: "" }), [stateDisplatch])
const { editWeaponId } = state
// Validate weaponId to be an actual weapon
useEffect(() => {
if (!editWeaponId) return
if (!database._getWeapon(editWeaponId))
resetEditWeapon()
}, [database, editWeaponId, resetEditWeapon])
return <Box my={1} display="flex" flexDirection="column" gap={1}>
{/* editor/character detail display */}
<Suspense fallback={false}>
<WeaponEditor
weaponId={editWeaponId}
footer
onClose={resetEditWeapon}
/>
</Suspense>
<CardDark ref={invScrollRef} sx={{ p: 2, pb: 1 }}>
<Grid container spacing={1} sx={{ mb: 1 }}>
<Grid item>
<WeaponToggle sx={{ height: "100%" }} onChange={weaponType => stateDisplatch({ weaponType })} value={weaponType} size="small" />
</Grid>
<Grid item flexGrow={1}>
<SolidToggleButtonGroup sx={{ height: "100%" }} onChange={(e, newVal) => stateDisplatch({ rarity: newVal })} value={rarity} size="small">
{allRarities.map(star => <ToggleButton key={star} value={star}><Box display="flex" gap={1}><strong>{star}</strong><Stars stars={1} /></Box></ToggleButton>)}
</SolidToggleButtonGroup>
</Grid>
<Grid item >
<SortByButton sx={{ height: "100%" }} sortKeys={weaponSortKeys}
value={sortType} onChange={sortType => stateDisplatch({ sortType })}
ascending={ascending} onChangeAsc={ascending => stateDisplatch({ ascending })}
/>
</Grid>
</Grid>
<Grid container alignItems="flex-end">
<Grid item flexGrow={1}>
<Pagination count={numPages} page={currentPageIndex + 1} onChange={setPage} />
</Grid>
<Grid item>
<ShowingWeapon numShowing={weaponIdsToShow.length} total={totalShowing} t={t} />
</Grid>
</Grid>
</CardDark>
<Suspense fallback={<Skeleton variant="rectangular" sx={{ width: "100%", height: "100%", minHeight: 500 }} />}>
<Grid container spacing={1} columns={columns}>
<Grid item xs={1}>
<CardDark sx={{ height: "100%", width: "100%", minHeight: 300, display: "flex", flexDirection: "column" }}>
<CardContent>
<Typography sx={{ textAlign: "center" }}>Add New Weapon</Typography>
</CardContent>
<WeaponSelectionModal show={newWeaponModalShow} onHide={() => setnewWeaponModalShow(false)} onSelect={newWeapon} />
<Box sx={{
flexGrow: 1,
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<Button onClick={() => setnewWeaponModalShow(true)} color="info" sx={{ borderRadius: "1em" }}>
<Typography variant="h1"><FontAwesomeIcon icon={faPlus} className="fa-fw" /></Typography>
</Button>
</Box>
</CardDark>
</Grid>
{weaponIdsToShow.map(weaponId =>
<Grid item key={weaponId} xs={1} >
<WeaponCard
weaponId={weaponId}
onDelete={deleteWeapon}
onEdit={editWeapon}
canEquip
/>
</Grid>)}
</Grid>
</Suspense>
{numPages > 1 && <CardDark><CardContent>
<Grid container alignItems="flex-end">
<Grid item flexGrow={1}>
<Pagination count={numPages} page={currentPageIndex + 1} onChange={setPage} />
</Grid>
<Grid item>
<ShowingWeapon numShowing={weaponIdsToShow.length} total={totalShowing} t={t} />
</Grid>
</Grid>
</CardContent></CardDark>}
</Box>
}
Example #21
Source File: BoardBar.tsx From knboard with MIT License | 4 votes |
BoardBar = () => {
const dispatch = useDispatch();
const members = useSelector(selectAllMembers);
const error = useSelector((state: RootState) => state.board.detailError);
const detail = useSelector((state: RootState) => state.board.detail);
const boardOwner = useSelector(currentBoardOwner);
const { id } = useParams();
const detailDataExists = detail?.id.toString() === id;
if (!detailDataExists || error || !detail) {
return null;
}
const handleAddColumn = () => {
dispatch(addColumn(detail.id));
};
const handleEditLabels = () => {
dispatch(setDialogOpen(true));
};
return (
<Container data-testid="board">
<Items>
<Left>
<BoardName
id={detail.id}
name={detail.name}
isOwner={boardOwner}
data-testid="board-name"
/>
<AvatarGroup
max={3}
data-testid="member-group"
css={css`
margin-left: 1.5rem;
& .MuiAvatarGroup-avatar {
${avatarStyles}
border: none;
}
&:hover {
cursor: pointer;
}
`}
onClick={(e: any) => {
if (e.target.classList.contains("MuiAvatarGroup-avatar")) {
dispatch(setMemberListOpen(true));
}
}}
>
{members.map((member) => (
<MemberDetail
key={member.id}
member={member}
isOwner={detail.owner === member.id}
/>
))}
</AvatarGroup>
{boardOwner && <MemberInvite boardId={detail.id} />}
<MemberFilter boardId={detail.id} />
</Left>
<Right>
<Button
size="small"
css={css`
${buttonStyles}
margin-right: 0.5rem;
font-weight: 600;
`}
onClick={handleEditLabels}
startIcon={<FontAwesomeIcon icon={faPen} />}
data-testid="open-labels-dialog"
>
Edit labels
</Button>
<Button
size="small"
css={css`
${buttonStyles}
font-weight: 600;
`}
onClick={handleAddColumn}
startIcon={<FontAwesomeIcon icon={faPlus} />}
data-testid="add-col"
>
Add Column
</Button>
</Right>
</Items>
<MemberDialog board={detail} />
<MemberListDialog />
<EditTaskDialog />
<CreateTaskDialog />
<LabelDialog />
</Container>
);
}
Example #22
Source File: UserActivity.tsx From frontend.ro with MIT License | 4 votes |
function UserActivity({ profileUser, currentUser }: ConnectedProps<typeof connector> & Props) {
const isOwnProfile = currentUser.info && currentUser.info.username === profileUser.username;
const [didError, setDidError] = useState(false);
const [solvedExercises, setSolvedExercises] = useState<Submission[]>(undefined);
const [tutorialsProgress, setTutorialsProgress] = useState<TutorialProgressI[]>(undefined);
const fetchTutorialsProgress = async () => {
try {
const tutorials = await TutorialService.getAll();
const progressResponses = await Promise.all(tutorials.map((tutorial) => {
return TutorialService.getProgress(tutorial.tutorialId);
}));
setTutorialsProgress(progressResponses);
} catch (err) {
console.error('UserActivity.fetchTutorialsProgress', err);
setDidError(true);
}
};
useEffect(() => {
// Solved exercises
if (isOwnProfile) {
ExerciseService
.getSolvedExercises()
.then((resp) => setSolvedExercises(resp))
.catch((err) => console.error(err));
fetchTutorialsProgress();
} else {
setSolvedExercises([]);
setTutorialsProgress([]);
}
}, []);
if (didError) {
return (
<p className="text-red text-center">
Oops! Nu am putut încărca profilul.
<br />
Încearcă din nou.
</p>
);
}
if (!solvedExercises || !tutorialsProgress) {
// Loading
return null;
}
if (!isOwnProfile) {
return <NoActivity user={profileUser} />;
}
return (
<PageContainer>
<section className="mb-12">
<h2> Tutoriale </h2>
{tutorialsProgress
.map(aggregateTutorialProgress)
.map((aggregatedProgress, index) => (
<div
key={tutorialsProgress[index].name}
className={`${styles['progress-wrapper']} p-3`}
>
<TutorialProgress
title={tutorialsProgress[index].name}
tutorialProgress={tutorialsProgress[index]}
/>
{aggregatedProgress.done < aggregatedProgress.total && (
<Link href={`/${tutorialsProgress[index].tutorialId}/tutorial`}>
<a className="btn btn--light no-underline mt-4">
{(
aggregatedProgress.done === 0
&& aggregatedProgress.inProgress === 0
)
? 'Începe tutorialul'
: 'Continuă'}
</a>
</Link>
)}
{/* TODO: https://github.com/FrontEnd-ro/frontend.ro/issues/512 */}
{/* {aggregatedProgress.done === aggregatedProgress.total && (
<Link href="#">
<a className="btn btn--light no-underline mt-4">
Vezi certificarea
</a>
</Link>
)} */}
</div>
))}
</section>
<h2>
Exerciții rezolvate
</h2>
<div className={styles['exercises-wrapper']}>
{solvedExercises.map((submission: Submission) => (
<ExercisePreview
key={submission._id}
exercise={submission.exercise}
href={`rezolva/${submission.exercise._id}`}
viewMode="STUDENT"
feedbackCount={submission.feedbacks.filter((f) => f.type === 'improvement').length}
isApproved={submission.status === SubmissionStatus.DONE}
readOnly={[
SubmissionStatus.AWAITING_REVIEW,
SubmissionStatus.DONE,
].includes(submission.status)}
/>
))}
{solvedExercises.length === 0 && (
<Link href="/exercitii">
<a className="d-flex align-items-center justify-content-center no-underline text-center">
<FontAwesomeIcon icon={faPlus} width="32" height="32" />
<span> Rezolvă un exercițiu </span>
</a>
</Link>
)}
</div>
<hr />
{isOwnProfile && profileUser.role.includes(UserRole.ADMIN) && (
<CreatedExercises />
)}
</PageContainer>
);
}
Example #23
Source File: AddMedia.tsx From sync-party with GNU General Public License v3.0 | 4 votes |
export default function AddMedia({
isActive,
partyItemsSet,
setAddMediaIsActive,
socket,
setPlayerFocused,
handleItemEditSave
}: Props): JSX.Element {
const { t } = useTranslation();
const user = useSelector((state: RootAppState) => state.globalState.user);
const party = useSelector((state: RootAppState) => state.globalState.party);
const userItems = useSelector(
(state: RootAppState) => state.globalState.userItems
);
const mediaItemDefault: NewMediaItem = {
name: '',
type: 'file',
owner: user ? user.id : null,
url: ''
};
const [activeTab, setActiveTab] = useState<'user' | 'web' | 'file'>('file');
const [file, setFile] = useState<File | null>(null);
const [mediaItem, setMediaItem] = useState(mediaItemDefault);
const [uploadStartTime, setUploadStartTime] = useState(0);
const [isUploading, setIsUploading] = useState(false);
const [progress, setProgress] = useState(0);
const [addedSuccessfully, setAddedSuccessfully] = useState(false);
const [lastCreatedItem, setLastCreatedItem] = useState<NewMediaItem>();
const [uploadError, setUploadError] = useState(false);
const [fetchingLinkMetadata, setFetchingLinkMetadata] = useState(false);
const [linkMetadata, setLinkMetadata] = useState<{
videoTitle: string;
channelTitle: string;
} | null>(null);
const dispatch = useDispatch();
// Preselect user tab if there are items to add
useEffect(() => {
if (userItems && party)
if (
userItems.filter(
(userItem: MediaItem) => !partyItemsSet.has(userItem.id)
).length
) {
setActiveTab('user');
}
}, [userItems, party, partyItemsSet]);
const addUserItem = async (item: MediaItem): Promise<void> => {
if (party) {
try {
const response = await Axios.post(
'/api/partyItems',
{ mediaItem: item, partyId: party.id },
axiosConfig()
);
if (response.data.success === true) {
updatePartyAndUserParties();
} else {
dispatch(
setGlobalState({
errorMessage: t(
`apiResponseMessages.${response.data.msg}`
)
})
);
}
} catch (error) {
dispatch(
setGlobalState({
errorMessage: t(`errors.addToPartyError`)
})
);
}
}
};
const addWebItem = async (event: React.MouseEvent): Promise<void> => {
event.preventDefault();
if (party) {
try {
const response = await Axios.post(
'/api/mediaItem',
{ mediaItem: mediaItem, partyId: party.id },
axiosConfig()
);
if (response.data.success === true) {
updatePartyAndUserParties();
getUpdatedUserItems(dispatch, t);
resetUploadForm();
setIsUploading(false);
setLastCreatedItem(mediaItem);
setAddedSuccessfully(true);
hideFinishInAFewSecs();
toggleCollapseAddMediaMenu();
} else {
dispatch(
setGlobalState({
errorMessage: t(
`apiResponseMessages.${response.data.msg}`
)
})
);
}
} catch (error) {
dispatch(
setGlobalState({
errorMessage: t(`errors.addItemError`)
})
);
}
}
};
const addFileItem = async (event: React.MouseEvent): Promise<void> => {
event.preventDefault();
if (party && file && mediaItem.owner) {
const formData = new FormData();
formData.append('owner', mediaItem.owner);
formData.append('name', mediaItem.name);
formData.append('file', file);
formData.append('partyId', party.id);
setIsUploading(true);
setAddedSuccessfully(false);
setUploadStartTime(Date.now());
try {
const response = await Axios.post('/api/file', formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
onUploadProgress: (progressEvent) => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
setProgress(percentCompleted);
},
withCredentials: true
});
if (response.data.success === true) {
updatePartyAndUserParties();
getUpdatedUserItems(dispatch, t);
resetUploadForm();
setLastCreatedItem(mediaItem);
setIsUploading(false);
setAddedSuccessfully(true);
hideFinishInAFewSecs();
toggleCollapseAddMediaMenu();
} else {
dispatch(
setGlobalState({
errorMessage: t(
`apiResponseMessages.${response.data.msg}`
)
})
);
}
} catch (error) {
dispatch(
setGlobalState({
errorMessage: t(`errors.uploadError`)
})
);
resetUploadForm();
setIsUploading(false);
setUploadError(true);
}
}
};
const updatePartyAndUserParties = async (): Promise<void> => {
if (socket && party && userItems) {
// Update userParties
const updatedUserParties = await getUpdatedUserParties(dispatch, t);
const updatedParty = updatedUserParties.find(
(userParty: ClientParty) => userParty.id === party.id
);
// Preselect file tab if there are no items left to add
if (
updatedParty &&
!userItems.filter(
(userItem: MediaItem) =>
!updatedParty.items.find(
(item: MediaItem) => item.id === userItem.id
)
).length
) {
setActiveTab('file');
}
// Update current party
dispatch(
setGlobalState({
party: updatedParty
})
);
// Ask other users to update their userParties
socket.emit('partyUpdate', { partyId: party.id });
}
};
const handleLinkInput = async (
event: React.ChangeEvent<HTMLInputElement>
): Promise<void> => {
let url = event.target.value;
// YT: Remove list-related URL params
if (
url.indexOf('https://www.youtube.com') === 0 &&
url.indexOf('&list=') > -1
) {
url = url.slice(0, url.indexOf('&list='));
}
const webMediaItem: NewMediaItem = {
...mediaItem,
url: url,
type: 'web'
};
setMediaItem(webMediaItem);
if (url.indexOf('https://www.youtube.com') === 0) {
setFetchingLinkMetadata(true);
try {
const response = await Axios.post(
'/api/linkMetadata',
{ url: url },
{ ...axiosConfig(), timeout: 3000 }
);
setLinkMetadata({
videoTitle: response.data.videoTitle,
channelTitle: response.data.channelTitle
});
setMediaItem({
...webMediaItem,
name: response.data.videoTitle
});
setFetchingLinkMetadata(false);
} catch (error) {
setMediaItem({ ...webMediaItem, name: '' });
setFetchingLinkMetadata(false);
}
}
};
const toggleCollapseAddMediaMenu = (): void => {
if (isActive) {
setActiveTab('file');
}
setAddMediaIsActive(!isActive);
setUploadError(false);
resetUploadForm();
};
const changeTab = (tab: 'user' | 'web' | 'file'): void => {
setActiveTab(tab);
setFile(null);
setMediaItem(mediaItemDefault);
setUploadError(false);
};
const resetUploadForm = (): void => {
setFile(null);
setMediaItem(mediaItemDefault);
};
const hideFinishInAFewSecs = (): void => {
setTimeout(() => {
setAddedSuccessfully(false);
}, 5000);
};
return (
<div
className={'mt-2' + (!isActive ? '' : ' flex flex-col flex-shrink')}
>
{isActive && (
<>
<AddMediaTabBar
activeTab={activeTab}
changeTab={changeTab}
isUploading={isUploading}
toggleCollapseAddMediaMenu={toggleCollapseAddMediaMenu}
></AddMediaTabBar>
<div className="flex flex-col">
{!isUploading && !uploadError && userItems && party ? (
<>
{activeTab === 'user' && (
<AddMediaTabUser
partyItemsSet={partyItemsSet}
addUserItem={addUserItem}
setPlayerFocused={(
focused: boolean
): void => setPlayerFocused(focused)}
handleItemEditSave={handleItemEditSave}
></AddMediaTabUser>
)}
{activeTab === 'web' && (
<AddMediaTabWeb
mediaItem={mediaItem}
setMediaItem={(
mediaItem: NewMediaItem
): void => setMediaItem(mediaItem)}
addWebItem={addWebItem}
handleLinkInput={handleLinkInput}
setPlayerFocused={(
focused: boolean
): void => setPlayerFocused(focused)}
linkMetadata={linkMetadata}
fetchingLinkMetadata={
fetchingLinkMetadata
}
></AddMediaTabWeb>
)}
{activeTab === 'file' && (
<AddMediaTabFile
file={file}
setFile={(file: File): void =>
setFile(file)
}
mediaItem={mediaItem}
setMediaItem={(
mediaItem: NewMediaItem
): void => setMediaItem(mediaItem)}
addFileItem={addFileItem}
resetUploadForm={resetUploadForm}
setPlayerFocused={(
focused: boolean
): void => setPlayerFocused(focused)}
></AddMediaTabFile>
)}
</>
) : !uploadError ? (
<AddMediaUploadProgress
progress={progress}
uploadStartTime={uploadStartTime}
></AddMediaUploadProgress>
) : (
<div className="my-3">
{t('mediaMenu.uploadError')}
</div>
)}
</div>
</>
)}
{!isActive && (
<>
<Button
padding="p-1"
title={t('mediaMenu.addMediaTitle')}
text={
<>
<FontAwesomeIcon
icon={faPlus}
></FontAwesomeIcon>
<span>{' ' + t('mediaMenu.addMedia')}</span>
</>
}
onClick={toggleCollapseAddMediaMenu}
></Button>
{addedSuccessfully && lastCreatedItem && (
<div className="my-3 breakLongWords">
<FontAwesomeIcon
className="text-purple-400"
icon={faThumbsUp}
></FontAwesomeIcon>{' '}
{lastCreatedItem.type === 'file'
? t('mediaMenu.uploadFinished')
: t('mediaMenu.addingFinished')}
{lastCreatedItem.name}
</div>
)}
</>
)}
</div>
);
}