Browse Source

feat: add UserHeader

add user profile details via a svelte store

this sets a standard for abstracting ui from data wrappers even when
multiple calls are needed
master
DanConwayDev 2 years ago
parent
commit
4fc877bd3e
No known key found for this signature in database
GPG Key ID: 68E15486D73F75E1
  1. 1
      .storybook/main.ts
  2. BIN
      .storybook/test-assets/test-profile-image.jpg
  3. BIN
      __snapshots__/repo-details--long-and-no-spaces.png
  4. BIN
      __snapshots__/repo-details--long-details.png
  5. BIN
      __snapshots__/repo-details--no-description.png
  6. BIN
      __snapshots__/repo-details--no-name-or-description.png
  7. BIN
      __snapshots__/repo-details--no-relays.png
  8. BIN
      __snapshots__/repo-details--no-tags.png
  9. BIN
      __snapshots__/repo-details--one-maintainer-s-profile-has-no-display-name-or-name.png
  10. BIN
      __snapshots__/repo-details--one-maintainer-s-profile-not-loaded.png
  11. BIN
      __snapshots__/repo-details--one-maintainer-s-profile-only-has-display-name-but-no-name.png
  12. 322
      __snapshots__/repo-details.test.js.snap
  13. BIN
      __snapshots__/users-header--default-5-c-13-d-641.png
  14. BIN
      __snapshots__/users-header--display-name-without-name.png
  15. BIN
      __snapshots__/users-header--loading.png
  16. BIN
      __snapshots__/users-header--name-and-display-name-shows-name.png
  17. BIN
      __snapshots__/users-header--no-image.png
  18. BIN
      __snapshots__/users-header--not-found.png
  19. 86
      __snapshots__/users-header.test.js.snap
  20. 2
      src/lib/components/RepoSummaryCard.stories.svelte
  21. 2
      src/lib/components/ReposSummaryList.stories.svelte
  22. 2
      src/lib/components/repo/RepoDetails.stories.svelte
  23. 26
      src/lib/components/repo/RepoDetails.svelte
  24. 22
      src/lib/components/repo/type.ts
  25. 37
      src/lib/components/repo/vectors.ts
  26. 2
      src/lib/components/users/UserHeader.stories.svelte
  27. 1
      src/lib/components/users/UserHeader.svelte
  28. 2
      src/lib/components/users/vectors.ts
  29. 76
      src/lib/stores/repo.ts
  30. 36
      src/lib/stores/users.ts
  31. 37
      src/lib/wrappers/RepoDetails.svelte
  32. 4
      src/routes/repo/[repo_id]/+page.svelte

1
.storybook/main.ts

@ -13,6 +13,7 @@ const config: StorybookConfig = {
name: "@storybook/sveltekit", name: "@storybook/sveltekit",
options: {}, options: {},
}, },
staticDirs: ['test-assets'],
docs: { docs: {
autodocs: "tag", autodocs: "tag",
}, },

BIN
.storybook/test-assets/test-profile-image.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
__snapshots__/repo-details--long-and-no-spaces.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 54 KiB

BIN
__snapshots__/repo-details--long-details.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 66 KiB

BIN
__snapshots__/repo-details--no-description.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 31 KiB

BIN
__snapshots__/repo-details--no-name-or-description.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 31 KiB

BIN
__snapshots__/repo-details--no-relays.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 27 KiB

BIN
__snapshots__/repo-details--no-tags.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 31 KiB

BIN
__snapshots__/repo-details--one-maintainer-s-profile-has-no-display-name-or-name.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 35 KiB

BIN
__snapshots__/repo-details--one-maintainer-s-profile-not-loaded.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 33 KiB

BIN
__snapshots__/repo-details--one-maintainer-s-profile-only-has-display-name-but-no-name.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 38 KiB

322
__snapshots__/repo-details.test.js.snap

@ -27,16 +27,46 @@ exports[`Repo/Details Long Details smoke-test 1`] = `
<h4> <h4>
maintainers maintainers
</h4> </h4>
<div class="badge badge-accent block my-2"> <div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="carole"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
carole carole
</div> </div>
<div class="badge badge-accent block my-2"> </div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="bob"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
bob bob
</div> </div>
<div class="badge badge-accent block my-2"> </div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="steve"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
steve steve
</div> </div>
</div> </div>
</div>
<div> <div>
<h4> <h4>
relays relays
@ -80,16 +110,46 @@ exports[`Repo/Details Long and No Spaces smoke-test 1`] = `
<h4> <h4>
maintainers maintainers
</h4> </h4>
<div class="badge badge-accent block my-2"> <div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="carole"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
carole carole
</div> </div>
<div class="badge badge-accent block my-2"> </div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="bob"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
bob bob
</div> </div>
<div class="badge badge-accent block my-2"> </div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="steve"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
steve steve
</div> </div>
</div> </div>
</div>
<div> <div>
<h4> <h4>
relays relays
@ -129,16 +189,46 @@ exports[`Repo/Details No Description smoke-test 1`] = `
<h4> <h4>
maintainers maintainers
</h4> </h4>
<div class="badge badge-accent block my-2"> <div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="carole"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
carole carole
</div> </div>
<div class="badge badge-accent block my-2"> </div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="bob"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
bob bob
</div> </div>
<div class="badge badge-accent block my-2"> </div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="steve"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
steve steve
</div> </div>
</div> </div>
</div>
<div> <div>
<h4> <h4>
relays relays
@ -254,16 +344,46 @@ exports[`Repo/Details No Name or Description smoke-test 1`] = `
<h4> <h4>
maintainers maintainers
</h4> </h4>
<div class="badge badge-accent block my-2"> <div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="carole"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
carole carole
</div> </div>
<div class="badge badge-accent block my-2"> </div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="bob"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
bob bob
</div> </div>
<div class="badge badge-accent block my-2"> </div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="steve"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
steve steve
</div> </div>
</div> </div>
</div>
<div> <div>
<h4> <h4>
relays relays
@ -307,16 +427,46 @@ exports[`Repo/Details No Relays smoke-test 1`] = `
<h4> <h4>
maintainers maintainers
</h4> </h4>
<div class="badge badge-accent block my-2"> <div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="carole"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
carole carole
</div> </div>
<div class="badge badge-accent block my-2"> </div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="bob"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
bob bob
</div> </div>
<div class="badge badge-accent block my-2"> </div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="steve"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
steve steve
</div> </div>
</div> </div>
</div>
<div> <div>
<div> <div>
</div> </div>
@ -338,16 +488,46 @@ exports[`Repo/Details No Tags smoke-test 1`] = `
<h4> <h4>
maintainers maintainers
</h4> </h4>
<div class="badge badge-accent block my-2"> <div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="carole"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
carole carole
</div> </div>
<div class="badge badge-accent block my-2"> </div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="bob"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
bob bob
</div> </div>
<div class="badge badge-accent block my-2"> </div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="steve"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
steve steve
</div> </div>
</div> </div>
</div>
<div> <div>
<h4> <h4>
relays relays
@ -391,16 +571,42 @@ exports[`Repo/Details One Maintainer's Profile Has No displayName or Name smoke-
<h4> <h4>
maintainers maintainers
</h4> </h4>
<div class="badge badge-accent block my-2"> <div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="carole"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
carole carole
</div> </div>
<div class="badge badge-neutral block my-2">
cannot find name
</div> </div>
<div class="badge badge-accent block my-2"> <div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded bg-neutral">
</div>
</div>
<div class="flex-auto pl-3 m-auto">
npub18669...
</div>
</div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="steve"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
steve steve
</div> </div>
</div> </div>
</div>
<div> <div>
<h4> <h4>
relays relays
@ -444,15 +650,43 @@ exports[`Repo/Details One Maintainer's Profile Not Loaded smoke-test 1`] = `
<h4> <h4>
maintainers maintainers
</h4> </h4>
<div class="badge badge-accent block my-2"> <div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="carole"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
carole carole
</div> </div>
<div class="badge skeleton my-2 w-40 block">
</div> </div>
<div class="badge badge-accent block my-2"> <div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded skeleton">
</div>
</div>
<div class="flex-auto pl-3 m-auto">
<div class="w-24 h-4 skeleton">
</div>
</div>
</div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="steve"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
steve steve
</div> </div>
</div> </div>
</div>
<div> <div>
<h4> <h4>
relays relays
@ -496,16 +730,46 @@ exports[`Repo/Details One Maintainer's Profile Only Has displayName But No Name
<h4> <h4>
maintainers maintainers
</h4> </h4>
<div class="badge badge-accent block my-2"> <div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="carole"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
carole carole
</div> </div>
<div class="badge badge-accent block my-2">
bob
</div> </div>
<div class="badge badge-accent block my-2"> <div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="DanConwayDev"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
DanConwayDev
</div>
</div>
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="steve"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
steve steve
</div> </div>
</div> </div>
</div>
<div> <div>
<h4> <h4>
relays relays

BIN
__snapshots__/users-header--default-5-c-13-d-641.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
__snapshots__/users-header--display-name-without-name.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
__snapshots__/users-header--loading.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
__snapshots__/users-header--name-and-display-name-shows-name.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
__snapshots__/users-header--no-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
__snapshots__/users-header--not-found.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

86
__snapshots__/users-header.test.js.snap

@ -0,0 +1,86 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Users/Header default smoke-test 1`] = `
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="DanConwayDev"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
DanConwayDev
</div>
</div>
`;
exports[`Users/Header displayName without name smoke-test 1`] = `
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="DanConwayDev"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
DanConwayDev
</div>
</div>
`;
exports[`Users/Header loading smoke-test 1`] = `
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded skeleton">
</div>
</div>
<div class="flex-auto pl-3 m-auto">
<div class="w-24 h-4 skeleton">
</div>
</div>
</div>
`;
exports[`Users/Header name and displayName shows name smoke-test 1`] = `
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded">
<img class="my-0"
src="../test-profile-image.jpg"
alt="Dan"
>
</div>
</div>
<div class="flex-auto pl-3 m-auto">
Dan
</div>
</div>
`;
exports[`Users/Header no image smoke-test 1`] = `
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded bg-neutral">
</div>
</div>
<div class="flex-auto pl-3 m-auto">
DanConwayDev
</div>
</div>
`;
exports[`Users/Header not found smoke-test 1`] = `
<div class="flex my-2">
<div class="avatar flex-none">
<div class="w-8 h-8 rounded bg-neutral">
</div>
</div>
<div class="flex-auto pl-3 m-auto">
npub18669...
</div>
</div>
`;

2
src/lib/components/RepoSummaryCard.stories.svelte

@ -2,7 +2,7 @@
import type { Meta } from "@storybook/svelte"; import type { Meta } from "@storybook/svelte";
import RepoSummaryCard from "./RepoSummaryCard.svelte"; import RepoSummaryCard from "./RepoSummaryCard.svelte";
import { Story, Template } from "@storybook/addon-svelte-csf"; import { Story, Template } from "@storybook/addon-svelte-csf";
import { RepoSummaryCardArgsVectors as vectors } from "./Repo.vectors"; import { RepoSummaryCardArgsVectors as vectors } from "./repo/vectors";
export const meta: Meta<RepoSummaryCard> = { export const meta: Meta<RepoSummaryCard> = {
title: "Repo/Summary/Card", title: "Repo/Summary/Card",

2
src/lib/components/ReposSummaryList.stories.svelte

@ -2,7 +2,7 @@
import type { Meta } from "@storybook/svelte"; import type { Meta } from "@storybook/svelte";
import ReposSummaryList from "./ReposSummaryList.svelte"; import ReposSummaryList from "./ReposSummaryList.svelte";
import { Story, Template } from "@storybook/addon-svelte-csf"; import { Story, Template } from "@storybook/addon-svelte-csf";
import { RepoSummaryCardArgsVectors as vectors } from "./Repo.vectors"; import { RepoSummaryCardArgsVectors as vectors } from "./repo/vectors";
export const meta: Meta<ReposSummaryList> = { export const meta: Meta<ReposSummaryList> = {
title: "Repo/Summary/List", title: "Repo/Summary/List",

2
src/lib/components/RepoDetails.stories.svelte → src/lib/components/repo/RepoDetails.stories.svelte

@ -2,7 +2,7 @@
import type { Meta } from "@storybook/svelte"; import type { Meta } from "@storybook/svelte";
import RepoDetails from "./RepoDetails.svelte"; import RepoDetails from "./RepoDetails.svelte";
import { Story, Template } from "@storybook/addon-svelte-csf"; import { Story, Template } from "@storybook/addon-svelte-csf";
import { RepoDetailsArgsVectors as vectors } from "./Repo.vectors"; import { RepoDetailsArgsVectors as vectors } from "./vectors";
export const meta: Meta<RepoDetails> = { export const meta: Meta<RepoDetails> = {
title: "Repo/Details", title: "Repo/Details",

26
src/lib/components/RepoDetails.svelte → src/lib/components/repo/RepoDetails.svelte

@ -1,31 +1,11 @@
<script lang="ts" context="module"> <script lang="ts" context="module">
import type { NDKUserProfile } from "@nostr-dev-kit/ndk"; import type { NDKUserProfile } from "@nostr-dev-kit/ndk";
export interface Args {
repo_id: string;
name: string;
description: string;
git_server: string;
tags: string[];
maintainers: User[];
relays: string[];
loading?: boolean;
}
export const defaults: Args = {
repo_id: "",
name: "",
description: "",
git_server: "",
tags: [],
maintainers: [],
relays: [],
loading: true,
};
</script> </script>
<script lang="ts"> <script lang="ts">
import type { User } from "./users/type"; import type { User } from "$lib/components/users/type";
import UserHeader from "./users/UserHeader.svelte"; import UserHeader from "$lib/components/users/UserHeader.svelte";
import { defaults } from "./type";
export let { export let {
repo_id, repo_id,

22
src/lib/components/repo/type.ts

@ -0,0 +1,22 @@
import type { User } from "../users/type";
export interface Repo {
repo_id: string;
name: string;
description: string;
git_server: string;
tags: string[];
maintainers: User[];
relays: string[];
loading: boolean;
}
export const defaults: Repo = {
repo_id: "",
name: "",
description: "",
git_server: "",
tags: [],
maintainers: [],
relays: [],
loading: true,
};

37
src/lib/components/Repo.vectors.ts → src/lib/components/repo/vectors.ts

@ -1,8 +1,8 @@
import type { Args as SummaryCardArgs } from "./RepoSummaryCard.svelte"; import type { Args as SummaryCardArgs } from "../RepoSummaryCard.svelte";
import type { Args as DetailsArgs } from "./RepoDetails.svelte";
import type { NDKUserProfile } from "@nostr-dev-kit/ndk"; import type { NDKUserProfile } from "@nostr-dev-kit/ndk";
import type { User } from "./users/type"; import type { User } from "../users/type";
import { UserVectors, withName } from "./users/vectors"; import { UserVectors, withName } from "../users/vectors";
import type { Repo } from "./type";
export let RepoSummaryCardArgsVectors = { export let RepoSummaryCardArgsVectors = {
Short: { Short: {
@ -20,7 +20,7 @@ export let RepoSummaryCardArgsVectors = {
"LoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsum>", "LoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsum>",
} as SummaryCardArgs, } as SummaryCardArgs,
}; };
let base: DetailsArgs = { let base: Repo = {
repo_id: "9ee507fc4357d7ee16a5d8901bedcd103f23c17d", repo_id: "9ee507fc4357d7ee16a5d8901bedcd103f23c17d",
name: "Short Name", name: "Short Name",
description: "short description", description: "short description",
@ -36,46 +36,47 @@ let base: DetailsArgs = {
withName(UserVectors.default, "bob"), withName(UserVectors.default, "bob"),
withName(UserVectors.default, "steve"), withName(UserVectors.default, "steve"),
], ],
loading: false,
}; };
export let RepoDetailsArgsVectors = { export let RepoDetailsArgsVectors = {
Short: { ...base, } as DetailsArgs, Short: { ...base, } as Repo,
Long: { Long: {
...base, ...base,
name: "Long Name that goes on and on and on and on and on and on and on and on and on", name: "Long Name that goes on and on and on and on and on and on and on and on and on",
description: description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis quis nisl eget turpis congue molestie. Nulla vitae purus nec augue accumsan facilisis sed sed ligula. Vestibulum sed risus lacinia risus lacinia molestie. Ut lorem quam, consequat eget tempus in, rhoncus vel nunc. Duis efficitur a leo vel sodales. Nam id fermentum lacus. Etiam nec placerat velit. Praesent ac consectetur est. Aenean iaculis commodo enim.\n Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis quis nisl eget turpis congue molestie.", "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis quis nisl eget turpis congue molestie. Nulla vitae purus nec augue accumsan facilisis sed sed ligula. Vestibulum sed risus lacinia risus lacinia molestie. Ut lorem quam, consequat eget tempus in, rhoncus vel nunc. Duis efficitur a leo vel sodales. Nam id fermentum lacus. Etiam nec placerat velit. Praesent ac consectetur est. Aenean iaculis commodo enim.\n Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis quis nisl eget turpis congue molestie.",
} as DetailsArgs, } as Repo,
LongNoSpaces: { LongNoSpaces: {
...base, ...base,
name: "LongNameLongNameLongNameLongNameLongNameLongNameLongNameLongName", name: "LongNameLongNameLongNameLongNameLongNameLongNameLongNameLongName",
description: description:
"LoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsum", "LoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsum",
} as DetailsArgs, } as Repo,
NoNameOrDescription: { ...base, name: "", description: "" } as DetailsArgs, NoNameOrDescription: { ...base, name: "", description: "" } as Repo,
NoDescription: { ...base, description: "" } as DetailsArgs, NoDescription: { ...base, description: "" } as Repo,
NoTags: { ...base, tags: [] } as DetailsArgs, NoTags: { ...base, tags: [] } as Repo,
MaintainersOneProfileNotLoaded: { MaintainersOneProfileNotLoaded: {
...base, maintainers: [ ...base, maintainers: [
{ ...base.maintainers[0] }, { ...base.maintainers[0] },
{ ...UserVectors.loading }, { ...UserVectors.loading },
{ ...base.maintainers[2] }, { ...base.maintainers[2] },
] ]
} as DetailsArgs, } as Repo,
MaintainersOneProfileDisplayNameWithoutName: { MaintainersOneProfileDisplayNameWithoutName: {
...base, maintainers: [ ...base, maintainers: [
{ ...base.maintainers[0] }, { ...base.maintainers[0] },
{ ...UserVectors.display_name_only }, { ...UserVectors.display_name_only },
{ ...base.maintainers[2] }, { ...base.maintainers[2] },
] ]
} as DetailsArgs, } as Repo,
MaintainersOneProfileNameAndDisplayNamePresent: { MaintainersOneProfileNameAndDisplayNamePresent: {
...base, maintainers: [ ...base, maintainers: [
{ ...base.maintainers[0] }, { ...base.maintainers[0] },
{ ...UserVectors.display_name_and_name }, { ...UserVectors.display_name_and_name },
{ ...base.maintainers[2] }, { ...base.maintainers[2] },
] ]
} as DetailsArgs, } as Repo,
MaintainersOneProfileNoNameOrDisplayNameBeingPresent: { MaintainersOneProfileNoNameOrDisplayNameBeingPresent: {
...base, maintainers: [ ...base, maintainers: [
{ ...base.maintainers[0] }, { ...base.maintainers[0] },
@ -83,8 +84,8 @@ export let RepoDetailsArgsVectors = {
{ ...base.maintainers[2] }, { ...base.maintainers[2] },
] ]
} as DetailsArgs, } as Repo,
NoMaintainers: { ...base, maintainers: [] } as DetailsArgs, NoMaintainers: { ...base, maintainers: [] } as Repo,
NoRelays: { ...base, relays: [] } as DetailsArgs, NoRelays: { ...base, relays: [] } as Repo,
NoMaintainersOrRelays: { ...base, maintainers: [], relays: [] } as DetailsArgs, NoMaintainersOrRelays: { ...base, maintainers: [], relays: [] } as Repo,
}; };

2
src/lib/components/users/UserHeader.stories.svelte

@ -44,7 +44,7 @@
<Story <Story
name="displayName without name" name="displayName without name"
args={{ user: { ...vectors.no_profile } }} args={{ user: { ...vectors.display_name_only } }}
/> />
<Story <Story

1
src/lib/components/users/UserHeader.svelte

@ -7,7 +7,6 @@
</script> </script>
<script lang="ts"> <script lang="ts">
import Name from "./Name.svelte";
import { getName, type User } from "./type"; import { getName, type User } from "./type";
export let user: User = defaults; export let user: User = defaults;

2
src/lib/components/users/vectors.ts

@ -8,7 +8,7 @@ let base: User = {
loading: false, loading: false,
}; };
let image = "https://daisyui.com/images/stock/photo-1534528741775-53994a69daeb.jpg"; let image = "../test-profile-image.jpg";
export let UserVectors = { export let UserVectors = {
loading: { ...base, loading: true } as User, loading: { ...base, loading: true } as User,

76
src/lib/stores/repo.ts

@ -0,0 +1,76 @@
import { NDKUser } from "@nostr-dev-kit/ndk";
import { writable, type Unsubscriber, type Writable } from "svelte/store"
import { ndk } from "./ndk";
import type { Repo } from "$lib/components/repo/type";
import { defaults } from "$lib/components/repo/type";
import type { User } from "$lib/components/users/type";
import { ensureUser, users } from "./users";
let repo_kind: number = 30317;
export let selected_repo: Writable<Repo> = writable({ ...defaults });
let selected_repo_id: string = "";
let maintainers_unsubscribers: Unsubscriber[] = [];
export let ensureSelectedRepo = (repo_id: string) => {
if (selected_repo_id == repo_id) return selected_repo;
selected_repo_id = repo_id;
let sub = ndk.subscribe({
kinds: [repo_kind],
'#d': [repo_id],
limit: 1,
});
sub.on("event", (event) => {
try {
if (event.kind == repo_kind && event.tagValue("d") == repo_id) {
selected_repo.set({
loading: false,
repo_id: event.replaceableDTag(),
name: event.tagValue("name") || "",
description: event.tagValue("description") || "",
git_server: event.tagValue("git_server") || "",
tags: event.getMatchingTags("t") || [],
maintainers: event.getMatchingTags("p").map(
(t: string[]) =>
({
hexpubkey: t[1],
loading: true,
npub: "",
}) as User,
),
relays: event
.getMatchingTags("relay")
.map((t: string[]) => t[1]),
});
let old_unsubscribers = maintainers_unsubscribers;
maintainers_unsubscribers = event
.getMatchingTags("p")
.map((t: string[]) => {
return ensureUser(t[1]).subscribe((u: User) => {
selected_repo.update((repo) => {
return {
...repo,
maintainers: repo.maintainers.map((m) => {
if (m.hexpubkey == u.hexpubkey) return { ...u };
else return { ...m };
}),
};
});
})
});
old_unsubscribers.forEach((unsubscriber) => unsubscriber());
}
} catch { }
});
sub.on("eose", () => {
selected_repo.update((repo) => {
return {
...repo,
loading: false,
}
})
});
}

36
src/lib/stores/users.ts

@ -0,0 +1,36 @@
import type { User } from "$lib/components/users/type";
import { NDKUser } from "@nostr-dev-kit/ndk";
import { writable, type Writable } from "svelte/store"
import { ndk } from "./ndk";
export let users: { [hexpubkey: string]: Writable<User>; } = {};
export let ensureUser = (hexpubkey: string): Writable<User> => {
if (!users[hexpubkey]) {
let u = ndk.getUser({ hexpubkey });
let base: User = {
loading: false,
hexpubkey,
npub: u.npub,
};
users[hexpubkey] = writable(base);
u.fetchProfile().then(
(p) => {
users[hexpubkey].update((u) => ({
...u,
loading: false,
profile: p === null ? undefined : p,
}));
},
() => {
users[hexpubkey].update((u) => ({
...u,
loading: false,
}));
}
);
}
return users[hexpubkey];
}

37
src/lib/wrappers/RepoDetails.svelte

@ -1,39 +1,10 @@
<script lang="ts"> <script lang="ts">
import type { Args } from "$lib/components/RepoDetails.svelte"; import RepoDetails from "$lib/components/repo/RepoDetails.svelte";
import { defaults } from "$lib/components/RepoDetails.svelte"; import { ensureSelectedRepo, selected_repo } from "$lib/stores/repo";
import RepoDetails from "$lib/components/RepoDetails.svelte";
import { ndk } from "$lib/stores/ndk";
export let repo_id = ""; export let repo_id = "";
let repo: Args = { ...defaults }; ensureSelectedRepo(repo_id);
let loading: boolean = true;
let kind: number = 30317;
let sub = ndk.subscribe({
kinds: [kind],
limit: 1,
});
sub.on("event", (event) => {
try {
if (event.kind == kind && event.tagValue("d") == repo_id)
repo = {
repo_id: event.replaceableDTag(),
name: event.tagValue("name") || "",
description: event.tagValue("description") || "",
git_server: event.tagValue("git_server") || "",
tags: event.getMatchingTags("t") || [],
maintainers: event
.getMatchingTags("p")
.map((t: string[]) => t[1]),
relays: event
.getMatchingTags("relay")
.map((t: string[]) => t[1]),
};
} catch {}
});
sub.on("eose", () => {
if (loading == true) loading = false;
});
</script> </script>
<RepoDetails {...repo} {loading} /> <RepoDetails {...$selected_repo} />

4
src/routes/repo/[repo_id]/+page.svelte

@ -1,11 +1,15 @@
<script lang="ts"> <script lang="ts">
import RepoDetails from "$lib/wrappers/RepoDetails.svelte"; import RepoDetails from "$lib/wrappers/RepoDetails.svelte";
import OpenPRs from "$lib/wrappers/OpenPRs.svelte"; import OpenPRs from "$lib/wrappers/OpenPRs.svelte";
import { ensureSelectedRepo, selected_repo } from "$lib/stores/repo";
export let data: { repo_id: string }; export let data: { repo_id: string };
let repo_id = data.repo_id; let repo_id = data.repo_id;
ensureSelectedRepo(repo_id);
</script> </script>
<h1>{$selected_repo.name}</h1>
<div class="flex"> <div class="flex">
<div class="w-2/3"> <div class="w-2/3">
<OpenPRs {repo_id} /> <OpenPRs {repo_id} />

Loading…
Cancel
Save