diff --git a/docs/content/docs/2.components/chat-reasoning.md b/docs/content/docs/2.components/chat-reasoning.md new file mode 100644 index 0000000000..891510bf7f --- /dev/null +++ b/docs/content/docs/2.components/chat-reasoning.md @@ -0,0 +1,12 @@ +--- +description: A collapsible component to display AI reasoning or thinking process. +category: data +links: + - label: GitHub + icon: i-simple-icons-github + to: https://github.com/nuxt/ui/blob/v4/src/runtime/components/ChatReasoning.vue +--- + +::callout{icon="i-lucide-construction" to="/getting-started/roadmap"} +This page is a work in progress. +:: diff --git a/docs/content/docs/2.components/chat-shimmer.md b/docs/content/docs/2.components/chat-shimmer.md new file mode 100644 index 0000000000..0f66656585 --- /dev/null +++ b/docs/content/docs/2.components/chat-shimmer.md @@ -0,0 +1,12 @@ +--- +description: A text component with an animated shimmer effect. +category: element +links: + - label: GitHub + icon: i-simple-icons-github + to: https://github.com/nuxt/ui/blob/v4/src/runtime/components/ChatShimmer.vue +--- + +::callout{icon="i-lucide-construction" to="/getting-started/roadmap"} +This page is a work in progress. +:: diff --git a/docs/public/components/dark/chat-reasoning.png b/docs/public/components/dark/chat-reasoning.png new file mode 100644 index 0000000000..37304d6aad Binary files /dev/null and b/docs/public/components/dark/chat-reasoning.png differ diff --git a/docs/public/components/dark/chat-shimmer.png b/docs/public/components/dark/chat-shimmer.png new file mode 100644 index 0000000000..905d8d2a15 Binary files /dev/null and b/docs/public/components/dark/chat-shimmer.png differ diff --git a/docs/public/components/light/chat-reasoning.png b/docs/public/components/light/chat-reasoning.png new file mode 100644 index 0000000000..1a15968bb8 Binary files /dev/null and b/docs/public/components/light/chat-reasoning.png differ diff --git a/docs/public/components/light/chat-shimmer.png b/docs/public/components/light/chat-shimmer.png new file mode 100644 index 0000000000..c7a0125ecf Binary files /dev/null and b/docs/public/components/light/chat-shimmer.png differ diff --git a/playgrounds/nuxt/app/app.vue b/playgrounds/nuxt/app/app.vue index 2e635104d3..90336f644c 100644 --- a/playgrounds/nuxt/app/app.vue +++ b/playgrounds/nuxt/app/app.vue @@ -54,8 +54,9 @@ provide('components', components) import type { UIMessage } from 'ai' import { Chat } from '@ai-sdk/vue' +import { DefaultChatTransport } from 'ai' const toast = useToast() +const appConfig = useAppConfig() -const messages: UIMessage[] = [{ - id: '1', - role: 'user', - parts: [{ type: 'text', text: 'Hello, how are you?' }] -}, { - id: '2', - role: 'assistant', - parts: [{ type: 'text', text: 'I\'m good, thank you! How can I help you today?' }] -}] -const input = ref('') +const mode = ref<'live' | 'mock'>('mock') -const chat = new Chat({ - messages, - onError(error) { - const { message: description } = typeof error.message === 'string' && error.message[0] === '{' ? JSON.parse(error.message) : error - - toast.add({ - description, - icon: 'i-lucide-alert-circle', - color: 'error', - duration: 0 - }) +const initialMockMessages: UIMessage[] = [ + { + id: 'msg-1', + role: 'user', + parts: [{ type: 'text', text: 'Can you explain how neural networks work?' }] + }, + { + id: 'msg-2', + role: 'assistant', + parts: [ + { + type: 'reasoning', + text: 'The user is asking about neural networks. Let me break this down:\n\n1. **Start with basics** - neurons, layers, weights\n2. **Use analogies** - compare to biological neurons\n3. **Provide examples** - show practical applications\n\nI should keep it accessible while being technically accurate.', + state: 'done' + }, + { + type: 'text', + text: 'Neural networks are computing systems inspired by biological neural networks in the brain.\n\n**Key concepts:**\n\n1. **Neurons** - Basic units that receive inputs and produce outputs\n2. **Layers** - Groups of neurons (input, hidden, output)\n3. **Weights** - Connection strengths between neurons\n4. **Activation functions** - Determine if a neuron should fire' + } + ] } -}) +] -function onSubmit() { - chat.sendMessage({ text: input.value }) +const mockChat = shallowRef(createMockChat()) +const liveChat = shallowRef(createLiveChat()) + +function createMockChat(messages: UIMessage[] = initialMockMessages) { + return new Chat({ + id: `mock-${Date.now()}`, + messages, + transport: new DefaultChatTransport({ + api: '/api/chat-mock' + }), + onError(error) { + console.error('Mock chat error:', error) + } + }) +} + +function createLiveChat() { + return new Chat({ + id: `live-${Date.now()}`, + onFinish() { + console.log('Live chat finished') + console.log(liveChat.value.messages) + }, + onError(error) { + const { message: description } = typeof error.message === 'string' && error.message[0] === '{' ? JSON.parse(error.message) : error + toast.add({ + description, + icon: appConfig.ui.icons.error, + color: 'error', + duration: 0 + }) + } + }) +} + +const input = ref('') +const chat = computed(() => mode.value === 'live' ? liveChat.value : mockChat.value) +const messages = computed(() => chat.value.messages) +const status = computed(() => chat.value.status) + +function onSubmit() { + if (!input.value.trim()) return + chat.value.sendMessage({ text: input.value }) input.value = '' } + +function handleStop() { + chat.value.stop() +} + +function handleReload() { + chat.value.regenerate() +} + +function clearMessages() { + if (mode.value === 'mock') { + mockChat.value = createMockChat([]) + } else { + liveChat.value = createLiveChat() + } +} + +function addUserMessage() { + mockChat.value = createMockChat([ + ...mockChat.value.messages, + { + id: `msg-${Date.now()}`, + role: 'user', + parts: [{ type: 'text', text: 'This is a test user message.' }] + } + ]) +} + +function addAssistantMessage() { + mockChat.value = createMockChat([ + ...mockChat.value.messages, + { + id: `msg-${Date.now()}`, + role: 'assistant', + parts: [ + { + type: 'reasoning', + text: 'Processing the request...\n\n- Analyzing the context\n- Formulating a response\n- Checking for accuracy', + state: 'done' + }, + { + type: 'text', + text: 'This is a test assistant response with **markdown** support.' + } + ] + } + ]) +} + +const mockActions = [ + { label: 'Simulate Stream', icon: 'i-lucide-play', onClick: () => chat.value.sendMessage({ text: 'Test streaming' }) }, + { label: 'Add User Message', icon: 'i-lucide-user', onClick: addUserMessage }, + { label: 'Add Assistant Message', icon: 'i-lucide-bot', onClick: addAssistantMessage }, + { type: 'separator' as const }, + { label: 'Clear All', icon: 'i-lucide-trash-2', onClick: clearMessages } +] + +const messageActions = [ + { icon: 'i-lucide-copy', label: 'Copy', onClick: () => toast.add({ title: 'Copied!' }) }, + { icon: 'i-lucide-thumbs-up', label: 'Like' }, + { icon: 'i-lucide-thumbs-down', label: 'Dislike' }, + { icon: 'i-lucide-rotate-ccw', label: 'Regenerate' } +] diff --git a/playgrounds/nuxt/app/pages/components/chat-shimmer.vue b/playgrounds/nuxt/app/pages/components/chat-shimmer.vue new file mode 100644 index 0000000000..750a678597 --- /dev/null +++ b/playgrounds/nuxt/app/pages/components/chat-shimmer.vue @@ -0,0 +1,45 @@ + + + diff --git a/playgrounds/nuxt/server/api/chat-mock.post.ts b/playgrounds/nuxt/server/api/chat-mock.post.ts new file mode 100644 index 0000000000..5c2a4be895 --- /dev/null +++ b/playgrounds/nuxt/server/api/chat-mock.post.ts @@ -0,0 +1,81 @@ +import { simulateReadableStream } from 'ai' + +export default defineEventHandler(async () => { + return new Response( + simulateReadableStream({ + initialDelayInMs: 500, + chunkDelayInMs: 80, + chunks: [ + `data: {"type":"start","messageId":"msg-${Date.now()}"}\n\n`, + `data: {"type":"reasoning-start","id":"reasoning-1"}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"Let me "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"think about "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"this carefully...\\n\\n"}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"The user "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"is asking "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"a question "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"that requires "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"some context. "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"I should first "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"understand what "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"they're looking for, "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"then provide "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"a clear explanation.\\n\\n"}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"I'll need to "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"consider the "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"technical aspects "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"while keeping "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"it accessible. "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"Maybe I should "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"include some "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"examples to "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"make it clearer.\\n\\n"}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"Ok, I think "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"I have a good "}\n\n`, + `data: {"type":"reasoning-delta","id":"reasoning-1","delta":"approach now."}\n\n`, + `data: {"type":"reasoning-end","id":"reasoning-1"}\n\n`, + `data: {"type":"text-start","id":"text-1"}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"## Simulated "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"Streaming Response\\n\\n"}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"This is a "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"**simulated** streaming "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"response using "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"the AI SDK's "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"\`simulateReadableStream\` "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"utility.\\n\\n"}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"## Features "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"Demonstrated\\n\\n"}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"1. **Reasoning blocks** "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"- Shows the AI's "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"thinking process\\n"}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"2. **Text streaming** "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"- Progressive content "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"delivery\\n"}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"3. **Markdown rendering** "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"- Rich text formatting\\n\\n"}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"## Code Example\\n\\n"}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"\`\`\`typescript\\n"}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"const response = "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"await chat"}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":".sendMessage("}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"{ text: 'Hello!' })"}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"\\n\`\`\`\\n\\n"}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"> **Note:** This "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"is a mock response "}\n\n`, + `data: {"type":"text-delta","id":"text-1","delta":"for testing purposes."}\n\n`, + `data: {"type":"text-end","id":"text-1"}\n\n`, + `data: {"type":"finish"}\n\n`, + `data: [DONE]\n\n` + ] + }).pipeThrough(new TextEncoderStream()), + { + status: 200, + headers: { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + 'x-vercel-ai-ui-message-stream': 'v1' + } + } + ) +}) diff --git a/playgrounds/nuxt/server/api/chat.post.ts b/playgrounds/nuxt/server/api/chat.post.ts index 638db990d1..23d808d71c 100644 --- a/playgrounds/nuxt/server/api/chat.post.ts +++ b/playgrounds/nuxt/server/api/chat.post.ts @@ -5,7 +5,7 @@ export default defineEventHandler(async (event) => { const { messages } = await readBody(event) return streamText({ - model: gateway('openai/gpt-4o-mini'), + model: gateway('google/gemini-2.5-flash'), maxOutputTokens: 10000, system: 'You are a helpful assistant for Nuxt UI, a UI library for Nuxt and Vue.', messages: await convertToModelMessages(messages), @@ -13,7 +13,15 @@ export default defineEventHandler(async (event) => { openai: { reasoningEffort: 'low', reasoningSummary: 'detailed' + }, + google: { + thinkingConfig: { + includeThoughts: true, + thinkingBudget: 2048 + } } } - }).toUIMessageStreamResponse() + }).toUIMessageStreamResponse({ + sendReasoning: true + }) }) diff --git a/src/runtime/components/ChatReasoning.vue b/src/runtime/components/ChatReasoning.vue new file mode 100644 index 0000000000..88c8245526 --- /dev/null +++ b/src/runtime/components/ChatReasoning.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/src/runtime/components/ChatShimmer.vue b/src/runtime/components/ChatShimmer.vue new file mode 100644 index 0000000000..6c6c4af8e7 --- /dev/null +++ b/src/runtime/components/ChatShimmer.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/src/runtime/keyframes.css b/src/runtime/keyframes.css index e15dddb1cd..bf3174430a 100644 --- a/src/runtime/keyframes.css +++ b/src/runtime/keyframes.css @@ -537,3 +537,13 @@ transform: translate3d(0, calc(-100% * var(--gap)), 0); } } + +@keyframes shimmer { + from { + background-position: 100% center; + } + + to { + background-position: 0% center; + } +} diff --git a/src/runtime/locale/ar.ts b/src/runtime/locale/ar.ts index f501153e02..a61b752465 100644 --- a/src/runtime/locale/ar.ts +++ b/src/runtime/locale/ar.ts @@ -113,6 +113,13 @@ export default defineLocale({ copy: 'نسخ الكود إلى الحافظة' } }, + chatReasoning: { + thinking: 'يفكر...', + thoughtFewSeconds: 'فكر لبضع ثوانٍ', + thoughtSeconds: 'فكر لمدة {duration} ثانية', + thoughtMinute: 'فكر لمدة {duration} دقيقة', + thoughtMinutes: 'فكر لمدة {duration} دقائق' + }, selectMenu: { create: 'إنشاء "{label}"', noData: 'لا توجد بيانات', diff --git a/src/runtime/locale/az.ts b/src/runtime/locale/az.ts index fd745722c5..4b18b01ab5 100644 --- a/src/runtime/locale/az.ts +++ b/src/runtime/locale/az.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kodu buferə kopyala' } }, + chatReasoning: { + thinking: 'Düşünür...', + thoughtFewSeconds: 'Bir neçə saniyə düşündü', + thoughtSeconds: '{duration} saniyə düşündü', + thoughtMinute: '{duration} dəqiqə düşündü', + thoughtMinutes: '{duration} dəqiqə düşündü' + }, selectMenu: { create: '"{label}" yarat', noData: 'Məlumat yoxdur', diff --git a/src/runtime/locale/bg.ts b/src/runtime/locale/bg.ts index f629c9f15a..c476cfd58b 100644 --- a/src/runtime/locale/bg.ts +++ b/src/runtime/locale/bg.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Копирай кода в клипборда' } }, + chatReasoning: { + thinking: 'Мисли...', + thoughtFewSeconds: 'Мисли няколко секунди', + thoughtSeconds: 'Мисли {duration} секунди', + thoughtMinute: 'Мисли {duration} минута', + thoughtMinutes: 'Мисли {duration} минути' + }, selectMenu: { create: 'Създайте "{label}"', noData: 'Няма данни', diff --git a/src/runtime/locale/bn.ts b/src/runtime/locale/bn.ts index fd113b0d29..f676916642 100644 --- a/src/runtime/locale/bn.ts +++ b/src/runtime/locale/bn.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'কোড ক্লিপবোর্ডে কপি করুন' } }, + chatReasoning: { + thinking: 'চিন্তা করছে...', + thoughtFewSeconds: 'কয়েক সেকেন্ড চিন্তা করেছে', + thoughtSeconds: '{duration} সেকেন্ড চিন্তা করেছে', + thoughtMinute: '{duration} মিনিট চিন্তা করেছে', + thoughtMinutes: '{duration} মিনিট চিন্তা করেছে' + }, selectMenu: { create: '"{label}" তৈরি করুন', noData: 'কোন তথ্য নেই', diff --git a/src/runtime/locale/ca.ts b/src/runtime/locale/ca.ts index 6140fd8025..1b53250384 100644 --- a/src/runtime/locale/ca.ts +++ b/src/runtime/locale/ca.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Copiar codi al portapapers' } }, + chatReasoning: { + thinking: 'Pensant...', + thoughtFewSeconds: 'Ha pensat uns segons', + thoughtSeconds: 'Ha pensat {duration} segons', + thoughtMinute: 'Ha pensat {duration} minut', + thoughtMinutes: 'Ha pensat {duration} minuts' + }, selectMenu: { create: 'Crear "{label}"', noData: 'Sense dades', diff --git a/src/runtime/locale/ckb.ts b/src/runtime/locale/ckb.ts index d7fcc45035..2fa892b861 100644 --- a/src/runtime/locale/ckb.ts +++ b/src/runtime/locale/ckb.ts @@ -113,6 +113,13 @@ export default defineLocale({ copy: 'لەبەرگرتنەوەی کۆد' } }, + chatReasoning: { + thinking: 'بیرکردنەوە...', + thoughtFewSeconds: 'چەند چرکەیەک بیری کردەوە', + thoughtSeconds: '{duration} چرکە بیری کردەوە', + thoughtMinute: '{duration} خولەک بیری کردەوە', + thoughtMinutes: '{duration} خولەک بیری کردەوە' + }, selectMenu: { create: '"{label}" زیادکردنی', noData: 'هیچ داتایەک نییە', diff --git a/src/runtime/locale/cs.ts b/src/runtime/locale/cs.ts index 0703d84d95..450ad02544 100644 --- a/src/runtime/locale/cs.ts +++ b/src/runtime/locale/cs.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopírovat kód do schránky' } }, + chatReasoning: { + thinking: 'Přemýšlí...', + thoughtFewSeconds: 'Přemýšlel několik sekund', + thoughtSeconds: 'Přemýšlel {duration} sekund', + thoughtMinute: 'Přemýšlel {duration} minutu', + thoughtMinutes: 'Přemýšlel {duration} minut' + }, selectMenu: { create: 'Vytvořit "{label}"', noData: 'Žádná data', diff --git a/src/runtime/locale/da.ts b/src/runtime/locale/da.ts index 373e30f8fc..b80e4a3c2d 100644 --- a/src/runtime/locale/da.ts +++ b/src/runtime/locale/da.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopiér kode til udklipsholder' } }, + chatReasoning: { + thinking: 'Tænker...', + thoughtFewSeconds: 'Tænkte i et par sekunder', + thoughtSeconds: 'Tænkte i {duration} sekunder', + thoughtMinute: 'Tænkte i {duration} minut', + thoughtMinutes: 'Tænkte i {duration} minutter' + }, selectMenu: { create: 'Opret "{label}"', noData: 'Ingen data', diff --git a/src/runtime/locale/de.ts b/src/runtime/locale/de.ts index 22f4432272..69ed09d50b 100644 --- a/src/runtime/locale/de.ts +++ b/src/runtime/locale/de.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Code in die Zwischenablage kopieren' } }, + chatReasoning: { + thinking: 'Denkt nach...', + thoughtFewSeconds: 'Hat ein paar Sekunden nachgedacht', + thoughtSeconds: 'Hat {duration} Sekunden nachgedacht', + thoughtMinute: 'Hat {duration} Minute nachgedacht', + thoughtMinutes: 'Hat {duration} Minuten nachgedacht' + }, selectMenu: { create: '"{label}" erstellen', noData: 'Keine Daten', diff --git a/src/runtime/locale/de_ch.ts b/src/runtime/locale/de_ch.ts index e321f26a8a..76160d7116 100644 --- a/src/runtime/locale/de_ch.ts +++ b/src/runtime/locale/de_ch.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Code in die Zwischenablage kopieren' } }, + chatReasoning: { + thinking: 'Denkt nach...', + thoughtFewSeconds: 'Hat ein paar Sekunden nachgedacht', + thoughtSeconds: 'Hat {duration} Sekunden nachgedacht', + thoughtMinute: 'Hat {duration} Minute nachgedacht', + thoughtMinutes: 'Hat {duration} Minuten nachgedacht' + }, selectMenu: { create: '"{label}" erstellen', noData: 'Keine Daten', diff --git a/src/runtime/locale/el.ts b/src/runtime/locale/el.ts index 9422ca9c4a..ab9e5cc695 100644 --- a/src/runtime/locale/el.ts +++ b/src/runtime/locale/el.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Αντιγραφή κώδικα στο πρόχειρο' } }, + chatReasoning: { + thinking: 'Σκέφτεται...', + thoughtFewSeconds: 'Σκέφτηκε για λίγα δευτερόλεπτα', + thoughtSeconds: 'Σκέφτηκε για {duration} δευτερόλεπτα', + thoughtMinute: 'Σκέφτηκε για {duration} λεπτό', + thoughtMinutes: 'Σκέφτηκε για {duration} λεπτά' + }, selectMenu: { create: 'Δημιουργία "{label}"', noData: 'Δεν υπάρχουν δεδομένα', diff --git a/src/runtime/locale/en.ts b/src/runtime/locale/en.ts index 0cffb91108..1ae5750e5e 100644 --- a/src/runtime/locale/en.ts +++ b/src/runtime/locale/en.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Copy code to clipboard' } }, + chatReasoning: { + thinking: 'Thinking...', + thoughtFewSeconds: 'Thought for a few seconds', + thoughtSeconds: 'Thought for {duration} seconds', + thoughtMinutes: 'Thought for {duration} minutes', + thoughtMinute: 'Thought for {duration} minute' + }, selectMenu: { create: 'Create "{label}"', noData: 'No data', diff --git a/src/runtime/locale/en_gb.ts b/src/runtime/locale/en_gb.ts index 4298c0a9e5..fde0959e8a 100644 --- a/src/runtime/locale/en_gb.ts +++ b/src/runtime/locale/en_gb.ts @@ -5,5 +5,7 @@ import en from './en' export default defineLocale({ name: 'English (United Kingdom)', code: 'en-GB', - messages: en.messages + messages: { + ...en.messages + } }) diff --git a/src/runtime/locale/es.ts b/src/runtime/locale/es.ts index 4c573edda9..5c130e7029 100644 --- a/src/runtime/locale/es.ts +++ b/src/runtime/locale/es.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Copiar código al portapapeles' } }, + chatReasoning: { + thinking: 'Pensando...', + thoughtFewSeconds: 'Pensó durante unos segundos', + thoughtSeconds: 'Pensó durante {duration} segundos', + thoughtMinute: 'Pensó durante {duration} minuto', + thoughtMinutes: 'Pensó durante {duration} minutos' + }, selectMenu: { create: 'Crear "{label}"', noData: 'Sin datos', diff --git a/src/runtime/locale/et.ts b/src/runtime/locale/et.ts index f2ce4dd9be..37ce2227ee 100644 --- a/src/runtime/locale/et.ts +++ b/src/runtime/locale/et.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopeeri kood lõikelauale' } }, + chatReasoning: { + thinking: 'Mõtleb...', + thoughtFewSeconds: 'Mõtles mõne sekundi', + thoughtSeconds: 'Mõtles {duration} sekundit', + thoughtMinute: 'Mõtles {duration} minuti', + thoughtMinutes: 'Mõtles {duration} minutit' + }, selectMenu: { create: 'Loo "{label}"', noData: 'Pole andmeid', diff --git a/src/runtime/locale/eu.ts b/src/runtime/locale/eu.ts index 077c12e176..118f443e7b 100644 --- a/src/runtime/locale/eu.ts +++ b/src/runtime/locale/eu.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopiatu kodea clipboard-era' } }, + chatReasoning: { + thinking: 'Pentsatzen...', + thoughtFewSeconds: 'Segundo batzuk pentsatu du', + thoughtSeconds: '{duration} segundo pentsatu du', + thoughtMinute: '{duration} minutu pentsatu du', + thoughtMinutes: '{duration} minutu pentsatu du' + }, selectMenu: { create: 'Sortu {label}', noData: 'Daturik gabe', diff --git a/src/runtime/locale/fa_ir.ts b/src/runtime/locale/fa_ir.ts index 147d82781a..57dcb2cd88 100644 --- a/src/runtime/locale/fa_ir.ts +++ b/src/runtime/locale/fa_ir.ts @@ -113,6 +113,13 @@ export default defineLocale({ copy: 'کپی کد در کلیپ‌بورد' } }, + chatReasoning: { + thinking: 'در حال فکر کردن...', + thoughtFewSeconds: 'چند ثانیه فکر کرد', + thoughtSeconds: '{duration} ثانیه فکر کرد', + thoughtMinute: '{duration} دقیقه فکر کرد', + thoughtMinutes: '{duration} دقیقه فکر کرد' + }, selectMenu: { create: 'ایجاد "{label}"', noData: 'داده‌ای موجود نیست', diff --git a/src/runtime/locale/fi.ts b/src/runtime/locale/fi.ts index 311704e60a..03e4270d72 100644 --- a/src/runtime/locale/fi.ts +++ b/src/runtime/locale/fi.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopioi koodi leikepöydälle' } }, + chatReasoning: { + thinking: 'Ajattelee...', + thoughtFewSeconds: 'Ajatteli muutaman sekunnin', + thoughtSeconds: 'Ajatteli {duration} sekuntia', + thoughtMinute: 'Ajatteli {duration} minuutin', + thoughtMinutes: 'Ajatteli {duration} minuuttia' + }, selectMenu: { create: 'Luo "{label}"', noData: 'Ei tietoja', diff --git a/src/runtime/locale/fr.ts b/src/runtime/locale/fr.ts index 1c74bc825f..34b2d1d5b9 100644 --- a/src/runtime/locale/fr.ts +++ b/src/runtime/locale/fr.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Copier le code dans le presse-papiers' } }, + chatReasoning: { + thinking: 'Réflexion...', + thoughtFewSeconds: 'A réfléchi quelques secondes', + thoughtSeconds: 'A réfléchi {duration} secondes', + thoughtMinute: 'A réfléchi {duration} minute', + thoughtMinutes: 'A réfléchi {duration} minutes' + }, selectMenu: { create: 'Créer "{label}"', noData: 'Aucune donnée', diff --git a/src/runtime/locale/gl.ts b/src/runtime/locale/gl.ts index 4ae693cf5a..09fcc8f3f9 100644 --- a/src/runtime/locale/gl.ts +++ b/src/runtime/locale/gl.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Copiar código ao portapapeis' } }, + chatReasoning: { + thinking: 'Pensando...', + thoughtFewSeconds: 'Pensou uns segundos', + thoughtSeconds: 'Pensou {duration} segundos', + thoughtMinute: 'Pensou {duration} minuto', + thoughtMinutes: 'Pensou {duration} minutos' + }, selectMenu: { create: 'Crear "{label}"', noData: 'Sen datos', diff --git a/src/runtime/locale/he.ts b/src/runtime/locale/he.ts index 0855ec3088..f984ce95f9 100644 --- a/src/runtime/locale/he.ts +++ b/src/runtime/locale/he.ts @@ -113,6 +113,13 @@ export default defineLocale({ copy: 'העתק קוד ללוח' } }, + chatReasoning: { + thinking: 'חושב...', + thoughtFewSeconds: 'חשב כמה שניות', + thoughtSeconds: 'חשב {duration} שניות', + thoughtMinute: 'חשב {duration} דקה', + thoughtMinutes: 'חשב {duration} דקות' + }, selectMenu: { create: 'צור "{label}"', noData: 'אין נתונים', diff --git a/src/runtime/locale/hi.ts b/src/runtime/locale/hi.ts index 61fa58bca1..99625f0fbf 100644 --- a/src/runtime/locale/hi.ts +++ b/src/runtime/locale/hi.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'कोड को क्लिपबोर्ड पर कॉपी करें' } }, + chatReasoning: { + thinking: 'सोच रहा है...', + thoughtFewSeconds: 'कुछ सेकंड सोचा', + thoughtSeconds: '{duration} सेकंड सोचा', + thoughtMinute: '{duration} मिनट सोचा', + thoughtMinutes: '{duration} मिनट सोचा' + }, selectMenu: { create: '"{label}" बनाएँ', noData: 'कोई डेटा नहीं', diff --git a/src/runtime/locale/hr.ts b/src/runtime/locale/hr.ts index 8bed8ec9ba..31dd46722e 100644 --- a/src/runtime/locale/hr.ts +++ b/src/runtime/locale/hr.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopiraj kod u međuspremnik' } }, + chatReasoning: { + thinking: 'Razmišlja...', + thoughtFewSeconds: 'Razmišljao nekoliko sekundi', + thoughtSeconds: 'Razmišljao {duration} sekundi', + thoughtMinute: 'Razmišljao {duration} minutu', + thoughtMinutes: 'Razmišljao {duration} minuta' + }, selectMenu: { create: 'Stvori "{label}"', noData: 'Nema podataka', diff --git a/src/runtime/locale/hu.ts b/src/runtime/locale/hu.ts index e3a293b247..f0811c3245 100644 --- a/src/runtime/locale/hu.ts +++ b/src/runtime/locale/hu.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kód másolása a vágólapra' } }, + chatReasoning: { + thinking: 'Gondolkodik...', + thoughtFewSeconds: 'Néhány másodpercig gondolkodott', + thoughtSeconds: '{duration} másodpercig gondolkodott', + thoughtMinute: '{duration} percig gondolkodott', + thoughtMinutes: '{duration} percig gondolkodott' + }, selectMenu: { create: '"{label}" létrehozása', noData: 'Nincs adat', diff --git a/src/runtime/locale/hy.ts b/src/runtime/locale/hy.ts index 43283166de..4cb799bc43 100644 --- a/src/runtime/locale/hy.ts +++ b/src/runtime/locale/hy.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Պատճենել կոդը սեղմատախտակին' } }, + chatReasoning: { + thinking: 'Thinking...', + thoughtFewSeconds: 'Thought for a few seconds', + thoughtSeconds: 'Thought for {duration} seconds', + thoughtMinute: 'Thought for {duration} minute', + thoughtMinutes: 'Thought for {duration} minutes' + }, selectMenu: { create: 'Ստեղծել "{label}"', noData: 'Տվյալներ չկան', diff --git a/src/runtime/locale/id.ts b/src/runtime/locale/id.ts index 686416e456..08b4ce9a49 100644 --- a/src/runtime/locale/id.ts +++ b/src/runtime/locale/id.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Salin kode ke clipboard' } }, + chatReasoning: { + thinking: 'Berpikir...', + thoughtFewSeconds: 'Berpikir beberapa detik', + thoughtSeconds: 'Berpikir {duration} detik', + thoughtMinute: 'Berpikir {duration} menit', + thoughtMinutes: 'Berpikir {duration} menit' + }, selectMenu: { create: 'Buat "{label}"', noData: 'Tidak ada data', diff --git a/src/runtime/locale/it.ts b/src/runtime/locale/it.ts index 90305cf035..c1ecd0893c 100644 --- a/src/runtime/locale/it.ts +++ b/src/runtime/locale/it.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Copia codice negli appunti' } }, + chatReasoning: { + thinking: 'Pensando...', + thoughtFewSeconds: 'Ha pensato per qualche secondo', + thoughtSeconds: 'Ha pensato per {duration} secondi', + thoughtMinute: 'Ha pensato per {duration} minuto', + thoughtMinutes: 'Ha pensato per {duration} minuti' + }, selectMenu: { create: 'Crea "{label}"', noData: 'Nessun dato', diff --git a/src/runtime/locale/ja.ts b/src/runtime/locale/ja.ts index 90a16c8677..dea3605015 100644 --- a/src/runtime/locale/ja.ts +++ b/src/runtime/locale/ja.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'コードをクリップボードにコピー' } }, + chatReasoning: { + thinking: '考え中...', + thoughtFewSeconds: '数秒間考えました', + thoughtSeconds: '{duration}秒間考えました', + thoughtMinute: '{duration}分間考えました', + thoughtMinutes: '{duration}分間考えました' + }, selectMenu: { create: '"{label}"を作成', noData: 'データがありません', diff --git a/src/runtime/locale/ka.ts b/src/runtime/locale/ka.ts index 798da9a72a..72107ca0d6 100644 --- a/src/runtime/locale/ka.ts +++ b/src/runtime/locale/ka.ts @@ -114,6 +114,13 @@ export default defineLocale({ copy: 'კოდის კოპირება ბუფერში' } }, + chatReasoning: { + thinking: 'ფიქრობს...', + thoughtFewSeconds: 'რამდენიმე წამი ფიქრობდა', + thoughtSeconds: '{duration} წამი ფიქრობდა', + thoughtMinute: '{duration} წუთი ფიქრობდა', + thoughtMinutes: '{duration} წუთი ფიქრობდა' + }, selectMenu: { create: 'დაამატე "{label}"', // "Create" translates as "შექმნა", but since we are simply adding new choice, creating sounds wrong, thus I chose to use "დაამატე", meaning "add". noData: 'მონაცემები არ არის', diff --git a/src/runtime/locale/kk.ts b/src/runtime/locale/kk.ts index 11e481a19f..6187b3118d 100644 --- a/src/runtime/locale/kk.ts +++ b/src/runtime/locale/kk.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Кодты алмасу буферіне көшіру' } }, + chatReasoning: { + thinking: 'Ойланып жатыр...', + thoughtFewSeconds: 'Бірнеше секунд ойланды', + thoughtSeconds: '{duration} секунд ойланды', + thoughtMinute: '{duration} минут ойланды', + thoughtMinutes: '{duration} минут ойланды' + }, selectMenu: { create: '"{label}" жасау', noData: 'Деректер жоқ', diff --git a/src/runtime/locale/km.ts b/src/runtime/locale/km.ts index 2d4198de06..a5b2d2c705 100644 --- a/src/runtime/locale/km.ts +++ b/src/runtime/locale/km.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'ចម្លងកូដទៅក្ដារតម្បៀតខ្ទាស់' } }, + chatReasoning: { + thinking: 'កំពុងគិត...', + thoughtFewSeconds: 'បានគិតប៉ុន្មានវិនាទី', + thoughtSeconds: 'បានគិត {duration} វិនាទី', + thoughtMinute: 'បានគិត {duration} នាទី', + thoughtMinutes: 'បានគិត {duration} នាទី' + }, selectMenu: { create: 'បង្កើត "{label}"', noData: 'មិនមានទិន្នន័យ', diff --git a/src/runtime/locale/ko.ts b/src/runtime/locale/ko.ts index 7dc2e4411b..36f309425e 100644 --- a/src/runtime/locale/ko.ts +++ b/src/runtime/locale/ko.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: '코드를 클립보드에 복사' } }, + chatReasoning: { + thinking: '생각 중...', + thoughtFewSeconds: '몇 초 동안 생각했습니다', + thoughtSeconds: '{duration}초 동안 생각했습니다', + thoughtMinute: '{duration}분 동안 생각했습니다', + thoughtMinutes: '{duration}분 동안 생각했습니다' + }, selectMenu: { create: '"{label}" 생성', noData: '데이터가 없습니다.', diff --git a/src/runtime/locale/ky.ts b/src/runtime/locale/ky.ts index 8895876854..9df3bf5768 100644 --- a/src/runtime/locale/ky.ts +++ b/src/runtime/locale/ky.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Кодду алмашуу буферине көчүрүү' } }, + chatReasoning: { + thinking: 'Ойлонуп жатат...', + thoughtFewSeconds: 'Бир нече секунд ойлонду', + thoughtSeconds: '{duration} секунд ойлонду', + thoughtMinute: '{duration} мүнөт ойлонду', + thoughtMinutes: '{duration} мүнөт ойлонду' + }, selectMenu: { create: '"{label}" жасоо', noData: 'Маалымат жок', diff --git a/src/runtime/locale/lb.ts b/src/runtime/locale/lb.ts index f574b01612..7151b5b282 100644 --- a/src/runtime/locale/lb.ts +++ b/src/runtime/locale/lb.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Code an d\'Zwëschspäicher kopéieren' } }, + chatReasoning: { + thinking: 'Denkt no...', + thoughtFewSeconds: 'Huet e puer Sekonnen nogeduecht', + thoughtSeconds: 'Huet {duration} Sekonnen nogeduecht', + thoughtMinute: 'Huet {duration} Minutt nogeduecht', + thoughtMinutes: 'Huet {duration} Minutten nogeduecht' + }, selectMenu: { create: '"{label}" erstellen', noData: 'Keng Donnéeën', diff --git a/src/runtime/locale/lo.ts b/src/runtime/locale/lo.ts index 48a317b513..4a03b76f1c 100644 --- a/src/runtime/locale/lo.ts +++ b/src/runtime/locale/lo.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'ຄັດລອກໂຄ້ດ' } }, + chatReasoning: { + thinking: 'ກຳລັງຄິດ...', + thoughtFewSeconds: 'ຄິດສອງສາມວິນາທີ', + thoughtSeconds: 'ຄິດ {duration} ວິນາທີ', + thoughtMinute: 'ຄິດ {duration} ນາທີ', + thoughtMinutes: 'ຄິດ {duration} ນາທີ' + }, selectMenu: { create: 'ສ້າງ "{label}"', noData: 'ບໍ່ມີຂໍ້ມູນ', diff --git a/src/runtime/locale/lt.ts b/src/runtime/locale/lt.ts index 110847e4cd..e0536d1c18 100644 --- a/src/runtime/locale/lt.ts +++ b/src/runtime/locale/lt.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopijuoti kodą į iškarpinę' } }, + chatReasoning: { + thinking: 'Galvoja...', + thoughtFewSeconds: 'Galvojo kelias sekundes', + thoughtSeconds: 'Galvojo {duration} sekundes', + thoughtMinute: 'Galvojo {duration} minutę', + thoughtMinutes: 'Galvojo {duration} minutes' + }, selectMenu: { create: 'Sukurti „{label}"', noData: 'Nėra duomenų', diff --git a/src/runtime/locale/mn.ts b/src/runtime/locale/mn.ts index 0d801ef562..e89e19aa4f 100644 --- a/src/runtime/locale/mn.ts +++ b/src/runtime/locale/mn.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Кодыг санах ойд хуулах' } }, + chatReasoning: { + thinking: 'Бодож байна...', + thoughtFewSeconds: 'Хэдэн секунд бодсон', + thoughtSeconds: '{duration} секунд бодсон', + thoughtMinute: '{duration} минут бодсон', + thoughtMinutes: '{duration} минут бодсон' + }, selectMenu: { create: '"{label}" үүсгэх', noData: 'Мэдээлэл байхгүй', diff --git a/src/runtime/locale/ms.ts b/src/runtime/locale/ms.ts index f021598c61..dab9ac50c8 100644 --- a/src/runtime/locale/ms.ts +++ b/src/runtime/locale/ms.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Salin kod ke papan klip' } }, + chatReasoning: { + thinking: 'Berfikir...', + thoughtFewSeconds: 'Berfikir beberapa saat', + thoughtSeconds: 'Berfikir {duration} saat', + thoughtMinute: 'Berfikir {duration} minit', + thoughtMinutes: 'Berfikir {duration} minit' + }, selectMenu: { create: 'Cipta "{label}"', noData: 'Tiada data', diff --git a/src/runtime/locale/nb_no.ts b/src/runtime/locale/nb_no.ts index 5c92e3c79a..2099e15af1 100644 --- a/src/runtime/locale/nb_no.ts +++ b/src/runtime/locale/nb_no.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopier kode til utklippstavle' } }, + chatReasoning: { + thinking: 'Tenker...', + thoughtFewSeconds: 'Tenkte i noen sekunder', + thoughtSeconds: 'Tenkte i {duration} sekunder', + thoughtMinute: 'Tenkte i {duration} minutt', + thoughtMinutes: 'Tenkte i {duration} minutter' + }, selectMenu: { create: 'Opprett "{label}"', noData: 'Ingen data', diff --git a/src/runtime/locale/nl.ts b/src/runtime/locale/nl.ts index dba219d0f7..de51496d02 100644 --- a/src/runtime/locale/nl.ts +++ b/src/runtime/locale/nl.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Code naar klembord kopiëren' } }, + chatReasoning: { + thinking: 'Denkt na...', + thoughtFewSeconds: 'Dacht een paar seconden na', + thoughtSeconds: 'Dacht {duration} seconden na', + thoughtMinute: 'Dacht {duration} minuut na', + thoughtMinutes: 'Dacht {duration} minuten na' + }, selectMenu: { create: '"{label}" creëren', noData: 'Geen gegevens', diff --git a/src/runtime/locale/pl.ts b/src/runtime/locale/pl.ts index bbd092fa4c..bc2cd17d27 100644 --- a/src/runtime/locale/pl.ts +++ b/src/runtime/locale/pl.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopiuj kod do schowka' } }, + chatReasoning: { + thinking: 'Myśli...', + thoughtFewSeconds: 'Myślał przez kilka sekund', + thoughtSeconds: 'Myślał przez {duration} sekund', + thoughtMinute: 'Myślał przez {duration} minutę', + thoughtMinutes: 'Myślał przez {duration} minut' + }, selectMenu: { create: 'Utwórz "{label}"', noData: 'Brak danych', diff --git a/src/runtime/locale/pt.ts b/src/runtime/locale/pt.ts index 6a34792c38..96cb265054 100644 --- a/src/runtime/locale/pt.ts +++ b/src/runtime/locale/pt.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Copiar código para a área de transferência' } }, + chatReasoning: { + thinking: 'A pensar...', + thoughtFewSeconds: 'Pensou durante alguns segundos', + thoughtSeconds: 'Pensou durante {duration} segundos', + thoughtMinute: 'Pensou durante {duration} minuto', + thoughtMinutes: 'Pensou durante {duration} minutos' + }, selectMenu: { create: 'Criar "{label}"', noData: 'Sem dados', diff --git a/src/runtime/locale/pt_br.ts b/src/runtime/locale/pt_br.ts index d08ac29858..08522fbfaf 100644 --- a/src/runtime/locale/pt_br.ts +++ b/src/runtime/locale/pt_br.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Copiar código para a área de transferência' } }, + chatReasoning: { + thinking: 'Pensando...', + thoughtFewSeconds: 'Pensou por alguns segundos', + thoughtSeconds: 'Pensou por {duration} segundos', + thoughtMinute: 'Pensou por {duration} minuto', + thoughtMinutes: 'Pensou por {duration} minutos' + }, selectMenu: { create: 'Criar "{label}"', noData: 'Nenhum dado', diff --git a/src/runtime/locale/ro.ts b/src/runtime/locale/ro.ts index 6f146592cd..a4753e3921 100644 --- a/src/runtime/locale/ro.ts +++ b/src/runtime/locale/ro.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Copiază codul în clipboard' } }, + chatReasoning: { + thinking: 'Gândește...', + thoughtFewSeconds: 'A gândit câteva secunde', + thoughtSeconds: 'A gândit {duration} secunde', + thoughtMinute: 'A gândit {duration} minut', + thoughtMinutes: 'A gândit {duration} minute' + }, selectMenu: { create: 'Creează "{label}"', noData: 'Nu există date', diff --git a/src/runtime/locale/ru.ts b/src/runtime/locale/ru.ts index 52947bda1b..6af3d789b0 100644 --- a/src/runtime/locale/ru.ts +++ b/src/runtime/locale/ru.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Скопировать код в буфер обмена' } }, + chatReasoning: { + thinking: 'Думает...', + thoughtFewSeconds: 'Думал несколько секунд', + thoughtSeconds: 'Думал {duration} секунд', + thoughtMinute: 'Думал {duration} минуту', + thoughtMinutes: 'Думал {duration} минут' + }, selectMenu: { create: 'Создать "{label}"', noData: 'Нет данных', diff --git a/src/runtime/locale/sk.ts b/src/runtime/locale/sk.ts index 0213784488..d0999a7b88 100644 --- a/src/runtime/locale/sk.ts +++ b/src/runtime/locale/sk.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopírovať kód do schránky' } }, + chatReasoning: { + thinking: 'Premýšľa...', + thoughtFewSeconds: 'Premýšľal niekoľko sekúnd', + thoughtSeconds: 'Premýšľal {duration} sekúnd', + thoughtMinute: 'Premýšľal {duration} minútu', + thoughtMinutes: 'Premýšľal {duration} minút' + }, selectMenu: { create: 'Vytvoriť "{label}"', noData: 'Žiadne dáta', diff --git a/src/runtime/locale/sl.ts b/src/runtime/locale/sl.ts index 0478b93b99..01fa74d3a2 100644 --- a/src/runtime/locale/sl.ts +++ b/src/runtime/locale/sl.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopiraj kodo v odložišče' } }, + chatReasoning: { + thinking: 'Razmišlja...', + thoughtFewSeconds: 'Razmišljal nekaj sekund', + thoughtSeconds: 'Razmišljal {duration} sekund', + thoughtMinute: 'Razmišljal {duration} minuto', + thoughtMinutes: 'Razmišljal {duration} minut' + }, selectMenu: { create: 'Ustvari "{label}"', noData: 'Ni podatkov', diff --git a/src/runtime/locale/sq.ts b/src/runtime/locale/sq.ts index 93d282000b..1739194a2c 100644 --- a/src/runtime/locale/sq.ts +++ b/src/runtime/locale/sq.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopjo kodin në kujtesë' } }, + chatReasoning: { + thinking: 'Duke menduar...', + thoughtFewSeconds: 'Mendoi disa sekonda', + thoughtSeconds: 'Mendoi {duration} sekonda', + thoughtMinute: 'Mendoi {duration} minutë', + thoughtMinutes: 'Mendoi {duration} minuta' + }, selectMenu: { create: 'Krijo "{label}"', noData: 'Nuk ka të dhëna', diff --git a/src/runtime/locale/sv.ts b/src/runtime/locale/sv.ts index 474a5d368f..4ecb9eec52 100644 --- a/src/runtime/locale/sv.ts +++ b/src/runtime/locale/sv.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kopiera kod till urklipp' } }, + chatReasoning: { + thinking: 'Tänker...', + thoughtFewSeconds: 'Tänkte i några sekunder', + thoughtSeconds: 'Tänkte i {duration} sekunder', + thoughtMinute: 'Tänkte i {duration} minut', + thoughtMinutes: 'Tänkte i {duration} minuter' + }, selectMenu: { create: 'Skapa "{label}"', noData: 'Inga data', diff --git a/src/runtime/locale/th.ts b/src/runtime/locale/th.ts index aeb7a8285f..b9525d760e 100644 --- a/src/runtime/locale/th.ts +++ b/src/runtime/locale/th.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'คัดลอกโค้ดไปยังคลิปบอร์ด' } }, + chatReasoning: { + thinking: 'กำลังคิด...', + thoughtFewSeconds: 'คิดไปสักครู่', + thoughtSeconds: 'คิดไป {duration} วินาที', + thoughtMinute: 'คิดไป {duration} นาที', + thoughtMinutes: 'คิดไป {duration} นาที' + }, selectMenu: { create: 'สร้าง "{label}"', noData: 'ไม่มีข้อมูล', diff --git a/src/runtime/locale/tj.ts b/src/runtime/locale/tj.ts index 05d4ee8ef2..c651462437 100644 --- a/src/runtime/locale/tj.ts +++ b/src/runtime/locale/tj.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Нусха бардоштан' } }, + chatReasoning: { + thinking: 'Фикр мекунад...', + thoughtFewSeconds: 'Якчанд сония фикр кард', + thoughtSeconds: '{duration} сония фикр кард', + thoughtMinute: '{duration} дақиқа фикр кард', + thoughtMinutes: '{duration} дақиқа фикр кард' + }, selectMenu: { create: '"{label}" созед', noData: 'Маълумот нест', diff --git a/src/runtime/locale/tr.ts b/src/runtime/locale/tr.ts index fc0eb9a2bc..c09e3a929a 100644 --- a/src/runtime/locale/tr.ts +++ b/src/runtime/locale/tr.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Kodu panoya kopyala' } }, + chatReasoning: { + thinking: 'Düşünüyor...', + thoughtFewSeconds: 'Birkaç saniye düşündü', + thoughtSeconds: '{duration} saniye düşündü', + thoughtMinute: '{duration} dakika düşündü', + thoughtMinutes: '{duration} dakika düşündü' + }, selectMenu: { create: '"{label}" oluştur', noData: 'Veri yok', diff --git a/src/runtime/locale/ug_cn.ts b/src/runtime/locale/ug_cn.ts index 2b9375604e..131c75e9e1 100644 --- a/src/runtime/locale/ug_cn.ts +++ b/src/runtime/locale/ug_cn.ts @@ -113,6 +113,13 @@ export default defineLocale({ copy: 'كۆچۈرۈش' } }, + chatReasoning: { + thinking: 'ئويلاۋاتىدۇ...', + thoughtFewSeconds: 'بىر نەچچە سېكۇنت ئويلىدى', + thoughtSeconds: '{duration} سېكۇنت ئويلىدى', + thoughtMinute: '{duration} مىنۇت ئويلىدى', + thoughtMinutes: '{duration} مىنۇت ئويلىدى' + }, selectMenu: { create: '"{label}" نى قۇرۇش', noData: 'سانلىق مەلۇمات يوق', diff --git a/src/runtime/locale/uk.ts b/src/runtime/locale/uk.ts index b87905923a..0b414253e1 100644 --- a/src/runtime/locale/uk.ts +++ b/src/runtime/locale/uk.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Копіювати код у буфер обміну' } }, + chatReasoning: { + thinking: 'Думає...', + thoughtFewSeconds: 'Думав кілька секунд', + thoughtSeconds: 'Думав {duration} секунд', + thoughtMinute: 'Думав {duration} хвилину', + thoughtMinutes: 'Думав {duration} хвилин' + }, selectMenu: { create: 'Створити "{label}"', noData: 'Немає даних', diff --git a/src/runtime/locale/ur.ts b/src/runtime/locale/ur.ts index 0e68476e57..27f51fca2b 100644 --- a/src/runtime/locale/ur.ts +++ b/src/runtime/locale/ur.ts @@ -113,6 +113,13 @@ export default defineLocale({ copy: 'کوڈ کاپی کریں' } }, + chatReasoning: { + thinking: 'سوچ رہا ہے...', + thoughtFewSeconds: 'چند سیکنڈ سوچا', + thoughtSeconds: '{duration} سیکنڈ سوچا', + thoughtMinute: '{duration} منٹ سوچا', + thoughtMinutes: '{duration} منٹ سوچا' + }, selectMenu: { create: '"{label}" بنائیں', noData: 'کوئی ڈیٹا نہیں', diff --git a/src/runtime/locale/uz.ts b/src/runtime/locale/uz.ts index f840efcb45..c5a58ee957 100644 --- a/src/runtime/locale/uz.ts +++ b/src/runtime/locale/uz.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Koddan buferga nusxa olish' } }, + chatReasoning: { + thinking: 'O\'ylayapti...', + thoughtFewSeconds: 'Bir necha soniya o\'yladi', + thoughtSeconds: '{duration} soniya o\'yladi', + thoughtMinute: '{duration} daqiqa o\'yladi', + thoughtMinutes: '{duration} daqiqa o\'yladi' + }, selectMenu: { create: '"{label}" yaratish', noData: 'Maʼlumot yoʻq', diff --git a/src/runtime/locale/vi.ts b/src/runtime/locale/vi.ts index 979812f57e..2abf655997 100644 --- a/src/runtime/locale/vi.ts +++ b/src/runtime/locale/vi.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: 'Sao chép mã vào bộ nhớ tạm' } }, + chatReasoning: { + thinking: 'Đang suy nghĩ...', + thoughtFewSeconds: 'Đã suy nghĩ vài giây', + thoughtSeconds: 'Đã suy nghĩ {duration} giây', + thoughtMinute: 'Đã suy nghĩ {duration} phút', + thoughtMinutes: 'Đã suy nghĩ {duration} phút' + }, selectMenu: { create: 'Tạo "{label}"', noData: 'Không có dữ liệu', diff --git a/src/runtime/locale/zh_cn.ts b/src/runtime/locale/zh_cn.ts index 9f9338eb05..278aa1fba5 100644 --- a/src/runtime/locale/zh_cn.ts +++ b/src/runtime/locale/zh_cn.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: '复制代码到剪贴板' } }, + chatReasoning: { + thinking: '思考中...', + thoughtFewSeconds: '思考了几秒钟', + thoughtSeconds: '思考了 {duration} 秒', + thoughtMinute: '思考了 {duration} 分钟', + thoughtMinutes: '思考了 {duration} 分钟' + }, selectMenu: { create: '创建 "{label}"', noData: '没有数据', diff --git a/src/runtime/locale/zh_tw.ts b/src/runtime/locale/zh_tw.ts index bd282ded1a..1cf6eb16d1 100644 --- a/src/runtime/locale/zh_tw.ts +++ b/src/runtime/locale/zh_tw.ts @@ -112,6 +112,13 @@ export default defineLocale({ copy: '複製程式碼到剪貼簿' } }, + chatReasoning: { + thinking: '思考中...', + thoughtFewSeconds: '思考了幾秒鐘', + thoughtSeconds: '思考了 {duration} 秒', + thoughtMinute: '思考了 {duration} 分鐘', + thoughtMinutes: '思考了 {duration} 分鐘' + }, selectMenu: { create: '建立「{label}」', noData: '沒有資料', diff --git a/src/runtime/types/locale.ts b/src/runtime/types/locale.ts index 20beb0f16d..1734dca142 100644 --- a/src/runtime/types/locale.ts +++ b/src/runtime/types/locale.ts @@ -116,6 +116,13 @@ export type Messages = { copy: string } } + chatReasoning: { + thinking: string + thoughtFewSeconds: string + thoughtSeconds: string + thoughtMinutes: string + thoughtMinute: string + } selectMenu: { create: string noData: string diff --git a/src/theme/chat-reasoning.ts b/src/theme/chat-reasoning.ts new file mode 100644 index 0000000000..1f33e93c41 --- /dev/null +++ b/src/theme/chat-reasoning.ts @@ -0,0 +1,12 @@ +import type { ModuleOptions } from '../module' + +export default (options: Required) => ({ + slots: { + root: '', + trigger: ['group flex w-full items-center gap-2 text-muted text-sm hover:text-default cursor-pointer disabled:cursor-default disabled:hover:text-muted', options.theme.transitions && 'transition-colors'], + leadingIcon: 'size-4 shrink-0', + trailingIcon: ['size-4 shrink-0 group-data-[state=open]:rotate-180', options.theme.transitions && 'transition-transform duration-200'], + content: 'data-[state=open]:animate-[collapsible-down_200ms_ease-out] data-[state=closed]:animate-[collapsible-up_200ms_ease-out] overflow-hidden', + body: 'pt-2 text-sm text-muted' + } +}) diff --git a/src/theme/chat-shimmer.ts b/src/theme/chat-shimmer.ts new file mode 100644 index 0000000000..3280b74f48 --- /dev/null +++ b/src/theme/chat-shimmer.ts @@ -0,0 +1,8 @@ +export default { + slots: { + base: [ + 'relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent', + '[background-repeat:no-repeat,padding-box]' + ] + } +} diff --git a/src/theme/index.ts b/src/theme/index.ts index 687acd97db..b20c356476 100644 --- a/src/theme/index.ts +++ b/src/theme/index.ts @@ -19,6 +19,8 @@ export { default as chatMessages } from './chat-messages' export { default as chatPalette } from './chat-palette' export { default as chatPrompt } from './chat-prompt' export { default as chatPromptSubmit } from './chat-prompt-submit' +export { default as chatReasoning } from './chat-reasoning' +export { default as chatShimmer } from './chat-shimmer' export { default as checkbox } from './checkbox' export { default as checkboxGroup } from './checkbox-group' export { default as chip } from './chip' diff --git a/test/components/ChatReasoning.spec.ts b/test/components/ChatReasoning.spec.ts new file mode 100644 index 0000000000..b9b4c00505 --- /dev/null +++ b/test/components/ChatReasoning.spec.ts @@ -0,0 +1,44 @@ +import { describe, it, expect } from 'vitest' +import { axe } from 'vitest-axe' +import { mountSuspended } from '@nuxt/test-utils/runtime' +import ChatReasoning from '../../src/runtime/components/ChatReasoning.vue' +import type { ChatReasoningProps, ChatReasoningSlots } from '../../src/runtime/components/ChatReasoning.vue' +import ComponentRender from '../component-render' + +describe('ChatReasoning', () => { + const props = { text: 'This is the reasoning content.' } + + it.each([ + // Props + ['with text', { props }], + ['with open', { props: { ...props, open: true } }], + ['with defaultOpen', { props: { ...props, defaultOpen: true } }], + ['with isStreaming', { props: { ...props, isStreaming: true } }], + ['with duration', { props: { ...props, duration: 5 } }], + ['with disabled', { props: { ...props, disabled: true } }], + ['with icon', { props: { ...props, icon: 'i-lucide-brain' } }], + ['with trailingIcon', { props: { ...props, trailingIcon: 'i-lucide-chevron-right' } }], + ['with getThinkingMessage', { props: { ...props, getThinkingMessage: (isStreaming: boolean, duration?: number) => isStreaming ? 'Processing...' : `Done in ${duration}s` } }], + // Slots + ['with thinkingMessage slot', { props: { ...props, isStreaming: true }, slots: { thinkingMessage: () => 'Custom thinking message' } }], + ['with class', { props: { ...props, class: 'my-4' } }], + ['with ui', { props: { ...props, ui: { root: 'bg-muted' } } }], + ['with default slot', { props: { open: true }, slots: { default: () => 'Default slot content' } }], + ['with body slot', { props: { open: true }, slots: { body: () => 'Body slot content' } }], + ['with trigger slot', { props, slots: { trigger: () => 'Custom trigger' } }] + ])('renders %s correctly', async (nameOrHtml: string, options: { props?: ChatReasoningProps, slots?: Partial }) => { + const html = await ComponentRender(nameOrHtml, options, ChatReasoning) + expect(html).toMatchSnapshot() + }) + + it('passes accessibility tests', async () => { + const wrapper = await mountSuspended(ChatReasoning, { + props: { + text: 'Reasoning content for accessibility test', + open: true + } + }) + + expect(await axe(wrapper.element)).toHaveNoViolations() + }) +}) diff --git a/test/components/ChatShimmer.spec.ts b/test/components/ChatShimmer.spec.ts new file mode 100644 index 0000000000..f07dbaa5c6 --- /dev/null +++ b/test/components/ChatShimmer.spec.ts @@ -0,0 +1,33 @@ +import { describe, it, expect } from 'vitest' +import { axe } from 'vitest-axe' +import { mountSuspended } from '@nuxt/test-utils/runtime' +import ChatShimmer from '../../src/runtime/components/ChatShimmer.vue' +import type { ChatShimmerProps } from '../../src/runtime/components/ChatShimmer.vue' +import ComponentRender from '../component-render' + +describe('ChatShimmer', () => { + const props = { text: 'Loading...' } + + it.each([ + // Props + ['with text', { props }], + ['with as', { props: { ...props, as: 'div' } }], + ['with duration', { props: { ...props, duration: 3 } }], + ['with spread', { props: { ...props, spread: 4 } }], + ['with class', { props: { ...props, class: 'text-lg' } }], + ['with ui', { props: { ...props, ui: { base: 'font-bold' } } }] + ])('renders %s correctly', async (nameOrHtml: string, options: { props?: ChatShimmerProps }) => { + const html = await ComponentRender(nameOrHtml, options, ChatShimmer) + expect(html).toMatchSnapshot() + }) + + it('passes accessibility tests', async () => { + const wrapper = await mountSuspended(ChatShimmer, { + props: { + text: 'Loading content...' + } + }) + + expect(await axe(wrapper.element)).toHaveNoViolations() + }) +}) diff --git a/test/components/__snapshots__/ChatReasoning-vue.spec.ts.snap b/test/components/__snapshots__/ChatReasoning-vue.spec.ts.snap new file mode 100644 index 0000000000..9963d5fd30 --- /dev/null +++ b/test/components/__snapshots__/ChatReasoning-vue.spec.ts.snap @@ -0,0 +1,146 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`ChatReasoning > renders with body slot correctly 1`] = ` +"
+
+
Body slot content
+
+
" +`; + +exports[`ChatReasoning > renders with class correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with default slot correctly 1`] = ` +"
+
+
Default slot content
+
+
" +`; + +exports[`ChatReasoning > renders with defaultOpen correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with disabled correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with duration correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with getThinkingMessage correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with icon correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with isStreaming correctly 1`] = ` +"
+
+
This is the reasoning content.
+
+
" +`; + +exports[`ChatReasoning > renders with open correctly 1`] = ` +"
+
+
This is the reasoning content.
+
+
" +`; + +exports[`ChatReasoning > renders with text correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with thinkingMessage slot correctly 1`] = ` +"
+
+
This is the reasoning content.
+
+
" +`; + +exports[`ChatReasoning > renders with trailingIcon correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with trigger slot correctly 1`] = ` +"
Custom trigger +
" +`; + +exports[`ChatReasoning > renders with ui correctly 1`] = ` +"
+ +
" +`; diff --git a/test/components/__snapshots__/ChatReasoning.spec.ts.snap b/test/components/__snapshots__/ChatReasoning.spec.ts.snap new file mode 100644 index 0000000000..c2374d8425 --- /dev/null +++ b/test/components/__snapshots__/ChatReasoning.spec.ts.snap @@ -0,0 +1,146 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`ChatReasoning > renders with body slot correctly 1`] = ` +"
+
+
Body slot content
+
+
" +`; + +exports[`ChatReasoning > renders with class correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with default slot correctly 1`] = ` +"
+
+
Default slot content
+
+
" +`; + +exports[`ChatReasoning > renders with defaultOpen correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with disabled correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with duration correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with getThinkingMessage correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with icon correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with isStreaming correctly 1`] = ` +"
+
+
This is the reasoning content.
+
+
" +`; + +exports[`ChatReasoning > renders with open correctly 1`] = ` +"
+
+
This is the reasoning content.
+
+
" +`; + +exports[`ChatReasoning > renders with text correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with thinkingMessage slot correctly 1`] = ` +"
+
+
This is the reasoning content.
+
+
" +`; + +exports[`ChatReasoning > renders with trailingIcon correctly 1`] = ` +"
+ +
" +`; + +exports[`ChatReasoning > renders with trigger slot correctly 1`] = ` +"
Custom trigger +
" +`; + +exports[`ChatReasoning > renders with ui correctly 1`] = ` +"
+ +
" +`; diff --git a/test/components/__snapshots__/ChatShimmer-vue.spec.ts.snap b/test/components/__snapshots__/ChatShimmer-vue.spec.ts.snap new file mode 100644 index 0000000000..18c0270fc7 --- /dev/null +++ b/test/components/__snapshots__/ChatShimmer-vue.spec.ts.snap @@ -0,0 +1,13 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`ChatShimmer > renders with as correctly 1`] = `"
Loading...
"`; + +exports[`ChatShimmer > renders with class correctly 1`] = `"Loading..."`; + +exports[`ChatShimmer > renders with duration correctly 1`] = `"Loading..."`; + +exports[`ChatShimmer > renders with spread correctly 1`] = `"Loading..."`; + +exports[`ChatShimmer > renders with text correctly 1`] = `"Loading..."`; + +exports[`ChatShimmer > renders with ui correctly 1`] = `"Loading..."`; diff --git a/test/components/__snapshots__/ChatShimmer.spec.ts.snap b/test/components/__snapshots__/ChatShimmer.spec.ts.snap new file mode 100644 index 0000000000..18c0270fc7 --- /dev/null +++ b/test/components/__snapshots__/ChatShimmer.spec.ts.snap @@ -0,0 +1,13 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`ChatShimmer > renders with as correctly 1`] = `"
Loading...
"`; + +exports[`ChatShimmer > renders with class correctly 1`] = `"Loading..."`; + +exports[`ChatShimmer > renders with duration correctly 1`] = `"Loading..."`; + +exports[`ChatShimmer > renders with spread correctly 1`] = `"Loading..."`; + +exports[`ChatShimmer > renders with text correctly 1`] = `"Loading..."`; + +exports[`ChatShimmer > renders with ui correctly 1`] = `"Loading..."`;