Thomas G. Lopes commited on
Commit
143859e
·
1 Parent(s): fbef5e8

fix light theme in structured output

Browse files
src/lib/components/debug-menu.svelte CHANGED
@@ -9,6 +9,7 @@
9
  import { showQuotaModal } from "./quota-modal.svelte";
10
  import type { ToastData } from "./toaster.svelte.js";
11
  import { addToast } from "./toaster.svelte.js";
 
12
 
13
  let innerWidth = $state<number>();
14
  let innerHeight = $state<number>();
@@ -113,6 +114,7 @@
113
  <div class="text-sm dark:text-gray-300">
114
  <p>Viewport: {innerWidth}x{innerHeight}</p>
115
  <p>Environment: {import.meta.env.MODE}</p>
 
116
  </div>
117
 
118
  <div class="grid grid-cols-2 gap-2">
 
9
  import { showQuotaModal } from "./quota-modal.svelte";
10
  import type { ToastData } from "./toaster.svelte.js";
11
  import { addToast } from "./toaster.svelte.js";
12
+ import { isDark } from "$lib/spells/is-dark.svelte";
13
 
14
  let innerWidth = $state<number>();
15
  let innerHeight = $state<number>();
 
114
  <div class="text-sm dark:text-gray-300">
115
  <p>Viewport: {innerWidth}x{innerHeight}</p>
116
  <p>Environment: {import.meta.env.MODE}</p>
117
+ <p>isDark: {isDark()}</p>
118
  </div>
119
 
120
  <div class="grid grid-cols-2 gap-2">
src/lib/components/inference-playground/structured-output-modal.svelte CHANGED
@@ -10,6 +10,7 @@
10
  import typia from "typia";
11
  import IconX from "~icons/carbon/close";
12
  import Dialog from "../dialog.svelte";
 
13
 
14
  interface Props {
15
  conversation: ConversationClass;
@@ -112,7 +113,7 @@
112
  <Dialog title="Edit Structured Output" {open} onClose={() => (open = false)}>
113
  <div class="flex justify-end">
114
  <div
115
- class="flex items-center gap-0.5 rounded-md border bg-gray-900 p-0.5 text-sm dark:border-gray-600 dark:bg-gray-800"
116
  {...radioGroup.root}
117
  >
118
  {#each modes as mode}
@@ -120,7 +121,7 @@
120
  <div
121
  class={[
122
  "rounded px-2 py-0.5 capitalize select-none",
123
- item.checked ? " dark:bg-gray-700" : "hover:bg-gray-700/70",
124
  ]}
125
  {...item.attrs}
126
  >
@@ -134,40 +135,46 @@
134
  <div class="fade-y -mx-2 mt-2 -mb-4 max-h-200 space-y-4 overflow-auto px-2 py-4 text-left">
135
  <!-- Top-level properties -->
136
  <div>
137
- <label for="schema-name" class="block text-sm font-medium text-gray-300">Name</label>
138
  <input
139
  type="text"
140
  id="schema-name"
141
- class="mt-1 block w-full rounded-md border-gray-700 bg-gray-800 px-2 py-1 text-white shadow-sm focus:border-blue-500 focus:ring-blue-500"
142
  value={schemaObj.current.name}
143
  {...onchange(value => updateSchema({ name: value }))}
144
  />
145
  </div>
146
 
147
  <div>
148
- <label for="schema-description" class="block text-sm font-medium text-gray-300">Description</label>
 
 
149
  <textarea
150
  id="schema-description"
151
  rows="3"
152
- class="mt-1 block w-full rounded-md border-gray-700 bg-gray-800 px-2 py-1 text-white shadow-sm focus:border-blue-500 focus:ring-blue-500"
153
  value={schemaObj.current.description}
154
  {...onchange(value => updateSchema({ description: value }))}
155
  ></textarea>
156
  </div>
157
 
158
  <!-- Properties Section -->
159
- <div class="border-t border-gray-700 pt-4">
160
- <h3 class="text-lg leading-6 font-medium text-gray-100">Properties</h3>
161
  {#if schemaObj.current.schema?.properties}
162
  <div class="mt-3 space-y-3">
163
  {#each Object.entries(schemaObj.current.schema.properties) as [propertyName, propertyDefinition], index (index)}
164
- <div class="relative space-y-2 rounded-md border border-gray-700 p-3">
 
 
165
  <div>
166
- <label for="{propertyName}-name" class="block text-xs font-medium text-gray-400"> Name </label>
 
 
167
  <input
168
  type="text"
169
  id="{propertyName}-name"
170
- class="mt-1 block w-full rounded-md border-gray-700 bg-gray-800 px-2 py-1 text-sm text-white shadow-sm focus:border-blue-500 focus:ring-blue-500"
171
  value={propertyName}
172
  {...onchange(value => {
173
  const updatedProperties = { ...schemaObj.current.schema?.properties };
@@ -181,7 +188,7 @@
181
 
182
  <button
183
  type="button"
184
- class="absolute top-2 right-2 text-red-400 hover:text-red-500"
185
  onclick={() => {
186
  const updatedProperties = { ...schemaObj.current.schema?.properties };
187
  if (!updatedProperties || !updatedProperties[propertyName]) return;
@@ -194,10 +201,12 @@
194
  </button>
195
 
196
  <div>
197
- <label for="{propertyName}-type" class="block text-xs font-medium text-gray-400">Type</label>
 
 
198
  <select
199
  id="{propertyName}-type"
200
- class="mt-1 block w-full rounded-md border-gray-700 bg-gray-800 px-2 py-1 text-sm text-white shadow-sm focus:border-blue-500 focus:ring-blue-500"
201
  bind:value={
202
  () => propertyDefinition.type,
203
  value => {
@@ -221,13 +230,14 @@
221
  </div>
222
 
223
  <div>
224
- <label for="{propertyName}-description" class="block text-xs font-medium text-gray-400"
225
- >Description</label
 
226
  >
227
  <input
228
  type="text"
229
  id="{propertyName}-description"
230
- class="mt-1 block w-full rounded-md border-gray-700 bg-gray-800 px-2 py-1 text-sm text-white shadow-sm focus:border-blue-500 focus:ring-blue-500"
231
  value={propertyDefinition.description}
232
  {...onchange(value => {
233
  const updatedProperties = { ...schemaObj.current.schema?.properties };
@@ -245,7 +255,7 @@
245
  aria-describedby="required-{propertyName}-description"
246
  name="required-{propertyName}"
247
  type="checkbox"
248
- class="h-4 w-4 rounded border-gray-700 bg-gray-800 text-blue-600 focus:ring-blue-500"
249
  checked={schemaObj.current.schema?.required?.includes(propertyName)}
250
  onchange={e => {
251
  let updatedRequired = [...(schemaObj.current.schema?.required || [])];
@@ -261,7 +271,9 @@
261
  />
262
  </div>
263
  <div class="ml-3 text-sm">
264
- <label for="required-{propertyName}" class="font-medium text-gray-300">Required</label>
 
 
265
  </div>
266
  </div>
267
  </div>
@@ -290,8 +302,8 @@
290
  </div>
291
 
292
  <!-- Strict and Additional Properties -->
293
- <div class="border-t border-gray-700 pt-4">
294
- <h3 class="text-lg leading-6 font-medium text-gray-100">Options</h3>
295
  <div class="mt-3 space-y-2">
296
  <div class="relative flex items-start">
297
  <div class="flex h-5 items-center">
@@ -299,7 +311,7 @@
299
  id="additionalProperties"
300
  name="additionalProperties"
301
  type="checkbox"
302
- class="h-4 w-4 rounded border-gray-700 bg-gray-800 text-blue-600 focus:ring-blue-500"
303
  checked={schemaObj.current.schema?.additionalProperties !== undefined
304
  ? schemaObj.current.schema.additionalProperties
305
  : true}
@@ -307,7 +319,9 @@
307
  />
308
  </div>
309
  <div class="ml-3 text-sm">
310
- <label for="additionalProperties" class="font-medium text-gray-300">Allow additional properties</label>
 
 
311
  <p id="additionalProperties-description" class="text-gray-500">
312
  If unchecked, only properties defined in the schema are allowed.
313
  </p>
@@ -320,13 +334,13 @@
320
  id="strict"
321
  name="strict"
322
  type="checkbox"
323
- class="h-4 w-4 rounded border-gray-700 bg-gray-800 text-blue-600 focus:ring-blue-500"
324
  checked={schemaObj.current.strict !== undefined ? schemaObj.current.strict : false}
325
  onchange={e => updateSchema({ strict: e.currentTarget.checked })}
326
  />
327
  </div>
328
  <div class="ml-3 text-sm">
329
- <label for="strict" class="font-medium text-gray-300">Strict mode</label>
330
  <p id="strict-description" class="text-gray-500">Enforces stricter validation rules.</p>
331
  </div>
332
  </div>
@@ -337,10 +351,10 @@
337
  <!-- inside dialogs its a-ok -->
338
  <!-- svelte-ignore a11y_autofocus -->
339
  <div
340
- class="relative mt-2 max-h-120 overflow-x-clip overflow-y-auto rounded-lg bg-gray-800 text-left ring-gray-100 focus-within:ring-3 dark:ring-gray-600"
341
  >
342
  <div class="shiki-container pointer-events-none absolute inset-0" aria-hidden="true">
343
- {#await codeToHtml(tempSchema, { lang: "json", theme: "catppuccin-macchiato" })}
344
  <!-- nothing -->
345
  {:then rendered}
346
  {@html rendered}
@@ -354,13 +368,13 @@
354
  conversation.update({ structuredOutput: { ...conversation.data.structuredOutput, schema: v } });
355
  })}
356
  {...oninput(v => (tempSchema = v))}
357
- class="relative z-10 h-120 w-full resize-none overflow-hidden rounded-lg bg-transparent whitespace-pre-wrap text-transparent caret-white outline-none @2xl:px-3"
358
  ></textarea>
359
  </div>
360
  {/if}
361
 
362
  {#snippet footer()}
363
- <button class="btn ml-auto" onclick={() => (open = false)}>Save</button>
364
  {/snippet}
365
  </Dialog>
366
 
 
10
  import typia from "typia";
11
  import IconX from "~icons/carbon/close";
12
  import Dialog from "../dialog.svelte";
13
+ import { isDark } from "$lib/spells/is-dark.svelte";
14
 
15
  interface Props {
16
  conversation: ConversationClass;
 
113
  <Dialog title="Edit Structured Output" {open} onClose={() => (open = false)}>
114
  <div class="flex justify-end">
115
  <div
116
+ class="flex items-center gap-0.5 rounded-md border border-gray-300 bg-white p-0.5 text-sm dark:border-gray-600 dark:bg-gray-800"
117
  {...radioGroup.root}
118
  >
119
  {#each modes as mode}
 
121
  <div
122
  class={[
123
  "rounded px-2 py-0.5 capitalize select-none",
124
+ item.checked ? "bg-gray-200 dark:bg-gray-700" : "hover:bg-gray-100 dark:hover:bg-gray-700/70",
125
  ]}
126
  {...item.attrs}
127
  >
 
135
  <div class="fade-y -mx-2 mt-2 -mb-4 max-h-200 space-y-4 overflow-auto px-2 py-4 text-left">
136
  <!-- Top-level properties -->
137
  <div>
138
+ <label for="schema-name" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Name</label>
139
  <input
140
  type="text"
141
  id="schema-name"
142
+ class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-gray-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
143
  value={schemaObj.current.name}
144
  {...onchange(value => updateSchema({ name: value }))}
145
  />
146
  </div>
147
 
148
  <div>
149
+ <label for="schema-description" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
150
+ Description
151
+ </label>
152
  <textarea
153
  id="schema-description"
154
  rows="3"
155
+ class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-gray-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
156
  value={schemaObj.current.description}
157
  {...onchange(value => updateSchema({ description: value }))}
158
  ></textarea>
159
  </div>
160
 
161
  <!-- Properties Section -->
162
+ <div class="border-t border-gray-200 pt-4 dark:border-gray-700">
163
+ <h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-gray-100">Properties</h3>
164
  {#if schemaObj.current.schema?.properties}
165
  <div class="mt-3 space-y-3">
166
  {#each Object.entries(schemaObj.current.schema.properties) as [propertyName, propertyDefinition], index (index)}
167
+ <div
168
+ class="relative space-y-2 rounded-md border border-gray-300 bg-white p-3 dark:border-gray-700 dark:bg-gray-900"
169
+ >
170
  <div>
171
+ <label for="{propertyName}-name" class="block text-xs font-medium text-gray-500 dark:text-gray-400">
172
+ Name
173
+ </label>
174
  <input
175
  type="text"
176
  id="{propertyName}-name"
177
+ class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-sm text-gray-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
178
  value={propertyName}
179
  {...onchange(value => {
180
  const updatedProperties = { ...schemaObj.current.schema?.properties };
 
188
 
189
  <button
190
  type="button"
191
+ class="absolute top-2 right-2 text-red-500 hover:text-red-600 dark:text-red-400 dark:hover:text-red-500"
192
  onclick={() => {
193
  const updatedProperties = { ...schemaObj.current.schema?.properties };
194
  if (!updatedProperties || !updatedProperties[propertyName]) return;
 
201
  </button>
202
 
203
  <div>
204
+ <label for="{propertyName}-type" class="block text-xs font-medium text-gray-500 dark:text-gray-400">
205
+ Type
206
+ </label>
207
  <select
208
  id="{propertyName}-type"
209
+ class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-sm text-gray-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
210
  bind:value={
211
  () => propertyDefinition.type,
212
  value => {
 
230
  </div>
231
 
232
  <div>
233
+ <label
234
+ for="{propertyName}-description"
235
+ class="block text-xs font-medium text-gray-500 dark:text-gray-400">Description</label
236
  >
237
  <input
238
  type="text"
239
  id="{propertyName}-description"
240
+ class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-sm text-gray-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
241
  value={propertyDefinition.description}
242
  {...onchange(value => {
243
  const updatedProperties = { ...schemaObj.current.schema?.properties };
 
255
  aria-describedby="required-{propertyName}-description"
256
  name="required-{propertyName}"
257
  type="checkbox"
258
+ class="h-4 w-4 rounded border border-gray-300 bg-white text-blue-600 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800"
259
  checked={schemaObj.current.schema?.required?.includes(propertyName)}
260
  onchange={e => {
261
  let updatedRequired = [...(schemaObj.current.schema?.required || [])];
 
271
  />
272
  </div>
273
  <div class="ml-3 text-sm">
274
+ <label for="required-{propertyName}" class="font-medium text-gray-700 dark:text-gray-300">
275
+ Required
276
+ </label>
277
  </div>
278
  </div>
279
  </div>
 
302
  </div>
303
 
304
  <!-- Strict and Additional Properties -->
305
+ <div class="border-t border-gray-200 pt-4 dark:border-gray-700">
306
+ <h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-gray-100">Options</h3>
307
  <div class="mt-3 space-y-2">
308
  <div class="relative flex items-start">
309
  <div class="flex h-5 items-center">
 
311
  id="additionalProperties"
312
  name="additionalProperties"
313
  type="checkbox"
314
+ class="h-4 w-4 rounded border border-gray-300 bg-white text-blue-600 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800"
315
  checked={schemaObj.current.schema?.additionalProperties !== undefined
316
  ? schemaObj.current.schema.additionalProperties
317
  : true}
 
319
  />
320
  </div>
321
  <div class="ml-3 text-sm">
322
+ <label for="additionalProperties" class="font-medium text-gray-700 dark:text-gray-300">
323
+ Allow additional properties
324
+ </label>
325
  <p id="additionalProperties-description" class="text-gray-500">
326
  If unchecked, only properties defined in the schema are allowed.
327
  </p>
 
334
  id="strict"
335
  name="strict"
336
  type="checkbox"
337
+ class="h-4 w-4 rounded border border-gray-300 bg-white text-blue-600 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800"
338
  checked={schemaObj.current.strict !== undefined ? schemaObj.current.strict : false}
339
  onchange={e => updateSchema({ strict: e.currentTarget.checked })}
340
  />
341
  </div>
342
  <div class="ml-3 text-sm">
343
+ <label for="strict" class="font-medium text-gray-700 dark:text-gray-300">Strict mode</label>
344
  <p id="strict-description" class="text-gray-500">Enforces stricter validation rules.</p>
345
  </div>
346
  </div>
 
351
  <!-- inside dialogs its a-ok -->
352
  <!-- svelte-ignore a11y_autofocus -->
353
  <div
354
+ class="relative mt-2 max-h-120 overflow-x-clip overflow-y-auto rounded-lg bg-gray-100 text-left ring-gray-100 focus-within:ring-3 dark:bg-gray-800 dark:ring-gray-600"
355
  >
356
  <div class="shiki-container pointer-events-none absolute inset-0" aria-hidden="true">
357
+ {#await codeToHtml(tempSchema, { lang: "json", theme: isDark() ? "catppuccin-macchiato" : "catppuccin-latte" })}
358
  <!-- nothing -->
359
  {:then rendered}
360
  {@html rendered}
 
368
  conversation.update({ structuredOutput: { ...conversation.data.structuredOutput, schema: v } });
369
  })}
370
  {...oninput(v => (tempSchema = v))}
371
+ class="relative z-10 h-120 w-full resize-none overflow-hidden rounded-lg bg-transparent whitespace-pre-wrap text-transparent caret-black outline-none @2xl:px-3 dark:caret-white"
372
  ></textarea>
373
  </div>
374
  {/if}
375
 
376
  {#snippet footer()}
377
+ <button class="btn ml-auto" onclick={() => (open = false)}> Save </button>
378
  {/snippet}
379
  </Dialog>
380
 
src/lib/spells/is-dark.svelte.ts ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { createSubscriber } from "svelte/reactivity";
2
+
3
+ const subscribe = createSubscriber(update => {
4
+ const mutationObserver = new MutationObserver(entries => {
5
+ for (const entry of entries) {
6
+ if (entry.type === "attributes" && entry.attributeName === "class") {
7
+ update();
8
+ }
9
+ }
10
+ });
11
+ mutationObserver.observe(document.body, { attributes: true });
12
+
13
+ return () => {
14
+ mutationObserver.disconnect();
15
+ };
16
+ });
17
+
18
+ export function isDark() {
19
+ subscribe();
20
+ return document.body.classList.contains("dark");
21
+ }