Tek kaynak (DTCG JSON) → tüm hedefler (CSS, Tailwind, iOS, Android, Figma). Style Dictionary ile build. Ad-hoc renk/boy değişikliği yapan PR'lar burada başlamalı; başka yerde tanımlanan token geçersiz kabul edilir.
{
"$schema": "https://design-tokens.org/schema.json",
"color": {
"primary": {
"500": { "$value": "#059669", "$type": "color",
"$description": "Brand primary · pasta yeşili. Light bg, dark text üzerinde AAA." },
"600": { "$value": "#047857", "$type": "color" }
},
"semantic": {
"text": {
"default": { "$value": "{color.neutral.900}", "$type": "color" },
"muted": { "$value": "{color.neutral.500}", "$type": "color" }
}
}
},
"space": {
"4": { "$value": "16px", "$type": "dimension" },
"6": { "$value": "24px", "$type": "dimension" }
},
"radius": {
"md": { "$value": "8px", "$type": "dimension" },
"lg": { "$value": "12px", "$type": "dimension" }
}
}
/* dist/css/tokens.css · auto-generated, do not edit */ :root { /* color · primary */ --nb-color-primary-500: #059669; --nb-color-primary-600: #047857; /* color · semantic */ --nb-color-text-default: #111827; --nb-color-text-muted: #6b7280; /* space */ --nb-space-4: 16px; --nb-space-6: 24px; /* radius */ --nb-radius-md: 8px; --nb-radius-lg: 12px; } [data-theme="dark"] { --nb-color-primary-500: #10b981; --nb-color-text-default: #fafafa; --nb-color-text-muted: #a1a1aa; }
// dist/js/tailwind.tokens.js module.exports = { theme: { extend: { colors: { primary: { 500: 'var(--nb-color-primary-500)', 600: 'var(--nb-color-primary-600)', }, text: { DEFAULT: 'var(--nb-color-text-default)', muted: 'var(--nb-color-text-muted)', }, }, spacing: { '4': 'var(--nb-space-4)', '6': 'var(--nb-space-6)' }, borderRadius: { md: 'var(--nb-radius-md)', lg: 'var(--nb-radius-lg)' }, }, }, };
// dist/ios/NBTokens.swift import SwiftUI enum NBColor { static let primary500 = Color("primary-500") static let textDefault = Color("text-default") static let textMuted = Color("text-muted") } enum NBSpace { static let s4: CGFloat = 16 static let s6: CGFloat = 24 } enum NBRadius { static let md: CGFloat = 8 static let lg: CGFloat = 12 }
// dist/android/Tokens.kt object NBColor { val primary500 = Color(0xFF059669) val textDefault = Color(0xFF111827) val textMuted = Color(0xFF6B7280) } object NBSpace { val s4 = 16.dp val s6 = 24.dp } object NBRadius { val md = 8.dp val lg = 12.dp }
// style-dictionary.config.js module.exports = { source: ['tokens/**/*.json'], platforms: { css: { transformGroup: 'css', buildPath: 'dist/css/', files: [{ destination: 'tokens.css', format: 'css/variables' }] }, tailwind:{ transformGroup: 'js', buildPath: 'dist/js/', files: [{ destination: 'tailwind.tokens.js', format: 'javascript/module' }] }, ios: { transformGroup: 'ios-swift', buildPath: 'dist/ios/', files: [{ destination: 'NBTokens.swift', format: 'ios-swift/class.swift' }] }, android: { transformGroup: 'compose', buildPath: 'dist/android/', files: [{ destination: 'Tokens.kt', format: 'compose/object' }] }, figma: { transformGroup: 'figma', buildPath: 'dist/figma/', files: [{ destination: 'tokens.json', format: 'json/nested' }] } } }; # package.json scripts # "tokens:build": "style-dictionary build" # "tokens:watch": "style-dictionary build --watch"
tokens/*.json'da. CSS, Swift, Kotlin'de hard-coded değer kabul edilmez (CI'da grep ile bloklanır).color.primary.500); export'ta platform-prefix (--nb-, NB) eklenir.text.default → neutral.900. Çift değer ("#111827") yasak; tek değişiklikte her iki yer güncellenmez.[data-theme="dark"] selector ile override; iOS'ta Color Asset (Any/Dark); Android'de qualifier.@nexberry/tokens). Major bump = breaking (token sil/yeniden adlandır), minor = ekle, patch = value değişimi.dist/figma/tokens.json'u import eder; designer'lar canlı senkronla çalışır.color: #059669, padding: 16px, borderRadius: 8 gibi magic value. Hep var(--nb-*), NBColor.*, NBSpace.*.