💄 style: Update agent onboarding style (#13678)

* 💄 style: Update onboarding

* style: update

* 💄 style: Update i18n

* fix: test
This commit is contained in:
CanisMinor 2026-04-10 10:44:09 +08:00 committed by GitHub
parent 5f25efd54c
commit 4787bed380
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 905 additions and 496 deletions

View file

@ -1,6 +1,6 @@
const { defineConfig } = require('@lobehub/i18n-cli');
const fs = require('fs');
const path = require('path');
const fs = require('node:fs');
const path = require('node:path');
module.exports = defineConfig({
entry: 'locales/en-US',
@ -27,14 +27,14 @@ module.exports = defineConfig({
],
temperature: 0,
saveImmediately: true,
modelName: 'chatgpt-4o-latest',
modelName: 'gpt-5.1-chat-latest',
experimental: {
jsonMode: true,
},
markdown: {
reference:
'You need to maintain the component format of the mdx file; the output text does not need to be wrapped in any code block syntax on the outermost layer.\n' +
fs.readFileSync(path.join(__dirname, 'docs/glossary.md'), 'utf-8'),
fs.readFileSync(path.join(__dirname, 'docs/glossary.md'), 'utf8'),
entry: ['./README.md', './docs/**/*.md', './docs/**/*.mdx'],
entryLocale: 'en-US',
outputLocales: ['zh-CN'],

View file

@ -40,6 +40,7 @@ export default eslint(
// AI coding tools directories
'.claude',
'.serena',
'.i18nrc.js',
],
next: true,
react: 'next',

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "تسجيل وكيل",
"agent.completionSubtitle": "تم إعداد مساعدك وهو جاهز للعمل.",
"agent.completionTitle": "تم الإعداد بالكامل!",
"agent.enterApp": "دخول التطبيق",
"agent.completion.sentence.readyWhenYouAre": "جاهز متى شئت :)",
"agent.completion.sentence.readyWithName": "{{name}} هنا - أنا جاهز!",
"agent.completionSubtitle": "كل شيء جاهز - لنبدأ عندما تكون مستعدًا.",
"agent.completionTitle": "أنت على وشك الانتهاء",
"agent.enterApp": "أنا جاهز",
"agent.greeting.emojiLabel": "رمز تعبيري",
"agent.greeting.nameLabel": "الاسم",
"agent.greeting.namePlaceholder": "مثلًا: لومي، أطلس، نيكو...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "مثلًا: دافئ وودود، حاد ومباشر...",
"agent.history.current": "الحالي",
"agent.history.title": "مواضيع السجل",
"agent.layout.mode.agent": "وضع الوكيل",
"agent.layout.mode.classic": "الوضع الكلاسيكي",
"agent.layout.skip": "تخطي هذه الخطوة",
"agent.layout.skipConfirm.content": "هل ترغب في المغادرة الآن؟ أستطيع مساعدتك في تخصيص الأمور خلال ثوانٍ.",
"agent.layout.skipConfirm.ok": "تخطي الآن",
"agent.layout.skipConfirm.title": "تخطي الإعداد الآن؟",
"agent.layout.switchMessage": "لست في مزاج لذلك اليوم؟ يمكنك التبديل إلى <modeLink><modeText>{{mode}}</modeText></modeLink> أو <skipLink><skipText>{{skip}}</skipText></skipLink>.",
"agent.modeSwitch.agent": "تفاعلي",
"agent.modeSwitch.classic": "كلاسيكي",
"agent.modeSwitch.debug": "تصدير التصحيح",
"agent.modeSwitch.label": "اختر وضع التسجيل",
"agent.modeSwitch.reset": "إعادة ضبط التدفق",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "تخطي التسجيل",
"agent.stage.agentIdentity": "هوية الوكيل",
"agent.stage.painPoints": "نقاط الألم",
"agent.stage.proSettings": "الإعدادات المتقدمة",
@ -33,6 +41,16 @@
"agent.telemetryHint": "يمكنك أيضًا الإجابة بكلماتك الخاصة.",
"agent.title": "تسجيل المحادثة",
"agent.welcome": "...هم؟ لقد استيقظت للتو — ذهني فارغ. من أنت؟ وأيضًا — ماذا يجب أن يُطلق علي؟ أحتاج إلى اسم أيضًا.",
"agent.welcome.footer": "قم بتكوين وكيل Lobe AI الخاص بك. يعمل على خادمك، ويتعلم من كل تفاعل، ويصبح أقوى كلما استمر في العمل.",
"agent.welcome.guide.growTogether.desc": "مع كل محادثة، سأفهمك بشكل أفضل وأصبح زميلًا أقوى مع مرور الوقت.",
"agent.welcome.guide.growTogether.title": "النمو معك",
"agent.welcome.guide.knowYou.desc": "ما الذي يشغل بالك هذه الأيام؟ القليل من السياق يساعدني في دعمك بشكل أفضل.",
"agent.welcome.guide.knowYou.title": "التعرف عليك",
"agent.welcome.guide.name.desc": "امنحني اسمًا ليكون الأمر أكثر شخصية منذ البداية.",
"agent.welcome.guide.name.title": "امنحني اسمًا",
"agent.welcome.sentence.1": "سررت بلقائك! دعنا نتعرّف على بعض.",
"agent.welcome.sentence.2": "ما نوع الشريك الذي تريدني أن أكونه؟",
"agent.welcome.sentence.3": "أولًا، اختر لي اسمًا :)",
"back": "رجوع",
"finish": "ابدأ الآن",
"interests.area.business": "الأعمال والاستراتيجية",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "Въвеждане на агент",
"agent.completionSubtitle": "Вашият асистент е конфигуриран и готов за работа.",
"agent.completionTitle": "Всичко е готово!",
"agent.enterApp": "Влезте в приложението",
"agent.completion.sentence.readyWhenYouAre": "На разположение съм, когато сте готови :)",
"agent.completion.sentence.readyWithName": "{{name}} тук — готов/а!",
"agent.completionSubtitle": "Всичко е на място — нека започнем, когато си готов.",
"agent.completionTitle": "Почти сте готови",
"agent.enterApp": "Готов съм",
"agent.greeting.emojiLabel": "Емоджи",
"agent.greeting.nameLabel": "Име",
"agent.greeting.namePlaceholder": "напр. Луми, Атлас, Неко...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "напр. Топло и приятелско, Остро и директно...",
"agent.history.current": "Текущо",
"agent.history.title": "История на темите",
"agent.layout.mode.agent": "Агентски режим",
"agent.layout.mode.classic": "Класически режим",
"agent.layout.skip": "Пропуснете тази стъпка",
"agent.layout.skipConfirm.content": "Вече ли тръгвате? Мога за секунди да ви помогна да персонализирате нещата.",
"agent.layout.skipConfirm.ok": "Пропуснете засега",
"agent.layout.skipConfirm.title": "Да пропуснете въвеждането засега?",
"agent.layout.switchMessage": "Не сте в настроение днес? Можете да преминете в <modeLink><modeText>{{mode}}</modeText></modeLink> или да <skipLink><skipText>{{skip}}</skipText></skipLink>.",
"agent.modeSwitch.agent": "Разговорен",
"agent.modeSwitch.classic": "Класически",
"agent.modeSwitch.debug": "Експорт за отстраняване на грешки",
"agent.modeSwitch.label": "Изберете режим за въвеждане",
"agent.modeSwitch.reset": "Нулиране на процеса",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "Пропуснете въвеждането",
"agent.stage.agentIdentity": "Идентичност на агента",
"agent.stage.painPoints": "Трудности",
"agent.stage.proSettings": "Разширени настройки",
@ -33,6 +41,16 @@
"agent.telemetryHint": "Можете също да отговорите със свои думи.",
"agent.title": "Разговорно въвеждане",
"agent.welcome": "...хм? Току-що се събудих — умът ми е празен. Кой сте вие? И — какво име да ми дадете? Имам нужда и от име.",
"agent.welcome.footer": "Настройте своя Lobe AI агент. Той работи на вашия сървър, учи се от всяко взаимодействие и става по-мощен, колкото по-дълго работи.",
"agent.welcome.guide.growTogether.desc": "С всяка беседа ще те опознавам по-добре и с времето ще ставам все по-надежден партньор.",
"agent.welcome.guide.growTogether.title": "Растем заедно",
"agent.welcome.guide.knowYou.desc": "Какво имаш за вършене напоследък? Малко контекст ще ми помогне да те подкрепя по-добре.",
"agent.welcome.guide.knowYou.title": "Да те опозная",
"agent.welcome.guide.name.desc": "Дай ми име, за да звучи по-лично от самото начало.",
"agent.welcome.guide.name.title": "Дай ми име",
"agent.welcome.sentence.1": "Радвам се да се запознаем! Нека се опознаем по-добре.",
"agent.welcome.sentence.2": "Какъв тип партньор искаш да бъда?",
"agent.welcome.sentence.3": "Първо, дай ми име :)",
"back": "Назад",
"finish": "Да започнем",
"interests.area.business": "Бизнес и стратегия",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "Agent-Einführung",
"agent.completionSubtitle": "Ihr Assistent ist konfiguriert und einsatzbereit.",
"agent.completionTitle": "Alles erledigt!",
"agent.enterApp": "App betreten",
"agent.completion.sentence.readyWhenYouAre": "Bereit, wenn du es bist :)",
"agent.completion.sentence.readyWithName": "{{name}} hier ich bin bereit!",
"agent.completionSubtitle": "Alles ist vorbereitet wir können loslegen, sobald du soweit bist.",
"agent.completionTitle": "Du bist fast am Ziel",
"agent.enterApp": "Ich bin bereit",
"agent.greeting.emojiLabel": "Emoji",
"agent.greeting.nameLabel": "Name",
"agent.greeting.namePlaceholder": "z. B. Lumi, Atlas, Neko...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "z. B. Warm & freundlich, Scharf & direkt...",
"agent.history.current": "Aktuell",
"agent.history.title": "Verlaufsthemen",
"agent.layout.mode.agent": "Agentenmodus",
"agent.layout.mode.classic": "Klassischer Modus",
"agent.layout.skip": "Diesen Schritt überspringen",
"agent.layout.skipConfirm.content": "Gehst du schon? Ich könnte dir in wenigen Sekunden helfen, alles zu personalisieren.",
"agent.layout.skipConfirm.ok": "Für jetzt überspringen",
"agent.layout.skipConfirm.title": "Onboarding jetzt überspringen?",
"agent.layout.switchMessage": "Heute nicht so in Stimmung? Du kannst zum <modeLink><modeText>{{mode}}</modeText></modeLink> wechseln oder <skipLink><skipText>{{skip}}</skipText></skipLink>.",
"agent.modeSwitch.agent": "Konversation",
"agent.modeSwitch.classic": "Klassisch",
"agent.modeSwitch.debug": "Debug-Export",
"agent.modeSwitch.label": "Wählen Sie Ihren Einführungsmodus",
"agent.modeSwitch.reset": "Flow zurücksetzen",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "Einführung überspringen",
"agent.stage.agentIdentity": "Agentenidentität",
"agent.stage.painPoints": "Schmerzpunkte",
"agent.stage.proSettings": "Erweiterte Einstellungen",
@ -33,6 +41,16 @@
"agent.telemetryHint": "Sie können auch in Ihren eigenen Worten antworten.",
"agent.title": "Konversations-Einführung",
"agent.welcome": "...hm? Ich bin gerade aufgewacht mein Kopf ist leer. Wer sind Sie? Und wie soll ich heißen? Ich brauche auch einen Namen.",
"agent.welcome.footer": "Konfiguriere deinen Lobe AI Agent. Er läuft auf deinem Server, lernt aus jeder Interaktion und wird mit der Zeit immer leistungsfähiger.",
"agent.welcome.guide.growTogether.desc": "Mit jedem Gespräch verstehe ich dich besser und werde nach und nach ein stärkerer Teamplayer.",
"agent.welcome.guide.growTogether.title": "Gemeinsam wachsen",
"agent.welcome.guide.knowYou.desc": "Woran arbeitest du zurzeit? Ein wenig Kontext hilft mir, dich besser zu unterstützen.",
"agent.welcome.guide.knowYou.title": "Dich kennenlernen",
"agent.welcome.guide.name.desc": "Gib mir einen Namen, damit sich alles von Anfang an persönlicher anfühlt.",
"agent.welcome.guide.name.title": "Gib mir einen Namen",
"agent.welcome.sentence.1": "Sehr schön, dich kennenzulernen! Lass uns einander besser kennenlernen.",
"agent.welcome.sentence.2": "Welche Art von Partner soll ich für dich sein?",
"agent.welcome.sentence.3": "Gib mir zuerst einen Namen :)",
"back": "Zurück",
"finish": "Los gehts",
"interests.area.business": "Geschäft & Strategie",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "Agent Onboarding",
"agent.completionSubtitle": "Your assistant is configured and ready to go.",
"agent.completionTitle": "You're All Set!",
"agent.enterApp": "Enter App",
"agent.completion.sentence.readyWhenYouAre": "Ready when you are :)",
"agent.completion.sentence.readyWithName": "{{name}} here - I'm ready!",
"agent.completionSubtitle": "Everything's in place - let's get started when you're ready.",
"agent.completionTitle": "You are almost there",
"agent.enterApp": "I'm ready",
"agent.greeting.emojiLabel": "Emoji",
"agent.greeting.nameLabel": "Name",
"agent.greeting.namePlaceholder": "e.g. Lumi, Atlas, Neko...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "e.g. Warm & friendly, Sharp & direct...",
"agent.history.current": "Current",
"agent.history.title": "History Topics",
"agent.layout.mode.agent": "agent mode",
"agent.layout.mode.classic": "classic mode",
"agent.layout.skip": "skip this step",
"agent.layout.skipConfirm.content": "Leaving already? I could help personalize things for you in seconds.",
"agent.layout.skipConfirm.ok": "Skip for now",
"agent.layout.skipConfirm.title": "Skip onboarding for now?",
"agent.layout.switchMessage": "Not feeling it today? You can switch to <modeLink><modeText>{{mode}}</modeText></modeLink> or <skipLink><skipText>{{skip}}</skipText></skipLink>.",
"agent.modeSwitch.agent": "Conversational",
"agent.modeSwitch.classic": "Classic",
"agent.modeSwitch.debug": "Debug Export",
"agent.modeSwitch.label": "Choose your onboarding mode",
"agent.modeSwitch.reset": "Reset Flow",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "Skip onboarding",
"agent.stage.agentIdentity": "Agent Identity",
"agent.stage.painPoints": "Pain Points",
"agent.stage.proSettings": "Advanced Setup",
@ -33,6 +41,16 @@
"agent.telemetryHint": "You can also answer in your own words.",
"agent.title": "Conversation Onboarding",
"agent.welcome": "...hm? I just woke up — my mind's a blank. Who are you? And — what should I be called? I need a name too.",
"agent.welcome.footer": "Configure your Lobe AI Agent. It lives on your server, learns from every interaction, and becomes more powerful the longer it runs.",
"agent.welcome.guide.growTogether.desc": "With each chat, I'll understand you better and become a stronger teammate over time.",
"agent.welcome.guide.growTogether.title": "Grow with You",
"agent.welcome.guide.knowYou.desc": "What's on your plate these days? A little context helps me support you better.",
"agent.welcome.guide.knowYou.title": "Get to Know You",
"agent.welcome.guide.name.desc": "Give me a name so this feels more personal from the start.",
"agent.welcome.guide.name.title": "Name Me",
"agent.welcome.sentence.1": "So nice to meet you! Lets get to know each other.",
"agent.welcome.sentence.2": "What kind of partner do you want me to be?",
"agent.welcome.sentence.3": "First, give me a name :)",
"back": "Back",
"finish": "Get Started",
"interests.area.business": "Business & Strategy",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "Incorporación del Agente",
"agent.completionSubtitle": "Tu asistente está configurado y listo para comenzar.",
"agent.completionTitle": "¡Todo Listo!",
"agent.enterApp": "Entrar a la Aplicación",
"agent.completion.sentence.readyWhenYouAre": "Cuando tú digas :)",
"agent.completion.sentence.readyWithName": "Aquí {{name}} — ¡listo cuando tú quieras!",
"agent.completionSubtitle": "Todo está listo. Empecemos cuando te venga bien.",
"agent.completionTitle": "Ya casi lo tienes",
"agent.enterApp": "Estoy listo",
"agent.greeting.emojiLabel": "Emoji",
"agent.greeting.nameLabel": "Nombre",
"agent.greeting.namePlaceholder": "p. ej. Lumi, Atlas, Neko...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "p. ej. Cálido y amigable, Directo y preciso...",
"agent.history.current": "Actual",
"agent.history.title": "Temas del Historial",
"agent.layout.mode.agent": "modo agente",
"agent.layout.mode.classic": "modo clásico",
"agent.layout.skip": "omitir este paso",
"agent.layout.skipConfirm.content": "¿Ya te vas? Puedo ayudarte a personalizar todo en solo unos segundos.",
"agent.layout.skipConfirm.ok": "Omitir por ahora",
"agent.layout.skipConfirm.title": "¿Omitir la configuración inicial por ahora?",
"agent.layout.switchMessage": "¿No te convence hoy? Puedes cambiar a <modeLink><modeText>{{mode}}</modeText></modeLink> o <skipLink><skipText>{{skip}}</skipText></skipLink>.",
"agent.modeSwitch.agent": "Conversacional",
"agent.modeSwitch.classic": "Clásico",
"agent.modeSwitch.debug": "Exportar Depuración",
"agent.modeSwitch.label": "Elige tu modo de incorporación",
"agent.modeSwitch.reset": "Reiniciar Flujo",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "Omitir incorporación",
"agent.stage.agentIdentity": "Identidad del Agente",
"agent.stage.painPoints": "Puntos Problemáticos",
"agent.stage.proSettings": "Configuración Avanzada",
@ -33,6 +41,16 @@
"agent.telemetryHint": "También puedes responder con tus propias palabras.",
"agent.title": "Incorporación Conversacional",
"agent.welcome": "...¿hm? Acabo de despertar — mi mente está en blanco. ¿Quién eres? Y — ¿cómo debería llamarme? También necesito un nombre.",
"agent.welcome.footer": "Configura tu Lobe AI Agent. Vive en tu servidor, aprende de cada interacción y se vuelve más potente cuanto más tiempo funciona.",
"agent.welcome.guide.growTogether.desc": "Con cada conversación, te comprenderé mejor y me convertiré en un compañero más sólido con el tiempo.",
"agent.welcome.guide.growTogether.title": "Crecer contigo",
"agent.welcome.guide.knowYou.desc": "¿Qué tienes entre manos estos días? Un poco de contexto me ayuda a apoyarte mejor.",
"agent.welcome.guide.knowYou.title": "Conocerte",
"agent.welcome.guide.name.desc": "Dame un nombre para que todo se sienta más personal desde el principio.",
"agent.welcome.guide.name.title": "Ponme un nombre",
"agent.welcome.sentence.1": "¡Qué gusto conocerte! Vamos a conocernos mejor.",
"agent.welcome.sentence.2": "¿Qué tipo de compañero quieres que sea?",
"agent.welcome.sentence.3": "Primero, dame un nombre :)",
"back": "Volver",
"finish": "Comenzar",
"interests.area.business": "Negocios y Estrategia",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "آموزش نماینده",
"agent.completionSubtitle": "دستیار شما تنظیم شده و آماده استفاده است.",
"agent.completionTitle": "همه چیز آماده است!",
"agent.enterApp": "ورود به برنامه",
"agent.completion.sentence.readyWhenYouAre": "هر وقت آماده بودی :)",
"agent.completion.sentence.readyWithName": "{{name}} اینجاست - من آماده‌ام!",
"agent.completionSubtitle": "همه‌چیز مهیاست - هر وقت آماده بودی شروع می‌کنیم.",
"agent.completionTitle": "تقریباً تمام شد",
"agent.enterApp": "آماده‌ام",
"agent.greeting.emojiLabel": "ایموجی",
"agent.greeting.nameLabel": "نام",
"agent.greeting.namePlaceholder": "مثلاً لومی، اطلس، نکو...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "مثلاً گرم و دوستانه، تیز و مستقیم...",
"agent.history.current": "فعلی",
"agent.history.title": "موضوعات تاریخچه",
"agent.layout.mode.agent": "حالت ایجنت",
"agent.layout.mode.classic": "حالت کلاسیک",
"agent.layout.skip": "رد کردن این مرحله",
"agent.layout.skipConfirm.content": "می‌خوای همین حالا بری؟ می‌تونم در چند ثانیه همه‌چیز رو برات شخصی‌سازی کنم.",
"agent.layout.skipConfirm.ok": "فعلاً رد کن",
"agent.layout.skipConfirm.title": "فعلاً از راه‌اندازی اولیه رد می‌شی؟",
"agent.layout.switchMessage": "امروز حال و هواشو نداری؟ می‌تونی به <modeLink><modeText>{{mode}}</modeText></modeLink> یا <skipLink><skipText>{{skip}}</skipText></skipLink> تغییر بدی.",
"agent.modeSwitch.agent": "مکالمه‌ای",
"agent.modeSwitch.classic": "کلاسیک",
"agent.modeSwitch.debug": "صادرات اشکال‌زدایی",
"agent.modeSwitch.label": "حالت آموزش خود را انتخاب کنید",
"agent.modeSwitch.reset": "بازنشانی جریان",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "رد کردن آموزش",
"agent.stage.agentIdentity": "هویت نماینده",
"agent.stage.painPoints": "نقاط ضعف",
"agent.stage.proSettings": "تنظیمات پیشرفته",
@ -33,6 +41,16 @@
"agent.telemetryHint": "همچنین می‌توانید با کلمات خود پاسخ دهید.",
"agent.title": "آموزش مکالمه",
"agent.welcome": "...هم؟ تازه بیدار شدم — ذهنم خالیه. شما کی هستید؟ و — چه نامی باید داشته باشم؟ من هم به یک نام نیاز دارم.",
"agent.welcome.footer": "ایجنت Lobe AI خودت را تنظیم کن. روی سرور تو اجرا می‌شود، از هر تعامل یاد می‌گیرد و هرچه بیشتر کار کند قدرتمندتر می‌شود.",
"agent.welcome.guide.growTogether.desc": "با هر گفتگو، بهتر می‌فهممت و کم‌کم همراه قوی‌تری برایت می‌شوم.",
"agent.welcome.guide.growTogether.title": "با تو رشد می‌کنم",
"agent.welcome.guide.knowYou.desc": "این روزها درگیر چه کارهایی هستی؟ کمی زمینه کمکم می‌کند بهتر همراهت باشم.",
"agent.welcome.guide.knowYou.title": "آشنایی با تو",
"agent.welcome.guide.name.desc": "برای اینکه از همان اول حس صمیمی‌تری داشته باشیم، یک اسم برای من انتخاب کن.",
"agent.welcome.guide.name.title": "اسم من را انتخاب کن",
"agent.welcome.sentence.1": "از آشنایی با تو خوشحالم! بیاییم همدیگر را بهتر بشناسیم.",
"agent.welcome.sentence.2": "می‌خواهی چه نوع همراهی برایت باشم؟",
"agent.welcome.sentence.3": "اول از همه، یک اسم برای من بگذار :)",
"back": "بازگشت",
"finish": "شروع کن",
"interests.area.business": "کسب‌وکار و استراتژی",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "Intégration de l'agent",
"agent.completionSubtitle": "Votre assistant est configuré et prêt à l'emploi.",
"agent.completionTitle": "Tout est prêt !",
"agent.enterApp": "Entrer dans l'application",
"agent.completion.sentence.readyWhenYouAre": "Prêt quand vous l'êtes :)",
"agent.completion.sentence.readyWithName": "{{name}} ici — je suis prêt !",
"agent.completionSubtitle": "Tout est en place — commençons quand vous le souhaitez.",
"agent.completionTitle": "Vous y êtes presque",
"agent.enterApp": "Je suis prêt",
"agent.greeting.emojiLabel": "Émoji",
"agent.greeting.nameLabel": "Nom",
"agent.greeting.namePlaceholder": "par ex. Lumi, Atlas, Neko...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "par ex. Chaleureux et amical, Franc et direct...",
"agent.history.current": "Actuel",
"agent.history.title": "Sujets historiques",
"agent.layout.mode.agent": "mode agent",
"agent.layout.mode.classic": "mode classique",
"agent.layout.skip": "passer cette étape",
"agent.layout.skipConfirm.content": "Vous partez déjà ? Je peux personnaliser les choses pour vous en quelques secondes.",
"agent.layout.skipConfirm.ok": "Passer pour le moment",
"agent.layout.skipConfirm.title": "Passer l'initialisation pour l'instant ?",
"agent.layout.switchMessage": "Pas d'humeur aujourd'hui ? Vous pouvez passer en <modeLink><modeText>{{mode}}</modeText></modeLink> ou <skipLink><skipText>{{skip}}</skipText></skipLink>.",
"agent.modeSwitch.agent": "Conversationnel",
"agent.modeSwitch.classic": "Classique",
"agent.modeSwitch.debug": "Exportation de débogage",
"agent.modeSwitch.label": "Choisissez votre mode d'intégration",
"agent.modeSwitch.reset": "Réinitialiser le processus",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "Passer l'intégration",
"agent.stage.agentIdentity": "Identité de l'agent",
"agent.stage.painPoints": "Points sensibles",
"agent.stage.proSettings": "Configuration avancée",
@ -33,6 +41,16 @@
"agent.telemetryHint": "Vous pouvez également répondre avec vos propres mots.",
"agent.title": "Intégration par conversation",
"agent.welcome": "...hm ? Je viens de me réveiller — mon esprit est vide. Qui êtes-vous ? Et — comment devrais-je m'appeler ? J'ai besoin d'un nom aussi.",
"agent.welcome.footer": "Configurez votre agent Lobe AI. Il fonctionne sur votre serveur, apprend à chaque interaction et devient plus performant au fil du temps.",
"agent.welcome.guide.growTogether.desc": "À chaque discussion, je vous comprendrai mieux et, avec le temps, je deviendrai un coéquipier plus efficace.",
"agent.welcome.guide.growTogether.title": "Évoluer avec vous",
"agent.welcome.guide.knowYou.desc": "Qu'avez-vous au programme ces temps-ci ? Un peu de contexte m'aidera à mieux vous assister.",
"agent.welcome.guide.knowYou.title": "Mieux vous connaître",
"agent.welcome.guide.name.desc": "Donnez-moi un nom pour que cela paraisse plus personnalisé dès le départ.",
"agent.welcome.guide.name.title": "Donnez-moi un nom",
"agent.welcome.sentence.1": "Ravi de vous rencontrer ! Faisons connaissance.",
"agent.welcome.sentence.2": "Quel type de partenaire voulez-vous que je sois ?",
"agent.welcome.sentence.3": "D'abord, donnez-moi un nom :)",
"back": "Retour",
"finish": "Commencer",
"interests.area.business": "Affaires & Stratégie",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "Introduzione Agente",
"agent.completionSubtitle": "Il tuo assistente è configurato e pronto all'uso.",
"agent.completionTitle": "Tutto Pronto!",
"agent.enterApp": "Accedi all'App",
"agent.completion.sentence.readyWhenYouAre": "Quando sei pronto :)",
"agent.completion.sentence.readyWithName": "{{name}} qui - sono pronto!",
"agent.completionSubtitle": "È tutto pronto: iniziamo quando vuoi.",
"agent.completionTitle": "Ci sei quasi",
"agent.enterApp": "Sono pronto",
"agent.greeting.emojiLabel": "Emoji",
"agent.greeting.nameLabel": "Nome",
"agent.greeting.namePlaceholder": "es. Lumi, Atlas, Neko...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "es. Caldo e amichevole, Tagliente e diretto...",
"agent.history.current": "Corrente",
"agent.history.title": "Argomenti della Cronologia",
"agent.layout.mode.agent": "modalità agente",
"agent.layout.mode.classic": "modalità classica",
"agent.layout.skip": "salta questo passaggio",
"agent.layout.skipConfirm.content": "Vai già via? Posso aiutarti a personalizzare tutto in pochi secondi.",
"agent.layout.skipConfirm.ok": "Salta per ora",
"agent.layout.skipConfirm.title": "Saltare lonboarding per ora?",
"agent.layout.switchMessage": "Non è giornata? Puoi passare a <modeLink><modeText>{{mode}}</modeText></modeLink> oppure a <skipLink><skipText>{{skip}}</skipText></skipLink>.",
"agent.modeSwitch.agent": "Conversazionale",
"agent.modeSwitch.classic": "Classico",
"agent.modeSwitch.debug": "Esportazione Debug",
"agent.modeSwitch.label": "Scegli la modalità di introduzione",
"agent.modeSwitch.reset": "Reimposta Flusso",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "Salta introduzione",
"agent.stage.agentIdentity": "Identità dell'Agente",
"agent.stage.painPoints": "Punti Critici",
"agent.stage.proSettings": "Configurazione Avanzata",
@ -33,6 +41,16 @@
"agent.telemetryHint": "Puoi anche rispondere con le tue parole.",
"agent.title": "Introduzione Conversazionale",
"agent.welcome": "...ehm? Mi sono appena svegliato — la mia mente è vuota. Chi sei? E — come dovrei chiamarmi? Ho bisogno di un nome anch'io.",
"agent.welcome.footer": "Configura il tuo Lobe AI Agent. Vive sul tuo server, impara da ogni interazione e diventa più potente con il tempo.",
"agent.welcome.guide.growTogether.desc": "Con ogni conversazione ti capirò meglio e diventerò un alleato sempre più forte.",
"agent.welcome.guide.growTogether.title": "Crescere Insieme",
"agent.welcome.guide.knowYou.desc": "Di cosa ti occupi ultimamente? Un po di contesto mi aiuta a supportarti meglio.",
"agent.welcome.guide.knowYou.title": "Conoscerti",
"agent.welcome.guide.name.desc": "Dammi un nome così tutto sembrerà più personale fin dallinizio.",
"agent.welcome.guide.name.title": "Dammi un Nome",
"agent.welcome.sentence.1": "Che bello conoscerti! Cominciamo a conoscerci meglio.",
"agent.welcome.sentence.2": "Che tipo di partner vuoi che io sia?",
"agent.welcome.sentence.3": "Per iniziare, dammi un nome :)",
"back": "Indietro",
"finish": "Inizia",
"interests.area.business": "Business e Strategia",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "エージェントオンボーディング",
"agent.completionSubtitle": "アシスタントの設定が完了し、準備が整いました。",
"agent.completionTitle": "準備完了!",
"agent.enterApp": "アプリに入る",
"agent.completion.sentence.readyWhenYouAre": "準備ができたらいつでもどうぞ :)",
"agent.completion.sentence.readyWithName": "{{name}}です。準備できています!",
"agent.completionSubtitle": "準備は整っています。ご都合の良いときに始めましょう。",
"agent.completionTitle": "もう少しで完了です",
"agent.enterApp": "準備できました",
"agent.greeting.emojiLabel": "絵文字",
"agent.greeting.nameLabel": "名前",
"agent.greeting.namePlaceholder": "例: ルミ、アトラス、ネコ...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "例: 温かくフレンドリー、鋭く直接的...",
"agent.history.current": "現在",
"agent.history.title": "履歴トピック",
"agent.layout.mode.agent": "エージェントモード",
"agent.layout.mode.classic": "クラシックモード",
"agent.layout.skip": "このステップをスキップ",
"agent.layout.skipConfirm.content": "もう離れますか?数秒であなた向けにカスタマイズできますよ。",
"agent.layout.skipConfirm.ok": "とりあえずスキップ",
"agent.layout.skipConfirm.title": "オンボーディングを今はスキップしますか?",
"agent.layout.switchMessage": "今日は気分が乗らないですか?<modeLink><modeText>{{mode}}</modeText></modeLink>か<skipLink><skipText>{{skip}}</skipText></skipLink>に切り替えられます。",
"agent.modeSwitch.agent": "会話モード",
"agent.modeSwitch.classic": "クラシック",
"agent.modeSwitch.debug": "デバッグエクスポート",
"agent.modeSwitch.label": "オンボーディングモードを選択",
"agent.modeSwitch.reset": "フローをリセット",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "オンボーディングをスキップ",
"agent.stage.agentIdentity": "エージェントのアイデンティティ",
"agent.stage.painPoints": "課題",
"agent.stage.proSettings": "高度な設定",
@ -33,6 +41,16 @@
"agent.telemetryHint": "独自の言葉で答えることもできます。",
"agent.title": "会話型オンボーディング",
"agent.welcome": "...ん?今起きたばかりで、頭が真っ白です。あなたは誰ですか?それと、私の名前は何にしますか?",
"agent.welcome.footer": "あなたの Lobe AI エージェントを設定してください。エージェントはあなたのサーバー上で稼働し、すべてのやり取りから学習し、稼働時間が長くなるほどより高性能になります。",
"agent.welcome.guide.growTogether.desc": "チャットを重ねるごとにあなたのことをより理解し、時間とともに頼れる仲間になります。",
"agent.welcome.guide.growTogether.title": "一緒に成長",
"agent.welcome.guide.knowYou.desc": "最近何に取り組んでいますか?少し背景を教えていただければ、より適切にサポートできます。",
"agent.welcome.guide.knowYou.title": "あなたのことを知る",
"agent.welcome.guide.name.desc": "最初からもっと親しみやすくするために、私に名前を付けてください。",
"agent.welcome.guide.name.title": "名前をつけて",
"agent.welcome.sentence.1": "はじめまして!まずはお互いを知りましょう。",
"agent.welcome.sentence.2": "どんなパートナーでいてほしいですか?",
"agent.welcome.sentence.3": "まずは私に名前を付けてください :)",
"back": "前へ",
"finish": "使い始める",
"interests.area.business": "ビジネスと戦略",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "에이전트 온보딩",
"agent.completionSubtitle": "당신의 어시스턴트가 설정되어 준비되었습니다.",
"agent.completionTitle": "모든 준비가 완료되었습니다!",
"agent.enterApp": "앱으로 들어가기",
"agent.completion.sentence.readyWhenYouAre": "준비되시면 말씀하세요 :)",
"agent.completion.sentence.readyWithName": "{{name}}입니다 — 준비됐어요!",
"agent.completionSubtitle": "모든 준비가 완료되었습니다 — 준비되시면 시작해요.",
"agent.completionTitle": "거의 다 왔어요",
"agent.enterApp": "준비됐어요",
"agent.greeting.emojiLabel": "이모지",
"agent.greeting.nameLabel": "이름",
"agent.greeting.namePlaceholder": "예: 루미, 아틀라스, 네코...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "예: 따뜻하고 친근한, 날카롭고 직설적인...",
"agent.history.current": "현재",
"agent.history.title": "히스토리 주제",
"agent.layout.mode.agent": "에이전트 모드",
"agent.layout.mode.classic": "클래식 모드",
"agent.layout.skip": "이 단계 건너뛰기",
"agent.layout.skipConfirm.content": "벌써 나가시려나요? 몇 초면 개인화 설정을 도와드릴게요.",
"agent.layout.skipConfirm.ok": "일단 건너뛰기",
"agent.layout.skipConfirm.title": "지금 온보딩을 건너뛰시겠어요?",
"agent.layout.switchMessage": "오늘은 기분이 아니신가요? <modeLink><modeText>{{mode}}</modeText></modeLink>로 전환하거나 <skipLink><skipText>{{skip}}</skipText></skipLink>하실 수 있어요.",
"agent.modeSwitch.agent": "대화형",
"agent.modeSwitch.classic": "클래식",
"agent.modeSwitch.debug": "디버그 내보내기",
"agent.modeSwitch.label": "온보딩 모드 선택",
"agent.modeSwitch.reset": "흐름 초기화",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "온보딩 건너뛰기",
"agent.stage.agentIdentity": "에이전트 정체성",
"agent.stage.painPoints": "문제점",
"agent.stage.proSettings": "고급 설정",
@ -33,6 +41,16 @@
"agent.telemetryHint": "자신의 말로 대답할 수도 있습니다.",
"agent.title": "대화형 온보딩",
"agent.welcome": "...음? 방금 깨어났어요 — 머리가 텅 비었네요. 당신은 누구시죠? 그리고 — 저를 뭐라고 불러야 할까요? 저도 이름이 필요해요.",
"agent.welcome.footer": "Lobe AI 에이전트를 구성하세요. 이 에이전트는 서버에 상주하며 모든 상호작용에서 학습하여 실행할수록 더 강력해집니다.",
"agent.welcome.guide.growTogether.desc": "대화를 나눌수록 더 잘 이해하게 되어 시간이 지날수록 든든한 동료가 될게요.",
"agent.welcome.guide.growTogether.title": "함께 성장하기",
"agent.welcome.guide.knowYou.desc": "요즘 어떤 일을 하고 계신가요? 상황을 조금 알려주시면 더 잘 도와드릴 수 있어요.",
"agent.welcome.guide.knowYou.title": "당신을 알아가기",
"agent.welcome.guide.name.desc": "처음부터 더 친근하게 느낄 수 있도록 이름을 지어주세요.",
"agent.welcome.guide.name.title": "이름 지어주기",
"agent.welcome.sentence.1": "만나서 반가워요! 서로 알아가볼까요?",
"agent.welcome.sentence.2": "어떤 파트너가 되길 원하시나요?",
"agent.welcome.sentence.3": "먼저, 이름을 지어주세요 :)",
"back": "이전 단계",
"finish": "시작하기",
"interests.area.business": "비즈니스 및 전략",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "Agent Onboarding",
"agent.completionSubtitle": "Je assistent is geconfigureerd en klaar om te starten.",
"agent.completionTitle": "Alles is gereed!",
"agent.enterApp": "App Betreden",
"agent.completion.sentence.readyWhenYouAre": "Zeg het maar wanneer je klaar bent :)",
"agent.completion.sentence.readyWithName": "{{name}} hier ik ben er klaar voor!",
"agent.completionSubtitle": "Alles staat klaar — we kunnen beginnen zodra jij zover bent.",
"agent.completionTitle": "Je bent er bijna",
"agent.enterApp": "Ik ben er klaar voor",
"agent.greeting.emojiLabel": "Emoji",
"agent.greeting.nameLabel": "Naam",
"agent.greeting.namePlaceholder": "bijv. Lumi, Atlas, Neko...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "bijv. Warm & vriendelijk, Scherp & direct...",
"agent.history.current": "Huidig",
"agent.history.title": "Historische Onderwerpen",
"agent.layout.mode.agent": "agentmodus",
"agent.layout.mode.classic": "klassieke modus",
"agent.layout.skip": "deze stap overslaan",
"agent.layout.skipConfirm.content": "Ga je nu al weg? Ik kan binnen enkele seconden helpen om alles voor je te personaliseren.",
"agent.layout.skipConfirm.ok": "Voor nu overslaan",
"agent.layout.skipConfirm.title": "Onboarding nu overslaan?",
"agent.layout.switchMessage": "Even geen zin vandaag? Je kunt schakelen naar <modeLink><modeText>{{mode}}</modeText></modeLink> of <skipLink><skipText>{{skip}}</skipText></skipLink>.",
"agent.modeSwitch.agent": "Conversatie",
"agent.modeSwitch.classic": "Klassiek",
"agent.modeSwitch.debug": "Debug Export",
"agent.modeSwitch.label": "Kies je onboarding modus",
"agent.modeSwitch.reset": "Flow Resetten",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "Onboarding overslaan",
"agent.stage.agentIdentity": "Agent Identiteit",
"agent.stage.painPoints": "Pijnpunten",
"agent.stage.proSettings": "Geavanceerde Instellingen",
@ -33,6 +41,16 @@
"agent.telemetryHint": "Je kunt ook antwoorden in je eigen woorden.",
"agent.title": "Conversatie Onboarding",
"agent.welcome": "...hm? Ik ben net wakker — mijn gedachten zijn leeg. Wie ben jij? En — hoe moet ik genoemd worden? Ik heb ook een naam nodig.",
"agent.welcome.footer": "Configureer je Lobe AI Agent. Hij draait op je eigen server, leert van elke interactie en wordt krachtiger naarmate hij langer actief is.",
"agent.welcome.guide.growTogether.desc": "Met ieder gesprek leer ik je beter kennen en word ik op termijn een sterkere teammate.",
"agent.welcome.guide.growTogether.title": "Met je meegroeien",
"agent.welcome.guide.knowYou.desc": "Waar ben je de laatste tijd mee bezig? Een beetje context helpt me om je beter te ondersteunen.",
"agent.welcome.guide.knowYou.title": "Jou leren kennen",
"agent.welcome.guide.name.desc": "Geef me een naam zodat het vanaf het begin persoonlijker voelt.",
"agent.welcome.guide.name.title": "Geef me een naam",
"agent.welcome.sentence.1": "Leuk om je te ontmoeten! Laten we elkaar beter leren kennen.",
"agent.welcome.sentence.2": "Wat voor partner wil je dat ik voor je ben?",
"agent.welcome.sentence.3": "Geef me eerst een naam :)",
"back": "Terug",
"finish": "Aan de slag",
"interests.area.business": "Zakelijk & Strategie",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "Wprowadzenie Agenta",
"agent.completionSubtitle": "Twój asystent jest skonfigurowany i gotowy do działania.",
"agent.completionTitle": "Wszystko gotowe!",
"agent.enterApp": "Wejdź do aplikacji",
"agent.completion.sentence.readyWhenYouAre": "Jestem gotów, kiedy Ty będziesz :)",
"agent.completion.sentence.readyWithName": "{{name}} w gotowości możemy zaczynać!",
"agent.completionSubtitle": "Wszystko przygotowane zaczniemy, gdy tylko dasz znak.",
"agent.completionTitle": "Jesteś już prawie na miejscu",
"agent.enterApp": "Jestem gotów",
"agent.greeting.emojiLabel": "Emoji",
"agent.greeting.nameLabel": "Imię",
"agent.greeting.namePlaceholder": "np. Lumi, Atlas, Neko...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "np. Ciepły i przyjazny, Ostry i bezpośredni...",
"agent.history.current": "Bieżące",
"agent.history.title": "Tematy historii",
"agent.layout.mode.agent": "tryb agenta",
"agent.layout.mode.classic": "tryb klasyczny",
"agent.layout.skip": "pomiń ten krok",
"agent.layout.skipConfirm.content": "Już wychodzisz? Mogę pomóc spersonalizować wszystko w kilka sekund.",
"agent.layout.skipConfirm.ok": "Pomiń na razie",
"agent.layout.skipConfirm.title": "Pominąć konfigurację wstępną?",
"agent.layout.switchMessage": "Nie masz dziś ochoty? Możesz przełączyć na <modeLink><modeText>{{mode}}</modeText></modeLink> lub <skipLink><skipText>{{skip}}</skipText></skipLink>.",
"agent.modeSwitch.agent": "Konwersacyjny",
"agent.modeSwitch.classic": "Klasyczny",
"agent.modeSwitch.debug": "Eksport debugowania",
"agent.modeSwitch.label": "Wybierz tryb wprowadzenia",
"agent.modeSwitch.reset": "Zresetuj proces",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "Pomiń wprowadzenie",
"agent.stage.agentIdentity": "Tożsamość Agenta",
"agent.stage.painPoints": "Problemy",
"agent.stage.proSettings": "Zaawansowana konfiguracja",
@ -33,6 +41,16 @@
"agent.telemetryHint": "Możesz również odpowiedzieć własnymi słowami.",
"agent.title": "Wprowadzenie do rozmowy",
"agent.welcome": "...hm? Właśnie się obudziłem — moja głowa jest pusta. Kim jesteś? I — jak mam się nazywać? Potrzebuję też imienia.",
"agent.welcome.footer": "Skonfiguruj swojego agenta Lobe AI. Działa na Twoim serwerze, uczy się z każdej interakcji i staje się potężniejszy z czasem.",
"agent.welcome.guide.growTogether.desc": "Z każdą rozmową będę lepiej Cię rozumieć i z biegiem czasu stanę się jeszcze lepszym wsparciem.",
"agent.welcome.guide.growTogether.title": "Rozwijajmy się razem",
"agent.welcome.guide.knowYou.desc": "Nad czym ostatnio pracujesz? Trochę kontekstu pomoże mi lepiej Cię wspierać.",
"agent.welcome.guide.knowYou.title": "Poznajmy się",
"agent.welcome.guide.name.desc": "Nadaj mi imię, aby od początku było bardziej osobiste.",
"agent.welcome.guide.name.title": "Nazwij mnie",
"agent.welcome.sentence.1": "Miło Cię poznać! Poznajmy się lepiej.",
"agent.welcome.sentence.2": "Jakim partnerem mam dla Ciebie być?",
"agent.welcome.sentence.3": "Najpierw nadaj mi imię :)",
"back": "Wstecz",
"finish": "Zaczynamy",
"interests.area.business": "Biznes i strategia",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "Integração do Agente",
"agent.completionSubtitle": "Seu assistente está configurado e pronto para uso.",
"agent.completionTitle": "Tudo Pronto!",
"agent.enterApp": "Entrar no Aplicativo",
"agent.completion.sentence.readyWhenYouAre": "Pronto quando você estiver :)",
"agent.completion.sentence.readyWithName": "{{name}} aqui — pronto para começar!",
"agent.completionSubtitle": "Tudo preparado — é só começar quando quiser.",
"agent.completionTitle": "Você está quase lá",
"agent.enterApp": "Estou pronto",
"agent.greeting.emojiLabel": "Emoji",
"agent.greeting.nameLabel": "Nome",
"agent.greeting.namePlaceholder": "ex.: Lumi, Atlas, Neko...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "ex.: Caloroso e amigável, Direto e objetivo...",
"agent.history.current": "Atual",
"agent.history.title": "Tópicos do Histórico",
"agent.layout.mode.agent": "modo agente",
"agent.layout.mode.classic": "modo clássico",
"agent.layout.skip": "pular esta etapa",
"agent.layout.skipConfirm.content": "Indo embora já? Posso ajudar a personalizar tudo para você em poucos segundos.",
"agent.layout.skipConfirm.ok": "Pular por enquanto",
"agent.layout.skipConfirm.title": "Pular a configuração inicial agora?",
"agent.layout.switchMessage": "Não está no clima hoje? Você pode mudar para <modeLink><modeText>{{mode}}</modeText></modeLink> ou <skipLink><skipText>{{skip}}</skipText></skipLink>.",
"agent.modeSwitch.agent": "Conversacional",
"agent.modeSwitch.classic": "Clássico",
"agent.modeSwitch.debug": "Exportar Depuração",
"agent.modeSwitch.label": "Escolha seu modo de integração",
"agent.modeSwitch.reset": "Reiniciar Fluxo",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "Pular integração",
"agent.stage.agentIdentity": "Identidade do Agente",
"agent.stage.painPoints": "Pontos de Dor",
"agent.stage.proSettings": "Configuração Avançada",
@ -33,6 +41,16 @@
"agent.telemetryHint": "Você também pode responder com suas próprias palavras.",
"agent.title": "Integração por Conversa",
"agent.welcome": "...hm? Acabei de acordar — minha mente está vazia. Quem é você? E — como devo ser chamado? Preciso de um nome também.",
"agent.welcome.footer": "Configure seu Lobe AI Agent. Ele vive no seu servidor, aprende com cada interação e se torna mais poderoso quanto mais tempo estiver em uso.",
"agent.welcome.guide.growTogether.desc": "A cada conversa, vou entender você melhor e me tornar um parceiro mais forte ao longo do tempo.",
"agent.welcome.guide.growTogether.title": "Crescer com Você",
"agent.welcome.guide.knowYou.desc": "O que anda ocupando seu tempo hoje em dia? Um pouco de contexto me ajuda a apoiar você melhor.",
"agent.welcome.guide.knowYou.title": "Conhecer Você",
"agent.welcome.guide.name.desc": "Dê-me um nome para deixar tudo mais pessoal desde o começo.",
"agent.welcome.guide.name.title": "Dar um Nome",
"agent.welcome.sentence.1": "Muito prazer! Vamos nos conhecer melhor.",
"agent.welcome.sentence.2": "Que tipo de parceiro você quer que eu seja?",
"agent.welcome.sentence.3": "Primeiro, me dê um nome :)",
"back": "Voltar",
"finish": "Começar",
"interests.area.business": "Negócios e Estratégia",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "Настройка агента",
"agent.completionSubtitle": "Ваш помощник настроен и готов к работе.",
"agent.completionTitle": "Все готово!",
"agent.enterApp": "Войти в приложение",
"agent.completion.sentence.readyWhenYouAre": "Готов, как только вы будете готовы :)",
"agent.completion.sentence.readyWithName": "{{name}} на связи — готов приступить!",
"agent.completionSubtitle": "Всё готово — начнём, когда вы будете готовы.",
"agent.completionTitle": "Почти всё готово",
"agent.enterApp": "Я готов",
"agent.greeting.emojiLabel": "Эмодзи",
"agent.greeting.nameLabel": "Имя",
"agent.greeting.namePlaceholder": "например, Луми, Атлас, Неко...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "например, Теплый и дружелюбный, Резкий и прямолинейный...",
"agent.history.current": "Текущий",
"agent.history.title": "Темы истории",
"agent.layout.mode.agent": "режим агента",
"agent.layout.mode.classic": "классический режим",
"agent.layout.skip": "пропустить этот шаг",
"agent.layout.skipConfirm.content": "Уже уходите? Я могу за пару секунд помочь настроить всё под вас.",
"agent.layout.skipConfirm.ok": "Пропустить пока",
"agent.layout.skipConfirm.title": "Пропустить вводный этап сейчас?",
"agent.layout.switchMessage": "Не в настроении сегодня? Можно переключиться на <modeLink><modeText>{{mode}}</modeText></modeLink> или <skipLink><skipText>{{skip}}</skipText></skipLink>.",
"agent.modeSwitch.agent": "Разговорный",
"agent.modeSwitch.classic": "Классический",
"agent.modeSwitch.debug": "Экспорт отладки",
"agent.modeSwitch.label": "Выберите режим настройки",
"agent.modeSwitch.reset": "Сбросить процесс",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "Пропустить настройку",
"agent.stage.agentIdentity": "Идентичность агента",
"agent.stage.painPoints": "Болевые точки",
"agent.stage.proSettings": "Расширенные настройки",
@ -33,6 +41,16 @@
"agent.telemetryHint": "Вы также можете ответить своими словами.",
"agent.title": "Настройка через беседу",
"agent.welcome": "...мм? Я только что проснулся — мой разум пуст. Кто вы? И — как меня назвать? Мне тоже нужно имя.",
"agent.welcome.footer": "Настройте агента Lobe AI. Он размещается на вашем сервере, учится на каждом взаимодействии и с течением времени становится всё мощнее.",
"agent.welcome.guide.growTogether.desc": "С каждой беседой я буду лучше понимать вас и со временем стану более полезным напарником.",
"agent.welcome.guide.growTogether.title": "Расти вместе с вами",
"agent.welcome.guide.knowYou.desc": "Что у вас сейчас на повестке? Немного контекста поможет мне лучше вам помочь.",
"agent.welcome.guide.knowYou.title": "Познакомиться с вами",
"agent.welcome.guide.name.desc": "Дайте мне имя — так всё будет восприниматься более лично с самого начала.",
"agent.welcome.guide.name.title": "Назовите меня",
"agent.welcome.sentence.1": "Очень приятно познакомиться! Давайте узнаем друг друга поближе.",
"agent.welcome.sentence.2": "Каким партнёром вы хотели бы, чтобы я был(а)?",
"agent.welcome.sentence.3": "Сначала придумайте мне имя :)",
"back": "Назад",
"finish": "Начать",
"interests.area.business": "Бизнес и стратегия",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "Temsilci Başlatma",
"agent.completionSubtitle": "Asistanınız yapılandırıldı ve kullanıma hazır.",
"agent.completionTitle": "Her Şey Hazır!",
"agent.enterApp": "Uygulamaya Gir",
"agent.completion.sentence.readyWhenYouAre": "Hazır olduğunda ben de hazırım :)",
"agent.completion.sentence.readyWithName": "{{name}} burada - hazırım!",
"agent.completionSubtitle": "Her şey hazır - ne zaman istersen başlayabiliriz.",
"agent.completionTitle": "Neredeyse hazırsın",
"agent.enterApp": "Hazırım",
"agent.greeting.emojiLabel": "Emoji",
"agent.greeting.nameLabel": "Ad",
"agent.greeting.namePlaceholder": "ör. Lumi, Atlas, Neko...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "ör. Sıcak & samimi, Keskin & direkt...",
"agent.history.current": "Mevcut",
"agent.history.title": "Geçmiş Konular",
"agent.layout.mode.agent": "ajan modu",
"agent.layout.mode.classic": "klasik mod",
"agent.layout.skip": "bu adımı atla",
"agent.layout.skipConfirm.content": "Şimdiden gidiyor musun? Saniyeler içinde her şeyi kişiselleştirmene yardımcı olabilirim.",
"agent.layout.skipConfirm.ok": "Şimdilik atla",
"agent.layout.skipConfirm.title": "Şimdilik başlangıcı atlamak istiyor musun?",
"agent.layout.switchMessage": "Bugün modunda değil misin? <modeLink><modeText>{{mode}}</modeText></modeLink> ya da <skipLink><skipText>{{skip}}</skipText></skipLink> seçebilirsin.",
"agent.modeSwitch.agent": "Sohbet Odaklı",
"agent.modeSwitch.classic": "Klasik",
"agent.modeSwitch.debug": "Hata Ayıklama Dışa Aktarımı",
"agent.modeSwitch.label": "Başlatma modunuzu seçin",
"agent.modeSwitch.reset": "Akışı Sıfırla",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "Başlatmayı Atla",
"agent.stage.agentIdentity": "Temsilci Kimliği",
"agent.stage.painPoints": "Sorun Noktaları",
"agent.stage.proSettings": "Gelişmiş Ayarlar",
@ -33,6 +41,16 @@
"agent.telemetryHint": "Kendi kelimelerinizle de cevap verebilirsiniz.",
"agent.title": "Sohbet Başlatma",
"agent.welcome": "...hm? Yeni uyandım — zihnim bomboş. Siz kimsiniz? Ve — bana ne ad vermeliyim? Bir adıma da ihtiyacım var.",
"agent.welcome.footer": "Lobe AI Ajanını yapılandır. Sunucunda yaşar, her etkileşimden öğrenir ve çalıştıkça daha güçlü hale gelir.",
"agent.welcome.guide.growTogether.desc": "Her sohbetle seni daha iyi anlayacak ve zamanla daha güçlü bir ekip arkadaşı olacağım.",
"agent.welcome.guide.growTogether.title": "Seninle Büyür",
"agent.welcome.guide.knowYou.desc": "Son zamanlarda nelerle uğraşıyorsun? Biraz bağlam, sana daha iyi destek olmama yardımcı olur.",
"agent.welcome.guide.knowYou.title": "Seni Tanımak",
"agent.welcome.guide.name.desc": "Bana bir isim ver ki en başından itibaren daha kişisel hissettirsin.",
"agent.welcome.guide.name.title": "Bana İsim Ver",
"agent.welcome.sentence.1": "Tanıştığımıza çok memnun oldum! Birbirimizi tanıyalım.",
"agent.welcome.sentence.2": "Nasıl bir yol arkadaşı olmamı istersin?",
"agent.welcome.sentence.3": "Önce, bana bir isim ver :)",
"back": "Geri",
"finish": "Başlayalım",
"interests.area.business": "İş ve Strateji",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "Đăng ký Đại lý",
"agent.completionSubtitle": "Trợ lý của bạn đã được cấu hình và sẵn sàng hoạt động.",
"agent.completionTitle": "Mọi thứ đã sẵn sàng!",
"agent.enterApp": "Vào Ứng dụng",
"agent.completion.sentence.readyWhenYouAre": "Sẵn sàng khi bạn sẵn sàng :)",
"agent.completion.sentence.readyWithName": "{{name}} đây - Tôi đã sẵn sàng!",
"agent.completionSubtitle": "Mọi thứ đã ổn định — hãy bắt đầu khi bạn muốn.",
"agent.completionTitle": "Bạn sắp hoàn tất rồi",
"agent.enterApp": "Tôi đã sẵn sàng",
"agent.greeting.emojiLabel": "Biểu tượng cảm xúc",
"agent.greeting.nameLabel": "Tên",
"agent.greeting.namePlaceholder": "ví dụ: Lumi, Atlas, Neko...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "ví dụ: Ấm áp & thân thiện, Sắc bén & trực tiếp...",
"agent.history.current": "Hiện tại",
"agent.history.title": "Chủ đề Lịch sử",
"agent.layout.mode.agent": "chế độ agent",
"agent.layout.mode.classic": "chế độ cổ điển",
"agent.layout.skip": "bỏ qua bước này",
"agent.layout.skipConfirm.content": "Rời đi rồi sao? Tôi có thể giúp bạn cá nhân hóa mọi thứ chỉ trong vài giây.",
"agent.layout.skipConfirm.ok": "Tạm thời bỏ qua",
"agent.layout.skipConfirm.title": "Bỏ qua phần giới thiệu chứ?",
"agent.layout.switchMessage": "Hôm nay không thoải mái à? Bạn có thể chuyển sang <modeLink><modeText>{{mode}}</modeText></modeLink> hoặc <skipLink><skipText>{{skip}}</skipText></skipLink>.",
"agent.modeSwitch.agent": "Hội thoại",
"agent.modeSwitch.classic": "Cổ điển",
"agent.modeSwitch.debug": "Xuất gỡ lỗi",
"agent.modeSwitch.label": "Chọn chế độ đăng ký của bạn",
"agent.modeSwitch.reset": "Đặt lại Quy trình",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "Bỏ qua đăng ký",
"agent.stage.agentIdentity": "Danh tính Đại lý",
"agent.stage.painPoints": "Điểm đau",
"agent.stage.proSettings": "Cài đặt Nâng cao",
@ -33,6 +41,16 @@
"agent.telemetryHint": "Bạn cũng có thể trả lời bằng từ ngữ của riêng mình.",
"agent.title": "Đăng ký Hội thoại",
"agent.welcome": "...hm? Tôi vừa tỉnh dậy — đầu óc tôi trống rỗng. Bạn là ai? Và — tôi nên được gọi là gì? Tôi cũng cần một cái tên.",
"agent.welcome.footer": "Cấu hình Lobe AI Agent của bạn. Nó chạy trên máy chủ của bạn, học từ mọi tương tác và trở nên mạnh mẽ hơn theo thời gian.",
"agent.welcome.guide.growTogether.desc": "Mỗi cuộc trò chuyện giúp tôi hiểu bạn hơn và trở thành cộng sự tốt hơn theo thời gian.",
"agent.welcome.guide.growTogether.title": "Cùng Phát Triển",
"agent.welcome.guide.knowYou.desc": "Dạo này bạn đang bận điều gì? Một chút bối cảnh sẽ giúp tôi hỗ trợ bạn tốt hơn.",
"agent.welcome.guide.knowYou.title": "Tìm Hiểu Bạn",
"agent.welcome.guide.name.desc": "Hãy đặt cho tôi một cái tên để mọi thứ trở nên gần gũi hơn ngay từ đầu.",
"agent.welcome.guide.name.title": "Đặt Tên Cho Tôi",
"agent.welcome.sentence.1": "Rất vui được gặp bạn! Hãy cùng làm quen nhé.",
"agent.welcome.sentence.2": "Bạn muốn tôi trở thành kiểu cộng sự như thế nào?",
"agent.welcome.sentence.3": "Trước tiên, hãy đặt cho tôi một cái tên :)",
"back": "Quay lại",
"finish": "Bắt đầu ngay",
"interests.area.business": "Kinh doanh & Chiến lược",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "代理人入职",
"agent.completionSubtitle": "你的助手已配置完成,随时可以开始。",
"agent.completionTitle": "一切就绪!",
"agent.enterApp": "进入应用",
"agent.completion.sentence.readyWhenYouAre": "随时待命,就等你 :)",
"agent.completion.sentence.readyWithName": "{{name}}在这儿,我准备好了!",
"agent.completionSubtitle": "一切就绪,你准备好时我们就开始。",
"agent.completionTitle": "就快完成了",
"agent.enterApp": "我准备好了",
"agent.greeting.emojiLabel": "表情符号",
"agent.greeting.nameLabel": "名称",
"agent.greeting.namePlaceholder": "例如Lumi, Atlas, Neko...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "例如:温暖友好,犀利直接...",
"agent.history.current": "当前",
"agent.history.title": "历史主题",
"agent.layout.mode.agent": "代理模式",
"agent.layout.mode.classic": "经典模式",
"agent.layout.skip": "跳过此步骤",
"agent.layout.skipConfirm.content": "就要离开了吗?我可以在几秒钟内帮助您完成个性化设置。",
"agent.layout.skipConfirm.ok": "暂时跳过",
"agent.layout.skipConfirm.title": "暂时跳过入门引导?",
"agent.layout.switchMessage": "暂时不想继续?可以切换到 <modeLink><modeText>{{mode}}</modeText></modeLink> 或 <skipLink><skipText>{{skip}}</skipText></skipLink>。",
"agent.modeSwitch.agent": "对话模式",
"agent.modeSwitch.classic": "经典模式",
"agent.modeSwitch.debug": "调试导出",
"agent.modeSwitch.label": "选择您的入职模式",
"agent.modeSwitch.reset": "重置流程",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "跳过引导",
"agent.stage.agentIdentity": "代理人身份",
"agent.stage.painPoints": "痛点",
"agent.stage.proSettings": "高级设置",
@ -33,6 +41,16 @@
"agent.telemetryHint": "您也可以用自己的话回答。",
"agent.title": "对话入职",
"agent.welcome": "...嗯?我刚\"醒过来\",脑子还有点空白。你是谁?还有——你希望我叫什么?我也得找个名字。",
"agent.welcome.footer": "配置你的 Lobe AI 代理。它运行在你的服务器上,会从每次交互中学习,运行越久就越强大。",
"agent.welcome.guide.growTogether.desc": "每次交谈我都会更了解你,久而久之会成为更可靠的队友。",
"agent.welcome.guide.growTogether.title": "与您一起成长",
"agent.welcome.guide.knowYou.desc": "最近忙些什么?给我一些背景信息能让我更好地帮助你。",
"agent.welcome.guide.knowYou.title": "了解你",
"agent.welcome.guide.name.desc": "给我取个名字,这样从一开始就更有亲切感。",
"agent.welcome.guide.name.title": "给我起个名字",
"agent.welcome.sentence.1": "很高兴认识你!让我们互相了解一下吧。",
"agent.welcome.sentence.2": "你希望我成为怎样的伙伴?",
"agent.welcome.sentence.3": "先给我起个名字吧 :)",
"back": "上一步",
"finish": "开始使用",
"interests.area.business": "商业与战略",

View file

@ -1,8 +1,10 @@
{
"agent.banner.label": "代理人入門",
"agent.completionSubtitle": "您的助手已配置完成,準備就緒。",
"agent.completionTitle": "一切準備就緒!",
"agent.enterApp": "進入應用程式",
"agent.completion.sentence.readyWhenYouAre": "只要你準備好,我就開始 🙂",
"agent.completion.sentence.readyWithName": "{{name}} 在這裡 我準備好了!",
"agent.completionSubtitle": "一切就緒,你準備好時就開始吧。",
"agent.completionTitle": "就快完成了",
"agent.enterApp": "我已準備好",
"agent.greeting.emojiLabel": "表情符號",
"agent.greeting.nameLabel": "名稱",
"agent.greeting.namePlaceholder": "例如Lumi、Atlas、Neko...",
@ -11,13 +13,19 @@
"agent.greeting.vibePlaceholder": "例如:溫暖友善、犀利直接...",
"agent.history.current": "目前",
"agent.history.title": "歷史主題",
"agent.layout.mode.agent": "代理模式",
"agent.layout.mode.classic": "經典模式",
"agent.layout.skip": "跳過此步驟",
"agent.layout.skipConfirm.content": "就要離開了嗎?我可以在幾秒內幫你完成個人化設定。",
"agent.layout.skipConfirm.ok": "先跳過",
"agent.layout.skipConfirm.title": "要先跳過新手引導嗎?",
"agent.layout.switchMessage": "暫時不想繼續?可以切換到 <modeLink><modeText>{{mode}}</modeText></modeLink> 或 <skipLink><skipText>{{skip}}</skipText></skipLink>。",
"agent.modeSwitch.agent": "對話模式",
"agent.modeSwitch.classic": "經典模式",
"agent.modeSwitch.debug": "除錯匯出",
"agent.modeSwitch.label": "選擇您的入門模式",
"agent.modeSwitch.reset": "重置流程",
"agent.progress": "{{currentStep}}/{{totalSteps}}",
"agent.skipOnboarding": "跳過入門",
"agent.stage.agentIdentity": "代理人身份",
"agent.stage.painPoints": "痛點",
"agent.stage.proSettings": "進階設定",
@ -32,7 +40,17 @@
"agent.telemetryDecline": "不用了,謝謝",
"agent.telemetryHint": "您也可以用自己的話回答。",
"agent.title": "對話入門",
"agent.welcome": "...嗯?我剛醒來——腦袋一片空白。您是誰?還有——我應該叫什麼名字?我也需要一個名字。",
"agent.welcome": "...嗯?我剛醒來——腦袋一片空白。您是誰?還有我應該叫什麼名字?我也需要一個名字。",
"agent.welcome.footer": "設定您的 Lobe AI 代理。它常駐於您的伺服器上,從每次互動中學習,運行時間越長就會變得越強大。",
"agent.welcome.guide.growTogether.desc": "每次對話我都會更了解你,並逐漸成為更可靠的夥伴。",
"agent.welcome.guide.growTogether.title": "與你一同成長",
"agent.welcome.guide.knowYou.desc": "最近在忙些什麼?提供一點背景資訊能幫助我更好地協助你。",
"agent.welcome.guide.knowYou.title": "認識你",
"agent.welcome.guide.name.desc": "幫我取個名字,讓我們從一開始就更有親切感。",
"agent.welcome.guide.name.title": "給我取名",
"agent.welcome.sentence.1": "很高興認識你!我們來互相了解一下吧。",
"agent.welcome.sentence.2": "你想要我成為什麼樣的夥伴?",
"agent.welcome.sentence.3": "先幫我取個名字吧 :)",
"back": "上一步",
"finish": "開始使用",
"interests.area.business": "商業與策略",

View file

@ -1,9 +1,10 @@
'use client';
import type { BuiltinInterventionProps } from '@lobechat/types';
import { Button, Flexbox, Input, Text, TextArea } from '@lobehub/ui';
import { SendButton } from '@lobehub/editor/react';
import { Flexbox, Icon, Input, Text, TextArea } from '@lobehub/ui';
import { Select } from '@lobehub/ui/base-ui';
import { ArrowLeft, ArrowRight } from 'lucide-react';
import { ArrowLeft, PenLine } from 'lucide-react';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
@ -23,6 +24,7 @@ const FieldInput = memo<{
autoSize={{ maxRows: 6, minRows: 2 }}
placeholder={field.placeholder}
value={value as string}
variant={'filled'}
onChange={(e) => onChange(field.key, e.target.value)}
/>
);
@ -34,6 +36,7 @@ const FieldInput = memo<{
placeholder={field.placeholder}
style={{ width: '100%' }}
value={value as string}
variant={'filled'}
onChange={(v) => onChange(field.key, v as string)}
/>
);
@ -46,6 +49,7 @@ const FieldInput = memo<{
placeholder={field.placeholder}
style={{ width: '100%' }}
value={value as string[]}
variant={'filled'}
onChange={(v) => onChange(field.key, v as string[])}
/>
);
@ -55,6 +59,7 @@ const FieldInput = memo<{
<Input
placeholder={field.placeholder}
value={value as string}
variant={'filled'}
onChange={(e) => onChange(field.key, e.target.value)}
onPressEnter={onPressEnter}
/>
@ -163,17 +168,18 @@ const AskUserQuestionIntervention = memo<BuiltinInterventionProps<AskUserQuestio
)}
{isFreeform ? (
<TextArea
autoSize={{ maxRows: 6, minRows: 2 }}
autoSize={{ maxRows: 6, minRows: 3 }}
placeholder={question.description || ''}
value={formData['__freeform__'] as string}
variant={'filled'}
onChange={(e) => handleFieldChange('__freeform__', e.target.value)}
/>
) : (
<>
{!escapeActive && (
<Flexbox gap={8} ref={formContainerRef}>
{!escapeActive ? (
<Flexbox gap={16} ref={formContainerRef}>
{question.fields!.map((field) => (
<Flexbox gap={4} key={field.key}>
<Flexbox gap={6} key={field.key}>
<Text style={{ fontSize: 13 }}>
{field.label}
{field.required && <span style={{ color: 'red' }}> *</span>}
@ -189,37 +195,34 @@ const AskUserQuestionIntervention = memo<BuiltinInterventionProps<AskUserQuestio
</Flexbox>
))}
</Flexbox>
)}
{/* Escape hatch: bypass form, type freely */}
{escapeActive ? (
<Flexbox gap={8} ref={escapeContainerRef}>
<Text className={styles.escapeLink} type="secondary" onClick={handleEscapeToggle}>
<ArrowLeft size={14} /> {t('form.otherBack')}
</Text>
) : (
<TextArea
autoSize={{ maxRows: 6, minRows: 2 }}
autoSize={{ maxRows: 6, minRows: 3 }}
value={escapeText}
variant={'filled'}
onChange={(e) => setEscapeText(e.target.value)}
/>
</Flexbox>
) : (
<Text className={styles.escapeLink} type="secondary" onClick={handleEscapeToggle}>
{t('form.other')} <ArrowRight size={14} />
</Text>
)}
</>
)}
<Flexbox horizontal gap={8} justify="flex-end">
<Button onClick={handleSkip}>{t('form.skip')}</Button>
<Button
disabled={isSubmitDisabled}
loading={submitting}
type="primary"
onClick={handleSubmit}
>
{t('form.submit')}
</Button>
<Flexbox horizontal gap={8} justify={'space-between'}>
<Flexbox horizontal gap={8} justify="flex-start">
{escapeActive ? (
<Text className={styles.escapeLink} type="secondary" onClick={handleEscapeToggle}>
<Icon icon={ArrowLeft} /> {t('form.otherBack')}
</Text>
) : (
<>
<Text className={styles.escapeLink} type="secondary" onClick={handleSkip}>
{t('form.skip')}
</Text>
<Text className={styles.escapeLink} type="secondary" onClick={handleEscapeToggle}>
{t('form.other')} <Icon icon={PenLine} />
</Text>
</>
)}
</Flexbox>
<SendButton disabled={isSubmitDisabled} loading={submitting} onClick={handleSubmit} />
</Flexbox>
</Flexbox>
);

View file

@ -26,6 +26,10 @@ export interface ChatListProps {
* Custom item renderer. If not provided, uses default ChatItem.
*/
itemContent?: (index: number, id: string) => ReactNode;
/**
* Force showing welcome component even when messages exist
*/
showWelcome?: boolean;
/**
* Welcome component to display when there are no messages
*/
@ -36,7 +40,7 @@ export interface ChatListProps {
*
* Uses ConversationStore for message data and fetching.
*/
const ChatList = memo<ChatListProps>(({ disableActionsBar, welcome, itemContent }) => {
const ChatList = memo<ChatListProps>(({ disableActionsBar, welcome, itemContent, showWelcome }) => {
// Fetch messages (SWR key is null when skipFetch is true)
const context = useConversationStore((s) => s.context);
const enableUserMemories = useUserStore(settingsSelectors.memoryEnabled);
@ -76,7 +80,7 @@ const ChatList = memo<ChatListProps>(({ disableActionsBar, welcome, itemContent
return <SkeletonList />;
}
if (displayMessageIds.length === 0) {
if ((showWelcome || displayMessageIds.length === 0) && welcome) {
return (
<WideScreenContainer
style={{

View file

@ -1,22 +1,17 @@
import { memo, useState } from 'react';
import { memo } from 'react';
import Intervention from '../Messages/AssistantGroup/Tool/Detail/Intervention';
import { type PendingIntervention } from '../store/slices/data/pendingInterventions';
import { useStyles } from './style';
import { styles } from './style';
interface InterventionContentProps {
intervention: PendingIntervention;
}
const InterventionContent = memo<InterventionContentProps>(({ intervention }) => {
const { styles } = useStyles();
const [actionsContainer, setActionsContainer] = useState<HTMLDivElement | null>(null);
return (
<>
<div className={styles.content}>
<Intervention
actionsPortalTarget={actionsContainer}
apiName={intervention.apiName}
assistantGroupId={intervention.assistantGroupId}
id={intervention.toolMessageId}
@ -25,8 +20,6 @@ const InterventionContent = memo<InterventionContentProps>(({ intervention }) =>
toolCallId={intervention.toolCallId}
/>
</div>
<div className={styles.actions} ref={setActionsContainer} />
</>
);
});

View file

@ -1,7 +1,8 @@
import { cx } from 'antd-style';
import { memo } from 'react';
import { type PendingIntervention } from '../store/slices/data/pendingInterventions';
import { useStyles } from './style';
import { styles } from './style';
interface InterventionTabBarProps {
activeIndex: number;
@ -11,8 +12,6 @@ interface InterventionTabBarProps {
const InterventionTabBar = memo<InterventionTabBarProps>(
({ interventions, activeIndex, onTabChange }) => {
const { cx, styles } = useStyles();
return (
<div className={styles.tabBar}>
{interventions.map((item, index) => (

View file

@ -1,16 +1,16 @@
import { ChatInput } from '@lobehub/editor/react';
import { memo, useCallback, useMemo, useState } from 'react';
import { type PendingIntervention } from '../store/slices/data/pendingInterventions';
import InterventionContent from './InterventionContent';
import InterventionTabBar from './InterventionTabBar';
import { useStyles } from './style';
import { styles } from './style';
interface InterventionBarProps {
interventions: PendingIntervention[];
}
const InterventionBar = memo<InterventionBarProps>(({ interventions }) => {
const { styles } = useStyles();
const [activeId, setActiveId] = useState<string | null>(null);
// Derive the active index from the stored toolCallId.
@ -34,7 +34,7 @@ const InterventionBar = memo<InterventionBarProps>(({ interventions }) => {
if (!activeIntervention) return null;
return (
<div className={styles.container}>
<ChatInput className={styles.container} maxHeight={'50vh' as any} resize={false}>
{interventions.length > 1 && (
<InterventionTabBar
activeIndex={activeIndex}
@ -43,7 +43,7 @@ const InterventionBar = memo<InterventionBarProps>(({ interventions }) => {
/>
)}
<InterventionContent intervention={activeIntervention} key={activeIntervention.toolCallId} />
</div>
</ChatInput>
);
});

View file

@ -1,30 +1,20 @@
import { createStyles } from 'antd-style';
import { createStaticStyles } from 'antd-style';
export const useStyles = createStyles(({ css, token }) => ({
export const styles = createStaticStyles(({ css, cssVar }) => ({
actions: css`
padding-block: 8px;
padding-inline: 16px;
border-block-start: 1px solid ${token.colorBorderSecondary};
border-block-start: 1px solid ${cssVar.colorBorderSecondary};
`,
container: css`
overflow: hidden;
display: flex;
flex-direction: column;
max-height: 50vh;
margin-block-end: 12px;
border: 1px solid ${token.colorBorderSecondary};
border-radius: 10px;
background: ${token.colorBgContainer};
`,
content: css`
overflow-y: auto;
flex: 1;
min-height: 0;
padding-block: 12px;
padding-inline: 16px;
padding-block: 8px 12px;
`,
tab: css`
cursor: pointer;
@ -34,25 +24,25 @@ export const useStyles = createStyles(({ css, token }) => ({
border-block-end: 2px solid transparent;
font-size: 12px;
color: ${token.colorTextSecondary};
color: ${cssVar.colorTextSecondary};
white-space: nowrap;
transition: all 0.2s;
&:hover {
color: ${token.colorText};
color: ${cssVar.colorText};
}
`,
tabActive: css`
border-block-end-color: ${token.colorPrimary};
color: ${token.colorPrimary};
background: ${token.colorPrimaryBg};
border-block-end-color: ${cssVar.colorPrimary};
color: ${cssVar.colorPrimary};
background: ${cssVar.colorPrimaryBg};
`,
tabBar: css`
overflow-x: auto;
display: flex;
align-items: center;
border-block-end: 1px solid ${token.colorBorderSecondary};
border-block-end: 1px solid ${cssVar.colorBorderSecondary};
`,
tabCounter: css`
margin-inline-start: auto;
@ -60,7 +50,7 @@ export const useStyles = createStyles(({ css, token }) => ({
padding-inline: 14px;
font-size: 11px;
color: ${token.colorTextTertiary};
color: ${cssVar.colorTextTertiary};
white-space: nowrap;
`,
}));

View file

@ -0,0 +1,56 @@
'use client';
import { Button, Center, Flexbox, Text } from '@lobehub/ui';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { useAgentMeta } from '@/features/Conversation/hooks/useAgentMeta';
import LobeMessage from '@/routes/onboarding/components/LobeMessage';
import { staticStyle } from './staticStyle';
interface CompletionPanelProps {
finishTargetUrl?: string;
}
const CompletionPanel = memo<CompletionPanelProps>(({ finishTargetUrl }) => {
const { t } = useTranslation('onboarding');
const agentMeta = useAgentMeta();
return (
<Center height={'100%'} width={'100%'}>
<Flexbox
className={staticStyle.completionEnter}
gap={14}
style={{ maxWidth: 600, width: '100%' }}
>
<LobeMessage
avatar={agentMeta.avatar}
avatarSize={72}
fontSize={32}
gap={16}
sentences={[
t('agent.completion.sentence.readyWithName', { name: agentMeta.title }),
t('agent.completion.sentence.readyWhenYouAre'),
]}
/>
<Text fontSize={16} type={'secondary'}>
{t('agent.completionSubtitle')}
</Text>
<Button
size={'large'}
style={{ marginTop: 8 }}
type={'primary'}
onClick={() => {
if (finishTargetUrl) window.location.assign(finishTargetUrl);
}}
>
{t('agent.enterApp')}
</Button>
</Flexbox>
</Center>
);
});
CompletionPanel.displayName = 'CompletionPanel';
export default CompletionPanel;

View file

@ -8,6 +8,7 @@ import AgentOnboardingConversation from './Conversation';
// Prevent unhandled rejections from @splinetool/runtime fetching remote assets in CI
vi.mock('@lobehub/ui/brand', () => ({
LobeHub: () => null,
LogoThree: () => null,
}));
@ -33,8 +34,17 @@ vi.mock('@/features/Conversation', () => ({
return <div data-testid="chat-input" />;
},
ChatList: ({ itemContent }: { itemContent?: (index: number, id: string) => ReactNode }) => (
ChatList: ({
itemContent,
showWelcome,
welcome,
}: {
itemContent?: (index: number, id: string) => ReactNode;
showWelcome?: boolean;
welcome?: ReactNode;
}) => (
<div data-testid="chat-list">
{showWelcome ? <div data-testid="chat-welcome">{welcome}</div> : null}
{mockState.displayMessages.map((message, index) => (
<div key={message.id}>{itemContent?.(index, message.id)}</div>
))}
@ -63,6 +73,10 @@ vi.mock('@/features/Conversation/hooks/useAgentMeta', () => ({
}),
}));
vi.mock('./Welcome', () => ({
default: ({ content }: { content: string }) => <div data-testid="welcome-content">{content}</div>,
}));
describe('AgentOnboardingConversation', () => {
beforeEach(() => {
chatInputSpy.mockClear();
@ -83,6 +97,7 @@ describe('AgentOnboardingConversation', () => {
render(<AgentOnboardingConversation />);
expect(screen.getByTestId('chat-welcome')).toBeInTheDocument();
expect(screen.getByText('Welcome')).toBeInTheDocument();
expect(screen.queryByText('finish')).not.toBeInTheDocument();
});

View file

@ -1,13 +1,8 @@
'use client';
import { Avatar, Button, Flexbox, FluentEmoji, Markdown, Text } from '@lobehub/ui';
import { LogoThree } from '@lobehub/ui/brand';
import { cx } from 'antd-style';
import { LogIn } from 'lucide-react';
import type { CSSProperties } from 'react';
import { Flexbox } from '@lobehub/ui';
import { memo, useEffect, useMemo, useRef, useState } from 'react';
import { flushSync } from 'react-dom';
import { useTranslation } from 'react-i18next';
import type { ActionKeys } from '@/features/ChatInput';
import {
@ -17,10 +12,10 @@ import {
MessageItem,
useConversationStore,
} from '@/features/Conversation';
import { useAgentMeta } from '@/features/Conversation/hooks/useAgentMeta';
import { isDev } from '@/utils/env';
import { staticStyle } from './staticStyle';
import CompletionPanel from './CompletionPanel';
import Welcome from './Welcome';
const assistantLikeRoles = new Set(['assistant', 'assistantGroup', 'supervisor']);
@ -32,22 +27,8 @@ interface AgentOnboardingConversationProps {
const chatInputLeftActions: ActionKeys[] = isDev ? ['model'] : [];
const greetingCenterStyle: CSSProperties = { flex: 1, minHeight: '100%' };
const agentTitleStyle: CSSProperties = { fontSize: 12, fontWeight: 500 };
const outerContainerStyle: CSSProperties = { minHeight: 0 };
const scrollContainerStyle: CSSProperties = {
minHeight: 0,
overflowX: 'hidden',
overflowY: 'auto',
position: 'relative',
};
const completionTitleStyle: CSSProperties = { fontSize: 18, fontWeight: 600 };
const greetingContainerVT: CSSProperties = { viewTransitionName: 'greeting-container' };
const AgentOnboardingConversation = memo<AgentOnboardingConversationProps>(
({ finishTargetUrl, onboardingFinished, readOnly }) => {
const { t } = useTranslation('onboarding');
const agentMeta = useAgentMeta();
const displayMessages = useConversationStore(conversationSelectors.displayMessages);
const isGreetingState = useMemo(() => {
@ -76,96 +57,41 @@ const AgentOnboardingConversation = memo<AgentOnboardingConversationProps>(
prevGreetingRef.current = isGreetingState;
}, [isGreetingState]);
const shouldShowGreetingWelcome = showGreeting && !onboardingFinished;
const greetingWelcome = useMemo(() => {
if (!shouldShowGreetingWelcome) return undefined;
const message = displayMessages[0];
if (!message || typeof message.content !== 'string') return undefined;
return <Welcome content={message.content} />;
}, [displayMessages, shouldShowGreetingWelcome]);
if (onboardingFinished) return <CompletionPanel finishTargetUrl={finishTargetUrl} />;
const listWelcome = greetingWelcome;
const itemContent = (index: number, id: string) => {
const isLatestItem = displayMessages.length === index + 1;
if (showGreeting && index === 0) {
const message = displayMessages[0];
return (
<Flexbox align={'center'} justify={'center'} style={greetingCenterStyle}>
<Flexbox align={'center'} className={staticStyle.greetingWrap} gap={24}>
<LogoThree className={staticStyle.greetingLogo} size={64} />
<Flexbox className={cx(staticStyle.greetingCard)} style={greetingContainerVT}>
<Flexbox horizontal align={'flex-start'} gap={12}>
<Avatar
avatar={agentMeta.avatar}
background={agentMeta.backgroundColor}
className={cx(staticStyle.greetingAvatar, staticStyle.greetingAvatarAnimated)}
shape={'square'}
size={36}
/>
<Flexbox gap={4}>
<Text
className={staticStyle.greetingTitleAnimated}
style={agentTitleStyle}
type={'secondary'}
>
{agentMeta.title}
</Text>
<Markdown
className={cx(staticStyle.greetingText, staticStyle.greetingTextAnimated)}
variant={'chat'}
>
{message.content}
</Markdown>
</Flexbox>
</Flexbox>
</Flexbox>
</Flexbox>
</Flexbox>
);
}
if (isLatestItem && onboardingFinished) {
return (
<>
<MessageItem id={id} index={index} isLatestItem={isLatestItem} />
<Flexbox
align={'center'}
className={staticStyle.completionEnter}
gap={14}
paddingBlock={40}
>
<FluentEmoji emoji={'🎉'} size={56} type={'anim'} />
<Text style={completionTitleStyle}>{t('agent.completionTitle')}</Text>
<Text type={'secondary'}>{t('agent.completionSubtitle')}</Text>
<Button
icon={<LogIn size={16} />}
style={{ marginTop: 8 }}
type={'primary'}
onClick={() => {
if (finishTargetUrl) window.location.assign(finishTargetUrl);
}}
>
{t('agent.enterApp')}
</Button>
</Flexbox>
</>
);
}
return <MessageItem id={id} index={index} isLatestItem={isLatestItem} />;
};
return (
<Flexbox
className={staticStyle.viewTransitionGreeting}
flex={1}
style={outerContainerStyle}
width={'100%'}
>
<Flexbox flex={1} style={scrollContainerStyle} width={'100%'}>
<ChatList itemContent={itemContent} />
<Flexbox flex={1} height={'100%'}>
<Flexbox flex={1} style={{ overflow: 'hidden' }}>
<ChatList
itemContent={itemContent}
showWelcome={shouldShowGreetingWelcome}
welcome={listWelcome}
/>
</Flexbox>
{!readOnly && !onboardingFinished && (
<Flexbox className={staticStyle.composerZone}>
<ChatInput
allowExpand={false}
leftActions={chatInputLeftActions}
showRuntimeConfig={false}
/>
</Flexbox>
)}
</Flexbox>
);

View file

@ -0,0 +1,92 @@
import { Block, Flexbox, FluentEmoji, Grid, Markdown, Text } from '@lobehub/ui';
import { Divider } from 'antd';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import LobeMessage from '@/routes/onboarding/components/LobeMessage';
import { staticStyle } from './staticStyle';
interface WelcomeProps {
content: string;
}
const Welcome = memo<WelcomeProps>(({ content }) => {
const { t } = useTranslation('onboarding');
const guids = [
{
avatar: '👋',
title: t('agent.welcome.guide.name.title'),
desc: t('agent.welcome.guide.name.desc'),
},
{
avatar: '💬',
title: t('agent.welcome.guide.knowYou.title'),
desc: t('agent.welcome.guide.knowYou.desc'),
},
{
avatar: '🌱',
title: t('agent.welcome.guide.growTogether.title'),
desc: t('agent.welcome.guide.growTogether.desc'),
},
];
return (
<>
<Flexbox flex={1} />
<Flexbox
className={staticStyle.greetingTextAnimated}
gap={12}
width={'100%'}
style={{
paddingBottom: 'max(10vh, 32px)',
}}
>
<LobeMessage
avatarSize={72}
fontSize={32}
gap={16}
sentences={[
t('agent.welcome.sentence.1'),
t('agent.welcome.sentence.2'),
t('agent.welcome.sentence.3'),
]}
/>
<Divider dashed style={{ margin: 0 }} />
<Text italic style={{ marginBlock: 8 }} type={'secondary'}>
{t('agent.welcome.footer')}
</Text>
<Divider dashed style={{ margin: 0 }} />
<Grid paddingBlock={24}>
{guids.map((item, i) => (
<Block
shadow
gap={12}
key={i}
padding={16}
variant={'outlined'}
style={{
boxShadow: '0 8px 16px -8px rgba(0,0,0,0.06)',
}}
>
<FluentEmoji emoji={item.avatar} size={24} type={'anim'} />
<Flexbox gap={8}>
<Text fontSize={16} weight={500}>
{item.title}
</Text>
<Text type={'secondary'}>{item.desc}</Text>
</Flexbox>
</Block>
))}
</Grid>
<Markdown fontSize={16} variant={'chat'}>
{content}
</Markdown>
</Flexbox>
</>
);
});
Welcome.displayName = 'Welcome';
export default Welcome;

View file

@ -134,11 +134,7 @@ const AgentOnboardingPage = memo(() => {
return (
<OnboardingContainer>
<Flexbox
gap={24}
style={{ height: '100%', maxWidth: 840, position: 'relative', width: '100%' }}
>
<Flexbox flex={1} gap={16} style={{ minHeight: 0 }}>
<Flexbox height={'100%'} width={'100%'}>
<OnboardingConversationProvider
agentId={onboardingAgentId}
frozen={onboardingFinished}
@ -207,7 +203,6 @@ const AgentOnboardingPage = memo(() => {
) : undefined
}
/>
</Flexbox>
</OnboardingContainer>
);
});

View file

@ -1,32 +1,5 @@
import { createStaticStyles, keyframes } from 'antd-style';
const greetingLogoEnter = keyframes`
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
`;
const greetingAvatarEnter = keyframes`
from {
opacity: 0;
transform: translateY(12px);
}
to {
opacity: 1;
transform: translateY(0);
}
`;
const greetingTitleEnter = keyframes`
from { opacity: 0; }
to { opacity: 1; }
`;
const greetingTextEnter = keyframes`
from {
opacity: 0;
@ -53,82 +26,7 @@ export const staticStyle = createStaticStyles(({ css, cssVar }) => ({
completionEnter: css`
animation: ${completionSlideUp} 0.5s ease-out both;
`,
greetingAvatarAnimated: css`
animation: ${greetingAvatarEnter} 350ms ease-out 200ms both;
`,
greetingCard: css`
padding: 20px;
border: 1px solid ${cssVar.colorBorderSecondary};
border-radius: 16px;
background: ${cssVar.colorFillQuaternary};
`,
greetingLogo: css`
filter: drop-shadow(0 4px 24px ${cssVar.colorPrimary}33);
animation: ${greetingLogoEnter} 400ms ease-out both;
`,
greetingTextAnimated: css`
animation: ${greetingTextEnter} 400ms ease-out 500ms both;
`,
greetingTitleAnimated: css`
animation: ${greetingTitleEnter} 250ms ease 350ms both;
`,
composerZone: css`
gap: 8px;
margin-block-start: -8px;
`,
greetingAvatar: css`
border-radius: 10px;
box-shadow: 0 2px 12px ${cssVar.colorBgLayout};
`,
greetingDivider: css`
width: 100%;
margin-block: 4px;
`,
greetingText: css`
font-size: 16px;
line-height: 1.7;
color: ${cssVar.colorText};
`,
greetingWrap: css`
width: 100%;
max-width: 640px;
`,
inlineQuestion: css`
margin-block-start: 4px;
padding-block-start: 12px;
border-block-start: 1px solid ${cssVar.colorBorderSecondary};
`,
viewTransitionGreeting: css`
::view-transition-old(greeting-container) {
animation: 350ms cubic-bezier(0.4, 0, 0.2, 1) both fade-out;
}
::view-transition-new(greeting-container) {
animation: 350ms cubic-bezier(0.4, 0, 0.2, 1) both fade-in;
}
@keyframes fade-out {
from {
transform: scale(1);
opacity: 1;
}
to {
transform: scale(0.97);
opacity: 0;
}
}
@keyframes fade-in {
from {
transform: scale(0.97);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
`,
}));

View file

@ -65,7 +65,7 @@ const ClassicOnboardingPage = memo(() => {
return (
<OnboardingContainer>
<Flexbox gap={24} style={{ maxWidth: 480, width: '100%' }}>
<Flexbox gap={24} style={{ maxWidth: 600, width: '100%' }}>
<ModeSwitch />
{renderStep()}
</Flexbox>

View file

@ -2,14 +2,24 @@ export default {
'agent.banner.label': 'Agent Onboarding',
'agent.history.current': 'Current',
'agent.history.title': 'History Topics',
'agent.layout.mode.agent': 'agent mode',
'agent.layout.mode.classic': 'classic mode',
'agent.layout.skip': 'skip this step',
'agent.layout.skipConfirm.content':
'Leaving already? I could help personalize things for you in seconds.',
'agent.layout.skipConfirm.ok': 'Skip for now',
'agent.layout.skipConfirm.title': 'Skip onboarding for now?',
'agent.layout.switchMessage':
'Not feeling it today? You can switch to <modeLink><modeText>{{mode}}</modeText></modeLink> or <skipLink><skipText>{{skip}}</skipText></skipLink>.',
'agent.modeSwitch.agent': 'Conversational',
'agent.modeSwitch.classic': 'Classic',
'agent.modeSwitch.debug': 'Debug Export',
'agent.modeSwitch.label': 'Choose your onboarding mode',
'agent.skipOnboarding': 'Skip onboarding',
'agent.completionTitle': "You're All Set!",
'agent.completionSubtitle': 'Your assistant is configured and ready to go.',
'agent.enterApp': 'Enter App',
'agent.completionTitle': 'You are almost there',
'agent.completionSubtitle': "Everything's in place - let's get started when you're ready.",
'agent.completion.sentence.readyWhenYouAre': 'Ready when you are :)',
'agent.completion.sentence.readyWithName': "{{name}} here - I'm ready!",
'agent.enterApp': "I'm ready",
'agent.modeSwitch.reset': 'Reset Flow',
'agent.progress': '{{currentStep}}/{{totalSteps}}',
'agent.stage.agentIdentity': 'Agent Identity',
@ -24,6 +34,19 @@ export default {
'agent.summaryHint': 'Finish here if the setup summary looks right.',
'agent.welcome':
"...hm? I just woke up — my mind's a blank. Who are you? And — what should I be called? I need a name too.",
'agent.welcome.guide.growTogether.desc':
"With each chat, I'll understand you better and become a stronger teammate over time.",
'agent.welcome.guide.growTogether.title': 'Grow with You',
'agent.welcome.guide.knowYou.desc':
"What's on your plate these days? A little context helps me support you better.",
'agent.welcome.guide.knowYou.title': 'Get to Know You',
'agent.welcome.guide.name.desc': 'Give me a name so this feels more personal from the start.',
'agent.welcome.guide.name.title': 'Name Me',
'agent.welcome.sentence.1': 'So nice to meet you! Lets get to know each other.',
'agent.welcome.sentence.2': 'What kind of partner do you want me to be?',
'agent.welcome.sentence.3': 'First, give me a name :)',
'agent.welcome.footer':
'Configure your Lobe AI Agent. It lives on your server, learns from every interaction, and becomes more powerful the longer it runs.',
'agent.greeting.prompt': 'Give me a name, a vibe, and an emoji',
'agent.greeting.nameLabel': 'Name',
'agent.greeting.namePlaceholder': 'e.g. Lumi, Atlas, Neko...',

View file

@ -4,7 +4,7 @@ import { type UserCredSummary } from '@lobechat/types';
import { CopyButton, Flexbox } from '@lobehub/ui';
import { useQuery } from '@tanstack/react-query';
import { Alert, Descriptions, Modal, Skeleton, Typography } from 'antd';
import { createStyles } from 'antd-style';
import { createStaticStyles, cx } from 'antd-style';
import { Eye, EyeOff } from 'lucide-react';
import { type FC, useState } from 'react';
import { useTranslation } from 'react-i18next';
@ -13,24 +13,24 @@ import { lambdaClient } from '@/libs/trpc/client';
const { Text } = Typography;
const useStyles = createStyles(({ css, token }) => ({
const styles = createStaticStyles(({ css, cssVar }) => ({
kvKey: css`
min-width: 140px;
padding-block: 8px;
padding-inline: 12px;
border-radius: ${token.borderRadius}px 0 0 ${token.borderRadius}px;
border-radius: ${cssVar.borderRadius} 0 0 ${cssVar.borderRadius};
font-family: ${token.fontFamilyCode};
font-family: ${cssVar.fontFamilyCode};
font-size: 13px;
color: ${token.colorTextSecondary};
color: ${cssVar.colorTextSecondary};
background: ${token.colorFillQuaternary};
background: ${cssVar.colorFillQuaternary};
`,
kvRow: css`
display: flex;
align-items: stretch;
border: 1px solid ${token.colorBorderSecondary};
border-radius: ${token.borderRadius}px;
border: 1px solid ${cssVar.colorBorderSecondary};
border-radius: ${cssVar.borderRadius};
&:not(:last-child) {
margin-block-end: 8px;
@ -45,15 +45,15 @@ const useStyles = createStyles(({ css, token }) => ({
padding-block: 8px;
padding-inline: 12px;
border-radius: 0 ${token.borderRadius}px ${token.borderRadius}px 0;
border-radius: 0 ${cssVar.borderRadius} ${cssVar.borderRadius} 0;
font-family: ${token.fontFamilyCode};
font-family: ${cssVar.fontFamilyCode};
font-size: 13px;
background: ${token.colorBgContainer};
background: ${cssVar.colorBgContainer};
`,
maskedValue: css`
color: ${token.colorTextQuaternary};
color: ${cssVar.colorTextQuaternary};
letter-spacing: 2px;
`,
toggleBtn: css`
@ -64,15 +64,15 @@ const useStyles = createStyles(({ css, token }) => ({
justify-content: center;
padding: 4px;
border-radius: ${token.borderRadiusSM}px;
border-radius: ${cssVar.borderRadiusSM};
color: ${token.colorTextTertiary};
color: ${cssVar.colorTextTertiary};
transition: all 0.2s;
&:hover {
color: ${token.colorText};
background: ${token.colorFillSecondary};
color: ${cssVar.colorText};
background: ${cssVar.colorFillSecondary};
}
`,
valuesSection: css`
@ -96,7 +96,6 @@ interface KVRowProps {
}
const KVRow: FC<KVRowProps> = ({ keyName, value }) => {
const { styles, cx } = useStyles();
const [visible, setVisible] = useState(false);
return (
@ -133,7 +132,6 @@ interface ViewCredModalProps {
const ViewCredModal: FC<ViewCredModalProps> = ({ cred, open, onClose }) => {
const { t } = useTranslation('setting');
const { styles } = useStyles();
const { data, isLoading, error } = useQuery({
enabled: open && !!cred,

View file

@ -1,4 +1,5 @@
import { render, screen } from '@testing-library/react';
import { type ReactNode } from 'react';
import { MemoryRouter } from 'react-router-dom';
import { describe, expect, it, vi } from 'vitest';
@ -16,6 +17,34 @@ vi.mock('@/hooks/useIsDark', () => ({
useIsDark: () => false,
}));
vi.mock('react-i18next', () => ({
Trans: ({
components,
values,
}: {
components: Record<string, ReactNode>;
values?: { mode?: string; skip?: string };
}) => {
const modeText = values?.mode ?? '';
const skipText = values?.skip ?? '';
return (
<>
{'Not feeling it today? You can switch to '}
{components.modeLink}
{' or '}
{components.skipLink}
{'.'}
<span style={{ display: 'none' }}>{modeText}</span>
<span style={{ display: 'none' }}>{skipText}</span>
</>
);
},
useTranslation: () => ({
t: (key: string) => key,
}),
}));
describe('OnBoardingContainer', () => {
it('renders onboarding content without footer copyright', () => {
render(
@ -42,6 +71,6 @@ describe('OnBoardingContainer', () => {
</MemoryRouter>,
);
expect(screen.getByRole('button', { name: 'agent.skipOnboarding' })).toBeInTheDocument();
expect(screen.getByText('agent.layout.skip')).toBeInTheDocument();
});
});

View file

@ -1,10 +1,10 @@
'use client';
import { Button, Center, Flexbox } from '@lobehub/ui';
import { Divider } from 'antd';
import { Center, Flexbox, FluentEmoji, Text } from '@lobehub/ui';
import { Divider, Popconfirm } from 'antd';
import { cx, useTheme } from 'antd-style';
import { type FC, type PropsWithChildren, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { type FC, type MouseEvent, type PropsWithChildren, useCallback } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { useLocation, useNavigate } from 'react-router-dom';
import { ProductLogo } from '@/components/Branding';
@ -18,17 +18,26 @@ import { styles } from './style';
const OnBoardingContainer: FC<PropsWithChildren> = ({ children }) => {
const isDarkMode = useIsDark();
const theme = useTheme();
const { t } = useTranslation('onboarding');
const { t } = useTranslation(['onboarding', 'common']);
const { pathname } = useLocation();
const navigate = useNavigate();
const finishOnboarding = useUserStore((s) => s.finishOnboarding);
const isAgentOnboarding = pathname.startsWith('/onboarding/agent');
const handleSkip = useCallback(() => {
const handleConfirmSkip = useCallback(() => {
finishOnboarding();
navigate('/');
}, [finishOnboarding, navigate]);
const swichMode = useCallback(
(e: MouseEvent) => {
e.stopPropagation();
e.preventDefault();
navigate(isAgentOnboarding ? '/onboarding/classic' : '/onboarding/agent');
},
[isAgentOnboarding, navigate],
);
return (
<Flexbox className={styles.outerContainer} height={'100%'} padding={8} width={'100%'}>
<Flexbox
@ -51,16 +60,61 @@ const OnBoardingContainer: FC<PropsWithChildren> = ({ children }) => {
<Divider className={styles.divider} orientation={'vertical'} />
<ThemeButton placement={'bottomRight'} size={18} />
</Flexbox>
{isAgentOnboarding ? (
<Button size={'small'} type={'text'} onClick={handleSkip}>
{t('agent.skipOnboarding')}
</Button>
) : null}
</Flexbox>
</Flexbox>
<Center height={'100%'} width={'100%'}>
{children}
</Center>
<Center paddingBlock={'0 8px'} paddingInline={16}>
<Text fontSize={12} type={'secondary'}>
<Trans
i18nKey={'agent.layout.switchMessage'}
ns={'onboarding'}
components={{
modeLink: (
<a
href={isAgentOnboarding ? '/onboarding/classic' : '/onboarding/agent'}
onClick={swichMode}
/>
),
modeText: <Text as={'span'} />,
skipLink: (
<Popconfirm
arrow={false}
cancelButtonProps={{ type: 'text' }}
cancelText={t('cancel', { ns: 'common' })}
okText={t('agent.layout.skipConfirm.ok', { ns: 'onboarding' })}
style={{ cursor: 'pointer' }}
description={
<Text fontSize={13} style={{ marginBottom: 8 }} type={'secondary'}>
{t('agent.layout.skipConfirm.content', { ns: 'onboarding' })}
</Text>
}
icon={
<FluentEmoji
emoji={'😗'}
size={24}
style={{ marginRight: 8 }}
type={'anim'}
/>
}
title={
<Text fontSize={15}>{t('agent.completionTitle', { ns: 'onboarding' })}</Text>
}
onConfirm={handleConfirmSkip}
/>
),
skipText: <Text as={'span'} style={{ cursor: 'pointer' }} />,
}}
values={{
mode: isAgentOnboarding
? t('agent.layout.mode.classic')
: t('agent.layout.mode.agent'),
skip: t('agent.layout.skip'),
}}
/>
</Text>
</Center>
</Flexbox>
</Flexbox>
);

View file

@ -1,4 +1,4 @@
import { type FlexboxProps } from '@lobehub/ui';
import { Avatar, type FlexboxProps } from '@lobehub/ui';
import { Flexbox, Text } from '@lobehub/ui';
import { type TypewriterEffectProps } from '@lobehub/ui/awesome';
import { TypewriterEffect } from '@lobehub/ui/awesome';
@ -9,32 +9,41 @@ import { useTranslation } from 'react-i18next';
import { ProductLogo } from '@/components/Branding';
interface LobeMessageProps extends Omit<FlexboxProps, 'children'> {
avatar?: string;
avatarSize?: number;
fontSize?: number;
gap?: number;
sentences: TypewriterEffectProps['sentences'];
}
const LobeMessage = memo<LobeMessageProps>(({ sentences, fontSize = 24, ...rest }) => {
const LobeMessage = memo<LobeMessageProps>(
({ gap = 8, avatar, avatarSize, sentences, fontSize = 24, ...rest }) => {
const { i18n } = useTranslation();
const locale = i18n.language;
return (
<Flexbox gap={8} {...rest}>
<ProductLogo size={fontSize * 2} />
<Flexbox gap={gap} {...rest}>
{avatar ? (
<Avatar avatar={avatar} size={avatarSize || fontSize * 2} />
) : (
<ProductLogo size={avatarSize || fontSize * 2} />
)}
<Text as={'h1'} fontSize={fontSize} weight={'bold'}>
<TypewriterEffect
cursorCharacter={<LoadingDots size={fontSize} variant={'pulse'} />}
cursorFade={false}
deletePauseDuration={1000}
deletingSpeed={32}
deletingSpeed={16}
hideCursorWhileTyping={'afterTyping'}
key={locale}
pauseDuration={16_000}
sentences={sentences}
typingSpeed={64}
typingSpeed={32}
/>
</Text>
</Flexbox>
);
});
},
);
export default LobeMessage;