enzostvs HF Staff commited on
Commit
9e99f25
·
1 Parent(s): f454591

wip dark mode

Browse files
src/lib/components/chat/Assistant.svelte CHANGED
@@ -15,10 +15,10 @@
15
 
16
  let selectedModels = $derived(nodeData.current?.data.selectedModels as ChatModel[] ?? []);
17
  let loading = $derived(nodeData.current?.data.loading as boolean ?? false);
18
- let message = $derived(nodeData.current?.data.content ? { role: 'assistant', content: nodeData.current?.data.content } as ChatMessage : null);
19
  </script>
20
 
21
- <article class="bg-white border border-gray-200 shadow-lg/5 p-5 w-[600px] rounded-3xl">
22
  <div class="nodrag">
23
  <header class="flex items-center justify-between mb-3">
24
  <div class="flex items-center gap-1 flex-wrap">
 
15
 
16
  let selectedModels = $derived(nodeData.current?.data.selectedModels as ChatModel[] ?? []);
17
  let loading = $derived(nodeData.current?.data.loading as boolean ?? false);
18
+ let message = $derived(nodeData.current?.data.content ? { role: 'assistant', content: nodeData.current?.data.content, timestamp: nodeData.current?.data.timestamp as number ?? 0 } as ChatMessage : null);
19
  </script>
20
 
21
+ <article class="bg-background border border-border shadow-lg/5 p-5 w-[600px] rounded-3xl">
22
  <div class="nodrag">
23
  <header class="flex items-center justify-between mb-3">
24
  <div class="flex items-center gap-1 flex-wrap">
src/lib/components/chat/Message.svelte CHANGED
@@ -34,10 +34,11 @@
34
  </p>
35
  {:else}
36
  <SvelteMarkdown source={message.content} renderers={renderers as any} />
 
 
 
 
 
 
37
  {/if}
38
- </main>
39
- <!-- {#if message.timestamp}
40
- <p class="text-[10px] text-muted-foreground bg-muted px-2 py-1 rounded-md font-mono">
41
- {message.timestamp / 1000}s
42
- </p>
43
- {/if} -->
 
34
  </p>
35
  {:else}
36
  <SvelteMarkdown source={message.content} renderers={renderers as any} />
37
+ {#if message.timestamp}
38
+ <p class="text-xs text-muted-foreground/70">
39
+ - Generated in
40
+ {message.timestamp / 1000}s
41
+ </p>
42
+ {/if}
43
  {/if}
44
+ </main>
 
 
 
 
 
src/lib/components/chat/User.svelte CHANGED
@@ -1,6 +1,7 @@
1
  <script lang="ts">
2
  import { Send, X } from '@lucide/svelte';
3
  import { Handle, useEdges, useNodes, useNodesData, Position, type NodeProps, type Edge , type Node, useSvelteFlow} from '@xyflow/svelte';
 
4
 
5
  import type { ChatModel, ChatMessage } from '$lib/helpers/types';
6
  import { Button } from '$lib/components/ui/button';
@@ -25,19 +26,22 @@
25
  function addModel(model: ChatModel) {
26
  if (!selectedModels.some((m) => m.id === model.id)) {
27
  selectedModels = [...selectedModels, model];
 
 
 
28
  }
29
  }
30
  function removeModel(model: ChatModel) {
31
  selectedModels = selectedModels.filter((m) => m.id !== model.id);
32
  }
33
 
34
- function handleTriggerAction() {
35
  const newNodes: Node[] = [];
36
  const newEdges: Edge[] = [];
37
  messages = [...messages, { role: 'user', content: prompt }];
38
  updateNodeData(id, { messages }, { replace: true });
39
 
40
- selectedModels.forEach((m) => {
41
  const newNodeId = `assistant-${crypto.randomUUID()}`;
42
  const newNode: Node = {
43
  id: newNodeId,
@@ -73,11 +77,11 @@
73
  }
74
 
75
  async function handleTriggerAiCall(newNodes: Node[]) {
76
- const start = Date.now();
77
  newNodes.forEach(async (node) => {
78
  const model = (node?.data?.selectedModels as ChatModel[])?.length > 0 ? (node?.data?.selectedModels as ChatModel[])[0] : null;
79
  if (!model) return;
80
  try {
 
81
  const response = await fetch('/api', {
82
  method: 'POST',
83
  body: JSON.stringify({
@@ -117,6 +121,8 @@
117
  }
118
  updateNodes((currentNodes) => [...currentNodes, newNode]);
119
  updateEdges((currentEdges) => [...currentEdges, newEdge]);
 
 
120
  break;
121
  }
122
 
@@ -134,7 +140,7 @@
134
  let lastMessage = $derived(messages?.length > 0 && messages[messages.length - 1].role === 'user' ? messages[messages.length - 1] : null);
135
  </script>
136
 
137
- <article class="bg-white border border-gray-200 shadow-lg/5 p-5 w-[600px] rounded-3xl">
138
  <div class="nodrag">
139
  <header class="flex items-center justify-between mb-3">
140
  <div class="flex items-center gap-1 flex-wrap">
@@ -149,7 +155,7 @@
149
  {/if}
150
  </Button>
151
  {/each}
152
- {#if selectedModels.length < 3 && !loading && !lastMessage}
153
  <ComboBoxModels
154
  onSelect={addModel}
155
  excludeIds={selectedModels.map((m) => m.id)}
@@ -178,7 +184,7 @@
178
  }
179
  }}
180
  ></textarea>
181
- <Button variant="outline" size="icon-sm" class="" disabled={!selectedModels.length || !prompt || loading} onclick={handleTriggerAction}>
182
  {#if loading}
183
  <Spinner className="size-5"/>
184
  {:else}
 
1
  <script lang="ts">
2
  import { Send, X } from '@lucide/svelte';
3
  import { Handle, useEdges, useNodes, useNodesData, Position, type NodeProps, type Edge , type Node, useSvelteFlow} from '@xyflow/svelte';
4
+ import { mode } from 'mode-watcher';
5
 
6
  import type { ChatModel, ChatMessage } from '$lib/helpers/types';
7
  import { Button } from '$lib/components/ui/button';
 
26
  function addModel(model: ChatModel) {
27
  if (!selectedModels.some((m) => m.id === model.id)) {
28
  selectedModels = [...selectedModels, model];
29
+ if (lastMessage) {
30
+ handleTriggerAction([model]);
31
+ }
32
  }
33
  }
34
  function removeModel(model: ChatModel) {
35
  selectedModels = selectedModels.filter((m) => m.id !== model.id);
36
  }
37
 
38
+ function handleTriggerAction(models: ChatModel[] = selectedModels) {
39
  const newNodes: Node[] = [];
40
  const newEdges: Edge[] = [];
41
  messages = [...messages, { role: 'user', content: prompt }];
42
  updateNodeData(id, { messages }, { replace: true });
43
 
44
+ models.forEach((m) => {
45
  const newNodeId = `assistant-${crypto.randomUUID()}`;
46
  const newNode: Node = {
47
  id: newNodeId,
 
77
  }
78
 
79
  async function handleTriggerAiCall(newNodes: Node[]) {
 
80
  newNodes.forEach(async (node) => {
81
  const model = (node?.data?.selectedModels as ChatModel[])?.length > 0 ? (node?.data?.selectedModels as ChatModel[])[0] : null;
82
  if (!model) return;
83
  try {
84
+ const start = Date.now();
85
  const response = await fetch('/api', {
86
  method: 'POST',
87
  body: JSON.stringify({
 
121
  }
122
  updateNodes((currentNodes) => [...currentNodes, newNode]);
123
  updateEdges((currentEdges) => [...currentEdges, newEdge]);
124
+ const end = Date.now();
125
+ updateNodeData(node.id, { ...node.data, content, timestamp: end - start, loading: false }, { replace: true });
126
  break;
127
  }
128
 
 
140
  let lastMessage = $derived(messages?.length > 0 && messages[messages.length - 1].role === 'user' ? messages[messages.length - 1] : null);
141
  </script>
142
 
143
+ <article class="bg-background border border-border shadow-lg/5 p-5 w-[600px] rounded-3xl">
144
  <div class="nodrag">
145
  <header class="flex items-center justify-between mb-3">
146
  <div class="flex items-center gap-1 flex-wrap">
 
155
  {/if}
156
  </Button>
157
  {/each}
158
+ {#if selectedModels.length < 3 && !loading}
159
  <ComboBoxModels
160
  onSelect={addModel}
161
  excludeIds={selectedModels.map((m) => m.id)}
 
184
  }
185
  }}
186
  ></textarea>
187
+ <Button variant={mode.current === 'dark' ? 'default' : 'outline'} size="icon-sm" class="" disabled={!selectedModels.length || !prompt || loading} onclick={() => handleTriggerAction()}>
188
  {#if loading}
189
  <Spinner className="size-5"/>
190
  {:else}
src/lib/components/chat/markdown/Heading.svelte CHANGED
@@ -4,11 +4,11 @@
4
  </script>
5
 
6
  {#if depth === 1}
7
- <h1 class="text-xl font-semibold text-foreground mt-4 mb-2 first:mt-0">{@render children?.()}</h1>
8
  {:else if depth === 2}
9
- <h2 class="text-lg font-semibold text-foreground mt-3.5 mb-2 first:mt-0">{@render children?.()}</h2>
10
  {:else if depth === 3}
11
- <h3 class="text-base font-semibold text-foreground mt-3 mb-1.5 first:mt-0">{@render children?.()}</h3>
12
  {:else}
13
- <h4 class="text-sm font-semibold text-foreground mt-2.5 mb-1 first:mt-0">{@render children?.()}</h4>
14
  {/if}
 
4
  </script>
5
 
6
  {#if depth === 1}
7
+ <h1 class="text-2xl font-semibold text-foreground mt-4 mb-2 first:mt-0">{@render children?.()}</h1>
8
  {:else if depth === 2}
9
+ <h2 class="text-xl font-semibold text-foreground mt-3.5 mb-2 first:mt-0">{@render children?.()}</h2>
10
  {:else if depth === 3}
11
+ <h3 class="text-lg font-semibold text-foreground mt-3 mb-1.5 first:mt-0">{@render children?.()}</h3>
12
  {:else}
13
+ <h4 class="text-base font-semibold text-foreground mt-2.5 mb-1 first:mt-0">{@render children?.()}</h4>
14
  {/if}
src/lib/components/chat/markdown/List.svelte CHANGED
@@ -4,11 +4,11 @@
4
  </script>
5
 
6
  {#if ordered}
7
- <ol class="list-decimal list-outside pl-5 my-2 space-y-1 text-sm text-foreground/90 marker:text-muted-foreground" {start}>
8
  {@render children?.()}
9
  </ol>
10
  {:else}
11
- <ul class="list-disc list-outside pl-5 my-2 space-y-1 text-sm text-foreground/90 marker:text-muted-foreground">
12
  {@render children?.()}
13
  </ul>
14
  {/if}
 
4
  </script>
5
 
6
  {#if ordered}
7
+ <ol class="list-decimal list-outside pl-5 my-2 space-y-1 text-base text-foreground/90 marker:text-muted-foreground" {start}>
8
  {@render children?.()}
9
  </ol>
10
  {:else}
11
+ <ul class="list-disc list-outside pl-5 my-2 space-y-1 text-base text-foreground/90 marker:text-muted-foreground">
12
  {@render children?.()}
13
  </ul>
14
  {/if}
src/lib/components/chat/markdown/Paragraph.svelte CHANGED
@@ -3,4 +3,4 @@
3
  let { children }: { children?: Snippet } = $props();
4
  </script>
5
 
6
- <p class="text-sm leading-relaxed text-foreground/90 mb-3 last:mb-0">{@render children?.()}</p>
 
3
  let { children }: { children?: Snippet } = $props();
4
  </script>
5
 
6
+ <p class="text-base leading-relaxed text-foreground/90 mb-3 last:mb-0">{@render children?.()}</p>
src/lib/components/flow/actions/PanelRightActions.svelte CHANGED
@@ -1,6 +1,7 @@
1
  <script lang="ts">
2
- import { Plus, Contrast } from '@lucide/svelte';
3
  import { Panel } from '@xyflow/svelte';
 
4
 
5
  import { Button } from '$lib/components/ui/button';
6
 
@@ -10,13 +11,21 @@
10
  function handleReset() {
11
  const ok = confirm('Are you sure you want to reset the flow?');
12
  if (ok) {
13
- onReset();
14
  }
15
  }
16
  </script>
17
 
18
  <Panel position="top-right" class="p-3 flex items-center justify-end gap-2">
19
  <Button variant="outline" size="icon" class="" onclick={handleReset}>
20
- <Plus />
 
 
 
 
 
 
 
 
21
  </Button>
22
  </Panel>
 
1
  <script lang="ts">
2
+ import { Cog, Contrast, RefreshCcw } from '@lucide/svelte';
3
  import { Panel } from '@xyflow/svelte';
4
+ import { toggleMode } from 'mode-watcher';
5
 
6
  import { Button } from '$lib/components/ui/button';
7
 
 
11
  function handleReset() {
12
  const ok = confirm('Are you sure you want to reset the flow?');
13
  if (ok) {
14
+ location.reload();
15
  }
16
  }
17
  </script>
18
 
19
  <Panel position="top-right" class="p-3 flex items-center justify-end gap-2">
20
  <Button variant="outline" size="icon" class="" onclick={handleReset}>
21
+ <RefreshCcw />
22
+ </Button>
23
+ <Button variant="outline" size="icon" class="" onclick={() => toggleMode()}>
24
+ <Contrast />
25
+ </Button>
26
+ <Button variant="outline" size="icon" class="" onclick={() => {
27
+ alert("Coming soon...")
28
+ }}>
29
+ <Cog />
30
  </Button>
31
  </Panel>
src/routes/+layout.svelte CHANGED
@@ -34,7 +34,7 @@
34
  {#if modelsState.loading}
35
  <MainLoading />
36
  {:else}
37
- {@render children?.()}
38
  {/if}
39
  </div>
40
  </svelte:boundary>
 
34
  {#if modelsState.loading}
35
  <MainLoading />
36
  {:else}
37
+ {@render children?.()}
38
  {/if}
39
  </div>
40
  </svelte:boundary>
src/routes/+page.svelte CHANGED
@@ -1,7 +1,8 @@
1
  <script lang="ts">
2
- import { SvelteFlow, Background, MiniMap, Panel, BackgroundVariant, type Node, type Edge } from '@xyflow/svelte';
3
  import '@xyflow/svelte/dist/style.css';
4
-
 
5
  import { modelsState } from '$lib/state/models.svelte';
6
  import User from '$lib/components/chat/User.svelte';
7
  import Assistant from '$lib/components/chat/Assistant.svelte';
@@ -39,6 +40,7 @@
39
  minZoom={0.8}
40
  maxZoom={1.5}
41
  fitView
 
42
  proOptions={{ hideAttribution: true }}
43
  fitViewOptions={{
44
  maxZoom: 1,
@@ -46,12 +48,24 @@
46
  interpolate: "smooth",
47
  duration: 500,
48
  }}
49
- defaultEdgeOptions={{ type: 'smoothstep', animated: true }}
50
- class="bg-white!"
 
51
  >
52
  <FitViewOnResize initialNodes={initialNodes} />
53
- <MiniMap />
54
- <Background variant={BackgroundVariant.Lines} gap={30} patternColor="rgba(0, 0, 0, 0.04)" />
 
 
 
 
 
 
 
 
 
 
 
55
  <PanelRightActions
56
  onReset={() => {
57
  nodes = getInitialNodes();
 
1
  <script lang="ts">
2
+ import { SvelteFlow, Background, MiniMap, Panel, BackgroundVariant, type Node, type Edge, type ColorMode } from '@xyflow/svelte';
3
  import '@xyflow/svelte/dist/style.css';
4
+ import { theme, mode } from 'mode-watcher';
5
+
6
  import { modelsState } from '$lib/state/models.svelte';
7
  import User from '$lib/components/chat/User.svelte';
8
  import Assistant from '$lib/components/chat/Assistant.svelte';
 
40
  minZoom={0.8}
41
  maxZoom={1.5}
42
  fitView
43
+ colorMode={mode.current}
44
  proOptions={{ hideAttribution: true }}
45
  fitViewOptions={{
46
  maxZoom: 1,
 
48
  interpolate: "smooth",
49
  duration: 500,
50
  }}
51
+ defaultEdgeOptions={{ type: "bezier" }}
52
+ class="bg-background!"
53
+
54
  >
55
  <FitViewOnResize initialNodes={initialNodes} />
56
+ <MiniMap
57
+ nodeColor={mode.current === 'dark' ? 'rgba(255, 255, 255, 0.07)' : 'rgba(0, 0, 0, 0.07)'}
58
+ maskColor={mode.current === 'dark' ? 'rgba(255, 255, 255, 0.07)' : 'rgba(0, 0, 0, 0.05)'}
59
+ class="rounded-xl! dark:bg-gray-950! overflow-hidden!"
60
+ />
61
+ <Background
62
+ variant={BackgroundVariant.Lines}
63
+ gap={30}
64
+ patternColor={
65
+ mode.current === 'dark' ? 'rgba(255, 255, 255, 0.04)' : 'rgba(0, 0, 0, 0.04)'
66
+ }
67
+ class="bg-background!"
68
+ />
69
  <PanelRightActions
70
  onReset={() => {
71
  nodes = getInitialNodes();
src/routes/api/+server.ts CHANGED
@@ -15,7 +15,7 @@ export async function POST({ request }: RequestEvent) {
15
  const stream = client.chatCompletionStream({
16
  model: model,
17
  messages: [
18
- { role: 'system', content: 'You are a helpful assistant. You are very helpful and friendly. Use markdown to format your responses.' },
19
  ...(messages ?? []),
20
  { role: 'user', content: prompt }
21
  ],
 
15
  const stream = client.chatCompletionStream({
16
  model: model,
17
  messages: [
18
+ { role: 'system', content: 'You are a helpful assistant. You are very helpful and friendly. Use markdown to format your responses, but don\'t include array start and end markers.' },
19
  ...(messages ?? []),
20
  { role: 'user', content: prompt }
21
  ],
src/routes/layout.css CHANGED
@@ -119,3 +119,7 @@
119
  @apply bg-background text-foreground;
120
  }
121
  }
 
 
 
 
 
119
  @apply bg-background text-foreground;
120
  }
121
  }
122
+
123
+ .dark .svelte-flow__edge-path {
124
+ @apply stroke-gray-800;
125
+ }