react-icons/fa#FaSearch TypeScript Examples
The following examples show how to use
react-icons/fa#FaSearch.
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: Header.tsx From twitch-clone with MIT License | 6 votes |
Header: React.FC = () => {
return (
<Container>
<LeftMenu>
<img src="/favicon.svg" alt="Twitch Clone" width="32" height="32" />
<ul>
<li>
<a href="#">Browse</a>
</li>
<li>...</li>
</ul>
</LeftMenu>
<MiddleMenu>
<div>
<input id="search" type="text" placeholder="Search" />
<label aria-label="search" htmlFor="search">
Search
</label>
<FaSearch size={16} />
</div>
</MiddleMenu>
<RightMenu>
<CgCrown size={24} />
<Button buttonType="secondary">Log In</Button>
<Button buttonType="primary">Sign Up</Button>
<BsPerson size={24} color="#fafafa" />
</RightMenu>
</Container>
);
}
Example #2
Source File: index.tsx From pokedex with MIT License | 6 votes |
InputSearch: React.FC<InputSearchProps> = ({ value, onChange }) => {
const [isFocused, setIsFocused] = useState(false);
const handleInputBlur = useCallback(() => {
setIsFocused(false);
}, []);
const handleInputFocus = useCallback(() => {
setIsFocused(true);
}, []);
return (
<Container isFocused={isFocused}>
<FaSearch />
<input
placeholder={isFocused ? '' : 'Qual Pokémon você está procurando?'}
value={value}
onChange={e => onChange(e.target.value)}
onFocus={handleInputFocus}
onBlur={handleInputBlur}
/>
</Container>
);
}
Example #3
Source File: IPForm.tsx From iplocate with MIT License | 6 votes |
IPForm: React.FC<Props> = (props) => {
const { onSubmit } = props;
const [value, setValue] = useState("");
const [error, setError] = useState(false);
const handleSubmit: React.FormEventHandler = (e) => {
e.preventDefault();
if (!validateIp(value)) {
setError(true);
} else {
onSubmit(value);
setValue("");
}
};
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
setValue(e.currentTarget.value);
setError(false);
};
return (
<>
<Form onSubmit={handleSubmit} error={error}>
<Input
value={value}
onChange={handleChange}
placeholder="IP Address"
aria-label="IP Address input"
/>
<button type="submit" aria-label="Search IP Address">
<FaSearch />
</button>
</Form>
{error && <ErrorMessage>Invalid IP Address.</ErrorMessage>}
</>
);
}
Example #4
Source File: columns.tsx From crossfeed with Creative Commons Zero v1.0 Universal | 6 votes |
createColumns: CreateColumns = () => [
{
Header: 'Details',
Cell: ({ row: { original } }: CellProps<Domain>) => (
<Link to={`/inventory/domain/${original.id}`}>
<FaSearch className="margin-x-auto display-block" />
</Link>
)
},
{
Header: 'Organization',
accessor: (e) => e.organization.name,
id: 'organizationName',
Filter: ColumnFilter
},
{
Header: 'Domain',
accessor: 'name',
id: 'reverseName',
Filter: ColumnFilter
},
{
Header: 'IP',
accessor: 'ip',
Filter: ColumnFilter
},
{
Header: 'Ports',
id: 'port',
disableSortBy: true,
accessor: ({ services }) =>
services.map((service) => service.port).join(', '),
Filter: ColumnFilter
},
{
Header: 'Services',
id: 'service',
disableSortBy: true,
accessor: (domain) => getServiceNames(domain),
Filter: ColumnFilter
},
{
Header: 'Vulnerabilities',
id: 'vulnerability',
accessor: (domain) =>
domain.vulnerabilities &&
domain.vulnerabilities
.map((vulnerability) => vulnerability.cve)
.join(', '),
Filter: ColumnFilter
},
{
Header: 'Last Seen',
id: 'updatedAt',
accessor: ({ updatedAt }) =>
`${formatDistanceToNow(parseISO(updatedAt))} ago`,
disableFilters: true
},
{
Header: 'First Seen',
id: 'createdAt',
accessor: ({ createdAt }) =>
`${formatDistanceToNow(parseISO(createdAt))} ago`,
disableFilters: true
}
]
Example #5
Source File: ColumnFilter.tsx From crossfeed with Creative Commons Zero v1.0 Universal | 6 votes |
ColumnFilter: React.FC<Props> = ({
column: { filterValue, setFilter, id }
}) => {
const [search, setSearch] = useState('');
const onSubmit: React.FormEventHandler = (e) => {
e.preventDefault();
setFilter(search);
};
const clear: React.MouseEventHandler = (e) => {
setSearch('');
setFilter('');
};
return (
<form onSubmit={onSubmit} className={classes.root}>
<TextInput
id={id}
name={id}
type="text"
value={search}
onChange={(e) => {
setSearch(e.target.value);
}}
className={classes.input}
/>
<FaSearch className={classes.searchIcon}></FaSearch>
{filterValue && (
<button type="button" className={classes.clearFilter} onClick={clear}>
<FaTimes />
</button>
)}
</form>
);
}
Example #6
Source File: App.tsx From clarity with Apache License 2.0 | 5 votes |
SideMenuItems: (MenuItem | GroupedMenuItem)[] = [
new MenuItem(
Pages.Accounts,
'Accounts',
<IoMdKey fontSize={SideMenuIconSize} />
),
new MenuItem(
Pages.Faucet,
'Faucet',
<IoIosWater fontSize={SideMenuIconSize} />,
false,
FaucetAsterix
),
new MenuItem(
Pages.DeployContracts,
'Deploy Contract',
<IoMdRocket fontSize={SideMenuIconSize} />
),
// new MenuItem(
// Pages.Explorer,
// 'Explorer',
// <FaMapMarkedAlt fontSize={SideMenuIconSize} />
// ),
new MenuItem(Pages.Blocks, 'Blocks', <FiGrid fontSize={SideMenuIconSize} />),
new MenuItem(
Pages.Deploys,
'Deploys',
<FaListUl fontSize={SideMenuIconSize} />
),
new MenuItem(
Pages.Search,
'Search',
<FaSearch fontSize={SideMenuIconSize} />
),
new MenuItem(
Pages.Validators,
'Validators',
<FaUsers fontSize={SideMenuIconSize} />
),
new MenuItem(
Pages.ConnectedPeers,
'Connected Peers',
<FaNetworkWired fontSize={SideMenuIconSize} />
)
// new GroupedMenuItem(
// 'clarityContracts',
// 'Contracts',
// <FaFileContract fontSize={SideMenuIconSize} />,
// [new MenuItem(Pages.Vesting, 'Vesting')]
// )
]
Example #7
Source File: App.tsx From casper-clarity with Apache License 2.0 | 5 votes |
SideMenuItems: (MenuItem | GroupedMenuItem)[] = [
new MenuItem(
Pages.Accounts,
'Accounts',
<IoMdKey fontSize={SideMenuIconSize} />
),
faucetMenuItem,
new MenuItem(
Pages.DeployContracts,
'Deploy Contract',
<IoMdRocket fontSize={SideMenuIconSize} />
),
// new MenuItem(
// Pages.Explorer,
// 'Explorer',
// <FaMapMarkedAlt fontSize={SideMenuIconSize} />
// ),
new MenuItem(Pages.Blocks, 'Blocks', <FiGrid fontSize={SideMenuIconSize} />),
new MenuItem(
Pages.Deploys,
'Deploys',
<FaListUl fontSize={SideMenuIconSize} />
),
new MenuItem(
Pages.Search,
'Search',
<FaSearch fontSize={SideMenuIconSize} />
),
new MenuItem(
Pages.Validators,
'Validators',
<FaUsers fontSize={SideMenuIconSize} />
),
new MenuItem(
Pages.ConnectedPeers,
'Connected Peers',
<FaNetworkWired fontSize={SideMenuIconSize} />
)
// new GroupedMenuItem(
// 'clarityContracts',
// 'Contracts',
// <FaFileContract fontSize={SideMenuIconSize} />,
// [new MenuItem(Pages.Vesting, 'Vesting')]
// )
]
Example #8
Source File: index.tsx From netflix-clone with GNU General Public License v3.0 | 5 votes |
NavBar: React.FC = () => {
const [isBlack, setIsBlack] = useState(false);
useEffect(() => {
window.addEventListener('scroll', () => setIsBlack(window.scrollY > 10));
// Executa quando a pagina for desconstruida
return () => {
window.removeEventListener('scroll', () =>
setIsBlack(window.scrollY > 10),
);
};
}, []);
return (
<Container isBlack={isBlack}>
<RoutesMenu>
<img src={LogoNetflix} alt="dahdjahdkja" />
<ul>
<li style={{ fontWeight: 'bold' }}>Inicio</li>
<li>Series</li>
<li>Filmes</li>
<li>Mais Recentes</li>
<li>Minha Lista</li>
</ul>
</RoutesMenu>
<Profile>
<FaSearch />
<FaGift />
<FaBell />
<button type="button">
<img
src="https://occ-0-761-185.1.nflxso.net/dnm/api/v6/Z-WHgqd_TeJxSuha8aZ5WpyLcX8/AAAABR8DzEDMx6x6rgkSexM2EYh44oQISc8fyEFr6WnraR9_HyniHFDRbXRrElpLThfL9OYFOueAItK7VIEb2xH7AqA.png?r=c71"
alt="imagem profile usuario"
/>
<FaCaretDown />
</button>
</Profile>
</Container>
);
}
Example #9
Source File: AddReferenceWebDrawer.tsx From personal-archive with MIT License | 5 votes |
AddReferenceWebDrawer: FC<Props> = ({show, onConfirm, onCancel}) => {
const [url, setUrl] = useState('')
const clear = () => {
setUrl('')
}
const onClose = () => {
clear()
onCancel()
}
const onSubmit = () => {
if (url.length === 0) {
toast.error('url required')
return
}
if (!url.startsWith('http')) {
toast.error('invalid url')
return
}
clear()
onConfirm(url)
}
return (
<>
<Drawer shown={show} onClose={onClose} title="Add Web Reference">
<InputField
size="small"
value={url}
onChange={e => setUrl((e.target as any).value)}
onKeyDown={e => {
if (e.key === 'Enter') {
onSubmit()
}
}}
suffix={
<span role="button" onClick={onSubmit} style={{ marginRight: '10px' }}>
<FaSearch />
</span>
}
/>
<ButtonWrapper>
<Button onClick={onSubmit} size="small">Add</Button>
</ButtonWrapper>
</Drawer>
</>
)
}
Example #10
Source File: AddReferenceArticleDrawer.tsx From personal-archive with MIT License | 5 votes |
AddReferenceArticleDrawer: FC<Props> = ({show, onConfirm, onCancel}) => {
const [keyword, setKeyword] = useState('')
const [fetching, searchArticles, clear, articles, pagination] = useRequestSearchArticles()
const onSearch = (page: number) => searchArticles(keyword, page)
const onClear = () => {
setKeyword('')
clear()
}
const onClose = () => {
onClear()
onCancel()
}
const onSelect = (article: Article) => {
onClear()
onConfirm(article)
}
return (
<Drawer shown={show} onClose={onClose} title="Add Article Reference">
<InputField
size="small"
value={keyword}
onChange={e => setKeyword((e.target as any).value)}
onKeyDown={e => {
if (e.key === 'Enter') {
onSearch(1)
}
}}
suffix={
<span role="button" onClick={() => onSearch(1)} style={{marginRight: '10px'}}>
<FaSearch/>
</span>
}
/>
{fetching ? <Loading type="boxLoader"/> : null}
{
articles.map((article, i) => (
<ArticleWrapper key={article.id}>
<a href="#!" onClick={() => onSelect(article)}>
{article.title}
</a>
</ArticleWrapper>
))
}
<Pagination
pageCount={pagination.totalPages}
selectedPage={pagination.page}
onPageChange={onSearch}
/>
<div>
<Button onClick={onClose} type="white">Close</Button>
</div>
</Drawer>
)
}
Example #11
Source File: MainLayout.tsx From personal-archive with MIT License | 5 votes |
SearchDrawer: FC<{ show: boolean, onClose: () => void }> = ({show, onClose}) => {
const [keyword, setKeyword] = useState('')
const history = useHistory()
const ref = useRef<HTMLElement>(null)
useEffect(() => {
if (show && ref.current) {
setTimeout(() => ref?.current?.focus(), 100)
}
}, [show])
const onSubmit = () => {
setKeyword('')
onClose()
history.push(`/articles/search?q=${encodeURIComponent(keyword)}`)
}
return (
<Drawer
shown={show}
onClose={() => {
setKeyword('')
onClose()
}}
>
<InputField
ref={ref}
size="small"
value={keyword}
onChange={e => setKeyword((e.target as any).value)}
onKeyDown={e => {
if (e.key === 'Enter') {
onSubmit()
}
}}
onBlur={onClose}
suffix={
<span role="button" onClick={onSubmit} style={{ marginRight: '10px' }}>
<FaSearch />
</span>
}
/>
</Drawer>
)
}
Example #12
Source File: MainLayout.tsx From personal-archive with MIT License | 5 votes |
MainLayout: FC<Props> = ({ side, title, children}) => {
const [showSearchDrawer, setShowSearchDrawer] = useState(false)
const [showNav, setShowNav] = useState(false) // only works in mobile
const history = useHistory()
useEffect(() => {
// 페이지 이동시 초기화
history.listen(() => setShowNav(false))
}, [history])
useSubscribe(ShowSearchDrawer, (isOpened: boolean) => setShowSearchDrawer(isOpened))
const customTokens = getTokens({})
return (
<ThemeProvider theme={{orbit: customTokens}}>
<Parent>
<Helmet>
<title>{getTitle(title)}</title>
</Helmet>
<Header>
<Logo>PA</Logo>
<Menu onClick={() => history.push(`/tags/all`)}>
<FaRegNewspaper size="21px" />
</Menu>
<Menu onClick={() => history.push(`/notes`)}>
<FaRegStickyNote size="21px" />
</Menu>
<Menu onClick={() => setShowSearchDrawer(true)}>
<FaSearch size="21px" />
</Menu>
<Menu onClick={() => history.push(`/settings`)}>
<FaRegSun size="21px" />
</Menu>
<DarkModeSwitch />
</Header>
<Middle>
<Mobile>
<When condition={side != null}>
<Menu onClick={() => setShowNav(true)}>
<MenuHamburger/>
</Menu>
</When>
</Mobile>
</Middle>
<Body>
<Desktop>
<When condition={side != null}>
<Nav>
{side}
</Nav>
</When>
</Desktop>
<Main>
{children}
<SearchDrawer
show={showSearchDrawer}
onClose={() => setShowSearchDrawer(false)}
/>
</Main>
</Body>
<Drawer
shown={showNav}
onClose={() => setShowNav(false)}
>
<Stack>
{side}
</Stack>
</Drawer>
</Parent>
</ThemeProvider>
)
}
Example #13
Source File: InputTypeahead.tsx From hub with Apache License 2.0 | 4 votes |
InputTypeahead = forwardRef((props: Props, ref: Ref<RefInputTypeaheadField>) => {
const inputEl = useRef<HTMLInputElement>(null);
const itemsWrapper = useRef<HTMLDivElement | null>(null);
const [inputValue, setInputValue] = useState('');
const [highlightedText, setHighlightedText] = useState<RegExp | null>(null);
const [highlightedItem, setHighlightedItem] = useState<number | null>(null);
useImperativeHandle(ref, () => ({
reset: () => {
setInputValue('');
},
getValue(): string {
return inputValue;
},
updateValue(newValue: string): void {
setInputValue(newValue);
},
}));
const getVisibleItems = useCallback((): Option[] | null => {
let filteredItems: Option[] = [];
let elements: any[] | null = null;
if (!isNull(highlightedItem)) {
setHighlightedItem(null);
}
if (isUndefined(props.displayItemsInValueLength) || inputValue.length >= props.displayItemsInValueLength) {
filteredItems = props.options.filter((opt: Option) => opt.name.toLowerCase().includes(inputValue.toLowerCase()));
elements = orderBy(
filteredItems,
[
(item: Option) =>
props.selected.hasOwnProperty(item.filterKey) && props.selected[item.filterKey].includes(item.id.toString())
? -1
: 1,
'total',
],
['asc', 'desc']
);
// Scroll top when new visible items are displayed
if (itemsWrapper && itemsWrapper.current) {
itemsWrapper.current.scroll(0, 0);
}
}
return elements;
}, [highlightedItem, props.displayItemsInValueLength, props.options, props.selected, inputValue]);
const getSelectedItems = useCallback((): Option[] => {
let selectedItems: Option[] = [];
Object.keys(props.selected).forEach((fKey: string) => {
props.selected[fKey].forEach((item: string) => {
const selected = props.options.find((opt: Option) => opt.id.toString() === item && opt.filterKey === fKey);
if (!isUndefined(selected)) {
selectedItems.push(selected);
}
});
});
return orderBy(selectedItems, 'total', 'desc');
}, [props.options, props.selected]);
const getOptionName = (name: string): JSX.Element => {
if (!isNull(highlightedText)) {
const stringParts: string[] = compact(name.split(highlightedText));
if (stringParts.length === 1) {
return (
<span
className={classnames({
'fw-bold highlighted': name.toLowerCase() === inputValue.toLowerCase(),
})}
>
{name}
</span>
);
}
return (
<>
{stringParts.map((str: string, index: number) => (
<span
key={`${name}_${index}`}
className={classnames({
'fw-bold highlighted': str.toLowerCase() === inputValue.toLowerCase(),
})}
>
{str}
</span>
))}
</>
);
} else {
return <>{name}</>;
}
};
const [visibleItems, setVisibleItems] = useState<Option[] | null>(null);
const [selectedItems, setSelectedItems] = useState<Option[]>(getSelectedItems());
useEffect(() => {
setVisibleItems(getVisibleItems());
}, [inputValue, props.options]); /* eslint-disable-line react-hooks/exhaustive-deps */
useEffect(() => {
setSelectedItems(getSelectedItems());
}, [getSelectedItems, props.selected]);
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
e.stopPropagation();
e.preventDefault();
setHighlightedItem(null);
setInputValue(e.target.value);
const escapedValue = escapeRegExp(e.target.value.toLowerCase());
setHighlightedText(e.target.value !== '' ? new RegExp(`(${escapedValue})`, 'gi') : null);
};
const onSelect = (filterKey: string, id: string, isSelected: boolean) => {
setHighlightedItem(null);
props.onChange(filterKey, id, !isSelected);
if (props.onChangeSelection) {
props.onChangeSelection();
}
};
const onKeyDown = (e: KeyboardEvent<HTMLInputElement>): void => {
switch (e.key) {
case 'ArrowDown':
updateHighlightedItem('down');
return;
case 'ArrowUp':
updateHighlightedItem('up');
return;
case 'Enter':
if (!isNull(highlightedItem) && visibleItems) {
const item = visibleItems[highlightedItem];
const isSelected =
props.selected.hasOwnProperty(item.filterKey) &&
props.selected[item.filterKey].includes(item.id.toString());
onSelect(item.filterKey, item.id.toString(), isSelected);
}
return;
default:
return;
}
};
const scrollDropdown = (index: number) => {
if (itemsWrapper && itemsWrapper.current) {
const itemsOnScreen = Math.floor(itemsWrapper.current.clientHeight / ITEM_HEIGHT);
if (index + 1 > itemsOnScreen) {
itemsWrapper.current.scroll(0, (index + 1 - itemsOnScreen) * ITEM_HEIGHT);
} else {
itemsWrapper.current.scroll(0, 0);
}
}
};
const updateHighlightedItem = (arrow: 'up' | 'down') => {
if (!isNull(highlightedItem)) {
let newIndex: number = arrow === 'up' ? highlightedItem - 1 : highlightedItem + 1;
if (newIndex > visibleItems!.length - 1) {
newIndex = 0;
}
if (newIndex < 0) {
newIndex = visibleItems!.length - 1;
}
scrollDropdown(newIndex);
setHighlightedItem(newIndex);
} else {
if (visibleItems && visibleItems.length > 0) {
const newIndex = arrow === 'up' ? visibleItems.length - 1 : 0;
scrollDropdown(newIndex);
setHighlightedItem(newIndex);
}
}
};
if (props.options.length === 0) return null;
return (
<>
<div className={`mb-3 input-group-sm ${styles.inputWrapper} ${props.inputWrapperClassName}`}>
<input
ref={inputEl}
type="text"
placeholder={props.placeholder || `Search ${props.label}`}
className={classnames(
'flex-grow-1 form-control',
styles.input,
{ 'ps-3 pe-4': props.searchIcon },
{ 'px-3': isUndefined(props.searchIcon) || !props.searchIcon }
)}
name={`inputTypeahead_${props.label}`}
value={inputValue}
onChange={onChange}
onKeyDown={onKeyDown}
spellCheck="false"
autoFocus={!isUndefined(props.autofocus) && props.autofocus}
/>
{props.searchIcon && <FaSearch className={`text-muted position-absolute ${styles.searchIcon}`} />}
{!isUndefined(props.additionalInfo) && <div className="alert p-0 mt-3">{props.additionalInfo}</div>}
</div>
{selectedItems.length > 0 && props.visibleClear && (
<div className="py-1 border-bottom">
<button
className="btn btn-sm w-100"
onClick={() => {
if (props.onClear) {
props.onClear();
}
}}
aria-label="Clear all"
>
<div className="d-flex flex-row align-items-center text-muted">
<IoIosClose />
<small className="ms-2">Clear all</small>
</div>
</button>
</div>
)}
{visibleItems && (
<>
{visibleItems.length === 0 ? (
<div className={`p-3 text-center ${props.listClassName}`}>
<small className="text-muted">Sorry, no matches found</small>
</div>
) : (
<div className={`${styles.itemsList} ${props.listClassName}`} ref={itemsWrapper}>
{visibleItems.map((opt: Option, index: number) => {
const isSelected =
props.selected.hasOwnProperty(opt.filterKey) &&
props.selected[opt.filterKey].includes(opt.id.toString());
const name = getOptionName(opt.name);
return (
<button
key={`opt_${opt.filterKey}_${opt.id}`}
data-testid="typeaheadDropdownBtn"
className={classnames(
'dropdown-item',
styles.option,
props.optClassName,
{
[styles.selected]: isSelected,
},
{
[styles.highlighted]: index === highlightedItem,
}
)}
onClick={() => {
onSelect(opt.filterKey, opt.id.toString(), isSelected);
if (props.onChangeSelection) {
props.onChangeSelection();
}
}}
aria-label={`${isSelected ? 'Unselect' : 'Select'} option`}
>
<div className="d-flex flex-row align-items-center position-relative">
{isSelected && (
<div className={`position-absolute ${styles.checkMark}`}>
<IoIosCheckmark />
</div>
)}
<InputTypeaheadOptionItem opt={opt} name={name} iconClassName={styles.icon} />
{isSelected && (
<div className={`position-absolute ${styles.close}`}>
<IoIosClose />
</div>
)}
</div>
</button>
);
})}
</div>
)}
</>
)}
</>
);
})
Example #14
Source File: CompareTemplatesList.tsx From hub with Apache License 2.0 | 4 votes |
CompareTemplatesList = (props: Props) => {
const [inputValue, setInputValue] = useState<string>('');
const [visibleTemplates, setVisibleTemplates] = useState<CompareChartTemplate[]>(props.templates || []);
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
e.stopPropagation();
e.preventDefault();
setInputValue(e.target.value);
};
const getStatusIcon = (status: CompareChartTemplateStatus): JSX.Element => {
return (
<>
{(() => {
switch (status) {
case CompareChartTemplateStatus.Deleted:
return (
<div className="text-danger">
<GoDiffRemoved />
</div>
);
case CompareChartTemplateStatus.Added:
return (
<span className="text-success">
<GoDiffAdded />
</span>
);
case CompareChartTemplateStatus.Modified:
return (
<span className={styles.modifiedIcon}>
<GoDiffModified />
</span>
);
default:
return null;
}
})()}
</>
);
};
useEffect(() => {
const getVisibleTemplates = (): CompareChartTemplate[] => {
const tmpls = props.templates || [];
return tmpls.filter((tmpl: CompareChartTemplate) => {
const term = `${tmpl.name} ${tmpl.resourceKinds ? tmpl.resourceKinds.join(' ') : ''}`.toLowerCase();
return term.includes(inputValue.toLowerCase());
});
};
const reviewActiveTemplate = (filteredTemplates: CompareChartTemplate[]) => {
if (filteredTemplates.length === 0 && !isUndefined(props.activeTemplateName)) {
props.onTemplateChange(null);
} else {
if (props.activeTemplateName) {
const activeTemplate = filteredTemplates.find(
(tmpl: CompareChartTemplate) => tmpl.name === props.activeTemplateName
);
if (isUndefined(activeTemplate)) {
props.onTemplateChange(filteredTemplates[0]);
}
} else {
props.onTemplateChange(filteredTemplates[0]);
}
}
};
if (inputValue === '') {
setVisibleTemplates(props.templates || []);
if (isUndefined(props.activeTemplateName) && props.templates) {
props.onTemplateChange(props.templates[0]);
}
} else {
const filteredTemplates = getVisibleTemplates();
reviewActiveTemplate(filteredTemplates);
setVisibleTemplates(filteredTemplates);
}
}, [inputValue, props.templates]); /* eslint-disable-line react-hooks/exhaustive-deps */
if (isNull(props.templates) || isUndefined(props.templates)) return null;
return (
<div className="h-100 d-flex flex-column overflow-auto pe-2">
<div className="position-relative w-100">
<div className="mb-3 input-group-sm">
<input
type="text"
placeholder="Search by template or resource kind"
className={`flex-grow-1 form-control ps-3 pe-4 ${styles.input}`}
name="CompareChartTemplateInput"
value={inputValue}
onChange={onChange}
spellCheck="false"
disabled={isUndefined(props.templates) || props.templates.length === 0}
/>
<FaSearch className={`text-muted position-absolute ${styles.searchIcon}`} />
</div>
</div>
{visibleTemplates.length === 0 ? (
<div
className={`alert alert-dark p-2 text-center ${styles.alert}`}
role="alert"
aria-live="assertive"
aria-atomic="true"
>
<small className="text-muted">Sorry, no matches found</small>
</div>
) : (
<>
{visibleTemplates.map((template: CompareChartTemplate, index: number) => {
const isActive: boolean =
!isUndefined(props.activeTemplateName) && props.activeTemplateName === template.name;
return (
<div key={`template_${index}`}>
<button
className={classnames('btn btn-light btn-sm mb-2 text-start w-100', styles.btn, {
[`activeTemplate ${styles.active}`]: isActive,
})}
onClick={() => {
if (!isActive) {
props.onTemplateChange(template);
}
}}
aria-label={`Show template ${template.name}`}
aria-pressed={isActive}
>
<div className="d-flex flex-column">
{(() => {
switch (template.type) {
case ChartTmplTypeFile.Template:
return (
<>
<div className="d-flex flex-row align-items-baseline mb-1">
<div className={styles.legend}>
<small className="text-muted text-uppercase">Template:</small>
</div>
<div className={`text-truncate ${styles.templateName}`}>{template.name}</div>
<div className="ps-2 ms-auto">{getStatusIcon(template.status)}</div>
</div>
<div className="d-flex flex-row mb-1">
<div className={styles.legend}>
<small className="text-muted text-uppercase">Resource:</small>
</div>
{template.resourceKinds && template.resourceKinds.length > 0 ? (
<>
{template.resourceKinds.length > 1 ? (
<>
<ResourceLabel text="Multiple kinds" />
</>
) : (
<ResourceLabel text={template.resourceKinds[0]} />
)}
</>
) : (
<>-</>
)}
</div>
</>
);
case ChartTmplTypeFile.Helper:
return (
<div className="d-flex flex-row align-items-baseline mb-1">
<div className={styles.legend}>
<small className="text-muted text-uppercase">Helper:</small>
</div>
<div className={`text-truncate ${styles.templateName}`}>{template.name}</div>
<div className="ps-2 ms-auto">{getStatusIcon(template.status)}</div>
</div>
);
}
})()}
</div>
</button>
</div>
);
})}
</>
)}
</div>
);
}
Example #15
Source File: TemplatesList.tsx From hub with Apache License 2.0 | 4 votes |
TemplatesList = (props: Props) => {
const [inputValue, setInputValue] = useState<string>('');
const [visibleTemplates, setVisibleTemplates] = useState<ChartTemplate[]>(props.templates || []);
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
e.stopPropagation();
e.preventDefault();
setInputValue(e.target.value);
};
useEffect(() => {
const getVisibleTemplates = (): ChartTemplate[] => {
const tmpls = props.templates || [];
return tmpls.filter((tmpl: ChartTemplate) => {
const term = `${tmpl.name} ${tmpl.resourceKinds ? tmpl.resourceKinds.join(' ') : ''}`.toLowerCase();
return term.includes(inputValue.toLowerCase());
});
};
const reviewActiveTemplate = (filteredTemplates: ChartTemplate[]) => {
if (filteredTemplates.length === 0 && !isUndefined(props.activeTemplateName)) {
props.onTemplateChange(null);
} else {
if (props.activeTemplateName) {
const activeTemplate = filteredTemplates.find(
(tmpl: ChartTemplate) => tmpl.name === props.activeTemplateName
);
if (isUndefined(activeTemplate)) {
props.onTemplateChange(filteredTemplates[0]);
}
} else {
props.onTemplateChange(filteredTemplates[0]);
}
}
};
if (inputValue === '') {
setVisibleTemplates(props.templates || []);
if (isUndefined(props.activeTemplateName) && !isNull(props.templates)) {
props.onTemplateChange(props.templates[0]);
}
} else {
const filteredTemplates = getVisibleTemplates();
reviewActiveTemplate(filteredTemplates);
setVisibleTemplates(filteredTemplates);
}
}, [inputValue]); /* eslint-disable-line react-hooks/exhaustive-deps */
if (isNull(props.templates)) return null;
return (
<div className="h-100 d-flex flex-column overflow-auto pe-2">
<div className="position-relative w-100">
<div className="mb-3 input-group-sm">
<input
type="text"
placeholder="Search by template or resource kind"
className={`flex-grow-1 form-control ps-3 pe-4 ${styles.input}`}
name="chartTemplateInput"
value={inputValue}
onChange={onChange}
spellCheck="false"
/>
<FaSearch className={`text-muted position-absolute ${styles.searchIcon}`} />
<div className="alert p-0 mt-3">
<small className="text-muted text-break fst-italic">
This chart version contains <span className="fw-bold">{props.templates.length}</span>{' '}
{props.templates.length === 1 ? 'template' : 'templates'}
</small>
</div>
</div>
</div>
{visibleTemplates.length === 0 ? (
<div
className={`alert alert-dark p-2 text-center ${styles.alert}`}
role="alert"
aria-live="assertive"
aria-atomic="true"
>
<small className="text-muted">Sorry, no matches found</small>
</div>
) : (
<>
{visibleTemplates.map((template: ChartTemplate, index: number) => {
const isActive: boolean =
!isUndefined(props.activeTemplateName) && props.activeTemplateName === template.name;
return (
<div key={`template_${index}`}>
<button
className={classnames('btn btn-light btn-sm mb-2 text-start w-100', styles.btn, {
[`activeTemplate ${styles.active}`]: isActive,
})}
onClick={() => {
if (!isActive) {
props.onTemplateChange(template);
}
}}
aria-label={`Show template ${template.name}`}
aria-pressed={isActive}
>
<div className="d-flex flex-column">
{(() => {
switch (template.type) {
case ChartTmplTypeFile.Template:
return (
<>
<div className="d-flex flex-row align-items-baseline mb-1">
<div className={styles.legend}>
<small className="text-muted text-uppercase">Template:</small>
</div>
<div className={`text-truncate ${styles.templateName}`}>{template.name}</div>
</div>
<div className="d-flex flex-row mb-1">
<div className={styles.legend}>
<small className="text-muted text-uppercase">Resource:</small>
</div>
{template.resourceKinds && template.resourceKinds.length > 0 ? (
<>
{template.resourceKinds.length > 1 ? (
<>
<ResourceLabel text="Multiple kinds" />
</>
) : (
<ResourceLabel text={template.resourceKinds[0]} />
)}
</>
) : (
<>-</>
)}
</div>
</>
);
case ChartTmplTypeFile.Helper:
return (
<div className="d-flex flex-row align-items-baseline mb-1">
<div className={styles.legend}>
<small className="text-muted text-uppercase">Helper:</small>
</div>
<div className={`text-truncate ${styles.templateName}`}>{template.name}</div>
</div>
);
}
})()}
</div>
</button>
</div>
);
})}
</>
)}
</div>
);
}
Example #16
Source File: ContentDefaultModal.tsx From hub with Apache License 2.0 | 4 votes |
ContentDefaultModal = (props: Props) => {
const history = useHistory();
const anchor = useRef<HTMLDivElement>(null);
const [openStatus, setOpenStatus] = useState<boolean>(false);
const [selectedItem, setSelectedItem] = useState<any | null>(null);
const [isChangingSelectedItem, setIsChangingSelectedItem] = useState<boolean>(false);
const [code, setCode] = useState<string | undefined>(undefined);
const [inputValue, setInputValue] = useState<string>('');
const [visibleFiles, setVisibleFiles] = useState<any[]>(props.files || []);
const [currentPkgId, setCurrentPkgId] = useState<string>(props.packageId);
const onItemChange = (file: any | null) => {
setIsChangingSelectedItem(true);
setSelectedItem(file);
updateUrl(file ? file.name.toLowerCase() : undefined);
const getContent = (): string | undefined => {
let content: string | undefined;
switch (props.kind) {
case ContentDefaultModalKind.CustomResourcesDefinition:
if (!isNull(file) && !isUndefined(file.example)) {
content = stringify(file.example, { sortMapEntries: true });
}
break;
default:
content = file.file;
break;
}
return content;
};
if (!isNull(file)) {
setCode(getContent());
if (anchor && anchor.current) {
anchor.current.scrollIntoView({
block: 'start',
inline: 'nearest',
behavior: 'smooth',
});
}
} else {
setCode(undefined);
}
setIsChangingSelectedItem(false);
};
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
e.stopPropagation();
e.preventDefault();
setInputValue(e.target.value);
};
useEffect(() => {
const getVisibleFiles = (): any[] => {
return props.files!.filter((file: any) => {
const term = `${file.name} ${file.kind || ''}`.toLowerCase();
return term.includes(inputValue.toLowerCase());
});
};
const reviewActiveFile = (currentFilteredFiles: any[][]) => {
if (currentFilteredFiles.length === 0 && !isUndefined(selectedItem)) {
onItemChange(null);
} else {
if (selectedItem) {
const activeFile = currentFilteredFiles.find((file: any) => file === selectedItem);
if (isUndefined(activeFile)) {
onItemChange(currentFilteredFiles[0]);
}
} else {
onItemChange(currentFilteredFiles[0]);
}
}
};
if (props.files && props.files.length > 0) {
if (inputValue === '') {
setVisibleFiles(props.files);
if (isUndefined(selectedItem)) {
onItemChange(props.files[0]);
}
} else {
const filteredFiles = getVisibleFiles();
reviewActiveFile(filteredFiles);
setVisibleFiles(filteredFiles);
}
}
}, [inputValue]); /* eslint-disable-line react-hooks/exhaustive-deps */
const updateUrl = (fileName?: string) => {
history.replace({
search: `?modal=${props.modalName}${fileName ? `&file=${fileName}` : ''}`,
state: { searchUrlReferer: props.searchUrlReferer, fromStarredPage: props.fromStarredPage },
});
};
const cleanUrl = () => {
history.replace({
search: '',
state: { searchUrlReferer: props.searchUrlReferer, fromStarredPage: props.fromStarredPage },
});
};
useEffect(() => {
if (props.visibleModal && !openStatus && props.files && props.files.length > 0) {
onOpenModal();
}
}, []); /* eslint-disable-line react-hooks/exhaustive-deps */
useEffect(() => {
if (props.packageId !== currentPkgId) {
setCurrentPkgId(props.packageId);
if (openStatus) {
setOpenStatus(false);
} else if (!openStatus && props.visibleModal) {
onOpenModal();
}
}
}, [props.packageId]); /* eslint-disable-line react-hooks/exhaustive-deps */
if (isUndefined(props.files) || props.files.length === 0) return null;
const getSelectedFileName = (): string => {
switch (props.kind) {
case ContentDefaultModalKind.CustomResourcesDefinition:
return `${props.normalizedName}-${selectedItem.kind}.yaml`;
case ContentDefaultModalKind.Rules:
return `${props.normalizedName}-${selectedItem.name.replace('.yaml', '')}.yaml`;
case ContentDefaultModalKind.Policy:
return `${props.normalizedName}-${selectedItem.name}`;
}
};
const onOpenModal = () => {
if (props.files && props.files.length > 0) {
setVisibleFiles(props.files);
let currentActiveFile = props.files[0];
if (props.visibleFile) {
const visibleFile = props.files.find((file: any) => file.name.toLowerCase() === props.visibleFile);
if (visibleFile) {
currentActiveFile = visibleFile;
}
}
onItemChange(currentActiveFile);
setOpenStatus(true);
} else {
cleanUrl();
}
};
const onCloseModal = () => {
setOpenStatus(false);
setSelectedItem(null);
setCode(undefined);
setInputValue('');
cleanUrl();
};
return (
<div className="mb-2">
<div className="text-center">
<button
className="btn btn-outline-secondary btn-sm text-nowrap w-100"
onClick={onOpenModal}
aria-label={`Open ${props.title} modal`}
disabled={isUndefined(props.files) || props.files.length === 0}
>
{props.btnModalContent}
</button>
</div>
{openStatus && (
<Modal
modalDialogClassName={styles.modalDialog}
modalClassName="h-100"
header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>{props.title}</div>}
onClose={onCloseModal}
open={openStatus}
breakPoint="md"
footerClassName={styles.modalFooter}
>
<div className="h-100 mw-100">
<div className="d-flex flex-row align-items-stretch g-0 h-100 mh-100">
<div className="col-3 h-100 overflow-auto">
<div className="position-relative w-100 pe-2">
<div className="mb-3 input-group-sm">
<input
type="text"
placeholder={`Search by name ${
props.kind === ContentDefaultModalKind.CustomResourcesDefinition ? 'or resource kind' : ''
}`}
className={`flex-grow-1 form-control ps-3 pe-4 ${styles.input}`}
name="contentDefaultModalInput"
value={inputValue}
onChange={onChange}
spellCheck="false"
/>
<FaSearch className={`text-muted position-absolute ${styles.searchIcon}`} />
<div className="alert p-0 mt-3">
<small className="text-muted text-break fst-italic">
This package version contains <span className="fw-bold">{props.files.length}</span>{' '}
{FILE_TYPE[props.kind][props.files.length === 1 ? 'singular' : 'plural']}
</small>
</div>
</div>
</div>
{visibleFiles.length === 0 ? (
<div
className="alert alert-dark p-2 text-center"
role="alert"
aria-live="assertive"
aria-atomic="true"
>
<small className="text-muted">Sorry, no matches found</small>
</div>
) : (
<div className="pe-2">
{visibleFiles.map((file: any, index: number) => {
const isActive = selectedItem === file;
return (
<button
key={`file_${file.name}_${index}`}
className={classnames('btn btn-light btn-sm mb-2 text-start w-100', styles.btn, {
[`activeTemplate ${styles.active}`]: isActive,
})}
onClick={() => {
if (!isActive) {
onItemChange(file);
}
}}
aria-label={`Show ${props.title} ${file.name}`}
aria-pressed={isActive}
>
<div className="d-flex flex-column align-self-center">
{(() => {
switch (props.kind) {
case ContentDefaultModalKind.CustomResourcesDefinition:
const resource = file as CustomResourcesDefinition;
return (
<>
<div className="d-flex flex-row align-items-baseline my-1">
<div className={styles.legend}>
<small className="text-muted text-uppercase">Kind:</small>
</div>
<span className={`text-truncate border fw-bold ${styles.label}`}>
{resource.kind}
</span>
</div>
<div className="d-flex flex-row align-items-baseline mb-1">
<div className={styles.legend}>
<small className="text-muted text-uppercase">Version:</small>
</div>
<div className={`text-truncate ${styles.btnItemContent}`}>
{resource.version}
</div>
</div>
</>
);
default:
return (
<div className="d-flex flex-row align-items-baseline mb-1">
<div>
<small className="text-muted text-uppercase me-2">Name:</small>
</div>
<div className={`text-truncate ${styles.btnItemContent}`}>{file.name}</div>
</div>
);
}
})()}
</div>
</button>
);
})}
</div>
)}
</div>
<div className="col-9 ps-3 h-100">
<div className={`position-relative h-100 mh-100 border ${styles.templateWrapper}`}>
{isChangingSelectedItem && <Loading />}
<div className="d-flex flex-column h-100">
{!isNull(selectedItem) && (
<>
{(() => {
switch (props.kind) {
case ContentDefaultModalKind.CustomResourcesDefinition:
return (
<div className={`p-3 border-bottom ${styles.extraInfo}`}>
<div className="h6 fw-bold">{selectedItem.displayName || selectedItem.name}</div>
<div className="d-flex flex-row align-items-baseline mb-1">
<div className={styles.legend}>
<small className="text-muted text-uppercase">Name:</small>
</div>
<div className={`text-truncate ${styles.btnItemContent}`}>{selectedItem.name}</div>
</div>
<div className="d-flex flex-row align-items-baseline mb-1">
<div className={styles.legend}>
<small className="text-muted text-uppercase">Description:</small>
</div>
<div className={styles.btnItemContent}>
{selectedItem.description.replace(/\n/g, ' ')}
</div>
</div>
</div>
);
default:
return null;
}
})()}
</>
)}
<div className="position-relative flex-grow-1 overflow-hidden h-100">
{visibleFiles.length > 0 && (
<>
{code && !isNull(selectedItem) ? (
<>
<BlockCodeButtons filename={getSelectedFileName()} content={code} />
<div className={`position-relative overflow-auto h-100 ${styles.fileWrapper}`}>
<div className={`position-absolute ${styles.anchor}`} ref={anchor} />
<SyntaxHighlighter
language={props.language}
style={docco}
customStyle={{
backgroundColor: 'transparent',
padding: '1.5rem',
lineHeight: '1.25rem',
marginBottom: '0',
height: '100%',
fontSize: '80%',
overflow: 'initial',
color: '#636a6e',
}}
lineNumberStyle={{
color: 'var(--color-black-25)',
marginRight: '5px',
fontSize: '0.8rem',
}}
showLineNumbers
>
{code}
</SyntaxHighlighter>
</div>
</>
) : (
<div className="fst-italic d-flex align-items-center justify-content-center h-100 h3">
No example provided
</div>
)}
</>
)}
</div>
</div>
</div>
</div>
</div>
</div>
</Modal>
)}
</div>
);
}
Example #17
Source File: InviteMembers.tsx From convoychat with GNU General Public License v3.0 | 4 votes |
InviteMembers: React.FC<IInviteMembers> = ({ roomId }) => {
const [selectedMembers, setSelectedMembers] = useState<any>({});
const { state, dispatch } = useModalContext();
const { register, handleSubmit, errors: formErrors } = useForm<Inputs>();
const onSubmit = async (data: Inputs) => {};
const { data: allUsers } = useListUsersQuery();
const [
createInvitationLink,
{ data: invitationLink },
] = useCreateInvitationLinkMutation({});
const [inviteMembers, { loading: isLoading }] = useInviteMembersMutation();
const toggleMemberSelection = (member: IMember) => {
if (selectedMembers[member.id]) {
let copy = { ...selectedMembers };
delete copy[member.id];
setSelectedMembers({ ...copy });
} else {
setSelectedMembers({ ...selectedMembers, [member.id]: member });
}
};
const closeModal = () => {
dispatch({ type: "CLOSE", modal: "InviteMembers" });
};
useEffect(() => {
if (state.isInviteMembersModalOpen) {
createInvitationLink({ variables: { roomId } });
}
}, [state.isInviteMembersModalOpen, roomId]);
const selectedMembersIds = Object.keys(selectedMembers);
return (
<Modal
closeTimeoutMS={300}
isOpen={state.isInviteMembersModalOpen}
onRequestClose={closeModal}
contentLabel="Create New Room"
className="ModalContent"
overlayClassName="ModalOverlay"
>
<h2>Invite Members</h2>
<small className="textcolor--gray">yeah... yeah spam them</small>
<Spacer gap="huge" />
<Input
type="text"
icon={FaLink}
postfixIcon={FaCopy}
placeholder="invitation link"
defaultValue={invitationLink?.invitation?.link}
onPostfixIconClick={e => copyToClipboard(e.value)}
label={
<span>
Copy Invitation Link{" "}
<span className="textcolor--gray">(expires after 24hours)</span>
</span>
}
/>
<Spacer gap="large" />
<div>
<Input
type="text"
name="username"
label="Find Users"
placeholder="bear grylls"
icon={FaSearch}
errors={formErrors}
inputRef={register({ required: "Username is required" })}
/>
{allUsers && (
<MemberSelector
members={allUsers?.users}
selectedMembers={selectedMembers}
onMemberClick={toggleMemberSelection}
/>
)}
<Spacer gap="xlarge" />
<ButtonGroup gap="medium" float="right">
<Button onClick={closeModal} variant="danger" icon={FaTimes}>
Cancel
</Button>
<Button
icon={FaPaperPlane}
isLoading={isLoading}
disabled={selectedMembersIds.length < 1}
onClick={() => {
inviteMembers({
variables: { roomId, members: selectedMembersIds },
});
}}
>
Invite members ({selectedMembersIds.length})
</Button>
</ButtonGroup>
</div>
</Modal>
);
}