Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
some changes
Browse files- src/lib/components/community/Card.svelte +3 -2
- src/lib/components/community/viewer/Viewer.svelte +83 -68
- src/lib/components/models/Card.svelte +1 -1
- src/lib/components/models/drawer/Drawer.svelte +74 -50
- src/lib/components/sidebar/Sidebar.svelte +9 -0
- src/routes/+page.svelte +9 -3
- src/routes/api/community/[id]/+server.ts +29 -1
- src/routes/gallery/+page.svelte +3 -3
src/lib/components/community/Card.svelte
CHANGED
@@ -8,9 +8,10 @@
|
|
8 |
import Reactions from "./reactions/Reactions.svelte";
|
9 |
|
10 |
export let card: CommunityCard;
|
|
|
11 |
|
12 |
const handleClick = async () => {
|
13 |
-
const request = await fetch(`/api/community/${card?.id}`);
|
14 |
const { gallery, next, previous } = await request.json();
|
15 |
galleryStore.set({
|
16 |
gallery,
|
@@ -27,7 +28,7 @@
|
|
27 |
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
28 |
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
29 |
<div
|
30 |
-
class="cursor-pointer group bg-neutral-700 rounded-xl h-[400px] relative flex items-start justify-between flex-col p-5 transition-all duration-200 brightness-
|
31 |
on:click={handleClick}
|
32 |
>
|
33 |
<div class="w-full h-full absolute top-0 left-0 -z-[1] rounded-xl overflow-hidden">
|
|
|
8 |
import Reactions from "./reactions/Reactions.svelte";
|
9 |
|
10 |
export let card: CommunityCard;
|
11 |
+
export let form: Record<string, string>;
|
12 |
|
13 |
const handleClick = async () => {
|
14 |
+
const request = await fetch(`/api/community/${card?.id}?${new URLSearchParams(form)}`);
|
15 |
const { gallery, next, previous } = await request.json();
|
16 |
galleryStore.set({
|
17 |
gallery,
|
|
|
28 |
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
29 |
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
30 |
<div
|
31 |
+
class="cursor-pointer group bg-neutral-700 rounded-xl h-[400px] relative flex items-start justify-between flex-col p-5 transition-all duration-200 brightness-90 hover:brightness-100 z-[1] overflow-hidden"
|
32 |
on:click={handleClick}
|
33 |
>
|
34 |
<div class="w-full h-full absolute top-0 left-0 -z-[1] rounded-xl overflow-hidden">
|
src/lib/components/community/viewer/Viewer.svelte
CHANGED
@@ -7,10 +7,10 @@
|
|
7 |
import Icon from "@iconify/svelte";
|
8 |
|
9 |
import { galleryStore } from "$lib/stores/use-gallery";
|
10 |
-
import UserIsLogged from '$lib/components/UserIsLogged.svelte';
|
11 |
import Reactions from '../reactions/Reactions.svelte';
|
12 |
import Button from '$lib/components/Button.svelte';
|
13 |
|
|
|
14 |
let { open, gallery, previous, next } = get(galleryStore);
|
15 |
let loading = false;
|
16 |
|
@@ -36,7 +36,7 @@
|
|
36 |
const handlePagination = async (id?: string) => {
|
37 |
if (!id) return;
|
38 |
loading = true;
|
39 |
-
const request = await fetch(`/api/community/${id}`);
|
40 |
const { gallery, next, previous } = await request.json();
|
41 |
galleryStore.set({
|
42 |
gallery,
|
@@ -48,6 +48,14 @@
|
|
48 |
$page.url.searchParams.set('gallery', id);
|
49 |
goto(`?${$page.url.searchParams.toString()}`);
|
50 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
</script>
|
52 |
|
53 |
<div
|
@@ -55,77 +63,84 @@
|
|
55 |
class:opacity-0={!open}
|
56 |
class:pointer-events-none={!open}
|
57 |
>
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
<div>
|
71 |
-
<p class="text-neutral-
|
72 |
-
|
73 |
</p>
|
74 |
-
<p class="text-neutral-
|
75 |
-
|
|
|
|
|
|
|
76 |
</p>
|
|
|
77 |
</div>
|
78 |
</div>
|
79 |
-
<button on:click={handleClose}>
|
80 |
-
<Icon icon="carbon:close" class="w-6 h-6 text-white" />
|
81 |
-
</button>
|
82 |
-
</header>
|
83 |
-
<div class="mt-8 grid grid-cols-1 gap-5">
|
84 |
-
<Reactions reactions={gallery?.reactions} gallery_id={gallery.id} />
|
85 |
-
<div>
|
86 |
-
<a
|
87 |
-
href="/generate?model={gallery?.model?.id}"
|
88 |
-
class="flex items-center justify-start gap-4 rounded-lg cursor-pointer w-full text-left transition-all duration-200 hover:bg-neutral-950/50 p-3 -mx-3 group relative"
|
89 |
-
>
|
90 |
-
<img src={gallery?.model?.image} alt={gallery?.model?.title} class="w-14 h-14 rounded-lg object-cover" />
|
91 |
-
<div>
|
92 |
-
<p class="text-neutral-200 text-base font-medium">{gallery?.model?.title}</p>
|
93 |
-
<p class="text-neutral-400 text-sm">{gallery?.model?.id}</p>
|
94 |
-
</div>
|
95 |
-
<div class="rounded-full absolute top-1/2 -translate-y-1/2 text-neutral-100 w-8 h-8 right-4 bg-pink-500 flex items-center justify-center transition-all duration-200 group-hover:opacity-100 opacity-0">
|
96 |
-
<Icon icon="tabler:arrow-up" class="w-5 h-5 transform rotate-45 font-bold" />
|
97 |
-
</div>
|
98 |
-
</a>
|
99 |
-
</div>
|
100 |
-
<div>
|
101 |
-
<p class="text-neutral-400 font-semibold text-xs uppercase">
|
102 |
-
Prompt
|
103 |
-
</p>
|
104 |
-
<p class="text-neutral-200 text-base font-medium mt-2">"{gallery?.prompt}"</p>
|
105 |
-
</div>
|
106 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
</div>
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
theme="dark"
|
112 |
-
disabled={!previous}
|
113 |
-
loading={loading}
|
114 |
-
onClick={() => handlePagination(previous)}
|
115 |
-
>
|
116 |
-
Previous
|
117 |
-
</Button>
|
118 |
-
<Button
|
119 |
-
size="lg"
|
120 |
-
theme="light"
|
121 |
-
loading={loading}
|
122 |
-
disabled={!next}
|
123 |
-
onClick={() => handlePagination(next)}
|
124 |
-
>
|
125 |
-
Next
|
126 |
-
</Button>
|
127 |
-
</footer>
|
128 |
-
</div>
|
129 |
-
{/if}
|
130 |
-
</div>
|
131 |
</div>
|
|
|
7 |
import Icon from "@iconify/svelte";
|
8 |
|
9 |
import { galleryStore } from "$lib/stores/use-gallery";
|
|
|
10 |
import Reactions from '../reactions/Reactions.svelte';
|
11 |
import Button from '$lib/components/Button.svelte';
|
12 |
|
13 |
+
export let form: Record<string, string>;
|
14 |
let { open, gallery, previous, next } = get(galleryStore);
|
15 |
let loading = false;
|
16 |
|
|
|
36 |
const handlePagination = async (id?: string) => {
|
37 |
if (!id) return;
|
38 |
loading = true;
|
39 |
+
const request = await fetch(`/api/community/${id}?${new URLSearchParams(form)}`);
|
40 |
const { gallery, next, previous } = await request.json();
|
41 |
galleryStore.set({
|
42 |
gallery,
|
|
|
48 |
$page.url.searchParams.set('gallery', id);
|
49 |
goto(`?${$page.url.searchParams.toString()}`);
|
50 |
};
|
51 |
+
|
52 |
+
// to url search params
|
53 |
+
const handleClickModel = (id?: string) => {
|
54 |
+
if (!id) return;
|
55 |
+
$page.url.searchParams.set('model', id);
|
56 |
+
$page.url.searchParams.delete('gallery');
|
57 |
+
goto(`/?${$page.url.searchParams.toString()}`);
|
58 |
+
};
|
59 |
</script>
|
60 |
|
61 |
<div
|
|
|
63 |
class:opacity-0={!open}
|
64 |
class:pointer-events-none={!open}
|
65 |
>
|
66 |
+
{#if open}
|
67 |
+
<div
|
68 |
+
class="mx-auto w-full max-w-6xl bg-neutral-900 transition-all duration-200 lg:grid lg:grid-cols-2 rounded-xl overflow-hidden"
|
69 |
+
use:clickoutside on:clickoutside={handleClose}
|
70 |
+
>
|
71 |
+
{#if gallery?.id}
|
72 |
+
<img src={env.PUBLIC_FILE_UPLOAD_DIR}/{gallery?.image} alt={gallery?.prompt} class="w-full object-cover h-[200px] lg:h-auto" />
|
73 |
+
<div class="flex flex-col justify-between w-full overflow-auto flex-1">
|
74 |
+
<div class="w-full p-8">
|
75 |
+
<header class="w-full flex items-start justify-between">
|
76 |
+
<div class="flex items-center justify-start gap-4">
|
77 |
+
<img src={gallery?.user?.picture} class="w-12 h-12 rounded-full object-cover" alt={gallery?.user?.name} />
|
78 |
+
<div>
|
79 |
+
<p class="text-neutral-100 font-bold text-lg">
|
80 |
+
{gallery?.user?.name}
|
81 |
+
</p>
|
82 |
+
<p class="text-neutral-400 text-sm">
|
83 |
+
@{gallery?.user?.preferred_username}
|
84 |
+
</p>
|
85 |
+
</div>
|
86 |
+
</div>
|
87 |
+
<button on:click={handleClose}>
|
88 |
+
<Icon icon="carbon:close" class="w-6 h-6 text-white" />
|
89 |
+
</button>
|
90 |
+
</header>
|
91 |
+
<div class="mt-8 grid grid-cols-1 gap-5 overflow-auto">
|
92 |
+
<Reactions reactions={gallery?.reactions} gallery_id={gallery.id} />
|
93 |
+
<div>
|
94 |
+
<button
|
95 |
+
class="flex items-center justify-start gap-4 cursor-pointer w-full text-left transition-all duration-200 hover:bg-neutral-950/50 py-3 pr-3 pl-6 -mx-3 group relative"
|
96 |
+
on:click={() => handleClickModel(gallery?.model?.id)}
|
97 |
+
>
|
98 |
+
<img src={gallery?.model?.image} alt={gallery?.model?.title} class="w-14 h-14 rounded-lg object-cover" />
|
99 |
+
<div>
|
100 |
+
<p class="text-neutral-200 text-base font-medium">{gallery?.model?.title}</p>
|
101 |
+
<p class="text-neutral-400 text-sm">{gallery?.model?.id}</p>
|
102 |
+
</div>
|
103 |
+
<div class="rounded-full absolute top-1/2 -translate-y-1/2 text-neutral-100 w-8 h-8 right-4 bg-pink-500 flex items-center justify-center transition-all duration-200 group-hover:opacity-100 opacity-0">
|
104 |
+
<Icon icon="tabler:arrow-up" class="w-5 h-5 transform rotate-45 font-bold" />
|
105 |
+
</div>
|
106 |
+
</button>
|
107 |
+
</div>
|
108 |
<div>
|
109 |
+
<p class="text-neutral-400 font-semibold text-xs uppercase">
|
110 |
+
Prompt
|
111 |
</p>
|
112 |
+
<p class="text-neutral-200 text-base font-medium mt-2">"{gallery?.prompt}"</p>
|
113 |
+
</div>
|
114 |
+
<div>
|
115 |
+
<p class="text-neutral-400 font-semibold text-xs uppercase">
|
116 |
+
Dimension
|
117 |
</p>
|
118 |
+
<p class="text-neutral-200 text-base font-medium mt-2">1024x1024</p>
|
119 |
</div>
|
120 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
</div>
|
122 |
+
<footer class="border-t border-neutral-800 px-8 py-6 flex items-center justify-between">
|
123 |
+
<Button
|
124 |
+
size="lg"
|
125 |
+
theme="dark"
|
126 |
+
disabled={!previous}
|
127 |
+
loading={loading}
|
128 |
+
onClick={() => handlePagination(previous)}
|
129 |
+
>
|
130 |
+
Previous
|
131 |
+
</Button>
|
132 |
+
<Button
|
133 |
+
size="lg"
|
134 |
+
theme="light"
|
135 |
+
loading={loading}
|
136 |
+
disabled={!next}
|
137 |
+
onClick={() => handlePagination(next)}
|
138 |
+
>
|
139 |
+
Next
|
140 |
+
</Button>
|
141 |
+
</footer>
|
142 |
</div>
|
143 |
+
{/if}
|
144 |
+
</div>
|
145 |
+
{/if}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
</div>
|
src/lib/components/models/Card.svelte
CHANGED
@@ -22,7 +22,7 @@
|
|
22 |
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
23 |
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
24 |
<div
|
25 |
-
class="w-full cursor-pointer group bg-neutral-900 rounded-xl relative flex items-start justify-between flex-col p-3 border border-neutral-800 transition-all duration-200 brightness-
|
26 |
on:click={handleClick}
|
27 |
>
|
28 |
<div class="w-full h-[350px] relative z-[1] mb-3 overflow-hidden">
|
|
|
22 |
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
23 |
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
24 |
<div
|
25 |
+
class="w-full cursor-pointer group bg-neutral-900 rounded-xl relative flex items-start justify-between flex-col p-3 border border-neutral-800 transition-all duration-200 brightness-90 hover:brightness-100 z-[1]"
|
26 |
on:click={handleClick}
|
27 |
>
|
28 |
<div class="w-full h-[350px] relative z-[1] mb-3 overflow-hidden">
|
src/lib/components/models/drawer/Drawer.svelte
CHANGED
@@ -9,6 +9,7 @@
|
|
9 |
import UserIsLogged from '$lib/components/UserIsLogged.svelte';
|
10 |
import Comments from '$lib/components/models/drawer/comments/Comments.svelte';
|
11 |
import { env } from '$env/dynamic/public';
|
|
|
12 |
|
13 |
let { open, model } = get(modelStore);
|
14 |
|
@@ -31,63 +32,86 @@
|
|
31 |
</script>
|
32 |
|
33 |
<div
|
34 |
-
class="w-full fixed top-0 left-0 h-full bg-black bg-opacity-50 z-
|
35 |
class:opacity-0={!open}
|
36 |
class:pointer-events-none={!open}
|
|
|
37 |
>
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
</div>
|
56 |
-
<div class="bg-blue-500 bg-opacity-20 border border-blue-500 px-3 py-1.5 rounded-full text-neutral-100 flex items-center justify-center gap-1 font-bold text-xs">
|
57 |
-
<Icon icon="solar:download-square-bold" class="lg:w-4 lg:h-4 w-3 h-3 text-blue-500" />
|
58 |
-
{model?.downloads ?? 0}
|
59 |
-
</div>
|
60 |
</div>
|
61 |
</div>
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
</
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
<div class="grid grid-cols-3 md:grid-cols-5 lg:grid-cols-6 gap-5 mt-2">
|
72 |
-
{#each model?.gallery as example}
|
73 |
-
<div class="w-full h-[120px] relative z-[1] mb-3 overflow-hidden">
|
74 |
-
<img src="{env.PUBLIC_FILE_UPLOAD_DIR}/{example.image}" class="w-full h-full bg-center bg-cover rounded-lg object-cover object-center bg-neutral-800" alt={example.prompt} />
|
75 |
-
</div>
|
76 |
-
{/each}
|
77 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
{/if}
|
80 |
-
</
|
81 |
</div>
|
82 |
-
|
83 |
-
<p class="font-semibold text-neutral-100 text-base lg:text-lg mb-6">
|
84 |
-
Commentaires ({model?.comments?.length ?? 0})
|
85 |
-
</p>
|
86 |
-
{#if model?.id}
|
87 |
-
<UserIsLogged>
|
88 |
-
<Comments comments={model?.comments} model={model} />
|
89 |
-
</UserIsLogged>
|
90 |
-
{/if}
|
91 |
-
</footer>
|
92 |
-
</div>
|
93 |
</div>
|
|
|
9 |
import UserIsLogged from '$lib/components/UserIsLogged.svelte';
|
10 |
import Comments from '$lib/components/models/drawer/comments/Comments.svelte';
|
11 |
import { env } from '$env/dynamic/public';
|
12 |
+
import Button from '$lib/components/Button.svelte';
|
13 |
|
14 |
let { open, model } = get(modelStore);
|
15 |
|
|
|
32 |
</script>
|
33 |
|
34 |
<div
|
35 |
+
class="w-full fixed top-0 left-0 h-full bg-black bg-opacity-50 z-0 backdrop-blur transition-all duration-100"
|
36 |
class:opacity-0={!open}
|
37 |
class:pointer-events-none={!open}
|
38 |
+
class:!z-40={open}
|
39 |
>
|
40 |
+
{#if open}
|
41 |
+
<div
|
42 |
+
class="ml-auto w-full max-w-3xl bg-neutral-950 h-full border-l border-neutral-800 transition-all duration-200 flex flex-col justify-between"
|
43 |
+
use:clickoutside on:clickoutside={handleClose}
|
44 |
+
>
|
45 |
+
<div class="p-8 overflow-auto">
|
46 |
+
<header class="flex w-full justify-between items-start mb-6 pr-6">
|
47 |
+
<div class="flex items-center justify-start gap-3 lg:gap-6">
|
48 |
+
<img src={model?.image} class="lg:w-16 lg:h-16 w-12 h-12 rounded-xl bg-neutral-800 object-cover" alt={model?.id} />
|
49 |
+
<div>
|
50 |
+
<p class="text-white font-semibold text-lg lg:text-2xl mb-1 truncate">
|
51 |
+
{model?.title ?? model?.id}
|
52 |
+
</p>
|
53 |
+
<a href="https://huggingface.co/{model?.id}" class="text-neutral-400 underline hover:text-blue-00 flex items-center justify-start gap-1">
|
54 |
+
<Icon icon="iconamoon:link-external-fill" class="w-4 h-4" />
|
55 |
+
View on HuggingFace
|
56 |
+
</a>
|
|
|
|
|
|
|
|
|
|
|
57 |
</div>
|
58 |
</div>
|
59 |
+
<button on:click={handleClose}>
|
60 |
+
<Icon icon="carbon:close" class="w-6 h-6 text-white cursor-pointer" />
|
61 |
+
</button>
|
62 |
+
</header>
|
63 |
+
<main>
|
64 |
+
<div class="justify-start items-center gap-4 flex mb-6">
|
65 |
+
<div class="bg-red-500 bg-opacity-20 border border-red-500 px-3 py-1.5 rounded-full text-neutral-100 flex items-center justify-center gap-1 font-medium text-sm">
|
66 |
+
<Icon icon="solar:heart-bold" class="lg:w-4 lg:h-4 w-3 h-3 text-red-500" />
|
67 |
+
{model?.likes ?? 0}
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
</div>
|
69 |
+
<a
|
70 |
+
href="/"
|
71 |
+
class="bg-blue-500 bg-opacity-20 border border-blue-500 hover:bg-opacity-60 transition-all duration-200 px-3 py-1.5 rounded-full text-neutral-100 flex items-center justify-center gap-1 font-medium text-sm"
|
72 |
+
>
|
73 |
+
<Icon icon="solar:download-square-bold" class="lg:w-4 lg:h-4 w-3 h-3 text-blue-500" />
|
74 |
+
View files
|
75 |
+
</a>
|
76 |
+
<a
|
77 |
+
href="/generate?model={model?.id}"
|
78 |
+
class="bg-pink-500 bg-opacity-20 hover:bg-opacity-60 transition-all duration-200 border border-pink-500 px-3 py-1.5 rounded-full text-neutral-100 flex items-center justify-center gap-1 font-medium text-sm"
|
79 |
+
>
|
80 |
+
<Icon icon="fluent:glance-horizontal-sparkles-16-filled" class="lg:w-4 lg:h-4 w-3 h-3 text-pink-500" />
|
81 |
+
Generate
|
82 |
+
</a>
|
83 |
</div>
|
84 |
+
{#if model?.gallery && model?.gallery?.length > 0}
|
85 |
+
<div>
|
86 |
+
<p class="text-neutral-400 uppercase text-xs font-bold">Examples</p>
|
87 |
+
<div class="grid grid-cols-3 md:grid-cols-5 lg:grid-cols-6 gap-5 mt-2">
|
88 |
+
{#each model?.gallery as example}
|
89 |
+
<div class="w-full h-[120px] relative z-[1] mb-3 overflow-hidden">
|
90 |
+
<img src="{env.PUBLIC_FILE_UPLOAD_DIR}/{example.image}" class="w-full h-full bg-center bg-cover rounded-lg object-cover object-center bg-neutral-800" alt={example.prompt} />
|
91 |
+
</div>
|
92 |
+
{/each}
|
93 |
+
</div>
|
94 |
+
</div>
|
95 |
+
{:else}
|
96 |
+
<div class="bg-neutral-900 rounded-lg p-8 text-center">
|
97 |
+
<p class="text-neutral-400 font-base">No generation examples available for this model</p>
|
98 |
+
<a href="/generate?model={model?.id}" class="text-neutral-100 underline">
|
99 |
+
Generate the first one
|
100 |
+
</a>
|
101 |
+
</div>
|
102 |
+
{/if}
|
103 |
+
</main>
|
104 |
+
</div>
|
105 |
+
<footer class="p-8 border-t border-neutral-900 bg-neutral-900/30">
|
106 |
+
<p class="font-semibold text-neutral-100 text-base lg:text-lg mb-6">
|
107 |
+
Commentaires ({model?.comments?.length ?? 0})
|
108 |
+
</p>
|
109 |
+
{#if model?.id}
|
110 |
+
<UserIsLogged>
|
111 |
+
<Comments comments={model?.comments} model={model} />
|
112 |
+
</UserIsLogged>
|
113 |
{/if}
|
114 |
+
</footer>
|
115 |
</div>
|
116 |
+
{/if}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
</div>
|
src/lib/components/sidebar/Sidebar.svelte
CHANGED
@@ -2,11 +2,13 @@
|
|
2 |
import cookies from 'js-cookie';
|
3 |
import Icon from "@iconify/svelte"
|
4 |
import { get } from 'svelte/store';
|
|
|
5 |
|
6 |
import { userStore, openWindowLogin } from "$lib/stores/use-user";
|
7 |
import { SIDEBAR_MENUS } from "$lib/utils";
|
8 |
|
9 |
import Menu from "./Menu.svelte";
|
|
|
10 |
|
11 |
let isOpen = false;
|
12 |
let user = get(userStore);
|
@@ -23,6 +25,13 @@
|
|
23 |
cookies.remove("hf_access_token");
|
24 |
window.location.href = "/";
|
25 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
</script>
|
27 |
|
28 |
<button class="bg-transparent absolute top-10 right-8 cursor-pointer xl:hidden" on:click="{handleClick}">
|
|
|
2 |
import cookies from 'js-cookie';
|
3 |
import Icon from "@iconify/svelte"
|
4 |
import { get } from 'svelte/store';
|
5 |
+
import { page } from '$app/stores';
|
6 |
|
7 |
import { userStore, openWindowLogin } from "$lib/stores/use-user";
|
8 |
import { SIDEBAR_MENUS } from "$lib/utils";
|
9 |
|
10 |
import Menu from "./Menu.svelte";
|
11 |
+
import { browser } from '$app/environment';
|
12 |
|
13 |
let isOpen = false;
|
14 |
let user = get(userStore);
|
|
|
25 |
cookies.remove("hf_access_token");
|
26 |
window.location.href = "/";
|
27 |
}
|
28 |
+
|
29 |
+
// sveltekit close sidebar on route change
|
30 |
+
if (browser) {
|
31 |
+
page.subscribe((value) => {
|
32 |
+
if (isOpen) handleClick();
|
33 |
+
});
|
34 |
+
}
|
35 |
</script>
|
36 |
|
37 |
<button class="bg-transparent absolute top-10 right-8 cursor-pointer xl:hidden" on:click="{handleClick}">
|
src/routes/+page.svelte
CHANGED
@@ -26,7 +26,10 @@
|
|
26 |
$: elementScroll = browser ? document?.getElementById('app') : undefined;
|
27 |
|
28 |
if (data?.model?.id) {
|
29 |
-
modelStore.set(
|
|
|
|
|
|
|
30 |
}
|
31 |
|
32 |
const handleFetchMore = async () => {
|
@@ -48,7 +51,10 @@
|
|
48 |
const request = await fetch(`/api/models?${new URLSearchParams(form)}`);
|
49 |
const response = await request.json();
|
50 |
if (add) data = {...data, models: [...data.models, ...response.cards ]};
|
51 |
-
else
|
|
|
|
|
|
|
52 |
}
|
53 |
</script>
|
54 |
|
@@ -61,6 +67,7 @@
|
|
61 |
<Dialog open={submitModelDialog} onClose={() => submitModelDialog = false}>
|
62 |
<SubmitModel onClose={() => submitModelDialog = false} />
|
63 |
</Dialog>
|
|
|
64 |
<h1 class="text-white font-semibold text-2xl">
|
65 |
Explore Models ({data?.total_items ?? 0})
|
66 |
</h1>
|
@@ -110,5 +117,4 @@
|
|
110 |
/>
|
111 |
<GoTop />
|
112 |
</div>
|
113 |
-
<Drawer />
|
114 |
</main>
|
|
|
26 |
$: elementScroll = browser ? document?.getElementById('app') : undefined;
|
27 |
|
28 |
if (data?.model?.id) {
|
29 |
+
modelStore.set({
|
30 |
+
model: data.model,
|
31 |
+
open: true
|
32 |
+
});
|
33 |
}
|
34 |
|
35 |
const handleFetchMore = async () => {
|
|
|
51 |
const request = await fetch(`/api/models?${new URLSearchParams(form)}`);
|
52 |
const response = await request.json();
|
53 |
if (add) data = {...data, models: [...data.models, ...response.cards ]};
|
54 |
+
else {
|
55 |
+
data.models = response.cards;
|
56 |
+
data.total_items = response.total_items;
|
57 |
+
}
|
58 |
}
|
59 |
</script>
|
60 |
|
|
|
67 |
<Dialog open={submitModelDialog} onClose={() => submitModelDialog = false}>
|
68 |
<SubmitModel onClose={() => submitModelDialog = false} />
|
69 |
</Dialog>
|
70 |
+
<Drawer />
|
71 |
<h1 class="text-white font-semibold text-2xl">
|
72 |
Explore Models ({data?.total_items ?? 0})
|
73 |
</h1>
|
|
|
117 |
/>
|
118 |
<GoTop />
|
119 |
</div>
|
|
|
120 |
</main>
|
src/routes/api/community/[id]/+server.ts
CHANGED
@@ -3,8 +3,10 @@ import prisma from '$lib/prisma';
|
|
3 |
|
4 |
/** @type {import('./$types').RequestHandler} */
|
5 |
|
6 |
-
export async function GET({ params } : RequestEvent) {
|
7 |
const id = params.id;
|
|
|
|
|
8 |
|
9 |
const gallery = await prisma.gallery.findFirst({
|
10 |
where: {
|
@@ -63,7 +65,20 @@ export async function GET({ params } : RequestEvent) {
|
|
63 |
isPublic: true,
|
64 |
createdAt: {
|
65 |
lt: gallery.createdAt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
}
|
|
|
67 |
},
|
68 |
select: {
|
69 |
id: true,
|
@@ -75,7 +90,20 @@ export async function GET({ params } : RequestEvent) {
|
|
75 |
isPublic: true,
|
76 |
createdAt: {
|
77 |
gt: gallery.createdAt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
}
|
|
|
79 |
},
|
80 |
select: {
|
81 |
id: true,
|
|
|
3 |
|
4 |
/** @type {import('./$types').RequestHandler} */
|
5 |
|
6 |
+
export async function GET({ params, url } : RequestEvent) {
|
7 |
const id = params.id;
|
8 |
+
const filter = url.searchParams.get('filter') || 'new'
|
9 |
+
const search = url.searchParams.get('search') || ''
|
10 |
|
11 |
const gallery = await prisma.gallery.findFirst({
|
12 |
where: {
|
|
|
65 |
isPublic: true,
|
66 |
createdAt: {
|
67 |
lt: gallery.createdAt
|
68 |
+
},
|
69 |
+
OR: [
|
70 |
+
{ prompt: { contains: search } },
|
71 |
+
],
|
72 |
+
},
|
73 |
+
orderBy: {
|
74 |
+
...(filter === 'new' ? {
|
75 |
+
createdAt: 'desc'
|
76 |
+
} : {
|
77 |
+
reactions: {
|
78 |
+
_count: 'desc'
|
79 |
+
}
|
80 |
}
|
81 |
+
)
|
82 |
},
|
83 |
select: {
|
84 |
id: true,
|
|
|
90 |
isPublic: true,
|
91 |
createdAt: {
|
92 |
gt: gallery.createdAt
|
93 |
+
},
|
94 |
+
OR: [
|
95 |
+
{ prompt: { contains: search } },
|
96 |
+
],
|
97 |
+
},
|
98 |
+
orderBy: {
|
99 |
+
...(filter === 'new' ? {
|
100 |
+
createdAt: 'desc'
|
101 |
+
} : {
|
102 |
+
reactions: {
|
103 |
+
_count: 'desc'
|
104 |
+
}
|
105 |
}
|
106 |
+
)
|
107 |
},
|
108 |
select: {
|
109 |
id: true,
|
src/routes/gallery/+page.svelte
CHANGED
@@ -53,7 +53,7 @@
|
|
53 |
<h1 class="text-white font-semibold text-2xl">
|
54 |
Community Gallery ({data.total_items})
|
55 |
</h1>
|
56 |
-
<div class="flex items-center justify-between mt-5">
|
57 |
<Radio options={COMMUNITY_FILTER_OPTIONS} value="{form.filter}" onChange={handleChangeFilter} />
|
58 |
<div class="items-center justify-end gap-5 hidden lg:flex">
|
59 |
<!-- <UserIsLogged> -->
|
@@ -74,7 +74,7 @@
|
|
74 |
<!-- mx-auto grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 3xl:grid-cols-5 gap-5 mt-8 lg:mt-10 -->
|
75 |
<div class="mx-auto grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 2xl:grid-cols-4 gap-5 mt-8 lg:mt-10">
|
76 |
{#each data.cards as card}
|
77 |
-
<Card card={card} />
|
78 |
{/each}
|
79 |
<InfiniteScroll
|
80 |
elementScroll="{elementScroll ?? undefined}"
|
@@ -84,5 +84,5 @@
|
|
84 |
/>
|
85 |
<GoTop />
|
86 |
</div>
|
87 |
-
<GalleryViewer />
|
88 |
</main>
|
|
|
53 |
<h1 class="text-white font-semibold text-2xl">
|
54 |
Community Gallery ({data.total_items})
|
55 |
</h1>
|
56 |
+
<div class="flex items-start sm:items-center justify-between mt-5 flex-col sm:flex-row gap-5 sm:justify-between">
|
57 |
<Radio options={COMMUNITY_FILTER_OPTIONS} value="{form.filter}" onChange={handleChangeFilter} />
|
58 |
<div class="items-center justify-end gap-5 hidden lg:flex">
|
59 |
<!-- <UserIsLogged> -->
|
|
|
74 |
<!-- mx-auto grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 3xl:grid-cols-5 gap-5 mt-8 lg:mt-10 -->
|
75 |
<div class="mx-auto grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 2xl:grid-cols-4 gap-5 mt-8 lg:mt-10">
|
76 |
{#each data.cards as card}
|
77 |
+
<Card card={card} form={form} />
|
78 |
{/each}
|
79 |
<InfiniteScroll
|
80 |
elementScroll="{elementScroll ?? undefined}"
|
|
|
84 |
/>
|
85 |
<GoTop />
|
86 |
</div>
|
87 |
+
<GalleryViewer form={form} />
|
88 |
</main>
|