feat: initial web3 corporate style guide
- Extract design tokens (colors, typography, spacing) from dao-marketplace - Build component CSS: base, card, button, forms - Create interactive Vite showcase app with tabbed navigation - Add README, .gitignore, AGENTS.md - Build passes (vite v8.2.2)
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
node_modules/
|
||||
dist/
|
||||
*.local
|
||||
.DS_Store
|
||||
.vite/
|
||||
19
AGENTS.md
Normal file
19
AGENTS.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Web3 Style Guide — Engineering Standards
|
||||
|
||||
- **Minimal-Change Fixes:** Verify flaws before patching; touch only what the task requires.
|
||||
- **Token-First:** Always reference CSS custom properties instead of raw hex/rgb values.
|
||||
- **Verification:** Run `npm run build` before declaring work finished.
|
||||
- **Atomic Commits:** Small, clear, descriptive commits (`feat:`, `fix:`, `chore:`, `tokens:`).
|
||||
|
||||
## Current Status
|
||||
- Tokens: colors, typography, spacing — extracted from dao-marketplace
|
||||
- Components: base, card, button, forms — extracted and generalized
|
||||
- Showcase: interactive Vite app with tabbed navigation
|
||||
- Build: passes (vite v8.2.2)
|
||||
|
||||
## Roadmap
|
||||
- [ ] Add React component library (pixel-card, pixel-btn, etc.)
|
||||
- [ ] Add dark/light theme toggle
|
||||
- [ ] Add Figma token export
|
||||
- [ ] Add Storybook for component documentation
|
||||
- [ ] Publish as npm package `@web3/style-guide`
|
||||
72
README.md
Normal file
72
README.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Web3 Corporate Style Guide
|
||||
|
||||
A shared design system for products across the Web3 ecosystem. Derived from the visual language of the DAO Marketplace project.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev # Vite dev server with live component showcase
|
||||
npm run build # Production build
|
||||
```
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── tokens/ # Design tokens (CSS custom properties)
|
||||
│ ├── index.css # Master token import
|
||||
│ ├── colors.css # Color palette
|
||||
│ ├── typography.css # Font families, sizes, weights
|
||||
│ └── spacing.css # Layout dimensions, radii, gaps
|
||||
├── css/ # Component stylesheets
|
||||
│ ├── web3-style.css # Master stylesheet (imports all below)
|
||||
│ ├── base.css # Reset, header, nav, main, responsive
|
||||
│ ├── card.css # .pixel-card component
|
||||
│ ├── button.css # .pixel-btn component
|
||||
│ └── forms.css # Form controls, footer, grids
|
||||
├── components/ # (reserved for future React/Vue components)
|
||||
├── App.tsx # Interactive showcase app
|
||||
├── main.tsx # Entry point
|
||||
└── demo.css # Showcase-specific styles
|
||||
```
|
||||
|
||||
## Integration
|
||||
|
||||
### Option A: Full CSS Import
|
||||
```css
|
||||
@import "@web3/style-guide/css/web3-style.css";
|
||||
```
|
||||
|
||||
### Option B: Tokens Only
|
||||
```css
|
||||
@import "@web3/style-guide/tokens/index.css";
|
||||
```
|
||||
|
||||
### Option C: Individual Components
|
||||
```css
|
||||
@import "@web3/style-guide/css/card.css";
|
||||
@import "@web3/style-guide/css/button.css";
|
||||
```
|
||||
|
||||
## Design Language
|
||||
|
||||
| Token | Value | Usage |
|
||||
|-------|-------|-------|
|
||||
| `--color-bg-primary` | `#0c1020` | Page background |
|
||||
| `--color-accent-green` | `#59d8ae` | Brand indicator, success |
|
||||
| `--color-accent-blue` | `#6f8bff` | Buttons, focus rings |
|
||||
| `--color-text-primary` | `#e7eaf1` | Body text |
|
||||
| `--font-family-base` | `Inter, system-ui, ...` | All UI text |
|
||||
|
||||
## Brand Conventions
|
||||
|
||||
- **Dark-first**: All views use `#0c1020` with radial mesh gradients
|
||||
- **Green status dot**: 10px glowing indicator in product headers
|
||||
- **Blue interactive**: Buttons and focus rings use `#6f8bff`
|
||||
- **Floating footer**: Fixed bottom bar with backdrop blur
|
||||
- **Glassmorphism**: Cards use `rgba(21,27,48,.82)` with `backdrop-filter`
|
||||
|
||||
## License
|
||||
|
||||
Internal use across Web3 ecosystem products.
|
||||
15
index.html
Normal file
15
index.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Web3 Style Guide</title>
|
||||
<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=Inter:wght@400;500;570;620;680;760&display=swap" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
1446
package-lock.json
generated
Normal file
1446
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
package.json
Normal file
23
package.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "@web3/style-guide",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint src --ext ts,tsx,css"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.3.0",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.3.0",
|
||||
"typescript": "^5.6.0",
|
||||
"vite": "^8.2.2"
|
||||
}
|
||||
}
|
||||
291
src/App.tsx
Normal file
291
src/App.tsx
Normal file
@ -0,0 +1,291 @@
|
||||
import React, { useState } from 'react';
|
||||
import './css/web3-style.css';
|
||||
import './demo.css';
|
||||
|
||||
export function App() {
|
||||
const [activeTab, setActiveTab] = useState<'tokens' | 'components' | 'layouts' | 'docs'>('tokens');
|
||||
const [lang, setLang] = useState('en');
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Header / Nav */}
|
||||
<header>
|
||||
<h1>Web3 Corporate Style Guide</h1>
|
||||
<nav className="pixel-nav">
|
||||
<a
|
||||
href="#tokens"
|
||||
aria-current={activeTab === 'tokens' ? 'page' : undefined}
|
||||
onClick={(e) => { e.preventDefault(); setActiveTab('tokens'); }}
|
||||
>
|
||||
Design Tokens
|
||||
</a>
|
||||
<a
|
||||
href="#components"
|
||||
aria-current={activeTab === 'components' ? 'page' : undefined}
|
||||
onClick={(e) => { e.preventDefault(); setActiveTab('components'); }}
|
||||
>
|
||||
Components
|
||||
</a>
|
||||
<a
|
||||
href="#layouts"
|
||||
aria-current={activeTab === 'layouts' ? 'page' : undefined}
|
||||
onClick={(e) => { e.preventDefault(); setActiveTab('layouts'); }}
|
||||
>
|
||||
Layout Templates
|
||||
</a>
|
||||
<a
|
||||
href="#docs"
|
||||
aria-current={activeTab === 'docs' ? 'page' : undefined}
|
||||
onClick={(e) => { e.preventDefault(); setActiveTab('docs'); }}
|
||||
>
|
||||
Integration Guide
|
||||
</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
{/* Main Content Area */}
|
||||
<main>
|
||||
{activeTab === 'tokens' && (
|
||||
<div>
|
||||
<div className="pixel-card">
|
||||
<h2>Design Tokens</h2>
|
||||
<p>
|
||||
Core design primitives derived from the DAO Marketplace ecosystem. Import via <code>@import "@web3/style-guide/tokens/index.css";</code> or reference the CSS variables directly.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Colors */}
|
||||
<div className="pixel-card">
|
||||
<h3>Color Palette</h3>
|
||||
<div className="color-grid">
|
||||
<div className="color-swatch" style={{ background: '#0c1020', color: '#fff' }}>
|
||||
<div className="swatch-label">Bg Primary</div>
|
||||
<div className="swatch-hex">#0c1020</div>
|
||||
</div>
|
||||
<div className="color-swatch" style={{ background: 'rgba(21,27,48,.82)', color: '#fff' }}>
|
||||
<div className="swatch-label">Bg Secondary</div>
|
||||
<div className="swatch-hex">rgba(21,27,48,.82)</div>
|
||||
</div>
|
||||
<div className="color-swatch" style={{ background: 'rgba(6,10,22,.28)', color: '#fff' }}>
|
||||
<div className="swatch-label">Bg Elevated</div>
|
||||
<div className="swatch-hex">rgba(6,10,22,.28)</div>
|
||||
</div>
|
||||
<div className="color-swatch" style={{ background: '#59d8ae', color: '#000' }}>
|
||||
<div className="swatch-label">Accent Green</div>
|
||||
<div className="swatch-hex">#59d8ae</div>
|
||||
</div>
|
||||
<div className="color-swatch" style={{ background: '#6f8bff', color: '#fff' }}>
|
||||
<div className="swatch-label">Accent Blue</div>
|
||||
<div className="swatch-hex">#6f8bff</div>
|
||||
</div>
|
||||
<div className="color-swatch" style={{ background: '#819aff', color: '#fff' }}>
|
||||
<div className="swatch-label">Blue Hover</div>
|
||||
<div className="swatch-hex">#819aff</div>
|
||||
</div>
|
||||
<div className="color-swatch" style={{ background: '#e7eaf1', color: '#000' }}>
|
||||
<div className="swatch-label">Text Primary</div>
|
||||
<div className="swatch-hex">#e7eaf1</div>
|
||||
</div>
|
||||
<div className="color-swatch" style={{ background: '#8e98aa', color: '#fff' }}>
|
||||
<div className="swatch-label">Text Muted</div>
|
||||
<div className="swatch-hex">#8e98aa</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Typography */}
|
||||
<div className="pixel-card">
|
||||
<h3>Typography Specimens</h3>
|
||||
<div className="type-specimen">
|
||||
<div className="specimen-label">Heading XL (clamp(1.45rem, 3vw, 2rem))</div>
|
||||
<h2 style={{ margin: 0 }}>The quick brown fox jumps over the lazy dog</h2>
|
||||
</div>
|
||||
<div className="type-specimen">
|
||||
<div className="specimen-label">Heading Large (1.05rem, 760 weight)</div>
|
||||
<h3 style={{ margin: 0 }}>Ecosystem Governance & Tokenomics Dashboard</h3>
|
||||
</div>
|
||||
<div className="type-specimen">
|
||||
<div className="specimen-label">Body Text (0.88rem, 1.55 line-height)</div>
|
||||
<p style={{ margin: 0 }}>
|
||||
Participate in decentralized decision making by creating and voting on proposals. Ensure your wallet is connected and tokens are delegated to activate voting power.
|
||||
</p>
|
||||
</div>
|
||||
<div className="type-specimen">
|
||||
<div className="specimen-label">Code / Monospace</div>
|
||||
<code>0x71C7656EC7ab88b098defB751B7401B5f6d8976F</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'components' && (
|
||||
<div>
|
||||
<div className="pixel-card">
|
||||
<h2>UI Components</h2>
|
||||
<p>
|
||||
Reusable Web3 UI components styled with dark-mode aesthetic, glowing glassmorphism gradients, and custom interaction states.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Card Components */}
|
||||
<div className="pixel-card">
|
||||
<h3>Card Container (<code>.pixel-card</code>)</h3>
|
||||
<p>Standard content container with subtle dark-theme border and shadow backdrop.</p>
|
||||
<div className="pixel-card" style={{ background: 'rgba(21, 27, 48, 0.95)', marginTop: 16 }}>
|
||||
<h2>Nested Pixel Card</h2>
|
||||
<p>Cards automatically style nested headers, paragraphs, lists, and inputs.</p>
|
||||
<ul>
|
||||
<li>Automatic top/bottom margin collapse on first/last child</li>
|
||||
<li>Responsive border radius (16px desktop, 12px mobile)</li>
|
||||
<li>Glassmorphism background (rgba(21, 27, 48, 0.82))</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Buttons */}
|
||||
<div className="pixel-card">
|
||||
<h3>Buttons (<code>.pixel-btn</code>)</h3>
|
||||
<div className="btn-demo-row" style={{ marginTop: 16 }}>
|
||||
<button className="pixel-btn">Primary Action</button>
|
||||
<button className="pixel-btn" disabled>Disabled State</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Form Controls */}
|
||||
<div className="pixel-card">
|
||||
<h3>Form Controls</h3>
|
||||
<div className="form-group">
|
||||
<label>
|
||||
Proposal Title
|
||||
<input type="text" placeholder="e.g. BIP-42: Community Growth Fund Allocation" />
|
||||
</label>
|
||||
<label>
|
||||
Proposal Description
|
||||
<textarea placeholder="Provide detailed rationale and implementation details..."></textarea>
|
||||
</label>
|
||||
<label>
|
||||
Target Category
|
||||
<select>
|
||||
<option value="treasury">Treasury Allocation</option>
|
||||
<option value="governance">Governance Parameter Update</option>
|
||||
<option value="grant">Ecosystem Grant</option>
|
||||
</select>
|
||||
</label>
|
||||
<button className="pixel-btn">Submit Proposal</button>
|
||||
<p className="form-status">✓ Transaction broadcast successfully. Hash: 0xabc...123</p>
|
||||
<p className="form-error">✕ Error: Insufficient voting power to submit proposal.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Metric / Treasury Grids */}
|
||||
<div className="pixel-card">
|
||||
<h3>Stat & Balance Display</h3>
|
||||
<div className="treasury-balance-grid">
|
||||
<div className="treasury-balance">
|
||||
<span>Treasury Holdings</span>
|
||||
<strong>1,250,000 DMP</strong>
|
||||
</div>
|
||||
<div className="treasury-balance">
|
||||
<span>Total Delegated Power</span>
|
||||
<strong>850,420 VOTES</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'layouts' && (
|
||||
<div>
|
||||
<div className="pixel-card">
|
||||
<h2>Layout Templates</h2>
|
||||
<p>Standard page scaffolding for products in the Web3 ecosystem.</p>
|
||||
</div>
|
||||
|
||||
<div className="pixel-card">
|
||||
<h3>Dashboard Page Pattern</h3>
|
||||
<p>Structure for key product views — navigation top, central container, floating glass footer.</p>
|
||||
<div style={{ padding: 16, border: '1px dashed rgba(255,255,255,0.2)', borderRadius: 8 }}>
|
||||
<code>
|
||||
<header><br/>
|
||||
<h1>[Product Name]</h1><br/>
|
||||
<nav className="pixel-nav">...</nav><br/>
|
||||
</header><br/>
|
||||
<main><br/>
|
||||
<div className="pixel-card">...</div><br/>
|
||||
</main><br/>
|
||||
<footer className="floating-footer">...</footer>
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'docs' && (
|
||||
<div>
|
||||
<div className="pixel-card">
|
||||
<h2>Integration Guide</h2>
|
||||
<p>How to use this style guide across web3 products (React, Next.js, Vite, static HTML).</p>
|
||||
</div>
|
||||
|
||||
<div className="pixel-card">
|
||||
<h3>1. Option A: Pure CSS / HTML</h3>
|
||||
<p>Include the combined CSS file in your HTML <code><head></code> or bundler import:</p>
|
||||
<pre style={{ background: 'rgba(8,12,25,0.62)', padding: 16, borderRadius: 8, overflowX: 'auto' }}>
|
||||
<code>
|
||||
import "@web3/style-guide/css/web3-style.css";
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<div className="pixel-card">
|
||||
<h3>2. Option B: CSS Module / Utility Import</h3>
|
||||
<p>Import individual design tokens and component stylesheets:</p>
|
||||
<pre style={{ background: 'rgba(8,12,25,0.62)', padding: 16, borderRadius: 8, overflowX: 'auto' }}>
|
||||
<code>
|
||||
@import "@web3/style-guide/tokens/colors.css";<br/>
|
||||
@import "@web3/style-guide/tokens/typography.css";<br/>
|
||||
@import "@web3/style-guide/components/card.css";<br/>
|
||||
@import "@web3/style-guide/components/button.css";
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<div className="pixel-card">
|
||||
<h3>3. Brand Conventions</h3>
|
||||
<ul>
|
||||
<li><strong>Dark-first mode:</strong> All views must maintain <code>#0c1020</code> background with radial mesh gradients.</li>
|
||||
<li><strong>Brand Indicator:</strong> Product header logos must include the 10px glowing green status indicator (<code>#59d8ae</code>).</li>
|
||||
<li><strong>Interactive Blue:</strong> Action buttons and input focus rings use <code>#6f8bff</code> with subtle vertical translation on hover.</li>
|
||||
<li><strong>Floating Footer:</strong> Global footer sticks to the viewport bottom with 18px backdrop blur and language selector.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</main>
|
||||
|
||||
{/* Floating Footer */}
|
||||
<footer className="floating-footer">
|
||||
<div className="footer-content">
|
||||
<div className="footer-copyright">
|
||||
© 2026 Web3 Ecosystem Style Guide • Built from DAO Marketplace Layout
|
||||
</div>
|
||||
<div className="footer-language">
|
||||
<span className="footer-language-label">Language:</span>
|
||||
<select
|
||||
className="footer-language-select"
|
||||
value={lang}
|
||||
onChange={(e) => setLang(e.target.value)}
|
||||
>
|
||||
<option value="en">English (US)</option>
|
||||
<option value="es">Español</option>
|
||||
<option value="fr">Français</option>
|
||||
<option value="de">Deutsch</option>
|
||||
<option value="zh">中文</option>
|
||||
<option value="ja">日本語</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
97
src/css/base.css
Normal file
97
src/css/base.css
Normal file
@ -0,0 +1,97 @@
|
||||
/* ==========================================================================
|
||||
Web3 Style Guide — Base Reset & Global Styles
|
||||
========================================================================== */
|
||||
|
||||
@import "../tokens/index.css";
|
||||
|
||||
:root { color: var(--color-text-primary); background: var(--color-bg-primary); font-family: var(--font-family-base); }
|
||||
* { box-sizing: border-box; }
|
||||
body { min-width: 320px; min-height: 100vh; margin: 0; background: radial-gradient(circle at 12% -10%, rgba(93,106,255,.2), transparent 32rem), radial-gradient(circle at 88% 0%, rgba(44,197,163,.12), transparent 30rem), var(--color-bg-primary); color: var(--color-text-primary); line-height: var(--line-height-body); }
|
||||
button, input, textarea, select { font: inherit; }
|
||||
button { -webkit-tap-highlight-color: transparent; }
|
||||
a { color: inherit; }
|
||||
|
||||
/* ==========================================================================
|
||||
Header / Navigation
|
||||
========================================================================== */
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--header-gap);
|
||||
min-height: var(--header-height);
|
||||
padding: 0 var(--header-padding-x);
|
||||
background: rgba(12, 16, 32, 0.78);
|
||||
border-bottom: 1px solid var(--color-border-subtle);
|
||||
backdrop-filter: blur(18px);
|
||||
}
|
||||
|
||||
header h1 {
|
||||
flex: 0 0 auto;
|
||||
margin: 0;
|
||||
color: var(--color-text-heading);
|
||||
font-size: 1.05rem;
|
||||
font-weight: var(--font-weight-heading);
|
||||
letter-spacing: var(--letter-spacing-logo);
|
||||
}
|
||||
|
||||
header h1::before {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 9px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-accent-green);
|
||||
box-shadow: 0 0 0 5px var(--color-accent-green-muted);
|
||||
content: "";
|
||||
}
|
||||
|
||||
.pixel-nav {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
overflow-x: auto;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.pixel-nav::-webkit-scrollbar { display: none; }
|
||||
|
||||
.pixel-nav a {
|
||||
padding: 8px 10px;
|
||||
border-radius: 7px;
|
||||
color: #aeb6c8;
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
text-decoration: none;
|
||||
transition: color .18s ease, background .18s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.pixel-nav a:hover,
|
||||
.pixel-nav a[aria-current="page"] {
|
||||
background: rgba(255, 255, 255, 0.07);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Main Content Area
|
||||
========================================================================== */
|
||||
|
||||
main {
|
||||
width: min(100%, var(--container-max-width));
|
||||
margin: 0 auto;
|
||||
padding: var(--container-padding-y) var(--container-padding-x) var(--container-padding-bottom);
|
||||
}
|
||||
|
||||
/* Add bottom padding to prevent content from being hidden behind floating footer */
|
||||
main {
|
||||
padding-bottom: 100px !important;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
header { flex-wrap: wrap; gap: 10px 18px; padding: 14px 20px; }
|
||||
header h1 { margin-right: auto; }
|
||||
.pixel-nav { order: 3; flex-basis: 100%; }
|
||||
main { padding: 30px 16px 48px; }
|
||||
}
|
||||
32
src/css/button.css
Normal file
32
src/css/button.css
Normal file
@ -0,0 +1,32 @@
|
||||
/* ==========================================================================
|
||||
Web3 Style Guide — Button Component (.pixel-btn)
|
||||
========================================================================== */
|
||||
|
||||
.pixel-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: var(--btn-min-height);
|
||||
padding: var(--btn-padding-y) var(--btn-padding-x);
|
||||
border: 1px solid var(--color-accent-blue);
|
||||
border-radius: var(--btn-radius);
|
||||
background: var(--color-accent-blue);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-bold);
|
||||
line-height: 1;
|
||||
transition: transform .15s ease, background .15s ease, border-color .15s ease, opacity .15s ease;
|
||||
}
|
||||
|
||||
.pixel-btn:hover:not(:disabled) {
|
||||
border-color: var(--color-accent-blue-hover);
|
||||
background: var(--color-accent-blue-hover);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.pixel-btn:active:not(:disabled) { transform: translateY(0); }
|
||||
.pixel-btn:disabled { cursor: not-allowed; opacity: 0.45; }
|
||||
|
||||
/* When nested in a form-group, align to start */
|
||||
.form-group .pixel-btn { justify-self: start; }
|
||||
77
src/css/card.css
Normal file
77
src/css/card.css
Normal file
@ -0,0 +1,77 @@
|
||||
/* ==========================================================================
|
||||
Web3 Style Guide — Card Component (.pixel-card)
|
||||
========================================================================== */
|
||||
|
||||
.pixel-card {
|
||||
margin-bottom: var(--card-gap);
|
||||
padding: var(--card-padding);
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--color-border-subtle);
|
||||
border-radius: var(--card-radius);
|
||||
background: var(--color-bg-secondary);
|
||||
box-shadow: 0 18px 45px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
|
||||
.pixel-card > :first-child { margin-top: 0; }
|
||||
.pixel-card > :last-child { margin-bottom: 0; }
|
||||
|
||||
.pixel-card h2 {
|
||||
margin: 0 0 8px;
|
||||
color: var(--color-text-heading);
|
||||
font-size: var(--font-size-xl);
|
||||
letter-spacing: var(--letter-spacing-tight);
|
||||
line-height: var(--line-height-tight);
|
||||
}
|
||||
|
||||
.pixel-card h3 {
|
||||
margin: 28px 0 9px;
|
||||
color: var(--color-text-subheading);
|
||||
font-size: var(--font-size-lg);
|
||||
letter-spacing: var(--letter-spacing-normal);
|
||||
}
|
||||
|
||||
.pixel-card p { color: var(--color-text-body); }
|
||||
.pixel-card strong { color: var(--color-text-strong); }
|
||||
.pixel-card ul { margin: 16px 0 0; padding-left: 20px; color: var(--color-text-body); }
|
||||
.pixel-card li + li { margin-top: 8px; }
|
||||
.pixel-card label { display: grid; gap: 7px; margin-top: 18px; color: #dbe0eb; font-size: .9rem; font-weight: var(--font-weight-semibold); }
|
||||
|
||||
/* Inputs inside cards */
|
||||
.pixel-card input,
|
||||
.pixel-card textarea,
|
||||
.pixel-card select {
|
||||
width: 100%;
|
||||
min-height: var(--input-min-height);
|
||||
padding: var(--input-padding);
|
||||
border: 1px solid var(--color-border-input);
|
||||
border-radius: var(--input-radius);
|
||||
outline: 0;
|
||||
background: var(--color-bg-input);
|
||||
color: var(--color-text-input);
|
||||
transition: border-color .18s ease, box-shadow .18s ease;
|
||||
}
|
||||
|
||||
.pixel-card textarea { min-height: var(--input-textarea-height); resize: vertical; }
|
||||
.pixel-card input::placeholder,
|
||||
.pixel-card textarea::placeholder { color: var(--color-text-placeholder); }
|
||||
|
||||
.pixel-card input:focus,
|
||||
.pixel-card textarea:focus,
|
||||
.pixel-card select:focus {
|
||||
border-color: var(--color-accent-blue);
|
||||
box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
|
||||
}
|
||||
|
||||
.pixel-card small { color: var(--color-text-muted); font-size: var(--font-size-xs); font-weight: var(--font-weight-regular); line-height: var(--line-height-code); }
|
||||
.pixel-card code { padding: 2px 5px; border-radius: 4px; background: rgba(255, 255, 255, 0.07); color: var(--color-text-code); font-family: var(--font-family-mono); font-size: 0.82em; }
|
||||
|
||||
/* Card with link list (dashboard style) */
|
||||
.pixel-card > ul:has(li a) { display: grid; gap: 8px; padding: 0; list-style: none; }
|
||||
.pixel-card > ul:has(li a) li { margin: 0; border: 1px solid var(--color-border-subtle); border-radius: 9px; background: var(--color-bg-elevated); }
|
||||
.pixel-card > ul:has(li a) a { display: block; padding: 13px 14px; color: #e8ecff; font-weight: var(--font-weight-semibold); text-decoration: none; }
|
||||
.pixel-card > ul:has(li a) li:hover { border-color: var(--color-accent-blue-border); }
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 760px) {
|
||||
.pixel-card { border-radius: var(--card-border-radius-mobile); }
|
||||
}
|
||||
78
src/css/forms.css
Normal file
78
src/css/forms.css
Normal file
@ -0,0 +1,78 @@
|
||||
/* ==========================================================================
|
||||
Web3 Style Guide — Form Components
|
||||
========================================================================== */
|
||||
|
||||
/* Form group wrapper */
|
||||
.form-group { display: grid; gap: 14px; margin-top: 20px; }
|
||||
|
||||
/* Error / Status messages */
|
||||
.form-error,
|
||||
.form-status { margin: 0; padding: 10px 12px; border-radius: var(--input-radius); font-size: var(--font-size-base); }
|
||||
.form-error { background: var(--color-error-bg); color: var(--color-error) !important; }
|
||||
.form-status { background: var(--color-success-bg); color: var(--color-success) !important; }
|
||||
|
||||
/* Floating Footer */
|
||||
.floating-footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
padding: var(--footer-padding);
|
||||
background: rgba(12, 16, 32, 0.85);
|
||||
backdrop-filter: blur(18px);
|
||||
-webkit-backdrop-filter: blur(18px);
|
||||
border-top: 1px solid var(--color-border-subtle);
|
||||
box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
max-width: var(--container-max-width);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.footer-copyright {
|
||||
color: var(--color-text-muted);
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-medium);
|
||||
letter-spacing: var(--letter-spacing-micro);
|
||||
}
|
||||
|
||||
.footer-language { display: flex; align-items: center; gap: 8px; }
|
||||
.footer-language-label { color: var(--color-text-muted); font-size: var(--font-size-sm); font-weight: var(--font-weight-medium); }
|
||||
|
||||
.footer-language-select {
|
||||
min-height: 36px;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--color-border-input);
|
||||
border-radius: var(--input-radius);
|
||||
background: var(--color-bg-input);
|
||||
color: var(--color-text-input);
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-medium);
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
transition: border-color .18s ease, box-shadow .18s ease;
|
||||
}
|
||||
|
||||
.footer-language-select:hover { border-color: var(--color-accent-blue-border); }
|
||||
.footer-language-select:focus { border-color: var(--color-accent-blue); box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color); }
|
||||
.footer-language-select option { background: var(--color-bg-primary); color: var(--color-text-input); }
|
||||
|
||||
/* Responsive footer */
|
||||
@media (max-width: 760px) {
|
||||
.floating-footer { padding: 10px 20px; }
|
||||
.footer-content { flex-direction: column; gap: 8px; text-align: center; }
|
||||
main { padding-bottom: 120px !important; }
|
||||
}
|
||||
|
||||
/* Treasury Balance Grid */
|
||||
.treasury-balance-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin-top: 24px; }
|
||||
.treasury-balance { display: grid; gap: 7px; padding: 18px; border: 1px solid var(--color-border-subtle); border-radius: 10px; background: var(--color-bg-elevated); }
|
||||
.treasury-balance span { color: var(--color-text-muted); font-size: var(--font-size-sm); font-weight: var(--font-weight-semibold); }
|
||||
.treasury-balance strong { color: var(--color-text-heading); font-size: 1.35rem; letter-spacing: var(--letter-spacing-tight); }
|
||||
.treasury-address { margin-top: 22px !important; overflow-wrap: anywhere; }
|
||||
10
src/css/web3-style.css
Normal file
10
src/css/web3-style.css
Normal file
@ -0,0 +1,10 @@
|
||||
/* ==========================================================================
|
||||
Web3 Style Guide — Main Stylesheet
|
||||
Re-exports all component styles in dependency order
|
||||
========================================================================== */
|
||||
|
||||
@import "../tokens/index.css";
|
||||
@import "./base.css";
|
||||
@import "./card.css";
|
||||
@import "./button.css";
|
||||
@import "./forms.css";
|
||||
22
src/demo.css
Normal file
22
src/demo.css
Normal file
@ -0,0 +1,22 @@
|
||||
/* ==========================================================================
|
||||
Web3 Style Guide — Demo Page Styles
|
||||
========================================================================== */
|
||||
|
||||
.demo-section { margin-bottom: 48px; }
|
||||
.demo-section h2 { color: var(--color-text-heading); font-size: var(--font-size-xl); letter-spacing: var(--letter-spacing-tight); margin-bottom: 16px; }
|
||||
.demo-row { display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-start; }
|
||||
.demo-spacer { height: 24px; }
|
||||
|
||||
/* Color Swatch Grid */
|
||||
.color-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 14px; }
|
||||
.color-swatch { padding: 18px; border-radius: var(--input-radius); border: 1px solid var(--color-border-subtle); }
|
||||
.color-swatch .swatch-label { font-size: var(--font-size-sm); font-weight: var(--font-weight-medium); margin-top: 8px; }
|
||||
.color-swatch .swatch-hex { font-family: var(--font-family-mono); font-size: var(--font-size-xs); color: var(--color-text-muted); }
|
||||
|
||||
/* Type Specimens */
|
||||
.type-specimen { margin-bottom: 24px; padding: 16px; border: 1px solid var(--color-border-subtle); border-radius: var(--card-border-radius-mobile); background: var(--color-bg-secondary); }
|
||||
.type-specimen .specimen-label { font-size: var(--font-size-xs); color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 8px; }
|
||||
.type-specimen .specimen-text { color: var(--color-text-primary); }
|
||||
|
||||
/* Button Variants Demo */
|
||||
.btn-demo-row { display: flex; gap: 12px; flex-wrap: wrap; }
|
||||
9
src/main.tsx
Normal file
9
src/main.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { App } from './App';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
45
src/tokens/colors.css
Normal file
45
src/tokens/colors.css
Normal file
@ -0,0 +1,45 @@
|
||||
/* ==========================================================================
|
||||
Web3 Design Tokens — Color Palette
|
||||
Derived from dao-marketplace visual system
|
||||
========================================================================== */
|
||||
|
||||
:root {
|
||||
/* --- Background & Surface --- */
|
||||
--color-bg-primary: #0c1020;
|
||||
--color-bg-secondary: rgba(21, 27, 48, 0.82);
|
||||
--color-bg-elevated: rgba(6, 10, 22, 0.28);
|
||||
--color-bg-input: rgba(8, 12, 25, 0.62);
|
||||
|
||||
/* --- Brand Accents --- */
|
||||
/* Green — the signature Web3 accent (used for the logo dot, success states) */
|
||||
--color-accent-green: #59d8ae;
|
||||
--color-accent-green-muted: rgba(89, 216, 174, 0.13);
|
||||
--color-accent-green-bg: rgba(89, 216, 174, 0.12);
|
||||
|
||||
/* Blue — primary interactive colour (buttons, focus rings, links) */
|
||||
--color-accent-blue: #6f8bff;
|
||||
--color-accent-blue-hover: #819aff;
|
||||
--color-accent-blue-muted: rgba(119, 148, 255, 0.17);
|
||||
--color-accent-blue-border: rgba(119, 148, 255, 0.55);
|
||||
|
||||
/* --- Text --- */
|
||||
--color-text-primary: #e7eaf1;
|
||||
--color-text-heading: #f6f7fb;
|
||||
--color-text-subheading: #f3f5f9;
|
||||
--color-text-strong: #eff2f8;
|
||||
--color-text-body: #b9c1d1;
|
||||
--color-text-muted: #8e98aa;
|
||||
--color-text-input: #f4f6fb;
|
||||
--color-text-placeholder: #738097;
|
||||
--color-text-code: #cbd5ff;
|
||||
|
||||
/* --- Semantic --- */
|
||||
--color-error: #ffb4bb;
|
||||
--color-error-bg: rgba(244, 99, 112, 0.12);
|
||||
--color-success: #9ee8ce;
|
||||
--color-success-bg: rgba(89, 216, 174, 0.12);
|
||||
|
||||
/* --- Borders --- */
|
||||
--color-border-subtle: rgba(255, 255, 255, 0.09);
|
||||
--color-border-input: rgba(255, 255, 255, 0.13);
|
||||
}
|
||||
8
src/tokens/index.css
Normal file
8
src/tokens/index.css
Normal file
@ -0,0 +1,8 @@
|
||||
/* ==========================================================================
|
||||
Web3 Style Guide — Design Tokens
|
||||
Import this file to bring all tokens into scope
|
||||
========================================================================== */
|
||||
|
||||
@import "./colors.css";
|
||||
@import "./typography.css";
|
||||
@import "./spacing.css";
|
||||
42
src/tokens/spacing.css
Normal file
42
src/tokens/spacing.css
Normal file
@ -0,0 +1,42 @@
|
||||
/* ==========================================================================
|
||||
Web3 Design Tokens — Spacing & Layout
|
||||
========================================================================== */
|
||||
|
||||
:root {
|
||||
/* --- Container --- */
|
||||
--container-max-width: 1120px;
|
||||
--container-padding-x: 28px;
|
||||
--container-padding-y: 48px;
|
||||
--container-padding-bottom: 72px;
|
||||
|
||||
/* --- Header --- */
|
||||
--header-height: 72px;
|
||||
--header-padding-x: 5vw;
|
||||
--header-gap: 32px;
|
||||
|
||||
/* --- Card --- */
|
||||
--card-padding: clamp(22px, 4vw, 32px);
|
||||
--card-gap: 20px;
|
||||
--card-radius: 16px;
|
||||
--card-border-radius-mobile: 12px;
|
||||
|
||||
/* --- Button --- */
|
||||
--btn-min-height: 42px;
|
||||
--btn-padding-x: 15px;
|
||||
--btn-padding-y: 10px;
|
||||
--btn-radius: 8px;
|
||||
|
||||
/* --- Inputs --- */
|
||||
--input-min-height: 44px;
|
||||
--input-padding: 11px 12px;
|
||||
--input-radius: 8px;
|
||||
--input-textarea-height: 112px;
|
||||
|
||||
/* --- Footer --- */
|
||||
--footer-padding: 12px 5vw;
|
||||
--footer-height: 100px; /* bottom padding reserved on main */
|
||||
|
||||
/* --- Focus Ring --- */
|
||||
--focus-ring-color: rgba(119, 148, 255, 0.17);
|
||||
--focus-ring-width: 3px;
|
||||
}
|
||||
35
src/tokens/typography.css
Normal file
35
src/tokens/typography.css
Normal file
@ -0,0 +1,35 @@
|
||||
/* ==========================================================================
|
||||
Web3 Design Tokens — Typography
|
||||
========================================================================== */
|
||||
|
||||
:root {
|
||||
/* --- Font Families --- */
|
||||
--font-family-base: Inter, ui-sans-serif, system-ui, -apple-system,
|
||||
BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
--font-family-mono: "SFMono-Regular", Consolas, monospace;
|
||||
|
||||
/* --- Font Sizes --- */
|
||||
--font-size-xs: 0.78rem;
|
||||
--font-size-sm: 0.82rem;
|
||||
--font-size-base: 0.88rem;
|
||||
--font-size-lg: 1.05rem;
|
||||
--font-size-xl: clamp(1.45rem, 3vw, 2rem);
|
||||
|
||||
/* --- Font Weights --- */
|
||||
--font-weight-regular: 400;
|
||||
--font-weight-medium: 570;
|
||||
--font-weight-semibold: 620;
|
||||
--font-weight-bold: 680;
|
||||
--font-weight-heading: 760;
|
||||
|
||||
/* --- Line Heights --- */
|
||||
--line-height-body: 1.55;
|
||||
--line-height-tight: 1.2;
|
||||
--line-height-code: 1.45;
|
||||
|
||||
/* --- Letter Spacing --- */
|
||||
--letter-spacing-tight: -0.045em;
|
||||
--letter-spacing-normal: -0.015em;
|
||||
--letter-spacing-logo: -0.03em;
|
||||
--letter-spacing-micro: -0.01em;
|
||||
}
|
||||
21
tsconfig.json
Normal file
21
tsconfig.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
8
vite.config.ts
Normal file
8
vite.config.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
root: '.',
|
||||
publicDir: 'public',
|
||||
});
|
||||
Reference in New Issue
Block a user