victor HF Staff Thomas G. Lopes commited on
Commit
427a3a2
·
unverified ·
1 Parent(s): 3884907

UI tweaks (#80)

Browse files

Co-authored-by: Thomas G. Lopes <26071571+TGlide@users.noreply.github.com>

src/lib/components/icon-custom.svelte CHANGED
@@ -1,7 +1,7 @@
1
  <script lang="ts">
2
  import type { SVGAttributes } from "svelte/elements";
3
 
4
- type Icon = "regen";
5
 
6
  interface Props extends SVGAttributes<SVGElement> {
7
  icon: Icon;
@@ -18,3 +18,12 @@
18
  />
19
  </svg>
20
  {/if}
 
 
 
 
 
 
 
 
 
 
1
  <script lang="ts">
2
  import type { SVGAttributes } from "svelte/elements";
3
 
4
+ type Icon = "regen" | "refresh";
5
 
6
  interface Props extends SVGAttributes<SVGElement> {
7
  icon: Icon;
 
18
  />
19
  </svg>
20
  {/if}
21
+
22
+ {#if icon === "refresh"}
23
+ <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"
24
+ ><path
25
+ d="M9.02 3.54A5.73 5.73 0 0 0 5.9 14.05v-2.71h1.04v4.16H2.77v-1.04H4.7A6.76 6.76 0 0 1 9.02 2.5v1.04Zm6.17 0h-1.92A6.76 6.76 0 0 1 8.94 15.5v-1.04a5.73 5.73 0 0 0 3.13-10.51v2.71h-1.04V2.5h4.16v1.04Z"
26
+ fill="currentColor"
27
+ /></svg
28
+ >
29
+ {/if}
src/lib/components/inference-playground/generation-config.svelte CHANGED
@@ -33,7 +33,7 @@
33
 
34
  <div>
35
  <div class="flex items-center justify-between">
36
- <label for={key} class="mb-2 block text-sm font-medium text-gray-900 dark:text-white">
37
  {label}
38
  </label>
39
  <div class="flex items-center gap-2">
 
33
 
34
  <div>
35
  <div class="flex items-center justify-between">
36
+ <label for={key} class="mb-0.5 block text-sm font-medium text-gray-900 dark:text-white">
37
  {label}
38
  </label>
39
  <div class="flex items-center gap-2">
src/lib/components/inference-playground/message.svelte CHANGED
@@ -3,13 +3,16 @@
3
  import Tooltip from "$lib/components/tooltip.svelte";
4
  import { TextareaAutosize } from "$lib/spells/textarea-autosize.svelte.js";
5
  import { PipelineTag, type Conversation, type ConversationMessage } from "$lib/types.js";
 
6
  import { fileToDataURL } from "$lib/utils/file.js";
7
  import { FileUpload } from "melt/builders";
8
  import { fade } from "svelte/transition";
 
9
  import IconImage from "~icons/carbon/image-reference";
10
  import IconMaximize from "~icons/carbon/maximize";
11
  import IconCustom from "../icon-custom.svelte";
12
  import ImgPreview from "./img-preview.svelte";
 
13
 
14
  type Props = {
15
  conversation: Conversation;
@@ -24,10 +27,11 @@
24
  let { message = $bindable(), conversation, loading, autofocus, onDelete, onRegen, isLast }: Props = $props();
25
 
26
  let element = $state<HTMLTextAreaElement>();
27
- new TextareaAutosize({
28
  element: () => element,
29
  input: () => message.content ?? "",
30
  });
 
31
 
32
  const canUploadImgs = $derived(
33
  message.role === "user" &&
@@ -59,13 +63,13 @@
59
  </script>
60
 
61
  <div
62
- class="group/message group relative flex flex-col items-start gap-x-4 gap-y-2 border-b px-3.5 pt-4 pb-6 hover:bg-gray-100/70
63
- @2xl:px-6 dark:border-gray-800 dark:hover:bg-gray-800/30"
64
  class:pointer-events-none={loading}
65
  {...fileUpload.dropzone}
66
  onclick={undefined}
67
  >
68
- <div class=" flex w-full flex-col items-start gap-x-4 gap-y-2 @2xl:flex-row">
69
  {#if fileUpload.isDragging}
70
  <div
71
  class="absolute inset-2 z-10 flex flex-col items-center justify-center rounded-xl bg-gray-800/50 backdrop-blur-md"
@@ -76,7 +80,12 @@
76
  </div>
77
  {/if}
78
 
79
- <div class="pt-3 text-sm font-semibold uppercase @2xl:basis-[130px]">
 
 
 
 
 
80
  {message.role}
81
  </div>
82
  <div class="flex w-full gap-4">
@@ -90,65 +99,97 @@
90
  data-message
91
  ></textarea>
92
 
93
- {#if canUploadImgs}
94
- <Tooltip openDelay={250}>
95
- {#snippet trigger(tooltip)}
96
- <button
97
- tabindex="0"
98
- type="button"
99
- class="mt-1.5 -mr-2 grid size-8 place-items-center rounded-lg border border-gray-200 bg-white text-xs font-medium
100
- text-gray-900 group-focus-within/message:visible group-hover/message:visible
101
- hover:bg-gray-100 hover:text-blue-700 focus:z-10
102
- focus:ring-4 focus:ring-gray-100 focus:outline-hidden sm:invisible dark:border-gray-600
103
- dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
104
- {...tooltip.trigger}
105
- {...fileUpload.trigger}
106
- >
107
- <IconImage />
108
- </button>
109
- <input {...fileUpload.input} />
110
- {/snippet}
111
- Add image
112
- </Tooltip>
113
- {/if}
114
-
115
- <Tooltip>
116
- {#snippet trigger(tooltip)}
117
- <button
118
- tabindex="0"
119
- onclick={onRegen}
120
- type="button"
121
- class="mt-1.5 -mr-2 grid size-8 place-items-center rounded-lg border border-gray-200 bg-white text-xs font-medium text-gray-900
122
- group-focus-within/message:visible group-hover/message:visible hover:bg-gray-100
123
- hover:text-blue-700 focus:z-10 focus:ring-4
124
- focus:ring-gray-100 focus:outline-hidden sm:invisible dark:border-gray-600 dark:bg-gray-800
125
- dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
126
- {...tooltip.trigger}
127
- >
128
- <IconCustom icon="regen" />
129
- </button>
130
- {/snippet}
131
- {regenLabel}
132
- </Tooltip>
133
-
134
- <Tooltip>
135
- {#snippet trigger(tooltip)}
136
- <button
137
- tabindex="0"
138
- onclick={onDelete}
139
- type="button"
140
- class="mt-1.5 size-8 rounded-lg border border-gray-200 bg-white text-xs font-medium text-gray-900
141
- group-focus-within/message:visible group-hover/message:visible hover:bg-gray-100
142
- hover:text-blue-700 focus:z-10 focus:ring-4
143
- focus:ring-gray-100 focus:outline-hidden sm:invisible dark:border-gray-600 dark:bg-gray-800
144
- dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
145
- {...tooltip.trigger}
146
- >
147
-
148
- </button>
149
- {/snippet}
150
- Delete
151
- </Tooltip>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  </div>
153
  </div>
154
 
 
3
  import Tooltip from "$lib/components/tooltip.svelte";
4
  import { TextareaAutosize } from "$lib/spells/textarea-autosize.svelte.js";
5
  import { PipelineTag, type Conversation, type ConversationMessage } from "$lib/types.js";
6
+ import { copyToClipboard } from "$lib/utils/copy.js";
7
  import { fileToDataURL } from "$lib/utils/file.js";
8
  import { FileUpload } from "melt/builders";
9
  import { fade } from "svelte/transition";
10
+ import IconCopy from "~icons/carbon/copy";
11
  import IconImage from "~icons/carbon/image-reference";
12
  import IconMaximize from "~icons/carbon/maximize";
13
  import IconCustom from "../icon-custom.svelte";
14
  import ImgPreview from "./img-preview.svelte";
15
+ import LocalToasts from "../local-toasts.svelte";
16
 
17
  type Props = {
18
  conversation: Conversation;
 
27
  let { message = $bindable(), conversation, loading, autofocus, onDelete, onRegen, isLast }: Props = $props();
28
 
29
  let element = $state<HTMLTextAreaElement>();
30
+ const autosized = new TextareaAutosize({
31
  element: () => element,
32
  input: () => message.content ?? "",
33
  });
34
+ const shouldStick = $derived(autosized.textareaHeight > 92);
35
 
36
  const canUploadImgs = $derived(
37
  message.role === "user" &&
 
63
  </script>
64
 
65
  <div
66
+ class="group/message group relative flex flex-col items-start gap-x-4 gap-y-2 border-b bg-white px-3.5 pt-4 pb-6 hover:bg-gray-100/70
67
+ @2xl:px-6 dark:border-gray-800 dark:bg-gray-900 dark:hover:bg-gray-800/30"
68
  class:pointer-events-none={loading}
69
  {...fileUpload.dropzone}
70
  onclick={undefined}
71
  >
72
+ <div class="flex w-full flex-col items-start gap-x-4 gap-y-2 max-md:text-sm @2xl:flex-row">
73
  {#if fileUpload.isDragging}
74
  <div
75
  class="absolute inset-2 z-10 flex flex-col items-center justify-center rounded-xl bg-gray-800/50 backdrop-blur-md"
 
80
  </div>
81
  {/if}
82
 
83
+ <div
84
+ class={[
85
+ "top-8 z-10 bg-inherit pt-3 text-sm font-semibold uppercase @2xl:basis-[130px] @2xl:self-start",
86
+ shouldStick && "@min-2xl:sticky",
87
+ ]}
88
+ >
89
  {message.role}
90
  </div>
91
  <div class="flex w-full gap-4">
 
99
  data-message
100
  ></textarea>
101
 
102
+ <!-- Sticky wrapper for action buttons -->
103
+ <div class={["top-8 z-10 self-start", shouldStick && "sticky"]}>
104
+ <div class="flex flex-col items-start gap-1 @2xl:flex-row @2xl:gap-4">
105
+ {#if canUploadImgs}
106
+ <Tooltip openDelay={250}>
107
+ {#snippet trigger(tooltip)}
108
+ <button
109
+ tabindex="0"
110
+ type="button"
111
+ class="mt-1.5 grid size-7 place-items-center rounded-lg border border-gray-200 bg-white text-xs font-medium text-gray-900
112
+ hover:bg-gray-100
113
+ hover:text-blue-700 focus:z-10 focus:ring-4
114
+ focus:ring-gray-100 focus:outline-hidden md:-mr-2 dark:border-gray-600
115
+ dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
116
+ {...tooltip.trigger}
117
+ {...fileUpload.trigger}
118
+ >
119
+ <IconImage />
120
+ </button>
121
+ <input {...fileUpload.input} />
122
+ {/snippet}
123
+ Add image
124
+ </Tooltip>
125
+ {/if}
126
+
127
+ <Tooltip>
128
+ {#snippet trigger(tooltip)}
129
+ <LocalToasts>
130
+ {#snippet children({ trigger, addToast })}
131
+ <button
132
+ tabindex="0"
133
+ onclick={() => {
134
+ copyToClipboard(message.content ?? "");
135
+ addToast({ data: { content: "✓", variant: "info" } });
136
+ }}
137
+ type="button"
138
+ class="mt-1.5 grid size-7 place-items-center rounded-lg border border-gray-200 bg-white text-xs font-medium text-gray-900 hover:bg-gray-100
139
+ hover:text-blue-700
140
+ focus:z-10 focus:ring-4 focus:ring-gray-100
141
+ focus:outline-hidden md:-mr-2 dark:border-gray-600 dark:bg-gray-800
142
+ dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
143
+ {...tooltip.trigger}
144
+ {...trigger}
145
+ >
146
+ <IconCopy />
147
+ </button>
148
+ {/snippet}
149
+ </LocalToasts>
150
+ {/snippet}
151
+ Copy
152
+ </Tooltip>
153
+
154
+ <Tooltip>
155
+ {#snippet trigger(tooltip)}
156
+ <button
157
+ tabindex="0"
158
+ onclick={onRegen}
159
+ type="button"
160
+ class="mt-1.5 grid size-7 place-items-center rounded-lg border border-gray-200 bg-white text-xs font-medium text-gray-900 hover:bg-gray-100
161
+ hover:text-blue-700
162
+ focus:z-10 focus:ring-4 focus:ring-gray-100
163
+ focus:outline-hidden md:-mr-2 dark:border-gray-600 dark:bg-gray-800
164
+ dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
165
+ {...tooltip.trigger}
166
+ >
167
+ <IconCustom icon={message.role === "user" ? "regen" : "refresh"} />
168
+ </button>
169
+ {/snippet}
170
+ {regenLabel}
171
+ </Tooltip>
172
+
173
+ <Tooltip>
174
+ {#snippet trigger(tooltip)}
175
+ <button
176
+ tabindex="0"
177
+ onclick={onDelete}
178
+ type="button"
179
+ class="mt-1.5 grid size-7 place-items-center rounded-lg border border-gray-200 bg-white text-xs font-medium text-gray-900 hover:bg-gray-100
180
+ hover:text-blue-700
181
+ focus:z-10 focus:ring-4 focus:ring-gray-100
182
+ focus:outline-hidden md:-mr-2 dark:border-gray-600 dark:bg-gray-800
183
+ dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
184
+ {...tooltip.trigger}
185
+ >
186
+
187
+ </button>
188
+ {/snippet}
189
+ Delete
190
+ </Tooltip>
191
+ </div>
192
+ </div>
193
  </div>
194
  </div>
195
 
src/lib/components/inference-playground/model-selector-modal.svelte CHANGED
@@ -70,7 +70,7 @@
70
 
71
  <!-- svelte-ignore a11y_no_static_element_interactions -->
72
  <!-- svelte-ignore a11y_click_events_have_key_events -->
73
- <div class="fixed inset-0 z-10 h-dvh bg-black/85 pt-32" bind:this={backdropEl} onclick={handleBackdropClick}>
74
  <div
75
  class="abs-x-center md:abs-y-center absolute top-12 flex w-[calc(100%-2rem)] max-w-[600px] flex-col overflow-hidden rounded-lg border bg-white text-gray-900 shadow-md dark:border-gray-800 dark:bg-gray-900 dark:text-gray-300"
76
  >
 
70
 
71
  <!-- svelte-ignore a11y_no_static_element_interactions -->
72
  <!-- svelte-ignore a11y_click_events_have_key_events -->
73
+ <div class="fixed inset-0 z-50 h-dvh bg-black/85 pt-32" bind:this={backdropEl} onclick={handleBackdropClick}>
74
  <div
75
  class="abs-x-center md:abs-y-center absolute top-12 flex w-[calc(100%-2rem)] max-w-[600px] flex-col overflow-hidden rounded-lg border bg-white text-gray-900 shadow-md dark:border-gray-800 dark:bg-gray-900 dark:text-gray-300"
76
  >
src/lib/components/local-toasts.svelte CHANGED
@@ -14,7 +14,7 @@
14
  const id = $props.id();
15
 
16
  export const trigger = {
17
- id,
18
  } as const;
19
 
20
  type ToastData = {
@@ -30,7 +30,7 @@
30
  export const addToast = toaster.addToast;
31
 
32
  function float(node: HTMLElement) {
33
- const triggerEl = document.getElementById(trigger.id);
34
  if (!triggerEl) return;
35
 
36
  const compute = () =>
 
14
  const id = $props.id();
15
 
16
  export const trigger = {
17
+ "data-local-toast-trigger": id,
18
  } as const;
19
 
20
  type ToastData = {
 
30
  export const addToast = toaster.addToast;
31
 
32
  function float(node: HTMLElement) {
33
+ const triggerEl = document.querySelector(`[data-local-toast-trigger=${id}]`);
34
  if (!triggerEl) return;
35
 
36
  const compute = () =>