Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm
Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)
Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability
Migration completed: $(date)
🤖 Clean migration with full functionality preserved
614 lines
23 KiB
Python
Executable File
614 lines
23 KiB
Python
Executable File
"""
|
|
DSS Merge Case Examples
|
|
|
|
Demonstrates how DSS handles multi-source token ingestion and translation
|
|
to the canonical DSS structure. Uses HeroUI and shadcn as examples.
|
|
|
|
Key Principle: DSS is MONOLITHIC. External systems translate TO us.
|
|
"""
|
|
|
|
import asyncio
|
|
import json
|
|
from pathlib import Path
|
|
|
|
# Add parent to path for imports
|
|
import sys
|
|
sys.path.insert(0, str(Path(__file__).parent.parent / "tools"))
|
|
|
|
from ingest import (
|
|
DesignToken, TokenCollection, TokenMerger, MergeStrategy,
|
|
CSSTokenSource, JSONTokenSource
|
|
)
|
|
from ingest.base import TokenType, TokenCategory
|
|
|
|
|
|
# =============================================================================
|
|
# CASE 1: HeroUI Token Structure
|
|
# =============================================================================
|
|
# HeroUI uses: --heroui-{category}-{scale}
|
|
# Example: --heroui-primary-500, --heroui-content1, --heroui-radius-medium
|
|
|
|
HEROUI_TOKENS = """
|
|
:root {
|
|
/* HeroUI Color Scale System */
|
|
--heroui-primary-50: #e6f1fe;
|
|
--heroui-primary-100: #cce3fd;
|
|
--heroui-primary-200: #99c7fb;
|
|
--heroui-primary-300: #66aaf9;
|
|
--heroui-primary-400: #338ef7;
|
|
--heroui-primary-500: #006FEE;
|
|
--heroui-primary-600: #005bc4;
|
|
--heroui-primary-700: #004493;
|
|
--heroui-primary-800: #002e62;
|
|
--heroui-primary-900: #001731;
|
|
|
|
--heroui-secondary-500: #7828c8;
|
|
--heroui-success-500: #17c964;
|
|
--heroui-warning-500: #f5a524;
|
|
--heroui-danger-500: #f31260;
|
|
|
|
/* HeroUI Content Layers */
|
|
--heroui-content1: #ffffff;
|
|
--heroui-content2: #f4f4f5;
|
|
--heroui-content3: #e4e4e7;
|
|
--heroui-content4: #d4d4d8;
|
|
|
|
/* HeroUI Layout Tokens */
|
|
--heroui-radius-small: 8px;
|
|
--heroui-radius-medium: 12px;
|
|
--heroui-radius-large: 14px;
|
|
|
|
--heroui-shadow-small: 0px 0px 5px 0px rgba(0,0,0,0.02);
|
|
--heroui-shadow-medium: 0px 0px 15px 0px rgba(0,0,0,0.03);
|
|
--heroui-shadow-large: 0px 0px 30px 0px rgba(0,0,0,0.04);
|
|
|
|
--heroui-font-size-tiny: 0.75rem;
|
|
--heroui-font-size-small: 0.875rem;
|
|
--heroui-font-size-medium: 1rem;
|
|
--heroui-font-size-large: 1.125rem;
|
|
|
|
--heroui-spacing-unit: 4px;
|
|
}
|
|
"""
|
|
|
|
# =============================================================================
|
|
# CASE 2: shadcn Token Structure
|
|
# =============================================================================
|
|
# shadcn uses: --{semantic-name} with background/foreground pattern
|
|
# Example: --primary, --primary-foreground, --card, --card-foreground
|
|
|
|
SHADCN_TOKENS = """
|
|
:root {
|
|
/* shadcn Semantic Colors (OKLCH format) */
|
|
--background: 0 0% 100%;
|
|
--foreground: 222.2 84% 4.9%;
|
|
|
|
--card: 0 0% 100%;
|
|
--card-foreground: 222.2 84% 4.9%;
|
|
|
|
--popover: 0 0% 100%;
|
|
--popover-foreground: 222.2 84% 4.9%;
|
|
|
|
--primary: 222.2 47.4% 11.2%;
|
|
--primary-foreground: 210 40% 98%;
|
|
|
|
--secondary: 210 40% 96.1%;
|
|
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
|
|
--muted: 210 40% 96.1%;
|
|
--muted-foreground: 215.4 16.3% 46.9%;
|
|
|
|
--accent: 210 40% 96.1%;
|
|
--accent-foreground: 222.2 47.4% 11.2%;
|
|
|
|
--destructive: 0 84.2% 60.2%;
|
|
|
|
--border: 214.3 31.8% 91.4%;
|
|
--input: 214.3 31.8% 91.4%;
|
|
--ring: 222.2 84% 4.9%;
|
|
|
|
--radius: 0.5rem;
|
|
|
|
/* shadcn Chart Colors */
|
|
--chart-1: 12 76% 61%;
|
|
--chart-2: 173 58% 39%;
|
|
--chart-3: 197 37% 24%;
|
|
--chart-4: 43 74% 66%;
|
|
--chart-5: 27 87% 67%;
|
|
}
|
|
"""
|
|
|
|
# =============================================================================
|
|
# CASE 3: Legacy Corporate CSS (typical client scenario)
|
|
# =============================================================================
|
|
# Legacy uses: various naming conventions, inconsistent structure
|
|
|
|
LEGACY_CORPORATE_TOKENS = """
|
|
:root {
|
|
/* Old brand colors - inconsistent naming */
|
|
--brand-blue: #1E40AF;
|
|
--brand-dark-blue: #1E3A8A;
|
|
--brand-light: #DBEAFE;
|
|
--brandAccent: #F59E0B; /* camelCase mixed in */
|
|
|
|
/* Old button colors */
|
|
--btn-primary-bg: #1E40AF;
|
|
--btn-primary-text: #FFFFFF;
|
|
--btn-secondary-bg: #F3F4F6;
|
|
|
|
/* Inconsistent spacing */
|
|
--space-xs: 4px;
|
|
--space-sm: 8px;
|
|
--spacing-md: 16px; /* Different prefix! */
|
|
--SPACING_LG: 24px; /* SCREAMING_CASE! */
|
|
|
|
/* Typography chaos */
|
|
--font-base: 16px;
|
|
--fontSize-lg: 18px;
|
|
--text-xl: 24px;
|
|
|
|
/* Random radius values */
|
|
--rounded: 4px;
|
|
--border-radius-md: 8px;
|
|
--corners-lg: 12px;
|
|
}
|
|
"""
|
|
|
|
|
|
# =============================================================================
|
|
# DSS CANONICAL STRUCTURE (The Target)
|
|
# =============================================================================
|
|
# This is what ALL external systems translate TO. Never changes.
|
|
|
|
DSS_CANONICAL = {
|
|
"colors": {
|
|
"primary": {"50": None, "100": None, "200": None, "300": None, "400": None,
|
|
"500": None, "600": None, "700": None, "800": None, "900": None},
|
|
"secondary": {"500": None},
|
|
"success": {"500": None},
|
|
"warning": {"500": None},
|
|
"danger": {"500": None},
|
|
"neutral": {"50": None, "100": None, "200": None, "300": None, "400": None,
|
|
"500": None, "600": None, "700": None, "800": None, "900": None},
|
|
},
|
|
"spacing": {
|
|
"xs": None, "sm": None, "md": None, "lg": None, "xl": None, "2xl": None
|
|
},
|
|
"radius": {
|
|
"sm": None, "md": None, "lg": None, "xl": None, "full": None
|
|
},
|
|
"shadows": {
|
|
"sm": None, "md": None, "lg": None, "xl": None
|
|
},
|
|
"typography": {
|
|
"fontSize": {"xs": None, "sm": None, "base": None, "lg": None, "xl": None}
|
|
}
|
|
}
|
|
|
|
|
|
# =============================================================================
|
|
# TRANSLATION DICTIONARIES
|
|
# =============================================================================
|
|
|
|
def create_heroui_translation():
|
|
"""
|
|
Translation dictionary: HeroUI → DSS Canonical
|
|
|
|
HeroUI uses numeric color scales (like DSS) but different naming.
|
|
Mapping is mostly 1:1 with prefix removal.
|
|
"""
|
|
return {
|
|
"$schema": "dss-translation-v1",
|
|
"project": "heroui-integration",
|
|
"source": "heroui",
|
|
"mappings": {
|
|
"tokens": {
|
|
# Colors - direct scale mapping
|
|
"--heroui-primary-50": "color.primary.50",
|
|
"--heroui-primary-100": "color.primary.100",
|
|
"--heroui-primary-200": "color.primary.200",
|
|
"--heroui-primary-300": "color.primary.300",
|
|
"--heroui-primary-400": "color.primary.400",
|
|
"--heroui-primary-500": "color.primary.500",
|
|
"--heroui-primary-600": "color.primary.600",
|
|
"--heroui-primary-700": "color.primary.700",
|
|
"--heroui-primary-800": "color.primary.800",
|
|
"--heroui-primary-900": "color.primary.900",
|
|
|
|
"--heroui-secondary-500": "color.secondary.500",
|
|
"--heroui-success-500": "color.success.500",
|
|
"--heroui-warning-500": "color.warning.500",
|
|
"--heroui-danger-500": "color.danger.500",
|
|
|
|
# Content layers → Neutral scale
|
|
"--heroui-content1": "color.neutral.50",
|
|
"--heroui-content2": "color.neutral.100",
|
|
"--heroui-content3": "color.neutral.200",
|
|
"--heroui-content4": "color.neutral.300",
|
|
|
|
# Layout tokens
|
|
"--heroui-radius-small": "radius.sm",
|
|
"--heroui-radius-medium": "radius.md",
|
|
"--heroui-radius-large": "radius.lg",
|
|
|
|
"--heroui-shadow-small": "shadow.sm",
|
|
"--heroui-shadow-medium": "shadow.md",
|
|
"--heroui-shadow-large": "shadow.lg",
|
|
|
|
# Typography
|
|
"--heroui-font-size-tiny": "typography.fontSize.xs",
|
|
"--heroui-font-size-small": "typography.fontSize.sm",
|
|
"--heroui-font-size-medium": "typography.fontSize.base",
|
|
"--heroui-font-size-large": "typography.fontSize.lg",
|
|
|
|
# Spacing
|
|
"--heroui-spacing-unit": "spacing.unit",
|
|
},
|
|
"components": {
|
|
"Button": "Button", # HeroUI Button → DSS Button
|
|
"Card": "Card",
|
|
"Input": "Input",
|
|
}
|
|
},
|
|
"custom_props": {
|
|
# HeroUI-specific that don't map to DSS core
|
|
# These go in isolated namespace
|
|
},
|
|
"notes": [
|
|
"HeroUI uses numeric scales similar to DSS - easy mapping",
|
|
"Content layers (1-4) map to neutral scale",
|
|
"Component mapping is mostly 1:1"
|
|
]
|
|
}
|
|
|
|
|
|
def create_shadcn_translation():
|
|
"""
|
|
Translation dictionary: shadcn → DSS Canonical
|
|
|
|
shadcn uses semantic naming (primary, secondary, muted) without scales.
|
|
We map to the 500 (default) value in DSS scales.
|
|
|
|
KEY DIFFERENCE: shadcn is HEADLESS - no numeric scales!
|
|
"""
|
|
return {
|
|
"$schema": "dss-translation-v1",
|
|
"project": "shadcn-integration",
|
|
"source": "shadcn",
|
|
"mappings": {
|
|
"tokens": {
|
|
# Semantic colors → DSS scale defaults
|
|
"--background": "color.neutral.50",
|
|
"--foreground": "color.neutral.900",
|
|
|
|
"--primary": "color.primary.500",
|
|
"--primary-foreground": "color.primary.50",
|
|
|
|
"--secondary": "color.secondary.500",
|
|
"--secondary-foreground": "color.secondary.50",
|
|
|
|
"--muted": "color.neutral.200",
|
|
"--muted-foreground": "color.neutral.600",
|
|
|
|
"--accent": "color.accent.500",
|
|
"--accent-foreground": "color.accent.50",
|
|
|
|
"--destructive": "color.danger.500",
|
|
|
|
"--card": "color.neutral.50",
|
|
"--card-foreground": "color.neutral.900",
|
|
|
|
"--popover": "color.neutral.50",
|
|
"--popover-foreground": "color.neutral.900",
|
|
|
|
"--border": "color.neutral.200",
|
|
"--input": "color.neutral.200",
|
|
"--ring": "color.primary.500",
|
|
|
|
# Layout
|
|
"--radius": "radius.md",
|
|
},
|
|
"components": {
|
|
# shadcn components → DSS components
|
|
"Button": "Button",
|
|
"Card": "Card",
|
|
"Input": "Input",
|
|
"Dialog": "Modal",
|
|
"Popover": "Popover",
|
|
}
|
|
},
|
|
"custom_props": {
|
|
# shadcn-specific that don't exist in DSS
|
|
"color.chart.1": "var(--chart-1)",
|
|
"color.chart.2": "var(--chart-2)",
|
|
"color.chart.3": "var(--chart-3)",
|
|
"color.chart.4": "var(--chart-4)",
|
|
"color.chart.5": "var(--chart-5)",
|
|
"color.sidebar.primary": "var(--sidebar-primary)",
|
|
},
|
|
"notes": [
|
|
"shadcn is HEADLESS - no numeric color scales",
|
|
"Semantic names map to 500 (default) DSS values",
|
|
"foreground variants map to contrast colors (50)",
|
|
"Chart colors are shadcn-specific custom props"
|
|
]
|
|
}
|
|
|
|
|
|
def create_legacy_translation():
|
|
"""
|
|
Translation dictionary: Legacy Corporate → DSS Canonical
|
|
|
|
Messy legacy code with inconsistent naming needs careful mapping.
|
|
"""
|
|
return {
|
|
"$schema": "dss-translation-v1",
|
|
"project": "acme-corp-legacy",
|
|
"source": "legacy-css",
|
|
"mappings": {
|
|
"tokens": {
|
|
# Brand colors (inconsistent naming)
|
|
"--brand-blue": "color.primary.500",
|
|
"--brand-dark-blue": "color.primary.700",
|
|
"--brand-light": "color.primary.100",
|
|
"--brandAccent": "color.warning.500", # camelCase → DSS
|
|
|
|
# Button colors → Component tokens
|
|
"--btn-primary-bg": "color.primary.500",
|
|
"--btn-primary-text": "color.neutral.50",
|
|
"--btn-secondary-bg": "color.neutral.100",
|
|
|
|
# Spacing chaos → DSS order
|
|
"--space-xs": "spacing.xs",
|
|
"--space-sm": "spacing.sm",
|
|
"--spacing-md": "spacing.md",
|
|
"--SPACING_LG": "spacing.lg",
|
|
|
|
# Typography normalization
|
|
"--font-base": "typography.fontSize.base",
|
|
"--fontSize-lg": "typography.fontSize.lg",
|
|
"--text-xl": "typography.fontSize.xl",
|
|
|
|
# Radius normalization
|
|
"--rounded": "radius.sm",
|
|
"--border-radius-md": "radius.md",
|
|
"--corners-lg": "radius.lg",
|
|
},
|
|
"components": {
|
|
".btn-primary": "Button[variant=primary]",
|
|
".btn-secondary": "Button[variant=secondary]",
|
|
".card-wrapper": "Card",
|
|
".input-field": "Input",
|
|
}
|
|
},
|
|
"custom_props": {
|
|
# ACME-specific branding that extends DSS
|
|
"color.brand.acme.primary": "#1E40AF",
|
|
"color.brand.acme.accent": "#F59E0B",
|
|
},
|
|
"validation_warnings": [
|
|
"Inconsistent spacing prefixes detected",
|
|
"Mixed case conventions found",
|
|
"Some values may need manual review"
|
|
],
|
|
"notes": [
|
|
"Legacy system had 4 different naming conventions",
|
|
"All mapped to DSS canonical structure",
|
|
"Brand-specific colors isolated in custom_props"
|
|
]
|
|
}
|
|
|
|
|
|
# =============================================================================
|
|
# MERGE DEMONSTRATIONS
|
|
# =============================================================================
|
|
|
|
async def demonstrate_merge_heroui_shadcn():
|
|
"""
|
|
CASE: Merge HeroUI and shadcn tokens into DSS canonical structure.
|
|
|
|
This demonstrates how two different atomic structures become one.
|
|
"""
|
|
print("\n" + "="*70)
|
|
print("MERGE CASE: HeroUI + shadcn → DSS Canonical")
|
|
print("="*70)
|
|
|
|
css_source = CSSTokenSource()
|
|
|
|
# Ingest both sources
|
|
heroui_collection = await css_source.extract(HEROUI_TOKENS)
|
|
shadcn_collection = await css_source.extract(SHADCN_TOKENS)
|
|
|
|
print(f"\n📥 HeroUI tokens extracted: {len(heroui_collection.tokens)}")
|
|
print(f"📥 shadcn tokens extracted: {len(shadcn_collection.tokens)}")
|
|
|
|
# Merge with PREFER_SPECIFIC strategy
|
|
# This prefers concrete values (hex) over references
|
|
merger = TokenMerger(strategy=MergeStrategy.PREFER_SPECIFIC)
|
|
result = merger.merge([heroui_collection, shadcn_collection])
|
|
|
|
print(f"\n🔀 Merged result: {result.stats['total_tokens']} tokens")
|
|
print(f" New tokens: {result.stats['new_tokens']}")
|
|
print(f" Conflicts resolved: {result.stats['conflicts_resolved']}")
|
|
|
|
# Show conflicts
|
|
if result.conflicts:
|
|
print(f"\n⚠️ Conflicts detected ({len(result.conflicts)}):")
|
|
for conflict in result.conflicts[:5]:
|
|
print(f" • {conflict.token_name}")
|
|
print(f" HeroUI: {conflict.existing.value}")
|
|
print(f" shadcn: {conflict.incoming.value}")
|
|
print(f" Resolution: {conflict.resolution}")
|
|
|
|
# Demonstrate atomic structure difference
|
|
print("\n" + "-"*70)
|
|
print("ATOMIC STRUCTURE COMPARISON:")
|
|
print("-"*70)
|
|
|
|
print("\n🎨 HeroUI (Numeric Scale System):")
|
|
print(" Uses: --heroui-primary-{50-900}")
|
|
print(" Pattern: Full color scales with 10 values each")
|
|
print(" Granularity: HIGH - precise control over each shade")
|
|
|
|
print("\n🔲 shadcn (Semantic System):")
|
|
print(" Uses: --primary, --primary-foreground")
|
|
print(" Pattern: Semantic pairs (color + contrast)")
|
|
print(" Granularity: LOW - headless, no scales")
|
|
|
|
print("\n📐 DSS Canonical (Target):")
|
|
print(" Uses: color.primary.{50-900}")
|
|
print(" Result: Unified scale with both sources merged")
|
|
|
|
return result
|
|
|
|
|
|
async def demonstrate_merge_with_legacy():
|
|
"""
|
|
CASE: Merge legacy corporate tokens with modern DSS structure.
|
|
|
|
Shows how messy legacy code gets normalized.
|
|
"""
|
|
print("\n" + "="*70)
|
|
print("MERGE CASE: Legacy Corporate → DSS Canonical")
|
|
print("="*70)
|
|
|
|
css_source = CSSTokenSource()
|
|
|
|
# Ingest legacy tokens
|
|
legacy_collection = await css_source.extract(LEGACY_CORPORATE_TOKENS)
|
|
|
|
print(f"\n📥 Legacy tokens extracted: {len(legacy_collection.tokens)}")
|
|
|
|
# Show the chaos
|
|
print("\n🔴 LEGACY TOKEN NAMING CHAOS:")
|
|
for token in legacy_collection.tokens[:8]:
|
|
print(f" {token.original_name} → {token.normalize_name()}")
|
|
|
|
# Get translation dictionary
|
|
translation = create_legacy_translation()
|
|
|
|
print("\n🔄 TRANSLATION DICTIONARY MAPPINGS:")
|
|
for legacy, dss in list(translation["mappings"]["tokens"].items())[:6]:
|
|
print(f" {legacy} → {dss}")
|
|
|
|
print("\n✅ RESULT: Unified DSS canonical tokens")
|
|
print(" All naming conventions normalized")
|
|
print(" Custom brand colors isolated in namespace")
|
|
|
|
return legacy_collection
|
|
|
|
|
|
async def demonstrate_conflict_strategies():
|
|
"""
|
|
CASE: Show different merge strategies and their outcomes.
|
|
"""
|
|
print("\n" + "="*70)
|
|
print("MERGE STRATEGIES COMPARISON")
|
|
print("="*70)
|
|
|
|
css_source = CSSTokenSource()
|
|
|
|
# Create conflicting tokens
|
|
source_a = """
|
|
:root {
|
|
--primary: #3B82F6;
|
|
--spacing-md: 16px;
|
|
}
|
|
"""
|
|
|
|
source_b = """
|
|
:root {
|
|
--primary: #2563EB;
|
|
--spacing-md: 20px;
|
|
}
|
|
"""
|
|
|
|
collection_a = await css_source.extract(source_a)
|
|
collection_b = await css_source.extract(source_b)
|
|
|
|
strategies = [
|
|
(MergeStrategy.FIRST, "Keep first occurrence"),
|
|
(MergeStrategy.LAST, "Use last (override)"),
|
|
(MergeStrategy.PREFER_SPECIFIC, "Prefer concrete values"),
|
|
(MergeStrategy.MERGE_METADATA, "Merge metadata, use latest value"),
|
|
]
|
|
|
|
for strategy, description in strategies:
|
|
merger = TokenMerger(strategy=strategy)
|
|
result = merger.merge([collection_a, collection_b])
|
|
|
|
primary_token = next(
|
|
(t for t in result.collection.tokens if 'primary' in t.name.lower()),
|
|
None
|
|
)
|
|
|
|
print(f"\n📋 {strategy.value}: {description}")
|
|
if primary_token:
|
|
print(f" --primary result: {primary_token.value}")
|
|
if result.conflicts:
|
|
print(f" Resolution: {result.conflicts[0].resolution}")
|
|
|
|
|
|
async def main():
|
|
"""Run all merge demonstrations."""
|
|
print("\n" + "="*70)
|
|
print("DSS MERGE CASE EXAMPLES")
|
|
print("Demonstrating Multi-Source Token Ingestion")
|
|
print("="*70)
|
|
|
|
# Run demonstrations
|
|
await demonstrate_merge_heroui_shadcn()
|
|
await demonstrate_merge_with_legacy()
|
|
await demonstrate_conflict_strategies()
|
|
|
|
# Summary
|
|
print("\n" + "="*70)
|
|
print("SUMMARY: ATOMIC STRUCTURE DIFFERENCES")
|
|
print("="*70)
|
|
|
|
print("""
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ ATOMIC STRUCTURE COMPARISON │
|
|
├─────────────────┬──────────────────────┬────────────────────────────┤
|
|
│ Feature │ HeroUI │ shadcn │
|
|
├─────────────────┼──────────────────────┼────────────────────────────┤
|
|
│ Color System │ Numeric scales │ Semantic pairs │
|
|
│ │ (50-900) │ (primary/foreground) │
|
|
├─────────────────┼──────────────────────┼────────────────────────────┤
|
|
│ Granularity │ HIGH (10 shades) │ LOW (2 values) │
|
|
├─────────────────┼──────────────────────┼────────────────────────────┤
|
|
│ Naming │ --heroui-{cat}-{n} │ --{semantic} │
|
|
├─────────────────┼──────────────────────┼────────────────────────────┤
|
|
│ CSS Variables │ Prefixed │ Unprefixed │
|
|
├─────────────────┼──────────────────────┼────────────────────────────┤
|
|
│ Theme Layers │ content1-4 │ card, popover, muted │
|
|
├─────────────────┼──────────────────────┼────────────────────────────┤
|
|
│ Design Tokens │ Full W3C-like │ Minimal semantic │
|
|
├─────────────────┼──────────────────────┼────────────────────────────┤
|
|
│ DSS Mapping │ Direct 1:1 │ Expand to scales │
|
|
│ │ (strip prefix) │ (500 = default) │
|
|
└─────────────────┴──────────────────────┴────────────────────────────┘
|
|
""")
|
|
|
|
print("""
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ DSS TRANSLATION APPROACH │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ HeroUI │ │ shadcn │
|
|
│ --heroui- │ TRANSLATION │ --primary ──────┐ │
|
|
│ primary-500 ────┼────── LAYER ────────┼→ color.primary.500 ←───────┤
|
|
│ │ │ --primary-foreground ─────┤
|
|
│ --heroui- │ │ ↓ │
|
|
│ content1 ───────┼─────────────────────┼→ color.neutral.50 │
|
|
│ │ │ │
|
|
│ │ DSS CANONICAL │ │
|
|
│ │ (IMMUTABLE) │ │
|
|
│ │ │ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
""")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|