atproto explorer
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor theme selection

+19 -62
+19 -20
src/App.tsx
··· 6 6 ComAtprotoRepoListRecords, 7 7 ComAtprotoSyncListRepos, 8 8 } from "@atcute/client/lexicons"; 9 - import createProp from "./utils/createProp.js"; 10 9 import { 11 10 A, 12 11 action, ··· 20 19 import { getPDS, resolveHandle } from "./utils/api.js"; 21 20 import { JSONValue } from "./lib/json.jsx"; 22 21 import { AiFillGithub, Bluesky, TbMoonStar, TbSun } from "./lib/svg.jsx"; 23 - 24 - type Theme = "light" | "dark"; 25 - export const theme = createProp<Theme>( 26 - localStorage?.theme || "light", 27 - function (newState: Theme) { 28 - if (newState === "dark") document.documentElement.classList.add("dark"); 29 - else document.documentElement.classList.remove("dark"); 30 - 31 - localStorage.theme = newState; 32 - this[1](newState); 33 - return newState; 34 - }, 35 - ); 36 22 37 23 let rpc: XRPC; 38 24 const [notice, setNotice] = createSignal(""); ··· 297 283 const Layout: Component<RouteSectionProps<unknown>> = (props) => { 298 284 const params = useParams(); 299 285 const [pdsList, setPdsList] = createSignal<any>(); 286 + const [theme, setTheme] = createSignal( 287 + ( 288 + localStorage.theme === "dark" || 289 + (!("theme" in localStorage) && 290 + window.matchMedia("(prefers-color-scheme: dark)").matches) 291 + ) ? 292 + "dark" 293 + : "light", 294 + ); 300 295 301 296 onMount(async () => { 302 297 setNotice(""); ··· 313 308 <div class="basis-1/3"> 314 309 <span 315 310 class="cursor-pointer" 316 - onclick={() => 317 - theme.set(theme.get() === "light" ? "dark" : "light") 318 - } 311 + onclick={() => { 312 + setTheme(theme() === "light" ? "dark" : "light"); 313 + if (theme() === "dark") 314 + document.documentElement.classList.add("dark"); 315 + else document.documentElement.classList.remove("dark"); 316 + localStorage.theme = theme(); 317 + }} 319 318 > 320 - {theme.get() === "light" ? 321 - <TbSun class="size-6" /> 322 - : <TbMoonStar class="size-6" />} 319 + {theme() === "dark" ? 320 + <TbMoonStar class="size-6" /> 321 + : <TbSun class="size-6" />} 323 322 </span> 324 323 </div> 325 324 <div class="basis-1/3 text-center font-mono text-xl font-bold">
-42
src/utils/createProp.ts
··· 1 - import { Accessor, createSignal, Signal } from "solid-js"; 2 - 3 - type Updatable<T> = T | ((prev: T) => T); 4 - type Setter<T> = (updatable: Updatable<T>) => T; 5 - interface Prop<T> { 6 - get: Accessor<T>; 7 - set: Setter<T>; 8 - } 9 - const createProp = <T>( 10 - initial: T | Signal<T>, 11 - setterOverrider?: (this: Signal<T>, value: T) => T, 12 - accessorOverrider?: (accessor: Accessor<T>) => Accessor<T>, 13 - ): Prop<T> => { 14 - // Type guard to check if initial is Signal<T> 15 - function isSignal<T>(value: any): value is Signal<T> { 16 - return ( 17 - Array.isArray(value) && 18 - value.length === 2 && 19 - typeof value[0] === "function" && 20 - typeof value[1] === "function" 21 - ); 22 - } 23 - const signal = 24 - isSignal(initial) ? (initial as Signal<T>) : createSignal<T>(initial as T); 25 - 26 - let setter: Setter<T>; 27 - if (setterOverrider) { 28 - const overrider = setterOverrider.bind(signal); 29 - setter = (updatable: Updatable<T>) => 30 - overrider( 31 - typeof updatable === "function" ? 32 - (updatable as Function)(signal[0]()) 33 - : updatable, 34 - ); 35 - } else setter = signal[1]; 36 - 37 - return { 38 - get: accessorOverrider ? accessorOverrider(signal[0]) : signal[0], 39 - set: setter, 40 - }; 41 - }; 42 - export default createProp;