Spaces:
Runtime error
Runtime error
darkmode + runtime + likes
Browse files- src/lib/components/result/space/Author.svelte +4 -4
- src/lib/components/result/space/Overview.svelte +9 -3
- src/lib/components/result/space/Runtime.svelte +51 -0
- src/lib/components/result/space/Space.svelte +16 -3
- src/lib/components/result/space/likers/Likers.svelte +56 -25
- src/routes/api/search/+server.ts +3 -3
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
|
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-
|
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
|
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:
|
72 |
<p class="uppercase text-sm text-black/60 dark:text-zinc-300 font-semibold font-title truncate">
|
73 |
-
{
|
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 {...
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
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,35 +21,52 @@
|
|
21 |
tab = id as "data-visualization" | "global"
|
22 |
}
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
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="
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
</div>
|
64 |
{:else}
|
65 |
-
<div>
|
66 |
-
|
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 |
-
|
30 |
if (dataAuthor.error) {
|
31 |
-
|
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 |
},
|