Skip to content

Commit

Permalink
feat(explorer): add theme switcher (#4041)
Browse files Browse the repository at this point in the history
* feat(explorer): add theme switcher

* fix: add missing style to the icon

* fix: lint

* refactor: remove theme context from explorer

* feat(explorer): add background to search suggestions (#4162)

* feat(explorer): add backgrounds to the search suggestions

* refactor: add styles to search ui kit

* revert changes

* fix: remove unnecessary backdrop-blur

* fix: remove map

* feat(explorer): add darkmode support to epoch page (#4160)

* feat: polish darkmode

* fix format

* feat: update imports

* feat(explorer): improve darkmode colors for transaction page (#4158)

* feat(explorer): improve darkmode colors for transaction page

* feat: add button to the split panes

---------

Co-authored-by: evavirseda <[email protected]>
  • Loading branch information
VmMad and evavirseda authored Nov 25, 2024
1 parent 15f6ea6 commit 3ed9c13
Show file tree
Hide file tree
Showing 24 changed files with 147 additions and 61 deletions.
8 changes: 8 additions & 0 deletions apps/explorer/src/components/ThemedIotaLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { IotaLogoWeb } from '@iota/ui-icons';

export function ThemedIotaLogo(): React.JSX.Element {
return <IotaLogoWeb className="text-neutral-10 dark:text-neutral-92" width={137} height={36} />;
}
12 changes: 6 additions & 6 deletions apps/explorer/src/components/footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

import { Divider } from '@iota/apps-ui-kit';
import { LegalLinks, LegalText } from './Legal';
import { IotaLogoWeb } from '@iota/ui-icons';
import { Link } from '~/components/ui';
import { FOOTER_LINKS } from '~/lib/constants';
import { ThemedIotaLogo } from '../ThemedIotaLogo';

function FooterLinks(): JSX.Element {
return (
Expand All @@ -26,11 +26,11 @@ function FooterLinks(): JSX.Element {

function Footer(): JSX.Element {
return (
<footer className="sticky top-[100%] bg-neutral-96 px-5 py-10 md:px-10 md:py-14">
<footer className="sticky top-[100%] px-5 py-10 md:px-10 md:py-14">
<nav className="container flex flex-col justify-center gap-md md:gap-lg">
<div className="flex flex-col-reverse items-center gap-7.5 md:flex-row md:justify-between ">
<div className="hidden self-center text-neutral-10 md:flex md:self-start">
<IotaLogoWeb width={137} height={36} />
<div className="hidden self-center md:flex md:self-start">
<ThemedIotaLogo />
</div>
<div>
<FooterLinks />
Expand All @@ -42,8 +42,8 @@ function Footer(): JSX.Element {
<LegalLinks />
</div>
</nav>
<div className="mt-4 flex justify-center pt-5 text-neutral-10 md:hidden md:self-start">
<IotaLogoWeb width={137} height={36} />
<div className="mt-4 flex justify-center pt-5 md:hidden md:self-start">
<ThemedIotaLogo />
</div>
<p className="mt-8 w-full text-center text-body-sm text-neutral-40">{EXPLORER_REV}</p>
</footer>
Expand Down
10 changes: 7 additions & 3 deletions apps/explorer/src/components/gas-breakdown/GasBreakdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ function GasPaymentLinks({ objectIds }: { objectIds: string[] }): JSX.Element {
function GasInfo({ label, info }: { label: string; info?: React.ReactNode }) {
return (
<div className="flex flex-col gap-2 md:flex-row md:gap-10">
<span className="w-full flex-shrink-0 text-label-lg text-neutral-40 dark:text-neutral-60 md:w-40">
<span className="w-full flex-shrink-0 text-label-lg text-neutral-40 md:w-40 dark:text-neutral-60">
{label}
</span>
{info ? (
info
) : (
<span className="text-label-lg text-neutral-40 dark:text-neutral-60 md:w-40">
<span className="text-label-lg text-neutral-40 md:w-40 dark:text-neutral-60">
--
</span>
)}
Expand Down Expand Up @@ -91,7 +91,11 @@ export function GasBreakdown({ summary }: GasBreakdownProps): JSX.Element | null
const isSponsored = gasData.isSponsored;

return (
<CollapsibleCard collapsible render={({ isOpen }) => <Title title="Gas & Storage Fee" />}>
<CollapsibleCard
collapsible
render={({ isOpen }) => <Title title="Gas & Storage Fee" />}
hideBorder
>
<div className="px-md--rs pb-lg pt-xs">
<Accordion hideBorder>
<AccordionContent isExpanded>
Expand Down
12 changes: 7 additions & 5 deletions apps/explorer/src/components/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,29 @@
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { IotaLogoWeb } from '@iota/ui-icons';

import { NetworkSelector } from '../network';
import Search from '../search/Search';
import { LinkWithQuery } from '~/components/ui';
import { ThemeSwitcher, ThemedIotaLogo } from '~/components';

function Header(): JSX.Element {
return (
<header className="flex h-header justify-center overflow-visible bg-neutral-98">
<header className="flex h-header justify-center overflow-visible backdrop-blur-lg">
<div className="container flex h-full flex-1 items-center justify-between gap-5">
<LinkWithQuery
data-testid="nav-logo-button"
to="/"
className="flex flex-nowrap items-center gap-1 text-neutral-10"
>
<IotaLogoWeb width={137} height={36} />
<ThemedIotaLogo />
</LinkWithQuery>
<div className="flex w-[360px] justify-center">
<Search />
</div>
<NetworkSelector />
<div className="flex flex-row gap-xs">
<ThemeSwitcher />
<NetworkSelector />
</div>
</div>
</header>
);
Expand Down
53 changes: 53 additions & 0 deletions apps/explorer/src/components/header/ThemeSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { Button, ButtonType } from '@iota/apps-ui-kit';
import { DarkMode, LightMode } from '@iota/ui-icons';
import { useEffect, useLayoutEffect } from 'react';
import { useTheme, Theme } from '@iota/core';

export function ThemeSwitcher(): React.JSX.Element {
const { theme, setTheme } = useTheme();

const ThemeIcon = theme === Theme.Dark ? DarkMode : LightMode;

function handleOnClick(): void {
const newTheme = theme === Theme.Light ? Theme.Dark : Theme.Light;
setTheme(newTheme);
saveThemeToLocalStorage(newTheme);
}

function saveThemeToLocalStorage(newTheme: Theme): void {
localStorage.setItem('theme', newTheme);
}

function updateDocumentClass(theme: Theme): void {
document.documentElement.classList.toggle('dark', theme === Theme.Dark);
}

useLayoutEffect(() => {
const storedTheme = localStorage.getItem('theme') as Theme | null;
if (storedTheme) {
setTheme(storedTheme);
updateDocumentClass(storedTheme);
} else {
const prefersDarkTheme = window.matchMedia('(prefers-color-scheme: dark)').matches;
const preferredTheme = prefersDarkTheme ? Theme.Dark : Theme.Light;

setTheme(preferredTheme);
updateDocumentClass(preferredTheme);
}
}, []);

useEffect(() => {
updateDocumentClass(theme);
}, [theme]);

return (
<Button
type={ButtonType.Ghost}
onClick={handleOnClick}
icon={<ThemeIcon className="h-5 w-5" />}
/>
);
}
1 change: 1 addition & 0 deletions apps/explorer/src/components/header/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
// SPDX-License-Identifier: Apache-2.0

export * from './Header';
export * from './ThemeSwitcher';
1 change: 1 addition & 0 deletions apps/explorer/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ export * from './AreaGraph';
export * from './GraphTooltipContent';
export * from './IotaTokenCard';
export * from './TransactionsCardGraph';
export * from './ThemedIotaLogo';
10 changes: 6 additions & 4 deletions apps/explorer/src/components/layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { KioskClientProvider, useCookieConsentBanner } from '@iota/core';
import { KioskClientProvider, useCookieConsentBanner, ThemeProvider } from '@iota/core';
import { IotaClientProvider, WalletProvider } from '@iota/dapp-kit';
import type { Network } from '@iota/iota-sdk/client';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
Expand Down Expand Up @@ -39,9 +39,11 @@ export function Layout(): JSX.Element {
<WalletProvider autoConnect enableUnsafeBurner={import.meta.env.DEV}>
<KioskClientProvider>
<NetworkContext.Provider value={[network, setNetwork]}>
<Outlet />
<Toaster />
<ReactQueryDevtools />
<ThemeProvider appId="iota-explorer">
<Outlet />
<Toaster />
<ReactQueryDevtools />
</ThemeProvider>
</NetworkContext.Provider>
</KioskClientProvider>
</WalletProvider>
Expand Down
2 changes: 1 addition & 1 deletion apps/explorer/src/components/layout/PageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function PageLayout({ content, loading }: PageLayoutProps): JSX.Element {
: "The explorer is running slower than usual. We're working to fix the issue and appreciate your patience.";

return (
<div className="relative min-h-screen w-full bg-neutral-98">
<div className="relative min-h-screen w-full">
<section ref={headerRef} className="fixed top-0 z-20 flex w-full flex-col">
{renderNetworkDegradeBanner && (
<InfoBox
Expand Down
2 changes: 1 addition & 1 deletion apps/explorer/src/components/module/PkgModulesWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export function PkgModulesWrapper({
isLoading={false}
suggestions={searchSuggestions}
renderSuggestion={(suggestion) => (
<div className="z-10 flex cursor-pointer justify-between bg-neutral-98">
<div className="z-10 flex cursor-pointer justify-between">
<ListItem
hideBottomBorder
onClick={() => onChangeModule(suggestion.label)}
Expand Down
2 changes: 1 addition & 1 deletion apps/explorer/src/components/object/ObjectFieldsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export function ObjectFieldsCard({
}}
isLoading={false}
renderSuggestion={(suggestion) => (
<div className="flex cursor-pointer justify-between bg-neutral-98">
<div className="flex cursor-pointer justify-between">
<ListItem hideBottomBorder>
<div className="overflow-hidden text-ellipsis">
{suggestion.label}
Expand Down
2 changes: 1 addition & 1 deletion apps/explorer/src/components/search/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function Search(): JSX.Element {
isLoading={isPending || debouncedQuery !== query}
suggestions={results}
renderSuggestion={(suggestion) => (
<div className="flex cursor-pointer justify-between bg-neutral-98">
<div className="flex cursor-pointer justify-between">
<ListItem hideBottomBorder>
<div className="overflow-hidden text-ellipsis">{suggestion.label}</div>
<div className="break-words pl-xs text-caption font-medium uppercase text-steel">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function ProgrammableTxnBlockCard({
const itemsToShow = defaultItemsToShow || items.length;

return (
<CollapsibleCard collapsible initialClose={initialClose} title={cardTitle}>
<CollapsibleCard collapsible initialClose={initialClose} title={cardTitle} hideBorder>
<ExpandableList items={items} defaultItemsToShow={itemsToShow} itemsLabel={itemsLabel}>
<div className="flex flex-col gap-xs overflow-y-auto p-md--rs pt-xs--rs">
{noExpandableList ? <>{items}</> : <ExpandableListItems />}
Expand Down
4 changes: 2 additions & 2 deletions apps/explorer/src/components/ui/ProgressBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ export interface ProgressBarProps {

export function ProgressBar({ progress }: ProgressBarProps): JSX.Element {
return (
<div className="relative w-full rounded-full bg-primary-90">
<div className="relative w-full rounded-full bg-primary-90 dark:bg-primary-10">
<motion.div
variants={getProgressBarVariant(progress)}
className="h-1 rounded-full bg-primary-30"
className="h-1 rounded-full bg-primary-30 dark:bg-primary-80"
initial="initial"
animate="animate"
/>
Expand Down
6 changes: 4 additions & 2 deletions apps/explorer/src/components/ui/RingChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export function RingChartLegend({ data }: RingChartLegendProps): JSX.Element {
style={{ background: colorDisplay }}
className="h-1.5 w-1.5 rounded-full"
/>
<div className="text-label-md text-neutral-10">
<div className="text-label-md text-neutral-10 dark:text-neutral-92">
{value} {label}
</div>
</div>
Expand Down Expand Up @@ -123,7 +123,9 @@ export function RingChart({
</svg>
<div className="absolute inset-0 mx-auto flex items-center justify-center">
<div className="flex flex-col items-center gap-1.5">
<span className="text-title-md text-neutral-10">{total}</span>
<span className="text-title-md text-neutral-10 dark:text-neutral-92">
{total}
</span>
</div>
</div>
</div>
Expand Down
34 changes: 13 additions & 21 deletions apps/explorer/src/components/ui/SplitPanes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { Button, ButtonSize, ButtonType } from '@iota/apps-ui-kit';
import { ArrowRight, ArrowUp } from '@iota/ui-icons';
import { cva, type VariantProps } from 'class-variance-authority';
import clsx from 'clsx';
Expand Down Expand Up @@ -93,35 +94,26 @@ function ResizeHandle({
onDragging={setIsDragging}
>
<div
data-is-dragging={isDragging}
className={clsx(
'relative bg-shader-neutral-light-8 group-hover/container:bg-primary-30 dark:bg-shader-neutral-dark-8',
'relative bg-shader-neutral-light-8 group-hover/container:bg-neutral-70 dark:bg-shader-neutral-dark-8 dark:group-hover/container:bg-primary-80/40',
isHorizontal ? 'h-full w-px' : 'h-px',
noHoverHidden && !isCollapsed && 'bg-transparent',
)}
>
{collapsibleButton && (
<button
type="button"
onClick={togglePanelCollapse}
data-is-dragging={isDragging}
className={clsx([
'group/button',
'flex h-6 w-6 cursor-pointer items-center justify-center rounded-full',
'border border-neutral-70 bg-white text-neutral-60 group-hover/container:border-primary-30',
'hover:bg-primary-30 hover:text-white',
isHorizontal
? 'absolute left-1/2 top-10 -translate-x-2/4'
: 'absolute left-10 top-1/2 -translate-y-2/4',
<div
className={clsx(
'absolute right-0 top-1/2 -translate-y-1/2 translate-x-1/2 transform [&_button]:p-xxs',
noHoverHidden && !isCollapsed && 'hidden group-hover/container:flex',
])}
)}
>
<ChevronButton
className={clsx(
'h-4 w-4 text-neutral-70 group-hover/button:!text-white group-hover/container:text-primary-30',
isCollapsed && 'rotate-180',
)}
<Button
size={ButtonSize.Small}
onClick={togglePanelCollapse}
type={ButtonType.Secondary}
icon={<ChevronButton className={clsx(!isCollapsed && 'rotate-180')} />}
/>
</button>
</div>
)}
</div>
</PanelResizeHandle>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface CollapsibleCardProps {
hideBorder?: boolean;
render?: ({ isOpen }: { isOpen: boolean }) => ReactNode;
supportingTitleElement?: ReactNode;
isTransparentPanel?: boolean;
}

export function CollapsibleCard({
Expand All @@ -38,6 +39,7 @@ export function CollapsibleCard({
hideBorder,
render,
supportingTitleElement,
isTransparentPanel,
}: CollapsibleCardProps) {
const [open, setOpen] = useState(!initialClose);
return collapsible ? (
Expand Down Expand Up @@ -69,7 +71,7 @@ export function CollapsibleCard({
</Accordion>
</div>
) : (
<Panel hasBorder={!hideBorder}>
<Panel hasBorder={!hideBorder} bgColor={isTransparentPanel ? 'bg-transparent' : undefined}>
<Title size={titleSize} title={title ?? ''} />
<div>{children}</div>
{footer && (
Expand Down
8 changes: 8 additions & 0 deletions apps/explorer/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ body,
--steel-dark: theme('colors.steel.dark');
}

:root {
@apply bg-neutral-98;
}

:root.dark {
@apply bg-neutral-4;
}

@layer base {
body {
@apply antialiased;
Expand Down
Loading

0 comments on commit 3ed9c13

Please sign in to comment.