enzostvs HF staff commited on
Commit
07a1325
1 Parent(s): 4721dfc

darkmode + runtime + likes

Browse files
src/lib/components/result/space/Author.svelte CHANGED
@@ -1,16 +1,16 @@
1
  <script lang="ts">
 
 
2
  import ProTag from "$lib/components/ProTag.svelte";
3
  import Community from "$lib/components/icons/Community.svelte";
4
  import Like from "$lib/components/icons/Like.svelte";
5
  import UpVote from "$lib/components/icons/UpVote.svelte";
6
- import type { Author } from "$lib/types";
7
- import Icon from "@iconify/svelte";
8
 
9
- export let author: Author | undefined;
10
  </script>
11
 
12
  <div class="rounded-2xl bg-white dark:bg-zinc-900 p-5 shadow flex items-start justify-start gap-5 col-span-2">
13
- <img src={author?.avatarUrl} alt={author?.fullname} class="w-44 h-44 rounded-xl" />
14
  <div class="w-full pt-2 pl-1 h-full flex flex-col justify-between">
15
  <div>
16
  {#if author?.fullname}
 
1
  <script lang="ts">
2
+ import Icon from "@iconify/svelte";
3
+ import type { Author } from "$lib/types";
4
  import ProTag from "$lib/components/ProTag.svelte";
5
  import Community from "$lib/components/icons/Community.svelte";
6
  import Like from "$lib/components/icons/Like.svelte";
7
  import UpVote from "$lib/components/icons/UpVote.svelte";
 
 
8
 
9
+ export let author: Author;
10
  </script>
11
 
12
  <div class="rounded-2xl bg-white dark:bg-zinc-900 p-5 shadow flex items-start justify-start gap-5 col-span-2">
13
+ <img src={author?.avatarUrl} alt={author?.fullname} class="w-44 h-full rounded-xl object-cover" />
14
  <div class="w-full pt-2 pl-1 h-full flex flex-col justify-between">
15
  <div>
16
  {#if author?.fullname}
src/lib/components/result/space/Overview.svelte CHANGED
@@ -13,6 +13,12 @@
13
  export let sdk_version: string | undefined;
14
  export let license: string | undefined;
15
  export let pinned: boolean | undefined;
 
 
 
 
 
 
16
 
17
  </script>
18
 
@@ -66,11 +72,11 @@
66
  </p>
67
  </div>
68
  {/if}
69
- {#if emoji}
70
  <div class="border rounded-lg border-zinc-300/70 dark:border-zinc-800 p-3 flex items-center justify-start gap-3">
71
- <Icon icon="solar:subtitles-bold-duotone" class="w-6 h-6 text-gray-500 dark:text-white" />
72
  <p class="uppercase text-sm text-black/60 dark:text-zinc-300 font-semibold font-title truncate">
73
- {title}
74
  </p>
75
  </div>
76
  {/if}
 
13
  export let sdk_version: string | undefined;
14
  export let license: string | undefined;
15
  export let pinned: boolean | undefined;
16
+ export let createdAt: string | undefined;
17
+
18
+ const formatDate = (date: string) => {
19
+ const d = new Date(date);
20
+ return `${d.toLocaleString("default", { month: "short" })} ${d.getDate()}, ${d.getFullYear()}`;
21
+ }
22
 
23
  </script>
24
 
 
72
  </p>
73
  </div>
74
  {/if}
75
+ {#if createdAt}
76
  <div class="border rounded-lg border-zinc-300/70 dark:border-zinc-800 p-3 flex items-center justify-start gap-3">
77
+ <Icon icon="solar:calendar-date-bold-duotone" class="w-6 h-6 text-gray-500 dark:text-white" />
78
  <p class="uppercase text-sm text-black/60 dark:text-zinc-300 font-semibold font-title truncate">
79
+ {formatDate(createdAt)}
80
  </p>
81
  </div>
82
  {/if}
src/lib/components/result/space/Runtime.svelte ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import Icon from "@iconify/svelte";
3
+ import type { Author } from "$lib/types";
4
+
5
+ export let runtime: any;
6
+
7
+ const renderBadge = (stage: string) => {
8
+ switch (stage) {
9
+ case "RUNNING_BUILDING":
10
+ return "bg-blue-500/30 text-blue-600";
11
+ case "RUNNING":
12
+ return "bg-green-500/30 text-green-600";
13
+ case "ERROR":
14
+ return "bg-red-500/30 text-red-600";
15
+ default:
16
+ return "bg-gray-500/30 text-gray-600";
17
+ }
18
+ }
19
+ </script>
20
+
21
+ <div class="rounded-2xl bg-white dark:bg-zinc-900 p-5 shadow col-span-3">
22
+ <div class="flex w-full justify-between items-start mb-4">
23
+ <div class="text-zinc-700 dark:text-zinc-300 flex items-center gap-2">
24
+ <Icon icon="solar:settings-bold-duotone" class="w-6 h-6" />
25
+ <p class="font-semibold text-sm uppercase tracking-wider">Runtime config</p>
26
+ </div>
27
+ <div class={`${renderBadge(runtime.stage)} font-semibold font-title text-sm px-3 py-1 rounded-full`}>
28
+ {runtime.stage}
29
+ </div>
30
+ </div>
31
+ <div class="w-full">
32
+ <div class="grid grid-cols-2 gap-4">
33
+ {#if runtime.hardware}
34
+ <div class="border rounded-lg border-zinc-300/70 dark:border-zinc-800 p-3 flex items-center justify-start gap-3">
35
+ <Icon icon="solar:diskette-bold-duotone" class="w-6 h-6 text-gray-500 dark:text-white" />
36
+ <p class="uppercase text-sm text-black/60 dark:text-zinc-300 font-semibold font-title truncate">
37
+ Hardware: {runtime.hardware.current}
38
+ </p>
39
+ </div>
40
+ {/if}
41
+ {#if runtime.storage}
42
+ <div class="border rounded-lg border-zinc-300/70 dark:border-zinc-800 p-3 flex items-center justify-start gap-3">
43
+ <Icon icon="solar:cloud-storage-bold-duotone" class="w-6 h-6 text-gray-500 dark:text-white" />
44
+ <p class="uppercase text-sm text-black/60 dark:text-zinc-300 font-semibold font-title truncate">
45
+ Storage: {runtime.storage.current}
46
+ </p>
47
+ </div>
48
+ {/if}
49
+ </div>
50
+ </div>
51
+ </div>
src/lib/components/result/space/Space.svelte CHANGED
@@ -1,15 +1,28 @@
1
  <script lang="ts">
2
  import Author from "./Author.svelte";
3
  import Overview from "./Overview.svelte";
 
4
  import Likers from "./likers/Likers.svelte";
5
 
6
  export let data: Record<string, any> | null = {};
7
 
 
 
 
 
 
8
  $: console.log(data);
9
  </script>
10
 
11
  <div class="grid grid-cols-1 lg:grid-cols-5 gap-8 mt-8">
12
- <Overview {...data?.cardData} />
13
- <Author author={data?.author}/>
14
- <Likers likers={data?.likers} />
 
 
 
 
 
 
 
15
  </div>
 
1
  <script lang="ts">
2
  import Author from "./Author.svelte";
3
  import Overview from "./Overview.svelte";
4
+ import Runtime from "./Runtime.svelte";
5
  import Likers from "./likers/Likers.svelte";
6
 
7
  export let data: Record<string, any> | null = {};
8
 
9
+ $: formattedData = {
10
+ ...data?.cardData,
11
+ createdAt: data?.createdAt
12
+ }
13
+
14
  $: console.log(data);
15
  </script>
16
 
17
  <div class="grid grid-cols-1 lg:grid-cols-5 gap-8 mt-8">
18
+ <Overview {...formattedData } />
19
+ {#if data?.author}
20
+ <Author author={data?.author} />
21
+ {/if}
22
+ {#if data?.likers}
23
+ <Likers likers={data?.likers} />
24
+ {/if}
25
+ {#if data?.runtime}
26
+ <Runtime runtime={data?.runtime} />
27
+ {/if}
28
  </div>
src/lib/components/result/space/likers/Likers.svelte CHANGED
@@ -1,10 +1,10 @@
1
  <!-- enzostvs/stable-diffusion-tpu -->
2
  <script lang="ts">
3
- // import { Chart, type EChartsOptions } from 'svelte-echarts'
4
  import Icon from "@iconify/svelte";
5
  import type { Liker } from "$lib/types";
6
 
7
- export let likers: Record<string, Array<Liker>> | undefined;
8
 
9
  let tab: "data-visualization" | "global" = "global";
10
  const tabs = [{
@@ -21,35 +21,52 @@
21
  tab = id as "data-visualization" | "global"
22
  }
23
 
24
- // const options: EChartsOptions = {
25
- // xAxis: {
26
- // data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
27
- // type: 'category',
28
- // },
29
- // yAxis: {
30
- // type: 'value',
31
- // },
32
- // series: [
33
- // {
34
- // data: [820, 932, 901, 934, 1290, 1330, 1320],
35
- // type: 'bar',
36
- // },
37
- // ],
38
- // }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  </script>
40
 
41
- <div class="rounded-2xl bg-white p-5 shadow col-span-3">
42
- <div class="text-zinc-700 flex items-center gap-2 mb-4">
43
  <Icon icon="solar:heart-angle-bold-duotone" class="w-6 h-6" />
44
  <p class="font-semibold text-sm uppercase tracking-wider">Likes</p>
45
  </div>
46
  <div class="flex items-center justify-start gap-3 mb-5">
47
  {#each tabs as { id, label, icon }}
48
  <button
49
- class="flex items-center justify-center gap-2 px-4 py-2 border-2 border-zinc-200 rounded-lg font-title text-sm font-semibold uppercase text-black/60"
50
  class:bg-indigo-100={tab === id}
51
  class:text-indigo-600={tab === id}
52
  class:!border-indigo-100={tab === id}
 
 
 
53
  on:click={() => handleSelectTab(id)}
54
  >
55
  <Icon icon={icon} class="w-6 h-6" />
@@ -58,13 +75,27 @@
58
  {/each}
59
  </div>
60
  {#if tab === "global"}
61
- <div class="bg-red-50">
62
- global
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  </div>
64
  {:else}
65
- <div>
66
- data-visualization
67
  </div>
68
  {/if}
69
- <!-- <Chart {options} /> -->
70
  </div>
 
1
  <!-- enzostvs/stable-diffusion-tpu -->
2
  <script lang="ts">
3
+ import { Chart, type EChartsOptions } from 'svelte-echarts'
4
  import Icon from "@iconify/svelte";
5
  import type { Liker } from "$lib/types";
6
 
7
+ export let likers: Record<string, Array<Liker>>;
8
 
9
  let tab: "data-visualization" | "global" = "global";
10
  const tabs = [{
 
21
  tab = id as "data-visualization" | "global"
22
  }
23
 
24
+ const options: EChartsOptions = {
25
+ xAxis: {
26
+ data: Object.keys(likers ?? []),
27
+ type: 'category',
28
+ },
29
+ yAxis: {
30
+ type: 'value',
31
+ },
32
+ color: ['#14b8a6'],
33
+ series: [
34
+ {
35
+ data: Object.keys(likers ?? []).map((key) => likers?.[key].length ?? 0),
36
+ type: 'bar',
37
+ },
38
+ ],
39
+ tooltip: {
40
+ trigger: 'axis',
41
+ axisPointer: {
42
+ type: 'shadow',
43
+ },
44
+ },
45
+ }
46
+
47
+ const formatBigNumber = (num: number) => {
48
+ if (num < 1000) return num;
49
+ if (num < 1000000) return `${(num / 1000).toFixed(1)}K`;
50
+ if (num < 1000000000) return `${(num / 1000000).toFixed(1)}M`;
51
+ return `${(num / 1000000000).toFixed(1)}B`;
52
+ }
53
  </script>
54
 
55
+ <div class="rounded-2xl bg-white dark:bg-zinc-900 p-5 shadow col-span-3">
56
+ <div class="text-zinc-700 dark:text-zinc-300 flex items-center gap-2 mb-4">
57
  <Icon icon="solar:heart-angle-bold-duotone" class="w-6 h-6" />
58
  <p class="font-semibold text-sm uppercase tracking-wider">Likes</p>
59
  </div>
60
  <div class="flex items-center justify-start gap-3 mb-5">
61
  {#each tabs as { id, label, icon }}
62
  <button
63
+ class="flex items-center justify-center gap-2 px-4 py-2 border-2 border-zinc-200 dark:border-zinc-700 dark:text-zinc-200 rounded-lg font-title text-sm font-semibold uppercase text-black/60"
64
  class:bg-indigo-100={tab === id}
65
  class:text-indigo-600={tab === id}
66
  class:!border-indigo-100={tab === id}
67
+ class:dark:bg-indigo-100={tab === id}
68
+ class:dark:text-indigo-600={tab === id}
69
+ class:dark:!border-indigo-100={tab === id}
70
  on:click={() => handleSelectTab(id)}
71
  >
72
  <Icon icon={icon} class="w-6 h-6" />
 
75
  {/each}
76
  </div>
77
  {#if tab === "global"}
78
+ <div class="">
79
+ {#each Object.keys(likers ?? []) as year}
80
+ <p class="uppercase text-zinc-600 dark:text-zinc-400 font-semibold font-title text-sm">{year}</p>
81
+ <div class="flex items-center mt-3 flex-wrap">
82
+ {#each likers[year].slice(0, 100) as like}
83
+ <div class="flex items-center -mr-1.5 -mt-1.5 relative cursor-pointer group">
84
+ <img src={like.avatarUrl.includes(".svg") ? `https://huggingface.co${like.avatarUrl}` : like.avatarUrl} alt={like.fullname} class="w-8 h-8 rounded-full ring-[1px] ring-white dark:ring-zinc-900" />
85
+ <p class="font-title absolute left-full top-0 bg-zinc-100 shadow rounded px-2 py-0.5 text-zinc-600 text-xs opacity-0 group-hover:opacity-100 pointer-events-none z-10 whitespace-nowrap translate-y-1/2">{like.fullname}</p>
86
+ </div>
87
+ {/each}
88
+ {#if likers[year].length > 100}
89
+ <div class="w-8 h-8 flex items-center justify-center border rounded-full border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900 z-10">
90
+ <p class="text-xs font-title text-zinc-700">+{formatBigNumber(likers[year].length - 15)}</p>
91
+ </div>
92
+ {/if}
93
+ </div>
94
+ {/each}
95
  </div>
96
  {:else}
97
+ <div class="h-[380px] -mx-8 -my-8">
98
+ <Chart {options} />
99
  </div>
100
  {/if}
 
101
  </div>
src/routes/api/search/+server.ts CHANGED
@@ -26,9 +26,9 @@ export async function POST({ request }: RequestEvent) {
26
  },
27
  });
28
 
29
- const dataAuthor = await responseAuthor.json();
30
  if (dataAuthor.error) {
31
- throw error(responseAuthor.status, dataAuthor.error);
32
  }
33
 
34
  const responseLikers = await fetch(`${env.PUBLIC_API_URL}/${body.namespace}/${body.repoId}/likers?expand[]=likeAt`, {
@@ -55,7 +55,7 @@ export async function POST({ request }: RequestEvent) {
55
 
56
  const formattedData = {
57
  ...data,
58
- author: {
59
  ...dataAuthor,
60
  avatarUrl: dataAuthor.avatarUrl.replace("w=200&h=200", "w=400&h=400")
61
  },
 
26
  },
27
  });
28
 
29
+ let dataAuthor = await responseAuthor.json();
30
  if (dataAuthor.error) {
31
+ dataAuthor = null
32
  }
33
 
34
  const responseLikers = await fetch(`${env.PUBLIC_API_URL}/${body.namespace}/${body.repoId}/likers?expand[]=likeAt`, {
 
55
 
56
  const formattedData = {
57
  ...data,
58
+ author: dataAuthor && {
59
  ...dataAuthor,
60
  avatarUrl: dataAuthor.avatarUrl.replace("w=200&h=200", "w=400&h=400")
61
  },