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 TabRouteScrollState = { 25 activeTab: string; 26 scrollPositions: Record<string, number>; 27}; 28/** 29 * @deprecated should be safe to remove i think 30 */ 31export const notificationsScrollAtom = atom<TabRouteScrollState>({ 32 activeTab: "mentions", 33 scrollPositions: {}, 34}); 35 36export type InteractionFilter = { 37 likes: boolean; 38 reposts: boolean; 39 quotes: boolean; 40 replies: boolean; 41 showAll: boolean; 42}; 43const defaultFilters: InteractionFilter = { 44 likes: true, 45 reposts: true, 46 quotes: true, 47 replies: true, 48 showAll: false, 49}; 50export const postInteractionsFiltersAtom = atomWithStorage<InteractionFilter>( 51 "postInteractionsFilters", 52 defaultFilters 53); 54 55export const reusableTabRouteScrollAtom = atom<Record<string, TabRouteScrollState | undefined> | undefined>({}); 56 57export const likedPostsAtom = atomWithStorage<Record<string, string>>( 58 "likedPosts", 59 {} 60); 61 62export const defaultconstellationURL = "constellation.microcosm.blue"; 63export const constellationURLAtom = atomWithStorage<string>( 64 "constellationURL", 65 defaultconstellationURL 66); 67export const defaultslingshotURL = "slingshot.microcosm.blue"; 68export const slingshotURLAtom = atomWithStorage<string>( 69 "slingshotURL", 70 defaultslingshotURL 71); 72export const defaultImgCDN = "cdn.bsky.app"; 73export const imgCDNAtom = atomWithStorage<string>("imgcdnurl", defaultImgCDN); 74export const defaultVideoCDN = "video.bsky.app"; 75export const videoCDNAtom = atomWithStorage<string>( 76 "videocdnurl", 77 defaultVideoCDN 78); 79 80export const defaulthue = 28; 81export const hueAtom = atomWithStorage<number>("hue", defaulthue); 82 83export const isAtTopAtom = atom<boolean>(true); 84 85type ComposerState = 86 | { kind: "closed" } 87 | { kind: "root" } 88 | { kind: "reply"; parent: string } 89 | { kind: "quote"; subject: string }; 90export const composerAtom = atom<ComposerState>({ kind: "closed" }); 91 92//export const agentAtom = atom<Agent | null>(null); 93//export const authedAtom = atom<boolean>(false); 94 95export function useAtomCssVar(atom: typeof hueAtom, cssVar: string) { 96 const value = useAtomValue(atom); 97 98 useEffect(() => { 99 document.documentElement.style.setProperty(cssVar, value.toString()); 100 }, [value, cssVar]); 101 102 useEffect(() => { 103 document.documentElement.style.setProperty(cssVar, value.toString()); 104 }, []); 105} 106 107hueAtom.onMount = (setAtom) => { 108 const stored = localStorage.getItem("hue"); 109 if (stored != null) setAtom(Number(stored)); 110}; 111// export function initAtomToCssVar(atom: typeof hueAtom, cssVar: string) { 112// const initial = store.get(atom); 113// console.log("atom get ", initial); 114// document.documentElement.style.setProperty(cssVar, initial.toString()); 115// }