feat: make sidebar permanent with theme toggle, github link

This commit is contained in:
Victor Oliva
2025-08-29 09:49:46 +08:00
parent 5c4129007d
commit 2d490f7dc1
2 changed files with 57 additions and 9 deletions

View File

@@ -1,4 +1,5 @@
import { state, useStateObservable } from "@react-rxjs/core"
import { createSignal } from "@react-rxjs/utils"
import {
createContext,
FC,
@@ -6,7 +7,9 @@ import {
useContext,
useLayoutEffect,
} from "react"
import { fromEvent, map } from "rxjs"
import { fromEvent, map, merge } from "rxjs"
export const [changeTheme$, changeTheme] = createSignal<"light" | "dark">()
const getCurrentMedia = (): "light" | "dark" =>
window.matchMedia
@@ -15,17 +18,30 @@ const getCurrentMedia = (): "light" | "dark" =>
: "light"
: "dark"
const defaultTheme = getCurrentMedia()
const prefLSKey = "theme"
changeTheme$.subscribe((theme) => {
if (getCurrentMedia() === theme) {
localStorage.removeItem(prefLSKey)
} else {
localStorage.setItem(prefLSKey, theme)
}
})
const defaultTheme =
(localStorage.getItem(prefLSKey) as "light" | "dark") || getCurrentMedia()
const ThemeContext = createContext<"light" | "dark">(defaultTheme)
export const useTheme = () => useContext(ThemeContext)
const theme$ = state(
fromEvent<MediaQueryListEvent>(
window.matchMedia("(prefers-color-scheme: dark)"),
"change",
).pipe(map((evt) => (evt.matches ? "dark" : "light"))),
merge(
fromEvent<MediaQueryListEvent>(
window.matchMedia("(prefers-color-scheme: dark)"),
"change",
).pipe(map((evt) => (evt.matches ? "dark" : "light"))),
changeTheme$,
),
defaultTheme,
)

View File

@@ -6,6 +6,8 @@ import { FC, PropsWithChildren, useState } from "react"
import { useLocation } from "react-router-dom"
import { twMerge } from "tailwind-merge"
import { NetworkSwitcher } from "./Network/Network"
import SliderToggle from "@/components/Toggle"
import { changeTheme, useTheme } from "@/ThemeProvider"
const navigationItems = [
{ path: "/explorer", label: "Explorer", important: true },
@@ -13,7 +15,6 @@ const navigationItems = [
{ path: "/extrinsics", label: "Extrinsics", important: true },
{ path: "/constants", label: "Constants", important: false },
{ path: "/runtimeCalls", label: "Runtime Calls", important: true },
{ path: "/rpcCalls", label: "RPC Calls", important: false },
{ path: "/metadata", label: "Metadata", important: false },
]
@@ -61,7 +62,7 @@ export const Header = () => {
<Button
variant="ghost"
size="icon"
className="lg:hidden text-foreground hover:bg-accent"
className="text-foreground hover:bg-accent"
>
<Menu className="h-5 w-5" />
</Button>
@@ -71,7 +72,7 @@ export const Header = () => {
className="bg-background border-accent w-64 pt-10"
>
<NetworkSwitcher forSmallScreen />
<nav className="flex flex-col gap-4">
<nav className="flex flex-col gap-4 lg:hidden">
{navigationItems
.filter(({ important }) => !important)
.map(({ path, label }) => (
@@ -84,6 +85,23 @@ export const Header = () => {
</NavLink>
))}
</nav>
<NavLink to="/rpcCalls" onClick={() => setIsOpen(false)}>
RPC Calls
</NavLink>
<NavLink to="/accounts" onClick={() => setIsOpen(false)}>
Accounts
</NavLink>
<hr />
<ThemeToggle />
<div className="grow" />
<div className="border-t p-2 text-right">
<a
href="https://github.com/polkadot-api/papi-console"
target="_blank"
>
github
</a>
</div>
</SheetContent>
</Sheet>
</div>
@@ -112,3 +130,17 @@ const NavLink: FC<
</Link>
)
}
const ThemeToggle = () => {
const theme = useTheme()
return (
<label className="flex items-center justify-between px-4">
<div>Dark mode</div>
<SliderToggle
isToggled={theme === "dark"}
toggle={() => changeTheme(theme === "dark" ? "light" : "dark")}
/>
</label>
)
}