atmosphere explorer pds.ls
tool typescript atproto

collection filter styling #4

closed opened by futur.blue targeting main from futur.blue/pdsls: filter-styling
Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:uu5axsmbm2or2dngy4gwchec/sh.tangled.repo.pull/3lyecvsfzoe22
+78 -7
Diff #0
+75 -6
src/views/collection.tsx
··· 3 import { $type, ActorIdentifier, InferXRPCBodyOutput } from "@atcute/lexicons"; 4 import * as TID from "@atcute/tid"; 5 import { A, useParams } from "@solidjs/router"; 6 - import { createEffect, createResource, createSignal, For, Show, untrack } from "solid-js"; 7 import { createStore } from "solid-js/store"; 8 - import { Button } from "../components/button.jsx"; 9 import { JSONType, JSONValue } from "../components/json.jsx"; 10 - 11 - 12 13 14 ··· 72 const [batchDelete, setBatchDelete] = createSignal(false); 73 const [lastSelected, setLastSelected] = createSignal<number>(); 74 const [reverse, setReverse] = createSignal(false); 75 const did = params.repo; 76 let pds: string; 77 let rpc: Client; 78 79 const fetchRecords = async () => { 80 if (!pds) pds = await resolvePDS(did); ··· 157 true, 158 ); 159 160 return ( 161 <Show when={records.length || response()}> 162 <div class="flex w-full flex-col items-center"> 163 - <div class="dark:bg-dark-500 sticky top-0 z-5 flex w-screen flex-col items-center justify-center gap-2 bg-neutral-100 pt-1 pb-3"> 164 <div class="flex w-[22rem] items-center gap-2 sm:w-[24rem]"> 165 <Show when={agent() && agent()?.sub === did}> 166 <div class="flex items-center gap-x-2"> ··· 221 </div> 222 <Show when={records.length > 1}> 223 <div class="flex w-[22rem] items-center justify-between gap-x-2 sm:w-[24rem]"> 224 - <Button 225 onClick={() => { 226 setReverse(!reverse());
··· 3 import { $type, ActorIdentifier, InferXRPCBodyOutput } from "@atcute/lexicons"; 4 import * as TID from "@atcute/tid"; 5 import { A, useParams } from "@solidjs/router"; 6 + import { createEffect, createResource, createSignal, For, Show, untrack, onMount, onCleanup } from "solid-js"; 7 import { createStore } from "solid-js/store"; 8 + import { Button, type ButtonProps } from "../components/button.jsx"; 9 import { JSONType, JSONValue } from "../components/json.jsx"; 10 + import { agent } from "../components/login.jsx"; 11 + import { TextInput } from "../components/text-input.jsx"; 12 13 14 ··· 72 const [batchDelete, setBatchDelete] = createSignal(false); 73 const [lastSelected, setLastSelected] = createSignal<number>(); 74 const [reverse, setReverse] = createSignal(false); 75 + const [filterStuck, setFilterStuck] = createSignal(false); 76 const did = params.repo; 77 let pds: string; 78 let rpc: Client; 79 + let sticky!: HTMLDivElement; 80 81 const fetchRecords = async () => { 82 if (!pds) pds = await resolvePDS(did); ··· 159 true, 160 ); 161 162 + const FilterButton = (props: ButtonProps) => { 163 + return <Button 164 + class="flex items-center gap-1 rounded-lg bg-white px-2 py-1.5 text-xs font-semibold border-[0.5px] border-neutral-300 dark:border-neutral-700 shadow-md" 165 + classList={{ 166 + "dark:bg-dark-300 dark:hover:bg-dark-100 dark:active:bg-dark-100 bg-white hover:bg-neutral-50 active:bg-neutral-50": !filterStuck(), 167 + "dark:bg-dark-100 dark:hover:bg-dark-50 dark:active:bg-dark-50 bg-neutral-50 hover:bg-neutral-200 active:bg-neutral-200": filterStuck() 168 + }} 169 + {...props} 170 + /> 171 + } 172 + 173 + onMount(() => { 174 + let ticking = false; 175 + const tick = () => { 176 + const topPx = parseFloat(getComputedStyle(sticky).top); 177 + const { top } = sticky.getBoundingClientRect(); 178 + setFilterStuck(top <= topPx + 0.5); 179 + ticking = false; 180 + }; 181 + 182 + const onScroll = () => { 183 + if (!ticking) { 184 + ticking = true; 185 + requestAnimationFrame(tick); 186 + } 187 + }; 188 + 189 + window.addEventListener("scroll", onScroll, { passive: true }); 190 + 191 + tick(); 192 + 193 + onCleanup(() => { 194 + window.removeEventListener("scroll", onScroll); 195 + }); 196 + }); 197 + 198 return ( 199 <Show when={records.length || response()}> 200 <div class="flex w-full flex-col items-center"> 201 + <div 202 + ref={(el) => (sticky = el)} 203 + class="sticky top-2 z-10 flex flex-col items-center justify-center gap-2 rounded-lg p-3 transition-colors" 204 + classList={{ 205 + "bg-neutral-50 dark:bg-dark-300 border-[0.5px] border-neutral-300 dark:border-neutral-700 shadow-md": filterStuck(), 206 + "bg-transparent border-transparent shadow-none -mt-2": !filterStuck(), 207 + }} 208 + > 209 <div class="flex w-[22rem] items-center gap-2 sm:w-[24rem]"> 210 <Show when={agent() && agent()?.sub === did}> 211 <div class="flex items-center gap-x-2"> ··· 266 </div> 267 <Show when={records.length > 1}> 268 <div class="flex w-[22rem] items-center justify-between gap-x-2 sm:w-[24rem]"> 269 + <FilterButton 270 onClick={() => { 271 setReverse(!reverse()); 272 + setRecords([]); 273 + 274 + 275 + 276 + 277 + 278 + class={`iconify ${reverse() ? "lucide--rotate-ccw" : "lucide--rotate-cw"} text-sm`} 279 + ></span> 280 + Reverse 281 + </FilterButton> 282 + <div> 283 + <Show when={batchDelete()}> 284 + <span>{records.filter((rec) => rec.toDelete).length}</span> 285 + 286 + 287 + 288 + 289 + <div class="flex w-[5rem] items-center justify-end"> 290 + <Show when={cursor()}> 291 + <Show when={!response.loading}> 292 + <FilterButton onClick={() => refetch()}>Load More</FilterButton> 293 + </Show> 294 + <Show when={response.loading}> 295 + <div class="iconify lucide--loader-circle w-[5rem] animate-spin text-xl" />
+3 -1
src/components/button.tsx
··· 2 3 export interface ButtonProps { 4 class?: string; 5 onClick?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent>; 6 children?: JSX.Element; 7 } ··· 12 type="button" 13 class={ 14 props.class ?? 15 - "dark:hover:bg-dark-100 dark:bg-dark-300 dark:shadow-dark-800 dark:active:bg-dark-100 flex items-center gap-1 rounded-lg bg-white px-2 py-1.5 text-xs font-semibold shadow-sm hover:bg-neutral-50 active:bg-neutral-50" 16 } 17 onClick={props.onClick} 18 > 19 {props.children}
··· 2 3 export interface ButtonProps { 4 class?: string; 5 + classList?: Record<string, boolean | undefined>; 6 onClick?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent>; 7 children?: JSX.Element; 8 } ··· 13 type="button" 14 class={ 15 props.class ?? 16 + "dark:hover:bg-dark-100 dark:bg-dark-300 dark:shadow-dark-800 dark:active:bg-dark-100 flex items-center gap-1 rounded-lg bg-white px-2 py-1.5 text-xs font-semibold border-[0.5px] border-neutral-300 dark:border-neutral-700 shadow-md hover:bg-neutral-50 active:bg-neutral-50" 17 } 18 + classList={props.classList} 19 onClick={props.onClick} 20 > 21 {props.children}

History

2 rounds 2 comments
sign up or login to add to the discussion
1 commit
expand
prettier
expand 1 comment

gonna try again with a patch I guess?

closed without merging
futur.blue submitted #0
3 commits
expand
collection filter background on scroll
buttons styling
naming
expand 1 comment

huh weird diff