mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-06-22 06:03:49 +08:00
docs(ui): plan client polish fixes
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
# Client UI Polish Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Fix the client-side account, favorites, reviews, sync, restore, and shell UI issues reported in QA.
|
||||
|
||||
**Architecture:** Preserve existing Vue component boundaries. Add thin wrappers/helpers for modal account management, custom titlebar, review star controls, and sync restore candidate resolution. Backend-dependent review actions are client-side affordances only until backend endpoints exist.
|
||||
|
||||
**Tech Stack:** Vue 3 Composition API, TypeScript strict mode, Electron IPC, Tailwind CSS, Vitest, Testing Library Vue.
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
- Create `src/components/UserManagementModal.vue` to present `UserManagementView` as a global overlay.
|
||||
- Create `src/components/WindowTitleBar.vue` for frameless titlebar UI and window controls.
|
||||
- Modify `src/App.vue` to mount the new account modal, pass sync feedback to installed apps modal, pass favorite status to detail modal, and use restore candidate helper.
|
||||
- Modify `src/components/AppSidebar.vue` and `src/components/AccountQuickMenu.vue` for overflow-safe labels and menu closing coverage.
|
||||
- Modify `src/components/UserManagementView.vue` for cover-image rendering and modal-friendly layout.
|
||||
- Modify `src/components/InstalledAppsModal.vue` to show sync feedback locally.
|
||||
- Modify `src/components/FavoriteFolderSelector.vue` for normalized default-folder de-dupe and favorited-state text/actions.
|
||||
- Modify `src/components/FavoriteFolderManager.vue` so the entire row content opens detail while checkbox stays isolated.
|
||||
- Modify `src/components/AppDetailModal.vue` and `src/components/AppDetailPage.vue` to show `已收藏` state.
|
||||
- Modify `src/components/ReviewsPanel.vue` for star rating, filters, user detail affordance, and disabled backend-dependent actions.
|
||||
- Modify `src/modules/appListSync.ts` for `resolveCloudInstallCandidate()`.
|
||||
- Modify `electron/main/index.ts`, `electron/preload/index.ts`, and `src/vite-env.d.ts` for frameless window controls.
|
||||
- Add/update unit tests under `src/__tests__/unit/`.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Account Menu And User Management Modal
|
||||
|
||||
**Files:**
|
||||
- Create: `src/components/UserManagementModal.vue`
|
||||
- Modify: `src/App.vue`
|
||||
- Modify: `src/components/AppSidebar.vue`
|
||||
- Modify: `src/components/AccountQuickMenu.vue`
|
||||
- Modify: `src/components/UserManagementView.vue`
|
||||
- Modify: `src/global/typedefinition.ts`
|
||||
- Modify: `src/modules/backendApi.ts`
|
||||
- Modify: `src/global/authState.ts`
|
||||
- Test: `src/__tests__/unit/AppSidebar.account.test.ts`
|
||||
- Test: `src/__tests__/unit/UserManagementView.test.ts`
|
||||
- Test: `src/__tests__/unit/App.account-placeholders.test.ts`
|
||||
- Test: `src/__tests__/unit/accountTypes.test.ts`
|
||||
- Test: `src/__tests__/unit/authState.test.ts`
|
||||
|
||||
- [ ] **Step 1: Write failing sidebar tests**
|
||||
|
||||
Add tests to `src/__tests__/unit/AppSidebar.account.test.ts` that verify each quick-menu action closes the menu, and that a user with empty `displayName` and long `username` still gets truncate/min-width classes.
|
||||
|
||||
- [ ] **Step 2: Run sidebar tests red**
|
||||
|
||||
Run: `npm run test -- --run src/__tests__/unit/AppSidebar.account.test.ts`
|
||||
|
||||
Expected: FAIL for missing fallback username coverage or quick-menu item truncation coverage.
|
||||
|
||||
- [ ] **Step 3: Implement sidebar overflow and close safety**
|
||||
|
||||
Update account label wrappers and quick-menu item labels with `min-w-0`, `truncate`, and explicit close-before-emit behavior already used by the parent.
|
||||
|
||||
- [ ] **Step 4: Write failing user management modal tests**
|
||||
|
||||
Update `src/__tests__/unit/App.account-placeholders.test.ts` so opening “用户管理” asserts a `role="dialog"` overlay exists and the main app grid/favorites frame is not replaced by `currentView === 'account'`.
|
||||
|
||||
- [ ] **Step 5: Write failing cover field tests**
|
||||
|
||||
Update `src/__tests__/unit/accountTypes.test.ts`, `authState.test.ts`, and `UserManagementView.test.ts` for optional `coverUrl` on `SparkUser` and visible cover rendering.
|
||||
|
||||
- [ ] **Step 6: Implement modal and cover rendering**
|
||||
|
||||
Add `UserManagementModal.vue`, add `showUserManagementModal` state in `App.vue`, keep `currentView` unchanged when opening user management, and pass through `close`, `open-forum`, `edit-profile`, `toggle-sync`, `sync-now`, and `refresh-downloads` events.
|
||||
|
||||
- [ ] **Step 7: Run account tests green**
|
||||
|
||||
Run: `npm run test -- --run src/__tests__/unit/AppSidebar.account.test.ts src/__tests__/unit/UserManagementView.test.ts src/__tests__/unit/App.account-placeholders.test.ts src/__tests__/unit/accountTypes.test.ts src/__tests__/unit/authState.test.ts`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Favorites State And Interaction Polish
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/App.vue`
|
||||
- Modify: `src/components/FavoriteFolderSelector.vue`
|
||||
- Modify: `src/components/FavoriteFolderManager.vue`
|
||||
- Modify: `src/components/AppDetailModal.vue`
|
||||
- Modify: `src/components/AppDetailPage.vue`
|
||||
- Modify: `src/modules/backendApi.ts`
|
||||
- Test: `src/__tests__/unit/FavoriteFolderSelector.test.ts`
|
||||
- Test: `src/__tests__/unit/FavoriteFolderManager.test.ts`
|
||||
- Test: `src/__tests__/unit/AppDetailModal.test.ts`
|
||||
- Test: `src/__tests__/unit/App.account-placeholders.test.ts`
|
||||
|
||||
- [ ] **Step 1: Write failing selector de-dupe tests**
|
||||
|
||||
Add a test where backend returns folder name ` 默认收藏夹 ` and assert only one default folder button appears.
|
||||
|
||||
- [ ] **Step 2: Run selector test red**
|
||||
|
||||
Run: `npm run test -- --run src/__tests__/unit/FavoriteFolderSelector.test.ts`
|
||||
|
||||
Expected: FAIL because current de-dupe compares exact name only.
|
||||
|
||||
- [ ] **Step 3: Normalize default folder names**
|
||||
|
||||
Trim folder names before default-folder comparison.
|
||||
|
||||
- [ ] **Step 4: Write failing detail favorite-state tests**
|
||||
|
||||
Add tests asserting a favorited app renders `已收藏` in `AppDetailModal` and emits the favorite action when clicked.
|
||||
|
||||
- [ ] **Step 5: Implement favorite state props**
|
||||
|
||||
Add `favorited`/`favoriteFolderName` props to detail components and compute current favorite metadata in `App.vue` from loaded folders/items.
|
||||
|
||||
- [ ] **Step 6: Write failing row click test**
|
||||
|
||||
Add a test that clicking the favorite row text/image area opens detail while clicking the checkbox only selects.
|
||||
|
||||
- [ ] **Step 7: Implement row-click behavior**
|
||||
|
||||
Make the favorite row content area larger/clickable and keep checkbox event isolated.
|
||||
|
||||
- [ ] **Step 8: Run favorites tests green**
|
||||
|
||||
Run: `npm run test -- --run src/__tests__/unit/FavoriteFolderSelector.test.ts src/__tests__/unit/FavoriteFolderManager.test.ts src/__tests__/unit/AppDetailModal.test.ts src/__tests__/unit/App.account-placeholders.test.ts`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Review Panel Client UX
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/components/ReviewsPanel.vue`
|
||||
- Modify: `src/global/typedefinition.ts`
|
||||
- Modify: `src/modules/backendApi.ts`
|
||||
- Test: `src/__tests__/unit/ReviewsPanel.test.ts`
|
||||
|
||||
- [ ] **Step 1: Write failing star rating test**
|
||||
|
||||
Add a test that clicks the “3 星” star button and verifies `submitReview` receives `rating: 3`.
|
||||
|
||||
- [ ] **Step 2: Write failing filter test**
|
||||
|
||||
Add reviews with different `packageArch` and `distro`; assert selecting an architecture or OS filter hides non-matching reviews.
|
||||
|
||||
- [ ] **Step 3: Write failing review action/user tests**
|
||||
|
||||
Add a test that reviewer avatar/name are buttons emitting/showing user detail affordance, and that like/reply/delete controls render with delete disabled unless local permission allows it.
|
||||
|
||||
- [ ] **Step 4: Run review tests red**
|
||||
|
||||
Run: `npm run test -- --run src/__tests__/unit/ReviewsPanel.test.ts`
|
||||
|
||||
Expected: FAIL because current UI uses select rating and lacks filters/actions.
|
||||
|
||||
- [ ] **Step 5: Implement star rating and filters**
|
||||
|
||||
Replace the native rating select with five star buttons and add local filter controls for package architecture and distro.
|
||||
|
||||
- [ ] **Step 6: Implement client-only review actions**
|
||||
|
||||
Render like/reply/delete buttons. Like/reply show a local “后端接口接入后可用” message. Delete is visible only for author/admin-compatible client data; otherwise omit or disable it.
|
||||
|
||||
- [ ] **Step 7: Run review tests green**
|
||||
|
||||
Run: `npm run test -- --run src/__tests__/unit/ReviewsPanel.test.ts`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Sync Feedback And Cross-Origin Restore
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/App.vue`
|
||||
- Modify: `src/components/InstalledAppsModal.vue`
|
||||
- Modify: `src/modules/appListSync.ts`
|
||||
- Test: `src/__tests__/unit/appListSync.test.ts`
|
||||
- Test: `src/__tests__/unit/App.account-placeholders.test.ts`
|
||||
|
||||
- [ ] **Step 1: Write failing restore helper tests**
|
||||
|
||||
Add `resolveCloudInstallCandidate()` tests for exact origin/category match, same package fallback across origin, and no candidate.
|
||||
|
||||
- [ ] **Step 2: Run sync helper tests red**
|
||||
|
||||
Run: `npm run test -- --run src/__tests__/unit/appListSync.test.ts`
|
||||
|
||||
Expected: FAIL because helper is missing.
|
||||
|
||||
- [ ] **Step 3: Implement restore helper**
|
||||
|
||||
Export `resolveCloudInstallCandidate(item, apps)` from `appListSync.ts` and use it in `App.vue` `installCloudItems()`.
|
||||
|
||||
- [ ] **Step 4: Write failing sync feedback test**
|
||||
|
||||
Update `App.account-placeholders.test.ts` or `InstalledAppsModal.test.ts` to assert clicking sync in the installed-apps modal shows `同步完成` or an error message in that modal.
|
||||
|
||||
- [ ] **Step 5: Implement modal sync feedback prop**
|
||||
|
||||
Add `syncMessage` prop to `InstalledAppsModal.vue` and pass `syncStatusMessage` from `App.vue`.
|
||||
|
||||
- [ ] **Step 6: Run sync tests green**
|
||||
|
||||
Run: `npm run test -- --run src/__tests__/unit/appListSync.test.ts src/__tests__/unit/App.account-placeholders.test.ts src/__tests__/unit/InstalledAppsModal.test.ts`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Frameless Window And Shell Polish
|
||||
|
||||
**Files:**
|
||||
- Create: `src/components/WindowTitleBar.vue`
|
||||
- Modify: `src/App.vue`
|
||||
- Modify: `electron/main/index.ts`
|
||||
- Modify: `electron/preload/index.ts`
|
||||
- Modify: `src/vite-env.d.ts`
|
||||
- Test: add or update appropriate unit tests for titlebar component and source config.
|
||||
|
||||
- [ ] **Step 1: Write failing titlebar component test**
|
||||
|
||||
Create a unit test that renders `WindowTitleBar.vue`, clicks minimize/maximize/close, and verifies IPC messages are sent.
|
||||
|
||||
- [ ] **Step 2: Write failing Electron config test or static check**
|
||||
|
||||
Add a lightweight test/static assertion that `BrowserWindow` is created with `frame: false`.
|
||||
|
||||
- [ ] **Step 3: Implement IPC handlers and titlebar**
|
||||
|
||||
Set `frame: false` in `BrowserWindow`; add IPC listeners for window minimize, toggle maximize, and close using existing close guard; add `WindowTitleBar.vue` with drag/no-drag regions.
|
||||
|
||||
- [ ] **Step 4: Mount titlebar in App.vue**
|
||||
|
||||
Place the titlebar at the top of the root layout and adjust sticky header offsets as needed.
|
||||
|
||||
- [ ] **Step 5: Verify category capsule color**
|
||||
|
||||
Run existing `CategoryBar.test.ts`; no code change needed if it already asserts `#2b7fff`.
|
||||
|
||||
Run: `npm run test -- --run src/__tests__/unit/CategoryBar.test.ts`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
---
|
||||
|
||||
### Task 6: Final Verification
|
||||
|
||||
**Files:**
|
||||
- All files touched by previous tasks.
|
||||
|
||||
- [ ] **Step 1: Run targeted unit tests**
|
||||
|
||||
Run the union of tests touched by this plan:
|
||||
|
||||
```bash
|
||||
npm run test -- --run src/__tests__/unit/AppSidebar.account.test.ts src/__tests__/unit/UserManagementView.test.ts src/__tests__/unit/App.account-placeholders.test.ts src/__tests__/unit/accountTypes.test.ts src/__tests__/unit/authState.test.ts src/__tests__/unit/FavoriteFolderSelector.test.ts src/__tests__/unit/FavoriteFolderManager.test.ts src/__tests__/unit/AppDetailModal.test.ts src/__tests__/unit/ReviewsPanel.test.ts src/__tests__/unit/appListSync.test.ts src/__tests__/unit/InstalledAppsModal.test.ts src/__tests__/unit/CategoryBar.test.ts
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 2: Run production build**
|
||||
|
||||
Run: `npm run build:vite`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 3: Check diff whitespace**
|
||||
|
||||
Run: `git diff --check`
|
||||
|
||||
Expected: no output.
|
||||
|
||||
- [ ] **Step 4: Commit client changes**
|
||||
|
||||
Commit message: `fix(ui): polish account favorites reviews and shell`
|
||||
|
||||
- [ ] **Step 5: Push feature branch**
|
||||
|
||||
Push `fix/client-ui-account-favorites` for review or merge.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Client UI Polish Design
|
||||
|
||||
## Goal
|
||||
|
||||
Fix the client-side account, favorites, review, sync, and shell UI issues reported during QA without changing backend contracts in this pass.
|
||||
|
||||
## Scope
|
||||
|
||||
This pass is client-only. It can change Vue components, renderer state, Electron window chrome, tests, and docs. It must not invent successful backend behavior for review likes, replies, or deletes until backend endpoints exist.
|
||||
|
||||
## User-Visible Requirements
|
||||
|
||||
- Long account names must not overflow the sidebar account entry or account quick menu.
|
||||
- Account quick-menu actions must close the menu immediately after selection.
|
||||
- User management must open as a global modal/popup overlay instead of replacing only the right content frame.
|
||||
- User management should render a profile-cover hero when a user has a background/cover URL, with a safe fallback when absent.
|
||||
- Favorites should not show duplicate default-folder entries.
|
||||
- The favorite selector must expose a visible new-folder action.
|
||||
- Clicking a favorite item row should open app detail; the checkbox should remain only for bulk selection.
|
||||
- The detail favorite button should show favorited state as `已收藏`, and opening it should allow switching folder or cancelling the favorite when client data can identify the existing item.
|
||||
- Review rating input should use clickable/star UI instead of a native select.
|
||||
- Reviews should expose architecture and OS/distro filters.
|
||||
- Review cards should expose user detail entry points from avatar/name and show client-side action affordances for like/reply/delete. Delete must be visibly limited to the author/admin; persistence is deferred until backend APIs exist.
|
||||
- The system title bar should be replaced by a frameless Electron window with an app-rendered title bar and window controls.
|
||||
- Selected category capsule color must remain `#2B7FFF`.
|
||||
- Manual sync must show visible feedback where the user clicked it.
|
||||
- Restore-from-account should resolve cloud items by same origin first, then fall back to same package across Spark/APM when the exact origin is not loaded.
|
||||
|
||||
## Architecture
|
||||
|
||||
Keep existing component boundaries and make small additions:
|
||||
|
||||
- `App.vue` remains the state coordinator for account modals, favorites, sync, and restore.
|
||||
- Add a small reusable `UserManagementModal.vue` wrapper around existing `UserManagementView.vue` instead of restructuring the view.
|
||||
- Add a `WindowTitleBar.vue` component and Electron IPC handlers for minimize/maximize/close, preserving the existing close-to-tray guard.
|
||||
- Keep review API calls in `backendApi.ts`; client-only review actions emit UI feedback until backend endpoints are added.
|
||||
- Add pure helper functions for sync restore candidate resolution so cross-source matching can be unit-tested without mounting the full app.
|
||||
|
||||
## Data Flow
|
||||
|
||||
- Account menu emits actions to `App.vue`; `App.vue` toggles modal state and loads downloaded history before showing user management.
|
||||
- Favorites are loaded from existing folder/item endpoints. `App.vue` computes current detail favorite metadata from loaded folders/items and passes status to detail components.
|
||||
- Review filters are local to `ReviewsPanel.vue`; they filter loaded review records by package architecture and distro string.
|
||||
- Sync feedback is stored in existing `syncStatusMessage` and passed to both `UserManagementView` and `InstalledAppsModal`.
|
||||
- Restore resolution uses `resolveCloudInstallCandidate(item, apps)` with exact origin/category preference and package-name fallback.
|
||||
|
||||
## Deferred Backend Work
|
||||
|
||||
The following need backend API work later:
|
||||
|
||||
- Persistent review likes.
|
||||
- Review replies and reply listing.
|
||||
- Server-authorized review deletion.
|
||||
- Fetching arbitrary forum user profile details and cover images. This client pass supports cover URLs when present in `SparkUser`; it does not scrape forum HTML.
|
||||
|
||||
## Testing
|
||||
|
||||
- Add/update unit tests for account modal behavior, quick-menu closing, user cover rendering, favorites selector normalization, star rating, review filters/actions, restore candidate resolution, and titlebar IPC/config.
|
||||
- Run targeted Vitest files and `npm run build:vite` before completion.
|
||||
Reference in New Issue
Block a user