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
194 changes: 157 additions & 37 deletions DESIGN_SYSTEM.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,69 +4,189 @@

Street Tasks is a map-first WeChat mini program for short-lived neighborhood information. The UI should feel quick, local, trustworthy, and easy to scan while someone is outside or moving.

## Visual Direction
## Visual Direction — Modern Minimal

Use a warm, restrained local-life tool style. Avoid marketing-page hero layouts, glossy glass effects, heavy blue-purple gradients, oversized shadows, and decorative shapes that do not carry information.
Clean, white, generous whitespace, thin borders, almost no shadows. Color is used sparingly and meaningfully — one primary teal for actions and confirmations, orange accent for urgency. Inspired by Linear, Notion, and Apple native apps.

**Key principles:**
- White cards on light gray background — no decorative gradients
- Thin 1rpx borders at `#E5E7EB` — shadows only for floating elements (map tools)
- One primary color (`#0F766E` teal) for interactive elements
- Accent orange (`#EA580C`) used very sparingly: discover button, resolve action
- Typography hierarchy through weight (800/600/400), not color
- Small precise radii (10/12/14rpx) — not soft pill shapes
- No decorative patterns, grids, or ornaments

## TDesign Strategy

The project currently has no frontend build step and no mini program npm dependency pipeline. Keep the implementation native by default, but follow TDesign-style rules:

- Components should have predictable states: default, active, disabled, loading, empty, and error.
- Touch targets should be at least `72rpx` high for primary actions and at least `44rpx` for small icon controls.
- Card radius should stay at or below `16rpx`.
- Card radius should stay at or below `14rpx`.
- Use semantic colors instead of one-off values.
- If `tdesign-miniprogram` is introduced later, map these tokens to TDesign theme variables first, then replace native controls incrementally.

## Tokens

- Background: `#F4F1EA`
- Surface: `#FFFEFA`
- Surface muted: `#F7F3EA`
- Text strong: `#14211D`
- Text normal: `#2E423A`
- Text muted: `#697970`
- Border: `rgba(31, 63, 52, 0.12)`
- Primary: `#1F6658`
- Primary dark: `#143E37`
- Accent: `#D7673F`
- Warning: `#B9791F`
- Danger: `#A73527`
- Success surface: `#E4F0E9`
- Warning surface: `#FFF2DA`
- Danger surface: `#FFE9E2`

## Typography

- Page title: `40-44rpx`, `font-weight: 900`, line-height `1.12-1.18`.
- Section title: `30-32rpx`, `font-weight: 900`, line-height `1.25`.
- Body text: `28-30rpx`, line-height `1.5-1.6`.
- Meta text: `22-24rpx`, line-height `1.35-1.5`.
## Design Tokens (CSS Custom Properties)

All tokens are defined in `app.wxss` on the `page` selector and referenced via `var(--token-name)`. Never hard-code hex or rgba values in normal page-level WXSS — use the token. Exception: `cover-view` overlays above native components such as `map` must use hard-coded values because their style support is more limited.

### Color

| Token | Value | Usage |
|-------|-------|-------|
| `--bg` | `#F7F8FA` | Page background |
| `--surface` | `#FFFFFF` | Card/panel surface |
| `--surface-muted` | `#F2F3F5` | Secondary surface |
| `--surface-neutral` | `#F2F3F5` | Neutral surface, disabled bg |
| `--field-bg` | `#F7F8FA` | Input field background |
| `--primary-surface` | `#F0FDFA` | Light teal tint bg |
| `--primary-deep` | `#0F766E` | Deep teal (map bg) |
| `--primary` | `#0F766E` | Brand primary |
| `--primary-dark` | `#0D655E` | Primary dark |
| `--primary-text` | `#0F766E` | Primary text variant |
| `--accent` | `#EA580C` | Accent orange (rare use) |
| `--accent-dark` | `#C2410C` | Accent dark |
| `--warning` | `#D97706` | Warning |
| `--warning-text` | `#B45309` | Warning text |
| `--warning-text-alt` | `#92400E` | Warning text alt |
| `--danger` | `#DC2626` | Danger/red |
| `--done-text` | `#047857` | Done/resolved text |
| `--success-bg` | `#ECFDF5` | Success surface |
| `--warning-bg` | `#FFFBEB` | Warning surface |
| `--danger-bg` | `#FEF2F2` | Danger surface |

### Text Color

| Token | Value | Usage |
|-------|-------|-------|
| `--text-strong` | `#1A1A1A` | Titles, primary content |
| `--text-normal` | `#374151` | Body text |
| `--text-muted` | `#6B7280` | Secondary, meta, helper |
| `--text-secondary` | `#4B5563` | Filter chip default |

### Border

| Token | Value | Usage |
|-------|-------|-------|
| `--border` | `#E5E7EB` | Default card border |
| `--border-soft` | `#E5E7EB` | Soft border |
| `--border-strong` | `#D1D5DB` | Strong border |
| `--border-focus` | `rgba(15,118,110,0.3)` | Focus/active state |
| `--divider` | `#F0F1F3` | Hairline dividers |
| `--relay-border-good` | `rgba(15,118,110,0.15)` | Relay panel good tone border |
| `--relay-border-warn` | `rgba(217,119,6,0.2)` | Relay panel warn tone border |
| `--relay-border-danger` | `rgba(220,38,38,0.18)` | Relay panel danger tone border |
| `--relay-border-done` | `rgba(4,120,87,0.15)` | Relay panel done tone border |

### Typography Scale

| Token | Size | Usage |
|-------|------|-------|
| `--fs-display` | `44rpx` | Large numbers, hero titles |
| `--fs-title` | `42rpx` | Page title |
| `--fs-section` | `32rpx` | Section title |
| `--fs-body` | `28rpx` | Body text |
| `--fs-label` | `24rpx` | Labels, buttons, helper |
| `--fs-meta` | `22rpx` | Smallest meta info |

### Font Weight

| Token | Value | Usage |
|-------|-------|-------|
| `--fw-black` | `800` | Titles only (was 900, dialed back) |
| `--fw-bold` | `600` | Section titles, labels, buttons |
| `--fw-regular` | `400` | Body text |

### Border Radius

| Token | Value | Usage |
|-------|-------|-------|
| `--radius-sm` | `10rpx` | Small components |
| `--radius-md` | `12rpx` | Buttons, inputs, images |
| `--radius-lg` | `14rpx` | Cards, panels, primary buttons |
| `--radius-pill` | `999rpx` | Pills, tags, chips |

### Spacing (4rpx base)

| Token | Value |
|-------|-------|
| `--space-1` | `4rpx` |
| `--space-2` | `8rpx` |
| `--space-3` | `12rpx` |
| `--space-4` | `16rpx` |
| `--space-5` | `20rpx` |
| `--space-6` | `24rpx` |
| `--space-7` | `28rpx` |
| `--space-8` | `32rpx` |

### Elevation

| Token | Value | Usage |
|-------|-------|-------|
| `--shadow-card` | `0 1rpx 3rpx rgba(0,0,0,0.04)` | Default card (barely visible) |
| `--shadow-raised` | `0 2rpx 8rpx rgba(0,0,0,0.06), 0 1rpx 2rpx rgba(0,0,0,0.04)` | Floating elements |
| `--shadow-dock` | `0 -1rpx 3rpx rgba(0,0,0,0.04)` | Bottom dock / tab bar |
| `--shadow-primary` | `0 2rpx 6rpx rgba(15,118,110,0.15)` | Primary button |
| `--shadow-accent` | `0 2rpx 6rpx rgba(234,88,12,0.15)` | Accent / share button |

### Disabled State (unified)

All `button[disabled]` elements use: `opacity: 1; background: var(--surface-neutral); color: var(--text-muted); box-shadow: none; border-color: transparent;`

## Tone System

Panels and marks use semantic tone modifiers: `.good`, `.warn`, `.danger`, `.done`, `.neutral`. In the minimal system, tones are expressed through background tint only — no gradient overlays.

Applied to: `relay-panel`, `activity-mark`, `tag`, `trust-insight`, `trust-signal`, `signal-item`.

## Layout Rules

- Map remains the first-viewport experience.
- Lists open as bottom drawers or compact cards, not full marketing sections.
- Forms use grouped fields and clear labels; helper text goes below the relevant control.
- Repeated items should be compact cards with image, title, tags, and one clear next action.
- The custom tab bar should be docked to the bottom with an opaque surface. Avoid floating gaps on form or list pages because content can show through behind the navigation.
- The custom tab bar should be docked to the bottom with a near-white translucent surface. Keep it thin — one hairline border, no heavy shadow.
- Keep all user-facing copy in Chinese.

## Component Patterns

- `BottomAction`: fixed above the custom tab bar, opaque, with one short title, one helper line, and one primary action. Use it for page-level submit actions so primary buttons do not hide behind the tab bar.
- `FormSection`: grouped form area with a section title and related fields. Helper notes are optional and should be omitted when field labels and placeholders already explain the task.
- `CategoryOption`: two-column direct-choice buttons for small option sets such as task categories. Prefer this over a picker when the choices are few and user-facing.
- `SignalPill`: small metric tile for repeated task-card signals such as confirmation count, stale count, and remaining time.
- `LocationCheck`: explicit location confirmation block in the publish form. Use it when location is required for correctness; show idle, loading, ready, and failed states without moving the submit button, and make retry language non-technical.
- Publish readiness should be expressed through `LocationCheck` and the fixed `BottomAction`; avoid adding a separate checklist when the bottom action can name the next required step.
- `TrustInsight`: detail-page section placed before trust actions. Summarize confirmations, stale reports, reports, and comment count into one cautious status sentence, then show compact segmented metrics and the next sensible action. Use it to explain the counts without implying absolute trust.
- `MapListEntry`: keep the collapsed map list entry as a compact top-right `cover-view` button with the label and count on one centered text line, such as "列表 6". Do not split the label and count into separate baseline-sensitive nodes, and do not use a bottom dock for this entry.
- `MapToolRow`: location and discover controls sit together at the lower-right of the map above the custom tab bar. Keep them as `cover-view` controls with solid backgrounds, and keep selected task cards above this tool row so icons remain tappable.
### Global Classes (defined in app.wxss)

- **`.panel`** — Base card: surface bg, 1rpx border, radius-lg, no shadow.
- **`.tag`** — Pill-shaped label, no border. Tone variants: `.warn`, `.danger`, `.done`, `.neutral`.
- **`.primary-button`** / **`.secondary-button`** / **`.ghost-button`** — Button hierarchy. Solid colors, no gradients.
- **`.bottom-action`** — Fixed action bar above tab bar with title + helper + primary button.
- **`.empty-panel`** — Centered empty state with `.empty-title`, `.empty-body`, `.empty-action`.
- **`.stat-panel`** — Metric grid (default 4-col). Override columns via page-level selector. Contains `.stat-item` > `.metric` + `.metric-label`.
- **`.head-mark`** — 78rpx solid near-black square with Chinese character for page headers.
- **`.form-field`** — Unified input/textarea/picker base: bg, border, radius, focus state.
- **`.filter-chip`** — Pill filter button, `.active` for selected state.
- **`.activity-mark`** — Colored label tile. Tone variants: `.done` (green), `.warn` (amber), `.danger` (red).
- **`.relay-panel`** — Share/relay prompt panel. Tone variants control border tint. Contains kicker pill, title, body, rows, actions, note.
- **`.share-button`** — Solid accent button for share actions.
- **`.page`** / **`.stack`** / **`.row`** / **`.between`** — Layout utilities.

### Page-Specific Patterns

- **`BottomAction`**: fixed above the custom tab bar, translucent white, with one short title, one helper line, and one primary action. Use it for page-level submit actions.
- **`FormSection`**: grouped form area with a section title and related fields.
- **`CategoryOption`**: two-column direct-choice buttons for small option sets.
- **`SignalPill`**: small metric tile for repeated task-card signals.
- **`LocationCheck`**: explicit location confirmation block in the publish form. Idle/ready/failed states expressed through border tint + bg tint.
- **`Publish readiness`** expressed through `LocationCheck` and the fixed `BottomAction`.
- **`TrustInsight`**: detail-page section before trust actions. One cautious status sentence + compact segmented metrics.
- **`RelayPanel`**: unified share/relay prompt used in 5+ contexts. Tone (`.good`/`.warn`/`.danger`/`.done`) controls border color.
- **`MapListEntry`**: compact top-right `cover-view` button — "列表 6".
- **`MapToolRow`**: location and discover controls at lower-right of map, above tab bar.
- **`CustomTabBar`**: bottom dock with a solid teal indicator above the active tab. Use normal `view`/`image` nodes because the map viewport now ends above the dock; fixed `cover-view` nodes can leave duplicate frames while content scrolls.

## QA Checklist

- Check the map page, publish page, detail page, admin page, and profile page.
- Check 375px-equivalent narrow screens for text overflow.
- Verify buttons do not overlap safe areas or the custom tab bar.
- Verify empty, loading, disabled, and active states still have visible styling.
- Verify relay panels render correctly for all 5 contexts.
- Verify tab bar indicator bar appears on the correct active tab.
- Verify no decorative gradients or grid patterns remain.
Loading
Loading