BlueSky & more on desktop lazurite.stormlightlabs.org/
tauri rust typescript bluesky appview atproto solid
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 132 lines 3.4 kB view raw
1import type { ExplorerState, ExplorerTargetKind, ExplorerViewState } from "$/lib/api/types/explorer"; 2import { createStore, produce } from "solid-js/store"; 3 4export type Crumb = { label: string; level: ExplorerTargetKind; active: boolean }; 5 6export function createExplorerState() { 7 const [state, setState] = createStore<ExplorerState>({ 8 inputValue: "", 9 current: null, 10 history: [], 11 historyIndex: -1, 12 lexiconIcons: {}, 13 }); 14 15 function setInputValue(value: string) { 16 setState("inputValue", value); 17 } 18 19 function pushView(viewState: ExplorerViewState) { 20 setState(produce((draft) => { 21 draft.history = draft.history.slice(0, draft.historyIndex + 1); 22 draft.history.push(viewState); 23 draft.historyIndex = draft.history.length - 1; 24 draft.current = viewState; 25 })); 26 } 27 28 function goBack(): boolean { 29 if (state.historyIndex > 0) { 30 setState(produce((draft) => { 31 draft.historyIndex -= 1; 32 draft.current = draft.history[draft.historyIndex]; 33 })); 34 return true; 35 } 36 return false; 37 } 38 39 function goForward(): boolean { 40 if (state.historyIndex < state.history.length - 1) { 41 setState(produce((draft) => { 42 draft.historyIndex += 1; 43 draft.current = draft.history[draft.historyIndex]; 44 })); 45 return true; 46 } 47 return false; 48 } 49 50 function goUp(): boolean { 51 const current = state.current; 52 if (!current || !current.resolved) return false; 53 54 const resolved = current.resolved; 55 if (resolved.targetKind === "record" && resolved.collection) { 56 return true; 57 } else if (resolved.targetKind === "collection") { 58 return true; 59 } else if (resolved.targetKind === "repo") { 60 return true; 61 } 62 return false; 63 } 64 65 function canGoBack() { 66 return state.historyIndex > 0; 67 } 68 69 function canGoForward() { 70 return state.historyIndex < state.history.length - 1; 71 } 72 73 function mergeLexiconIcons(icons: Record<string, string | null>) { 74 setState("lexiconIcons", (current) => ({ ...current, ...icons })); 75 } 76 77 function resetLexiconIcons() { 78 setState("lexiconIcons", {}); 79 } 80 81 function getBreadcrumb(): Crumb[] { 82 const current = state.current; 83 if (!current || !current.resolved) return []; 84 85 const resolved = current.resolved; 86 const crumbs: Crumb[] = []; 87 88 if (resolved.pdsUrl) { 89 crumbs.push({ label: "PDS", level: "pds", active: resolved.targetKind === "pds" }); 90 } 91 92 if (resolved.did) { 93 const handle = resolved.handle || resolved.did.slice(0, 20) + "..."; 94 crumbs.push({ label: handle, level: "repo", active: resolved.targetKind === "repo" }); 95 } 96 97 if (resolved.collection) { 98 const nsidParts = resolved.collection.split("."); 99 const shortName = nsidParts.at(-1) || resolved.collection; 100 crumbs.push({ label: shortName, level: "collection", active: resolved.targetKind === "collection" }); 101 } 102 103 if (resolved.rkey) { 104 crumbs.push({ 105 label: resolved.rkey.slice(0, 12) + "...", 106 level: "record", 107 active: resolved.targetKind === "record", 108 }); 109 } 110 111 if (crumbs.length > 0) { 112 crumbs.at(-1)!.active = true; 113 } 114 115 return crumbs; 116 } 117 118 return { 119 state, 120 setState, 121 setInputValue, 122 pushView, 123 goBack, 124 goForward, 125 goUp, 126 canGoBack, 127 canGoForward, 128 mergeLexiconIcons, 129 resetLexiconIcons, 130 getBreadcrumb, 131 }; 132}