an appview-less Bluesky client using Constellation and PDS Queries reddwarf.app
frontend spa bluesky reddwarf microcosm
1import type Agent from "@atproto/api"; 2import { atom, createStore, useAtomValue } from "jotai"; 3import { atomWithStorage } from "jotai/utils"; 4import { useEffect } from "react"; 5 6export const store = createStore(); 7 8export const selectedFeedUriAtom = atomWithStorage<string | null>( 9 "selectedFeedUri", 10 null 11); 12 13//export const feedScrollPositionsAtom = atom<Record<string, number>>({}); 14 15export const feedScrollPositionsAtom = atomWithStorage<Record<string, number>>( 16 "feedscrollpositions", 17 {} 18); 19 20export const likedPostsAtom = atomWithStorage<Record<string, string>>( 21 "likedPosts", 22 {} 23); 24 25export const defaultconstellationURL = "constellation.microcosm.blue"; 26export const constellationURLAtom = atomWithStorage<string>( 27 "constellationURL", 28 defaultconstellationURL 29); 30export const defaultslingshotURL = "slingshot.microcosm.blue"; 31export const slingshotURLAtom = atomWithStorage<string>( 32 "slingshotURL", 33 defaultslingshotURL 34); 35export const defaultaturilistservice = "aturilistservice.reddwarf.app"; 36export const aturiListServiceAtom = atomWithStorage<string>( 37 "aturilistservice", 38 defaultaturilistservice 39); 40export const defaultImgCDN = "cdn.bsky.app"; 41export const imgCDNAtom = atomWithStorage<string>("imgcdnurl", defaultImgCDN); 42export const defaultVideoCDN = "video.bsky.app"; 43export const videoCDNAtom = atomWithStorage<string>( 44 "videocdnurl", 45 defaultVideoCDN 46); 47 48export const defaulthue = 28; 49export const hueAtom = atomWithStorage<number>("hue", defaulthue); 50 51export const isAtTopAtom = atom<boolean>(true); 52 53type ComposerState = 54 | { kind: "closed" } 55 | { kind: "root" } 56 | { kind: "reply"; parent: string } 57 | { kind: "quote"; subject: string }; 58export const composerAtom = atom<ComposerState>({ kind: "closed" }); 59 60export const agentAtom = atom<Agent | null>(null); 61export const authedAtom = atom<boolean>(false); 62 63export function useAtomCssVar(atom: typeof hueAtom, cssVar: string) { 64 const value = useAtomValue(atom); 65 66 useEffect(() => { 67 document.documentElement.style.setProperty(cssVar, value.toString()); 68 }, [value, cssVar]); 69 70 useEffect(() => { 71 document.documentElement.style.setProperty(cssVar, value.toString()); 72 }, []); 73} 74 75hueAtom.onMount = (setAtom) => { 76 const stored = localStorage.getItem("hue"); 77 if (stored != null) setAtom(Number(stored)); 78}; 79// export function initAtomToCssVar(atom: typeof hueAtom, cssVar: string) { 80// const initial = store.get(atom); 81// console.log("atom get ", initial); 82// document.documentElement.style.setProperty(cssVar, initial.toString()); 83// }