Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Projects/Shared/DesignSystem/Sources/Color/ShapeStyle+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,31 @@ public extension ShapeStyle where Self == Color {
static var statusError: Color { .init(hex: "C92D33") }
static var statusWarningAlpha: Color { .init(hex: "FFB400", alpha: 0.4) }
static var statusWarning: Color { .init(hex: "FFB400") }
// MARK: - Component
static var bedgeFilledBackgroundDefault: Color { .beige600 }
static var bedgeFilledBackgroundInverse: Color { .primary500 }
static var bedgeFilledTextDefault: Color { .primary500 }
static var bedgeFilledTextInverse: Color { .beige50 }
static var bedgeOutlineBackround: Color { .beige50 }
static var bedgeOutlineBorder: Color { .primary100 }
static var bedgeOutlineText: Color { .primary500 }
static var buttonPrimaryBackgroundDefault: Color { .primary500 }
static var buttonPrimaryBackgroundDisabled: Color { .primary200 }
static var buttonPrimaryBackgroundPressed: Color { .primary800 }
static var buttonPrimaryTextDefault: Color { .beige50 }
static var buttonSecondaryBackgroundDefault: Color { .beige300 }
static var buttonSecondaryBackgroundPressed: Color { .beige400 }
static var buttonSecondaryBorderDefault: Color { .beige600 }
static var buttonSecondaryBorderPressed: Color { .secondary500 }
static var buttonSecondaryTextDefault: Color { .neutral600 }
static var buttonSecondaryTextDisabled: Color { .neutral300 }
static var inputBorderActive: Color { .beige700 }
static var inputBorderDefault: Color { .beige600 }
static var inputBorderError: Color { .borderError }
static var inputSurfaceDefault: Color { .beige50 }
static var inputSurfaceDisabled: Color { .beige300 }
static var inputTextActive: Color { .neutral500 }
static var inputTextDefault: Color { .neutral300 }
static var inputTextError: Color { .statusError }

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// AUTO-GENERATED by Tools/TokenGenerator.swift — DO NOT EDIT
// Source: Projects/Shared/DesignSystem/Resources/Mode 1.tokens.json

import CoreGraphics

public extension CGFloat {

// MARK: - Component
static let buttonRadius: CGFloat = .`default`
}
52 changes: 26 additions & 26 deletions Projects/Shared/DesignSystem/Sources/UI/Token/ComponentToken.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,72 +7,72 @@ public enum ComponentToken {
public enum Bedge {
public enum Filled {
public enum Background {
public static var `default`: Color { .beige600 }
public static var inverse: Color { .primary500 }
public static var `default`: Color { .bedgeFilledBackgroundDefault }
public static var inverse: Color { .bedgeFilledBackgroundInverse }
}

public enum Text {
public static var `default`: Color { .primary500 }
public static var inverse: Color { .beige50 }
public static var `default`: Color { .bedgeFilledTextDefault }
public static var inverse: Color { .bedgeFilledTextInverse }
}
}

public enum Outline {
public static var backround: Color { .beige50 }
public static var border: Color { .primary100 }
public static var text: Color { .primary500 }
public static var backround: Color { .bedgeOutlineBackround }
public static var border: Color { .bedgeOutlineBorder }
public static var text: Color { .bedgeOutlineText }
}
}

public enum Button {
public static var radius: CGFloat { .`default` }
public static var radius: CGFloat { .buttonRadius }

public enum Primary {
public enum Background {
public static var `default`: Color { .primary500 }
public static var disabled: Color { .primary200 }
public static var pressed: Color { .primary800 }
public static var `default`: Color { .buttonPrimaryBackgroundDefault }
public static var disabled: Color { .buttonPrimaryBackgroundDisabled }
public static var pressed: Color { .buttonPrimaryBackgroundPressed }
}

public enum Text {
public static var `default`: Color { .beige50 }
public static var `default`: Color { .buttonPrimaryTextDefault }
}
}

public enum Secondary {
public enum Background {
public static var `default`: Color { .beige300 }
public static var pressed: Color { .beige400 }
public static var `default`: Color { .buttonSecondaryBackgroundDefault }
public static var pressed: Color { .buttonSecondaryBackgroundPressed }
}

public enum Border {
public static var `default`: Color { .beige600 }
public static var pressed: Color { .secondary500 }
public static var `default`: Color { .buttonSecondaryBorderDefault }
public static var pressed: Color { .buttonSecondaryBorderPressed }
}

public enum Text {
public static var `default`: Color { .neutral600 }
public static var disabled: Color { .neutral300 }
public static var `default`: Color { .buttonSecondaryTextDefault }
public static var disabled: Color { .buttonSecondaryTextDisabled }
}
}
}

public enum Input {
public enum Border {
public static var active: Color { .beige700 }
public static var `default`: Color { .beige600 }
public static var error: Color { .borderError }
public static var active: Color { .inputBorderActive }
public static var `default`: Color { .inputBorderDefault }
public static var error: Color { .inputBorderError }
}

public enum Surface {
public static var `default`: Color { .beige50 }
public static var disabled: Color { .beige300 }
public static var `default`: Color { .inputSurfaceDefault }
public static var disabled: Color { .inputSurfaceDisabled }
}

public enum Text {
public static var active: Color { .neutral500 }
public static var `default`: Color { .neutral300 }
public static var error: Color { .statusError }
public static var active: Color { .inputTextActive }
public static var `default`: Color { .inputTextDefault }
public static var error: Color { .inputTextError }
}
}
}
97 changes: 84 additions & 13 deletions Tools/TokenGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ let colorOut = "\(sourcesDir)/Color/ShapeStyle+.swift"
let cgfloatDir = "\(sourcesDir)/Extension/CGFloat"
let radiusOut = "\(cgfloatDir)/CGFloat+Radius+.swift"
let spacingOut = "\(cgfloatDir)/CGFloat+Spacing+.swift"
let componentOut = "\(sourcesDir)/UI/Token/ComponentToken.swift"
let componentOut = "\(sourcesDir)/UI/Token/ComponentToken.swift" // legacy nested file (deleted at end)
let componentNumberOut = "\(cgfloatDir)/CGFloat+Component+.swift"
try? FileManager.default.createDirectory(atPath: "\(sourcesDir)/UI/Token", withIntermediateDirectories: true)
try? FileManager.default.createDirectory(atPath: cgfloatDir, withIntermediateDirectories: true)

Expand Down Expand Up @@ -124,35 +125,80 @@ func resolveComponentNumber(_ node: [String: Any]) -> String? {
return nil
}

func walkComponent(_ node: [String: Any], indent: String, out: inout [String]) {
// Component subtree 를 flat path 로 풀어 ShapeStyle / CGFloat 확장에 직접 추가한다.
// Component.button.primary.background.default → buttonPrimaryBackgroundDefault
// Component.button.radius → buttonRadius
func walkComponentFlat(
_ node: [String: Any],
pathPrefix: [String],
colorLines: inout [String],
numberLines: inout [String]
) {
let keys = node.keys.sorted()
// 리프(컬러/숫자) 먼저, 그 다음 그룹(중첩 enum)
let leafKeys = keys.filter { (node[$0] as? [String: Any])?["$type"] != nil }
let groupKeys = keys.filter { (node[$0] as? [String: Any])?["$type"] == nil }
for key in leafKeys {
guard let child = node[key] as? [String: Any], let type = child["$type"] as? String else { continue }
let propName = flatPropertyName(pathPrefix + [key])
switch type {
case "color":
if let expr = resolveComponentColor(child) {
out.append("\(indent)public static var \(swiftKey(key)): Color { \(expr) }")
colorLines.append(" static var \(propName): Color { \(expr) }")
}
case "number":
if let expr = resolveComponentNumber(child) {
out.append("\(indent)public static var \(swiftKey(key)): CGFloat { \(expr) }")
numberLines.append(" static let \(propName): CGFloat = \(expr)")
}
default: continue
}
}
for key in groupKeys {
guard let child = node[key] as? [String: Any] else { continue }
walkComponentFlat(child, pathPrefix: pathPrefix + [key], colorLines: &colorLines, numberLines: &numberLines)
}
}

// Component subtree 의 nested ComponentToken enum. 값은 flat 정의를 forwarding 하므로
// source of truth 는 항상 ShapeStyle / CGFloat 확장 한 곳.
// public static var `default`: Color { .buttonPrimaryBackgroundDefault }
func walkComponentNested(
_ node: [String: Any],
pathPrefix: [String],
indent: String,
out: inout [String]
) {
let keys = node.keys.sorted()
let leafKeys = keys.filter { (node[$0] as? [String: Any])?["$type"] != nil }
let groupKeys = keys.filter { (node[$0] as? [String: Any])?["$type"] == nil }
for key in leafKeys {
guard let child = node[key] as? [String: Any], let type = child["$type"] as? String else { continue }
let flatName = flatPropertyName(pathPrefix + [key])
switch type {
case "color":
out.append("\(indent)public static var \(swiftKey(key)): Color { .\(flatName) }")
case "number":
out.append("\(indent)public static var \(swiftKey(key)): CGFloat { .\(flatName) }")
default: continue
}
}
for (i, key) in groupKeys.enumerated() {
guard let child = node[key] as? [String: Any] else { continue }
if i == 0, !leafKeys.isEmpty { out.append("") }
if i > 0 { out.append("") }
out.append("\(indent)public enum \(capitalizeFirst(key)) {")
walkComponent(child, indent: indent + " ", out: &out)
walkComponentNested(child, pathPrefix: pathPrefix + [key], indent: indent + " ", out: &out)
out.append("\(indent)}")
}
}

// ["button", "primary", "background", "default"] → "buttonPrimaryBackgroundDefault"
func flatPropertyName(_ segs: [String]) -> String {
guard let first = segs.first else { return "" }
let head = first.prefix(1).lowercased() + first.dropFirst()
let tail = segs.dropFirst().map(capitalizeFirst).joined()
return swiftKey(head + tail)
}

func capitalizeFirst(_ s: String) -> String {
s.prefix(1).uppercased() + s.dropFirst()
}
Expand Down Expand Up @@ -251,6 +297,17 @@ if let status = semantic["status"] as? [String: Any] {
}
}

// Component colors — flat ShapeStyle 확장에 직접 합쳐 ComponentToken 중첩 enum 을 폐기.
let component = json["Component"] as! [String: Any]
var componentColorLines: [String] = []
var componentNumberLines: [String] = []
walkComponentFlat(component, pathPrefix: [], colorLines: &componentColorLines, numberLines: &componentNumberLines)
if !componentColorLines.isEmpty {
lines.append(" // MARK: - Component")
lines.append(contentsOf: componentColorLines)
lines.append("")
}

lines.append("}")
lines.append("")
try writeFile(colorOut, lines.joined(separator: "\n"))
Expand Down Expand Up @@ -286,13 +343,27 @@ sLines.append("}")
sLines.append("")
try writeFile(spacingOut, sLines.joined(separator: "\n"))

// MARK: - Component
// MARK: - Component (numbers)

let component = json["Component"] as! [String: Any]
var compLines: [String] = [header, "", "import SwiftUI", "", "public enum ComponentToken {"]
walkComponent(component, indent: " ", out: &compLines)
compLines.append("}")
compLines.append("")
try writeFile(componentOut, compLines.joined(separator: "\n"))
// 색상은 위에서 ShapeStyle+.swift 에 이미 추가됨. 숫자만 CGFloat 확장으로 별도 출력.

if !componentNumberLines.isEmpty {
var cLines: [String] = [header, "", "import CoreGraphics", "", "public extension CGFloat {", ""]
cLines.append(" // MARK: - Component")
cLines.append(contentsOf: componentNumberLines)
cLines.append("}")
cLines.append("")
try writeFile(componentNumberOut, cLines.joined(separator: "\n"))
}

// MARK: - Component (nested ComponentToken)

// flat ShapeStyle / CGFloat 확장을 forwarding 하는 구조적 접근용 enum.
// 그룹 단위 캡처/자동완성 탐색에 사용. 값의 source of truth 는 flat 정의 한 곳.
var ctLines: [String] = [header, "", "import SwiftUI", "", "public enum ComponentToken {"]
walkComponentNested(component, pathPrefix: [], indent: " ", out: &ctLines)
ctLines.append("}")
ctLines.append("")
try writeFile(componentOut, ctLines.joined(separator: "\n"))

print("[token-gen] done.")
Loading