alternative tangled frontend (extremely wip)

feat: make profile look good

serenity 292df67c be2255e6

+108 -24
+82 -6
src/components/Profile/PinnedRepos.tsx
··· 1 + import { UnderlineRouterLink } from "@/components/Animated/UnderlineRouterLink"; 1 2 import { Loading } from "@/components/Icons/Loading"; 3 + import { useMiniDoc } from "@/lib/queries/resolve-minidoc"; 2 4 import { usePinnedReposQuery } from "@/lib/queries/resolve-pinned-repos"; 5 + import { ShTangledRepo } from "@/lib/types/lexicons/sh/tangled/repo"; 6 + import { LucideBookMarked, LucideGitBranch } from "lucide-react"; 3 7 4 - export const PinnedRepos = ({ repoUris }: { repoUris: string[] }) => { 8 + export const PinnedRepos = ({ 9 + repoUris, 10 + identity, 11 + }: { 12 + repoUris: string[]; 13 + identity: { did: string; handle: string }; 14 + }) => { 5 15 const { 6 16 isLoading, 7 17 error: pinnedReposError, ··· 15 25 if (isLoading || !pinnedReposData) return <Loading />; 16 26 17 27 return ( 18 - <div> 19 - {pinnedReposData.map((pinnedRepo) => ( 20 - <div> 21 - <p>{pinnedRepo.name}</p> 28 + <div className="flex flex-1 flex-col gap-2 px-4 pt-2"> 29 + <h2 className="text-lg font-semibold">Pinned Repositories</h2> 30 + <div className="grid flex-1 grid-cols-2 gap-4"> 31 + {pinnedReposData.length === 0 ? ( 32 + <div> 33 + {/* TODO: don't check length at all. instead, when giving the repoUris prop, check the length and if it's less than six, fill the remaining slots (up to 6) with repos from the listRecords call.*/} 34 + <p>no pinned repos :(</p> 35 + </div> 36 + ) : ( 37 + pinnedReposData.map((pinnedRepo) => ( 38 + <PinnedRepo 39 + repo={pinnedRepo.value} 40 + isOwner={ 41 + pinnedRepo.uri.split("/")[2] === identity.did 42 + } 43 + repoUri={pinnedRepo.uri} 44 + /> 45 + )) 46 + )} 47 + </div> 48 + </div> 49 + ); 50 + }; 51 + 52 + const PinnedRepo = ({ 53 + repo, 54 + isOwner, 55 + repoUri, 56 + }: { 57 + repo: ShTangledRepo; 58 + isOwner: boolean; 59 + repoUri: string; 60 + }) => { 61 + const isForked = !!repo.source; 62 + const did = repoUri.split("/")[2]; 63 + const { 64 + isLoading: miniDocLoading, 65 + error: miniDocError, 66 + data: miniDocData, 67 + } = useMiniDoc(did); 68 + 69 + if (miniDocError && !miniDocLoading) 70 + return <p>Could not fetch pinned repos data.{miniDocError.message}</p>; 71 + if (miniDocLoading || !miniDocData) return <Loading />; 72 + 73 + const { handle: ownerHandle } = miniDocData; 74 + 75 + return ( 76 + <div className="border-overlay0 flex flex-col gap-1 rounded-sm border p-2 pt-3"> 77 + <div className="flex flex-col gap-1"> 78 + <div className="flex items-center"> 79 + {isOwner ? ( 80 + <LucideBookMarked height={16} className="text-text" /> 81 + ) : ( 82 + <LucideGitBranch height={16} className="text-text" /> 83 + )} 84 + <UnderlineRouterLink 85 + to={`/${ownerHandle}/${repo.name}`} 86 + underlineColor="bg-text" 87 + className="text-text" 88 + > 89 + <p> 90 + @{ownerHandle}/{repo.name} 91 + </p>{" "} 92 + </UnderlineRouterLink> 22 93 </div> 23 - ))} 94 + {repo.description && ( 95 + <p className="text-subtext pl-2 text-sm"> 96 + {repo.description} 97 + </p> 98 + )} 99 + </div> 24 100 </div> 25 101 ); 26 102 };
+7 -6
src/components/Profile/ProfileOverview.tsx
··· 61 61 if (err) return <p>{err.message}</p>; 62 62 63 63 const avatarUri = avatarQueryData === "#" ? undefined : avatarQueryData; 64 - const { handle } = miniDocQueryData; 64 + const { handle, did } = miniDocQueryData; 65 65 const { 66 66 pronouns, 67 67 description, ··· 72 72 } = profileQueryData; 73 73 74 74 return ( 75 - <div className="bg-surface0 flex w-256 justify-between gap-2 pt-8"> 76 - <div className="flex flex-col gap-4"> 75 + <div className="bg-surface0 flex w-256 gap-2 pt-8"> 76 + <div className="flex flex-col gap-4 w-64"> 77 77 {!avatarUri ? ( 78 78 <div className="flex h-24 w-24 items-center justify-center"> 79 79 <Loading /> ··· 173 173 })} 174 174 </div> 175 175 </div> 176 - <div> 177 - <PinnedRepos repoUris={pinnedRepositories ?? []} /> 178 - </div> 176 + <PinnedRepos 177 + repoUris={pinnedRepositories ?? []} 178 + identity={{ did, handle }} 179 + /> 179 180 </div> 180 181 ); 181 182 };
+19 -12
src/lib/queries/resolve-pinned-repos.ts
··· 29 29 const res = await fetch(req); 30 30 const data: unknown = await res.json(); 31 31 32 - const { 33 - success, 34 - error, 35 - data: parseData, 36 - } = devSylfrLodestoneResolveOutputBatchSchema.safeParse(data); 32 + // const parseValueResults = parseData.map((element) => { 33 + // return shTangledRepoSchema.safeParse(element.value); 34 + // }); 37 35 38 - if (!success) { 39 - console.error(error); 40 - throw new Error("Could not parse lodestone response correctly."); 36 + const isArray = Array.isArray(data); 37 + 38 + if (!isArray) { 39 + throw new Error( 40 + "Data from lodestone was not an array. Are you sure you called the right param?", 41 + ); 41 42 } 42 43 43 - const parseValueResults = parseData.map((element) => { 44 - return shTangledRepoSchema.safeParse(element.value); 45 - }); 44 + const parseResults = data.map((obj) => 45 + z 46 + .object({ 47 + uri: z.string(), 48 + cid: z.string(), 49 + value: shTangledRepoSchema, 50 + }) 51 + .safeParse(obj), 52 + ); 46 53 47 - return parseValueResults 54 + return parseResults 48 55 .filter((element) => { 49 56 if (!element.success) { 50 57 console.warn(