docs: consolidate exploration & audit reports under docs/ (TEC-3094)
- Move 8 stray .md (+5 .txt) from ~/Desktop into docs/explorations/from-desktop/ - Reorganize 27 .md/.txt at workspace root: - audit reports -> docs/audits/ - exploration reports -> docs/explorations/ - design system -> docs/design-system/ - Keep only README/CHANGELOG/CONTRIBUTING/CLAUDE at repo root - Refresh docs/README.md as canonical index with links to all groups - Note: pre-existing docs/audits/AUDIT_INDEX.md and AUDIT_SUMMARY.md were overwritten by the newer root-level versions during the move Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
241
docs/design-system/DESIGN_SYSTEM_QUICK_REFERENCE.md
Normal file
241
docs/design-system/DESIGN_SYSTEM_QUICK_REFERENCE.md
Normal file
@@ -0,0 +1,241 @@
|
||||
# Design System Quick Reference
|
||||
|
||||
## Component Imports
|
||||
|
||||
```typescript
|
||||
import {
|
||||
StatCard,
|
||||
PriceDelta,
|
||||
MarketIndex,
|
||||
DataTable,
|
||||
CompactHeader,
|
||||
DashboardLayout,
|
||||
TickerStrip,
|
||||
} from '@/components/design-system';
|
||||
```
|
||||
|
||||
## Quick Examples
|
||||
|
||||
### StatCard - KPI Display
|
||||
```tsx
|
||||
<StatCard
|
||||
label="Giá TB/m²"
|
||||
value="45.2"
|
||||
unit="tr/m²"
|
||||
delta={+2.5}
|
||||
sublabel="24h"
|
||||
icon={<TrendingUp />}
|
||||
/>
|
||||
```
|
||||
|
||||
### PriceDelta - Change Indicator
|
||||
```tsx
|
||||
<PriceDelta value={5.2} size="md" /> {/* +5.20% ↑ Green */}
|
||||
<PriceDelta value={-2.1} size="sm" /> {/* -2.10% ↓ Red */}
|
||||
<PriceDelta value={0} direction="neutral" /> {/* 0.00% - Yellow */}
|
||||
```
|
||||
|
||||
### MarketIndex - Hero Metric
|
||||
```tsx
|
||||
<MarketIndex
|
||||
name="GGX Market"
|
||||
value="1,240"
|
||||
changePercent={3.5}
|
||||
change={"+35"}
|
||||
window="24h"
|
||||
/>
|
||||
```
|
||||
|
||||
### DataTable - Sortable Data
|
||||
```tsx
|
||||
const columns: DataTableColumn<District>[] = [
|
||||
{
|
||||
id: 'name',
|
||||
header: 'District',
|
||||
cell: (row) => row.name,
|
||||
sortable: true,
|
||||
sortValue: (row) => row.name,
|
||||
},
|
||||
{
|
||||
id: 'price',
|
||||
header: 'Price/m²',
|
||||
cell: (row) => `${row.avgPrice} tr`,
|
||||
align: 'right',
|
||||
numeric: true,
|
||||
sortable: true,
|
||||
sortValue: (row) => row.avgPrice,
|
||||
},
|
||||
];
|
||||
|
||||
<DataTable columns={columns} data={districts} dense defaultSortId="price" />
|
||||
```
|
||||
|
||||
### TickerStrip - Scrolling Ticker
|
||||
```tsx
|
||||
<TickerStrip
|
||||
items={[
|
||||
{ id: 'q1', label: 'Quan 1', changePercent: 2.1 },
|
||||
{ id: 'q2', label: 'Quan 2', changePercent: -1.3 },
|
||||
]}
|
||||
/>
|
||||
```
|
||||
|
||||
### DashboardLayout - Full Page Frame
|
||||
```tsx
|
||||
<DashboardLayout
|
||||
header={<CompactHeader breadcrumb="Market" />}
|
||||
sidebar={<Navigation />}
|
||||
ticker={<TickerStrip items={items} />}
|
||||
sidebarCollapsed={collapsed}
|
||||
>
|
||||
<div className="space-y-6">
|
||||
{/* Main content */}
|
||||
</div>
|
||||
</DashboardLayout>
|
||||
```
|
||||
|
||||
## Design Tokens
|
||||
|
||||
### Colors (CSS Variables)
|
||||
|
||||
**Light Mode** (`:root`)
|
||||
- `--foreground: 220 20% 12%` — Dark navy text
|
||||
- `--background: 0 0% 97%` — Off-white background
|
||||
- `--background-elevated: 0 0% 100%` — Pure white cards
|
||||
- `--primary: 142 72% 42%` — Green (up)
|
||||
- `--signal-down: 0 84% 55%` — Red (down)
|
||||
- `--signal-neutral: 45 93% 45%` — Yellow (neutral)
|
||||
|
||||
**Dark Mode** (`.dark`)
|
||||
- `--foreground: 210 20% 90%` — Off-white text
|
||||
- `--background: 220 20% 4%` — Very dark background
|
||||
- Same primary/signal colors (brightness-adjusted)
|
||||
|
||||
### Typography
|
||||
|
||||
```css
|
||||
/* Font families */
|
||||
font-sans /* Inter */
|
||||
font-mono /* JetBrains Mono (tabular-nums) */
|
||||
|
||||
/* Data-specific sizes */
|
||||
text-ticker /* 0.8125rem — ticker animation */
|
||||
text-data-sm /* 0.75rem — compact stats */
|
||||
text-data-md /* 0.875rem — default metric */
|
||||
text-data-lg /* 1.25rem — large KPI values */
|
||||
```
|
||||
|
||||
### Spacing
|
||||
|
||||
```css
|
||||
h-row /* 2.25rem (36px) — table row height */
|
||||
h-ticker-bar /* 2rem (32px) — ticker height */
|
||||
h-header-compact /* 3rem (48px) — dashboard header */
|
||||
```
|
||||
|
||||
### Utilities
|
||||
|
||||
```css
|
||||
[data-numeric] /* Applies font-variant-numeric: tabular-nums */
|
||||
elevation-1 /* Subtle shadow: 0 1px 2px rgba(0,0,0,0.3) */
|
||||
elevation-2 /* Prominent shadow: 0 4px 12px rgba(0,0,0,0.4) */
|
||||
```
|
||||
|
||||
## Analytics API
|
||||
|
||||
```typescript
|
||||
import { analyticsApi } from '@/lib/analytics-api';
|
||||
import {
|
||||
useMarketReport,
|
||||
useHeatmap,
|
||||
usePriceTrend,
|
||||
useDistrictStats,
|
||||
} from '@/lib/hooks/use-analytics';
|
||||
|
||||
// Raw API calls
|
||||
const report = await analyticsApi.getMarketReport('Ho Chi Minh', 'month');
|
||||
const heatmap = await analyticsApi.getHeatmap('Ho Chi Minh', 'month');
|
||||
|
||||
// React Query hooks
|
||||
const { data: districts } = useDistrictStats('Ho Chi Minh', 'month');
|
||||
const { data: trend } = usePriceTrend('Quan 1', 'Ho Chi Minh', 'apartment', ['month-1', 'month']);
|
||||
```
|
||||
|
||||
## Charts (Recharts)
|
||||
|
||||
```typescript
|
||||
import { PriceTrendChart } from '@/components/charts/price-trend-chart';
|
||||
import { DistrictBarChart } from '@/components/charts/district-bar-chart';
|
||||
import { AgentPerformance } from '@/components/charts/agent-performance';
|
||||
|
||||
// Line chart with dual Y-axis
|
||||
<PriceTrendChart
|
||||
data={[{ period: 'Jan', 'Gia/m2': 45, 'Tin đăng': 120 }]}
|
||||
height={350}
|
||||
/>
|
||||
|
||||
// Bar chart
|
||||
<DistrictBarChart
|
||||
data={[{ district: 'Q1', price: 45, listings: 50 }]}
|
||||
dataKey="price"
|
||||
/>
|
||||
|
||||
// Mixed dashboard (with mock data)
|
||||
<AgentPerformance />
|
||||
```
|
||||
|
||||
## Maps (Mapbox)
|
||||
|
||||
```typescript
|
||||
import { DistrictHeatmap } from '@/components/charts/district-heatmap';
|
||||
import { ListingMap } from '@/components/map/listing-map';
|
||||
import { LocationPicker } from '@/components/map/location-picker';
|
||||
|
||||
// Heatmap
|
||||
<DistrictHeatmap
|
||||
data={[
|
||||
{ district: 'Quan 1', avgPriceM2: 150000, totalListings: 25, medianPrice: '7 tỷ' },
|
||||
]}
|
||||
city="Ho Chi Minh"
|
||||
onDistrictClick={(name) => console.log(name)}
|
||||
/>
|
||||
|
||||
// Listing markers
|
||||
<ListingMap
|
||||
listings={listings}
|
||||
selectedListingId={selected?.id}
|
||||
onMarkerClick={(listing) => navigate(`/listing/${listing.id}`)}
|
||||
/>
|
||||
|
||||
// Interactive location picker
|
||||
<LocationPicker
|
||||
lat={currentLat}
|
||||
lng={currentLng}
|
||||
onChange={({ lat, lng }, resolved) => {
|
||||
// resolved.city, resolved.district, resolved.ward available
|
||||
setCoords({ lat, lng });
|
||||
}}
|
||||
height="400px"
|
||||
/>
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always use `[data-numeric]` or `font-mono` for numbers** — ensures proper alignment
|
||||
2. **Signal colors:** Green (up), Red (down), Yellow (neutral)
|
||||
3. **Spacing:** Use Tailwind gap classes; `gap-4` for cards, `gap-6` for sections
|
||||
4. **Sticky headers:** `sticky top-0 z-10` pattern
|
||||
5. **Responsive:** Mobile-first; `md:` for tablet breakpoints
|
||||
6. **Dark mode:** CSS variables handle both modes automatically
|
||||
7. **No hardcoded colors:** Use `hsl(var(--primary))` pattern for dynamic theming
|
||||
|
||||
## Environment Setup
|
||||
|
||||
```bash
|
||||
# Required for maps
|
||||
NEXT_PUBLIC_MAPBOX_TOKEN=your_token_here
|
||||
|
||||
# Optional
|
||||
NEXT_PUBLIC_ANALYTICS_ENDPOINT=...
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user