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};
28export const notificationsScrollAtom = atom<TabRouteScrollState>({
29 activeTab: "mentions",
30 scrollPositions: {},
31});
32
33export const reusableTabRouteScrollAtom = atom<Record<string, TabRouteScrollState | undefined> | undefined>({});
34
35export const likedPostsAtom = atomWithStorage<Record<string, string>>(
36 "likedPosts",
37 {}
38);
39
40export const defaultconstellationURL = "constellation.microcosm.blue";
41export const constellationURLAtom = atomWithStorage<string>(
42 "constellationURL",
43 defaultconstellationURL
44);
45export const defaultslingshotURL = "slingshot.microcosm.blue";
46export const slingshotURLAtom = atomWithStorage<string>(
47 "slingshotURL",
48 defaultslingshotURL
49);
50export const defaultImgCDN = "cdn.bsky.app";
51export const imgCDNAtom = atomWithStorage<string>("imgcdnurl", defaultImgCDN);
52export const defaultVideoCDN = "video.bsky.app";
53export const videoCDNAtom = atomWithStorage<string>(
54 "videocdnurl",
55 defaultVideoCDN
56);
57
58export const defaulthue = 28;
59export const hueAtom = atomWithStorage<number>("hue", defaulthue);
60
61export const isAtTopAtom = atom<boolean>(true);
62
63type ComposerState =
64 | { kind: "closed" }
65 | { kind: "root" }
66 | { kind: "reply"; parent: string }
67 | { kind: "quote"; subject: string };
68export const composerAtom = atom<ComposerState>({ kind: "closed" });
69
70//export const agentAtom = atom<Agent | null>(null);
71//export const authedAtom = atom<boolean>(false);
72
73export function useAtomCssVar(atom: typeof hueAtom, cssVar: string) {
74 const value = useAtomValue(atom);
75
76 useEffect(() => {
77 document.documentElement.style.setProperty(cssVar, value.toString());
78 }, [value, cssVar]);
79
80 useEffect(() => {
81 document.documentElement.style.setProperty(cssVar, value.toString());
82 }, []);
83}
84
85hueAtom.onMount = (setAtom) => {
86 const stored = localStorage.getItem("hue");
87 if (stored != null) setAtom(Number(stored));
88};
89// export function initAtomToCssVar(atom: typeof hueAtom, cssVar: string) {
90// const initial = store.get(atom);
91// console.log("atom get ", initial);
92// document.documentElement.style.setProperty(cssVar, initial.toString());
93// }