Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions PRODUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Whisper Input Product Context

## Product Register

- Register: Product UI
- Platform: Windows desktop application built with Tauri and React
- Primary users: Chinese-speaking workplace users who use voice input for daily writing and question answering
- Core purpose: turn speech into text, optionally polish or structure it with a configured LLM, and insert the result into the active application

## Design Direction

- Personality: quiet, trustworthy, efficient, and familiar
- Density: compact enough for a 1240 x 800 desktop window without sacrificing readable type or 40 px control targets
- Hierarchy: use spacing, alignment, typography, and lightweight separators before borders or shadows
- Component language: preserve the existing sidebar, settings tabs, cards, buttons, toggles, icon system, tokens, and Chinese/English localization
- Motion: restrained and functional; respect reduced-motion preferences

## Current Iteration

- Scope: Settings > Privacy & Data only
- Selected reference: the third generated layout shown on 2026-07-11
- Goal: make all privacy explanations and five existing controls visible in the standard desktop viewport
- Functional constraint: do not change copy, handlers, confirmation dialogs, persistence, API keys, provider configuration behavior, or diagnostic export behavior
- Responsive constraint: preserve the compact desktop composition and fall back to a single column when the content area becomes narrow

## Anti-References

- Avoid one oversized vertical list with large empty areas
- Avoid nested cards, heavy borders, decorative shadows, loud danger styling, and unnecessary new labels
- Avoid new icons, features, routes, buttons, or rewritten explanatory text
103 changes: 103 additions & 0 deletions docs/superpowers/plans/2026-07-11-privacy-data-layout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Privacy And Data Layout 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:** Rebuild the Privacy & Data settings surface to match the selected compact data-lifecycle layout without changing any behavior or copy.

**Architecture:** Keep `PrivacySection` and all of its existing handlers in `Settings.tsx`. Replace only its JSX grouping with semantic layout classes, then implement the visual hierarchy in the existing replica stylesheet. Extend the existing source-contract test so future edits cannot silently remove the approved groups or restore the oversized privacy card width.

**Tech Stack:** React 18, TypeScript, Vite, Tauri 2, Node built-in test runner, existing CSS tokens and UI components.

## Global Constraints

- Change only the Privacy & Data page structure and visual styling.
- Preserve every existing label, description, button, toggle, handler, confirmation, IPC call, busy state, and notification.
- Do not add dependencies, icons, routes, API calls, or new settings.
- Fit the standard 1240 x 800 desktop window without page scrolling.
- Keep a responsive single-column fallback for narrow content areas.

---

### Task 1: Privacy Layout Contract

**Files:**
- Modify: `src/lib/frontendReplicaContract.test.ts`
- Test: `src/lib/frontendReplicaContract.test.ts`

**Interfaces:**
- Consumes: source text from `src/pages/Settings.tsx` and `src/styles/preview-replica.css`
- Produces: regression assertions for `wi-privacy-data-flow`, `wi-privacy-retention`, `wi-privacy-maintenance`, and the responsive privacy layout

- [ ] **Step 1: Write the failing test**

Add assertions that require the three approved semantic groups and their responsive CSS selectors.

- [ ] **Step 2: Run the focused test and verify failure**

Run: `node --test src/lib/frontendReplicaContract.test.ts`

Expected: FAIL because the new privacy layout classes do not exist yet.

- [ ] **Step 3: Keep the failing output as the implementation baseline**

Confirm the failure names the missing privacy layout class rather than an unrelated test or runtime error.

### Task 2: Selected Layout Implementation

**Files:**
- Modify: `src/pages/Settings.tsx`
- Modify: `src/styles/preview-replica.css`
- Test: `src/lib/frontendReplicaContract.test.ts`

**Interfaces:**
- Consumes: existing `Card`, `Toggle`, `Btn`, translations, handlers, and `privacyHelpItemsCopy`
- Produces: the compact privacy information band and grouped retention/maintenance actions

- [ ] **Step 1: Restructure only the `PrivacySection` JSX**

Wrap the existing help items in `wi-privacy-data-flow`, the history toggle and local clear actions in `wi-privacy-retention`, and configuration/diagnostics actions in `wi-privacy-maintenance`. Keep each existing control expression and callback unchanged.

- [ ] **Step 2: Add the layout CSS**

Use compact grid rows, lightweight separators, right-aligned controls, and a narrow-width media/container fallback. Remove the privacy card's restrictive 860 px width so the selected layout can use the available content area.

- [ ] **Step 3: Run the focused test and verify it passes**

Run: `node --test src/lib/frontendReplicaContract.test.ts`

Expected: all source-contract tests pass.

- [ ] **Step 4: Run production compilation**

Run: `npm run build`

Expected: TypeScript and Vite complete without errors.

### Task 3: Desktop Runtime And Visual QA

**Files:**
- Modify: `design-qa.md`

**Interfaces:**
- Consumes: selected generated option 3 and the locally running Tauri application
- Produces: a same-state visual comparison and final QA result

- [ ] **Step 1: Restart the Tauri desktop application**

Stop only the running `src-tauri\\target\\debug\\whisper-input.exe` process and relaunch the existing Tauri dev command so current local configuration remains in use.

- [ ] **Step 2: Capture the Privacy & Data page at 1240 x 800**

Open Settings, select Privacy & Data, and capture the running desktop window in the same state as the selected reference.

- [ ] **Step 3: Compare the selected reference and implementation together**

Check content fit, hierarchy, spacing, row alignment, button visibility, clipping, borders, and scrollbar state. Fix P0-P2 issues and repeat the capture.

- [ ] **Step 4: Record the result**

Update `design-qa.md` with the reference path, implementation capture path, findings table, and the exact line `final result: passed` only after all blocking issues are resolved.

- [ ] **Step 5: Keep the local application running for user inspection**

Report the running executable path and local frontend URL used by the desktop application.
48 changes: 48 additions & 0 deletions docs/superpowers/specs/2026-07-11-privacy-data-layout-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Privacy And Data Layout Design

## Scope

Redesign only the visual structure of `Settings > Privacy & Data`. Preserve all existing controls, labels, descriptions, state, async behavior, confirmations, IPC calls, and notification behavior.

## Approved Direction

The user selected the third generated concept: a clear data-lifecycle layout that separates privacy information, local retention, and maintenance actions while fitting the standard 1240 x 800 desktop window.

## Information Architecture

1. Keep the existing settings navigation and selected Privacy & Data tab unchanged.
2. Present the existing audio, recognized text, and local data explanations as a compact three-row information band.
3. Present local retention actions in one grouped surface:
- Save history, with the existing toggle.
- Clear history, with the existing button.
- Clear vocabulary, with the existing button.
4. Present maintenance actions in a second grouped surface:
- Clear configuration, with the existing button.
- Export diagnostic bundle, with the existing button.

## Visual Rules

- Use the existing design tokens, components, typography, and icon system.
- Use spacing, alignment, subtle surface tint, and row separators before borders and shadows.
- Keep body text at the existing readable product scale.
- Keep interactive targets at least 40 px high.
- Keep button alignment consistent on the right side of each action row.
- Avoid nested cards and avoid introducing new icons or decorative assets.
- At narrow content widths, switch grouped action rows to a single-column layout without clipping text or controls.

## Functional Invariants

- `onHistoryEnabledChange` continues to call `updatePrefs` and refresh on failure.
- Clear-history, clear-vocabulary, and clear-configuration confirmations remain unchanged.
- `runAction`, busy states, saved notifications, and failure notifications remain unchanged.
- Diagnostic filename generation and `exportDiagnosticBundle` invocation remain unchanged.
- Existing localization keys and `privacyHelpItemsCopy` content remain unchanged.

## Acceptance Criteria

- All three privacy explanations and all five controls are visible at 1240 x 800 without page scrolling.
- Existing actions remain keyboard reachable and retain their disabled/busy states.
- The page has no new visible heavy border or nested-card treatment.
- The layout remains usable at a narrower desktop content width through a responsive single-column fallback.
- TypeScript tests and the production build pass.
- Same-viewport visual QA compares the selected generated reference with the running desktop application and records `final result: passed` in `design-qa.md`.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "whisper-input-app",
"private": true,
"version": "1.3.26",
"version": "1.3.27",
"license": "Apache-2.0",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "whisper-input"
version = "1.3.26"
version = "1.3.27"
description = "Whisper Input - Windows AI voice input powered by cloud speech recognition and LLM polish"
authors = ["Qingyu Input"]
license = "Apache-2.0"
Expand Down
6 changes: 3 additions & 3 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://schema.tauri.app/config/2",
"productName": "Whisper Input",
"mainBinaryName": "whisper-input",
"version": "1.3.26",
"version": "1.3.27",
"identifier": "com.qingyu.input",
"build": {
"beforeDevCommand": "npm run dev",
Expand All @@ -22,9 +22,9 @@
"minWidth": 980,
"minHeight": 640,
"resizable": true,
"decorations": true,
"decorations": false,
"transparent": true,
"shadow": true,
"shadow": false,
"hiddenTitle": true,
"titleBarStyle": "Overlay",
"trafficLightPosition": { "x": 14, "y": 20 },
Expand Down
4 changes: 1 addition & 3 deletions src/components/WindowChrome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,7 @@ export function WindowChrome({
height,
position: 'relative',
borderRadius: 'var(--ol-window-shell-radius)',
boxShadow: os === 'win'
? '0 18px 42px -26px rgba(15, 17, 22, 0.42)'
: 'var(--ol-shadow-xl)',
boxShadow: os === 'win' ? 'none' : 'var(--ol-shadow-xl)',
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
Expand Down
3 changes: 2 additions & 1 deletion src/components/shell/PageContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export function PageContainer({ children, phase }: PageContainerProps) {
style={{
flex: 1,
minHeight: 0,
overflow: 'hidden',
overflow: 'auto',
overflowX: 'hidden',
padding: 0,
position: 'relative',
animation: phase === 'exiting' ? 'ol-page-fadeout 0.12s linear forwards' : undefined,
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/Row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function Row({ label, desc, children }: RowProps) {
<div style={{ display: 'grid', gridTemplateColumns: '180px 1fr', gap: 16, padding: '12px 0', borderTop: '0.5px solid var(--ol-line-soft)' }}>
<div>
<div style={{ fontSize: 13, fontWeight: 500, color: 'var(--ol-ink)' }}>{label}</div>
{desc && <div style={{ fontSize: 11.5, color: 'var(--ol-ink-4)', marginTop: 4, lineHeight: 1.5 }}>{desc}</div>}
{desc && <div style={{ fontSize: 12.5, color: 'var(--ol-ink-4)', marginTop: 4, lineHeight: 1.55 }}>{desc}</div>}
</div>
<div style={{ display: 'flex', alignItems: 'center' }}>{children}</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/SettingRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function SettingRow({ label, desc, children, controlWidth }: SettingRowPr
{desc && (
<div
className="ol-setting-desc"
style={{ fontSize: 11.5, color: 'var(--ol-ink-4)', marginTop: 4, lineHeight: 1.5 }}
style={{ fontSize: 12.5, color: 'var(--ol-ink-4)', marginTop: 4, lineHeight: 1.55 }}
>
{desc}
</div>
Expand Down
Loading
Loading