Remove obsolete audio and buzzer control documentation files, including detailed guides and HTML interfaces, to streamline the repository and eliminate redundancy. This cleanup enhances maintainability and focuses on essential resources for the reTerminal DM4 audio and buzzer functionalities.
This commit is contained in:
292
emmc-provisioning/docs/PORTAL_STYLING_GUIDE.md
Normal file
292
emmc-provisioning/docs/PORTAL_STYLING_GUIDE.md
Normal file
@@ -0,0 +1,292 @@
|
||||
# Portal Styling Guide (Template)
|
||||
|
||||
Use this document when building new portals so they match the visual and UX style of the reference portal (e.g. FreePBX / TM VOIP Extensions Portal). Replace placeholders like `[Portal Name]` with your portal’s name where relevant.
|
||||
|
||||
---
|
||||
|
||||
## 1. Design philosophy
|
||||
|
||||
- **Dark theme:** Dark backgrounds with light text; no light-mode variant in this guide.
|
||||
- **Accent:** Single accent (teal/cyan gradient) for primary actions, links, and highlights.
|
||||
- **Clarity:** Clear hierarchy (cards, sections, labels), consistent spacing, readable typography.
|
||||
- **Consistency:** Same tokens, components, and patterns across all pages (login, app, modals).
|
||||
|
||||
---
|
||||
|
||||
## 2. Design tokens (CSS variables)
|
||||
|
||||
Define these in `:root` (or in a shared CSS file) and use them everywhere instead of hard-coded colors.
|
||||
|
||||
### Colors
|
||||
|
||||
| Token | Value | Usage |
|
||||
|-------|--------|--------|
|
||||
| `--bg-primary` | `#0a0e14` | Page background |
|
||||
| `--bg-secondary` | `#11151c` | Header, secondary surfaces |
|
||||
| `--bg-tertiary` | `#1a1f2b` | Inputs, table header, hover states |
|
||||
| `--bg-card` | `#151a24` | Cards, modals |
|
||||
| `--accent-primary` | `#00d4aa` | Primary accent (teal) |
|
||||
| `--accent-secondary` | `#00b894` | Accent variant, secondary accent |
|
||||
| `--accent-glow` | `rgba(0, 212, 170, 0.15)` | Focus rings, subtle highlights |
|
||||
| `--text-primary` | `#e6e8eb` | Main text |
|
||||
| `--text-secondary` | `#8b949e` | Labels, secondary text |
|
||||
| `--text-muted` | `#5c6370` | Placeholders, disabled, hints |
|
||||
| `--border-color` | `#2d333b` | Borders (cards, inputs, tables) |
|
||||
| `--danger` | `#ff6b6b` | Errors, delete, destructive actions |
|
||||
| `--danger-glow` | `rgba(255, 107, 107, 0.15)` | Danger focus/hover background |
|
||||
| `--warning` | `#ffd93d` | Warnings |
|
||||
| `--success` | `#00d4aa` | Success (can match accent) |
|
||||
| `--gradient-accent` | `linear-gradient(135deg, #00d4aa 0%, #00b894 50%, #00cec9 100%)` | Primary buttons, logo text |
|
||||
|
||||
### Example `:root` block
|
||||
|
||||
```css
|
||||
:root {
|
||||
--bg-primary: #0a0e14;
|
||||
--bg-secondary: #11151c;
|
||||
--bg-tertiary: #1a1f2b;
|
||||
--bg-card: #151a24;
|
||||
--accent-primary: #00d4aa;
|
||||
--accent-secondary: #00b894;
|
||||
--accent-glow: rgba(0, 212, 170, 0.15);
|
||||
--text-primary: #e6e8eb;
|
||||
--text-secondary: #8b949e;
|
||||
--text-muted: #5c6370;
|
||||
--border-color: #2d333b;
|
||||
--danger: #ff6b6b;
|
||||
--danger-glow: rgba(255, 107, 107, 0.15);
|
||||
--warning: #ffd93d;
|
||||
--success: #00d4aa;
|
||||
--gradient-accent: linear-gradient(135deg, #00d4aa 0%, #00b894 50%, #00cec9 100%);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Typography
|
||||
|
||||
- **Body / UI font:** `'Outfit', -apple-system, BlinkMacSystemFont, sans-serif`
|
||||
- **Monospace (data, code, IDs):** `'JetBrains Mono', monospace`
|
||||
|
||||
Load from Google Fonts:
|
||||
|
||||
```html
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
```
|
||||
|
||||
- **Body:** `color: var(--text-primary);` `line-height: 1.6;`
|
||||
- **Labels:** `font-size: 0.85rem;` `font-weight: 500;` `color: var(--text-secondary);` optional `text-transform: uppercase;` `letter-spacing: 0.5px;`
|
||||
- **Card/section titles:** `font-size: 1.1rem;` `font-weight: 600;`
|
||||
- **Table header:** `font-size: 0.75rem–0.8rem;` `font-weight: 600;` `text-transform: uppercase;` `letter-spacing: 0.5px;` `color: var(--text-secondary);`
|
||||
- **Table body:** `font-size: 0.9rem;` monospace for IDs/codes
|
||||
|
||||
---
|
||||
|
||||
## 4. Page layout
|
||||
|
||||
### Global
|
||||
|
||||
- **Reset:** `* { margin: 0; padding: 0; box-sizing: border-box; }`
|
||||
- **Body:** `background: var(--bg-primary);` `color: var(--text-primary);` `min-height: 100vh;` `font-family: 'Outfit', ...`
|
||||
|
||||
### Background treatment (optional)
|
||||
|
||||
Subtle gradient overlay for depth:
|
||||
|
||||
```css
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background:
|
||||
radial-gradient(circle at 20% 20%, rgba(0, 212, 170, 0.03) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 80%, rgba(0, 184, 148, 0.03) 0%, transparent 50%),
|
||||
linear-gradient(180deg, var(--bg-primary) 0%, var(--bg-secondary) 100%);
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
```
|
||||
|
||||
### Header (fixed)
|
||||
|
||||
- **Container:** `background: var(--bg-secondary);` `border-bottom: 1px solid var(--border-color);` `position: fixed; top: 0; left: 0; right: 0; z-index: 1000;` optional `backdrop-filter: blur(10px);`
|
||||
- **Top row:** Logo left; status/user/actions right; `padding: 1rem 2rem;` `display: flex; align-items: center; justify-content: space-between;`
|
||||
- **Tabs row:** Under the top row; `background: var(--bg-tertiary);` `padding: 0.5rem 2rem;` `border-top: 1px solid var(--border-color);` horizontal flex, gap, overflow-x auto for small screens
|
||||
|
||||
### Main content
|
||||
|
||||
- **Container:** `max-width: 1400px;` `margin: 0 auto;` `padding: 2rem;` `padding-top: calc(2rem + 140px);` (offset for fixed header + tabs). On mobile reduce padding and increase top offset if header stacks.
|
||||
|
||||
---
|
||||
|
||||
## 5. Logo
|
||||
|
||||
- **Wrapper:** flex, `align-items: center;` `gap: 0.75rem;`
|
||||
- **Icon:** Square (e.g. 40×40px), `background: var(--gradient-accent);` `border-radius: 10px;` optional `box-shadow: 0 4px 20px var(--accent-glow);` emoji or icon inside.
|
||||
- **Title (h1):** `font-size: 1.5rem;` `font-weight: 600;` `background: var(--gradient-accent);` `-webkit-background-clip: text;` `background-clip: text;` `-webkit-text-fill-color: transparent;`
|
||||
|
||||
---
|
||||
|
||||
## 6. Tabs (main navigation)
|
||||
|
||||
- **Tab button (default):** `padding: 0.75rem 1.5rem;` `background: transparent;` `border: none;` `color: var(--text-secondary);` `font-size: 0.95rem;` `font-weight: 500;` `border-radius: 8px;` flex with icon + label, `gap: 0.5rem;`
|
||||
- **Hover:** `color: var(--text-primary);` `background: var(--bg-tertiary);`
|
||||
- **Active:** `background: var(--gradient-accent);` `color: var(--bg-primary);`
|
||||
- **Tab content:** `display: none;` by default; `.tab-content.active { display: block; }` optional fade-in animation.
|
||||
|
||||
---
|
||||
|
||||
## 7. Cards
|
||||
|
||||
- **Base:** `background: var(--bg-card);` `border: 1px solid var(--border-color);` `border-radius: 16px;` `padding: 1.5rem;` `margin-bottom: 1.5rem;`
|
||||
- **Card header:** flex, `justify-content: space-between;` `align-items: center;` `margin-bottom: 1.5rem;` `padding-bottom: 1rem;` `border-bottom: 1px solid var(--border-color);`
|
||||
- **Card title:** `font-size: 1.1rem;` `font-weight: 600;` flex with icon + text, `gap: 0.5rem;`
|
||||
|
||||
---
|
||||
|
||||
## 8. Buttons
|
||||
|
||||
- **Base:** `padding: 0.75rem 1.5rem;` `border-radius: 8px;` `font-size: 0.9rem;` `font-weight: 500;` inline-flex, `align-items: center;` `gap: 0.5rem;` `transition: all 0.2s ease;`
|
||||
- **Primary:** `background: var(--gradient-accent);` `color: var(--bg-primary);` `border: none;` hover: slight `translateY(-2px);` `box-shadow: 0 4px 20px var(--accent-glow);`
|
||||
- **Secondary:** `background: var(--bg-tertiary);` `border: 1px solid var(--border-color);` `color: var(--text-primary);` hover: `border-color: var(--accent-primary);`
|
||||
- **Danger:** `background: transparent;` `border: 1px solid var(--danger);` `color: var(--danger);` hover: `background: var(--danger);` `color: white;`
|
||||
- **Disabled:** `opacity: 0.5;` `cursor: not-allowed;`
|
||||
- **Icon-only (small):** e.g. 28×28px, `border-radius: 6px;` same semantic colors (e.g. `.btn-remove` with `--danger`).
|
||||
|
||||
---
|
||||
|
||||
## 9. Forms
|
||||
|
||||
- **Grid:** `display: grid;` `grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));` `gap: 1rem;`
|
||||
- **Form group:** flex column, `gap: 0.5rem;`
|
||||
- **Label:** `font-size: 0.85rem;` `font-weight: 500;` `color: var(--text-secondary);` optional uppercase + letter-spacing
|
||||
- **Input / select:** `padding: 0.75rem 1rem;` `background: var(--bg-tertiary);` `border: 1px solid var(--border-color);` `border-radius: 8px;` `color: var(--text-primary);` `font-size: 0.9rem;` monospace for IDs/codes
|
||||
- **Focus:** `outline: none;` `border-color: var(--accent-primary);` `box-shadow: 0 0 0 3px var(--accent-glow);`
|
||||
- **Placeholder:** `color: var(--text-muted);`
|
||||
- **Read-only:** `background: var(--bg-secondary);` `cursor: default;`
|
||||
- **Checkbox:** `accent-color: var(--accent-primary);` (or custom size e.g. 18×18px)
|
||||
- **Password field:** wrapper with toggle button; input `padding-right: 3rem;` so toggle doesn’t overlap text.
|
||||
|
||||
---
|
||||
|
||||
## 10. Tables
|
||||
|
||||
- **Container:** `overflow-x: auto;` `border-radius: 12px;` `border: 1px solid var(--border-color);`
|
||||
- **Table:** `width: 100%;` `border-collapse: collapse;`
|
||||
- **th / td:** `padding: 0.6rem 0.75rem;` `text-align: left;` `border-bottom: 1px solid var(--border-color);` `color: var(--text-primary);`
|
||||
- **th:** `background: var(--bg-tertiary);` `font-size: 0.75rem;` `font-weight: 600;` `text-transform: uppercase;` `letter-spacing: 0.5px;`
|
||||
- **tbody tr hover:** `background-color: var(--bg-tertiary);`
|
||||
- **Last row:** `tr:last-child td { border-bottom: none; }`
|
||||
- **Data cells:** `font-family: 'JetBrains Mono', monospace;` `font-size: 0.9rem;`
|
||||
- **Actions column:** right-aligned; min-width for action buttons; `.table-actions { display: flex; gap: 1rem; flex-wrap: wrap; }`
|
||||
- **Data table variant:** `.data-table` with alternating row background (e.g. `nth-child(even)` subtle `rgba(255,255,255,0.02)`) and same hover.
|
||||
|
||||
---
|
||||
|
||||
## 11. Badges and status
|
||||
|
||||
- **Status badge (e.g. connection):** flex, `align-items: center;` `gap: 0.5rem;` `padding: 0.5rem 1rem;` `background: var(--bg-tertiary);` `border-radius: 20px;` `font-size: 0.85rem;` `border: 1px solid var(--border-color);`
|
||||
- **Status dot:** 8×8px circle; `.connected { background: var(--success); }` `.error { background: var(--danger); }` optional pulse animation
|
||||
- **Pill badge (e.g. extension ID):** `padding: 0.25rem 0.75rem;` `background: var(--accent-glow);` `color: var(--accent-primary);` `border-radius: 20px;` `font-weight: 500;`
|
||||
- **Tech badge (e.g. PJSIP/SIP):** small, `border-radius: 4px;` `font-size: 0.75rem;` `font-weight: 600;` `text-transform: uppercase;` distinct colors per type (e.g. PJSIP blue, SIP purple)
|
||||
|
||||
---
|
||||
|
||||
## 12. Search and filters
|
||||
|
||||
- **Search box:** wrapper relative; input `padding: 0.6rem 1rem 0.6rem 2.5rem;` `width: 250px;` same colors as form inputs; optional `::before` search icon (e.g. 🔍) `left: 0.75rem;`
|
||||
- **Filter checkbox:** inline-flex, `align-items: center;` `gap: 0.4rem;` `color: var(--text-secondary);` `accent-color: var(--accent-primary);`
|
||||
|
||||
---
|
||||
|
||||
## 13. Empty and loading states
|
||||
|
||||
- **Empty state:** `text-align: center;` `padding: 3rem;` `color: var(--text-muted);`
|
||||
- **No results:** same idea, `padding: 2rem;`
|
||||
- **Loading:** flex center, `padding: 2rem;` spinner (e.g. 32×32px border, `border-top-color: var(--accent-primary);` `animation: spin 1s linear infinite;`)
|
||||
|
||||
---
|
||||
|
||||
## 14. Modals
|
||||
|
||||
- **Overlay:** `position: fixed;` `inset: 0;` `background: rgba(0,0,0,0.7);` `z-index: 1000;` flex center; `display: none;` `.active { display: flex; }`
|
||||
- **Dialog:** `background: var(--bg-card);` `border: 1px solid var(--border-color);` `border-radius: 16px;` `padding: 2rem;` `max-width: 500px;` `width: 90%;` optional scale-in animation
|
||||
- **Modal header:** flex, `align-items: center;` `gap: 1rem;` `margin-bottom: 1.5rem;`
|
||||
- **Modal icon:** e.g. 48×48px, `background: var(--accent-glow);` `border-radius: 12px;` centered content
|
||||
- **Modal title:** `font-size: 1.25rem;` `font-weight: 600;`
|
||||
- **Detail sections:** `margin-bottom: 2rem;` section title `font-size: 1.1rem;` `color: var(--accent-primary);` `border-bottom: 1px solid var(--border-color);` `padding-bottom: 0.5rem;`
|
||||
- **Details grid:** `grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));` `gap: 1rem;` each item: label (small, secondary) + value (primary)
|
||||
|
||||
---
|
||||
|
||||
## 15. Toasts (notifications)
|
||||
|
||||
- **Container:** `position: fixed;` `top: 1rem;` `right: 1rem;` `z-index: 1100;` flex column, `gap: 0.5rem;`
|
||||
- **Toast:** `padding: 1rem 1.5rem;` `background: var(--bg-card);` `border: 1px solid var(--border-color);` `border-radius: 8px;` flex, `align-items: center;` `gap: 0.75rem;` `max-width: 400px;` slide-in animation
|
||||
- **Success:** `border-left: 3px solid var(--success);`
|
||||
- **Error:** `border-left: 3px solid var(--danger);`
|
||||
|
||||
---
|
||||
|
||||
## 16. Pagination
|
||||
|
||||
- **Wrapper:** flex, `justify-content: center;` `align-items: center;` `gap: 0.5rem;` `padding: 1rem;` `border-top: 1px solid var(--border-color);`
|
||||
- **Button:** `padding: 0.5rem 0.75rem;` `background: var(--bg-tertiary);` `border: 1px solid var(--border-color);` `border-radius: 6px;` `color: var(--text-primary);` `font-size: 0.85rem;` `min-width: 36px;`
|
||||
- **Hover:** `background: var(--accent-glow);` `border-color: var(--accent-primary);` `color: var(--accent-primary);`
|
||||
- **Active page:** `background: var(--accent-primary);` `color: var(--bg-primary);`
|
||||
- **Disabled:** `opacity: 0.4;` `cursor: not-allowed;`
|
||||
- **Info text:** `color: var(--text-secondary);` `font-size: 0.85rem;` between prev/next
|
||||
|
||||
---
|
||||
|
||||
## 17. Login page
|
||||
|
||||
- **Layout:** full viewport, flex center; `padding: 2rem;`
|
||||
- **Card:** same tokens as app cards; `max-width: 400px;` `padding: 2.5rem;` `border-radius: 16px;` `box-shadow: 0 8px 32px rgba(0,0,0,0.3);`
|
||||
- **Logo:** centered; icon (e.g. 64×64px) with gradient + glow; title with gradient text
|
||||
- **Form:** same form-group and input styles as app; full-width primary submit button
|
||||
- **Error message:** `color: var(--danger);` `font-size: 0.9rem;` above or below form
|
||||
- Use the same `:root` variables and body background so login and app feel like one product.
|
||||
|
||||
---
|
||||
|
||||
## 18. Responsive
|
||||
|
||||
- **Breakpoint:** e.g. `@media (max-width: 768px)`
|
||||
- **Header top:** `flex-direction: column;` `gap: 1rem;` `text-align: center;` reduce padding
|
||||
- **Tabs:** reduce horizontal padding; allow horizontal scroll if needed
|
||||
- **Container:** reduce padding; increase `padding-top` if header height grows (e.g. `calc(1rem + 180px)`)
|
||||
- **Form grid:** `grid-template-columns: 1fr;` for single column on small screens
|
||||
|
||||
---
|
||||
|
||||
## 19. Checklist for a new portal
|
||||
|
||||
- [ ] Copy or recreate the `:root` design tokens.
|
||||
- [ ] Load **Outfit** and **JetBrains Mono** (or same weights).
|
||||
- [ ] Use the same header structure: logo + status/user + actions, then tabs.
|
||||
- [ ] Use `.card`, `.card-header`, `.card-title` for sections.
|
||||
- [ ] Use `.btn`, `.btn-primary`, `.btn-secondary`, `.btn-danger` for actions.
|
||||
- [ ] Use `.form-grid`, `.form-group`, and input/select styles for forms.
|
||||
- [ ] Use `.table-container`, table, `.data-table` and th/td styles for lists.
|
||||
- [ ] Use same modal overlay/dialog and toast styles.
|
||||
- [ ] Use same empty, loading, and error states.
|
||||
- [ ] Apply same login page layout and token usage.
|
||||
- [ ] Test at 768px width for basic responsive behavior.
|
||||
- [ ] Replace [Portal Name] and any product-specific labels in this guide for your portal.
|
||||
|
||||
---
|
||||
|
||||
## 20. Reference files (this repo)
|
||||
|
||||
| File | Purpose |
|
||||
|------|--------|
|
||||
| `static/css/main.css` | Full implementation of tokens, layout, components |
|
||||
| `app/templates/base.html` | App shell: fonts, header, tabs, container, toasts |
|
||||
| `app/templates/login.html` | Login layout and inline tokens (can be moved to main.css) |
|
||||
| `app/templates/tabs/_dashboard.html` | Example: cards, stats, table container |
|
||||
| `app/templates/tabs/_users.html` | Example: card, form-grid, form-group, buttons, table |
|
||||
|
||||
For a new portal, you can copy `main.css` and adapt it (e.g. change `:root` if you need a different accent), then build your base template and pages to use the same class names and structure described above.
|
||||
Reference in New Issue
Block a user