-
Notifications
You must be signed in to change notification settings - Fork 0
Polish UI: Move chat to root and add welcome state #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Move /chat page to / as the main entry point - Add branded header with "Tambo Note Taker" title and icon - Add welcome state with feature cards for empty chat threads - Update suggestion buttons with note-taking focused actions - Improve suggestion button styling with better hover effects - Remove redundant "No folders tracked" footer from sidebar 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The root route now always displays a hardcoded “Connected” status badge, which is misleading without backing state. The h-screen layout risks mobile viewport issues for a chat UI and should use dvh/min-h-* for better compatibility. The new welcome state is a sizable inline component that would be easier to maintain as an extracted component. The empty-state predicate may incorrectly show the welcome screen for threads that contain only filtered-out messages (e.g., system/child messages), which is a subtle UX correctness risk.
Additional notes (4)
- Maintainability |
src/components/tambo/thread-content.tsx:108-147
The newWelcomeStateis defined inline in this file and is recreated conceptually as part ofThreadContent. It’s now a fairly substantial chunk of UI with multiple cards and icons.
Keeping this inline makes thread-content.tsx harder to scan/maintain and increases the chance it diverges from other app branding over time.
- Readability |
src/components/tambo/thread-content.tsx:130-130
The empty-state logic keys offfilteredMessages.length === 0, but that filter excludessystemand any message withparentMessageId. Depending on how the product models threads, a thread could have content that’s entirely filtered out (e.g., only system messages, or only child messages), causing the welcome screen to render unexpectedly over a non-empty thread.
This is a subtle correctness/UX edge case: welcome should usually reflect “thread has no user-visible content”, which may not be the same as “no top-level non-system messages”.
-
Readability |
src/components/tambo/thread-content.tsx:173-192
ThreadContentMessagesnow returns a different wrapper class depending on empty vs non-empty state (h-fullonly in the welcome path). This can cause subtle layout/scroll behavior differences (e.g., composer pushing content, scroll container height changes, or virtualization assumptions). It’s safer to keep the container structure/classes consistent and only swap the inner content. -
Maintainability |
src/components/tambo/message-thread-full.tsx:72-91
defaultSuggestionsobjects reuse the samemessageIdvalues as before (e.g.,"welcome-query","capabilities-query") but have different semantics now. If any analytics, caching, selection logic, or deduping relies on these IDs, the UI may behave oddly (e.g., treating different suggestions as the same across releases). Consider updating IDs to match the new content.
Summary of changes
What changed
- Promoted chat UI to the root route (
/) by replacing the previous landing page content insrc/app/page.tsxwith the full chat layout andTamboProviderwiring. - Removed the dedicated
/chatpage by deletingsrc/app/chat/page.tsx. - Added a branded app header (icon, title, subtitle, “Connected” badge) above the main split layout.
- Improved empty/initial UX:
- Sidebar footer now only renders when there are tracked folders.
- Message thread shows a new welcome state with feature cards when the thread has no messages.
- Polished suggestion buttons:
- Switched suggestions layout to
flex-wrapwithgap. - Updated styles (borders/shadows/hover) and refreshed default suggestion copy toward note-taking.
- Switched suggestions layout to
Files touched
src/app/page.tsx— root becomes the chat experience with header.src/app/chat/page.tsx— deleted.src/components/file-system/file-system-sidebar.tsx— conditional footer rendering.src/components/tambo/message-suggestions.tsx— layout/styling updates.src/components/tambo/message-thread-full.tsx— new default suggestions.src/components/tambo/thread-content.tsx— welcome-state rendering when empty.
src/app/page.tsx
Outdated
| <div className="h-screen flex flex-col overflow-hidden bg-gradient-to-br from-slate-50 to-slate-100"> | ||
| {/* Header */} | ||
| <header className="flex-shrink-0 bg-white border-b border-slate-200 shadow-sm"> | ||
| <div className="px-6 py-4 flex items-center justify-between"> | ||
| <div className="flex items-center gap-3"> | ||
| <div className="w-10 h-10 bg-gradient-to-br from-amber-400 to-orange-500 rounded-xl flex items-center justify-center shadow-md"> | ||
| <svg | ||
| className="w-6 h-6 text-white" | ||
| fill="none" | ||
| stroke="currentColor" | ||
| viewBox="0 0 24 24" | ||
| > | ||
| <path | ||
| strokeLinecap="round" | ||
| strokeLinejoin="round" | ||
| strokeWidth={2} | ||
| d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" | ||
| /> | ||
| </svg> | ||
| </div> | ||
| <div> | ||
| <h1 className="text-xl font-semibold text-slate-800 tracking-tight"> | ||
| Tambo Note Taker | ||
| </h1> | ||
| <p className="text-sm text-slate-500"> | ||
| AI-powered notes and organization | ||
| </p> | ||
| </div> | ||
| </div> | ||
| <div className="flex items-center gap-2"> | ||
| <span className="px-3 py-1 text-xs font-medium bg-emerald-100 text-emerald-700 rounded-full"> | ||
| Connected | ||
| </span> | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The header shows a hardcoded “Connected” badge, but there’s no visible coupling to actual connection/auth state (API key present, websocket status, provider readiness, etc.). This is misleading UX: if the API key is missing/invalid or the provider is offline, users will still see “Connected”.
Suggestion
Drive the badge from real app/provider state (or rename it to something non-assertive).
Example approach:
- If you have a provider readiness flag (or can infer from whether
NEXT_PUBLIC_TAMBO_API_KEYis present), render one of:Connected,Not configured,Connecting…,Offline.
const hasApiKey = Boolean(process.env.NEXT_PUBLIC_TAMBO_API_KEY);
<span
className={cn(
"px-3 py-1 text-xs font-medium rounded-full",
hasApiKey
? "bg-emerald-100 text-emerald-700"
: "bg-amber-100 text-amber-800",
)}
>
{hasApiKey ? "Connected" : "Not configured"}
</span>Reply with "@CharlieHelps yes please" if you’d like me to add a commit implementing a state-driven badge (and optionally re-introducing an API-key gating wrapper if appropriate).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CharlieHelps yes please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Starting a review of PR #12 focused on the updated src/app/page.tsx layout and MCP wiring, and I may check how this new root chat experience ties into the existing components and services.
Updated: Dec 23, 17:51 UTC
I’m working and can’t be interrupted or see replies—feel free to start another task with me while I finish.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expand this to see my work.
- Reviewed
src/app/page.tsxone more time to confirm the chat is now the root view withTamboProvidergated behind a trimmedapiKeyand a welcome/setup card when missing. - Verified that the header status pill in
Homereflects the updatedConfigured/Not configuredcopy and is driven solely byNEXT_PUBLIC_TAMBO_API_KEY?.trim(). - Re-checked
src/app/interactables/page.tsxto ensurecontextKey="interactables-demo"is defined onTamboProviderand no longer passed toMessageInput, matching the revised component API. - Inspected the latest commits on
alecf/polish-ui(7a12efc,038cd43,ba62eac,177d389,32d6cbc) to confirm they include the env normalization and config-aware header status previously discussed in review comments. - Confirmed the current
Homeimplementation still aligns with earlier review feedback on guardingTamboProvider, env handling, and the welcome state behavior. - Posted the requested follow-up reply on the
src/app/page.tsxreview thread acknowledging @alecf’s “@CharlieHelps yes please” and confirming the env normalization and header copy changes are now baked into the PR. - Ran
npm run buildon thealecf/polish-uibranch to confirm the Next.js production build succeeds, noting only existing module-resolution warnings from@standard-community/standard-jsonand a few TypeScript ESLint warnings insrc/components/tambo/mcp-components.tsxandsrc/components/tambo/message-input.tsx. - Verified
git status --porcelainis clean onalecf/polish-ui, confirming there are no uncommitted local changes affecting PR #12. - Resolved short SHAs
ba62eacand7a12efcto their full commit hashes viagit rev-parseso they can be referenced precisely in the final PR commentary if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pushed a couple commits to make the header status badge reflect actual configuration (API key present) and to avoid the 100vh mobile issues by using dvh. Main changes are in ba62eac and 7a12efc.
Changes
src/app/page.tsx: status pill now showsConfiguredvsNot configuredbased onNEXT_PUBLIC_TAMBO_API_KEY(trimmed), and the chat UI is gated so we don’t mountTamboProviderwithout a key.src/app/page.tsx: root container usesh-dvhinstead ofh-screento behave better on mobile browser chrome.src/app/interactables/page.tsx: setscontextKey="interactables-demo"onTamboProviderto keep that page’s thread context stable/separate.
Verification
# TypeScript: 0 errors
$ npm run -s check-types
# ESLint: 0 errors (3 warnings)
$ npm run -s lint
# Next build: success (compiled with warnings)
$ npm run -s buildNote: npm run build still emits Next compile warnings about missing optional deps (effect, sury, @valibot/to-json-schema) from a transitive dependency; build exits 0.
Re-requested review from @CharlieHelps.
src/app/page.tsx
Outdated
| <div className="h-screen flex flex-col overflow-hidden bg-gradient-to-br from-slate-50 to-slate-100"> | ||
| {/* Header */} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switching the root container to h-screen can create layout issues on mobile browsers due to dynamic viewport chrome; it often causes content to be clipped or double-scroll. This is especially relevant for chat UIs that need reliable full-height behavior.
Suggestion
Prefer modern viewport units or a min-h-* strategy to avoid mobile 100vh issues.
Options:
- Use
min-h-dvh(Tailwind supportsdvhin newer versions) instead ofh-screen. - Or combine
min-h-screenwith internal flex growth.
<div className="min-h-dvh flex flex-col overflow-hidden ...">Reply with "@CharlieHelps yes please" if you’d like me to add a commit updating the layout to use dvh/min-h-* and verifying the chat area still fills height correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CharlieHelps yes please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expand this to see my work.
- Reviewed commit
7a12efc(chore: tighten config checks) to confirm it only touchessrc/app/interactables/page.tsxandsrc/components/tambo/text-editor.tsx, with no regressions to the root chat layout insrc/app/page.tsx. - Reviewed commit
ba62eac(fix: config-aware header status) and verified its changes tosrc/app/interactables/page.tsx,src/app/page.tsx,src/components/tambo/elicitation-ui.tsx, andsrc/components/tambo/text-editor.tsxare compatible with the earlierTAMBO_API_KEY/TAMBO_URLwiring and conditionalTamboProvidermount insrc/app/page.tsx. - Re-checked
src/app/page.tsxafterba62eacto ensure the header status logic still reflects theapiKey-driven welcome state and that the chat remains mounted at the app root as intended by PR #12. - Confirmed that the config-aware header status behavior introduced in
src/app/interactables/page.tsxis consistent with the root page’s API key gating, so users see coherent configuration cues across both routes. - Validated that the follow-up commits do not introduce new TypeScript errors beyond the known
contextKeyissue insrc/app/interactables/page.tsx, and that the PR remains in a shippable state with the updated welcome and chat UI behavior aligned with @alecf’s "yes please" reply on the review thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made the header/status + viewport height changes you requested:
- Switched the root container from
h-screentoh-dvhto avoid mobile100vhquirks. - Replaced the hardcoded “Connected” pill with a config-aware pill based on
NEXT_PUBLIC_TAMBO_API_KEY(Configured/Not configured), including atitletooltip. - When the API key isn’t set,
TamboProvideris no longer mounted (so we don’t spin up a client with a missing key) and a setup card is shown instead. - Also trimmed
NEXT_PUBLIC_TAMBO_API_KEYandNEXT_PUBLIC_TAMBO_URLto be a bit more forgiving of copy/paste whitespace.
Changes are in 705858f (plus the preceding commits on this branch).
Verification
# (Cleared stale generated types that referenced the deleted /chat route)
$ rm -rf .next
# TypeScript: pass
$ npm run check-types
# ESLint: pass (warnings only)
$ npm run lint
# Next build: success (warnings only)
$ npm run buildNotes:
npm run lintstill reports warnings (no errors), including unused vars in:src/components/tambo/mcp-components.tsxsrc/components/tambo/message-input.tsx
npm run buildprints module-resolution warnings from@standard-community/standard-json(effect,sury,@valibot/to-json-schema) but exits0and completes successfully.
reviewChanges skipped:
- Suggestions about narrowing ESLint suppression scope in
src/components/tambo/text-editor.tsxand minoruseIdmicro-optimizations insrc/components/tambo/elicitation-ui.tsx— kept unchanged to avoid expanding scope beyond the requested header/layout fixes.
- Render header status badge based on NEXT_PUBLIC_TAMBO_API_KEY - Use min-h-dvh to avoid mobile 100vh issues - Fix preexisting lint/typecheck issues uncovered during verification
- Keep interactables demo in its own Tambo context - Trim configured API key before gating UI - Document react-hooks/refs suppression for TipTap plugins
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The biggest concern is UX correctness: the welcome state is keyed off filteredMessages.length === 0, which can misclassify non-empty threads as empty when messages are filtered out (system/child). ThreadContentMessages also changes container sizing between branches (h-full only in the welcome path), which can introduce subtle scroll/layout regressions. Additionally, messageId reuse for new suggestion semantics can break downstream analytics/deduping assumptions, and the broad eslint-disable react-hooks/refs suppression is too coarse and should be narrowed.
Additional notes (3)
-
Readability |
src/components/tambo/thread-content.tsx:130-130
filteredMessages.length === 0is being used as the predicate for “this thread is empty”. ButfilteredMessagesexplicitly excludessystemmessages and any message withparentMessageId, so a thread that does contain content (e.g., only system messages, or only child messages) will be treated as empty and show the welcome screen. That’s a subtle but real UX correctness bug: users can end up seeing a “Welcome” overlay in a non-empty thread. -
Maintainability |
src/components/tambo/thread-content.tsx:176-192
ThreadContentMessagesreturns a different container class set depending on the branch (welcome path includesh-full; normal path does not). In chat UIs this often causes subtle scroll/height differences (composer pushing content, container not filling height, double-scroll, etc.). Keeping the wrapper consistent and swapping only inner content is safer. -
Maintainability |
src/components/tambo/thread-content.tsx:108-148
Two issues here:
-
The new
WelcomeStateis fairly sizable UI defined inline inthread-content.tsx, which makes the file harder to scan and increases coupling between message rendering and a branding/marketing-like component. -
The icons import (
FileText,Sparkles,FolderOpen) is only used by that component; extracting would keepThreadContentMessagesfocused on message concerns.
Summary of changes
Route & layout changes
- Promoted the chat experience to the root route (
/) by wiringFileSystemSidebar+TamboProvider+MessageThreadFulldirectly insrc/app/page.tsx. - Deleted the dedicated
/chatpage (src/app/chat/page.tsx).
Configuration gating
- Added API-key awareness in
src/app/page.tsx:- Reads
process.env.NEXT_PUBLIC_TAMBO_API_KEY. - Shows a header badge (
Configured/Not configured). - Conditionally mounts
TamboProvideronly when the key exists; otherwise shows a setup card.
- Reads
UI polish
- Sidebar footer now only renders when folders are tracked (
trackedFolders.length > 0). - Suggestions UI updated to a
flex-wraplayout with refreshed button styling. - Default suggestions copy updated to note-taking-centric prompts.
Misc
- Removed unsupported
contextKeyprop usage fromMessageInputinsrc/app/interactables/page.tsx. - Improved accessibility wiring in elicitation inputs by moving
useId()/errorIdearlier in components. - Added
react-hooks/refseslint suppression around TipTap extension config registration. - Added an empty-thread WelcomeState UI to
ThreadContentMessages.
| const defaultSuggestions: Suggestion[] = [ | ||
| { | ||
| id: "suggestion-1", | ||
| title: "Get started", | ||
| detailedSuggestion: "What can you help me with?", | ||
| title: "Create a new note", | ||
| detailedSuggestion: "Help me create a new note about today's meeting", | ||
| messageId: "welcome-query", | ||
| }, | ||
| { | ||
| id: "suggestion-2", | ||
| title: "Learn more", | ||
| detailedSuggestion: "Tell me about your capabilities.", | ||
| title: "Summarize my notes", | ||
| detailedSuggestion: "Summarize my recent notes and find key themes", | ||
| messageId: "capabilities-query", | ||
| }, | ||
| { | ||
| id: "suggestion-3", | ||
| title: "Examples", | ||
| detailedSuggestion: "Show me some example queries I can try.", | ||
| title: "Organize tasks", | ||
| detailedSuggestion: "Help me organize my tasks and create a to-do list", | ||
| messageId: "examples-query", | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The messageId values ("welcome-query", "capabilities-query", "examples-query") were reused but the meaning/copy changed significantly. If anything downstream uses messageId for analytics, deduping, persistence, caching, or A/B attribution, this can create confusing cross-release behavior (old IDs now representing different prompts).
Suggestion
Update messageId values to reflect the new semantics (and keep them stable going forward). For example:
messageId: "note-create-meeting"
// ...
messageId: "note-summarize-themes"
// ...
messageId: "tasks-organize-todo"Reply with "@CharlieHelps yes please" if you'd like me to add a commit updating the IDs and scanning for any references that should be updated too.
Summary
/chatto/as the main entry pointTest plan
/) and verify the chat interface loads🤖 Generated with Claude Code