tangled
alpha
login
or
join now
isuggest.selfce.st
/
strand
3
fork
atom
alternative tangled frontend (extremely wip)
3
fork
atom
overview
issues
pulls
pipelines
feat: make profile look good
serenity
2 weeks ago
292df67c
be2255e6
+108
-24
3 changed files
expand all
collapse all
unified
split
src
components
Profile
PinnedRepos.tsx
ProfileOverview.tsx
lib
queries
resolve-pinned-repos.ts
+82
-6
src/components/Profile/PinnedRepos.tsx
···
1
1
+
import { UnderlineRouterLink } from "@/components/Animated/UnderlineRouterLink";
1
2
import { Loading } from "@/components/Icons/Loading";
3
3
+
import { useMiniDoc } from "@/lib/queries/resolve-minidoc";
2
4
import { usePinnedReposQuery } from "@/lib/queries/resolve-pinned-repos";
5
5
+
import { ShTangledRepo } from "@/lib/types/lexicons/sh/tangled/repo";
6
6
+
import { LucideBookMarked, LucideGitBranch } from "lucide-react";
3
7
4
4
-
export const PinnedRepos = ({ repoUris }: { repoUris: string[] }) => {
8
8
+
export const PinnedRepos = ({
9
9
+
repoUris,
10
10
+
identity,
11
11
+
}: {
12
12
+
repoUris: string[];
13
13
+
identity: { did: string; handle: string };
14
14
+
}) => {
5
15
const {
6
16
isLoading,
7
17
error: pinnedReposError,
···
15
25
if (isLoading || !pinnedReposData) return <Loading />;
16
26
17
27
return (
18
18
-
<div>
19
19
-
{pinnedReposData.map((pinnedRepo) => (
20
20
-
<div>
21
21
-
<p>{pinnedRepo.name}</p>
28
28
+
<div className="flex flex-1 flex-col gap-2 px-4 pt-2">
29
29
+
<h2 className="text-lg font-semibold">Pinned Repositories</h2>
30
30
+
<div className="grid flex-1 grid-cols-2 gap-4">
31
31
+
{pinnedReposData.length === 0 ? (
32
32
+
<div>
33
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
34
+
<p>no pinned repos :(</p>
35
35
+
</div>
36
36
+
) : (
37
37
+
pinnedReposData.map((pinnedRepo) => (
38
38
+
<PinnedRepo
39
39
+
repo={pinnedRepo.value}
40
40
+
isOwner={
41
41
+
pinnedRepo.uri.split("/")[2] === identity.did
42
42
+
}
43
43
+
repoUri={pinnedRepo.uri}
44
44
+
/>
45
45
+
))
46
46
+
)}
47
47
+
</div>
48
48
+
</div>
49
49
+
);
50
50
+
};
51
51
+
52
52
+
const PinnedRepo = ({
53
53
+
repo,
54
54
+
isOwner,
55
55
+
repoUri,
56
56
+
}: {
57
57
+
repo: ShTangledRepo;
58
58
+
isOwner: boolean;
59
59
+
repoUri: string;
60
60
+
}) => {
61
61
+
const isForked = !!repo.source;
62
62
+
const did = repoUri.split("/")[2];
63
63
+
const {
64
64
+
isLoading: miniDocLoading,
65
65
+
error: miniDocError,
66
66
+
data: miniDocData,
67
67
+
} = useMiniDoc(did);
68
68
+
69
69
+
if (miniDocError && !miniDocLoading)
70
70
+
return <p>Could not fetch pinned repos data.{miniDocError.message}</p>;
71
71
+
if (miniDocLoading || !miniDocData) return <Loading />;
72
72
+
73
73
+
const { handle: ownerHandle } = miniDocData;
74
74
+
75
75
+
return (
76
76
+
<div className="border-overlay0 flex flex-col gap-1 rounded-sm border p-2 pt-3">
77
77
+
<div className="flex flex-col gap-1">
78
78
+
<div className="flex items-center">
79
79
+
{isOwner ? (
80
80
+
<LucideBookMarked height={16} className="text-text" />
81
81
+
) : (
82
82
+
<LucideGitBranch height={16} className="text-text" />
83
83
+
)}
84
84
+
<UnderlineRouterLink
85
85
+
to={`/${ownerHandle}/${repo.name}`}
86
86
+
underlineColor="bg-text"
87
87
+
className="text-text"
88
88
+
>
89
89
+
<p>
90
90
+
@{ownerHandle}/{repo.name}
91
91
+
</p>{" "}
92
92
+
</UnderlineRouterLink>
22
93
</div>
23
23
-
))}
94
94
+
{repo.description && (
95
95
+
<p className="text-subtext pl-2 text-sm">
96
96
+
{repo.description}
97
97
+
</p>
98
98
+
)}
99
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
64
-
const { handle } = miniDocQueryData;
64
64
+
const { handle, did } = miniDocQueryData;
65
65
const {
66
66
pronouns,
67
67
description,
···
72
72
} = profileQueryData;
73
73
74
74
return (
75
75
-
<div className="bg-surface0 flex w-256 justify-between gap-2 pt-8">
76
76
-
<div className="flex flex-col gap-4">
75
75
+
<div className="bg-surface0 flex w-256 gap-2 pt-8">
76
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
176
-
<div>
177
177
-
<PinnedRepos repoUris={pinnedRepositories ?? []} />
178
178
-
</div>
176
176
+
<PinnedRepos
177
177
+
repoUris={pinnedRepositories ?? []}
178
178
+
identity={{ did, handle }}
179
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
32
-
const {
33
33
-
success,
34
34
-
error,
35
35
-
data: parseData,
36
36
-
} = devSylfrLodestoneResolveOutputBatchSchema.safeParse(data);
32
32
+
// const parseValueResults = parseData.map((element) => {
33
33
+
// return shTangledRepoSchema.safeParse(element.value);
34
34
+
// });
37
35
38
38
-
if (!success) {
39
39
-
console.error(error);
40
40
-
throw new Error("Could not parse lodestone response correctly.");
36
36
+
const isArray = Array.isArray(data);
37
37
+
38
38
+
if (!isArray) {
39
39
+
throw new Error(
40
40
+
"Data from lodestone was not an array. Are you sure you called the right param?",
41
41
+
);
41
42
}
42
43
43
43
-
const parseValueResults = parseData.map((element) => {
44
44
-
return shTangledRepoSchema.safeParse(element.value);
45
45
-
});
44
44
+
const parseResults = data.map((obj) =>
45
45
+
z
46
46
+
.object({
47
47
+
uri: z.string(),
48
48
+
cid: z.string(),
49
49
+
value: shTangledRepoSchema,
50
50
+
})
51
51
+
.safeParse(obj),
52
52
+
);
46
53
47
47
-
return parseValueResults
54
54
+
return parseResults
48
55
.filter((element) => {
49
56
if (!element.success) {
50
57
console.warn(