@headlessui/react#Menu TypeScript Examples
The following examples show how to use
@headlessui/react#Menu.
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: stake-actions.tsx From arkadiko with GNU General Public License v3.0 | 6 votes |
StakeActions: React.FC<StakeActionsProps> = ({ children }) => {
return (
<Menu as="div" className="relative flex items-center justify-end">
{({ open }) => (
<>
<Menu.Button className="inline-flex items-center justify-center w-8 h-8 text-gray-400 bg-white rounded-full hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<span className="sr-only">Open options</span>
<StyledIcon as="DotsVerticalIcon" size={5} />
</Menu.Button>
<Transition
show={open}
as={Fragment}
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"
>
<Menu.Items
static
className="absolute top-0 z-10 w-48 mx-3 mt-1 origin-top-right bg-white divide-y divide-gray-200 rounded-md shadow-lg dark:bg-zinc-800 dark:divide-zinc-600 right-7 ring-1 ring-black ring-opacity-5 focus:outline-none"
>
<div className="px-1 py-1">{children}</div>
</Menu.Items>
</Transition>
</>
)}
</Menu>
);
}
Example #2
Source File: ProfileDropDown.tsx From platform with MIT License | 5 votes |
export default function ProfileDropDown(props) {
const { signOut, avatarUrl } = props;
return (
<Menu as="div" className="relative inline-block text-left">
{({ open }) => (
<>
<div>
<Menu.Button className="inline-flex justify-center w-full rounded-lg border-2 border-teal-500 shadow-sm bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-teal-500">
{avatarUrl ? (
<img
className="rounded-md h-8 w-8"
src={avatarUrl}
alt="Avatar"
/>
) : (
<span className="inline-block relative h-8 w-8 rounded-lg">
<svg
className="h-full w-full text-gray-300 rounded-lg"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M24 20.993V24H0v-2.996A14.977 14.977 0 0112.004 15c4.904 0 9.26 2.354 11.996 5.993zM16.002 8.999a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
</span>
)}
</Menu.Button>
</div>
<Transition
show={open}
as={Fragment}
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"
>
<Menu.Items
static
className="origin-top-right absolute right-0 mt-2 w-32 sm:w-44 rounded-md shadow-lg bg-white border border-teal-500 ring-black ring-opacity-100 divide-y divide-gray-100 focus:outline-none"
>
<div className="py-1">
<Menu.Item>
{({ active }) => (
<Link
to="/app/profile"
className={classNames(
active ? "bg-gray-100 text-gray-900" : "text-gray-700",
"block px-4 py-1 sm:py-2 text-xs sm:text-sm"
)}
>
Profile
</Link>
)}
</Menu.Item>
</div>
<div className="py-1">
<Menu.Item>
{({ active }) => (
<div
onClick={signOut}
className={classNames(
active ? "bg-gray-100 text-gray-900" : "text-gray-700",
"block px-4 py-1 sm:py-2 text-xs sm:text-sm cursor-pointer"
)}
>
Logout
</div>
)}
</Menu.Item>
</div>
</Menu.Items>
</Transition>
</>
)}
</Menu>
);
}
Example #3
Source File: stake-diko-section.tsx From arkadiko with GNU General Public License v3.0 | 4 votes |
StakeDikoSection = ({
loadingData,
loadingDikoToStDiko,
stDikoToDiko,
stakedAmount,
dikoCooldown,
dikoBalance,
stDikoBalance,
apy,
cooldownRunning,
startDikoCooldown,
setShowStakeModal,
setShowUnstakeModal,
canUnstake
}) => {
return (
<>
<section>
<header className="pb-5 border-b border-gray-200 dark:border-zinc-600 sm:flex sm:justify-between sm:items-end">
<div>
<h3 className="text-lg leading-6 text-gray-900 font-headings dark:text-zinc-50">
DIKO
</h3>
<p className="max-w-3xl mt-2 text-sm text-gray-500 dark:text-zinc-400">
When staking DIKO in the security module{' '}
<span className="font-semibold">you will receive stDIKO</span> which is a
representation of your share of the pool. DIKO in the pool is{' '}
<span className="font-semibold">auto-compounding</span>. Your amount of stDIKO{' '}
<span className="font-semibold">does not change</span>, but the DIKO value it
represents <span className="font-semibold">will increase</span>. Both DIKO and
stDIKO can be used to propose and vote in governance.
</p>
</div>
<div className="flex items-center mt-2 sm:mt-0">
<div className="w-5.5 h-5.5 rounded-full bg-indigo-200 flex items-center justify-center">
<StyledIcon as="QuestionMarkCircleIcon" size={5} className="text-indigo-600" />
</div>
<a
className="inline-flex items-center px-2 text-sm font-medium text-indigo-500 dark:text-indigo-300 dark:hover:text-indigo-200 hover:text-indigo-700"
href="https://docs.arkadiko.finance/protocol/diko/security-module"
target="_blank"
rel="noopener noreferrer"
>
More on the Security Module
<StyledIcon as="ExternalLinkIcon" size={3} className="block ml-2" />
</a>
</div>
</header>
<div className="mt-4 bg-white divide-y divide-gray-200 rounded-md shadow dark:divide-gray-600 dark:bg-zinc-800">
<div className="px-4 py-5 space-y-6 divide-y divide-gray-200 dark:divide-zinc-600 sm:p-6">
<div className="md:grid md:grid-flow-col gap-4 sm:grid-cols-[min-content,auto]">
<div className="self-center w-14">
<img className="w-12 h-12 rounded-full" src={tokenList[1].logo} alt="" />
</div>
<div className="mt-3 md:mt-0">
<p className="text-sm leading-6 text-gray-500 dark:text-zinc-400 md:mb-1">
stDIKO
</p>
{loadingDikoToStDiko ? (
<Placeholder className="py-2" width={Placeholder.width.HALF} />
) : (
<div>
<p className="text-lg font-semibold dark:text-white">
{microToReadable(stDikoBalance).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 6,
})}
</p>
<div className="flex items-center md:mt-1">
<p className="text-xs text-gray-500 dark:text-zinc-400">
1 stDIKO ≈{' '}
{stDikoToDiko.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 6,
})}{' '}
DIKO
</p>
<Tooltip
className="ml-2"
shouldWrapChildren={true}
label={`stDIKO's value is determined by dividing the total supply of DIKO in the pool by the total supply of stDIKO`}
>
<StyledIcon
as="InformationCircleIcon"
size={4}
className="block ml-2 text-gray-400"
/>
</Tooltip>
</div>
</div>
)}
</div>
<div className="mt-3 md:mt-0">
<p className="text-sm leading-6 text-gray-500 dark:text-zinc-400 md:mb-1">
DIKO
</p>
{loadingData ? (
<Placeholder className="py-2" width={Placeholder.width.HALF} />
) : (
<p className="text-lg font-semibold dark:text-white">
{microToReadable(stakedAmount).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 6,
})}
</p>
)}
</div>
<div className="mt-3 md:mt-0">
<p className="text-sm leading-6 text-gray-500 dark:text-zinc-400 md:mb-1">
Current APR
</p>
{loadingData ? (
<Placeholder className="py-2" width={Placeholder.width.HALF} />
) : (
<p className="text-indigo-600 dark:text-indigo-400">{apy}%</p>
)}
</div>
<div className="mt-3 md:mt-0">
<p className="flex items-center text-sm leading-6 text-gray-500 dark:text-zinc-400 md:mb-1">
Cooldown status
<Tooltip
className="ml-2"
shouldWrapChildren={true}
label={`The 10-day cooldown period is the time required prior to unstaking your tokens. Once it expires, there is a 2-day window to unstake your tokens.`}
>
<StyledIcon
as="InformationCircleIcon"
size={5}
className="block ml-2 text-gray-400"
/>
</Tooltip>
</p>
{loadingData ? (
<Placeholder className="py-2" width={Placeholder.width.HALF} />
) : (
<p className="text-base dark:text-white">{dikoCooldown}</p>
)}
</div>
<div className="self-center">
<Menu as="div" className="relative flex items-center justify-end">
{({ open }) => (
<>
<Menu.Button className="inline-flex items-center justify-center px-2 py-1 text-sm text-indigo-500 bg-white rounded-lg focus:outline-none focus-visible:ring focus-visible:ring-indigo-500 focus-visible:ring-opacity-75 dark:bg-zinc-800 dark:text-indigo-400">
<span>Actions</span>
<StyledIcon
as="ChevronUpIcon"
size={4}
className={`${
open
? ''
: 'transform rotate-180 transition ease-in-out duration-300'
} ml-2`}
/>
</Menu.Button>
<Transition
show={open}
as={Fragment}
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"
>
<Menu.Items
static
className="absolute top-0 z-10 w-48 mx-3 mt-6 origin-top-right bg-white divide-y divide-gray-200 rounded-md shadow-lg dark:divide-gray-600 right-3 ring-1 ring-black ring-opacity-5 focus:outline-none"
>
<div className="px-1 py-1">
<Menu.Item>
{({ active }) => (
<button
className={`${
active
? 'bg-indigo-500 text-white disabled:bg-gray-400 disabled:cursor-not-allowed'
: 'text-gray-900'
} group flex rounded-md items-center w-full px-2 py-2 text-sm`}
disabled={!(dikoBalance > 0)}
onClick={() => setShowStakeModal(true)}
>
{!(dikoBalance > 0) ? (
<Tooltip
placement="left"
className="mr-2"
label={`You don't have any available DIKO to stake in your wallet.`}
>
<div className="flex items-center w-full">
<StyledIcon
as="ArrowCircleDownIcon"
size={5}
className="block mr-3 text-gray-400 group-hover:text-white"
/>
Stake
</div>
</Tooltip>
) : (
<>
<StyledIcon
as="ArrowCircleDownIcon"
size={5}
className="block mr-3 text-gray-400 group-hover:text-white"
/>
Stake
</>
)}
</button>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<button
className={`${
active
? 'bg-indigo-500 text-white disabled:bg-gray-400 disabled:cursor-not-allowed'
: 'text-gray-900'
} group flex rounded-md items-center w-full px-2 py-2 text-sm`}
onClick={() => setShowUnstakeModal(true)}
disabled={!(stakedAmount > 0 && canUnstake)}
>
{!(stakedAmount > 0) ? (
<Tooltip
placement="left"
className="mr-2"
label={`You don't have any staked DIKO.`}
>
<div className="flex items-center w-full">
<StyledIcon
as="ArrowCircleUpIcon"
size={5}
className="mr-3 text-gray-400 group-hover:text-white"
/>
Unstake
</div>
</Tooltip>
) : !canUnstake ? (
<Tooltip
placement="left"
className="mr-2"
label={`Either you haven't started the cooldown period, or the cooldown timer hasn't ended yet.`}
>
<div className="flex items-center w-full">
<StyledIcon
as="ArrowCircleUpIcon"
size={5}
className="mr-3 text-gray-400 group-hover:text-white"
/>
Unstake
</div>
</Tooltip>
) : (
<>
<StyledIcon
as="ArrowCircleUpIcon"
size={5}
className="mr-3 text-gray-400 group-hover:text-white"
/>
Unstake
</>
)}
</button>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<button
className={`${
active
? 'bg-indigo-500 text-white disabled:bg-gray-400 disabled:cursor-not-allowed'
: 'text-gray-900'
} group flex rounded-md items-center w-full px-2 py-2 text-sm`}
onClick={() => startDikoCooldown()}
disabled={cooldownRunning}
>
{cooldownRunning ? (
<Tooltip
placement="left"
className="mr-2"
label={`Cooldown is already in progress.`}
>
<div className="flex items-center w-full">
<StyledIcon
as="ClockIcon"
size={5}
className="mr-3 text-gray-400 group-hover:text-white"
/>
Start cooldown
</div>
</Tooltip>
) : (
<>
<StyledIcon
as="ClockIcon"
size={5}
className="mr-3 text-gray-400 group-hover:text-white"
/>
Start cooldown
</>
)}
</button>
)}
</Menu.Item>
</div>
</Menu.Items>
</Transition>
</>
)}
</Menu>
</div>
</div>
</div>
</div>
</section>
</>
);
}
Example #4
Source File: events.tsx From eventcatalog with MIT License | 4 votes |
export default function Page({ events, services, domains }: PageProps) {
const filters = [
{
id: 'domains',
name: `Filter by Domains (${domains.length})`,
options: domains.map((domain) => ({
value: domain,
label: domain,
checked: false,
})),
},
{
id: 'services',
name: `Filter by Services (${services.length})`,
options: services.map((service) => ({
value: service,
label: service,
checked: false,
})),
},
];
const [selectedFilters, setSelectedFilters] = useState({ services: [], domains: [] });
const [showMermaidDiagrams, setShowMermaidDiagrams] = useState(false);
const [eventsToRender, setEventsToRender] = useState(events);
const [searchFilter, setSearchFilter] = useState('');
const handleFilterSelection = (option, type, event) => {
console.log(option, type, event);
if (event.target.checked) {
const newFilters = selectedFilters[type].concat([option.value]);
setSelectedFilters({ ...selectedFilters, [type]: newFilters });
} else {
const newFilters = selectedFilters[type].filter((value) => value !== option.value);
setSelectedFilters({ ...selectedFilters, [type]: newFilters });
}
};
const getFilteredEvents = (): any => {
if (!selectedFilters.services && !searchFilter && !selectedFilters.domains) return events;
let filteredEvents = events;
if (selectedFilters.services.length > 0) {
// @ts-ignore
filteredEvents = filteredEvents.filter((event) => {
const { services: serviceFilters } = selectedFilters;
const hasConsumersFromFilters = event.consumerNames.some((consumerId) => serviceFilters.indexOf(consumerId) > -1);
const hasProducersFromFilters = event.producerNames.some((producerId) => serviceFilters.indexOf(producerId) > -1);
return hasConsumersFromFilters || hasProducersFromFilters;
});
}
if (selectedFilters.domains.length > 0) {
// @ts-ignore
filteredEvents = filteredEvents.filter((event) => {
const { domains: domainFilters } = selectedFilters;
return domainFilters.indexOf(event.domain) > -1;
});
}
if (searchFilter) {
filteredEvents = filteredEvents.filter((event) => event.name.toLowerCase().includes(searchFilter.toLowerCase()));
}
return filteredEvents;
};
useEffect(() => {
setEventsToRender(getFilteredEvents());
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedFilters, searchFilter]);
// eslint-disable-next-line react-hooks/exhaustive-deps
const debouncedFilter = useCallback(
debounce((e) => {
setSearchFilter(e.target.value);
}, 500),
[eventsToRender]
);
const filtersApplied = !!searchFilter || selectedFilters.services.length > 0;
const { title } = useConfig();
return (
<>
<Head>
<title>{title} - All Events</title>
</Head>
<main className="max-w-7xl mx-auto min-h-screen px-4 xl:px-0">
<div className="relative z-10 flex items-baseline justify-between pt-8 pb-6 border-b border-gray-200">
<h1 className="text-2xl font-extrabold tracking-tight text-gray-900">Events ({events.length})</h1>
<div className="flex items-center">
<Menu as="div" className="hidden relative text-left">
<div>
<Menu.Button className="group inline-flex justify-center text-sm font-medium text-gray-700 hover:text-gray-900">
Sort
<ChevronDownIcon
className="flex-shrink-0 -mr-1 ml-1 h-5 w-5 text-gray-400 group-hover:text-gray-500"
aria-hidden="true"
/>
</Menu.Button>
</div>
<Transition
as={Fragment}
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"
>
<Menu.Items className="origin-top-right absolute right-0 mt-2 w-40 rounded-md shadow-2xl bg-white ring-1 ring-black ring-opacity-5 focus:outline-none">
<div className="py-1">
{sortOptions.map((option) => (
<Menu.Item key={option.name}>
{({ active }) => (
<a
href={option.href}
className={classNames(
option.current ? 'font-medium text-gray-900' : 'text-gray-500',
active ? 'bg-gray-100' : '',
'block px-4 py-2 text-sm'
)}
>
{option.name}
</a>
)}
</Menu.Item>
))}
</div>
</Menu.Items>
</Transition>
</Menu>
</div>
</div>
<section className="pt-6 pb-24">
<div className="grid grid-cols-4 gap-x-8 gap-y-10">
{/* Filters */}
<form className="hidden lg:block">
<div className="border-b border-gray-200 pb-6">
<label htmlFor="event" className="font-bold block text-sm font-medium text-gray-700">
Search Events
</label>
<div className="mt-1 relative rounded-md shadow-sm">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<SearchIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
</div>
<input
type="text"
name="event"
id="event"
onChange={debouncedFilter}
className="focus:ring-gray-500 focus:border-gray-500 block w-full pl-10 sm:text-sm border-gray-300 rounded-md"
/>
</div>
</div>
{filters.map((section: any) => {
if (!section.options.length) return null;
return (
<div key={section.id} className="border-b border-gray-200 py-6">
<h3 className="-my-3 flow-root">
<div className="py-3 bg-white w-full flex items-center justify-between text-sm text-gray-400 hover:text-gray-500">
<span className="font-bold font-medium text-gray-900">{section.name}</span>
</div>
</h3>
<div className="pt-6">
<div className="space-y-4">
{section.options.map((option, optionIdx) => (
<div key={option.value} className="flex items-center">
<input
id={`filter-${section.id}-${optionIdx}`}
name={`${section.id}[]`}
defaultValue={option.value}
type="checkbox"
onChange={(event) => handleFilterSelection(option, section.id, event)}
defaultChecked={option.checked}
className="h-4 w-4 border-gray-300 rounded text-gray-600 focus:ring-gray-500"
/>
<label htmlFor={`filter-${section.id}-${optionIdx}`} className="ml-3 text-sm text-gray-600">
{option.label}
</label>
</div>
))}
</div>
</div>
</div>
);
})}
<div className="border-b border-gray-200 py-6">
<h3 className="-my-3 flow-root">
<div className="py-3 bg-white w-full flex items-center justify-between text-sm text-gray-400 hover:text-gray-500">
<span className="font-bold font-medium text-gray-900">Features</span>
</div>
</h3>
<div className="pt-6">
<div className="space-y-4">
<div className="flex items-center">
<input
id="show-mermaid"
type="checkbox"
onChange={(e) => setShowMermaidDiagrams(e.target.checked)}
defaultChecked={showMermaidDiagrams}
className="h-4 w-4 border-gray-300 rounded text-gray-600 focus:ring-gray-500"
/>
<label htmlFor="show-mermaid" className="ml-3 text-sm text-gray-600">
Show Mermaid Diagrams
</label>
</div>
</div>
</div>
</div>
</form>
<div className="col-span-4 lg:col-span-3">
<div>
<h2 className="text-gray-500 text-xs font-medium uppercase tracking-wide">
{filtersApplied
? `Filtered Events (${eventsToRender.length}/${events.length})`
: `All Events (${events.length})`}
</h2>
<EventGrid events={eventsToRender} showMermaidDiagrams={showMermaidDiagrams} />
{eventsToRender.length === 0 && (
<div className="text-gray-400 flex h-96 justify-center items-center">
<div>
<SearchIcon className="w-6 h-6 inline-block mr-1" />
No events found.
</div>
</div>
)}
</div>
</div>
</div>
</section>
</main>
</>
);
}
Example #5
Source File: services.tsx From eventcatalog with MIT License | 4 votes |
export default function Page({ services }: PageProps) {
const [servicesToRender, setServicesToRender] = useState(services);
const [searchFilter, setSearchFilter] = useState('');
const getFilteredServices = (): any => {
let filteredServices = services;
if (searchFilter) {
filteredServices = filteredServices.filter((service) => service.name.toLowerCase().includes(searchFilter.toLowerCase()));
}
return filteredServices;
};
useEffect(() => {
setServicesToRender(getFilteredServices());
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchFilter]);
const debouncedFilter = useCallback(
debounce((e) => {
setSearchFilter(e.target.value);
}, 500),
[servicesToRender]
);
const filtersApplied = !!searchFilter;
const [showMermaidDiagrams, setShowMermaidDiagrams] = useState(false);
const { title } = useConfig();
return (
<>
<Head>
<title>{title} - All Services</title>
</Head>
<main className="max-w-7xl mx-auto md:min-h-screen px-4 xl:px-0">
<div className="relative z-10 flex items-baseline justify-between pt-8 pb-6 border-b border-gray-200">
<h1 className="text-2xl font-extrabold tracking-tight text-gray-900">Services ({services.length})</h1>
<div className="flex items-center">
<Menu as="div" className="relative hidden text-left">
<div>
<Menu.Button className="group inline-flex justify-center text-sm font-medium text-gray-700 hover:text-gray-900">
Sort
<ChevronDownIcon
className="flex-shrink-0 -mr-1 ml-1 h-5 w-5 text-gray-400 group-hover:text-gray-500"
aria-hidden="true"
/>
</Menu.Button>
</div>
<Transition
as={Fragment}
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"
>
<Menu.Items className="origin-top-right absolute right-0 mt-2 w-40 rounded-md shadow-2xl bg-white ring-1 ring-black ring-opacity-5 focus:outline-none">
<div className="py-1">
{sortOptions.map((option) => (
<Menu.Item key={option.name}>
{({ active }) => (
<a
href={option.href}
className={classNames(
option.current ? 'font-medium text-gray-900' : 'text-gray-500',
active ? 'bg-gray-100' : '',
'block px-4 py-2 text-sm'
)}
>
{option.name}
</a>
)}
</Menu.Item>
))}
</div>
</Menu.Items>
</Transition>
</Menu>
</div>
</div>
<section className="pt-6 pb-24">
<div className="grid grid-cols-4 gap-x-8 gap-y-10">
{/* Filters */}
<form className="hidden lg:block">
<div className="border-b border-gray-200 pb-6">
<label htmlFor="service" className="font-bold block text-sm font-medium text-gray-700">
Search Services
</label>
<div className="mt-1 relative rounded-md shadow-sm">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<SearchIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
</div>
<input
type="text"
name="service"
id="service"
onChange={debouncedFilter}
className="focus:ring-gray-500 focus:border-gray-500 block w-full pl-10 sm:text-sm border-gray-300 rounded-md"
/>
</div>
</div>
<div className="border-b border-gray-200 pb-6">
<h3 className="-my-3 flow-root">
<div className="py-3 bg-white w-full flex items-center justify-between text-sm text-gray-400 hover:text-gray-500">
<span className="font-medium text-gray-900">Features</span>
</div>
</h3>
<div className="pt-6">
<div className="space-y-4">
<div className="flex items-center">
<input
id="show-mermaid"
type="checkbox"
onChange={(e) => setShowMermaidDiagrams(e.target.checked)}
defaultChecked={showMermaidDiagrams}
className="h-4 w-4 border-gray-300 rounded text-gray-600 focus:ring-gray-500"
/>
<label htmlFor="show-mermaid" className="ml-3 text-sm text-gray-600">
Show Mermaid Diagrams
</label>
</div>
</div>
</div>
</div>
</form>
<div className="col-span-4 lg:col-span-3">
<div>
<h2 className="text-gray-500 text-xs font-medium uppercase tracking-wide">
{filtersApplied
? `Filtered Services (${servicesToRender.length}/${services.length})`
: `All Services (${services.length})`}
</h2>
<ServiceGrid services={servicesToRender} showMermaidDiagrams={showMermaidDiagrams} />
{servicesToRender.length === 0 && (
<div className="text-gray-400 flex h-96 justify-center items-center">
<div>
<SearchIcon className="w-6 h-6 inline-block mr-1" />
No services found.
</div>
</div>
)}
</div>
</div>
</div>
</section>
</main>
</>
);
}
Example #6
Source File: FilterMenu.tsx From platform with MIT License | 4 votes |
export default function FilterMenu(props) {
const { filters, setFilters, selected, setSelected, setAllDeselected } = props;
const trueState = Object.keys(filters).reduce((pre, cur) => ({ ...pre, [cur]: true }), {});
const falseState = Object.keys(filters).reduce((pre, cur) => ({ ...pre, [cur]: false }), {});
const [someSelected, setSomeSelected] = useState(false);
const handleClick = async (type) => {
setFilters((state) => {
return {
...state,
[type]: !state[type],
};
});
};
const handleSelectAll = () => {
selected ? setFilters(trueState) : setFilters(falseState);
setSelected(!selected);
};
useEffect(() => {
const allSelected = Object.values(filters).every(filter => filter);
if (allSelected) {
setSelected(false /* "Deselect All =" */);
}
setAllDeselected(Object.values(filters).every(filter => filter === false));
// Note: "selected" is unchecked i.e false!
setSomeSelected(Object.values(filters).some(filter => !filter));
}, [filters, setSelected, setAllDeselected]);
return (
<div className="mt-0.5">
<Menu as="div" className="relative inline-block text-left">
<div>
<Menu.Button
className={classNames(someSelected ? 'text-teal-600 bg-gray-100' : 'text-gray-500 bg-white hover:bg-gray-50', `ml-2 relative inline-flex items-center px-2 py-2 shadow-md
rounded-md border border-gray-300 text-sm ring-teal-500
focus:z-10 focus:outline-none
focus:ring-1 focus:ring-teal-500 focus:border-teal-500`)}
>
<span className="sr-only">Filter</span>
<i className="fas fa-filter"></i>
</Menu.Button>
</div>
<Menu.Items className="origin-top-right absolute right-0 mt-2 w-34 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none">
{
Object.keys(filters).map((filterName, key) => {
return (
<Menu.Item key={key} onClick={() => handleClick(filterName)}>
{({ active }) => (
<div
className={classNames(
active ? "bg-gray-100 text-gray-900" : "text-gray-700",
"group flex items-center px-4 py-2 text-sm cursor-pointer"
)}
>
<input
type="checkbox"
onChange={() => { }}
checked={filters[filterName]}
className="mr-3 focus:ring-teal-500 h-4 w-4 text-teal-600 rounded cursor-pointer"
/>
{`${filterName[0].toUpperCase()}${filterName.slice(1)}`}
</div>
)}
</Menu.Item>
)
})
}
<div className="py-1 border-t border-gray-100">
<Menu.Item onClick={handleSelectAll}>
{({ active }) => (
<div
className={classNames(
active ? "bg-gray-100 text-gray-900" : "text-gray-700",
"group flex items-center px-4 py-2 text-xs cursor-pointer text-center"
)}
>
{selected ? "Select All" : "Deselect All"}
</div>
)}
</Menu.Item>
</div>
</Menu.Items>
</Menu>
</div>
);
}
Example #7
Source File: ClassesDropdown.tsx From cpinitiative with Mozilla Public License 2.0 | 4 votes |
export default function ClassesDropdown({ dark = false }): JSX.Element {
return (
<Menu as="div" className="relative inline-block text-left">
{({ open }) => (
<div className="relative h-full">
<Menu.Button
className={classNames(
"group inline-flex items-center h-full px-1 pt-1 border-b-2 border-transparent text-sm leading-6 font-medium transition ease-in-out duration-150",
dark
? "hover:text-gray-200 hover:border-transparent focus:outline-none focus:text-gray-200"
: "hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300",
open
? dark
? "text-gray-200"
: "text-gray-700"
: dark
? "text-gray-400"
: "text-gray-500"
)}
>
Classes
<ChevronDownIcon
className={classNames(
"h-5 w-5 ml-2 transition ease-in-out duration-150",
dark
? "group-hover:text-gray-200 group-focus:text-gray-200"
: "group-hover:text-gray-500 group-focus:text-gray-500",
open
? dark
? "text-gray-200"
: "text-gray-500"
: "text-gray-400"
)}
aria-hidden="true"
/>
</Menu.Button>
<Transition
as={Fragment}
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"
>
<Menu.Items
className={classNames(
"origin-top-right absolute left-0 -mt-2 w-56 rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none",
dark ? "bg-gray-800" : "bg-white"
)}
>
<div className="py-1">
<Menu.Item>
<Link href="/classes">
<a
className={classNames(
"block px-4 py-2 text-sm font-medium",
dark
? "hover:bg-gray-600 text-gray-200"
: "hover:bg-gray-100 hover:text-gray-900 text-gray-700"
)}
>
Live Classes
</a>
</Link>
</Menu.Item>
<Menu.Item>
<Link href="/video-classes">
<a
className={classNames(
"block px-4 py-2 text-sm font-medium",
dark
? "hover:bg-gray-600 text-gray-200"
: "hover:bg-gray-100 hover:text-gray-900 text-gray-700"
)}
>
Self-Study Classes
</a>
</Link>
</Menu.Item>
</div>
</Menu.Items>
</Transition>
</div>
)}
</Menu>
)
}
Example #8
Source File: FileMenu.tsx From ide with Mozilla Public License 2.0 | 4 votes |
FileMenu = (props: FileMenuProps): JSX.Element => {
const [referenceElement, setReferenceElement] = useState<HTMLElement | null>(
null
);
const [popperElement, setPopperElement] = useState<HTMLElement | null>(null);
const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: 'bottom-start',
});
const [permission] = useAtom(actualUserPermissionAtom);
const canWrite = permission === 'OWNER' || permission === 'READ_WRITE';
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
return (
<Menu as="div" className="relative inline-block text-left">
{({ open }) => (
<>
<div>
<Menu.Button
className="relative inline-flex items-center px-4 py-2 shadow-sm text-sm font-medium text-gray-200 hover:bg-gray-800 focus:bg-gray-800 focus:outline-none"
ref={setReferenceElement}
>
File
<ChevronDownIcon
className="-mr-1 ml-2 h-5 w-5"
aria-hidden="true"
/>
</Menu.Button>
</div>
<Transition show={open}>
{mounted
? ReactDOM.createPortal(
<Menu.Items static as="div">
<div
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}
className="relative"
>
<Transition.Child
as={Fragment}
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"
>
<div className="origin-top-left absolute z-10 left-0 w-56 shadow-lg bg-gray-800 ring-1 ring-black ring-opacity-5 focus:outline-none">
<div className="py-1">
<Menu.Item>
{({ active }) => (
<a
href="/"
target="_blank"
className={classNames(
active
? 'bg-gray-700 text-gray-100'
: 'text-gray-200',
'group flex items-center px-4 py-2 text-sm'
)}
>
<PlusIcon
className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-300"
aria-hidden="true"
/>
New File
</a>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<button
type="button"
className={classNames(
active
? 'bg-gray-700 text-gray-100'
: 'text-gray-200',
'group flex items-center px-4 py-2 text-sm w-full focus:outline-none'
)}
onClick={() => props.onDownloadFile()}
>
<DownloadIcon
className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-300"
aria-hidden="true"
/>
Download File
</button>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<a
href={props.forkButtonUrl}
target="_blank"
rel="noreferrer"
className={classNames(
active
? 'bg-gray-700 text-gray-100'
: 'text-gray-200',
'group flex items-center px-4 py-2 text-sm w-full focus:outline-none'
)}
>
<DuplicateIcon
className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-300"
aria-hidden="true"
/>
Clone File
</a>
)}
</Menu.Item>
{canWrite && (
<Menu.Item>
{({ active }) => (
<button
type="button"
className={classNames(
active
? 'bg-gray-700 text-gray-100'
: 'text-gray-200',
'group flex items-center px-4 py-2 text-sm w-full focus:outline-none'
)}
onClick={() => props.onInsertFileTemplate()}
>
<TemplateIcon
className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-300"
aria-hidden="true"
/>
Reset File to Template
</button>
)}
</Menu.Item>
)}
<Menu.Item>
{({ active }) => (
<button
type="button"
className={classNames(
active
? 'bg-gray-700 text-gray-100'
: 'text-gray-200',
'group flex items-center px-4 py-2 text-sm w-full focus:outline-none'
)}
onClick={() => props.onOpenSettings()}
>
<CogIcon
className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-300"
aria-hidden="true"
/>
Settings
</button>
)}
</Menu.Item>
</div>
</div>
</Transition.Child>
</div>
</Menu.Items>,
document.body
)
: null}
</Transition>
</>
)}
</Menu>
);
}
Example #9
Source File: UserListItem.tsx From ide with Mozilla Public License 2.0 | 4 votes |
UserListItem = ({ user }: { user: User }): JSX.Element | null => {
const userRef = useAtomValue(authenticatedUserRefAtom);
const firebaseRef = useAtomValue(authenticatedFirebaseRefAtom);
const [permission] = useAtom(actualUserPermissionAtom);
const [defaultPermission] = useAtom(defaultPermissionAtom);
const [referenceElement, setReferenceElement] = useState<HTMLElement | null>(
null
);
const [popperElement, setPopperElement] = useState<HTMLElement | null>(null);
const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: 'bottom-end',
});
if (!permission || !defaultPermission) return null;
type PermissionUpdate = 'OWNER' | 'READ_WRITE' | 'READ' | 'DEFAULT';
const handleUpdateUserPermission = (
user: User,
permission: PermissionUpdate
): void => {
if (!firebaseRef) {
alert("Firebase hasn't loaded yet, please wait");
return;
}
if (permission === 'DEFAULT') {
firebaseRef.child('users').child(user.id).child('permission').remove();
} else {
firebaseRef.child('users').child(user.id).update({
permission,
});
}
};
return (
<li key={user.id} className="py-2 flex">
<span className="relative h-5 w-5">
<span
className="inline-block h-5 w-5 rounded"
style={{ backgroundColor: user.color }}
/>
<span className="absolute bottom-0 right-0 transform translate-y-1/3 translate-x-1/3 block rounded-full">
<span
className={`block h-3 w-3 rounded-full ${
isUserOnline(user) ? 'bg-green-400' : 'bg-gray-400'
}`}
/>
</span>
</span>
<div className="ml-3 flex-1">
<p
className={`text-sm font-medium ${
isUserOnline(user) ? 'text-gray-300' : 'text-gray-400'
}`}
>
{user.name}
{user.id === userRef?.key ? ' (Me)' : ''}
</p>
<p
className={`text-sm ${
isUserOnline(user) ? 'text-gray-400' : 'text-gray-500'
}`}
>
{user.permission
? permissionLabels[user.permission]
: `Default (${permissionLabels[defaultPermission]})`}
</p>
</div>
{user.id !== userRef?.key && permission === 'OWNER' && (
<Menu>
{({ open }) => (
<>
<div>
<Menu.Button
className="bg-[#1E1E1E] rounded-full flex items-center text-gray-500 hover:text-gray-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-[#1E1E1E] focus:ring-indigo-500"
ref={setReferenceElement}
>
<span className="sr-only">Open options</span>
<DotsVerticalIcon className="h-5 w-5" aria-hidden="true" />
</Menu.Button>
</div>
<Transition show={open}>
{ReactDOM.createPortal(
<Menu.Items as="div" static>
<div
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}
className="relative"
>
<Transition.Child
as={Fragment}
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"
>
<div className="origin-top-right absolute right-0 bg-gray-800 rounded-md mt-2 w-48 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
<div className="py-1">
{([
['OWNER', 'Owner'],
['READ_WRITE', 'Read & Write'],
['READ', 'View Only'],
[
'DEFAULT',
`Default (${permissionLabels[defaultPermission]})`,
],
['PRIVATE', 'Blocked'],
] as [PermissionUpdate, string][]).map(option => (
<Menu.Item key={option[0]}>
{({ active }) => (
<button
className={classNames(
active
? 'bg-gray-700 text-gray-100'
: 'text-gray-200',
'w-full text-left block px-4 py-2 text-sm focus:outline-none'
)}
onClick={() =>
handleUpdateUserPermission(
user,
option[0]
)
}
>
{option[1]}
</button>
)}
</Menu.Item>
))}
</div>
</div>
</Transition.Child>
</div>
</Menu.Items>,
document.body
)}
</Transition>
</>
)}
</Menu>
)}
</li>
);
}
Example #10
Source File: Navbar.tsx From ultimate-saas-ts with MIT License | 4 votes |
Component = () => {
const { data: session, status } = useSession();
const router = useRouter();
return (
<Disclosure as="nav" className="bg-white">
{({ open }) => (
<>
<div className="px-2 mx-auto max-w-7xl sm:px-6 lg:px-8">
<div className="relative flex justify-between h-16">
<div className="absolute inset-y-0 left-0 flex items-center sm:hidden">
<Disclosure.Button className="inline-flex items-center justify-center p-2 text-gray-400 rounded-md hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
<span className="sr-only">Open main menu</span>
{open ? (
<XIcon className="block w-6 h-6" aria-hidden="true" />
) : (
<MenuIcon className="block w-6 h-6" aria-hidden="true" />
)}
</Disclosure.Button>
</div>
<div className="flex items-center justify-center flex-1 sm:items-stretch sm:justify-start">
<div className="flex items-center flex-shrink-0">
<img
className="block w-auto h-8 lg:hidden"
src="https://tailwindui.com/img/logos/workflow-mark-indigo-600.svg"
alt="Workflow"
/>
<img
className="hidden w-auto h-8 lg:block"
src="https://tailwindui.com/img/logos/workflow-logo-indigo-600-mark-gray-800-text.svg"
alt="Workflow"
/>
</div>
<div className="hidden sm:ml-6 sm:flex sm:space-x-8">
<Link href="/">
<a
className={classNames(
'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium',
{
'border-indigo-500 text-gray-900':
router.pathname === '/',
'': router.pathname !== '/',
}
)}
>
Pricings
</a>
</Link>
<Link href="/account">
<a
className={classNames(
'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium',
{
'border-indigo-500 text-gray-900':
router.pathname === '/account',
'': router.pathname !== '/account',
}
)}
>
Account
</a>
</Link>
</div>
</div>
<div className="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
{/* Profile dropdown */}
{status === 'authenticated' ? (
<Menu as="div" className="relative ml-3">
<div>
<Menu.Button className="flex text-sm bg-white rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<span className="sr-only">Open user menu</span>
<img
className="w-8 h-8 rounded-full"
src={
session?.user?.image ||
'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80'
}
alt=""
/>
</Menu.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
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"
>
<Menu.Items className="absolute right-0 w-48 py-1 mt-2 origin-top-right bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
<Menu.Item>
{({ active }) => (
<Link href="/account">
<a
className={classNames(
active ? 'bg-gray-100' : '',
'block px-4 py-2 text-sm text-gray-700'
)}
>
Account
</a>
</Link>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<a
onClick={() => signOut()}
className={classNames(
active ? 'bg-gray-100' : '',
'block px-4 py-2 text-sm text-gray-700'
)}
>
Sign out
</a>
)}
</Menu.Item>
</Menu.Items>
</Transition>
</Menu>
) : (
<Link href="/api/auth/signin">
<a>Sign in</a>
</Link>
)}
</div>
</div>
</div>
<Disclosure.Panel className="sm:hidden">
<div className="pt-2 pb-4 space-y-1">
{/* Current: "bg-indigo-50 border-indigo-500 text-indigo-700", Default: "border-transparent text-gray-500 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-700" */}
<Link href="/">
<a className="block py-2 pl-3 pr-4 text-base font-medium text-indigo-700 border-l-4 border-indigo-500 bg-indigo-50">
Pricings
</a>
</Link>
<Link href="/account">
<a className="block py-2 pl-3 pr-4 text-base font-medium text-gray-500 border-l-4 border-transparent hover:bg-gray-50 hover:border-gray-300 hover:text-gray-700">
Account
</a>
</Link>
</div>
</Disclosure.Panel>
</>
)}
</Disclosure>
);
}
Example #11
Source File: AccountHeader.tsx From pali-wallet with MIT License | 4 votes |
AccountMenu: React.FC = () => {
const { navigate } = useUtils();
const { wallet } = getController();
const { encryptedMnemonic, accounts, activeAccount } = useStore();
const verifyAccounts = Object.keys(accounts);
const setActiveAccount = async (id: number) => {
await wallet.setAccount(Number(id));
wallet.account.sys.watchMemPool(accounts[Number(id)]);
};
const handleLogout = () => {
wallet.lock();
navigate('/');
};
return (
<Menu
id="account-settings-btn"
as="div"
className="absolute right-3 inline-block text-right md:max-w-2xl"
>
<Menu.Button className="inline-flex justify-center w-full hover:text-button-primaryhover text-white text-sm font-medium hover:bg-opacity-30 rounded-full focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75">
{encryptedMnemonic && <Icon name="dots" className="z-0" />}
</Menu.Button>
<Transition
as="div"
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<div className="fixed z-0 -inset-0 w-full bg-brand-black bg-opacity-50 transition-all duration-300 ease-in-out" />
<Menu.Items
as="div"
className="scrollbar-styled absolute z-10 right-0 pb-6 w-72 text-center text-brand-white font-poppins bg-menu-primary rounded-2xl focus:outline-none shadow-2xl overflow-auto origin-top-right ring-1 ring-black ring-opacity-5"
>
<h2
className="mb-3 pb-6 pt-8 w-full text-center text-brand-white bg-menu-primary border-b border-dashed border-dashed-light"
id="account-settings-title"
>
ACCOUNT SETTINGS
</h2>
<Menu.Item>
<li
onClick={() => navigate('/settings/account/private-key')}
className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
>
<Icon name="key" className="mb-2 ml-1 mr-2 text-brand-white" />
<span className="px-3">Your keys</span>
</li>
</Menu.Item>
<Menu.Item>
<Disclosure>
{({ open }) => (
<>
<Disclosure.Button className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200">
<Icon
name="user"
className="mb-2 ml-1 mr-2 text-brand-white"
id="accounts-btn"
/>
<span className="px-3 text-base">Accounts</span>
<Icon
name="select-down"
className={`${
open ? 'transform rotate-180' : ''
} mb-1 text-brand-white`}
/>
</Disclosure.Button>
<div
className="relative"
style={{
paddingTop: `${open ? '45px' : '0px'}`,
}}
>
<Disclosure.Panel
className={`static overflow-y-scroll scrollbar-styled pb-2
${
verifyAccounts?.length === 1
? 'h-16'
: verifyAccounts?.length === 2
? 'h-28'
: verifyAccounts?.length >= 3
? 'h-40'
: ''
}
text-sm bg-menu-secondary`}
>
<li
onClick={() => navigate('/settings/account/new')}
className="backface-visibility-hidden absolute top-0 flex items-center justify-center mb-4 mx-auto p-2.5 w-full text-brand-white text-sm font-medium hover:bg-bkg-2 bg-menu-secondary active:bg-opacity-40 border-b border-dashed border-gray-500 focus:outline-none cursor-pointer transform transition duration-300"
id="create-new-account-btn"
>
<Icon
name="appstoreadd"
className="mb-1 mr-3 text-brand-white"
/>
<span>Create new account</span>
</li>
{Object.values(accounts).map((account, index) => (
<li
key={account.id}
className="backface-visibility-hidden flex flex-col items-center justify-around mt-2 mx-auto p-2.5 max-w-95 text-white text-sm font-medium bg-menu-secondary active:bg-opacity-40 focus:outline-none cursor-pointer transform hover:scale-105 transition duration-300"
onClick={() => setActiveAccount(account.id)}
id={`account-${index}`}
>
<span>
{account.label} ({ellipsis(account.address, 4, 8)})
</span>
{activeAccount.id === account.id && (
<Icon
name="check"
className="mb-1 w-4"
wrapperClassname="w-6 absolute right-1"
/>
)}
</li>
))}
</Disclosure.Panel>
</div>
</>
)}
</Disclosure>
</Menu.Item>
<Menu.Item>
<li
onClick={() => navigate('/settings/account/hardware')}
className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
>
<Icon
name="partition"
className="mb-2 ml-1 mr-2 text-brand-white"
id="hardware-wallet-btn"
/>
<span className="px-3">Hardware wallet</span>
</li>
</Menu.Item>
<Menu.Item>
<li
onClick={handleLogout}
className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
>
<Icon name="lock" className="mb-2 ml-1 mr-2 text-brand-white" />
<span className="px-3">Lock</span>
</li>
</Menu.Item>
</Menu.Items>
</Transition>
</Menu>
);
}
Example #12
Source File: NormalHeader.tsx From pali-wallet with MIT License | 4 votes |
NormalHeader: React.FC = () => {
const { wallet } = getController();
const { activeNetwork, encryptedMnemonic, networks } = useStore();
const { handleRefresh, navigate } = useUtils();
const [currentTabURL, setCurrentTabURL] = useState<string>('');
const handleChangeNetwork = (chain: string, chainId: number) => {
wallet.setActiveNetwork(chain, chainId);
if (chain === 'syscoin') wallet.account.sys.setAddress();
};
const updateCurrentTabUrl = async () => {
const windows = await browser.windows.getAll({ populate: true });
for (const window of windows) {
const views = browser.extension.getViews({ windowId: window.id });
if (views) {
const tabs = await browser.tabs.query({
active: true,
currentWindow: true,
});
return String(tabs[0].url);
}
}
};
useEffect(() => {
let isMounted = true;
updateCurrentTabUrl().then((response: any) => {
if (isMounted) {
setCurrentTabURL(response);
}
});
return () => {
isMounted = false;
};
}, [wallet.isUnlocked()]);
const NetworkMenu = () => (
<Menu as="div" className="absolute left-2 inline-block mr-8 text-left">
{(menuprops) => (
<>
<Menu.Button className="inline-flex gap-x-2 items-center justify-start ml-2 w-full text-white text-sm font-medium hover:bg-opacity-30 rounded-full focus:outline-none cursor-pointer">
<span>{activeNetwork.label}</span>
<Icon
name="select-down"
className={`${
menuprops.open ? 'transform rotate-180' : ''
} text-brand-white`}
id="network-settings-btn"
/>
</Menu.Button>
<Transition
as="div"
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<div className="fixed z-50 -inset-0 w-full bg-brand-black bg-opacity-50 transition-all duration-300 ease-in-out" />
<Menu.Items
as="div"
className="absolute z-50 left-0 pb-6 w-72 h-menu text-center text-brand-white font-poppins bg-menu-primary rounded-2xl focus:outline-none shadow-2xl overflow-hidden origin-top-right ring-1 ring-black ring-opacity-5"
>
<h2
className="mb-6 pb-6 pt-8 w-full text-center text-brand-white bg-menu-primary border-b border-dashed border-dashed-light"
id="network-settings-title"
>
NETWORK SETTINGS
</h2>
<div className="scrollbar-styled h-80 overflow-auto">
<Menu.Item>
<li
onClick={() =>
navigate('/settings/networks/connected-sites')
}
className="flex items-center justify-start mb-2 mx-3 px-2 py-1 text-base bg-warning-success hover:bg-opacity-70 border border-solid border-transparent hover:border-warning-success rounded-full cursor-pointer transition-all duration-200"
>
<Icon
name="globe"
className="mb-1 ml-1 mr-4 text-brand-white"
/>
<span className="px-3">Connected sites</span>
</li>
</Menu.Item>
<Menu.Item>
<li
onClick={() => navigate('/settings/networks/trusted-sites')}
className="flex items-center justify-start mb-4 mx-3 px-2 py-1 text-base bg-brand-royalblue hover:bg-opacity-70 border border-solid border-brand-royalblue rounded-full cursor-pointer transition-all duration-200"
>
<Icon
name="warning"
className="mb-1 ml-1 mr-4 text-brand-white"
/>
<span className="px-3">Trusted sites</span>
</li>
</Menu.Item>
<Menu.Item>
<Disclosure>
{({ open }) => (
<>
<Disclosure.Button className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200">
<Icon
name="dolar"
className="ml-1 mr-4 text-brand-white"
/>
<span className="px-3 text-base">Syscoin core</span>
<Icon
name="select-down"
className={`${
open ? 'transform rotate-180' : ''
} text-brand-white mb-1`}
/>
</Disclosure.Button>
<Disclosure.Panel className="scrollbar-styled pb-2 pt-0.5 h-28 text-sm bg-menu-secondary overflow-auto">
{Object.values(networks.syscoin).map(
(currentNetwork: any) => (
<li
key={currentNetwork.chainId}
className="backface-visibility-hidden flex flex-col justify-around mt-2 mx-auto p-2.5 max-w-95 text-white text-sm font-medium bg-menu-secondary active:bg-opacity-40 focus:outline-none cursor-pointer transform hover:scale-105 transition duration-300"
onClick={() =>
handleChangeNetwork(
'syscoin',
currentNetwork.chainId
)
}
>
<span className="ml-8 text-left">
{currentNetwork.label}
</span>
{activeNetwork.chainId ===
currentNetwork.chainId && (
<Icon
name="check"
className="mb-1 w-4"
wrapperClassname="w-6 absolute right-20"
/>
)}
</li>
)
)}
</Disclosure.Panel>
</>
)}
</Disclosure>
</Menu.Item>
<Menu.Item>
<Disclosure>
{({ open }) => (
<>
<Disclosure.Button className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200">
<Icon
name="dolar"
className="ml-1 mr-4 text-brand-white"
/>
<span className="px-3 text-base">Web3 networks</span>
<Icon
name="select-down"
className={`${
open ? 'transform rotate-180' : ''
} mb-1 text-brand-white`}
/>
</Disclosure.Button>
<Disclosure.Panel className="scrollbar-styled pb-2 pt-0.5 h-28 text-sm bg-menu-secondary overflow-auto">
{Object.values(networks.ethereum).map(
(currentNetwork: any) => (
<li
key={currentNetwork.id}
className="backface-visibility-hidden flex flex-col justify-around mt-2 mx-auto p-2.5 max-w-95 text-white text-sm font-medium bg-menu-secondary active:bg-opacity-40 focus:outline-none cursor-pointer transform hover:scale-105 transition duration-300"
onClick={() =>
handleChangeNetwork(
'ethereum',
currentNetwork.chainId
)
}
>
<span className="ml-8 text-left">
{currentNetwork.label}
</span>
{activeNetwork.chainId ===
currentNetwork.chainId && (
<Icon
name="check"
className="mb-1 w-4"
wrapperClassname="w-6 absolute right-16"
/>
)}
</li>
)
)}
</Disclosure.Panel>
</>
)}
</Disclosure>
</Menu.Item>
<Menu.Item>
<li
onClick={() => navigate('/settings/networks/custom-rpc')}
className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
>
<Icon
name="appstoreadd"
className="ml-1 mr-4 text-brand-white"
/>
<span className="px-3">Custom RPC</span>
</li>
</Menu.Item>
<Menu.Item>
<li
onClick={() => navigate('/settings/networks/edit')}
className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
>
<Icon name="edit" className="ml-1 mr-4 text-brand-white" />
<span className="px-3">Manage networks</span>
</li>
</Menu.Item>
</div>
</Menu.Items>
</Transition>
</>
)}
</Menu>
);
const GeneralMenu = () => (
<Menu
as="div"
className="absolute right-2 top-2 flex items-center justify-evenly"
>
{() => (
<>
<Tooltip content={ellipsis(currentTabURL, 25, 0)}>
<div
onClick={() => navigate('/settings/networks/connected-sites')}
className="relative mx-1.5 text-brand-white cursor-pointer"
>
<Icon
name="globe"
className="hover:text-brand-royalblue text-white"
/>
<Badge className="absolute -right-1 top-1 w-3 h-3 text-warning-error bg-warning-error rounded-full" />
</div>
</Tooltip>
<div
onClick={() => handleRefresh(false)}
className="mx-1.5 hover:text-brand-royalblue text-brand-white cursor-pointer"
>
<Icon name="reload" />
</div>
<Menu.Button as="button" className="mx-1.5">
{Boolean(encryptedMnemonic) && (
<div id="general-settings-button">
<Icon
name="settings"
className="hover:text-brand-royalblue text-brand-white"
/>
</div>
)}
</Menu.Button>
<Transition
as="div"
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<div className="fixed z-50 -inset-0 w-full bg-brand-black bg-opacity-50 transition-all duration-300 ease-in-out" />
<Menu.Items
as="div"
className="scrollbar-styled absolute z-50 right-0 pb-6 w-72 h-96 text-center text-brand-white font-poppins bg-menu-primary rounded-2xl focus:outline-none shadow-2xl overflow-auto origin-top-right ring-1 ring-black ring-opacity-5"
>
<h2
className="mb-6 pb-6 pt-8 w-full text-center text-brand-white bg-menu-primary border-b border-dashed border-dashed-light"
id="general-settings-title"
>
GENERAL SETTINGS
</h2>
<Menu.Item>
<li
onClick={() => navigate('/settings/autolock')}
className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
>
<Icon name="clock" className="ml-1 mr-4 text-brand-white" />
<span className="px-3">Auto lock timer</span>
</li>
</Menu.Item>
<Menu.Item>
<li
onClick={() => navigate('/settings/currency')}
className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
>
<Icon name="dolar" className="ml-1 mr-4 text-brand-white" />
<span className="px-3">Currency</span>
</li>
</Menu.Item>
<Menu.Item>
<li
onClick={() => navigate('/settings/phrase')}
className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
>
<Icon name="wallet" className="ml-1 mr-4 text-brand-white" />
<span id="wallet-seed-phrase-btn" className="px-3">
Wallet Seed Phrase
</span>
</li>
</Menu.Item>
<Menu.Item>
<li
onClick={() => navigate('/settings/about')}
className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
>
<Icon
name="warning"
className="ml-1 mr-4 text-brand-white"
id="info-help-btn"
/>
<span className="px-3">Info/Help</span>
</li>
</Menu.Item>
<Menu.Item>
<li
onClick={() => navigate('/settings/forget-wallet')}
className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
>
<Icon
name="forget"
className="ml-1 mr-4 w-5 h-5 text-brand-white"
id="forget-wallet-btn"
/>
<span className="px-3">Forget wallet</span>
</li>
</Menu.Item>
</Menu.Items>
</Transition>
</>
)}
</Menu>
);
return (
<div className="relative flex items-center justify-between p-2 py-6 w-full text-gray-300 bg-bkg-1">
<NetworkMenu />
<GeneralMenu />
</div>
);
}
Example #13
Source File: SendEth.tsx From pali-wallet with MIT License | 4 votes |
SendEth = () => {
const controller = getController();
const { alert, navigate } = useUtils();
const { activeAccount } = useStore();
const [selectedAsset, setSelectedAsset] = useState<any | null>(null);
const [recommendedGasPrice, setRecommendedGasPrice] = useState(0);
const [recommendedGasLimit, setRecommendedGasLimit] = useState(0);
const [feeValue, setFeeValue] = useState(0);
const [editGas, setEditGas] = useState(false);
const [form] = Form.useForm();
const { convertGasFee } = feeUtils();
const getRecomendedFees = useCallback(async () => {
const gasPrice =
await controller.wallet.account.eth.tx.getRecommendedGasPrice(false);
const gasLimit = await controller.wallet.account.eth.tx.getGasLimit();
setRecommendedGasPrice(gasPrice);
setRecommendedGasLimit(gasLimit);
setFeeValue(gasPrice);
form.setFieldsValue({ baseFee: recommendedGasPrice, gasLimit, gasPrice });
}, [controller.wallet.account]);
useEffect(() => {
getRecomendedFees();
}, [getRecomendedFees]);
const hasAccountAssets = activeAccount && activeAccount.assets.length > 0;
const handleSelectedAsset = (item: string) => {
if (activeAccount?.assets) {
const getAsset = activeAccount?.assets.find(
(asset: any) => asset.contract_address === item
);
if (getAsset) {
setSelectedAsset(getAsset);
return;
}
setSelectedAsset(null);
}
};
const nextStep = ({ receiver, amount, gasPrice, gasLimit }: any) => {
try {
navigate('/send/confirm', {
state: {
tx: {
sender: activeAccount.address,
senderXprv: activeAccount.xprv,
receivingAddress: receiver,
amount,
gasPrice,
gasLimit,
fee: Number(convertGasFee(String(feeValue))),
token: null,
// token: {
// decimals: 18,
// contractAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
// },
},
},
});
} catch (error) {
alert.removeAll();
alert.error('An internal error has occurred.');
}
};
return (
<>
{editGas ? (
<EditGasFee
setGasFee={setRecommendedGasPrice}
setEdit={setEditGas}
form={form}
setFee={setFeeValue}
/>
) : (
<div className="mt-4">
<p className="flex flex-col items-center justify-center text-center font-rubik">
<span className="text-brand-royalblue font-poppins font-thin">
Balance
</span>
{selectedAsset
? getAssetBalance(selectedAsset, activeAccount)
: activeAccount.balances.ethereum}
</p>
<Form
form={form}
id="send-form"
labelCol={{ span: 8 }}
wrapperCol={{ span: 8 }}
initialValues={{
baseFee: recommendedGasPrice,
gasLimit: recommendedGasLimit,
gasPrice: recommendedGasPrice,
}}
onFinish={nextStep}
autoComplete="off"
className="standard flex flex-col gap-3 items-center justify-center mt-4 text-center md:w-full"
>
<Form.Item
name="receiver"
className="md:w-full md:max-w-md"
hasFeedback
rules={[
{
required: true,
message: '',
},
() => ({
validator(_, value) {
if (!value || isValidEthereumAddress(value)) {
return Promise.resolve();
}
return Promise.reject();
},
}),
]}
>
<Input type="text" placeholder="Receiver" className="large" />
</Form.Item>
<div className="flex items-center justify-center md:w-full md:max-w-md">
{hasAccountAssets && (
<Form.Item
name="asset"
className=""
rules={[
{
required: false,
message: '',
},
]}
>
<Menu>
<div className="relative inline-block text-left">
<Menu.Button
disabled={!hasAccountAssets}
className="inline-flex justify-center mt-3 py-3 w-20 text-white text-sm font-medium bg-fields-input-primary hover:bg-opacity-30 border border-fields-input-border focus:border-fields-input-borderfocus rounded-full focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75"
>
{selectedAsset?.symbol
? formatUrl(String(selectedAsset?.symbol), 2)
: 'ETH'}
<ChevronDoubleDownIcon
className="text-violet-200 hover:text-violet-100 -mr-1 ml-2 w-5 h-5"
aria-hidden="true"
/>
</Menu.Button>
<Transition
as={Fragment}
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"
>
{hasAccountAssets && (
<Menu.Items className="scrollbar-styled absolute z-10 left-0 mt-2 py-3 w-44 h-56 text-brand-white font-poppins bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-lg shadow-2xl overflow-auto origin-top-right">
{activeAccount &&
Object.values(activeAccount.assets).map(
(item: any) => (
<Menu.Item>
<button
onClick={() =>
handleSelectedAsset(
item.contract_address
)
}
className="group flex items-center justify-between px-2 py-2 w-full hover:text-brand-royalblue text-brand-white font-poppins text-sm border-0 border-transparent transition-all duration-300"
>
<p>{item.symbol}</p>
</button>
</Menu.Item>
)
)}
</Menu.Items>
)}
</Transition>
</div>
</Menu>
</Form.Item>
)}
<div className="flex flex-col">
<div className="flex w-full">
<label className="flex-1 mr-4 text-xs" htmlFor="gasPrice">
Gas Price
</label>
<label className="flex-1 mr-6 text-xs" htmlFor="gasLimit">
Gas Limit
</label>
</div>
<div
className={`${
hasAccountAssets ? 'w-48 ml-4' : 'w-72'
} flex gap-x-0.5 items-center justify-center md:w-full`}
>
<Form.Item
name="gasPrice"
className="flex-1 w-32 text-center bg-fields-input-primary rounded-l-full md:w-full"
rules={[
{
required: false,
message: '',
},
]}
>
<Input
type="text"
placeholder="Gas Price (GWEI)"
className="p-3 w-full text-sm bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-l-full outline-none md:w-full"
/>
</Form.Item>
<Form.Item
name="gasLimit"
className="flex-1 w-32 text-center bg-fields-input-primary rounded-r-full"
rules={[
{
required: false,
message: '',
},
]}
>
<Input
type="text"
placeholder="Gas Limit"
className="p-3 w-full text-sm bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-r-full outline-none md:w-full"
/>
</Form.Item>
</div>
</div>
</div>
<Form.Item
name="amount"
className="md:w-full md:max-w-md"
hasFeedback
rules={[
{
required: true,
message: '',
},
() => ({
validator(_, value) {
const balance = selectedAsset
? selectedAsset.balance / 10 ** selectedAsset.decimals
: Number(activeAccount?.balances.ethereum);
if (value > balance) {
return Promise.reject();
}
return Promise.resolve();
},
}),
]}
>
<Input className="large" type="number" placeholder="Amount" />
</Form.Item>
<div className="flex gap-x-0.5 items-center justify-center mx-2 md:w-full md:max-w-md">
<Form.Item
name="edit"
className="w-12 text-center bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-l-full opacity-70 cursor-pointer"
rules={[
{
required: false,
message: '',
},
]}
>
<Tooltip content="Click to edit fee">
<div onClick={() => setEditGas(true)}>
<Icon
wrapperClassname="w-6 ml-3 mt-1 h-10"
name="edit"
className="text-brand-royalbluemedium cursor-pointer"
/>
</div>
</Tooltip>
</Form.Item>
<Form.Item
name="baseFee"
className="md:w-full"
hasFeedback
rules={[
{
required: true,
message: '',
},
]}
>
<Tooltip content="Recommended network base fee">
<Input
disabled
className="block pl-4 pr-8 py-3 w-60 text-brand-white text-sm bg-fields-input-primary border border-fields-input-border rounded-r-full outline-none opacity-50 cursor-not-allowed md:w-full"
id="baseFee-input"
type="number"
placeholder="Base fee"
value={recommendedGasPrice}
/>
</Tooltip>
</Form.Item>
</div>
<p className="flex flex-col items-center justify-center p-0 max-w-xs text-center text-brand-royalblue sm:w-full md:my-4">
<span className="text-xs">Amount + fee</span>
<span className="mt-0.5 text-brand-white font-rubik text-xs">
{'≈ '}
</span>
</p>
<SecondaryButton type="submit" id="next-btn">
Next
</SecondaryButton>
</Form>
</div>
)}
</>
);
}
Example #14
Source File: SendSys.tsx From pali-wallet with MIT License | 4 votes |
SendSys = () => {
const { getFiatAmount } = usePrice();
const controller = getController();
const { alert, navigate } = useUtils();
const { activeNetwork, fiat, activeAccount } = useStore();
const [verifyAddress, setVerifyAddress] = useState<boolean>(true);
const [ZDAG, setZDAG] = useState<boolean>(false);
const [selectedAsset, setSelectedAsset] = useState<any | null>(null);
const [recommend, setRecommend] = useState(0.00001);
const [fiatValueToShow, setFiatValueToShow] = useState('');
const [form] = Form.useForm();
const handleGetFee = useCallback(async () => {
const recommendFee =
await controller.wallet.account.sys.tx.getRecommendedFee(
activeNetwork.url
);
setRecommend(recommendFee);
form.setFieldsValue({ fee: recommendFee });
}, [controller.wallet.account, form]);
useEffect(() => {
handleGetFee();
form.setFieldsValue({
verify: true,
ZDAG: false,
fee: recommend,
});
}, [form, handleGetFee]);
const assets = activeAccount.assets
? Object.values(activeAccount.assets)
: [];
const hasAccountAssets = assets && assets.length > 0;
const handleSelectedAsset = (item: number) => {
console.log('selected item', item);
if (assets) {
const getAsset = assets.find((asset: any) => asset.assetGuid === item);
if (getAsset) {
setSelectedAsset(getAsset);
return;
}
setSelectedAsset(null);
}
};
const verifyOnChange = (value: any) => {
setVerifyAddress(value);
form.setFieldsValue({ verify: value });
};
const ZDAGOnChange = (value: any) => {
setZDAG(value);
form.setFieldsValue({ ZDAG: value });
};
const nextStep = ({ receiver, amount, fee }: any) => {
try {
navigate('/send/confirm', {
state: {
tx: {
sender: activeAccount.address,
receivingAddress: receiver,
amount: Number(amount),
fee,
token: selectedAsset ? selectedAsset.assetGuid : null,
isToken: !!selectedAsset,
rbf: !ZDAG,
},
},
});
} catch (error) {
alert.removeAll();
alert.error('An internal error has occurred.');
}
};
const returnFiatAmount = async () => {
if (!selectedAsset) {
const value = await getFiatAmount(
Number(recommend),
6,
String(fiat.asset)
);
setFiatValueToShow(value);
}
const value = await getFiatAmount(
Number(recommend) + Number(recommend),
6,
String(fiat.asset)
);
setFiatValueToShow(value);
};
useEffect(() => {
returnFiatAmount();
}, [selectedAsset]);
return (
<div className="mt-4">
<p className="flex flex-col items-center justify-center text-center font-rubik">
<span className="text-brand-royalblue font-poppins font-thin">
Balance
</span>
{selectedAsset
? getAssetBalance(selectedAsset, activeAccount)
: activeAccount.balances.syscoin}
</p>
<Form
form={form}
id="send-form"
labelCol={{ span: 8 }}
wrapperCol={{ span: 8 }}
initialValues={{
verify: true,
ZDAG: false,
fee: recommend,
}}
onFinish={nextStep}
autoComplete="off"
className="standard flex flex-col gap-3 items-center justify-center mt-4 text-center md:w-full"
>
<Form.Item
name="receiver"
className="md:w-full md:max-w-md"
hasFeedback
rules={[
{
required: true,
message: '',
},
() => ({
validator(_, value) {
if (
!value ||
isValidSYSAddress(value, activeNetwork, verifyAddress)
) {
return Promise.resolve();
}
return Promise.reject();
},
}),
]}
>
<Input type="text" placeholder="Receiver" className="large" />
</Form.Item>
<div className="flex items-center justify-center md:w-full md:max-w-md">
{hasAccountAssets && (
<Form.Item
name="asset"
className=""
rules={[
{
required: false,
message: '',
},
]}
>
<Menu>
<div className="relative inline-block text-left">
<Menu.Button
disabled={!hasAccountAssets}
className="inline-flex justify-center py-3 w-20 text-white text-sm font-medium bg-fields-input-primary hover:bg-opacity-30 border border-fields-input-border focus:border-fields-input-borderfocus rounded-full focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75"
>
{selectedAsset?.symbol
? formatUrl(String(selectedAsset?.symbol), 2)
: 'SYS'}
<ChevronDoubleDownIcon
className="text-violet-200 hover:text-violet-100 -mr-1 ml-2 w-5 h-5"
aria-hidden="true"
/>
</Menu.Button>
<Transition
as={Fragment}
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"
>
{hasAccountAssets && (
<Menu.Items className="scrollbar-styled absolute z-10 left-0 mt-2 py-3 w-44 h-56 text-brand-white font-poppins bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-lg shadow-2xl overflow-auto origin-top-right">
{activeAccount && (
<>
{hasAccountAssets &&
Object.values(activeAccount.assets).map(
(item: any) => (
<>
<Menu.Item>
<button
onClick={() => handleSelectedAsset(-1)}
className="group flex items-center justify-between px-2 py-2 w-full hover:text-brand-royalblue text-brand-white font-poppins text-sm border-0 border-transparent transition-all duration-300"
>
<p>SYS</p>
<small>Native</small>
</button>
</Menu.Item>
<Menu.Item>
<button
onClick={() =>
handleSelectedAsset(item.assetGuid)
}
className="group flex items-center justify-between px-2 py-2 w-full hover:text-brand-royalblue text-brand-white font-poppins text-sm border-0 border-transparent transition-all duration-300"
>
<p>{item.symbol}</p>
<small>
{isNFT(item.assetGuid)
? 'NFT'
: 'SPT'}
</small>
</button>
</Menu.Item>
</>
)
)}
</>
)}
</Menu.Items>
)}
</Transition>
</div>
</Menu>
</Form.Item>
)}
<div
className={`${
hasAccountAssets ? 'w-48 ml-4' : 'w-72'
} flex gap-x-0.5 items-center justify-center md:w-full`}
>
<Form.Item
id="verify-address-switch"
name="verify"
className="flex-1 w-32 text-center bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-l-full md:w-full"
rules={[
{
required: false,
message: '',
},
]}
>
<Tooltip
childrenClassName="text-brand-white h-4"
content="Pali verifies your address to check if it is a valid SYS address. It's useful disable this verification if you want to send to specific type of addresses, like legacy. Only disable this verification if you are fully aware of what you are doing."
>
<p
className={`${
!hasAccountAssets && ' absolute top-0 left-8'
} text-10px cursor-default`}
>
Verify address
</p>
</Tooltip>
<Switch
checked={verifyAddress}
onChange={verifyOnChange}
className="relative inline-flex items-center w-9 h-4 border border-brand-royalblue rounded-full"
>
<span className="sr-only">Verify address</span>
<span
className={`${
verifyAddress
? 'translate-x-6 bg-warning-success'
: 'translate-x-1'
} inline-block w-2 h-2 transform bg-warning-error rounded-full`}
/>
</Switch>
</Form.Item>
<Form.Item
name="ZDAG"
className="flex-1 w-32 text-center bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-r-full"
rules={[
{
required: false,
message: '',
},
]}
>
<Tooltip
childrenClassName="text-brand-white h-4"
content="Disable this option for Replace-by-fee (RBF) and enable for Z-DAG, a exclusive Syscoin feature. Z-DAG enables faster transactions but should not be used for high amounts."
>
<p
className={`${
!hasAccountAssets && 'absolute top-0 right-14'
} text-10px cursor-default`}
>
Z-DAG
</p>
</Tooltip>
<Switch
checked={ZDAG}
onChange={ZDAGOnChange}
className="relative inline-flex items-center w-9 h-4 bg-transparent border border-brand-royalblue rounded-full"
>
<span className="sr-only">Z-DAG</span>
<span
className={`${
ZDAG
? 'bg-warning-success translate-x-6'
: 'bg-warning-error translate-x-1'
} inline-block w-2 h-2 transform rounded-full`}
id="z-dag-switch"
/>
</Switch>
</Form.Item>
</div>
</div>
<Form.Item
name="amount"
className="md:w-full md:max-w-md"
hasFeedback
rules={[
{
required: true,
message: '',
},
() => ({
validator(_, value) {
const balance = selectedAsset
? selectedAsset.balance / 10 ** selectedAsset.decimals
: Number(activeAccount?.balances.syscoin);
if (value > balance) {
return Promise.reject();
}
return Promise.resolve();
},
}),
]}
>
<Input className="large" type="number" placeholder="Amount" />
</Form.Item>
<div className="flex gap-x-0.5 items-center justify-center mx-2 md:w-full md:max-w-md">
<Form.Item
name="recommend"
className="py-1.5 w-12 text-center bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-l-full opacity-50"
rules={[
{
required: false,
message: '',
},
]}
>
<Tooltip content="Use recommended fee. Disabled for SYS networks because the fee used in transactions is already the recommended with current network conditions.">
<div>
<Icon
wrapperClassname="w-6 ml-3 mb-1"
name="verified"
className="text-warning-success opacity-50 cursor-not-allowed"
/>
</div>
</Tooltip>
</Form.Item>
<Form.Item
name="fee"
className="md:w-full"
hasFeedback
rules={[
{
required: true,
message: '',
},
]}
>
<Tooltip content="Network fee">
<Input
disabled
className="block pl-4 pr-8 py-3 w-60 text-brand-white text-sm bg-fields-input-primary border border-fields-input-border rounded-r-full outline-none opacity-50 cursor-not-allowed md:w-full"
id="fee-input"
type="number"
placeholder="Fee network"
value={recommend}
/>
</Tooltip>
</Form.Item>
</div>
<p className="flex flex-col items-center justify-center p-0 max-w-xs text-center text-brand-royalblue sm:w-full md:my-4">
<span className="text-xs">
{`With current network conditions we recommend a fee of ${recommend} SYS`}
</span>
<span className="mt-0.5 text-brand-white font-rubik text-xs">
{'≈ '}
{fiatValueToShow}
</span>
</p>
<SecondaryButton type="submit" id="next-btn">
Next
</SecondaryButton>
</Form>
</div>
);
}
Example #15
Source File: Currency.tsx From pali-wallet with MIT License | 4 votes |
CurrencyView = () => {
const controller = getController();
const { navigate, handleRefresh } = useUtils();
const { getFiatAmount } = usePrice();
const { activeAccount } = useStore();
if (!activeAccount) throw new Error('No account');
const { accounts, activeAccountId, coins, fiat, activeNetwork, networks } =
useStore();
const { asset } = fiat;
const [selectedCoin, setSelectedCoin] = useState(String(asset));
const [checkValueCoin, setCheckValueCoin] = useState('usd');
const [confirmed, setConfirmed] = useState(false);
const [fiatAmountValue, setFiatAmountValue] = useState('');
const convertCurrency = (value: number, toCoin: string) =>
value * coins[toCoin];
const convertToCrypto = (value: number, fromCoin: string) =>
value / coins[fromCoin];
const isUnlocked =
controller.wallet.isUnlocked() && activeAccount.address !== '';
const isSyscoinChain = Boolean(networks.syscoin[activeNetwork.chainId]);
const balance = isSyscoinChain
? activeAccount.balances.syscoin
: activeAccount.balances.ethereum;
const [conversorValues, setConversorValues] = useState({
crypto: balance,
fiat: convertCurrency(balance, checkValueCoin),
});
const handleConvert = (value: number, toCoin: string) => {
setConversorValues({
crypto: value,
fiat: convertCurrency(value, toCoin),
});
};
const handleReverseConvert = (value: number, fromCoin: string) => {
setConversorValues({
crypto: convertToCrypto(value, fromCoin),
fiat: value,
});
};
const handleConfirmCurrencyChange = () => {
setConfirmed(true);
};
const fiatCurrency = asset ? String(asset).toUpperCase() : 'USD';
const getFiatAmountValue = async () => {
const value = await getFiatAmount(balance || 0, 4, String(selectedCoin));
setFiatAmountValue(value);
};
useEffect(() => {
if (isUnlocked && accounts && accounts[activeAccountId]) {
handleRefresh(true);
}
}, [isUnlocked, activeAccountId]);
useEffect(() => {
if (selectedCoin) {
controller.utils.setFiat(
selectedCoin,
isSyscoinChain ? 'syscoin' : 'ethereum'
);
getFiatAmountValue();
}
}, [selectedCoin]);
useEffect(() => {
getFiatAmountValue();
}, [selectedCoin, getFiatAmountValue]);
return (
<Layout title="FIAT CURRENCY" id="fiat-currency-title">
<DefaultModal
show={confirmed}
onClose={() => navigate('/home')}
title="Fiat currency set successfully"
description={`Now you will see the values in your wallet in SYS and ${
selectedCoin.toUpperCase() || 'USD'
}`}
/>
<p className="mx-4 my-3 max-w-xs text-left text-white text-sm md:max-w-full">
You can choose and set your preferred currency to see in your wallet.
</p>
<div className="flex flex-col items-center justify-center">
<Menu as="div" className="relative inline-block text-left">
<Menu.Button
disabled={!fiat || !coins}
className="inline-flex justify-center py-2 w-80 text-white text-sm font-medium bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-full"
>
<p className="ml-2">
{selectedCoin ? selectedCoin.toUpperCase() : fiatCurrency}
</p>
<Icon
name="select-down"
className="text-brand-royalblue"
wrapperClassname="w-8 absolute right-28 bottom-3"
/>
</Menu.Button>
<Transition
as={Fragment}
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"
>
{fiat && coins && (
<Menu.Items className="scrollbar-styled absolute z-10 mt-2 py-3 w-full h-44 text-brand-white font-poppins bg-bkg-4 border border-fields-input-border rounded-xl shadow-2xl overflow-auto origin-top-right">
{Object.entries(coins).map(([key]) => (
<Menu.Item key={key}>
<button
key={key}
onClick={() => setSelectedCoin(key)}
className="group flex gap-x-1 items-center justify-start px-4 py-2 w-full hover:text-brand-royalbluemedium text-brand-white font-poppins text-sm border-0 border-b border-dashed border-brand-royalblue border-transparent border-opacity-30 transition-all duration-300"
>
{getSymbolFromCurrency(key.toUpperCase())}
<p>{key.toUpperCase()}</p>
</button>
</Menu.Item>
))}
</Menu.Items>
)}
</Transition>
</Menu>
<div className="flex flex-col items-center justify-center text-center">
{activeNetwork.chainId === 5700 ? (
<div className="flex gap-x-0.5 items-center justify-center mt-8">
<p className="font-rubik text-5xl font-medium">
{formatNumber(Number(balance) || 0)}{' '}
</p>
<p className="font-poppins md:mt-4">TSYS</p>
</div>
) : (
<>
<div className="flex gap-x-0.5 items-center justify-center mt-8">
<p className="font-rubik text-5xl font-medium">
{formatNumber(balance || 0)}{' '}
</p>
<p className="font-poppins md:mt-4">
{activeNetwork.currency
? activeNetwork.currency.toUpperCase()
: ''}
</p>
</div>
<p>{fiatAmountValue ?? 0}</p>
</>
)}
</div>
<div className="mt-6 md:mt-8">
<SecondaryButton type="button" onClick={handleConfirmCurrencyChange}>
Save
</SecondaryButton>
</div>
</div>
<div className="fixed bottom-0 left-0 flex flex-col gap-y-3 items-center justify-center w-full max-w-2xl h-44 bg-bkg-4 md:bottom-8 md:left-auto">
<p className="mb-2 text-left text-white text-sm">
Check your balance in different currencies
</p>
<div className="standard relative text-brand-royalblue text-sm font-medium">
<Input
type="number"
onChange={(event) =>
handleConvert(Number(event.target.value), checkValueCoin)
}
maxLength={20}
value={Number(conversorValues.crypto)}
className="flex items-center justify-between px-4 py-2 w-80 bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-full outline-none"
/>
<div className="absolute bottom-1.5 right-4 flex gap-x-3 items-center justify-center">
<p
className="cursor-pointer"
onClick={() => handleConvert(Number(balance), checkValueCoin)}
>
MAX
</p>
<div className="flex gap-x-3 items-center justify-center border-l border-dashed border-gray-700">
<Icon
name="dolar"
wrapperClassname="w-2 ml-4 mb-1.5"
className="text-brand-royalblue"
/>
<p>SYS</p>
</div>
</div>
</div>
<div className="standard relative text-brand-royalblue text-sm font-medium">
<Input
type="number"
maxLength={20}
onChange={(event) => {
handleReverseConvert(Number(event.target.value), checkValueCoin);
}}
value={Number(conversorValues.fiat)}
className="flex items-center justify-between px-4 py-2 w-80 bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-full outline-none"
/>
<div className="absolute bottom-2 right-2 flex gap-x-3 items-center justify-center">
<Menu as="div" className="relative inline-block text-left">
<Menu.Button
disabled={!fiat || !coins}
className="flex gap-x-1 justify-center mr-5 text-brand-royalblue text-sm font-medium bg-fields-input-primary rounded-full"
>
{getSymbolFromCurrency(checkValueCoin.toUpperCase())}
{checkValueCoin.toUpperCase()}
<Icon
name="select-down"
className="text-brand-royalblue"
wrapperClassname="w-8 absolute -right-1 bottom-1"
/>
</Menu.Button>
<Transition
as={Fragment}
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"
>
{fiat && coins && (
<Menu.Items className="scrollbar-styled absolute z-10 bottom-10 right-0 mt-2 py-3 w-44 h-56 text-brand-white font-poppins bg-bkg-4 border border-fields-input-border rounded-xl shadow-2xl overflow-auto origin-bottom-right">
{Object.entries(coins).map(([key]) => (
<Menu.Item key={key}>
<button
key={key}
onClick={() => {
setCheckValueCoin(key);
handleConvert(conversorValues.crypto, key);
}}
className="group flex gap-x-1 items-center justify-start px-4 py-2 w-full hover:text-brand-royalbluemedium text-brand-white font-poppins text-sm border-0 border-b border-dashed border-brand-royalblue border-transparent border-opacity-30 transition-all duration-300"
>
{getSymbolFromCurrency(key.toUpperCase())}
<p>{key.toUpperCase()}</p>
</button>
</Menu.Item>
))}
</Menu.Items>
)}
</Transition>
</Menu>
</div>
</div>
</div>
</Layout>
);
}