-
Notifications
You must be signed in to change notification settings - Fork 1.8k
docs: add comprehensive codebase architecture documentation #3068
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?
docs: add comprehensive codebase architecture documentation #3068
Conversation
…to-expand) Implements three high-impact UX improvements identified from user journey analysis: ## 1. Save State Indicator (onlook-dev#1 Priority - CRITICAL) **Problem**: Users had no visibility into whether changes were saved **Solution**: Real-time visual feedback in top bar - Created SaveStateManager to track save states (saved/saving/unsaved) - Integrated into EditorEngine lifecycle - CodeManager notifies on write start/complete/error - Visual indicator shows: spinning "Saving...", checkmark "Saved", orange dot "Unsaved" - Tooltip displays time since last save **Files**: - apps/web/client/src/components/store/editor/save-state/index.ts (NEW) - apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsx (NEW) - apps/web/client/src/components/store/editor/engine.ts - apps/web/client/src/components/store/editor/code/index.ts - apps/web/client/src/app/project/[id]/_components/top-bar/index.tsx **Impact**: Builds user trust, eliminates confusion about save status --- ## 2. Example Prompts (onlook-dev#5 - Conversion Boost) **Problem**: Empty chat provided no guidance for new users **Solution**: Mode-specific clickable example prompts - 3 examples per mode (CREATE/EDIT/ASK/FIX) - Auto-send message on click - Examples: "Add hero section", "Change button color", "Explain component", "Fix layout" **Files**: - apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx (NEW) - apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx - apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsx **Impact**: Reduces time-to-first-message, lowers cognitive load --- ## 3. Auto-Expand Last Tool Call (onlook-dev#4 - Transparency) **Problem**: Users manually clicked every tool to see AI actions **Solution**: Latest tool call auto-expands - Identifies last tool in message parts - Passes defaultOpen flag to CollapsibleCodeBlock - Previous tools remain collapsed - Works with all code editing tools **Files**: - apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx - apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsx - apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsx **Impact**: Improves transparency, reduces clicks --- ## Testing All changes type-checked successfully with `bun run typecheck` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
@paritoshk is attempting to deploy a commit to the Onlook Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughThis PR adds comprehensive architecture documentation, introduces example prompts in the chat interface, implements save state tracking with UI indicators, and refines tool call display with auto-expand behavior for the latest tool calls. Changes span documentation, UI components, and state management. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Actionable comments posted: 4
🧹 Nitpick comments (6)
ARCHITECTURE.md (2)
840-856: Verify and keep concrete version numbers in sync with the codebaseYou’re calling out specific versions (Next.js 16, React 19, TailwindCSS v4, TypeScript 5.5+, Bun, etc.). These can drift quickly and become a source of confusion if
package.json(or Bun workspaces) aren’t upgraded in lockstep.I’d either:
- Confirm these against the current dependencies and keep this section part of your release checklist, or
- Loosen the wording (e.g. “Next.js (App Router)”, “React”, “TailwindCSS”) and move exact versions to a single source-of-truth (like
package.json/bunfig.toml) referenced from here.
865-867: Avoid hedging language around Tailwind config locationThe note
Tailwind config (likely in @onlook/ui)is ambiguous and will age poorly.Recommend making this definitive (and adjusting the path if needed), for example:
- /apps/web/client/tailwind.config.ts - Tailwind config (likely in @onlook/ui) + /apps/web/client/tailwind.config.ts - Tailwind config + /packages/ui/tailwind.config.ts - Shared Tailwind configuration (if applicable)(or whatever the actual structure is). This keeps the doc authoritative instead of speculative.
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx (2)
80-83: Hardcoded user-facing text should use next-intl.The "Thinking ..." text should be internationalized using the
useTranslationshook that's already imported (Line 38).Based on learnings, avoid hardcoded user-facing text; use next-intl messages/hooks instead.
{isStreaming && <div className="flex w-full h-full flex-row items-center gap-2 px-4 my-2 text-small content-start text-foreground-secondary"> <Icons.LoadingSpinner className="animate-spin" /> - <p>Thinking ...</p> + <p>{t(transKeys.chat.thinking)}</p> </div>}You'll need to add the corresponding key to your translation files (e.g.,
apps/web/client/messages/*.json).
22-28: Consider using the already-importedChatTypefor cleaner typing.
ChatTypeis available from@onlook/models/chat(Line 6), so the inline import syntax on Line 25 is redundant.+import { ChatType, type ChatMessage } from '@onlook/models/chat'; -import { type ChatMessage } from '@onlook/models/chat'; ... interface ChatMessagesProps { messages: ChatMessage[]; onEditMessage: EditMessage; - onSendMessage: (content: string, type: import('@onlook/models').ChatType) => void; + onSendMessage: (content: string, type: ChatType) => void; isStreaming: boolean; error?: Error; }apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx (1)
120-132: Add a fallback for dynamic icon lookup.If
example.icondoesn't match a key inIcons,IconComponentwill beundefinedand cause a runtime error.{prompts.map((example, index) => { - const IconComponent = Icons[example.icon]; + const IconComponent = Icons[example.icon] ?? Icons.QuestionMarkCircled; return ( <Button key={index}Also consider using
example.promptor a unique identifier as the key instead ofindexif prompts could be reordered dynamically.apps/web/client/src/components/store/editor/save-state/index.ts (1)
69-76: Consider moving time formatting to the UI layer for proper i18n.The
formattedTimeSinceLastSavegetter returns hardcoded English strings that appear in the user-facing tooltip. For proper internationalization, time formatting should be handled in the UI layer using next-intl's formatting utilities.Refactor to expose only the numeric value and format in the UI:
- /** - * Get formatted time since last save (e.g., "2 seconds ago", "1 minute ago") - */ - get formattedTimeSinceLastSave(): string { - const seconds = this.timeSinceLastSave; - if (seconds < 60) { - return seconds === 1 ? '1 second ago' : `${seconds} seconds ago`; - } - const minutes = Math.floor(seconds / 60); - return minutes === 1 ? '1 minute ago' : `${minutes} minutes ago`; - }Then in
save-indicator.tsx, use next-intl'suseFormatteror format the time with translation keys:const formatter = useFormatter(); const time = editorEngine.saveState.timeSinceLastSave; const formattedTime = time < 60 ? t('editor.saveIndicator.secondsAgo', { count: time }) : t('editor.saveIndicator.minutesAgo', { count: Math.floor(time / 60) });This approach properly separates concerns and enables localization.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
.gitignore(1 hunks)ARCHITECTURE.md(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx(2 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx(3 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsx(5 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/top-bar/index.tsx(2 hunks)apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsx(1 hunks)apps/web/client/src/components/store/editor/code/index.ts(2 hunks)apps/web/client/src/components/store/editor/engine.ts(3 hunks)apps/web/client/src/components/store/editor/save-state/index.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/client/src/app/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/app/**/*.tsx: Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Do not use process.env in client code; import env from @/env insteadAvoid hardcoded user-facing text; use next-intl messages/hooks
Files:
apps/web/client/src/app/project/[id]/_components/top-bar/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsx
apps/web/client/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/app/project/[id]/_components/top-bar/index.tsxapps/web/client/src/components/store/editor/code/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/components/store/editor/engine.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsxapps/web/client/src/components/store/editor/save-state/index.ts
apps/web/client/src/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable references across renders
Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Avoid useMemo for creating MobX store instances
Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable identities across renders
Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Do not use useMemo to create MobX stores
Avoid placing MobX store instances in effect dependency arrays if it causes loops; split concerns instead
observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Files:
apps/web/client/src/app/project/[id]/_components/top-bar/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use the any type unless necessary
Files:
apps/web/client/src/app/project/[id]/_components/top-bar/index.tsxapps/web/client/src/components/store/editor/code/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/components/store/editor/engine.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsxapps/web/client/src/components/store/editor/save-state/index.ts
apps/web/client/src/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs
Files:
apps/web/client/src/app/project/[id]/_components/top-bar/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsx
{apps,packages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Avoid using the any type unless absolutely necessary
Files:
apps/web/client/src/app/project/[id]/_components/top-bar/index.tsxapps/web/client/src/components/store/editor/code/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/components/store/editor/engine.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsxapps/web/client/src/components/store/editor/save-state/index.ts
🧠 Learnings (9)
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.tsx : Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Applied to files:
apps/web/client/src/components/store/editor/code/index.tsapps/web/client/src/components/store/editor/save-state/index.ts
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Avoid hardcoded user-facing text; use next-intl messages/hooks instead
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/app/**/*.tsx : Avoid hardcoded user-facing text; use next-intl messages/hooks
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/**/*.tsx : observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Applied to files:
apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/**/*.tsx : Create MobX store instances with useState(() => new Store()) for stable identities across renders
Applied to files:
apps/web/client/src/components/store/editor/engine.tsapps/web/client/src/components/store/editor/save-state/index.ts
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/app/**/*.tsx : Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Applied to files:
ARCHITECTURE.md
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/messages/**/*.{json,ts} : Add or modify translation keys in apps/web/client/messages/* and keep keys stable (prefer additions over breaking renames)
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.tsx : Create MobX store instances with useState(() => new Store()) for stable references across renders
Applied to files:
apps/web/client/src/components/store/editor/save-state/index.ts
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/**/*.tsx : Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Applied to files:
apps/web/client/src/components/store/editor/save-state/index.ts
🧬 Code graph analysis (9)
apps/web/client/src/app/project/[id]/_components/top-bar/index.tsx (1)
apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsx (1)
SaveIndicator(9-62)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx (2)
packages/ui/src/components/icons/index.tsx (1)
Icons(138-3667)apps/web/client/src/components/store/editor/index.tsx (1)
useEditorEngine(10-14)
apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsx (3)
apps/web/client/src/components/store/editor/index.tsx (1)
useEditorEngine(10-14)apps/web/client/src/components/store/editor/save-state/index.ts (1)
SaveState(4-4)packages/ui/src/components/tooltip.tsx (3)
Tooltip(72-72)TooltipTrigger(72-72)TooltipContent(72-72)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx (3)
packages/models/src/chat/message/message.ts (1)
ChatMessage(19-19)apps/web/client/src/app/project/[id]/_hooks/use-chat/index.tsx (1)
EditMessage(19-23)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx (1)
ExamplePrompts(90-137)
apps/web/client/src/components/store/editor/engine.ts (1)
apps/web/client/src/components/store/editor/save-state/index.ts (1)
SaveStateManager(6-85)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsx (1)
apps/web/client/src/components/store/editor/chat/index.ts (1)
sendMessage(43-49)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx (1)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsx (1)
ToolCallDisplay(236-236)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsx (1)
apps/web/client/src/components/store/editor/index.tsx (1)
useEditorEngine(10-14)
apps/web/client/src/components/store/editor/save-state/index.ts (1)
apps/web/client/src/components/store/editor/engine.ts (1)
EditorEngine(34-138)
🪛 LanguageTool
ARCHITECTURE.md
[uncategorized] ~569-~569: The official name of this software platform is spelled with a capital “H”.
Context: ...` ### Feature Packages #### @onlook/github - Purpose: GitHub integration - *...
(GITHUB)
🔇 Additional comments (10)
.gitignore (1)
48-50: Tool-specific directory ignore looks goodIgnoring
.claude/alongside other temporary directories is appropriate and keeps tool artifacts out of version control without impacting build/runtime behavior.ARCHITECTURE.md (1)
1-427: Excellent high-level architecture overviewThis is a very strong, cohesive architecture doc: clear layering, consistent package naming, and the data-flow diagrams make the system understandable for both newcomers and maintainers. Nothing blocking here.
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsx (1)
31-31: LGTM!The
onSendMessageprop is correctly threaded toChatMessages, enabling the example prompts feature to trigger message sending. The type signature aligns with thesendMessagefunction from theuseChathook.apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsx (1)
18-29: LGTM!The
defaultOpenprop implementation is clean:
- Default value of
falsemaintains backward compatibilityuseState(defaultOpen)correctly initializes the state once on mountNote: This is intentionally a one-time initialization—if the parent changes
defaultOpenafter mount, the collapsible won't re-sync. This is appropriate for the "auto-expand latest tool call" use case.apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsx (1)
16-23: LGTM!The
isLatestprop is correctly added with a sensible default offalseand consistently propagated to allCollapsibleCodeBlockinstances for file-editing tools (WriteFileTool, FuzzyEditFileTool, SearchReplaceEditTool, SearchReplaceMultiEditFileTool).apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx (1)
35-42: LGTM!The reverse scan correctly identifies the last tool call for auto-expand behavior.
apps/web/client/src/components/store/editor/code/index.ts (1)
26-49: LGTM! Save lifecycle properly integrated.The save-state tracking is correctly implemented:
startSaving()is called at the beginning of the write operationdebouncedCompleteSave()allows batching multiple rapid writes before marking as savedmarkUnsaved()in the error handler ensures unsaved state is reflected when writes failapps/web/client/src/components/store/editor/engine.ts (1)
32-32: LGTM! SaveStateManager properly integrated.The SaveStateManager follows the same instantiation pattern as other engine managers and is correctly included in the engine's cleanup lifecycle.
Also applies to: 75-75, 119-119
apps/web/client/src/app/project/[id]/_components/top-bar/index.tsx (1)
22-22: LGTM! SaveIndicator appropriately placed in the top bar.The component is rendered alongside other status indicators and user elements, which is a logical placement for save state visibility.
Also applies to: 54-54
apps/web/client/src/components/store/editor/save-state/index.ts (1)
6-84: LGTM! Save-state lifecycle correctly implemented.The SaveStateManager properly handles:
- State transitions (saved → saving → saved/unsaved)
- Debounced save completion to batch rapid writes
- Conditional state updates (markUnsaved respects 'saving' state)
- Cleanup of pending timeouts
The MobX integration with
makeAutoObservableis correct, and the class follows the established manager patterns.
| const EXAMPLE_PROMPTS: Record<ChatType, ExamplePrompt[]> = { | ||
| [ChatType.CREATE]: [ | ||
| { | ||
| icon: 'MagicWand', | ||
| text: 'Add a hero section', | ||
| prompt: 'Create a modern hero section with a heading, subheading, and CTA button', | ||
| }, | ||
| { | ||
| icon: 'Component', | ||
| text: 'Build a contact form', | ||
| prompt: 'Add a contact form with name, email, message fields and a submit button', | ||
| }, | ||
| { | ||
| icon: 'Frame', | ||
| text: 'Create a navbar', | ||
| prompt: 'Build a responsive navigation bar with logo and menu items', | ||
| }, | ||
| ], | ||
| [ChatType.EDIT]: [ | ||
| { | ||
| icon: 'Pencil', | ||
| text: 'Change the button color', | ||
| prompt: 'Make the selected button blue with white text', | ||
| }, | ||
| { | ||
| icon: 'Size', | ||
| text: 'Adjust spacing', | ||
| prompt: 'Increase the padding around the selected element', | ||
| }, | ||
| { | ||
| icon: 'Text', | ||
| text: 'Update text content', | ||
| prompt: 'Change the heading text to say "Welcome to Our Platform"', | ||
| }, | ||
| ], | ||
| [ChatType.ASK]: [ | ||
| { | ||
| icon: 'QuestionMarkCircled', | ||
| text: 'Explain this component', | ||
| prompt: 'What does this component do and how does it work?', | ||
| }, | ||
| { | ||
| icon: 'Code', | ||
| text: 'Show me the structure', | ||
| prompt: 'Explain the component hierarchy and data flow', | ||
| }, | ||
| { | ||
| icon: 'InfoCircled', | ||
| text: 'Suggest improvements', | ||
| prompt: 'What improvements can I make to this component?', | ||
| }, | ||
| ], | ||
| [ChatType.FIX]: [ | ||
| { | ||
| icon: 'ExclamationTriangle', | ||
| text: 'Fix layout issues', | ||
| prompt: 'Fix any layout or alignment problems in the selected element', | ||
| }, | ||
| { | ||
| icon: 'CrossCircled', | ||
| text: 'Debug errors', | ||
| prompt: 'Find and fix any errors or warnings in the code', | ||
| }, | ||
| { | ||
| icon: 'Reset', | ||
| text: 'Optimize performance', | ||
| prompt: 'Improve the performance and remove any unnecessary code', | ||
| }, | ||
| ], | ||
| }; |
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.
🛠️ Refactor suggestion | 🟠 Major
All user-facing text should be internationalized.
The EXAMPLE_PROMPTS data structure contains numerous hardcoded strings (text and prompt fields) that violate the coding guidelines requiring next-intl for user-facing text. This is a significant amount of content that should be extracted to translation files.
Based on learnings, avoid hardcoded user-facing text; use next-intl messages/hooks instead.
Consider restructuring to use translation keys:
// Define keys structure
const EXAMPLE_PROMPT_KEYS: Record<ChatType, { icon: keyof typeof Icons; textKey: string; promptKey: string }[]> = {
[ChatType.CREATE]: [
{ icon: 'MagicWand', textKey: 'chat.prompts.create.hero.text', promptKey: 'chat.prompts.create.hero.prompt' },
// ...
],
// ...
};
// In component, use translations
const t = useTranslations();
const prompts = EXAMPLE_PROMPT_KEYS[chatMode].map(item => ({
icon: item.icon,
text: t(item.textKey),
prompt: t(item.promptKey),
}));🤖 Prompt for AI Agents
In
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx
around lines 15–84, the EXAMPLE_PROMPTS object contains hardcoded user-facing
strings (text and prompt) that must be internationalized; replace this structure
with a keys-only configuration (keep icon values) that references translation
keys (e.g. chat.prompts.<chatType>.<item>.(text|prompt)), move all literal
strings into the locale JSON/TS translation files, and in the consuming
component use next-intl's useTranslations to map keys to localized strings at
render time (build the final prompts array by calling t(key) for text and
prompt); update related types to accept keys, ensure icons remain the same, and
run the app to verify no missing translation keys.
| const getModeTitle = () => { | ||
| switch (chatMode) { | ||
| case ChatType.CREATE: | ||
| return 'Create something new'; | ||
| case ChatType.EDIT: | ||
| return 'Edit your design'; | ||
| case ChatType.ASK: | ||
| return 'Ask about your code'; | ||
| case ChatType.FIX: | ||
| return 'Fix issues'; | ||
| default: | ||
| return 'Try an example'; | ||
| } | ||
| }; |
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.
🛠️ Refactor suggestion | 🟠 Major
Internationalize getModeTitle() return values.
The hardcoded strings in getModeTitle() should use translations.
Based on learnings, avoid hardcoded user-facing text; use next-intl messages/hooks instead.
+import { useTranslations } from 'next-intl';
+import { transKeys } from '@/i18n/keys';
export const ExamplePrompts = observer(({ onSelectPrompt }: ExamplePromptsProps) => {
const editorEngine = useEditorEngine();
+ const t = useTranslations();
const chatMode = editorEngine.state.chatMode;
// ...
const getModeTitle = () => {
switch (chatMode) {
case ChatType.CREATE:
- return 'Create something new';
+ return t(transKeys.chat.prompts.titles.create);
// ... similar for other cases
}
};Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx
around lines 95 to 108, replace the hardcoded return strings in getModeTitle()
with calls to the next-intl translation hook (e.g., useTranslations) or the
messages object (t('chat.mode.create') etc. — import and initialize the
translator at the top of the component, map each ChatType case to a message key
(create, edit, ask, fix, default) and return t('path.to.key') instead of literal
text, and add the corresponding keys and translated values to the locale JSON
files so there is a fallback for all supported locales.
| <p className="text-sm text-foreground-tertiary/80 mb-6 text-center max-w-[300px]"> | ||
| Start a conversation or try one of these examples | ||
| </p> |
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.
🛠️ Refactor suggestion | 🟠 Major
Internationalize the description text.
The paragraph text should use translations.
Based on learnings, avoid hardcoded user-facing text; use next-intl messages/hooks instead.
<p className="text-sm text-foreground-tertiary/80 mb-6 text-center max-w-[300px]">
- Start a conversation or try one of these examples
+ {t(transKeys.chat.prompts.description)}
</p>Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx
around lines 116-118, the paragraph contains hardcoded user-facing text; replace
it with a translated message using next-intl (e.g., import and call
useTranslations or useMessage hook at the top of the component, add a messages
key like "chat.examplePrompt" to the locale files, then render
t('chat.examplePrompt') instead of the hardcoded string). Ensure you add the new
key to the appropriate locale JSON(s) and keep the original styling/props
unchanged.
| const getIndicatorContent = () => { | ||
| switch (saveState) { | ||
| case 'saving': | ||
| return ( | ||
| <div className="flex items-center gap-1.5 text-xs text-foreground-secondary"> | ||
| <Icons.Reload className="h-3 w-3 animate-spin" /> | ||
| <span>Saving...</span> | ||
| </div> | ||
| ); | ||
| case 'saved': | ||
| return ( | ||
| <div className="flex items-center gap-1.5 text-xs text-foreground-tertiary"> | ||
| <Icons.Check className="h-3 w-3" /> | ||
| <span>Saved</span> | ||
| </div> | ||
| ); | ||
| case 'unsaved': | ||
| return ( | ||
| <div className="flex items-center gap-1.5 text-xs text-orange-500"> | ||
| <Icons.Circle className="h-3 w-3 fill-current" /> | ||
| <span>Unsaved changes</span> | ||
| </div> | ||
| ); | ||
| } | ||
| }; | ||
|
|
||
| const getTooltipContent = () => { | ||
| switch (saveState) { | ||
| case 'saving': | ||
| return 'Saving your changes...'; | ||
| case 'saved': | ||
| return `Last saved ${editorEngine.saveState.formattedTimeSinceLastSave}`; | ||
| case 'unsaved': | ||
| return 'You have unsaved changes'; | ||
| } | ||
| }; |
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.
🛠️ Refactor suggestion | 🟠 Major
Internationalize user-facing text with next-intl.
Multiple hardcoded English strings violate the coding guidelines for this path. Use next-intl messages instead.
As per coding guidelines, files matching apps/web/client/src/app/**/*.tsx should avoid hardcoded user-facing text and use next-intl messages/hooks.
Apply this pattern to refactor the component:
+'use client';
+
import { useEditorEngine } from '@/components/store/editor';
import type { SaveState } from '@/components/store/editor/save-state';
import { Icons } from '@onlook/ui/icons';
import { Tooltip, TooltipContent, TooltipTrigger } from '@onlook/ui/tooltip';
import { observer } from 'mobx-react-lite';
+import { useTranslations } from 'next-intl';
export const SaveIndicator = observer(() => {
const editorEngine = useEditorEngine();
const saveState: SaveState = editorEngine.saveState.saveState;
+ const t = useTranslations();
const getIndicatorContent = () => {
switch (saveState) {
case 'saving':
return (
<div className="flex items-center gap-1.5 text-xs text-foreground-secondary">
<Icons.Reload className="h-3 w-3 animate-spin" />
- <span>Saving...</span>
+ <span>{t('editor.saveIndicator.saving')}</span>
</div>
);
case 'saved':
return (
<div className="flex items-center gap-1.5 text-xs text-foreground-tertiary">
<Icons.Check className="h-3 w-3" />
- <span>Saved</span>
+ <span>{t('editor.saveIndicator.saved')}</span>
</div>
);
case 'unsaved':
return (
<div className="flex items-center gap-1.5 text-xs text-orange-500">
<Icons.Circle className="h-3 w-3 fill-current" />
- <span>Unsaved changes</span>
+ <span>{t('editor.saveIndicator.unsavedChanges')}</span>
</div>
);
}
};
const getTooltipContent = () => {
switch (saveState) {
case 'saving':
- return 'Saving your changes...';
+ return t('editor.saveIndicator.tooltipSaving');
case 'saved':
- return `Last saved ${editorEngine.saveState.formattedTimeSinceLastSave}`;
+ return t('editor.saveIndicator.tooltipSaved', {
+ time: editorEngine.saveState.formattedTimeSinceLastSave
+ });
case 'unsaved':
- return 'You have unsaved changes';
+ return t('editor.saveIndicator.tooltipUnsaved');
}
};Then add the corresponding keys to your translation files (e.g., messages/en.json):
{
"editor": {
"saveIndicator": {
"saving": "Saving...",
"saved": "Saved",
"unsavedChanges": "Unsaved changes",
"tooltipSaving": "Saving your changes...",
"tooltipSaved": "Last saved {time}",
"tooltipUnsaved": "You have unsaved changes"
}
}
}🤖 Prompt for AI Agents
In apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsx
around lines 13 to 48, several user-facing strings are hardcoded; replace them
with next-intl message lookups: import and call useTranslations (e.g., const t =
useTranslations()), replace "Saving...", "Saved", "Unsaved changes", "Saving
your changes...", "Last saved {time}", and "You have unsaved changes" with
t('editor.saveIndicator.saving'), t('editor.saveIndicator.saved'),
t('editor.saveIndicator.unsavedChanges'),
t('editor.saveIndicator.tooltipSaving'), t('editor.saveIndicator.tooltipSaved',
{ time: editorEngine.saveState.formattedTimeSinceLastSave }), and
t('editor.saveIndicator.tooltipUnsaved') respectively, ensuring interpolation
for the saved tooltip; then add the corresponding keys to messages/en.json as
provided and run a build/lint to confirm no remaining hardcoded strings.
📚 Overview
This PR adds comprehensive architecture documentation for the Onlook codebase.
🎯 Changes
🔍 Why This Matters
This documentation will help:
📸 Preview
The documentation includes interactive Mermaid diagrams that show:
✅ Checklist
Important
Adds comprehensive architecture documentation and introduces save state management with UI indicators in the code editor.
ARCHITECTURE.mdwith detailed architecture documentation, including 8 Mermaid diagrams.SaveStateManagerinsave-state/index.tsto track save status (saved,saving,unsaved).CodeManagerincode/index.tsto useSaveStateManagerfor save operations.SaveIndicatorcomponent intop-bar/save-indicator.tsxto display save status in the UI.ExamplePromptscomponent inchat-messages/example-prompts.tsxfor chat suggestions.ChatMessagesinchat-messages/index.tsxto include example prompts when no messages are present.This description was created by
for a991f7b. You can customize this summary. It will automatically update as commits are pushed.
Summary by CodeRabbit
Release Notes
New Features
Improvements
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.