@headlessui/react#Listbox TypeScript Examples
The following examples show how to use
@headlessui/react#Listbox.
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: SelectHeader.tsx From yet-another-generic-startpage with MIT License | 6 votes |
HeaderButton = styled(Listbox.Button)<Pick<SelectHeaderProps, "open">>`
${({ theme: { space, color }, open }) => css`
height: calc(${space.medium} * 2);
padding: 0 ${space.small};
width: 100%;
display: inline-flex;
align-items: center;
cursor: pointer;
color: inherit;
background-color: transparent;
outline: none;
border: none;
border: ${color.fg.base} solid ${space.smallest};
> svg {
height: 1.2rem;
}
:hover {
background-color: ${color.bg.highlight};
}
:focus-visible {
background: ${color.bg.highlight};
border-color: ${color.primary.base};
}
${open &&
css`
border-color: ${color.primary.base};
`}
`}
`
Example #2
Source File: Select.tsx From yet-another-generic-startpage with MIT License | 6 votes |
Select = ({
value,
placeholder,
onChange,
options,
label,
}: SelectProps) => {
const currentOption = getOptionByValue(options, value)
return (
<Wrapper>
<Label label={label}>
<Listbox value={currentOption?.value} onChange={onChange}>
{({ open }) => (
<>
<SelectHeader
label={currentOption?.label || placeholder}
open={open}
/>
<SelectOptions options={options} />
</>
)}
</Listbox>
</Label>
</Wrapper>
)
}
Example #3
Source File: SelectOptions.tsx From yet-another-generic-startpage with MIT License | 6 votes |
StyledOptions = styled(Listbox.Options)`
${({ theme: { color, space } }) => css`
position: absolute;
width: 100%;
padding: 0;
margin: 0;
color: ${color.fg.surface};
background-color: ${color.bg.surface};
outline: none;
z-index: 10;
box-shadow: 0 0 ${space.small} ${color.bg.shade};
`}
`
Example #4
Source File: index.tsx From interbtc-ui with Apache License 2.0 | 6 votes |
SelectLabel = ({ className, ...rest }: SelectLabelProps): JSX.Element => (
<Listbox.Label
className={clsx(
{ 'text-interlayTextSecondaryInLightMode': process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT },
{ 'dark:text-kintsugiTextSecondaryInDarkMode': process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA },
className
)}
{...rest}
/>
)
Example #5
Source File: index.tsx From interbtc-ui with Apache License 2.0 | 6 votes |
SelectOption = ({ value, className, ...rest }: SelectOptionProps): JSX.Element => (
<Listbox.Option
className={({ active }) =>
clsx(
active ? clsx('text-white', 'bg-interlayDenim') : 'text-textPrimary',
'cursor-default',
'select-none',
'relative',
'py-2',
'pl-3',
'pr-9',
className
)
}
value={value}
{...rest}
/>
)
Example #6
Source File: select.tsx From marina with MIT License | 5 votes |
Select: React.FC<Props> = ({ list, selected, onSelect, disabled, onClick }) => {
return (
<Listbox value={selected} onChange={onSelect} disabled={disabled}>
{({ open }) => (
<>
<div
onClick={() => {
if (onClick) onClick();
}}
>
<Listbox.Button className="border-primary ring-primary focus:ring-primary focus:border-primary focus:outline-none flex flex-row justify-between w-full px-3 py-2.5 border-2 rounded-md">
<span className="font-md text-sm">{selected}</span>
{open ? (
<img src="assets/images/chevron-up.svg" alt="chevron" />
) : (
<img
className="transform -rotate-90"
src="assets/images/chevron-left.svg"
alt="chevron"
/>
)}
</Listbox.Button>
</div>
{open && (
<div>
<Listbox.Options
className="focus:outline-none px-3 py-2 text-left rounded-md shadow-lg"
static
>
{list.map((item) => (
<Listbox.Option
className="focus:outline-none py-3 cursor-pointer"
key={item}
value={item}
>
{item}
</Listbox.Option>
))}
</Listbox.Options>
</div>
)}
</>
)}
</Listbox>
);
}
Example #7
Source File: Nav.tsx From vignette-web with MIT License | 5 votes |
// en: `ENG`,
// ja: `日本`,
// ko: `한국`,
// 'zh-CN': `中国`,
// 'zh-TW': `中国`,
// fil: `FIL`,
// fr: `FR`,
// id: `IDN`,
// de: `DE`,
// it: `IT`,
// nl: `NL`,
function MyListbox({ router }: { router: NextRouter }) {
const [selectedLocale, setSelectedLocale] = useState(router.locale)
return (
<div>
<Listbox
value={selectedLocale}
onChange={(selected) => {
setSelectedLocale(selected)
setCookies(`NEXT_LOCALE`, selected)
router.push(router.asPath, undefined, {
locale: selected,
})
}}
>
<Listbox.Button className="relative flex w-full cursor-default items-center rounded-lg bg-transparent pl-1 text-left text-sm font-semibold outline-none sm:font-normal">
<ReactCountryFlag
countryCode={locales[selectedLocale as string].flag}
svg
/>
<span className="mx-1">
{locales[selectedLocale as string].shortName}
</span>
<BiChevronDown />
</Listbox.Button>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="w-18 absolute z-100 mt-1 max-h-96 overflow-auto rounded-md border bg-white text-black shadow-lg focus:outline-none dark:border-neutral-700 dark:bg-[#181a1b] dark:text-white">
{Object.keys(locales).map((key) => (
/* Use the `active` state to conditionally style the active option. */
/* Use the `selected` state to conditionally style the selected option. */
<Listbox.Option key={key} value={key} as={Fragment}>
{({ active, selected }) => (
<li
className={`flex cursor-default items-center px-2 py-1 sm:px-1 lg:py-0 ${
active
? `bg-gray-100 dark:bg-neutral-700 `
: `bg-white dark:bg-[#181a1b]`
}`}
>
<ReactCountryFlag countryCode={locales[key].flag} svg />
<span className="mx-1 text-sm text-black dark:text-white">
{locales[key].name}
</span>
{selected && (
<AiOutlineCheck className="fill-black dark:fill-white" />
)}
</li>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</Listbox>
</div>
)
}
Example #8
Source File: BlogNav.tsx From vignette-web with MIT License | 5 votes |
// en: `ENG`,
// ja: `日本`,
// ko: `한국`,
// 'zh-CN': `中国`,
// 'zh-TW': `中国`,
// fil: `FIL`,
// fr: `FR`,
// id: `IDN`,
// de: `DE`,
// it: `IT`,
// nl: `NL`,
function MyListbox({ router }: { router: NextRouter }) {
const [selectedLocale, setSelectedLocale] = useState(router.locale)
return (
<div>
<Listbox
value={selectedLocale}
onChange={(selected) => {
setSelectedLocale(selected)
setCookies(`NEXT_LOCALE`, selected)
router.push(router.asPath, undefined, {
locale: selected,
})
}}
>
<Listbox.Button className="relative flex w-full cursor-default items-center rounded-lg bg-transparent pl-1 text-left text-sm font-semibold outline-none sm:font-normal">
<ReactCountryFlag
countryCode={locales[selectedLocale as string].flag}
svg
/>
<span className="mx-1">
{locales[selectedLocale as string].shortName}
</span>
<BiChevronDown />
</Listbox.Button>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="w-18 absolute z-100 mt-1 max-h-96 overflow-auto rounded-md border bg-white text-black shadow-lg focus:outline-none dark:border-neutral-700 dark:bg-[#181a1b] dark:text-white">
{Object.keys(locales).map((key) => (
/* Use the `active` state to conditionally style the active option. */
/* Use the `selected` state to conditionally style the selected option. */
<Listbox.Option key={key} value={key} as={Fragment}>
{({ active, selected }) => (
<li
className={`flex cursor-default items-center px-2 py-1 sm:px-1 lg:py-0 ${
active
? `bg-gray-100 dark:bg-neutral-700 `
: `bg-white dark:bg-[#181a1b]`
}`}
>
<ReactCountryFlag countryCode={locales[key].flag} svg />
<span className="mx-1 text-sm text-black dark:text-white">
{locales[key].name}
</span>
{selected && (
<AiOutlineCheck className="fill-black dark:fill-white" />
)}
</li>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</Listbox>
</div>
)
}
Example #9
Source File: DropdownMenu.tsx From sdk with ISC License | 5 votes |
export default function DropdownMenu({title, selectedItem, setSelectedItem, items}: DropdownMenuProps) {
return(
<div className={"flex items-center justify-center"}>
<div className={"w-60 max-w-xs"}>
<Listbox value={selectedItem} onChange={setSelectedItem} as={"div"} className={"space-y-1"}>
{({open}) => (
<>
<Listbox.Label className={"block text-sm font-medium"}>{title}</Listbox.Label>
<div className={"relative"}>
<span className={"inline-block w-full rounded-md"}>
<Listbox.Button
className={classNames(
"cursor-default relative w-full",
"py-2 pl-3 pr-10 text-center",
"rounded-md shadow-md",
"sm:text-sm",
"focus:outline-none focus-visible:ring-2",
"focus-visible:ring-opacity-75 focus-visible:ring-white",
"focus-visible:ring-offset-2 focus-visible:border-indigo-500"
)}
>
<span className={"block truncate text-lg"}>{selectedItem?.label || ""}</span>
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<SelectorIcon className="w-5 h-5 text-gray-400" aria-hidden="true"/>
</span>
</Listbox.Button>
</span>
<Transition
// as={Fragment}
show={open}
unmount={false}
enter="transition duration-100 ease-in"
enterFrom="transform opacity-0"
enterTo="transform opacity-100"
leave="transition duration-75 ease-out"
leaveFrom="transform opacity-100"
leaveTo="transform opacity-0"
className={"absolute mt-1 w-full rounded-md dark:bg-gray-600"}
>
<Listbox.Options static className={"z-10 overflow-auto max-h-60 sm:text-sm"}>
{items.map((item) => {
const selected = item.key === selectedItem.key;
return(<Listbox.Option
key={item.key}
value={item}
disabled={item.disabled || selected}
>
{({ active }) => (
<div className={classNames(
"cursor-default select-none relative",
active ? "bg-blue-500" : ""
)}>
<span
className={classNames(
selected ? "font-semibold" : "font-normal",
"block truncate"
)}
>
{item.label}
</span>
</div>
)}
</Listbox.Option>
)})}
</Listbox.Options>
</Transition>
</div>
</>
)}
</Listbox>
</div>
</div>
)
}
Example #10
Source File: VariantSelectButton.tsx From Meshtastic with GNU General Public License v3.0 | 5 votes |
VariantSelectButton = ({
options,
}: VariantSelectButtonProps): JSX.Element => {
const [selected, setSelected] = useState(options[options.length - 1]);
return (
<Listbox value={selected} onChange={setSelected}>
{({ open }) => (
<>
<div className="relative select-none">
<Listbox.Button as={Fragment}>
<motion.button
whileHover={{ backgroundColor: 'var(--tertiary)' }}
whileTap={{ scale: 0.99 }}
className="relative -mt-5 ml-2 flex w-fit gap-1 rounded-lg bg-secondary p-2 py-2 pl-3 pr-10 text-lg font-medium leading-6 shadow-md md:mt-2"
>
<span className="block truncate">{selected.name}</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<HiSelector
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</span>
</motion.button>
</Listbox.Button>
<Transition
show={open}
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-primary py-1 shadow-md ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{options.map((variant, index) => (
<Listbox.Option
key={index}
className={({ active }) =>
`relative cursor-default select-none py-2 pl-3 pr-9 ${
active ? 'bg-secondary' : ''
}`
}
value={variant}
>
{({ selected, active }) => (
<>
<span
className={`block truncate ${
selected ? 'font-semibold' : 'font-normal'
}`}
>
{variant.name}
</span>
{selected ? (
<span
className={`absolute inset-y-0 right-0 flex items-center pr-4 ${
active ? '' : 'text-primaryInv'
}`}
>
<FiCheck className="h-5 w-5" aria-hidden="true" />
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</>
)}
</Listbox>
);
}
Example #11
Source File: index.tsx From interbtc-ui with Apache License 2.0 | 5 votes |
Select = ({ value, onChange, children }: SelectProps): JSX.Element => {
return (
<Listbox value={value} onChange={onChange}>
{children}
</Listbox>
);
}
Example #12
Source File: index.tsx From interbtc-ui with Apache License 2.0 | 5 votes |
SelectOptions = ({ open, className, variant = SELECT_VARIANTS.optionSelector, ...rest }: SelectOptionsProps): JSX.Element => ( <Transition show={open} as={React.Fragment} leave={clsx('transition', 'ease-in', 'duration-100')} leaveFrom='opacity-100' leaveTo='opacity-0' > <Listbox.Options static className={clsx( 'absolute', 'z-interlaySpeedDial', 'mt-1', 'w-full', 'bg-white', 'max-h-56', 'rounded', 'py-1', 'text-base', 'ring-1', 'ring-black', 'ring-opacity-25', 'dark:ring-white', 'dark:ring-opacity-25', 'overflow-auto', 'focus:outline-none', 'sm:text-sm', { [clsx('bg-white')]: process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT }, { [clsx('dark:bg-kintsugiMidnight')]: process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA }, { [clsx('dark:bg-kintsugiMidnight-900')]: process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA && variant === SELECT_VARIANTS.formField }, className )} {...rest} /> </Transition> )
Example #13
Source File: index.tsx From interbtc-ui with Apache License 2.0 | 5 votes |
SelectButton = ({
className,
children,
variant = 'optionSelector',
error,
...rest
}: SelectButtonProps): JSX.Element => (
<Listbox.Button
className={clsx(
'focus:outline-none',
'focus:ring',
'focus:ring-opacity-50',
'relative',
'w-full',
BORDER_CLASSES,
'rounded-md',
'pl-3',
'pr-10',
'py-2',
'text-left',
'cursor-default',
'leading-7',
{
[clsx('bg-white', 'focus:border-interlayDenim-300', 'focus:ring-interlayDenim-200')]:
process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT
},
{
[clsx(
'dark:bg-kintsugiMidnight-900',
'dark:focus:border-kintsugiSupernova-300',
'dark:focus:ring-kintsugiSupernova-200'
)]: process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA
},
{
[clsx('dark:bg-kintsugiMidnight')]: variant === SELECT_VARIANTS.formField
},
{
[clsx(
{ 'border-interlayCinnabar': process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT },
{ 'dark:border-kintsugiThunderbird': process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA }
)]: error
},
className
)}
{...rest}
>
{children}
<span
className={clsx(
'ml-3',
'absolute',
'inset-y-0',
'right-0',
'flex',
'items-center',
'pr-2',
'pointer-events-none'
)}
>
<SelectorIcon className={clsx('h-5', 'w-5', 'text-textSecondary')} aria-hidden='true' />
</span>
</Listbox.Button>
)
Example #14
Source File: ThemeToggle.tsx From aljoseph.co with MIT License | 5 votes |
export function ThemeToggle({ panelClassName = 'mt-4' }) {
const { setTheme, theme } = useTheme();
return (
<Listbox value={theme} onChange={setTheme}>
<Listbox.Label className="sr-only">Theme</Listbox.Label>
<Listbox.Button type="button">
<span className="dark:hidden">
<SunIcon className="w-6 h-6" selected={theme !== 'system'} />
</span>
<span className="hidden dark:inline">
<MoonIcon className="w-6 h-6" selected={theme !== 'system'} />
</span>
</Listbox.Button>
<Listbox.Options
className={cx(
'absolute z-50 top-full right-0 bg-white rounded-lg ring-1 ring-slate-900/10 shadow-lg overflow-hidden w-36 py-1 text-sm text-slate-700 font-semibold dark:bg-slate-800 dark:ring-0 dark:highlight-white/5 dark:text-slate-300',
panelClassName
)}
>
{settings.map(({ value, label, icon: Icon }) => (
<Listbox.Option key={value} value={value} as={Fragment}>
{({ active, selected }) => (
<li
className={cx(
'py-1 px-2 flex items-center cursor-pointer',
selected && 'text-pink-300',
active && 'bg-slate-50 dark:bg-slate-600/30'
)}
>
<Icon selected={selected} className="w-6 h-6 mr-2" />
{label}
</li>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Listbox>
)
}
Example #15
Source File: token-price-select.tsx From arkadiko with GNU General Public License v3.0 | 5 votes |
export function TokenPriceSelect({ tokenPrices, selected, setSelected }: Props) {
return (
<Listbox value={selected} onChange={setSelected}>
{({ open }) => (
<>
<Listbox.Label className="block text-sm font-medium text-gray-700 sr-only">Token price</Listbox.Label>
<div className="relative mt-1">
<Listbox.Button className="relative w-full py-2 pl-3 pr-10 text-left bg-white border border-gray-300 rounded-md shadow-sm cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<span className="block truncate">{selected.name}</span>
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<SelectorIcon className="w-5 h-5 text-gray-400" aria-hidden="true" />
</span>
</Listbox.Button>
<Transition
show={open}
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="absolute z-10 w-full py-1 mt-1 overflow-auto text-base bg-white rounded-md shadow-lg max-h-60 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{tokenPrices.map((token:any) => (
<Listbox.Option
key={token.id}
className={({ active }) =>
classNames(
active ? 'text-white bg-indigo-600' : 'text-gray-900',
'cursor-default select-none relative py-2 pl-3 pr-9'
)
}
value={token}
>
{({ selected, active }) => (
<>
<span className={classNames(selected ? 'font-semibold' : 'font-normal', 'block truncate')}>
{token.name}
</span>
{selected ? (
<span
className={classNames(
active ? 'text-white' : 'text-indigo-600',
'absolute inset-y-0 right-0 flex items-center pr-4'
)}
>
<CheckIcon className="w-5 h-5" aria-hidden="true" />
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</>
)}
</Listbox>
)
}
Example #16
Source File: select.tsx From website with Apache License 2.0 | 5 votes |
export function Select<T>(props: {
items: Array<Value<T>>;
selected: Value<T>;
setSelected: (value: Value<T>) => unknown;
}) {
const {selected, setSelected} = props;
return (
<div className="w-24">
<Listbox value={selected} onChange={setSelected}>
<div className="relative mt-1">
<Listbox.Button className="relative py-2 pr-10 pl-3 w-full text-left bg-black hover:bg-gray-800 rounded-lg focus-visible:border-indigo-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 shadow-md cursor-default sm:text-sm">
<span className="block truncate">{selected.name}</span>
<span className="flex absolute inset-y-0 right-0 items-center pr-2 pointer-events-none">
<HiChevronDown
className="w-4 h-4 text-gray-400"
aria-hidden="true"
/>
</span>
</Listbox.Button>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="overflow-auto absolute py-1 mt-1 w-full max-h-60 text-base bg-white rounded-md focus:outline-none ring-1 ring-black/5 shadow-lg sm:text-sm">
{props.items.map(item => (
<Listbox.Option
key={item.name}
className={({active}) =>
`${active ? 'text-amber-900 bg-amber-100' : 'text-gray-900'}
cursor-default select-none relative py-2 pl-10 pr-4`
}
value={item}
>
{({selected, active}) => (
<>
<span
className={`${
selected ? 'font-medium' : 'font-normal'
} block truncate`}
>
{item.name}
</span>
{selected && (
<span
className={`${
active ? 'text-amber-600' : 'text-amber-600'
}
absolute inset-y-0 left-0 flex items-center pl-3`}
>
<HiCheck className="w-5 h-5" aria-hidden="true" />
</span>
)}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</Listbox>
</div>
);
}
Example #17
Source File: SelectOption.tsx From yet-another-generic-startpage with MIT License | 5 votes |
SelectOption = ({ value, label }: Option) => (
<StyledOption>
<Listbox.Option value={value} className={getOptionClasses}>
{label}
</Listbox.Option>
</StyledOption>
)
Example #18
Source File: index.tsx From ledokku with MIT License | 4 votes |
App = () => {
const history = useHistory();
const toast = useToast();
const { id: appId } = useParams<{ id: string }>();
const [isUnlinkModalOpen, setIsUnlinkModalOpen] = useState(false);
const [isLinkModalOpen, setIsLinkModalOpen] = useState(false);
const [arrayOfLinkLogs, setArrayOfLinkLogs] = useState<RealTimeLog[]>([]);
const [arrayOfUnlinkLogs, setArrayOfUnlinkLogs] = useState<RealTimeLog[]>([]);
const [databaseAboutToUnlink, setdatabaseAboutToUnlink] = useState<string>();
const [isTerminalVisible, setIsTerminalVisible] = useState(false);
const [processStatus, setProcessStatus] = useState<
'running' | 'notStarted' | 'finished'
>('notStarted');
const [unlinkLoading, setUnlinkLoading] = useState(false);
const [linkLoading, setLinkLoading] = useState(false);
const [selectedDb, setSelectedDb] = useState({
value: { name: '', id: '', type: '' },
label: 'Please select database',
});
const [
linkDatabaseMutation,
{
data: databaseLinkData,
loading: databaseLinkLoading,
error: databaseLinkError,
},
] = useLinkDatabaseMutation();
const [unlinkDatabaseMutation] = useUnlinkDatabaseMutation();
useUnlinkDatabaseLogsSubscription({
onSubscriptionData: (data) => {
const logsExist = data.subscriptionData.data?.unlinkDatabaseLogs;
if (logsExist) {
setArrayOfUnlinkLogs((currentLogs) => {
return [...currentLogs, logsExist];
});
if (
logsExist.type === 'end:success' ||
logsExist.type === 'end:failure'
) {
setProcessStatus('finished');
}
}
},
});
useLinkDatabaseLogsSubscription({
onSubscriptionData: (data) => {
const logsExist = data.subscriptionData.data?.linkDatabaseLogs;
if (logsExist) {
setArrayOfLinkLogs((currentLogs) => {
return [...currentLogs, logsExist];
});
if (
logsExist.type === 'end:success' ||
logsExist.type === 'end:failure'
) {
setProcessStatus('finished');
}
}
},
});
const {
data: databaseData,
loading: databaseDataLoading,
} = useDatabaseQuery();
const { data, loading, refetch /* error */ } = useAppByIdQuery({
variables: {
appId,
},
fetchPolicy: 'cache-and-network',
ssr: false,
skip: !appId,
});
if (!data || !databaseData) {
return null;
}
// // TODO display error
if (loading || databaseDataLoading) {
// TODO nice loading
return <p>Loading...</p>;
}
const { databases } = databaseData;
const { app } = data;
if (!app) {
// TODO nice 404
return <p>App not found.</p>;
}
const linkedDatabases = app.databases;
const linkedIds = linkedDatabases?.map((db) => db.id);
const notLinkedDatabases = databases.filter((db) => {
return linkedIds?.indexOf(db.id) === -1;
});
// Hacky way to add create new database to link db select
notLinkedDatabases.length > 0 &&
notLinkedDatabases.push({ name: 'Create new database' } as any);
const dbOptions = notLinkedDatabases.map((db) => {
return {
value: { name: db.name, id: db.id, type: db.type },
label: <DatabaseLabel type={db.type} name={db.name} />,
};
});
const handleUnlink = async (databaseId: string, appId: string) => {
try {
await unlinkDatabaseMutation({
variables: {
input: {
databaseId,
appId,
},
},
});
setIsTerminalVisible(true);
setUnlinkLoading(true);
} catch (e) {
toast.error(e.message);
}
};
const handleConnect = async (databaseId: string, appId: string) => {
try {
await linkDatabaseMutation({
variables: {
input: {
databaseId,
appId,
},
},
});
setSelectedDb({
value: { name: '', id: '', type: '' },
label: 'Please select database',
});
setIsTerminalVisible(true);
setLinkLoading(true);
} catch (e) {
toast.error(e.message);
}
};
return (
<div>
<HeaderContainer>
<Header />
<AppHeaderInfo app={app} />
<AppHeaderTabNav app={app} />
</HeaderContainer>
<Container maxW="5xl" mt={10}>
<div className="grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-2 gap-4 mt-10">
<div>
<Heading as="h2" size="md" py={5}>
App info
</Heading>
<div className="bg-gray-100 shadow overflow-hidden rounded-lg border-b border-gray-200">
<Table mt="4" mb="4" variant="simple">
<Tbody mt="10">
<Tr py="4">
<Td className="font-semibold" py="3" px="4">
App name
</Td>
<Td py="3" px="4">
{app.name}
</Td>
</Tr>
<Tr>
<Td className="font-semibold" py="7" px="4">
id
</Td>
<Td w="1/3" py="3" px="4">
{app.id}
</Td>
</Tr>
<Tr>
<Td className="font-semibold" py="3" px="4">
Created at
</Td>
<Td py="3" px="4">
{app.createdAt}
</Td>
</Tr>
</Tbody>
</Table>
</div>
</div>
<div className="w-full">
<Heading as="h2" size="md" py={5}>
Databases
</Heading>
{databases.length === 0 ? (
<>
<div className="mt-4 mb-4">
<h2 className="text-gray-400">
Currently you haven't created any databases, to do so
proceed with the database creation flow
</h2>
</div>
<RouterLink
to={{
pathname: '/create-database/',
state: app.name,
}}
>
<Button width="large" color={'grey'}>
Create a database
</Button>
</RouterLink>
</>
) : (
<>
{notLinkedDatabases.length !== 0 ? (
<div>
<Listbox
as="div"
value={selectedDb}
//@ts-ignore
onChange={
selectedDb.value.name !== 'Create new database'
? setSelectedDb
: history.push({
pathname: '/create-database',
state: app.name,
})
}
>
{({ open }) => (
<div className="relative w-80">
<Listbox.Button className="cursor-default relative w-full rounded-md border border-gray-300 bg-white pl-3 pr-10 py-2 text-left focus:outline-none focus:shadow-outline-blue focus:border-blue-300 transition ease-in-out duration-150 sm:text-sm sm:leading-5">
<span className="block truncate">
{selectedDb.label}
</span>
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<svg
className="h-5 w-5 text-gray-400"
viewBox="0 0 20 20"
fill="none"
stroke="currentColor"
>
<path
d="M7 7l3-3 3 3m0 6l-3 3-3-3"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</span>
</Listbox.Button>
{open && (
<Transition
show={open}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
className="absolute mt-1 w-full rounded-md bg-white shadow-lg z-10"
>
<Listbox.Options
static
className="max-h-60 rounded-md py-1 text-base leading-6 ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm sm:leading-5"
>
{dbOptions.map(
(db) =>
db.value.id !== selectedDb.value.id && (
<Listbox.Option
key={dbOptions.indexOf(db)}
value={db as any}
>
{({ active }) => (
<div
className={cx(
'cursor-default select-none relative py-2 px-4',
{
'bg-gray-200': active,
'bg-white text-black': !active,
}
)}
>
{db.label}
</div>
)}
</Listbox.Option>
)
)}
</Listbox.Options>
</Transition>
)}
</div>
)}
</Listbox>
{databaseLinkError && (
<p className="text-red-500 text-sm font-semibold">
{databaseLinkError.graphQLErrors[0].message}
</p>
)}
<Button
color="grey"
width="large"
className="mt-2"
isLoading={
databaseLinkLoading &&
!databaseLinkData &&
!databaseLinkError
}
disabled={!selectedDb.value.id || linkLoading}
onClick={() => {
setIsLinkModalOpen(true);
}}
>
Link database
</Button>
{isLinkModalOpen && (
<Modal>
<ModalTitle>Link database</ModalTitle>
<ModalDescription>
{isTerminalVisible ? (
<>
<p className="mb-2 ">
Linking <b>{selectedDb.value.name}</b> with{' '}
<b>{app.name}</b>!
</p>
<p className="text-gray-500 mb-2">
Linking process usually takes a couple of
minutes. Breathe in, breathe out, logs are about
to appear below:
</p>
<Terminal className={'w-6/6'}>
{arrayOfLinkLogs.map((log) => (
<p
key={arrayOfLinkLogs.indexOf(log)}
className="text-s leading-5"
>
{log.message}
</p>
))}
</Terminal>
</>
) : (
<p>
Are you sure, you want to link{' '}
<b>{selectedDb.value.name}</b> to{' '}
<b>{app.name}</b>?
</p>
)}
</ModalDescription>
<ModalButton
ctaFn={() => {
setProcessStatus('running');
handleConnect(selectedDb.value.id, appId);
}}
ctaText={'Link'}
otherButtonText={'Cancel'}
isCtaLoading={isTerminalVisible ? false : linkLoading}
isCtaDisabled={isTerminalVisible}
isOtherButtonDisabled={processStatus === 'running'}
closeModal={() => {
setIsLinkModalOpen(false);
refetch({ appId });
setLinkLoading(false);
setIsTerminalVisible(false);
setProcessStatus('notStarted');
}}
/>
</Modal>
)}
</div>
) : (
<>
<p className="mt-3 mb-3 text-cool-gray-400">
All your databases are already linked to this app! If you
want to create more databases proceed with create database
flow.
</p>
<div className="ml-80">
<Link to="/create-database">
<Button
color={'grey'}
variant="outline"
className="text-sm mr-3"
>
Create database
</Button>
</Link>
</div>
</>
)}
{!loading && app && app.databases && (
<>
<h2 className="mb-1 mt-3 font-semibold">
{app.databases.length > 0 && 'Linked databases'}
</h2>
{app.databases.map((database) => (
<div
key={app.databases?.indexOf(database)}
className="flex flex-row justify-start"
>
<Link
to={`/database/${database.id}`}
className="py-2 block"
>
<div className="w-64 flex items-center py-3 px-2 shadow hover:shadow-md transition-shadow duration-100 ease-in-out rounded bg-white">
{database.type === 'POSTGRESQL' ? (
<>
<PostgreSQLIcon size={16} className="mr-1" />
</>
) : undefined}
{database.type === 'MONGODB' ? (
<>
<MongoIcon size={16} className="mr-1" />
</>
) : undefined}
{database.type === 'REDIS' ? (
<>
<RedisIcon size={16} className="mr-1" />
</>
) : undefined}
{database.type === 'MYSQL' ? (
<>
<MySQLIcon size={16} className="mr-1" />
</>
) : undefined}
{database.name}
</div>
</Link>
<Button
width="normal"
className="mt-4 ml-2 h-10"
color="red"
onClick={() => {
setIsUnlinkModalOpen(true);
setdatabaseAboutToUnlink(database.name);
}}
>
Unlink
</Button>
{isUnlinkModalOpen && (
<Modal>
<ModalTitle>Unlink database</ModalTitle>
<ModalDescription>
{isTerminalVisible ? (
<>
<p className="mb-2 ">
Unlinking <b>{app.name}</b>
from <b>{databaseAboutToUnlink}</b>!
</p>
<p className="text-gray-500 mb-2">
Unlinking process usually takes a couple of
minutes. Breathe in, breathe out, logs are
about to appear below:
</p>
<Terminal className={'w-6/6'}>
{arrayOfUnlinkLogs.map((log) => (
<p
key={arrayOfUnlinkLogs.indexOf(log)}
className="text-s leading-5"
>
{log.message}
</p>
))}
</Terminal>
</>
) : (
<p>
Are you sure, you want to unlink{' '}
<b>{app.name} </b>
from <b>{databaseAboutToUnlink}</b> ?
</p>
)}
</ModalDescription>
<ModalButton
ctaFn={() => {
setProcessStatus('running');
handleUnlink(database.id, appId);
}}
ctaText={'Unlink'}
otherButtonText={'Cancel'}
isOtherButtonDisabled={
processStatus === 'running'
}
isCtaLoading={
isTerminalVisible ? false : unlinkLoading
}
isCtaDisabled={isTerminalVisible === true}
closeModal={() => {
setIsUnlinkModalOpen(false);
refetch({ appId });
setUnlinkLoading(false);
setIsTerminalVisible(false);
setdatabaseAboutToUnlink('');
setProcessStatus('notStarted');
}}
/>
</Modal>
)}
</div>
))}
</>
)}
</>
)}
</div>
</div>
</Container>
</div>
);
}
Example #19
Source File: index.tsx From ledokku with MIT License | 4 votes |
Database = () => {
const { id: databaseId } = useParams<{ id: string }>();
const toast = useToast();
const [isUnlinkModalOpen, setIsUnlinkModalOpen] = useState(false);
const [isLinkModalOpen, setIsLinkModalOpen] = useState(false);
const [arrayOfUnlinkLogs, setArrayOfUnlinkLogs] = useState<RealTimeLog[]>([]);
const [arrayOfLinkLogs, setArrayOfLinkLogs] = useState<RealTimeLog[]>([]);
const [appAboutToUnlink, setAppAboutToUnlink] = useState<string>();
const [isTerminalVisible, setIsTerminalVisible] = useState(false);
const [processStatus, setProcessStatus] = useState<
'running' | 'notStarted' | 'finished'
>('notStarted');
const [unlinkLoading, setUnlinkLoading] = useState(false);
const [linkLoading, setLinkLoading] = useState(false);
const [selectedApp, setSelectedApp] = useState({
value: { name: '', id: '' },
label: 'Please select an app',
});
const [
linkDatabaseMutation,
{
data: databaseLinkData,
loading: databaseLinkLoading,
error: databaseLinkError,
},
] = useLinkDatabaseMutation();
const { data: appsData } = useAppsQuery();
const { data, loading, refetch /* error */ } = useDatabaseByIdQuery({
variables: {
databaseId,
},
ssr: false,
skip: !databaseId,
});
const [unlinkDatabaseMutation] = useUnlinkDatabaseMutation();
useUnlinkDatabaseLogsSubscription({
onSubscriptionData: (data) => {
const logsExist = data.subscriptionData.data?.unlinkDatabaseLogs;
if (logsExist) {
setArrayOfUnlinkLogs((currentLogs) => {
return [...currentLogs, logsExist];
});
if (
logsExist.type === 'end:success' ||
logsExist.type === 'end:failure'
) {
setProcessStatus('finished');
}
}
},
});
useLinkDatabaseLogsSubscription({
onSubscriptionData: (data) => {
const logsExist = data.subscriptionData.data?.linkDatabaseLogs;
if (logsExist) {
setArrayOfLinkLogs((currentLogs) => {
return [...currentLogs, logsExist];
});
if (
logsExist.type === 'end:success' ||
logsExist.type === 'end:failure'
) {
setProcessStatus('finished');
}
}
},
});
if (!data || !appsData) {
return null;
}
// // TODO display error
if (loading) {
// TODO nice loading
return <p>Loading...</p>;
}
const { database } = data;
const { apps } = appsData;
const handleUnlink = async (databaseId: string, appId: string) => {
try {
await unlinkDatabaseMutation({
variables: {
input: {
databaseId,
appId,
},
},
});
setIsTerminalVisible(true);
setUnlinkLoading(true);
} catch (e) {
toast.error(e.message);
}
};
if (!database) {
// TODO nice 404
return <p>Database not found.</p>;
}
const linkedApps = database.apps;
const linkedIds = linkedApps?.map((db) => db.id);
const notLinkedApps = apps.filter((db) => {
return linkedIds?.indexOf(db.id) === -1;
});
const appOptions = notLinkedApps.map((app) => {
return {
value: { name: app.name, id: app.id },
label: app.name,
};
});
const handleConnect = async (databaseId: string, appId: string) => {
try {
await linkDatabaseMutation({
variables: {
input: {
databaseId,
appId,
},
},
});
setSelectedApp({
value: { name: '', id: '' },
label: 'Please select an app',
});
setIsTerminalVisible(true);
setLinkLoading(true);
} catch (e) {
toast.error(e.message);
}
};
return (
<div>
<HeaderContainer>
<Header />
<DatabaseHeaderInfo database={database} />
<DatabaseHeaderTabNav database={database} />
</HeaderContainer>
<Container maxW="5xl" mt={10}>
<div className="grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-2 gap-4 mt-10">
<div>
<Heading as="h2" size="md" py={5}>
Database info
</Heading>
<div className="bg-gray-100 shadow overflow-hidden rounded-lg border-b border-gray-200">
<Table mt="4" mb="4" variant="simple">
<Tbody mt="10">
<Tr py="4">
<Td className="font-semibold" py="3" px="4">
Database name
</Td>
<Td py="3" px="4">
{database.name}
</Td>
</Tr>
<Tr>
<Td className="font-semibold" py="7" px="4">
id
</Td>
<Td w="1/3" py="3" px="4">
{database.id}
</Td>
</Tr>
<Tr>
<Td className="font-semibold" py="3" px="4">
Type
</Td>
<Td py="3" px="4">
{database.type}
</Td>
</Tr>
</Tbody>
</Table>
</div>
</div>
<div className="w-full">
<h1 className="font-bold text-lg font-bold py-5">Apps</h1>
{apps.length === 0 ? (
<>
<div className="mt-3 mb-4">
<h2 className="text-gray-400">
Currently you haven't created apps, to do so proceed with
the app creation flow
</h2>
</div>
<Link to="/create-app">
<Button width="large" color={'grey'}>
Create app
</Button>
</Link>
</>
) : (
<>
{notLinkedApps.length !== 0 ? (
<div>
<Listbox
as="div"
value={selectedApp}
//@ts-ignore
onChange={setSelectedApp}
>
{({ open }) => (
<div className="relative w-80">
<Listbox.Button className="cursor-default relative w-full rounded-md border border-gray-300 bg-white pl-3 pr-10 py-2 text-left focus:outline-none focus:shadow-outline-blue focus:border-blue-300 transition ease-in-out duration-150 sm:text-sm sm:leading-5">
<span className="block truncate">
{selectedApp.label}
</span>
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<svg
className="h-5 w-5 text-gray-400"
viewBox="0 0 20 20"
fill="none"
stroke="currentColor"
>
<path
d="M7 7l3-3 3 3m0 6l-3 3-3-3"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</span>
</Listbox.Button>
{open && (
<Transition
show={open}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
className="absolute mt-1 w-full rounded-md bg-white shadow-lg z-10"
>
<Listbox.Options
static
className="max-h-60 rounded-md py-1 text-base leading-6 shadow-ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm sm:leading-5"
>
{appOptions.map(
(app) =>
app.value.id !== selectedApp.value.id && (
<Listbox.Option
key={appOptions.indexOf(app)}
value={app as any}
>
{({ active }) => (
<div
className={cx(
'cursor-default select-none relative py-2 px-4',
{
'bg-gray-200': active,
'bg-white text-black': !active,
}
)}
>
{app.label}
</div>
)}
</Listbox.Option>
)
)}
</Listbox.Options>
</Transition>
)}
</div>
)}
</Listbox>
{databaseLinkError && (
<p className="text-red-500 text-sm font-semibold">
{databaseLinkError.graphQLErrors[0].message}
</p>
)}
<Button
color="grey"
width="large"
className="mt-2"
isLoading={
databaseLinkLoading &&
!databaseLinkData &&
!databaseLinkError
}
disabled={!selectedApp.value.id}
onClick={() => setIsLinkModalOpen(true)}
>
Link app
</Button>
{isLinkModalOpen && (
<Modal>
<ModalTitle>Link app</ModalTitle>
<ModalDescription>
{isTerminalVisible ? (
<>
<p className="mb-2 ">
Linking <b>{selectedApp.value.name}</b> with{' '}
<b>{database.name}</b>!
</p>
<p className="text-gray-500 mb-2">
Linking process usually takes a couple of
minutes. Breathe in, breathe out, logs are about
to appear below:
</p>
<Terminal className={'w-6/6'}>
{arrayOfLinkLogs.map((log) => (
<p
key={arrayOfLinkLogs.indexOf(log)}
className="text-s leading-5"
>
{log.message}
</p>
))}
</Terminal>
</>
) : (
<p>
Are you sure, you want to link{' '}
<b>{selectedApp.value.name}</b> to{' '}
<b>{database.name}</b>?
</p>
)}
</ModalDescription>
<ModalButton
ctaFn={() => {
setProcessStatus('running');
handleConnect(databaseId, selectedApp.value.id);
}}
ctaText={'Link'}
otherButtonText={'Cancel'}
isCtaLoading={isTerminalVisible ? false : linkLoading}
isCtaDisabled={isTerminalVisible}
isOtherButtonDisabled={processStatus === 'running'}
closeModal={() => {
setIsLinkModalOpen(false);
refetch({ databaseId });
setLinkLoading(false);
setIsTerminalVisible(false);
setProcessStatus('notStarted');
}}
/>
</Modal>
)}
</div>
) : (
<>
<p className="mt-3 mb-3 mr-8 text-cool-gray-400">
All your apps are already linked to this database! If you
want to create more apps proceed with create app flow.
</p>
<div className="ml-80">
<Link to="/create-app">
<Button
color={'grey'}
variant="outline"
className="text-sm mr-3"
>
Create app
</Button>
</Link>
</div>
</>
)}
{!loading && database && database.apps && (
<>
<h2 className="mb-1 mt-3 font-semibold">
{database.apps.length > 0 && 'Linked apps'}
</h2>
{database.apps.map((app) => (
<div
key={database.apps?.indexOf(app)}
className="flex flex-row justify-start"
>
<Link to={`/app/${app.id}`} className="py-2 block">
<div className="w-64 flex items-center py-3 px-2 shadow hover:shadow-md transition-shadow duration-100 ease-in-out rounded bg-white">
{app.name}
</div>
</Link>
<Button
width="normal"
className="mt-4 ml-2 h-10"
color="red"
onClick={() => {
setIsUnlinkModalOpen(true);
setAppAboutToUnlink(app.name);
}}
>
Unlink
</Button>
{isUnlinkModalOpen && (
<Modal>
<ModalTitle>Unlink app</ModalTitle>
<ModalDescription>
{isTerminalVisible ? (
<>
<p className="mb-2 ">
Unlinking <b>{database.name}</b> from{' '}
<b>{appAboutToUnlink}</b>!
</p>
<p className="text-gray-500 mb-2">
Unlinking process usually takes a couple of
minutes. Breathe in, breathe out, logs are
about to appear below:
</p>
<Terminal className={'w-6/6'}>
{arrayOfUnlinkLogs.map((log) => (
<p
key={arrayOfUnlinkLogs.indexOf(log)}
className="text-s leading-5"
>
{log.message}
</p>
))}
</Terminal>
</>
) : (
<p>
Are you sure, you want to unlink{' '}
<b>{database.name}</b> from{' '}
<b>{appAboutToUnlink}</b>?
</p>
)}
</ModalDescription>
<ModalButton
ctaFn={() => {
setProcessStatus('running');
handleUnlink(database.id, app.id);
}}
ctaText={'Unlink'}
otherButtonText={'Cancel'}
isCtaLoading={
isTerminalVisible ? false : unlinkLoading
}
isOtherButtonDisabled={
processStatus === 'running'
}
isCtaDisabled={isTerminalVisible}
closeModal={() => {
setIsUnlinkModalOpen(false);
refetch({ databaseId });
setUnlinkLoading(false);
setIsTerminalVisible(false);
setAppAboutToUnlink('');
setProcessStatus('notStarted');
}}
/>
</Modal>
)}
</div>
))}
</>
)}
</>
)}
</div>
</div>
</Container>
</div>
);
}
Example #20
Source File: tx-sidebar.tsx From arkadiko with GNU General Public License v3.0 | 4 votes |
TxSidebar = ({ showSidebar, setShowSidebar }) => {
const address = useSTXAddress();
const [isLoading, setIsLoading] = useState(true);
const [transactions, setTransactions] = useState<JSX.Element[]>();
const [pendingTransactions, setPendingTransactions] = useState<JSX.Element[]>();
const [networks, setNetworks] = useState([]);
const [selectedNetworkKey, setSelectedNetworkKey] = useState(
JSON.parse(localStorage.getItem('arkadiko-stacks-node') || JSON.stringify(DEFAULT_NETWORKS[0]))
.key
);
const selectedNetwork = networks.find(network => network.key === selectedNetworkKey);
const [networkName, setNetworkName] = useState('');
const [networkAddress, setNetworkAddress] = useState('');
const [networkKey, setNetworkKey] = useState('');
const onInputChange = (event: { target: { name: any; value: any } }) => {
const value = event.target.value;
if (event.target.name === 'networkName') {
setNetworkName(value);
} else if (event.target.name === 'networkAddress') {
setNetworkAddress(value);
} else if (event.target.name === 'networkKey') {
setNetworkKey(value);
}
};
const addNewNetwork = () => {
const networks = JSON.parse(localStorage.getItem('arkadiko-stacks-nodes') || '[]');
const network = {
name: networkName,
url: networkAddress,
key: networkKey,
};
networks.push(network);
localStorage.setItem('arkadiko-stacks-nodes', JSON.stringify(networks));
setSelectedNetworkKey(network);
};
useEffect(() => {
const network = JSON.parse(localStorage.getItem('arkadiko-stacks-node')) || networks[0];
if (showSidebar && selectedNetwork['url'] != network['url']) {
localStorage.setItem('arkadiko-stacks-node', JSON.stringify(selectedNetwork));
window.location.reload();
}
}, [selectedNetwork]);
useEffect(() => {
let mounted = true;
const fetchTransactions = async () => {
if (mounted && address) {
setIsLoading(true);
const txs = await getAccountTransactions(address || '', CONTRACT_ADDRESS || '');
let index = 0;
const txMap = txs.map((tx: ContractCallTransaction) => {
let status = 'error';
if (tx.tx_status === 'success') {
status = 'success';
} else if (tx.tx_status === 'pending') {
status = 'pending';
}
index += 1;
return <ContractTransaction key={index} transaction={tx} status={status} />;
});
setTransactions(txMap);
const pending = await getPendingTransactions(address || '', CONTRACT_ADDRESS || '');
const pendingMap = pending.map((tx: MempoolContractCallTransaction) => {
index += 1;
return <ContractTransaction key={index} transaction={tx} status="pending" />;
});
setPendingTransactions(pendingMap);
setIsLoading(false);
}
};
const setAllNetworks = () => {
const addedNetworks = JSON.parse(localStorage.getItem('arkadiko-stacks-nodes') || '[]');
setNetworks(DEFAULT_NETWORKS.concat(addedNetworks));
};
setAllNetworks();
if (showSidebar) {
fetchTransactions();
}
return () => {
mounted = false;
};
}, [showSidebar]);
return (
<Transition show={showSidebar} as={Fragment}>
<Dialog
as="div"
className="fixed inset-0 z-50 overflow-hidden"
onClose={() => {
setShowSidebar(false);
}}
>
<div className="absolute inset-0 overflow-hidden">
<Transition.Child
as={Fragment}
enter="ease-in-out duration-500"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in-out duration-500"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="absolute inset-0 transition-opacity bg-gray-700 bg-opacity-50" />
</Transition.Child>
<div className="fixed inset-y-0 right-0 flex max-w-full pl-10">
<Transition.Child
as={Fragment}
enter="transform transition ease-in-out duration-500 sm:duration-700"
enterFrom="translate-x-full"
enterTo="translate-x-0"
leave="transform transition ease-in-out duration-500 sm:duration-700"
leaveFrom="translate-x-0"
leaveTo="translate-x-full"
>
<div className="w-screen max-w-md">
<div className="flex flex-col h-full overflow-y-scroll bg-white shadow-xl dark:bg-zinc-800">
<div className="px-4 py-6 bg-indigo-700 sm:px-6">
<div className="flex items-start justify-between">
<Dialog.Title className="text-lg text-white font-headings">
Network Settings
</Dialog.Title>
<div className="flex items-center ml-3 h-7">
<button
type="button"
className="text-indigo-200 bg-indigo-700 rounded-md hover:text-white focus:outline-none focus:ring-2 focus:ring-white"
onClick={() => {
setShowSidebar(false);
}}
>
<span className="sr-only">Close panel</span>
<StyledIcon as="XIcon" size={6} solid={false} />
</button>
</div>
</div>
<div className="mt-1">
<p className="text-sm text-indigo-300">Switch between networks easily</p>
</div>
</div>
<div className="relative px-4 my-6 sm:px-6">
<div className="relative w-72">
<Listbox value={selectedNetworkKey} onChange={setSelectedNetworkKey}>
<Listbox.Button className="relative w-full py-2 pl-3 pr-10 text-left bg-white border border-gray-300 rounded-md shadow-sm cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm dark:bg-zinc-900 dark:border-zinc-800">
<span className="block truncate dark:text-zinc-50">
{selectedNetwork?.name}
</span>
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<StyledIcon as="SelectorIcon" size={5} className="text-gray-400" />
</span>
</Listbox.Button>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="absolute right-0 w-full py-1 mt-1 overflow-auto text-base bg-white rounded-md shadow-lg dark:text-zinc-50 dark:bg-zinc-900 max-h-56 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{networks.map(network => (
<Listbox.Option
key={network.key}
value={network.key}
className={({ active }) =>
`${active ? 'text-white bg-indigo-600' : 'text-gray-900'}
cursor-default select-none relative py-2 pl-10 pr-4`
}
>
{({ selected, active }) => (
<div>
<span
className={`${
selected ? 'font-semibold' : 'font-normal'
} block truncate dark:text-zinc-50`}
>
{network.name} ({network.url})
</span>
{selected ? (
<span
className={`${active ? 'text-white' : 'text-indigo-600'}
absolute inset-y-0 left-0 flex items-center pl-3`}
>
<StyledIcon as="CheckIcon" size={5} />
</span>
) : null}
</div>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</Listbox>
</div>
<Disclosure>
{() => (
<>
<Disclosure.Button className="flex items-center px-3 py-2 mt-4 text-sm font-medium leading-4 text-white bg-indigo-600 border border-transparent rounded-md shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<span>Add a network</span>
</Disclosure.Button>
<Disclosure.Panel className="p-4 mt-4 text-sm text-gray-700 bg-gray-100 rounded-md dark:bg-zinc-700 dark:text-zinc-100">
Use this form to add a new instance of the Stacks Blockchain API. Make
sure you review and trust the host before you add it.
<form className="mt-4">
<div className="flex flex-col">
<label
htmlFor="name"
className="block text-sm font-medium text-gray-500 dark:text-gray-300"
>
Name
</label>
<div className="flex mt-1 rounded-md shadow-sm">
<input
value={networkName}
onChange={onInputChange}
type="text"
name="networkName"
id="networkName"
className="flex-1 block w-full min-w-0 text-black border-gray-300 rounded-md focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</div>
</div>
<div className="flex flex-col mt-3">
<label
htmlFor="address"
className="block text-sm font-medium text-gray-500 dark:text-gray-300"
>
Address (include https://)
</label>
<div className="flex mt-1 rounded-md shadow-sm">
<input
value={networkAddress}
onChange={onInputChange}
type="text"
name="networkAddress"
id="networkAddress"
className="flex-1 block w-full min-w-0 text-black border-gray-300 rounded-md focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</div>
</div>
<div className="flex flex-col mt-3">
<label
htmlFor="key"
className="block text-sm font-medium text-gray-500 dark:text-gray-300"
>
Key
</label>
<div className="flex mt-1 rounded-md shadow-sm">
<input
value={networkKey}
onChange={onInputChange}
type="text"
name="networkKey"
id="networkKey"
className="flex-1 block w-full min-w-0 text-black border-gray-300 rounded-md focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</div>
</div>
<button
onClick={() => addNewNetwork()}
className="flex items-center px-3 py-2 mt-5 text-sm font-medium leading-4 text-white bg-indigo-600 border border-transparent rounded-md shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Add network
</button>
</form>
</Disclosure.Panel>
</>
)}
</Disclosure>
</div>
<div className="px-4 py-6 mt-6 bg-indigo-700 sm:px-6">
<div className="flex items-start justify-between">
<Dialog.Title className="text-lg text-white font-headings">
Transaction History
</Dialog.Title>
</div>
<div className="mt-1">
<p className="text-sm text-indigo-300">
Your pending and confirmed transactions.
</p>
</div>
</div>
{isLoading ? (
<div className="relative flex-1 px-4 mt-6 sm:px-6">
<ul className="divide-y divide-gray-200 dark:divide-zinc-700">
<li className="py-4">
<div className="flex flex-col space-y-3">
<Placeholder width={Placeholder.width.FULL} />
<Placeholder width={Placeholder.width.THIRD} />
<Placeholder width={Placeholder.width.HALF} />
</div>
</li>
<li className="py-4">
<div className="flex flex-col space-y-3">
<Placeholder width={Placeholder.width.FULL} />
<Placeholder width={Placeholder.width.THIRD} />
<Placeholder width={Placeholder.width.HALF} />
</div>
</li>
</ul>
</div>
) : (
<div className="relative flex-1 px-4 mt-6 sm:px-6">
<ul className="divide-y divide-gray-200 dark:divide-zinc-700">
{pendingTransactions}
{transactions}
</ul>
</div>
)}
</div>
</div>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
);
}
Example #21
Source File: token-swap-list.tsx From arkadiko with GNU General Public License v3.0 | 4 votes |
TokenSwapList: React.FC<Props> = ({ selected, setSelected, disabled }) => {
return (
<Listbox value={selected} onChange={setSelected} disabled={disabled}>
{({ open }) => (
<>
<div className="relative flex-1">
<Listbox.Button
className={`relative w-full py-2 pl-3 ${
disabled ? 'pr-3' : 'pr-10'
} text-left bg-white border border-gray-300 rounded-md shadow-sm cursor-default md:w-36 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm dark:bg-zinc-800 dark:border-zinc-900`}
>
<span className="flex items-center">
<img src={selected.logo} alt="" className="w-6 h-6 rounded-full shrink-0" />
<span className="block ml-3 truncate dark:text-zinc-50">{selected.name}</span>
</span>
{!disabled ? (
<span className="absolute inset-y-0 right-0 flex items-center pr-2 ml-3 pointer-events-none">
<StyledIcon as="SelectorIcon" size={5} className="text-gray-400" />
</span>
) : null}
</Listbox.Button>
<Transition
show={open}
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options
static
className="absolute z-20 w-full py-1 mt-1 overflow-auto text-base bg-white rounded-md shadow-lg dark:text-zinc-50 dark:bg-zinc-800 max-h-56 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
>
{tokenList
.filter(token => token.listed)
.map(token => (
<Listbox.Option
key={token.id}
className={({ active }) =>
classNames(
active ? 'text-white bg-indigo-600' : 'text-gray-900',
'cursor-default select-none relative py-2 pl-3 pr-9'
)
}
value={token}
>
{({ selected, active }) => (
<>
<div className="flex items-center">
<img
src={token.logo}
alt=""
className="w-6 h-6 rounded-full shrink-0"
/>
<span
className={classNames(
selected ? 'font-semibold' : 'font-normal',
'ml-3 block truncate dark:text-zinc-50'
)}
>
{token.name}
</span>
</div>
{selected ? (
<span
className={classNames(
active ? 'text-white' : 'text-indigo-600',
'absolute inset-y-0 right-0 flex items-center pr-4'
)}
>
<StyledIcon as="CheckIcon" size={5} />
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</>
)}
</Listbox>
);
}