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// }