diff --git a/messages/de.json b/messages/de.json index 277b88ac3..44bc796c9 100644 --- a/messages/de.json +++ b/messages/de.json @@ -2279,7 +2279,7 @@ "dictateError": "Spracheingabe konnte nicht gestartet werden. Prüfe die Mikrofonberechtigung und versuche es erneut.", "showConversations": "Unterhaltungen anzeigen", "hideConversations": "Unterhaltungen ausblenden", - "heroGreeting": "Wie kann ich dir helfen?", + "heroGreeting": "Frage mich etwas zu deinen Daten", "heroSubline": "Frag nach deinen Verläufen, Medikamenten oder Messwerten.", "thinkingElapsed": "{seconds}s", "thinkingDuration": "Nachgedacht für {seconds}s", diff --git a/messages/en.json b/messages/en.json index bf05239fc..d33948ea6 100644 --- a/messages/en.json +++ b/messages/en.json @@ -2279,7 +2279,7 @@ "dictateError": "Could not start voice input. Check microphone permission and try again.", "showConversations": "Show conversations", "hideConversations": "Hide conversations", - "heroGreeting": "How can I help you?", + "heroGreeting": "Ask me anything about your data", "heroSubline": "Ask about your trends, medications, or readings.", "thinkingElapsed": "{seconds}s", "thinkingDuration": "Thought for {seconds}s", diff --git a/messages/es.json b/messages/es.json index bb1b6992f..3af706e90 100644 --- a/messages/es.json +++ b/messages/es.json @@ -2279,7 +2279,7 @@ "dictateError": "No se pudo iniciar la entrada de voz. Comprueba el permiso del micrófono e inténtalo de nuevo.", "showConversations": "Mostrar conversaciones", "hideConversations": "Ocultar conversaciones", - "heroGreeting": "¿En qué puedo ayudarte?", + "heroGreeting": "Pregúntame lo que quieras sobre tus datos", "heroSubline": "Pregunta por tus tendencias, medicamentos o mediciones.", "thinkingElapsed": "{seconds}s", "thinkingDuration": "Pensó durante {seconds}s", diff --git a/messages/fr.json b/messages/fr.json index fb09bcfa2..d63aafdeb 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -2279,7 +2279,7 @@ "dictateError": "Impossible de démarrer la saisie vocale. Vérifiez l'autorisation du microphone et réessayez.", "showConversations": "Afficher les conversations", "hideConversations": "Masquer les conversations", - "heroGreeting": "Comment puis-je t'aider ?", + "heroGreeting": "Pose-moi une question sur tes données", "heroSubline": "Pose une question sur tes tendances, médicaments ou mesures.", "thinkingElapsed": "{seconds}s", "thinkingDuration": "A réfléchi pendant {seconds}s", diff --git a/messages/it.json b/messages/it.json index 9c2a5496c..a29c170e1 100644 --- a/messages/it.json +++ b/messages/it.json @@ -2279,7 +2279,7 @@ "dictateError": "Impossibile avviare l'inserimento vocale. Controlla l'autorizzazione del microfono e riprova.", "showConversations": "Mostra conversazioni", "hideConversations": "Nascondi conversazioni", - "heroGreeting": "Come posso aiutarti?", + "heroGreeting": "Chiedimi qualcosa sui tuoi dati", "heroSubline": "Chiedi dei tuoi andamenti, farmaci o misurazioni.", "thinkingElapsed": "{seconds}s", "thinkingDuration": "Ha riflettuto per {seconds}s", diff --git a/messages/pl.json b/messages/pl.json index e4c29338e..537bd840f 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -2279,7 +2279,7 @@ "dictateError": "Nie udało się uruchomić wprowadzania głosowego. Sprawdź uprawnienia mikrofonu i spróbuj ponownie.", "showConversations": "Pokaż rozmowy", "hideConversations": "Ukryj rozmowy", - "heroGreeting": "W czym mogę pomóc?", + "heroGreeting": "Zapytaj mnie o cokolwiek na temat twoich danych", "heroSubline": "Zapytaj o swoje trendy, leki lub pomiary.", "thinkingElapsed": "{seconds}s", "thinkingDuration": "Myślał przez {seconds}s", diff --git a/src/components/insights/coach-panel/__tests__/coach-conversation-deeplink.test.tsx b/src/components/insights/coach-panel/__tests__/coach-conversation-deeplink.test.tsx index c7bbc9049..e695b6148 100644 --- a/src/components/insights/coach-panel/__tests__/coach-conversation-deeplink.test.tsx +++ b/src/components/insights/coach-panel/__tests__/coach-conversation-deeplink.test.tsx @@ -136,24 +136,30 @@ describe(" page deep-link (#67)", () => { expect(html).toContain('data-slot="coach-hero"'); }); - // v1.19.1 (C2) — a dedicated, always-visible Conversations button on the - // page surface (not buried in the composer `+` menu). - it("renders the dedicated Conversations button on the page surface", () => { + // v1.21.0 — the page toolbar is a single trailing affordance: the settings + // gear in the top-right corner. The "Conversations" + "New chat" buttons + // were removed from the toolbar (both still live in the composer `+` menu), + // and the settings gear moved here from the composer. + it("renders the settings gear in the top-right page toolbar", () => { const html = render(, makeClient()); - expect(html).toContain('data-slot="coach-page-conversations"'); - expect(html).toContain('data-slot="coach-page-new-chat"'); + expect(html).toContain('data-slot="coach-page-settings"'); + const gear = html.match(/]*data-slot="coach-page-settings"[^>]*>/); + expect(gear?.[0]).toContain('href="/settings/ai"'); + // The old toolbar Conversations + New chat buttons are gone. + expect(html).not.toContain('data-slot="coach-page-conversations"'); + expect(html).not.toContain('data-slot="coach-page-new-chat"'); }); - // v1.19.1 (C5) — entering via the drawer handoff (`?view=conversations`) - // keeps the new-chat hero (no thread auto-resumed) while opening the - // history drawer; the toolbar + button stay present so the pane is never - // a blank dead-end. - it("keeps the hero and toolbar when opened with openHistoryOnMount", () => { + // v1.21.0 — entering via the drawer handoff (`?view=conversations`) keeps + // the new-chat hero (no thread auto-resumed) while opening the history + // drawer; the toolbar gear stays present so the pane is never a blank + // dead-end. + it("keeps the hero and toolbar gear when opened with openHistoryOnMount", () => { const html = render( , makeClient(), ); expect(html).toContain('data-slot="coach-hero"'); - expect(html).toContain('data-slot="coach-page-conversations"'); + expect(html).toContain('data-slot="coach-page-settings"'); }); }); diff --git a/src/components/insights/coach-panel/__tests__/coach-hero.test.tsx b/src/components/insights/coach-panel/__tests__/coach-hero.test.tsx index 7c36b6892..4d8c717d8 100644 --- a/src/components/insights/coach-panel/__tests__/coach-hero.test.tsx +++ b/src/components/insights/coach-panel/__tests__/coach-hero.test.tsx @@ -17,8 +17,10 @@ describe("", () => { composer} />, ); expect(html).toContain('data-slot="coach-hero"'); - // Greeting copy from insights.coach.heroGreeting. - expect(html).toContain("How can I help you?"); + // Greeting copy from insights.coach.heroGreeting — one line now. + expect(html).toContain("Ask me anything about your data"); + // The earlier two-line subline was dropped. + expect(html).not.toContain("Ask about your trends, medications"); // The composer is re-parented into the hero, not forked. expect(html).toContain('data-slot="coach-hero-composer"'); expect(html).toContain('data-slot="test-composer"'); @@ -26,7 +28,7 @@ describe("", () => { it("renders the German greeting under the de locale", () => { const html = render(, "de"); - expect(html).toContain("Wie kann ich dir helfen?"); + expect(html).toContain("Frage mich etwas zu deinen Daten"); }); it("does not render starter-question suggestion chips", () => { diff --git a/src/components/insights/coach-panel/__tests__/coach-input.test.tsx b/src/components/insights/coach-panel/__tests__/coach-input.test.tsx index 6f113d0c4..d54280561 100644 --- a/src/components/insights/coach-panel/__tests__/coach-input.test.tsx +++ b/src/components/insights/coach-panel/__tests__/coach-input.test.tsx @@ -237,10 +237,11 @@ describe("", () => { expect(html).toContain('data-slot="coach-input-send"'); }); - it("renders the control-hub action row with showHub (page composer)", () => { - // v1.18.11 (W11) — the page composer is the control hub: a `+` actions - // menu (new chat + open conversations) and a settings deep-link sit on - // the action row alongside the mic + send. + it("renders the one-row page composer with showHub", () => { + // v1.21.0 — the page composer is ONE baseline row: a leading `+` actions + // menu (new chat + open conversations), the textarea, then mic + send. + // The settings gear moved OUT of the composer (now the page toolbar's + // top-right), so the composer's front is only the `+`. const html = render( ", () => { ); expect(html).toContain('data-slot="coach-input-hub"'); expect(html).toContain('data-slot="coach-input-actions"'); - // The settings gear deep-links to Settings → AI (not an in-chat sheet). - const settings = html.match( - /]*data-slot="coach-input-settings"[^>]*>/, - ); - expect(settings?.[0]).toContain('href="/settings/ai"'); - // Mic + send remain present in the hub layout. + // The settings gear is gone from the composer entirely. + expect(html).not.toContain('data-slot="coach-input-settings"'); + // Mic + send remain present on the same row. expect(html).toContain('data-slot="coach-input-mic"'); expect(html).toContain('data-slot="coach-input-send"'); + // The leading `+` precedes the textarea; the textarea precedes the send. + const plusIdx = html.indexOf('data-slot="coach-input-actions"'); + const textareaIdx = html.indexOf('data-slot="coach-input-textarea"'); + const sendIdx = html.indexOf('data-slot="coach-input-send"'); + expect(plusIdx).toBeGreaterThan(-1); + expect(plusIdx).toBeLessThan(textareaIdx); + expect(textareaIdx).toBeLessThan(sendIdx); }); it("sizes the hub actions trigger to the 44px tap-target floor on phones", () => { diff --git a/src/components/insights/coach-panel/coach-conversation.tsx b/src/components/insights/coach-panel/coach-conversation.tsx index 84c074f18..0e5004d52 100644 --- a/src/components/insights/coach-panel/coach-conversation.tsx +++ b/src/components/insights/coach-panel/coach-conversation.tsx @@ -3,7 +3,7 @@ import { useEffect, useReducer, useState } from "react"; import Link from "next/link"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { MessagesSquare, Plus, Settings, Sparkles } from "lucide-react"; +import { Plus, Settings, Sparkles } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; @@ -539,35 +539,30 @@ export function CoachConversation({ data-variant={surface} className={cn("flex min-h-0 flex-1 flex-col", className)} > - {/* v1.19.1 (C2) — a clear, always-visible "Conversations" button on - the page surface. The composer's `+` menu still carries the same - action, but the maintainer wanted an obvious, dedicated affordance - to reach past conversations rather than one buried in a menu. */} + {/* v1.21.0 — the page toolbar is now a single trailing affordance: + the settings gear in the top-right corner. The "Conversations" + and "New chat" controls were removed here — both still live in the + composer's `+` actions menu, keeping the new-chat surface calm and + uncluttered. The gear deep-links to Settings → AI (one place for + model + behaviour), matching the drawer header's gear. */}
-
{heroActive ? ( diff --git a/src/components/insights/coach-panel/coach-hero.tsx b/src/components/insights/coach-panel/coach-hero.tsx index afe3d4561..d97f69887 100644 --- a/src/components/insights/coach-panel/coach-hero.tsx +++ b/src/components/insights/coach-panel/coach-hero.tsx @@ -64,11 +64,13 @@ export function CoachHero({ composer }: CoachHeroProps) { - {/* Greeting — a slightly larger, tighter display treatment of the - existing font (weight/tracking/size only, no new font). */} + {/* Greeting — one line. A slightly larger, tighter display + treatment of the existing font (weight/tracking/size only, no + new font). The earlier two-line subline was dropped: the + new-chat surface reads as a single calm invitation. */}
{t("insights.coach.heroGreeting")} -

- {t("insights.coach.heroSubline")} -

{/* Composer — the live , centred. */} diff --git a/src/components/insights/coach-panel/coach-input.tsx b/src/components/insights/coach-panel/coach-input.tsx index dc0b0e2a3..372682588 100644 --- a/src/components/insights/coach-panel/coach-input.tsx +++ b/src/components/insights/coach-panel/coach-input.tsx @@ -9,16 +9,7 @@ import { useState, useSyncExternalStore, } from "react"; -import Link from "next/link"; -import { - Loader2, - MessagesSquare, - Mic, - Plus, - Send, - Settings, - Square, -} from "lucide-react"; +import { Loader2, MessagesSquare, Mic, Plus, Send, Square } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; @@ -452,6 +443,46 @@ export function CoachInput({ ); + // v1.21.0 — the leading `+` actions menu (page surface only). Opens the + // attachment/scope menu: new chat + open conversations. The settings gear + // no longer lives here — it moved to the page toolbar's top-right corner, + // so the composer's front is ONLY the `+`. Const-lifted like the mic / send + // so it slots into the single-row composer without forking the layout. + const actionsButton = ( + + + + + + onNewChat?.()} + > + + onOpenHistory?.()} + > + + + + ); + return (
{/* v1.16.1 / v1.18.7 — modern chat-app composer: a single rounded - field. The drawer surface keeps the textarea flanked by the mic - (left) and send / stop (right) on one baseline. The page surface - (`showHub`) stacks the textarea over a control-hub action row so - the composer carries the conversation controls ChatGPT-style. - `items-end` keeps the single-row controls pinned to the input's - last line as it grows. Enter sends, Shift+Enter inserts a newline. */} + field, ONE baseline row. The drawer surface flanks the textarea with + the mic (left) and send / stop (right). The page surface (`showHub`) + leads with a `+` actions menu (new chat + open conversations), then + the textarea, then the mic + send — same row, vertically centred. + The settings gear is NOT in the composer; it lives in the page + toolbar's top-right corner. `items-end` keeps the flanking controls + pinned to the input's last line as it grows. Enter sends, + Shift+Enter inserts a newline. */}
- {/* v1.18.10 (W4) — the mic always renders so it stays discoverable. - When the browser lacks the Web Speech API (or during SSR) it is - DISABLED with an explanatory tooltip rather than vanishing or - sitting as a dead control that does nothing on tap. In the hub - layout the mic moves into the action row below the textarea. */} - {!showHub && micButton} + {/* Leading control. Page surface: the `+` actions menu. Drawer + surface: the dictation mic. */} + {showHub ? actionsButton : micButton}