atmosphere explorer
0
fork

Configure Feed

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

at fbdda4e2a833375d8b46175a2dc8f053e771361d 207 lines 8.9 kB view raw
1import { Handle } from "@atcute/lexicons"; 2import { Meta, MetaProvider, Title } from "@solidjs/meta"; 3import { A, RouteSectionProps, useLocation, useNavigate } from "@solidjs/router"; 4import { createEffect, ErrorBoundary, onCleanup, onMount, Show, Suspense } from "solid-js"; 5import { AccountManager } from "./auth/account.jsx"; 6import { agent } from "./auth/state.js"; 7import { RecordEditor } from "./components/create"; 8import { DropdownMenu, MenuProvider, MenuSeparator, NavMenu } from "./components/dropdown.jsx"; 9import { NavBar } from "./components/navbar.jsx"; 10import { NotificationContainer } from "./components/notification.jsx"; 11import { PermissionPromptContainer } from "./components/permission-prompt.jsx"; 12import { Search, SearchButton } from "./components/search.jsx"; 13import { themeEvent } from "./components/theme.jsx"; 14import { resolveHandle } from "./utils/api.js"; 15import { plcDirectory } from "./views/settings.jsx"; 16 17export const canHover = window.matchMedia("(hover: hover) and (pointer: fine)").matches; 18 19const headers: Record<string, string> = { 20 "did:plc:ia76kvnndjutgedggx2ibrem": "bunny.jpg", 21 "did:plc:oisofpd7lj26yvgiivf3lxsi": "puppy.jpg", 22 "did:plc:vwzwgnygau7ed7b7wt5ux7y2": "water.webp", 23 "did:plc:uu5axsmbm2or2dngy4gwchec": "city.webp", 24 "did:plc:aokggmp5jzj4nc5jifhiplqc": "bridge.jpg", 25 "did:plc:bnqkww7bjxaacajzvu5gswdf": "forest.jpg", 26 "did:plc:p2cp5gopk7mgjegy6wadk3ep": "aurora.jpg", 27 "did:plc:ucaezectmpny7l42baeyooxi": "almaty.webp", 28 "did:plc:7rfssi44thh6f4ywcl3u5nvt": "sonic.jpg", 29}; 30 31const Layout = (props: RouteSectionProps<unknown>) => { 32 const location = useLocation(); 33 const navigate = useNavigate(); 34 35 if (location.search.includes("hrt=true")) localStorage.setItem("hrt", "true"); 36 else if (location.search.includes("hrt=false")) localStorage.setItem("hrt", "false"); 37 if (location.search.includes("sailor=true")) localStorage.setItem("sailor", "true"); 38 else if (location.search.includes("sailor=false")) localStorage.setItem("sailor", "false"); 39 40 createEffect(async () => { 41 if (props.params.repo && !props.params.repo.startsWith("did:")) { 42 const did = await resolveHandle(props.params.repo as Handle); 43 navigate(location.pathname.replace(props.params.repo, did), { replace: true }); 44 } 45 }); 46 47 onMount(() => { 48 window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", themeEvent); 49 50 const handleGoToRepo = (ev: KeyboardEvent) => { 51 if (document.querySelector("[data-modal]")) return; 52 if (ev.target instanceof HTMLInputElement || ev.target instanceof HTMLTextAreaElement) return; 53 54 if (ev.key === "g" && agent()?.sub) { 55 ev.preventDefault(); 56 navigate(`/at://${agent()!.sub}`); 57 } 58 }; 59 60 window.addEventListener("keydown", handleGoToRepo); 61 onCleanup(() => window.removeEventListener("keydown", handleGoToRepo)); 62 63 if (localStorage.getItem("sailor") === "true") { 64 const style = document.createElement("style"); 65 style.textContent = ` 66 html, * { 67 cursor: url(/cursor.cur), pointer; 68 } 69 70 .star { 71 position: fixed; 72 pointer-events: none; 73 z-index: 9999; 74 font-size: 20px; 75 animation: sparkle 0.8s ease-out forwards; 76 } 77 78 @keyframes sparkle { 79 0% { 80 opacity: 1; 81 transform: translate(0, 0) rotate(var(--ttheta1)) scale(1); 82 } 83 100% { 84 opacity: 0; 85 transform: translate(var(--tx), var(--ty)) rotate(var(--ttheta2)) scale(0); 86 } 87 } 88 `; 89 document.head.appendChild(style); 90 91 let lastTime = 0; 92 const throttleDelay = 30; 93 94 document.addEventListener("mousemove", (e) => { 95 const now = Date.now(); 96 if (now - lastTime < throttleDelay) return; 97 lastTime = now; 98 99 const star = document.createElement("div"); 100 star.className = "star"; 101 star.textContent = "✨"; 102 star.style.left = e.clientX + "px"; 103 star.style.top = e.clientY + "px"; 104 105 const tx = (Math.random() - 0.5) * 50; 106 const ty = (Math.random() - 0.5) * 50; 107 const ttheta1 = Math.random() * 360; 108 const ttheta2 = ttheta1 + (Math.random() - 0.5) * 540; 109 star.style.setProperty("--tx", tx + "px"); 110 star.style.setProperty("--ty", ty + "px"); 111 star.style.setProperty("--ttheta1", ttheta1 + "deg"); 112 star.style.setProperty("--ttheta2", ttheta2 + "deg"); 113 114 document.body.appendChild(star); 115 116 setTimeout(() => star.remove(), 800); 117 }); 118 } 119 }); 120 121 return ( 122 <MetaProvider> 123 <Title>PDSls</Title> 124 <Show when={location.pathname !== "/"}> 125 <Meta name="robots" content="noindex, nofollow" /> 126 </Show> 127 <div id="main" class="mx-auto mb-8 flex max-w-lg flex-col items-center p-3"> 128 <header 129 class={`dark:shadow-dark-700 mb-3 flex h-13 w-full items-center justify-between rounded-xl border-[0.5px] border-neutral-300 bg-neutral-50 bg-size-[95%] bg-right bg-no-repeat p-2 pl-3 shadow-xs [--header-bg:#fafafa] [--trans-blue:#5BCEFA90] [--trans-pink:#F5A9B890] [--trans-white:#FFFFFF90] dark:border-neutral-700 dark:bg-neutral-800 dark:[--header-bg:#262626] dark:[--trans-blue:#5BCEFAa0] dark:[--trans-pink:#F5A9B8a0] dark:[--trans-white:#FFFFFFa0] ${localStorage.getItem("hrt") === "true" ? "bg-[linear-gradient(to_left,transparent_10%,var(--header-bg)_85%),linear-gradient(to_bottom,var(--trans-blue)_0%,var(--trans-blue)_20%,var(--trans-pink)_20%,var(--trans-pink)_40%,var(--trans-white)_40%,var(--trans-white)_60%,var(--trans-pink)_60%,var(--trans-pink)_80%,var(--trans-blue)_80%,var(--trans-blue)_100%)]" : ""}`} 130 style={{ 131 "background-image": 132 props.params.repo && props.params.repo in headers ? 133 `linear-gradient(to left, transparent 10%, var(--header-bg) 85%), url(/headers/${headers[props.params.repo]})` 134 : undefined, 135 }} 136 > 137 <A 138 href="/" 139 style='font-feature-settings: "cv05"' 140 class="relative flex items-center gap-1 text-xl font-semibold" 141 > 142 <span class="iconify tabler--binary-tree-filled text-[#76c4e5]"></span> 143 <span>PDSls</span> 144 <Show when={localStorage.getItem("hrt") === "true"}> 145 <img 146 src="/ribbon.webp" 147 alt="" 148 class="pointer-events-none absolute -top-3 -right-4 w-8 rotate-15" 149 /> 150 </Show> 151 </A> 152 <div class="relative flex items-center gap-0.5 rounded-lg bg-neutral-50/60 p-1 dark:bg-neutral-800/60"> 153 <div class="mr-1"> 154 <SearchButton /> 155 </div> 156 <Show when={agent()}> 157 <RecordEditor create={true} scope="create" /> 158 </Show> 159 <AccountManager /> 160 <MenuProvider> 161 <DropdownMenu icon="lucide--menu text-lg" buttonClass="rounded-md p-1.5"> 162 <NavMenu href="/jetstream" label="Jetstream" icon="lucide--radio-tower" /> 163 <NavMenu href="/firehose" label="Firehose" icon="lucide--rss" /> 164 <NavMenu href="/spacedust" label="Spacedust" icon="lucide--orbit" /> 165 <MenuSeparator /> 166 <NavMenu href="/labels" label="Labels" icon="lucide--tag" /> 167 <NavMenu href="/car" label="Archive tools" icon="lucide--folder-archive" /> 168 <MenuSeparator /> 169 <NavMenu href="/settings" label="Settings" icon="lucide--settings" /> 170 </DropdownMenu> 171 </MenuProvider> 172 </div> 173 </header> 174 <div class="flex w-full flex-col items-center gap-3 text-pretty"> 175 <Search /> 176 <Show when={props.params.pds}> 177 <NavBar params={props.params} /> 178 </Show> 179 <Show keyed when={location.pathname}> 180 <ErrorBoundary 181 fallback={(err) => <div class="mt-3 wrap-anywhere">Error: {err.message}</div>} 182 > 183 <Suspense 184 fallback={ 185 <span class="iconify lucide--loader-circle mt-3 animate-spin text-xl"></span> 186 } 187 > 188 {props.children} 189 </Suspense> 190 </ErrorBoundary> 191 </Show> 192 </div> 193 <NotificationContainer /> 194 <PermissionPromptContainer /> 195 <Show when={plcDirectory() !== "https://plc.directory"}> 196 <div class="dark:bg-dark-500 fixed right-0 bottom-0 left-0 z-10 flex items-center justify-center bg-neutral-100 px-3 py-1 text-xs"> 197 <span> 198 PLC directory: <span class="font-medium">{plcDirectory()}</span> 199 </span> 200 </div> 201 </Show> 202 </div> 203 </MetaProvider> 204 ); 205}; 206 207export { Layout };