From de8ce283dd652fbe0344c2865b5d8d348275da49 Mon Sep 17 00:00:00 2001 From: inman Date: Sun, 6 Sep 2026 15:07:19 +0800 Subject: [PATCH] feat: redesign coding default entry --- .../20260906-coding-default-page-a7c42e.md | 99 +++++++++++++++++++ README.md | 1 + design-qa.md | 47 +++++++++ src/App.tsx | 2 +- src/components/layout/Sidebar.tsx | 10 +- src/lib/coding-project-entry.ts | 12 +++ src/pages/Chat/CodingChatPanel.tsx | 99 ++++++++++++++++--- src/pages/Chat/CodingConversationTimeline.tsx | 20 ++-- src/pages/Chat/CodingWelcomeHero.tsx | 29 ++++++ src/pages/Chat/index.tsx | 2 + tests/e2e/main-navigation.spec.ts | 12 ++- tests/unit/coding-chat-panel.test.tsx | 29 +++++- 12 files changed, 334 insertions(+), 28 deletions(-) create mode 100644 .project-docs/30-worklog/tasks/20260906-coding-default-page-a7c42e.md create mode 100644 design-qa.md create mode 100644 src/lib/coding-project-entry.ts create mode 100644 src/pages/Chat/CodingWelcomeHero.tsx diff --git a/.project-docs/30-worklog/tasks/20260906-coding-default-page-a7c42e.md b/.project-docs/30-worklog/tasks/20260906-coding-default-page-a7c42e.md new file mode 100644 index 0000000..f820e15 --- /dev/null +++ b/.project-docs/30-worklog/tasks/20260906-coding-default-page-a7c42e.md @@ -0,0 +1,99 @@ +# Task: Redesign Coding default page + +## Identity + +- Task ID: 20260906-coding-default-page-a7c42e +- Mode: Feature +- Branch: codex/20260906-coding-default-page-a7c42e-coding-default-page +- Worktree: /Users/inmanx/Documents/makelore-task-coding-default-page-a7c42e +- Base commit: f8eee430f4f4167dc2ecc682ece96c652cdde14b +- Owner: codex +- Status: Ready for Integration + +## Scope + +- Replace the no-project Code entry redirect with a dedicated conversation-first + landing state on `/chat`. +- Restyle both the no-project landing and the empty Conversation timeline around + the existing Makelore M brand mark, a large centered prompt, and the existing + bottom-composer hierarchy shown in the supplied Codex reference. +- Keep project creation reachable from the landing surface and update focused + Renderer/Electron coverage plus README current-state wording. + +## Intent And Constraints + +- Reuse `src/assets/logo.svg`; do not copy or approximate the Codex mark and do + not generate a new brand asset. +- Preserve the single Makelore light visual system, bundled typography, Chinese + UI, project-local `.makelore` authority, and all Main-owned runtime/API seams. +- The no-project call to action must open the existing Sidebar project-creation + flow rather than introducing a second creation implementation. +- Existing projects, Agent selection, Conversation creation, Composer behavior, + model/runtime controls, and accepted/uncertain mutation semantics remain + unchanged. +- Completed peer tasks for Plugin rehoming and removal of the project setup gate + overlap in Code-entry files but have no committed branch tips to consume. This + task therefore stays isolated on the recorded base and keeps its changes small + enough for later semantic integration. + +## Outcome + +- Code now resolves an empty local project list to `/chat` instead of redirecting + to Project Configuration. +- The no-project view uses the existing Makelore M vector asset, a large centered + guide sentence, and a low, wide project starter modeled on the supplied Codex + composition while retaining the Makelore sidebar and light visual system. +- Every project-starter action reuses the Sidebar's existing project-creation + dialog through a renderer-local event bridge; the secondary action opens the + existing project/settings route. +- Empty Conversations reuse the same branded hero above the real editable + Composer and automatically yield to the normal timeline after the first entry. +- README current-state wording, focused unit coverage, and the Code-entry Electron + navigation regression were updated. A side-by-side visual QA pass is recorded + in project-root `design-qa.md` with `final result: passed`. + +## Verification + +- `corepack pnpm install --frozen-lockfile` — passed with pinned pnpm `10.33.4`. +- `corepack pnpm run typecheck` — passed. +- `corepack pnpm exec vitest run tests/unit/coding-chat-panel.test.tsx tests/unit/coding-conversation-timeline.test.tsx tests/unit/module-navigation.test.tsx tests/unit/app-module-provider-gate.test.tsx --maxWorkers=4` + — 4 files, 58 tests passed. +- `corepack pnpm test` — 222 files passed; 1,861 tests passed and 3 skipped. +- `corepack pnpm run lint:check` — passed with 0 errors and the repository's 5 + pre-existing warnings in `src/pages/Home/index.tsx` and + `src/pages/Makelore/index.tsx`. +- `corepack pnpm run build:vite` — Renderer, Electron Main, Preload, and utility + worker production builds passed; only existing Browserslist, mixed-import, and + chunk-size warnings were emitted. +- `corepack pnpm exec playwright test tests/e2e/main-navigation.spec.ts --grep + "returns to the module chooser"` — passed against the built Electron app, + including `/chat`, branded hero, starter visibility, and project-dialog launch. +- `git diff --check` — passed. +- Visual comparison: + `/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/codex-reference-vs-makelore.png` + — no actionable P0/P1/P2 differences. + +## Follow-ups + +- During integration, semantically reconcile `App.tsx`, `Sidebar.tsx`, and the + Code-entry tests with the concurrently completed but uncommitted Plugin-rehoming + and project-gate-removal tasks; their branch tips contain no commits to merge or + cherry-pick from this feature worktree. +- Recheck the starter's `项目与插件设置` label after those peer changes establish + their final settings terminology. + +## Promotion Candidates + +- Target: `.project-docs/30-worklog/current-state.md` and + `.project-docs/40-domain/business-rules.md`. + Proposal: record that entering Code with no active local project remains on + `/chat`, presents the branded project starter, and routes all creation actions + through the single existing Sidebar flow; empty Conversations share the same + brand hero until their first entry. + Evidence: focused unit coverage, the passing Electron navigation regression, + production build, and the passed side-by-side visual QA. + Future impact: future routing or setup work must not restore the configuration + redirect or a second project-creation implementation. + Human confirmation: not required for intent because the user explicitly + requested this entry behavior; integration still must reconcile the overlapping + peer tasks semantically. diff --git a/README.md b/README.md index 75e6478..2487f76 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Makelore 是一个面向软件、视觉创作与智能机器人的 AI 桌面工 - 桌面技术栈:Electron、React 19、Vite、TypeScript、Zustand、Tailwind CSS。 - AI 编程核心对话运行时:Electron Main 按需启动一个长驻 Pi Agent Server,同一进程内为每条 Conversation 建立独立的 Runtime、Session、凭证视图、扩展上下文和 JSONL 通道,同时复用 Pi 模块与进程启动成本;Server 异常退出时所有旧通道统一失效,下一次恢复只重启一个 Server。正式包中的 Agent Server 从明确传入的 `resources/pi-runtime` 根定位依赖清单与包入口,不从脚本所在目录或应用 `node_modules` 猜测解析。Renderer 不直接启动或调用 Pi,也不读取其 wire 类型。项目与 Conversation 元数据先从本地读取,选中对话后才按需准备对应逻辑线程;输入框不等待运行时准备完成。同一助手工具批次中,会取得项目写租约的 `bash`、`edit`、`write` 与动态产品工具按顺序执行,避免批次在命令启动前自锁;纯只读工具仍可并行。子 Agent 仍使用独立的短生命周期进程,以保留并发配额、故障和写入边界;macOS 上两类后台进程都使用 Electron 自带的 Helper,不在 Dock 中创建额外应用图标。 +- AI 编程默认入口:进入 Code 后保持在 `/chat`。尚未选择本地项目时,页面以麦洛 M 标识、居中引导语和贴底的项目启动面板承接第一步,主操作复用侧栏现有的新建/打开项目流程;已有项目的新 Conversation 在可编辑 Composer 上方沿用同一品牌引导,第一条消息出现后切换为正常时间线。 - AI 编程历史与配额反馈:Pi 上下文压缩不删除用户可见的 active-branch 历史,压缩摘要保持 Main-private;Renderer 首次渲染最近 120 个节点,向上滚动时按 100 个节点追加更早内容并保持阅读位置。Main 精确识别 `token_point_balance_exhausted` / `词元点数余额不足`,只向 Renderer 投影不可重试的稳定配额错误和安全中文提示,重开会话后仍可见且不暴露上游原始错误或 request id。 - 桌面性能策略:应用窗口使用不透明浅色表面并默认保留硬件合成;仅在显式安全模式或短时间内重复 GPU 进程崩溃时启用软件渲染,并把故障原因保存在用户数据目录。启动关键路径只创建本地应用壳,认证、代理、同步、更新和遥测在首帧后延迟初始化;开发版可通过 `app:performance` 快照观察 GPU、进程、WebContents、事件循环与 Renderer Long Task 聚合指标。 - 后台生命周期:Main 统一维护模块活动状态与任务租约。隐藏窗口、离开模块和关闭开发浏览器会释放非必要连接;生成、Code 执行、下载与发布构建持有租约并在完成后释放。已写入 Pi 的 prompt 或上下文整理即使确认超过 10 秒,也会继续持有运行所有权与后台租约,直到迟到响应、权威事件、明确失败或用户清理使其收敛;此时同一 Conversation 不接受重叠 mutation,其他 Conversation 不受影响。各模块的后台连接、轮询和子进程必须通过同一生命周期入口登记。 diff --git a/design-qa.md b/design-qa.md new file mode 100644 index 0000000..c437c73 --- /dev/null +++ b/design-qa.md @@ -0,0 +1,47 @@ +**Comparison Target** + +- Source visual truth: `/var/folders/m7/x9ry3xgx4x50fxb20_0108tr0000gn/T/codex-clipboard-58e2cc35-7a17-4951-8bbc-53fee12d5246.png` +- Implementation screenshot: `/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/makelore-coding-default.png` +- Combined comparison: `/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/codex-reference-vs-makelore.png` +- State: reference start screen and Makelore Code with no active local project. +- Viewport: implementation CSS viewport 1280 x 800 at device scale factor 1. The source is 908 x 835 pixels with unknown capture density. For full-view comparison, the source was aspect-fit onto a 1280 x 800 white canvas and the implementation was kept at its native 1280 x 800 size; both canvases were then placed side by side. + +**Findings** + +- No actionable P0, P1, or P2 differences remain. +- Fonts and typography: both screens use a restrained system sans-serif hierarchy. The Makelore prompt has the same single-line, medium-weight emphasis and remains comfortably readable without wrapping at the verified viewport. +- Spacing and layout rhythm: the M mark and guide sentence form one centered hero group, while the project starter stays anchored near the bottom with proportions close to the reference composer. The persistent Makelore sidebar is an intentional product-shell constraint rather than design drift. +- Colors and visual tokens: the implementation keeps Makelore's existing light background, muted neutral surfaces, dark foreground, and subtle elevation. It does not introduce a conflicting theme or decorative palette. +- Image quality and asset fidelity: the hero uses the repository's existing vector Makelore M asset, with no placeholder, CSS drawing, or reconstructed logo. +- Copy and content: the guide sentence is adapted to Makelore, and the bottom surface explains the required no-project action while preserving the reference's prompt-first reading order. + +**Open Questions** + +- None. The source does not include Makelore's persistent sidebar or its required project-selection state; those differences are intentional and necessary. + +**Full-view Comparison Evidence** + +- The combined comparison shows matching visual priority: small centered mark, large central guide copy, substantial white space, and a low, wide action surface. +- The implementation preserves the reference's quiet density while making the unavailable-chat state actionable through the existing project creation flow. + +**Focused Region Comparison Evidence** + +- A separate crop was not needed: at native 1x capture, the M mark, guide sentence, starter metadata, CTA copy, icons, radii, and shadows are all legible in the full-view evidence. + +**Comparison History** + +- Pass 1: no actionable P0/P1/P2 findings. No visual fixes were required after the combined comparison. + +**Implementation Checklist** + +- [x] Replace the old project-configuration default with the Code conversation entry. +- [x] Use the real Makelore M asset in the centered hero. +- [x] Add a large guide sentence and bottom project starter. +- [x] Connect the starter controls to the existing project dialog and settings route. +- [x] Verify the Electron entry interaction and capture the no-project state. + +**Follow-up Polish** + +- P3: after the concurrent project-dialog simplification lands, recheck the starter's secondary label so it reflects the final project/settings terminology exactly. + +final result: passed diff --git a/src/App.tsx b/src/App.tsx index f1cd4a1..a86559a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -218,7 +218,7 @@ function ProjectChatRoute() { if (!project) { if (!cancelled) { setResolvedProjectKey(null); - setResolvedRoute('config'); + setResolvedRoute('chat'); } return; } diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index f5e9b8b..ab02f53 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -31,6 +31,7 @@ import { import { getAiModuleForPath } from '@/lib/ai-modules'; import { invokeIpc } from '@/lib/api-client'; import { getAuthUserDisplayName } from '@/lib/auth-user-display'; +import { subscribeCodingProjectCreationRequest } from '@/lib/coding-project-entry'; import { WORKS_SQUARE_TOKEN_USAGE_STALE_EVENT } from '@/lib/works-square-usage-events'; import { fetchWorksTokenUsage, type WorksTokenUsage } from '@/lib/works-square'; import { isWorksTokenUsageExhausted } from '@/lib/works-square-token-usage'; @@ -393,7 +394,7 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi }, [authUser, refreshTokenUsage]); - const openCreateProject = () => { + const openCreateProject = useCallback(() => { setNewProjectName(''); setNewProjectSelectedPath(''); setNewProjectDirectoryMode('use-selected-directory'); @@ -402,7 +403,12 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi setNewProjectIdentityProjectId(''); setCreateProjectError(null); setCreateDialogOpen(true); - }; + }, []); + + useEffect(() => { + if (!isProgrammingModule) return undefined; + return subscribeCodingProjectCreationRequest(openCreateProject); + }, [isProgrammingModule, openCreateProject]); const closeCreateProject = () => { if (creatingProject) return; diff --git a/src/lib/coding-project-entry.ts b/src/lib/coding-project-entry.ts new file mode 100644 index 0000000..b8c5993 --- /dev/null +++ b/src/lib/coding-project-entry.ts @@ -0,0 +1,12 @@ +const CODING_PROJECT_CREATE_REQUEST_EVENT = 'makelore:coding-project-create-request'; + +export function requestCodingProjectCreation(): void { + if (typeof window === 'undefined') return; + window.dispatchEvent(new Event(CODING_PROJECT_CREATE_REQUEST_EVENT)); +} + +export function subscribeCodingProjectCreationRequest(listener: () => void): () => void { + if (typeof window === 'undefined') return () => undefined; + window.addEventListener(CODING_PROJECT_CREATE_REQUEST_EVENT, listener); + return () => window.removeEventListener(CODING_PROJECT_CREATE_REQUEST_EVENT, listener); +} diff --git a/src/pages/Chat/CodingChatPanel.tsx b/src/pages/Chat/CodingChatPanel.tsx index 35bdd7b..4f27fe4 100644 --- a/src/pages/Chat/CodingChatPanel.tsx +++ b/src/pages/Chat/CodingChatPanel.tsx @@ -1,8 +1,11 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { - Bot, + ArrowUp, CircleAlert, + FolderKanban, + Plus, RefreshCw, + Settings2, } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { @@ -40,10 +43,12 @@ import { CodingConversationSidebar } from './CodingConversationSidebar'; import { CodingConversationHeader } from './CodingConversationHeader'; import { CodingConversationTimeline } from './CodingConversationTimeline'; import { CodingInteractionPanel } from './CodingInteractionPanel'; +import { CodingWelcomeHero } from './CodingWelcomeHero'; import { createLocalConversationSnapshot } from './coding-chat-snapshot'; export interface CodingChatPanelProps { navigationDraft?: string; + onCreateProject?(): void; onOpenProjectSettings?(): void; } @@ -109,6 +114,7 @@ function acceptedPromptCount( export function CodingChatPanel({ navigationDraft, + onCreateProject, onOpenProjectSettings, }: CodingChatPanelProps) { const activeProject = useCodingWorkspaceStore((state) => state.activeProject); @@ -592,18 +598,87 @@ export function CodingChatPanel({ if (!activeProject && workspaceLoadState !== 'loading') { return ( -
-
-
-