coyotte508 HF staff commited on
Commit
c8c5d70
1 Parent(s): 06e879d

♿️ No-JS ethics modal (#166)

Browse files
src/lib/components/EthicsModal.svelte CHANGED
@@ -1,11 +1,9 @@
1
  <script lang="ts">
 
 
2
  import { PUBLIC_VERSION } from "$env/static/public";
3
  import Logo from "$lib/components/icons/Logo.svelte";
4
  import Modal from "$lib/components/Modal.svelte";
5
- import type { Settings } from "$lib/types/Settings";
6
- import { updateSettings } from "$lib/updateSettings";
7
-
8
- export let settings: Omit<Settings, "sessionId" | "createdAt" | "updatedAt">;
9
  </script>
10
 
11
  <Modal>
@@ -14,13 +12,11 @@
14
  >
15
  <h2 class="flex items-center text-2xl font-semibold text-gray-800">
16
  <Logo classNames="text-3xl mr-1.5" />HuggingChat
17
- {#if typeof PUBLIC_VERSION !== "undefined"}
18
- <div
19
- class="ml-3 flex h-6 items-center rounded-lg border border-gray-100 bg-gray-50 px-2 text-base text-gray-400"
20
- >
21
- v{PUBLIC_VERSION}
22
- </div>
23
- {/if}
24
  </h2>
25
  <p class="px-4 text-lg font-semibold leading-snug text-gray-800 sm:px-12">
26
  This application is for demonstration purposes only.
@@ -32,13 +28,14 @@
32
  <p class="px-2 text-sm text-gray-500">
33
  Your conversations will be shared with model authors unless you disable it from your settings.
34
  </p>
35
- <!-- The updateSettings call will invalidate the settings, which will reload the page without the modal -->
36
- <button
37
- type="button"
38
- on:click={() => updateSettings({ ...settings, ethicsModalAccepted: true })}
39
- class="mt-2 rounded-full bg-black px-5 py-2 text-lg font-semibold text-gray-100 transition-colors hover:bg-yellow-500"
40
- >
41
- Start chatting
42
- </button>
 
43
  </div>
44
  </Modal>
 
1
  <script lang="ts">
2
+ import { enhance } from "$app/forms";
3
+ import { base } from "$app/paths";
4
  import { PUBLIC_VERSION } from "$env/static/public";
5
  import Logo from "$lib/components/icons/Logo.svelte";
6
  import Modal from "$lib/components/Modal.svelte";
 
 
 
 
7
  </script>
8
 
9
  <Modal>
 
12
  >
13
  <h2 class="flex items-center text-2xl font-semibold text-gray-800">
14
  <Logo classNames="text-3xl mr-1.5" />HuggingChat
15
+ <div
16
+ class="ml-3 flex h-6 items-center rounded-lg border border-gray-100 bg-gray-50 px-2 text-base text-gray-400"
17
+ >
18
+ v{PUBLIC_VERSION}
19
+ </div>
 
 
20
  </h2>
21
  <p class="px-4 text-lg font-semibold leading-snug text-gray-800 sm:px-12">
22
  This application is for demonstration purposes only.
 
28
  <p class="px-2 text-sm text-gray-500">
29
  Your conversations will be shared with model authors unless you disable it from your settings.
30
  </p>
31
+ <form action="{base}/settings" use:enhance method="POST">
32
+ <input type="hidden" name="ethicsModalAccepted" value={true} />
33
+ <button
34
+ type="submit"
35
+ class="mt-2 rounded-full bg-black px-5 py-2 text-lg font-semibold text-gray-100 transition-colors hover:bg-yellow-500"
36
+ >
37
+ Start chatting
38
+ </button>
39
+ </form>
40
  </div>
41
  </Modal>
src/lib/components/SettingsModal.svelte CHANGED
@@ -5,7 +5,8 @@
5
  import CarbonClose from "~icons/carbon/close";
6
  import Switch from "$lib/components/Switch.svelte";
7
  import type { Settings } from "$lib/types/Settings";
8
- import { updateSettings } from "$lib/updateSettings";
 
9
 
10
  export let settings: Pick<Settings, "shareConversationsWithModelAuthors">;
11
 
@@ -13,7 +14,14 @@
13
  </script>
14
 
15
  <Modal>
16
- <div class="flex w-full flex-col gap-5 p-6">
 
 
 
 
 
 
 
17
  <div class="flex items-start justify-between text-xl font-semibold text-gray-800">
18
  <h2>Settings</h2>
19
  <button class="group" on:click={() => dispatch("close")}>
@@ -21,8 +29,11 @@
21
  </button>
22
  </div>
23
 
24
- <label class="flex cursor-pointer select-none items-center gap-2 text-gray-500" for="switch">
25
- <Switch name="switch" bind:checked={settings.shareConversationsWithModelAuthors} />
 
 
 
26
  Share conversations with model authors
27
  </label>
28
 
@@ -42,18 +53,10 @@
42
  >.
43
  </p>
44
  <button
45
- type="button"
46
  class="mt-2 rounded-full bg-black px-5 py-2 text-lg font-semibold text-gray-100 ring-gray-400 ring-offset-1 transition-colors hover:ring"
47
- on:click={() =>
48
- updateSettings({
49
- shareConversationsWithModelAuthors: settings.shareConversationsWithModelAuthors,
50
- }).then((res) => {
51
- if (res) {
52
- dispatch("close");
53
- }
54
- })}
55
  >
56
  Apply
57
  </button>
58
- </div>
59
  </Modal>
 
5
  import CarbonClose from "~icons/carbon/close";
6
  import Switch from "$lib/components/Switch.svelte";
7
  import type { Settings } from "$lib/types/Settings";
8
+ import { enhance } from "$app/forms";
9
+ import { base } from "$app/paths";
10
 
11
  export let settings: Pick<Settings, "shareConversationsWithModelAuthors">;
12
 
 
14
  </script>
15
 
16
  <Modal>
17
+ <form
18
+ class="flex w-full flex-col gap-5 p-6"
19
+ use:enhance={() => {
20
+ dispatch("close");
21
+ }}
22
+ method="post"
23
+ action="{base}/settings"
24
+ >
25
  <div class="flex items-start justify-between text-xl font-semibold text-gray-800">
26
  <h2>Settings</h2>
27
  <button class="group" on:click={() => dispatch("close")}>
 
29
  </button>
30
  </div>
31
 
32
+ <label class="flex cursor-pointer select-none items-center gap-2 text-gray-500">
33
+ <Switch
34
+ name="shareConversationsWithModelAuthors"
35
+ bind:checked={settings.shareConversationsWithModelAuthors}
36
+ />
37
  Share conversations with model authors
38
  </label>
39
 
 
53
  >.
54
  </p>
55
  <button
56
+ type="submit"
57
  class="mt-2 rounded-full bg-black px-5 py-2 text-lg font-semibold text-gray-100 ring-gray-400 ring-offset-1 transition-colors hover:ring"
 
 
 
 
 
 
 
 
58
  >
59
  Apply
60
  </button>
61
+ </form>
62
  </Modal>
src/lib/components/Switch.svelte CHANGED
@@ -3,19 +3,9 @@
3
  export let name: string;
4
  </script>
5
 
 
6
  <div
7
- class="relative inline-flex h-5 w-9 items-center rounded-full p-1 shadow-inner transition-all {checked
8
- ? 'bg-black'
9
- : 'bg-gray-300 hover:bg-gray-400'}"
10
  >
11
- <input
12
- bind:checked
13
- type="checkbox"
14
- {name}
15
- id={name}
16
- class="peer absolute inset-0 cursor-pointer opacity-0"
17
- />
18
- <div
19
- class="h-3.5 w-3.5 rounded-full bg-white shadow-sm transition-all peer-checked:translate-x-3.5"
20
- />
21
  </div>
 
3
  export let name: string;
4
  </script>
5
 
6
+ <input bind:checked type="checkbox" {name} class="peer pointer-events-none absolute opacity-0" />
7
  <div
8
+ class="relative inline-flex h-5 w-9 items-center rounded-full bg-gray-300 p-1 shadow-inner transition-all peer-checked:bg-black hover:bg-gray-400 peer-checked:[&>div]:translate-x-3.5"
 
 
9
  >
10
+ <div class="h-3.5 w-3.5 rounded-full bg-white shadow-sm transition-all" />
 
 
 
 
 
 
 
 
 
11
  </div>
src/lib/components/chat/ChatIntroduction.svelte CHANGED
@@ -15,13 +15,11 @@
15
  <div class="mb-3 flex items-center text-2xl font-semibold">
16
  <Logo classNames="mr-1 text-yellow-400 text-4xl" />
17
  HuggingChat
18
- {#if typeof PUBLIC_VERSION !== "undefined"}
19
- <div
20
- class="ml-3 flex h-6 items-center rounded-lg border border-gray-100 bg-gray-50 px-2 text-base text-gray-400 dark:border-gray-700/60 dark:bg-gray-800"
21
- >
22
- v{PUBLIC_VERSION}
23
- </div>
24
- {/if}
25
  </div>
26
  <p class="text-base text-gray-600 dark:text-gray-400">
27
  Making the community's best AI chat models available to everyone.
 
15
  <div class="mb-3 flex items-center text-2xl font-semibold">
16
  <Logo classNames="mr-1 text-yellow-400 text-4xl" />
17
  HuggingChat
18
+ <div
19
+ class="ml-3 flex h-6 items-center rounded-lg border border-gray-100 bg-gray-50 px-2 text-base text-gray-400 dark:border-gray-700/60 dark:bg-gray-800"
20
+ >
21
+ v{PUBLIC_VERSION}
22
+ </div>
 
 
23
  </div>
24
  <p class="text-base text-gray-600 dark:text-gray-400">
25
  Making the community's best AI chat models available to everyone.
src/lib/types/UrlDependency.ts CHANGED
@@ -1,5 +1,4 @@
1
  /* eslint-disable no-shadow */
2
  export enum UrlDependency {
3
  ConversationList = "conversation:list",
4
- Settings = "settings:list",
5
  }
 
1
  /* eslint-disable no-shadow */
2
  export enum UrlDependency {
3
  ConversationList = "conversation:list",
 
4
  }
src/lib/updateSettings.ts DELETED
@@ -1,29 +0,0 @@
1
- import { invalidate } from "$app/navigation";
2
- import { base } from "$app/paths";
3
- import { error } from "$lib/stores/errors";
4
- import type { Settings } from "./types/Settings";
5
- import { UrlDependency } from "./types/UrlDependency";
6
-
7
- export async function updateSettings(
8
- settings: Partial<
9
- Omit<Settings, "sessionId" | "ethicsModalAcceptedAt"> & { ethicsModalAccepted?: boolean }
10
- >
11
- ): Promise<boolean> {
12
- try {
13
- const res = await fetch(`${base}/settings`, {
14
- method: "PATCH",
15
- headers: { "Content-Type": "application/json" },
16
- body: JSON.stringify(settings),
17
- });
18
- if (!res.ok) {
19
- error.set("Error while updating settings, try again.");
20
- return false;
21
- }
22
- await invalidate(UrlDependency.Settings);
23
- return true;
24
- } catch (err) {
25
- console.error(err);
26
- error.set(String(err));
27
- return false;
28
- }
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/routes/+layout.server.ts CHANGED
@@ -8,7 +8,6 @@ export const load: LayoutServerLoad = async ({ locals, depends }) => {
8
  const { conversations } = collections;
9
 
10
  depends(UrlDependency.ConversationList);
11
- depends(UrlDependency.Settings);
12
 
13
  const settings = await collections.settings.findOne({ sessionId: locals.sessionId });
14
 
 
8
  const { conversations } = collections;
9
 
10
  depends(UrlDependency.ConversationList);
 
11
 
12
  const settings = await collections.settings.findOne({ sessionId: locals.sessionId });
13
 
src/routes/+layout.svelte CHANGED
@@ -135,7 +135,7 @@
135
  <SettingsModal on:close={() => (isSettingsOpen = false)} settings={data.settings} />
136
  {/if}
137
  {#if !data.settings.ethicsModalAcceptedAt}
138
- <EthicsModal settings={data.settings} />
139
  {/if}
140
  <slot />
141
  </div>
 
135
  <SettingsModal on:close={() => (isSettingsOpen = false)} settings={data.settings} />
136
  {/if}
137
  {#if !data.settings.ethicsModalAcceptedAt}
138
+ <EthicsModal />
139
  {/if}
140
  <slot />
141
  </div>
src/routes/settings/+page.server.ts ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { base } from "$app/paths";
2
+ import { collections } from "$lib/server/database.js";
3
+ import { redirect } from "@sveltejs/kit";
4
+ import { z } from "zod";
5
+
6
+ export const actions = {
7
+ default: async function ({ request, locals }) {
8
+ const formData = await request.formData();
9
+
10
+ const existingSettings = await collections.settings.findOne({ sessionId: locals.sessionId });
11
+
12
+ const { ethicsModalAccepted, ...settings } = z
13
+ .object({
14
+ shareConversationsWithModelAuthors: z
15
+ .boolean({ coerce: true })
16
+ .default(existingSettings?.shareConversationsWithModelAuthors ?? true),
17
+ ethicsModalAccepted: z.boolean({ coerce: true }).optional(),
18
+ })
19
+ .parse({
20
+ shareConversationsWithModelAuthors: formData.get("shareConversationsWithModelAuthors"),
21
+ ethicsModalAccepted: formData.get("ethicsModalAccepted"),
22
+ });
23
+
24
+ await collections.settings.updateOne(
25
+ {
26
+ sessionId: locals.sessionId,
27
+ },
28
+ {
29
+ $set: {
30
+ ...settings,
31
+ ...(ethicsModalAccepted && { ethicsModalAcceptedAt: new Date() }),
32
+ updatedAt: new Date(),
33
+ },
34
+ $setOnInsert: {
35
+ createdAt: new Date(),
36
+ },
37
+ },
38
+ {
39
+ upsert: true,
40
+ }
41
+ );
42
+
43
+ throw redirect(303, request.headers.get("referer") || base || "/");
44
+ },
45
+ };
src/routes/settings/+server.ts DELETED
@@ -1,34 +0,0 @@
1
- import { collections } from "$lib/server/database.js";
2
- import { z } from "zod";
3
-
4
- export async function PATCH({ locals, request }) {
5
- const json = await request.json();
6
-
7
- const { ethicsModalAccepted, ...settings } = z
8
- .object({
9
- shareConversationsWithModelAuthors: z.boolean().default(true),
10
- ethicsModalAccepted: z.boolean().optional(),
11
- })
12
- .parse(json);
13
-
14
- await collections.settings.updateOne(
15
- {
16
- sessionId: locals.sessionId,
17
- },
18
- {
19
- $set: {
20
- ...settings,
21
- ...(ethicsModalAccepted && { ethicsModalAcceptedAt: new Date() }),
22
- updatedAt: new Date(),
23
- },
24
- $setOnInsert: {
25
- createdAt: new Date(),
26
- },
27
- },
28
- {
29
- upsert: true,
30
- }
31
- );
32
-
33
- return new Response();
34
- }