Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(explorer): add missing darkmode colors to the homepage #4152

Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions apps/explorer/src/components/AddressesCardGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { useMemo } from 'react';
import { useGetAddressMetrics } from '~/hooks/useGetAddressMetrics';
import { useGetAllEpochAddressMetrics } from '~/hooks/useGetAllEpochAddressMetrics';
import { LabelTextSize, TooltipPosition } from '@iota/apps-ui-kit';
import { StatisticsPanel, GraphTooltip } from './StatisticsPanel';
import { StatisticsPanel } from './StatisticsPanel';
import { GraphTooltipContent } from './GraphTooltipContent';

const GRAPH_DATA_FIELD = 'cumulativeAddresses';
const GRAPH_DATA_TEXT = 'Total addresses';
Expand All @@ -18,7 +19,13 @@ function TooltipContent({ data }: { data: AllEpochsAddressMetrics[number] }): JS
const totalFormatted = formatAmount(data[GRAPH_DATA_FIELD]);

const overline = `${dateFormatted}, Epoch ${data.epoch}`;
return <GraphTooltip overline={overline} title={totalFormatted} subtitle={GRAPH_DATA_TEXT} />;
return (
<GraphTooltipContent
overline={overline}
title={totalFormatted}
subtitle={GRAPH_DATA_TEXT}
/>
);
}

const FALLBACK = '--';
Expand Down
24 changes: 18 additions & 6 deletions apps/explorer/src/components/AreaGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { bisector, extent } from 'd3-array';
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react';
import { throttle } from 'throttle-debounce';

import { GraphTooltipContent } from './GraphTooltipContent';
import { GraphTooltipContainer } from './GraphTooltipContent';

let idCounter = 0;

Expand Down Expand Up @@ -129,21 +129,33 @@ export function AreaGraph<D>({
offsetTop={0}
left={tooltipLeft}
top={tooltipTopAdj}
className="pointer-events-none absolute z-10 h-0 w-max overflow-visible"
className="pointer-events-none absolute z-10 h-0 w-max overflow-visible bg-black"
unstyled
detectBounds
>
<GraphTooltipContent>{tooltipContent(tooltipContentProps)}</GraphTooltipContent>
<GraphTooltipContainer>
{tooltipContent(tooltipContentProps)}
</GraphTooltipContainer>
</TooltipInPortal>
) : null}
<svg width={width} height={height}>
<defs>
<linearGradient id={fillGradientID} gradientTransform="rotate(90)">
<stop stopColor="#0067EE" stopOpacity="0.16" />
<stop offset="1" stopColor="#0067EE" stopOpacity="0" />
<stop
stopColor="currentColor"
className="text-shader-primary-light-16 dark:text-shader-primary-dark-16"
/>
<stop
offset="1"
stopColor="currentColor"
className="text-shader-primary-light-0 dark:text-shader-primary-dark-0"
/>
</linearGradient>
<linearGradient id={lineGradientID}>
<stop stopColor="currentColor" className="text-primary-30" />
<stop
stopColor="currentColor"
className="text-primary-30 dark:text-primary-80"
/>
</linearGradient>
</defs>
<AreaClosed<D>
Expand Down
24 changes: 17 additions & 7 deletions apps/explorer/src/components/GraphTooltipContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,13 @@

import { useTooltipPosition } from '@visx/tooltip';
import clsx from 'clsx';
import { type ReactNode } from 'react';

type GraphTooltipContentProps = {
children: ReactNode;
};

export function GraphTooltipContent({ children }: GraphTooltipContentProps): JSX.Element {
export function GraphTooltipContainer({ children }: React.PropsWithChildren): JSX.Element {
const { isFlippedHorizontally } = useTooltipPosition();
return (
<div
className={clsx(
'w-fit -translate-y-[calc(100%-10px)] rounded-md border border-solid border-neutral-70 bg-neutral-100/90 p-xs shadow-xl',
'w-fit -translate-y-[calc(100%-10px)] rounded-md border border-solid border-neutral-70 bg-neutral-100/90 p-xs shadow-xl dark:border-neutral-30 dark:bg-neutral-10/90 dark:shadow-neutral-0/20',
isFlippedHorizontally
? '-translate-x-[1px] rounded-bl-none'
: 'translate-x-[1px] rounded-br-none',
Expand All @@ -25,3 +20,18 @@ export function GraphTooltipContent({ children }: GraphTooltipContentProps): JSX
</div>
);
}

interface GraphTooltipContentProps {
title: string;
overline: string;
subtitle: string;
}
export function GraphTooltipContent({ title, overline, subtitle }: GraphTooltipContentProps) {
return (
<div className="flex flex-col gap-xxxs">
<span className="text-body-sm text-neutral-40 dark:text-neutral-60">{overline}</span>
<span className="text-label-lg text-neutral-12 dark:text-neutral-98">{title}</span>
<span className="text-body-sm text-neutral-40 dark:text-neutral-60">{subtitle}</span>
</div>
);
}
15 changes: 0 additions & 15 deletions apps/explorer/src/components/StatisticsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,3 @@ export function StatisticsPanel<T>({
</Panel>
);
}

interface GraphTooltipProps {
title: string;
overline: string;
subtitle: string;
}
export function GraphTooltip({ title, overline, subtitle }: GraphTooltipProps) {
return (
<div className="flex flex-col gap-xxxs">
<span className="text-body-sm text-neutral-40">{overline}</span>
<span className="text-label-lg text-neutral-12">{title}</span>
<span className="text-body-sm text-neutral-40">{subtitle}</span>
</div>
);
}
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} />;
}
9 changes: 7 additions & 2 deletions apps/explorer/src/components/TransactionsCardGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import { CoinFormat, formatAmount, formatBalance, formatDate } from '@iota/core';
import { useIotaClientQuery } from '@iota/dapp-kit';
import { LabelTextSize, TooltipPosition } from '@iota/apps-ui-kit';
import { GraphTooltip, StatisticsPanel } from './StatisticsPanel';
import { StatisticsPanel } from './StatisticsPanel';
import { GraphTooltipContent } from './GraphTooltipContent';

interface TooltipContentProps {
data: {
Expand All @@ -24,7 +25,11 @@ function TooltipContent({
const overline = `${dateFormatted}, Epoch ${epoch}`;

return (
<GraphTooltip overline={overline} title={totalFormatted} subtitle="Transaction Blocks" />
<GraphTooltipContent
overline={overline}
title={totalFormatted}
subtitle="Transaction Blocks"
/>
);
}

Expand Down
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
4 changes: 2 additions & 2 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
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
Loading
Loading