fix: simplify coding project card rail

This commit is contained in:
inman
2026-09-06 16:12:24 +08:00
parent faf751be5e
commit ce90f57ce7
5 changed files with 32 additions and 23 deletions

View File

@@ -22,6 +22,8 @@
- Apply the user's follow-up correction: the lower landing surface is a standalone - Apply the user's follow-up correction: the lower landing surface is a standalone
`新增项目` CTA followed by horizontally arranged existing-project cards, not a `新增项目` CTA followed by horizontally arranged existing-project cards, not a
composer-shaped project starter. composer-shaped project starter.
- Apply the user's final copy correction: remove the visible `已有项目` heading and
`选择一个项目继续` helper while retaining the horizontal project-card rail.
## Intent And Constraints ## Intent And Constraints
@@ -47,7 +49,8 @@
- The no-project view uses the existing Makelore M vector asset and a large - The no-project view uses the existing Makelore M vector asset and a large
centered guide sentence while retaining the Makelore sidebar and light visual centered guide sentence while retaining the Makelore sidebar and light visual
system. Its lower surface now uses the user's clarified standalone orange system. Its lower surface now uses the user's clarified standalone orange
`新增项目` CTA followed by an overflow-safe horizontal row of existing projects. `新增项目` CTA followed directly by an overflow-safe horizontal row of existing
projects, without the redundant visible project-section heading or helper copy.
- Project creation reuses the Sidebar's existing dialog through a renderer-local - Project creation reuses the Sidebar's existing dialog through a renderer-local
event bridge; project-card selection uses the same bridge to invoke the event bridge; project-card selection uses the same bridge to invoke the
Sidebar's validated entry flow instead of duplicating project activation. Sidebar's validated entry flow instead of duplicating project activation.
@@ -69,6 +72,12 @@
- Follow-up focused run: - Follow-up focused run:
`corepack pnpm exec vitest run tests/unit/coding-chat-panel.test.tsx tests/unit/coding-project-entry.test.ts tests/unit/module-navigation.test.tsx tests/unit/app-module-provider-gate.test.tsx --maxWorkers=4` `corepack pnpm exec vitest run tests/unit/coding-chat-panel.test.tsx tests/unit/coding-project-entry.test.ts tests/unit/module-navigation.test.tsx tests/unit/app-module-provider-gate.test.tsx --maxWorkers=4`
— 4 files, 48 tests passed. — 4 files, 48 tests passed.
- Final-copy focused run:
`corepack pnpm exec vitest run tests/unit/coding-chat-panel.test.tsx tests/unit/coding-project-entry.test.ts --maxWorkers=2`
— 2 files, 23 tests passed, including assertions that `已有项目` and
`选择一个项目继续` stay absent while real cards remain.
- `corepack pnpm exec eslint src/pages/Chat/CodingChatPanel.tsx tests/unit/coding-chat-panel.test.tsx tests/e2e/main-navigation.spec.ts`
— passed with no output.
- `corepack pnpm test` — 223 files passed; 1,863 tests passed and 3 skipped. - `corepack pnpm test` — 223 files passed; 1,863 tests passed and 3 skipped.
- `corepack pnpm run lint:check` — passed with 0 errors and the repository's 5 - `corepack pnpm run lint:check` — passed with 0 errors and the repository's 5
pre-existing warnings in `src/pages/Home/index.tsx` and pre-existing warnings in `src/pages/Home/index.tsx` and
@@ -79,14 +88,15 @@
- `corepack pnpm exec playwright test tests/e2e/main-navigation.spec.ts --grep - `corepack pnpm exec playwright test tests/e2e/main-navigation.spec.ts --grep
"offers a create CTA|returns to the module chooser"` — 2 tests passed against "offers a create CTA|returns to the module chooser"` — 2 tests passed against
the built Electron app, covering empty and remembered-project entry states, the built Electron app, covering empty and remembered-project entry states,
horizontal card order, direct card entry, `/chat`, and project-dialog launch. absent section/helper copy, horizontal card order, direct card entry, `/chat`,
and project-dialog launch.
- `git diff --check` — passed. - `git diff --check` — passed.
- Visual comparison: - Visual comparison:
`/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/codex-reference-vs-makelore-v2.png` `/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/codex-reference-vs-makelore-v3.png`
plus the focused lower crop plus the focused lower crop
`/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/codex-reference-vs-makelore-v2-bottom.png` `/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/codex-reference-vs-makelore-v3-bottom.png`
— the user-identified composer/CTA mismatch is resolved and no actionable — the user-identified composer/CTA and redundant-copy mismatches are resolved,
P0/P1/P2 differences remain. and no actionable P0/P1/P2 differences remain.
## Follow-ups ## Follow-ups
@@ -101,9 +111,9 @@
`.project-docs/40-domain/business-rules.md`. `.project-docs/40-domain/business-rules.md`.
Proposal: record that entering Code with no active local project remains on Proposal: record that entering Code with no active local project remains on
`/chat`, presents the branded hero, a standalone `新增项目` CTA, and real local `/chat`, presents the branded hero, a standalone `新增项目` CTA, and real local
projects as a horizontal card row. Creation and project-card entry route through projects as an unlabeled horizontal card row. Creation and project-card entry
the single existing Sidebar flows; empty Conversations share the same brand route through the single existing Sidebar flows; empty Conversations share the
hero until their first entry. same brand hero until their first entry.
Evidence: focused unit coverage, the passing Electron navigation regression, Evidence: focused unit coverage, the passing Electron navigation regression,
production build, and the passed side-by-side visual QA. production build, and the passed side-by-side visual QA.
Future impact: future routing or setup work must not restore the configuration Future impact: future routing or setup work must not restore the configuration

View File

@@ -1,20 +1,20 @@
**Comparison Target** **Comparison Target**
- Source visual truth: `/var/folders/m7/x9ry3xgx4x50fxb20_0108tr0000gn/T/codex-clipboard-58e2cc35-7a17-4951-8bbc-53fee12d5246.png`, superseded at the lower action area by the user's explicit follow-up: use a standalone `新增项目` CTA and horizontally arranged existing-project cards, not a conversation box. - Source visual truth: `/var/folders/m7/x9ry3xgx4x50fxb20_0108tr0000gn/T/codex-clipboard-58e2cc35-7a17-4951-8bbc-53fee12d5246.png`, superseded at the lower action area by the user's explicit follow-ups: use a standalone `新增项目` CTA and horizontally arranged existing-project cards, not a conversation box, and omit the visible `已有项目` / `选择一个项目继续` labels.
- Implementation screenshot: `/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/makelore-coding-default-v2.png` - Implementation screenshot: `/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/makelore-coding-default-v3.png`
- Full-view comparison: `/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/codex-reference-vs-makelore-v2.png` - Full-view comparison: `/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/codex-reference-vs-makelore-v3.png`
- Focused lower-region comparison: `/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/codex-reference-vs-makelore-v2-bottom.png` - Focused lower-region comparison: `/Users/inmanx/.codex/visualizations/2026/09/06/01a0756a-b6f5-7892-a11c-1c1608ebe592/codex-reference-vs-makelore-v3-bottom.png`
- State: Codex reference start screen and Makelore Code with two remembered local projects but no active project. - State: Codex reference start screen and Makelore Code with two remembered local projects but no active 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 remained at its native 1280 x 800 size. The focused comparison uses a 400-pixel-tall lower crop from each normalized content region. - 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 remained at its native 1280 x 800 size. The focused comparison uses a 400-pixel-tall lower crop from each normalized content region.
**Findings** **Findings**
- No actionable P0, P1, or P2 differences remain after applying the user's correction. - No actionable P0, P1, or P2 differences remain after applying the user's correction.
- Fonts and typography: the M hero keeps the reference's restrained system-sans hierarchy and single-line display copy. The CTA, section label, project names, and recency metadata form a clear descending hierarchy without crowding or truncation at the verified viewport. - Fonts and typography: the M hero keeps the reference's restrained system-sans hierarchy and single-line display copy. The CTA, project names, and recency metadata form a clear descending hierarchy without crowding or truncation at the verified viewport.
- Spacing and layout rhythm: the hero retains generous white space. The standalone CTA is visually separated from the existing-project row, and fixed-width cards create a true horizontal browsing pattern without increasing page height as the catalog grows. - Spacing and layout rhythm: the hero retains generous white space. The standalone CTA is visually separated from the existing-project row, and fixed-width cards create a true horizontal browsing pattern without increasing page height as the catalog grows.
- Colors and visual tokens: the CTA uses the existing Makelore brand orange and the cards use existing neutral surface tokens, preserving the single light product system and one-accent discipline. - Colors and visual tokens: the CTA uses the existing Makelore brand orange and the cards use existing neutral surface tokens, preserving the single light product system and one-accent discipline.
- Image quality and asset fidelity: the hero uses the repository's existing vector Makelore M asset. Project cards use the product's installed icon library; no placeholder image, CSS drawing, or reconstructed logo is present. - Image quality and asset fidelity: the hero uses the repository's existing vector Makelore M asset. Project cards use the product's installed icon library; no placeholder image, CSS drawing, or reconstructed logo is present.
- Copy and content: `新增项目`, `已有项目`, and `选择一个项目继续` state the two available paths directly. Project cards use real project names and last-opened timestamps from the local catalog. - Copy and content: `新增项目` remains the only action label above the card rail. The redundant `已有项目` heading and `选择一个项目继续` helper are absent; project cards themselves use real project names and last-opened timestamps from the local catalog.
- Interaction and accessibility: the CTA opens the existing creation dialog; each card has a project-specific accessible name, keyboard focus treatment, pressed feedback, horizontal overflow, and routes through the Sidebar's existing validated project-entry behavior. - Interaction and accessibility: the CTA opens the existing creation dialog; each card has a project-specific accessible name, keyboard focus treatment, pressed feedback, horizontal overflow, and routes through the Sidebar's existing validated project-entry behavior.
**Open Questions** **Open Questions**
@@ -35,6 +35,7 @@
- Pass 1: the user identified a P1 interaction-model mismatch: the lower surface looked like a default conversation box and omitted horizontally arranged existing projects. - Pass 1: the user identified a P1 interaction-model mismatch: the lower surface looked like a default conversation box and omitted horizontally arranged existing projects.
- Fix: replaced the composer-shaped starter with a standalone `新增项目` CTA; added a horizontal, overflow-safe row backed by the real project catalog; connected card clicks to the existing Sidebar entry path; added unit and Electron coverage. - Fix: replaced the composer-shaped starter with a standalone `新增项目` CTA; added a horizontal, overflow-safe row backed by the real project catalog; connected card clicks to the existing Sidebar entry path; added unit and Electron coverage.
- Pass 2: the revised full-view and focused comparisons show the corrected CTA/card hierarchy with no remaining actionable P0/P1/P2 findings. - Pass 2: the revised full-view and focused comparisons show the corrected CTA/card hierarchy with no remaining actionable P0/P1/P2 findings.
- Pass 3: removed the visible project-section heading and helper copy at the user's request. The fresh screenshot and focused comparison confirm that the CTA now leads directly into the unchanged horizontal card rail.
**Implementation Checklist** **Implementation Checklist**
@@ -42,6 +43,7 @@
- [x] Remove the composer-shaped no-project starter. - [x] Remove the composer-shaped no-project starter.
- [x] Add one standalone `新增项目` primary CTA. - [x] Add one standalone `新增项目` primary CTA.
- [x] Render real existing projects as horizontal cards. - [x] Render real existing projects as horizontal cards.
- [x] Remove the visible `已有项目` and `选择一个项目继续` labels.
- [x] Reuse the existing creation and validated project-entry flows. - [x] Reuse the existing creation and validated project-entry flows.
- [x] Verify both the empty catalog and remembered-project states in Electron. - [x] Verify both the empty catalog and remembered-project states in Electron.

View File

@@ -647,14 +647,7 @@ export function CodingChatPanel({
</Button> </Button>
{projects.length > 0 ? ( {projects.length > 0 ? (
<section className="mt-7" aria-labelledby="coding-existing-projects-title"> <section className="mt-7" aria-label="项目列表">
<div className="mb-3 flex items-end justify-between gap-4 px-0.5">
<h2 id="coding-existing-projects-title" className="text-sm font-semibold tracking-[-0.01em]">
</h2>
<p className="text-xs text-muted-foreground"></p>
</div>
<div <div
className="flex gap-3 overflow-x-auto pb-2" className="flex gap-3 overflow-x-auto pb-2"
data-testid="coding-existing-projects" data-testid="coding-existing-projects"

View File

@@ -64,6 +64,8 @@ test.describe('Makelore module navigation without setup flow', () => {
await expect(page).toHaveURL(/\/chat$/); await expect(page).toHaveURL(/\/chat$/);
await expect(page.getByRole('button', { name: '新增项目' })).toBeVisible(); await expect(page.getByRole('button', { name: '新增项目' })).toBeVisible();
await expect(page.getByText('已有项目')).toHaveCount(0);
await expect(page.getByText('选择一个项目继续')).toHaveCount(0);
const projectCards = page.getByTestId('coding-existing-projects'); const projectCards = page.getByTestId('coding-existing-projects');
await expect(projectCards).toBeVisible(); await expect(projectCards).toBeVisible();
await expect(projectCards.getByRole('button')).toHaveCount(2); await expect(projectCards.getByRole('button')).toHaveCount(2);

View File

@@ -226,6 +226,8 @@ describe('CodingChatPanel first Conversation', () => {
expect(screen.getByRole('button', { name: '新增项目' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '新增项目' })).toBeInTheDocument();
expect(screen.getByTestId('coding-existing-projects')).toHaveTextContent('Local project'); expect(screen.getByTestId('coding-existing-projects')).toHaveTextContent('Local project');
expect(screen.getByTestId('coding-existing-projects')).toHaveTextContent('Second local project'); expect(screen.getByTestId('coding-existing-projects')).toHaveTextContent('Second local project');
expect(screen.queryByText('已有项目')).not.toBeInTheDocument();
expect(screen.queryByText('选择一个项目继续')).not.toBeInTheDocument();
expect(screen.queryByTestId('coding-project-starter')).not.toBeInTheDocument(); expect(screen.queryByTestId('coding-project-starter')).not.toBeInTheDocument();
expect(screen.queryByRole('button', { name: '项目与插件设置' })).not.toBeInTheDocument(); expect(screen.queryByRole('button', { name: '项目与插件设置' })).not.toBeInTheDocument();