mirror of
https://github.com/619dev/Paperphone-plus.git
synced 2026-09-03 07:18:05 +08:00
Add PaperPhone design system
This commit is contained in:
253
DESIGN.md
Normal file
253
DESIGN.md
Normal file
@@ -0,0 +1,253 @@
|
||||
# PaperPhonePlus Design System
|
||||
|
||||
## 1. Product character
|
||||
|
||||
PaperPhonePlus is a private, end-to-end encrypted mobile messenger. Its interface
|
||||
combines Apple's quiet, content-first interaction model with a warm paper-gold
|
||||
identity. It should feel trustworthy, calm, fast, and native rather than like a
|
||||
marketing website or a desktop SaaS dashboard.
|
||||
|
||||
Use this document for application screens. It intentionally adapts ideas from
|
||||
Apple-style interfaces instead of copying Apple marketing layouts.
|
||||
|
||||
### Design principles
|
||||
|
||||
1. **Messages are the product.** Chrome recedes; conversation content has the
|
||||
strongest visual weight.
|
||||
2. **Gold means PaperPhone.** Gold identifies primary actions, active navigation,
|
||||
and brand moments. It is not a generic warning color.
|
||||
3. **Security is legible, not theatrical.** Explain encryption with concise text,
|
||||
familiar icons, and clear state. Avoid neon glows, hacker imagery, and excessive
|
||||
lock decoration.
|
||||
4. **Glass belongs to chrome.** Translucency is reserved for navigation bars,
|
||||
composer bars, sheets, and overlays. Message bubbles and ordinary list rows use
|
||||
stable, readable surfaces.
|
||||
5. **One-handed by default.** Primary controls are reachable, touch targets are at
|
||||
least 44×44 CSS pixels, and every screen respects device safe areas.
|
||||
|
||||
## 2. Color system
|
||||
|
||||
### Light theme
|
||||
|
||||
| Token | Value | Role |
|
||||
| --- | --- | --- |
|
||||
| `bg-primary` | `#f2f2f7` | App canvas and conversation background |
|
||||
| `bg-secondary` | `#ffffff` | Solid elevated surface and incoming bubble |
|
||||
| `bg-tertiary` | `#e5e5ea` | Dividers and disabled surfaces |
|
||||
| `text-primary` | `#1c1c1e` | Primary text |
|
||||
| `text-secondary` | `#636366` | Supporting text and message previews |
|
||||
| `text-muted` | `#8e8e93` | Timestamps, placeholders, disabled labels |
|
||||
| `accent` | `#d4a017` | PaperPhone brand and primary action |
|
||||
| `accent-pressed` | `#b8860b` | Pressed primary action |
|
||||
| `accent-soft` | `rgba(212, 160, 23, 0.12)` | Selection and active-navigation backing |
|
||||
| `system-link` | `#007aff` | Links and neutral informational actions |
|
||||
| `success` | `#34c759` | Online, delivered, verified, successful |
|
||||
| `warning` | `#ff9f0a` | Expiry and caution states only |
|
||||
| `danger` | `#ff3b30` | Destructive action, failed send, unread badge |
|
||||
| `separator` | `rgba(60, 60, 67, 0.18)` | Hairline separators |
|
||||
|
||||
### Dark theme
|
||||
|
||||
| Token | Value | Role |
|
||||
| --- | --- | --- |
|
||||
| `bg-primary` | `#000000` | App canvas |
|
||||
| `bg-secondary` | `#1c1c1e` | Solid elevated surface and incoming bubble |
|
||||
| `bg-tertiary` | `#2c2c2e` | Secondary controls |
|
||||
| `text-primary` | `#f5f5f7` | Primary text |
|
||||
| `text-secondary` | `#aeaeb2` | Supporting text |
|
||||
| `text-muted` | `#8e8e93` | Timestamps and placeholders |
|
||||
| `system-link` | `#0a84ff` | Links and neutral informational actions |
|
||||
| `separator` | `rgba(84, 84, 88, 0.65)` | Hairline separators |
|
||||
|
||||
Gold must maintain readable contrast. Use white text on a darkened gold fill for
|
||||
large primary buttons. On pale backgrounds, use the darker gold variant for text.
|
||||
Do not use gold for warnings; warning orange and danger red retain their semantic
|
||||
meaning.
|
||||
|
||||
## 3. Typography
|
||||
|
||||
Use the platform system font. Never require a network font for core UI.
|
||||
|
||||
```css
|
||||
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI",
|
||||
"Noto Sans", "Helvetica Neue", Arial, sans-serif;
|
||||
```
|
||||
|
||||
| Style | Size / line height | Weight | Usage |
|
||||
| --- | --- | --- | --- |
|
||||
| Navigation title | `17px / 22px` | 600 | Page and conversation titles |
|
||||
| Section title | `20px / 25px` | 600 | Major in-page section |
|
||||
| Body | `16px / 22px` | 400 | Messages, inputs, settings |
|
||||
| List name | `15px / 20px` | 500 | Contact and conversation name |
|
||||
| Supporting | `13px / 18px` | 400 | Preview, status, helper text |
|
||||
| Caption | `12px / 16px` | 400 | Timestamp and metadata |
|
||||
| Tab label | `10px / 12px` | 500 | Bottom navigation only |
|
||||
|
||||
Use sentence case. Avoid all-caps labels. Allow user-generated messages to wrap and
|
||||
scale; do not apply negative tracking to message text. Chinese, Japanese, Korean,
|
||||
Cyrillic, and Latin scripts must share a visually balanced fallback stack.
|
||||
|
||||
## 4. Shape, spacing, and depth
|
||||
|
||||
### Spacing
|
||||
|
||||
Use a 4px base grid: `4, 8, 12, 16, 20, 24, 32, 40`.
|
||||
|
||||
- Page horizontal inset: 16px.
|
||||
- Compact control gap: 8px.
|
||||
- List row vertical padding: 12px.
|
||||
- Message-to-message gap: 4px for the same sender, 12px when sender changes.
|
||||
- Major section gap: 24px.
|
||||
|
||||
### Radius
|
||||
|
||||
| Token | Value | Usage |
|
||||
| --- | --- | --- |
|
||||
| `sm` | `10px` | Compact controls and menus |
|
||||
| `md` | `14px` | Cards, inputs, attachment tiles |
|
||||
| `lg` | `20px` | Message bubbles and sheets |
|
||||
| `xl` | `28px` | Floating bottom navigation |
|
||||
| `full` | `9999px` | Avatars, badges, circular buttons |
|
||||
|
||||
### Elevation
|
||||
|
||||
- Prefer surface color and a hairline border over shadow.
|
||||
- Navigation glass may use one soft shadow no darker than 8% black in light mode.
|
||||
- Modals and sheets may use a larger shadow, but never stack multiple glowing
|
||||
shadows.
|
||||
- Avatars and ordinary message bubbles should not glow.
|
||||
|
||||
## 5. Materials
|
||||
|
||||
Glass surfaces may be used for the page header, bottom tab bar, chat composer,
|
||||
modal, and action sheet. Use a translucent theme surface with approximately
|
||||
`24px` blur and `160%` saturation. Always provide an opaque fallback.
|
||||
|
||||
Do not use backdrop blur on:
|
||||
|
||||
- message bubbles;
|
||||
- conversation rows;
|
||||
- settings rows;
|
||||
- media cards;
|
||||
- warning or encryption banners.
|
||||
|
||||
When reduced transparency is requested, glass becomes an opaque `bg-secondary`
|
||||
surface. When reduced motion is requested, remove entrance animations, glow
|
||||
animations, and spring scaling.
|
||||
|
||||
## 6. Core components
|
||||
|
||||
### Navigation bar
|
||||
|
||||
- 56px content height plus top safe-area inset.
|
||||
- Center or leading-align a 17px semibold title according to screen context.
|
||||
- Back and utility buttons have a 44×44px hit area.
|
||||
- Use gold for the primary route action; use `system-link` for informational links.
|
||||
|
||||
### Bottom tab bar
|
||||
|
||||
- Four destinations: Chats, Contacts, Discover, Profile.
|
||||
- The active tab uses a gold icon and label on a subtle gold backing.
|
||||
- Inactive tabs use muted text; do not place each tab inside a separate card.
|
||||
- Unread badges use danger red and must not depend on color alone: include a count.
|
||||
|
||||
### Conversation list row
|
||||
|
||||
- Avatar: 44×44px.
|
||||
- Primary line: contact/group name; truncate to one line.
|
||||
- Secondary line: latest message summary; truncate to one line.
|
||||
- Trailing column: timestamp above unread badge.
|
||||
- Online green is a small status indicator, never a large label.
|
||||
- Rows use a flat surface with a subtle pressed state, not floating glass cards.
|
||||
|
||||
### Message bubble
|
||||
|
||||
- Incoming: solid secondary surface, primary text.
|
||||
- Outgoing: restrained gold surface with contrast-checked text.
|
||||
- Maximum width: 78% of the conversation column.
|
||||
- Use 18–20px outer radius and a slightly tighter radius toward the sender edge.
|
||||
- Group consecutive messages before repeating avatar/name metadata.
|
||||
- Place delivery/read state beside the outgoing timestamp. Never communicate a
|
||||
failed send through color alone; include an icon and accessible label.
|
||||
- Long text, URLs, emoji, CJK text, and right-to-left text must wrap safely.
|
||||
|
||||
### Composer
|
||||
|
||||
- Anchored above the bottom safe area.
|
||||
- Text field minimum height: 40px; action hit areas: 44×44px.
|
||||
- The send control is gold only when content can be sent. Disabled state is neutral.
|
||||
- Attachment and emoji actions remain secondary and must not compete with Send.
|
||||
- Keyboard focus uses a visible 2px gold ring with a soft outer halo.
|
||||
|
||||
### Buttons
|
||||
|
||||
- Primary: solid PaperPhone gold, pill shape, minimum height 44px.
|
||||
- Secondary: neutral solid or glass surface, depending on context.
|
||||
- Destructive: system danger red; require confirmation for irreversible operations.
|
||||
- Icon-only: circular 44px hit area and an accessible name.
|
||||
- Avoid decorative gradients and shimmer on ordinary utility buttons.
|
||||
|
||||
### Security and warning banners
|
||||
|
||||
- Encryption state uses a shield/lock icon, a concise heading, and optional detail.
|
||||
- Warning banners use semantic warning yellow/orange, not brand gold.
|
||||
- Group-chat encryption limitations must be visually persistent until resolved.
|
||||
- Never claim encryption merely through an icon; display the actual state in text.
|
||||
|
||||
### Empty, loading, and error states
|
||||
|
||||
- Empty states use one quiet line icon, a short explanation, and at most one action.
|
||||
- Use skeletons only where layout is known; otherwise use a compact progress label.
|
||||
- Retry errors remain near the failed operation and preserve the user's input.
|
||||
|
||||
## 7. Motion and feedback
|
||||
|
||||
- Standard transition: 200ms, `cubic-bezier(0.2, 0.8, 0.2, 1)`.
|
||||
- Page entrance: subtle opacity and at most 8px vertical movement.
|
||||
- Press feedback: scale no smaller than 0.96 for buttons and 0.98 for rows.
|
||||
- Never animate message content while the user is selecting or copying it.
|
||||
- Haptics may accompany Send, call connect, and destructive confirmation in native
|
||||
shells, but the interface must remain understandable without haptics.
|
||||
|
||||
## 8. Responsive and accessibility rules
|
||||
|
||||
- Primary layout targets 320–480px phone widths.
|
||||
- Respect top, bottom, left, and right safe-area insets in every orientation.
|
||||
- Minimum touch target: 44×44px on coarse pointers.
|
||||
- Text must remain usable at 200% browser zoom without horizontal page scrolling.
|
||||
- Interactive controls need `:focus-visible` treatment and accessible names.
|
||||
- Never disable zoom.
|
||||
- Support `prefers-reduced-motion`, `prefers-contrast`, and reduced-transparency
|
||||
fallbacks where available.
|
||||
- Body text and essential icons target WCAG AA contrast.
|
||||
- Do not use color as the only indication of online, unread, failed, selected,
|
||||
encrypted, or verified state.
|
||||
|
||||
## 9. Do and don't
|
||||
|
||||
### Do
|
||||
|
||||
- Keep conversations visually quiet and content-first.
|
||||
- Use gold sparingly and consistently for PaperPhone identity.
|
||||
- Prefer stable solid surfaces behind long-form message content.
|
||||
- Test both themes with long multilingual strings and large dynamic text.
|
||||
- Keep navigation and composer behavior familiar across iOS and Android.
|
||||
|
||||
### Don't
|
||||
|
||||
- Do not reproduce Apple marketing hero layouts inside the app.
|
||||
- Do not turn the UI purple to resemble Slack or orange to resemble Intercom.
|
||||
- Do not cover every card with blur, gloss, gradients, or glow.
|
||||
- Do not use proprietary brand fonts that are unavailable to users.
|
||||
- Do not hide privacy or encryption limitations behind decorative visuals.
|
||||
- Do not sacrifice Android usability to imitate iOS chrome literally.
|
||||
|
||||
## 10. Agent implementation prompt
|
||||
|
||||
When building or modifying PaperPhonePlus UI, preserve existing behavior and use
|
||||
this system as the source of truth. Build a mobile-first, content-led messenger
|
||||
with platform-system typography, calm Apple-inspired hierarchy, PaperPhone gold
|
||||
for primary brand actions, solid readable message surfaces, and glass only on
|
||||
navigation/composer overlays. Implement both themes, safe areas, 44px touch targets,
|
||||
keyboard focus, reduced motion, and long multilingual content. Do not introduce
|
||||
marketing-page patterns or copy another company's brand identity.
|
||||
@@ -3,8 +3,6 @@
|
||||
Translucent glass materials · Depth & refraction · Fluid motion
|
||||
═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
|
||||
|
||||
:root {
|
||||
/* ── Color System (Light) ────────────────────────────────── */
|
||||
--bg-primary: #f2f2f7;
|
||||
@@ -30,8 +28,10 @@
|
||||
--warning: #ff9f0a;
|
||||
--danger: #ff453a;
|
||||
--info: #0a84ff;
|
||||
--system-link: #007aff;
|
||||
|
||||
--border: rgba(0, 0, 0, 0.06);
|
||||
--separator: rgba(60, 60, 67, 0.18);
|
||||
--border-active: rgba(212, 160, 23, 0.4);
|
||||
--shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
|
||||
--shadow-lg: 0 8px 40px rgba(0, 0, 0, 0.08);
|
||||
@@ -45,8 +45,8 @@
|
||||
rgba(255,255,255,0.9) 0%,
|
||||
rgba(255,255,255,0.3) 50%,
|
||||
rgba(255,255,255,0.05) 100%);
|
||||
--glass-blur: 40px;
|
||||
--glass-saturate: 200%;
|
||||
--glass-blur: 24px;
|
||||
--glass-saturate: 160%;
|
||||
--glass-shadow: 0 2px 20px rgba(0, 0, 0, 0.06),
|
||||
0 0 0 0.5px rgba(0, 0, 0, 0.04);
|
||||
|
||||
@@ -91,8 +91,10 @@
|
||||
--text-inverse: #000000;
|
||||
|
||||
--accent-glow: rgba(212, 160, 23, 0.35);
|
||||
--system-link: #0a84ff;
|
||||
|
||||
--border: rgba(255, 255, 255, 0.06);
|
||||
--separator: rgba(84, 84, 88, 0.65);
|
||||
--border-active: rgba(212, 160, 23, 0.5);
|
||||
--shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
|
||||
--shadow-lg: 0 8px 48px rgba(0, 0, 0, 0.5);
|
||||
@@ -121,7 +123,8 @@
|
||||
html, body, #root {
|
||||
height: 100%;
|
||||
height: 100dvh; /* Dynamic viewport height for iOS Safari */
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', sans-serif;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI',
|
||||
'Noto Sans', 'Helvetica Neue', Arial, sans-serif;
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
color: var(--text-primary);
|
||||
@@ -362,7 +365,7 @@ body {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: var(--radius-full);
|
||||
background: linear-gradient(145deg, var(--accent), var(--accent-light));
|
||||
background: var(--accent);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -371,7 +374,6 @@ body {
|
||||
color: white;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
box-shadow: 0 2px 8px var(--accent-glow);
|
||||
}
|
||||
.avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: var(--radius-full); }
|
||||
|
||||
@@ -402,7 +404,7 @@ body {
|
||||
.list-meta .time { font-size: 12px; color: var(--text-muted); }
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
Buttons — Liquid Glass Capsules
|
||||
Buttons — PaperPhone Gold + Neutral Capsules
|
||||
═══════════════════════════════════════════════════════════════ */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
@@ -422,28 +424,14 @@ body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Shimmer highlight */
|
||||
.btn::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0;
|
||||
height: 50%;
|
||||
background: linear-gradient(180deg,
|
||||
rgba(255,255,255,0.25) 0%,
|
||||
rgba(255,255,255,0) 100%);
|
||||
border-radius: var(--radius-full) var(--radius-full) 0 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(145deg, var(--accent), var(--accent-dark));
|
||||
background: var(--accent-dark);
|
||||
color: white;
|
||||
box-shadow: 0 2px 12px var(--accent-glow),
|
||||
inset 0 1px 0 rgba(255,255,255,0.2);
|
||||
box-shadow: 0 2px 8px var(--accent-glow);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
box-shadow: 0 4px 24px var(--accent-glow),
|
||||
inset 0 1px 0 rgba(255,255,255,0.2);
|
||||
background: var(--accent);
|
||||
box-shadow: 0 3px 12px var(--accent-glow);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.btn-primary:active {
|
||||
@@ -536,7 +524,7 @@ textarea.input {
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
Chat Bubbles — Glass Message Capsules
|
||||
Chat Bubbles — Stable, Readable Message Surfaces
|
||||
═══════════════════════════════════════════════════════════════ */
|
||||
.chat-messages-shell {
|
||||
position: relative;
|
||||
@@ -575,7 +563,7 @@ textarea.input {
|
||||
.msg-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
max-width: 80%;
|
||||
max-width: 78%;
|
||||
animation: msg-in 0.35s var(--ease-spring);
|
||||
}
|
||||
|
||||
@@ -594,32 +582,15 @@ textarea.input {
|
||||
}
|
||||
|
||||
.msg-row:not(.outgoing) .msg-bubble {
|
||||
background: var(--glass-bg-thick);
|
||||
backdrop-filter: blur(20px) saturate(160%);
|
||||
-webkit-backdrop-filter: blur(20px) saturate(160%);
|
||||
border: 0.5px solid var(--glass-border);
|
||||
background: var(--bg-secondary);
|
||||
border: 0.5px solid var(--border);
|
||||
border-bottom-left-radius: 6px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
.msg-row.outgoing .msg-bubble {
|
||||
background: linear-gradient(145deg, var(--accent), var(--accent-dark));
|
||||
background: var(--accent-dark);
|
||||
color: white;
|
||||
border-bottom-right-radius: 6px;
|
||||
box-shadow: 0 2px 12px var(--accent-glow);
|
||||
}
|
||||
|
||||
/* Outgoing bubble specular highlight */
|
||||
.msg-row.outgoing .msg-bubble::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0;
|
||||
height: 50%;
|
||||
background: linear-gradient(180deg,
|
||||
rgba(255,255,255,0.15) 0%,
|
||||
rgba(255,255,255,0) 100%);
|
||||
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.msg-time {
|
||||
@@ -687,7 +658,7 @@ textarea.input {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: var(--radius-full);
|
||||
background: linear-gradient(145deg, var(--accent), var(--accent-dark));
|
||||
background: var(--accent-dark);
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
@@ -1974,3 +1945,40 @@ textarea.input {
|
||||
.privacy-footer p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Respect platform accessibility preferences without changing app structure. */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
scroll-behavior: auto !important;
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-transparency: reduce) {
|
||||
.glass,
|
||||
.page-header,
|
||||
.tabbar,
|
||||
.chat-input-bar,
|
||||
.login-card,
|
||||
.modal,
|
||||
.btn-secondary,
|
||||
.privacy-card {
|
||||
background: var(--bg-secondary);
|
||||
backdrop-filter: none;
|
||||
-webkit-backdrop-filter: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-contrast: more) {
|
||||
:root {
|
||||
--border: rgba(0, 0, 0, 0.22);
|
||||
--text-muted: #636366;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--border: rgba(255, 255, 255, 0.28);
|
||||
--text-muted: #aeaeb2;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user