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