diff --git a/clients/macos/vellum-assistant/DesignSystem/Tokens/AnimationTokens.swift b/clients/macos/vellum-assistant/DesignSystem/Tokens/AnimationTokens.swift deleted file mode 100644 index 9aa69746fc0..00000000000 --- a/clients/macos/vellum-assistant/DesignSystem/Tokens/AnimationTokens.swift +++ /dev/null @@ -1,21 +0,0 @@ -import SwiftUI - -/// Animation presets. Use instead of raw Animation values. -enum VAnimation { - static let fast = Animation.easeOut(duration: 0.15) - static let standard = Animation.easeInOut(duration: 0.25) - static let slow = Animation.easeInOut(duration: 0.4) - static let spring = Animation.spring(response: 0.3, dampingFraction: 0.8) - - /// Gentle spring for panel open/close - static let panel = Animation.spring(response: 0.35, dampingFraction: 0.85) - - /// Bouncy spring for celebratory/attention-grabbing motion - static let bouncy = Animation.spring(response: 0.3, dampingFraction: 0.5) - - // MARK: - Durations (for use with withAnimation or explicit timing) - - static let durationFast: TimeInterval = 0.15 - static let durationStandard: TimeInterval = 0.25 - static let durationSlow: TimeInterval = 0.4 -} diff --git a/clients/macos/vellum-assistant/DesignSystem/Tokens/ColorTokens.swift b/clients/macos/vellum-assistant/DesignSystem/Tokens/ColorTokens.swift deleted file mode 100644 index fd2df17111d..00000000000 --- a/clients/macos/vellum-assistant/DesignSystem/Tokens/ColorTokens.swift +++ /dev/null @@ -1,126 +0,0 @@ -import SwiftUI - -// MARK: - Color Extension - -extension Color { - init(hex: UInt, alpha: Double = 1.0) { - self.init( - .sRGB, - red: Double((hex >> 16) & 0xFF) / 255, - green: Double((hex >> 8) & 0xFF) / 255, - blue: Double(hex & 0xFF) / 255, - opacity: alpha - ) - } -} - -// MARK: - Color Scales - -enum Slate { - static let _950 = Color(hex: 0x070D19) - static let _900 = Color(hex: 0x0F172A) - static let _800 = Color(hex: 0x1E293B) - static let _700 = Color(hex: 0x334155) - static let _600 = Color(hex: 0x475569) - static let _500 = Color(hex: 0x64748B) - static let _400 = Color(hex: 0x94A3B8) - static let _300 = Color(hex: 0xCBD5E1) - static let _200 = Color(hex: 0xE2E8F0) - static let _100 = Color(hex: 0xF1F5F9) - static let _50 = Color(hex: 0xF8FAFC) -} - -enum Emerald { - static let _950 = Color(hex: 0x073D2E) - static let _900 = Color(hex: 0x0A5843) - static let _800 = Color(hex: 0x0C7356) - static let _700 = Color(hex: 0x10906A) - static let _600 = Color(hex: 0x18B07A) - static let _500 = Color(hex: 0x38CF93) - static let _400 = Color(hex: 0x6EE7B5) - static let _300 = Color(hex: 0xA6F2D1) - static let _200 = Color(hex: 0xD2F9E8) - static let _100 = Color(hex: 0xECFDF5) -} - -enum Violet { - static let _950 = Color(hex: 0x321669) - static let _900 = Color(hex: 0x4A2390) - static let _800 = Color(hex: 0x5C2FB2) - static let _700 = Color(hex: 0x7240CC) - static let _600 = Color(hex: 0x8A5BE0) - static let _500 = Color(hex: 0x9878EA) - static let _400 = Color(hex: 0xB8A6F1) - static let _300 = Color(hex: 0xD4C8F7) - static let _200 = Color(hex: 0xE8E1FB) - static let _100 = Color(hex: 0xF4F0FD) -} - -enum Indigo { - static let _950 = Color(hex: 0x180F66) - static let _900 = Color(hex: 0x261A96) - static let _800 = Color(hex: 0x3525C4) - static let _700 = Color(hex: 0x4636E8) - static let _600 = Color(hex: 0x5B4EFF) - static let _500 = Color(hex: 0x7B6BFF) - static let _400 = Color(hex: 0x9488FF) - static let _300 = Color(hex: 0xB8B4FF) - static let _200 = Color(hex: 0xD8D8FF) - static let _100 = Color(hex: 0xEEEEFF) -} - -enum Rose { - static let _950 = Color(hex: 0x620F21) - static let _900 = Color(hex: 0x85142F) - static let _800 = Color(hex: 0xA8183E) - static let _700 = Color(hex: 0xD02050) - static let _600 = Color(hex: 0xE84060) - static let _500 = Color(hex: 0xF06A86) - static let _400 = Color(hex: 0xF99AAE) - static let _300 = Color(hex: 0xFCBFC9) - static let _200 = Color(hex: 0xFFE1E6) - static let _100 = Color(hex: 0xFFF1F3) -} - -enum Amber { - static let _950 = Color(hex: 0x5E3207) - static let _900 = Color(hex: 0x7A4409) - static let _800 = Color(hex: 0xA35E0C) - static let _700 = Color(hex: 0xC97C10) - static let _600 = Color(hex: 0xE8A020) - static let _500 = Color(hex: 0xFAC426) - static let _400 = Color(hex: 0xFDD94E) - static let _300 = Color(hex: 0xFEEC94) - static let _200 = Color(hex: 0xFEF7CD) - static let _100 = Color(hex: 0xFEFCE8) -} - -// MARK: - Semantic Color Tokens - -enum VColor { - // Backgrounds - static let background = Slate._950 - static let backgroundSubtle = Slate._800 - static let chatBackground = Slate._900 - static let surface = Slate._800 - static let surfaceBorder = Slate._700 - - // Text - static let textPrimary = Slate._50 - static let textSecondary = Slate._400 - static let textMuted = Slate._500 - - // Accent (violet = primary) - static let accent = Violet._600 - static let accentSubtle = Violet._100 - - // Onboarding accent (amber) - static let onboardingAccent = Amber._500 - static let onboardingAccentDark = Amber._600 - static let onboardingAccentDarker = Amber._800 - - // Status - static let success = Emerald._600 - static let error = Rose._600 - static let warning = Amber._600 -} diff --git a/clients/macos/vellum-assistant/DesignSystem/Tokens/MeadowTokens.swift b/clients/macos/vellum-assistant/DesignSystem/Tokens/MeadowTokens.swift deleted file mode 100644 index 40b4f371e6b..00000000000 --- a/clients/macos/vellum-assistant/DesignSystem/Tokens/MeadowTokens.swift +++ /dev/null @@ -1,28 +0,0 @@ -import SwiftUI - -/// Onboarding-specific design tokens for the Pixel Meadow theme. -enum Meadow { - // Panel - static let panelBackground = Slate._900.opacity(0.75) - static let panelBorder = Slate._700.opacity(0.4) - - // Egg glow - static let eggGlow = Amber._500 - static let eggGlowIntense = Amber._400 - static let crackLight = Amber._200 - - // Bottom caption - static let captionText = Color.white.opacity(0.5) - - // Pixel scaling factor - static let pixelScale: CGFloat = 2.0 - - // Art pixel size — each pixel-art cell renders as this many points - static let artPixelSize: CGFloat = 5.0 - - // Interview palette - static let avatarGradientStart = Violet._600 - static let avatarGradientEnd = Violet._400 - static let userBubbleGradientStart = Violet._600 - static let userBubbleGradientEnd = Violet._400 -} diff --git a/clients/macos/vellum-assistant/DesignSystem/Tokens/RadiusTokens.swift b/clients/macos/vellum-assistant/DesignSystem/Tokens/RadiusTokens.swift deleted file mode 100644 index 2c1bada66c3..00000000000 --- a/clients/macos/vellum-assistant/DesignSystem/Tokens/RadiusTokens.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Foundation - -/// Corner radius scale. Use `VRadius.pill` for capsule shapes. -enum VRadius { - static let xs: CGFloat = 2 - static let sm: CGFloat = 4 - static let md: CGFloat = 8 - static let lg: CGFloat = 12 - static let xl: CGFloat = 16 - - /// Use for fully rounded pill/capsule shapes - static let pill: CGFloat = 999 -} diff --git a/clients/macos/vellum-assistant/DesignSystem/Tokens/ShadowTokens.swift b/clients/macos/vellum-assistant/DesignSystem/Tokens/ShadowTokens.swift deleted file mode 100644 index 66158c6cb5a..00000000000 --- a/clients/macos/vellum-assistant/DesignSystem/Tokens/ShadowTokens.swift +++ /dev/null @@ -1,27 +0,0 @@ -import SwiftUI - -/// Shadow presets. Apply via `.vShadow(.md)` or `.shadow(color:radius:y:)`. -enum VShadow { - struct Definition { - let color: Color - let radius: CGFloat - let x: CGFloat - let y: CGFloat - } - - static let sm = Definition(color: .black.opacity(0.2), radius: 4, x: 0, y: 2) - static let md = Definition(color: .black.opacity(0.3), radius: 8, x: 0, y: 4) - static let lg = Definition(color: .black.opacity(0.4), radius: 16, x: 0, y: 8) - - /// Amber glow effect for brand elements (orb, highlights) - static let glow = Definition(color: Amber._500.opacity(0.3), radius: 12, x: 0, y: 0) - - /// Violet glow for accent elements (focused inputs, active buttons) - static let accentGlow = Definition(color: Violet._600.opacity(0.3), radius: 8, x: 0, y: 0) -} - -extension View { - func vShadow(_ definition: VShadow.Definition) -> some View { - shadow(color: definition.color, radius: definition.radius, x: definition.x, y: definition.y) - } -} diff --git a/clients/macos/vellum-assistant/DesignSystem/Tokens/SpacingTokens.swift b/clients/macos/vellum-assistant/DesignSystem/Tokens/SpacingTokens.swift deleted file mode 100644 index 29c1e85430f..00000000000 --- a/clients/macos/vellum-assistant/DesignSystem/Tokens/SpacingTokens.swift +++ /dev/null @@ -1,27 +0,0 @@ -import Foundation - -/// Spacing scale based on 4pt grid. -/// Usage: `.padding(VSpacing.lg)` or `.padding(.horizontal, VSpacing.xl)` -enum VSpacing { - static let xxs: CGFloat = 2 - static let xs: CGFloat = 4 - static let sm: CGFloat = 8 - static let md: CGFloat = 12 - static let lg: CGFloat = 16 - static let xl: CGFloat = 24 - static let xxl: CGFloat = 32 - static let xxxl: CGFloat = 48 - - // MARK: - Semantic Aliases - - /// Standard gap between inline elements (icons + text, etc.) - static let inline: CGFloat = sm - /// Standard content padding inside cards and panels - static let content: CGFloat = lg - /// Standard section gap between major UI blocks - static let section: CGFloat = xl - /// Standard window/page-level margin - static let page: CGFloat = xxl - /// Compact vertical padding for buttons - static let buttonV: CGFloat = 5.5 -} diff --git a/clients/macos/vellum-assistant/DesignSystem/Tokens/TypographyTokens.swift b/clients/macos/vellum-assistant/DesignSystem/Tokens/TypographyTokens.swift deleted file mode 100644 index 0e7ef552374..00000000000 --- a/clients/macos/vellum-assistant/DesignSystem/Tokens/TypographyTokens.swift +++ /dev/null @@ -1,58 +0,0 @@ -import AppKit -import SwiftUI - -/// Font presets for the app. Always use these instead of raw Font.system() calls. -/// -/// **Silkscreen** — pixelated bitmap font for headings and display text. -/// **DM Mono** — monospaced font for body/UI text. -enum VFont { - - /// DM Mono's default "f" has an exaggerated italic-style hook. - /// Stylistic Set 5 (ss05) provides a conventional "f" glyph. - private static func dmMono(_ name: String, size: CGFloat) -> Font { - guard let nsFont = NSFont(name: name, size: size) else { - return Font.custom(name, size: size) - } - let descriptor = nsFont.fontDescriptor.addingAttributes([ - .featureSettings: [[ - NSFontDescriptor.FeatureKey.typeIdentifier: kStylisticAlternativesType, - NSFontDescriptor.FeatureKey.selectorIdentifier: kStylisticAltFiveOnSelector, - ]] - ]) - return Font(NSFont(descriptor: descriptor, size: size) ?? nsFont) - } - // MARK: - Onboarding (Silkscreen pixel font) - - static let onboardingTitle = Font.custom("Silkscreen-Regular", size: 28) - static let onboardingSubtitle = Font.custom("Silkscreen-Regular", size: 15) - - // MARK: - Headings (Silkscreen) - // TODO: Clean up typography once we solidify the design system - we dont seem to use Bold - static let largeTitle = Font.custom("Silkscreen-Bold", size: 26) - static let title = Font.custom("Silkscreen-Bold", size: 22) - static let headline = Font.custom("Silkscreen-Bold", size: 13) - - // MARK: - Body / UI (DM Mono) - - static let body = dmMono("DMMono-Regular", size: 13) - static let bodyMedium = dmMono("DMMono-Medium", size: 13) - static let bodyBold = dmMono("DMMono-Medium", size: 13) - static let caption = dmMono("DMMono-Regular", size: 11) - static let captionMedium = dmMono("DMMono-Medium", size: 11) - static let small = dmMono("DMMono-Regular", size: 10) - - // MARK: - Specialized - - static let cardTitle = dmMono("DMMono-Medium", size: 17) - static let cardEmoji = Font.system(size: 32) - static let mono = dmMono("DMMono-Regular", size: 13) - static let monoSmall = dmMono("DMMono-Regular", size: 11) - - /// All-caps pixel display font (used for panel headers like "AGENT", "GENERATED CONTENT") - static let display = Font.custom("Silkscreen-Bold", size: 18) - static let panelTitle = Font.custom("Silkscreen-Regular", size: 24) - static let sectionTitle = Font.custom("Silkscreen-Regular", size: 18) - - /// Small Silkscreen label (used for thread tab names) - static let tabLabel = Font.custom("Silkscreen-Regular", size: 11) -} diff --git a/clients/macos/vellum-assistant/Features/Ambient/AmbientSuggestionWindow.swift b/clients/macos/vellum-assistant/Features/Ambient/AmbientSuggestionWindow.swift index 1135b4dee88..0d452dc9cdf 100644 --- a/clients/macos/vellum-assistant/Features/Ambient/AmbientSuggestionWindow.swift +++ b/clients/macos/vellum-assistant/Features/Ambient/AmbientSuggestionWindow.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import AppKit import SwiftUI diff --git a/clients/macos/vellum-assistant/Features/Ambient/InsightNotificationWindow.swift b/clients/macos/vellum-assistant/Features/Ambient/InsightNotificationWindow.swift index e01b2b69f6c..f135b890d4b 100644 --- a/clients/macos/vellum-assistant/Features/Ambient/InsightNotificationWindow.swift +++ b/clients/macos/vellum-assistant/Features/Ambient/InsightNotificationWindow.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import AppKit import SwiftUI diff --git a/clients/macos/vellum-assistant/Features/Chat/SkillInvocationChip.swift b/clients/macos/vellum-assistant/Features/Chat/SkillInvocationChip.swift index 3e6eb10ff33..07286491b3c 100644 --- a/clients/macos/vellum-assistant/Features/Chat/SkillInvocationChip.swift +++ b/clients/macos/vellum-assistant/Features/Chat/SkillInvocationChip.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct SkillInvocationChip: View { diff --git a/clients/macos/vellum-assistant/Features/MainWindow/NavigationToolbar.swift b/clients/macos/vellum-assistant/Features/MainWindow/NavigationToolbar.swift index 907d25331d0..849fe666c77 100644 --- a/clients/macos/vellum-assistant/Features/MainWindow/NavigationToolbar.swift +++ b/clients/macos/vellum-assistant/Features/MainWindow/NavigationToolbar.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct NavigationToolbar: View { diff --git a/clients/macos/vellum-assistant/Features/MainWindow/Panels/DebugPanel.swift b/clients/macos/vellum-assistant/Features/MainWindow/Panels/DebugPanel.swift index 17958e404f6..603fd2e2db1 100644 --- a/clients/macos/vellum-assistant/Features/MainWindow/Panels/DebugPanel.swift +++ b/clients/macos/vellum-assistant/Features/MainWindow/Panels/DebugPanel.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct DebugPanel: View { diff --git a/clients/macos/vellum-assistant/Features/MainWindow/Panels/DirectoryPanel.swift b/clients/macos/vellum-assistant/Features/MainWindow/Panels/DirectoryPanel.swift index 6394f13e326..98a12b109a4 100644 --- a/clients/macos/vellum-assistant/Features/MainWindow/Panels/DirectoryPanel.swift +++ b/clients/macos/vellum-assistant/Features/MainWindow/Panels/DirectoryPanel.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct DirectoryPanel: View { diff --git a/clients/macos/vellum-assistant/Features/MainWindow/Panels/DoctorPanel.swift b/clients/macos/vellum-assistant/Features/MainWindow/Panels/DoctorPanel.swift index d4d4fcdf012..ace6c742e10 100644 --- a/clients/macos/vellum-assistant/Features/MainWindow/Panels/DoctorPanel.swift +++ b/clients/macos/vellum-assistant/Features/MainWindow/Panels/DoctorPanel.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct DoctorPanel: View { diff --git a/clients/macos/vellum-assistant/Features/MainWindow/ThreadTab.swift b/clients/macos/vellum-assistant/Features/MainWindow/ThreadTab.swift index 89f8c607169..c8118725c6c 100644 --- a/clients/macos/vellum-assistant/Features/MainWindow/ThreadTab.swift +++ b/clients/macos/vellum-assistant/Features/MainWindow/ThreadTab.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI /// A thread tab component that renders a tab with thread-specific styling. diff --git a/clients/macos/vellum-assistant/Features/MainWindow/ThreadTabBar.swift b/clients/macos/vellum-assistant/Features/MainWindow/ThreadTabBar.swift index c7849d56129..3075b447501 100644 --- a/clients/macos/vellum-assistant/Features/MainWindow/ThreadTabBar.swift +++ b/clients/macos/vellum-assistant/Features/MainWindow/ThreadTabBar.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct ThreadTabBar: View { diff --git a/clients/macos/vellum-assistant/Features/Onboarding/AccessibilityPermissionStepView.swift b/clients/macos/vellum-assistant/Features/Onboarding/AccessibilityPermissionStepView.swift index ee9c2430063..2ff9e923332 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/AccessibilityPermissionStepView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/AccessibilityPermissionStepView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI @MainActor diff --git a/clients/macos/vellum-assistant/Features/Onboarding/AliveStepView.swift b/clients/macos/vellum-assistant/Features/Onboarding/AliveStepView.swift index 108364f2203..df85b632b9b 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/AliveStepView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/AliveStepView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI @MainActor diff --git a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/CapabilitiesBriefingView.swift b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/CapabilitiesBriefingView.swift index 970e483b38f..5237b5cbf8c 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/CapabilitiesBriefingView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/CapabilitiesBriefingView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI @MainActor diff --git a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/CapabilitiesModalView.swift b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/CapabilitiesModalView.swift index 7308c88ac33..4bcdd7b8df5 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/CapabilitiesModalView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/CapabilitiesModalView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI @MainActor diff --git a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/FirstMeetingEggView.swift b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/FirstMeetingEggView.swift index 77de0e29343..1adff98a375 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/FirstMeetingEggView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/FirstMeetingEggView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI @MainActor diff --git a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/FirstMeetingHatchView.swift b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/FirstMeetingHatchView.swift index 5ce98089eee..d3cd99f5ea7 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/FirstMeetingHatchView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/FirstMeetingHatchView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SpriteKit import SwiftUI diff --git a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/JITPermissionManager.swift b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/JITPermissionManager.swift index 46e3ee94fa2..92f7a57148e 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/JITPermissionManager.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/JITPermissionManager.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import Foundation import Speech import SwiftUI diff --git a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/JITPermissionView.swift b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/JITPermissionView.swift index 32bd55aa224..e46d93c1430 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/JITPermissionView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/JITPermissionView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI @MainActor diff --git a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/ObservationModeView.swift b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/ObservationModeView.swift index 4d4283148b4..747836311c7 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/ObservationModeView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/ObservationModeView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI /// Observation mode pitch view — step 4 of the first meeting flow. diff --git a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/ObservationSessionView.swift b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/ObservationSessionView.swift index f5e09e536c2..d4d8b2ec313 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/ObservationSessionView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/ObservationSessionView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import Combine import SwiftUI diff --git a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/ObservationSummaryView.swift b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/ObservationSummaryView.swift index 1c878877f70..0fdac2203d8 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/ObservationSummaryView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/FirstMeeting/ObservationSummaryView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI /// Post-observation summary view — shown after the observation session completes. diff --git a/clients/macos/vellum-assistant/Features/Onboarding/FnKeyStepView.swift b/clients/macos/vellum-assistant/Features/Onboarding/FnKeyStepView.swift index b968cdedd7e..af844e15639 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/FnKeyStepView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/FnKeyStepView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI @MainActor diff --git a/clients/macos/vellum-assistant/Features/Onboarding/Hatch/CreatureView.swift b/clients/macos/vellum-assistant/Features/Onboarding/Hatch/CreatureView.swift index c1332a8e670..313766fb6e4 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/Hatch/CreatureView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/Hatch/CreatureView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI /// The revealed creature (purple dino) with spring entrance and breathing animation. diff --git a/clients/macos/vellum-assistant/Features/Onboarding/Hatch/EggHatchScene.swift b/clients/macos/vellum-assistant/Features/Onboarding/Hatch/EggHatchScene.swift index 4f6fe6b61aa..e7b1529d441 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/Hatch/EggHatchScene.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/Hatch/EggHatchScene.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SpriteKit import AppKit diff --git a/clients/macos/vellum-assistant/Features/Onboarding/Hatch/PixelArtData.swift b/clients/macos/vellum-assistant/Features/Onboarding/Hatch/PixelArtData.swift index 09b15428393..5aeac9aecfe 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/Hatch/PixelArtData.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/Hatch/PixelArtData.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import Foundation /// Static pixel-art grids for egg and dino, stored as 2D arrays of UInt32? hex colors. diff --git a/clients/macos/vellum-assistant/Features/Onboarding/Interview/InterviewChatView.swift b/clients/macos/vellum-assistant/Features/Onboarding/Interview/InterviewChatView.swift index 45c0ea3f601..d0c590ab628 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/Interview/InterviewChatView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/Interview/InterviewChatView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct InterviewChatView: View { diff --git a/clients/macos/vellum-assistant/Features/Onboarding/MeadowBackground.swift b/clients/macos/vellum-assistant/Features/Onboarding/MeadowBackground.swift index 65d12f498ef..0b34dd2d7b9 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/MeadowBackground.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/MeadowBackground.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI /// Full-bleed pixel art meadow background for onboarding. diff --git a/clients/macos/vellum-assistant/Features/Onboarding/NamingStepView.swift b/clients/macos/vellum-assistant/Features/Onboarding/NamingStepView.swift index 0b92e2a9504..67f2444a6df 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/NamingStepView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/NamingStepView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI @MainActor diff --git a/clients/macos/vellum-assistant/Features/Onboarding/OnboardingButton.swift b/clients/macos/vellum-assistant/Features/Onboarding/OnboardingButton.swift index 3f0ffb33329..5b690eb19fb 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/OnboardingButton.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/OnboardingButton.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI enum OnboardingButtonStyle { diff --git a/clients/macos/vellum-assistant/Features/Onboarding/OnboardingPanel.swift b/clients/macos/vellum-assistant/Features/Onboarding/OnboardingPanel.swift index 8ee48e00733..8fb83060352 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/OnboardingPanel.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/OnboardingPanel.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI /// Compact dark frosted glass card for onboarding step content. diff --git a/clients/macos/vellum-assistant/Features/Onboarding/OnboardingProgressDots.swift b/clients/macos/vellum-assistant/Features/Onboarding/OnboardingProgressDots.swift index a5043f94973..454ce470287 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/OnboardingProgressDots.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/OnboardingProgressDots.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI /// Five cumulative progress dots for the onboarding flow. diff --git a/clients/macos/vellum-assistant/Features/Onboarding/ReactionBubble.swift b/clients/macos/vellum-assistant/Features/Onboarding/ReactionBubble.swift index 7d47eb6df36..2bfc446433c 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/ReactionBubble.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/ReactionBubble.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct ReactionBubble: View { diff --git a/clients/macos/vellum-assistant/Features/Onboarding/ScreenPermissionStepView.swift b/clients/macos/vellum-assistant/Features/Onboarding/ScreenPermissionStepView.swift index 4452c598eec..0cee5e123d9 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/ScreenPermissionStepView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/ScreenPermissionStepView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI @MainActor diff --git a/clients/macos/vellum-assistant/Features/Onboarding/SpeechPermissionStepView.swift b/clients/macos/vellum-assistant/Features/Onboarding/SpeechPermissionStepView.swift index 9f7c4328d3b..d8f688417b5 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/SpeechPermissionStepView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/SpeechPermissionStepView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import Speech import SwiftUI diff --git a/clients/macos/vellum-assistant/Features/Onboarding/TypewriterText.swift b/clients/macos/vellum-assistant/Features/Onboarding/TypewriterText.swift index 9b99141c1d7..865166fbb76 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/TypewriterText.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/TypewriterText.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct TypewriterText: View { diff --git a/clients/macos/vellum-assistant/Features/Onboarding/WakeUpStepView.swift b/clients/macos/vellum-assistant/Features/Onboarding/WakeUpStepView.swift index 03910d67b82..d747b3d2b26 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/WakeUpStepView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/WakeUpStepView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI @MainActor diff --git a/clients/macos/vellum-assistant/Features/Session/ConfirmationView.swift b/clients/macos/vellum-assistant/Features/Session/ConfirmationView.swift index f17f6ca0f2f..bb47ae603b9 100644 --- a/clients/macos/vellum-assistant/Features/Session/ConfirmationView.swift +++ b/clients/macos/vellum-assistant/Features/Session/ConfirmationView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct ConfirmationView: View { diff --git a/clients/macos/vellum-assistant/Features/Session/SessionOverlayView.swift b/clients/macos/vellum-assistant/Features/Session/SessionOverlayView.swift index cc6c3667244..80018219985 100644 --- a/clients/macos/vellum-assistant/Features/Session/SessionOverlayView.swift +++ b/clients/macos/vellum-assistant/Features/Session/SessionOverlayView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct SessionOverlayView: View { diff --git a/clients/macos/vellum-assistant/Features/Session/TextResponseView.swift b/clients/macos/vellum-assistant/Features/Session/TextResponseView.swift index 872f9757371..06d497a6b67 100644 --- a/clients/macos/vellum-assistant/Features/Session/TextResponseView.swift +++ b/clients/macos/vellum-assistant/Features/Session/TextResponseView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct TextResponseView: View { diff --git a/clients/macos/vellum-assistant/Features/Sharing/BundleConfirmationView.swift b/clients/macos/vellum-assistant/Features/Sharing/BundleConfirmationView.swift index ec7ae31e9b9..effb1046c49 100644 --- a/clients/macos/vellum-assistant/Features/Sharing/BundleConfirmationView.swift +++ b/clients/macos/vellum-assistant/Features/Sharing/BundleConfirmationView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct BundleConfirmationView: View { diff --git a/clients/macos/vellum-assistant/Features/Sharing/BundleConfirmationWindow.swift b/clients/macos/vellum-assistant/Features/Sharing/BundleConfirmationWindow.swift index 4f75096b22d..6bebb8f573a 100644 --- a/clients/macos/vellum-assistant/Features/Sharing/BundleConfirmationWindow.swift +++ b/clients/macos/vellum-assistant/Features/Sharing/BundleConfirmationWindow.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import AppKit import SwiftUI diff --git a/clients/macos/vellum-assistant/Features/Surfaces/CardSurfaceView.swift b/clients/macos/vellum-assistant/Features/Surfaces/CardSurfaceView.swift index 180d9075be9..3d738e679ab 100644 --- a/clients/macos/vellum-assistant/Features/Surfaces/CardSurfaceView.swift +++ b/clients/macos/vellum-assistant/Features/Surfaces/CardSurfaceView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct CardSurfaceView: View { diff --git a/clients/macos/vellum-assistant/Features/Surfaces/ConfirmationSurfaceView.swift b/clients/macos/vellum-assistant/Features/Surfaces/ConfirmationSurfaceView.swift index 8e8b385d30f..95511039578 100644 --- a/clients/macos/vellum-assistant/Features/Surfaces/ConfirmationSurfaceView.swift +++ b/clients/macos/vellum-assistant/Features/Surfaces/ConfirmationSurfaceView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct ConfirmationSurfaceView: View { diff --git a/clients/macos/vellum-assistant/Features/Surfaces/FileUploadSurfaceView.swift b/clients/macos/vellum-assistant/Features/Surfaces/FileUploadSurfaceView.swift index 26b4e9df4ad..db11badaa15 100644 --- a/clients/macos/vellum-assistant/Features/Surfaces/FileUploadSurfaceView.swift +++ b/clients/macos/vellum-assistant/Features/Surfaces/FileUploadSurfaceView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI import UniformTypeIdentifiers diff --git a/clients/macos/vellum-assistant/Features/Surfaces/FormSurfaceView.swift b/clients/macos/vellum-assistant/Features/Surfaces/FormSurfaceView.swift index b6c7e78b2e3..e36174da566 100644 --- a/clients/macos/vellum-assistant/Features/Surfaces/FormSurfaceView.swift +++ b/clients/macos/vellum-assistant/Features/Surfaces/FormSurfaceView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct FormSurfaceView: View { diff --git a/clients/macos/vellum-assistant/Features/Surfaces/ListSurfaceView.swift b/clients/macos/vellum-assistant/Features/Surfaces/ListSurfaceView.swift index 9487420b617..895ddf08507 100644 --- a/clients/macos/vellum-assistant/Features/Surfaces/ListSurfaceView.swift +++ b/clients/macos/vellum-assistant/Features/Surfaces/ListSurfaceView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct ListSurfaceView: View { diff --git a/clients/macos/vellum-assistant/Features/Surfaces/SurfaceContainerView.swift b/clients/macos/vellum-assistant/Features/Surfaces/SurfaceContainerView.swift index 3564109fb22..04638a32387 100644 --- a/clients/macos/vellum-assistant/Features/Surfaces/SurfaceContainerView.swift +++ b/clients/macos/vellum-assistant/Features/Surfaces/SurfaceContainerView.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import SwiftUI struct SurfaceContainerView: View { diff --git a/clients/macos/vellum-assistant/Features/Voice/VoiceTranscriptionWindow.swift b/clients/macos/vellum-assistant/Features/Voice/VoiceTranscriptionWindow.swift index 2ae6b2b00cb..8d179bbd63c 100644 --- a/clients/macos/vellum-assistant/Features/Voice/VoiceTranscriptionWindow.swift +++ b/clients/macos/vellum-assistant/Features/Voice/VoiceTranscriptionWindow.swift @@ -1,3 +1,4 @@ +import VellumAssistantShared import AppKit import Combine import SwiftUI diff --git a/clients/macos/vellum-assistant/DesignSystem/Components/Display/PixelBorderShape.swift b/clients/shared/DesignSystem/Components/Display/PixelBorderShape.swift similarity index 89% rename from clients/macos/vellum-assistant/DesignSystem/Components/Display/PixelBorderShape.swift rename to clients/shared/DesignSystem/Components/Display/PixelBorderShape.swift index 12f8bb41f01..f77a1411908 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Components/Display/PixelBorderShape.swift +++ b/clients/shared/DesignSystem/Components/Display/PixelBorderShape.swift @@ -1,16 +1,16 @@ import SwiftUI /// Shared pixel-step border used by retro chips and badges across surfaces. -struct PixelBorderShape: Shape { - let pixelSize: CGFloat - let cornerSteps: Int +public struct PixelBorderShape: Shape { + public let pixelSize: CGFloat + public let cornerSteps: Int - init(pixelSize: CGFloat = 3, cornerSteps: Int = 3) { + public init(pixelSize: CGFloat = 3, cornerSteps: Int = 3) { self.pixelSize = pixelSize self.cornerSteps = cornerSteps } - func path(in rect: CGRect) -> Path { + public func path(in rect: CGRect) -> Path { let step = pixelSize let corners = cornerSteps let width = rect.width diff --git a/clients/macos/vellum-assistant/DesignSystem/Components/Display/VCard.swift b/clients/shared/DesignSystem/Components/Display/VCard.swift similarity index 73% rename from clients/macos/vellum-assistant/DesignSystem/Components/Display/VCard.swift rename to clients/shared/DesignSystem/Components/Display/VCard.swift index 601b88b3dc3..59f4cb55b78 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Components/Display/VCard.swift +++ b/clients/shared/DesignSystem/Components/Display/VCard.swift @@ -1,10 +1,15 @@ import SwiftUI -struct VCard: View { - var padding: CGFloat = VSpacing.xl - @ViewBuilder let content: () -> Content +public struct VCard: View { + public var padding: CGFloat = VSpacing.xl + @ViewBuilder public let content: () -> Content - var body: some View { + public init(padding: CGFloat = VSpacing.xl, @ViewBuilder content: @escaping () -> Content) { + self.padding = padding + self.content = content + } + + public var body: some View { content() .padding(padding) .background(VColor.surface) diff --git a/clients/macos/vellum-assistant/DesignSystem/Components/Display/VEmptyState.swift b/clients/shared/DesignSystem/Components/Display/VEmptyState.swift similarity index 78% rename from clients/macos/vellum-assistant/DesignSystem/Components/Display/VEmptyState.swift rename to clients/shared/DesignSystem/Components/Display/VEmptyState.swift index f5afbe52897..3a9200b58b6 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Components/Display/VEmptyState.swift +++ b/clients/shared/DesignSystem/Components/Display/VEmptyState.swift @@ -1,11 +1,17 @@ import SwiftUI -struct VEmptyState: View { - let title: String - var subtitle: String? = nil - var icon: String? = nil +public struct VEmptyState: View { + public let title: String + public var subtitle: String? = nil + public var icon: String? = nil - var body: some View { + public init(title: String, subtitle: String? = nil, icon: String? = nil) { + self.title = title + self.subtitle = subtitle + self.icon = icon + } + + public var body: some View { VStack(spacing: VSpacing.lg) { if let icon = icon { Image(systemName: icon) diff --git a/clients/macos/vellum-assistant/DesignSystem/Components/Layout/VSidePanel.swift b/clients/shared/DesignSystem/Components/Layout/VSidePanel.swift similarity index 83% rename from clients/macos/vellum-assistant/DesignSystem/Components/Layout/VSidePanel.swift rename to clients/shared/DesignSystem/Components/Layout/VSidePanel.swift index 31b2a7c50b6..4d8fb24cc41 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Components/Layout/VSidePanel.swift +++ b/clients/shared/DesignSystem/Components/Layout/VSidePanel.swift @@ -1,12 +1,19 @@ import SwiftUI -struct VSidePanel: View { - let title: String - var onClose: (() -> Void)? = nil - @ViewBuilder let pinnedContent: () -> PinnedContent - @ViewBuilder let content: () -> Content +public struct VSidePanel: View { + public let title: String + public var onClose: (() -> Void)? = nil + @ViewBuilder public let pinnedContent: () -> PinnedContent + @ViewBuilder public let content: () -> Content - var body: some View { + public init(title: String, onClose: (() -> Void)? = nil, @ViewBuilder pinnedContent: @escaping () -> PinnedContent, @ViewBuilder content: @escaping () -> Content) { + self.title = title + self.onClose = onClose + self.pinnedContent = pinnedContent + self.content = content + } + + public var body: some View { VStack(alignment: .leading, spacing: 0) { // Header HStack { @@ -46,7 +53,7 @@ struct VSidePanel: View { } // Backward-compatible init (no pinnedContent) -extension VSidePanel where PinnedContent == EmptyView { +public extension VSidePanel where PinnedContent == EmptyView { init(title: String, onClose: (() -> Void)? = nil, @ViewBuilder content: @escaping () -> Content) { self.init(title: title, onClose: onClose, diff --git a/clients/macos/vellum-assistant/DesignSystem/Components/Layout/VSplitView.swift b/clients/shared/DesignSystem/Components/Layout/VSplitView.swift similarity index 85% rename from clients/macos/vellum-assistant/DesignSystem/Components/Layout/VSplitView.swift rename to clients/shared/DesignSystem/Components/Layout/VSplitView.swift index 2201dc09271..8c0843cc888 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Components/Layout/VSplitView.swift +++ b/clients/shared/DesignSystem/Components/Layout/VSplitView.swift @@ -1,12 +1,12 @@ import SwiftUI -struct VSplitView: View { - let main: Main - let panel: Panel? - var panelWidth: CGFloat = 320 - var showPanel: Bool = false +public struct VSplitView: View { + public let main: Main + public let panel: Panel? + public var panelWidth: CGFloat = 320 + public var showPanel: Bool = false - var body: some View { + public var body: some View { HStack(spacing: 0) { main .frame(maxWidth: .infinity, maxHeight: .infinity) @@ -23,7 +23,7 @@ struct VSplitView: View { .animation(VAnimation.standard, value: showPanel) } - init( + public init( panelWidth: CGFloat = 320, showPanel: Bool = false, @ViewBuilder main: () -> Main, @@ -36,7 +36,7 @@ struct VSplitView: View { } } -extension VSplitView where Panel == EmptyView { +public extension VSplitView where Panel == EmptyView { init( @ViewBuilder main: () -> Main ) { diff --git a/clients/macos/vellum-assistant/DesignSystem/Components/Layout/VToolbar.swift b/clients/shared/DesignSystem/Components/Layout/VToolbar.swift similarity index 74% rename from clients/macos/vellum-assistant/DesignSystem/Components/Layout/VToolbar.swift rename to clients/shared/DesignSystem/Components/Layout/VToolbar.swift index f693c30b0ef..c4fbe602704 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Components/Layout/VToolbar.swift +++ b/clients/shared/DesignSystem/Components/Layout/VToolbar.swift @@ -1,9 +1,13 @@ import SwiftUI -struct VToolbar: View { - @ViewBuilder let content: () -> Content +public struct VToolbar: View { + @ViewBuilder public let content: () -> Content - var body: some View { + public init(@ViewBuilder content: @escaping () -> Content) { + self.content = content + } + + public var body: some View { HStack(spacing: VSpacing.sm) { content() } diff --git a/clients/macos/vellum-assistant/DesignSystem/Components/Navigation/VSegmentedControl.swift b/clients/shared/DesignSystem/Components/Navigation/VSegmentedControl.swift similarity index 85% rename from clients/macos/vellum-assistant/DesignSystem/Components/Navigation/VSegmentedControl.swift rename to clients/shared/DesignSystem/Components/Navigation/VSegmentedControl.swift index 939f914ec87..4be805c36b4 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Components/Navigation/VSegmentedControl.swift +++ b/clients/shared/DesignSystem/Components/Navigation/VSegmentedControl.swift @@ -1,10 +1,15 @@ import SwiftUI -struct VSegmentedControl: View { - let items: [String] - @Binding var selection: Int +public struct VSegmentedControl: View { + public let items: [String] + @Binding public var selection: Int - var body: some View { + public init(items: [String], selection: Binding) { + self.items = items + self._selection = selection + } + + public var body: some View { HStack(spacing: 0) { ForEach(items.indices, id: \.self) { index in Button(action: { selection = index }) { diff --git a/clients/macos/vellum-assistant/DesignSystem/Components/Navigation/VTabBar.swift b/clients/shared/DesignSystem/Components/Navigation/VTabBar.swift similarity index 73% rename from clients/macos/vellum-assistant/DesignSystem/Components/Navigation/VTabBar.swift rename to clients/shared/DesignSystem/Components/Navigation/VTabBar.swift index d1bcb53a858..9f36770cf42 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Components/Navigation/VTabBar.swift +++ b/clients/shared/DesignSystem/Components/Navigation/VTabBar.swift @@ -1,9 +1,13 @@ import SwiftUI -struct VTabBar: View { - @ViewBuilder let content: () -> Content +public struct VTabBar: View { + @ViewBuilder public let content: () -> Content - var body: some View { + public init(@ViewBuilder content: @escaping () -> Content) { + self.content = content + } + + public var body: some View { ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: VSpacing.xs) { content() diff --git a/clients/macos/vellum-assistant/DesignSystem/Core/Buttons/VButton.swift b/clients/shared/DesignSystem/Core/Buttons/VButton.swift similarity index 78% rename from clients/macos/vellum-assistant/DesignSystem/Core/Buttons/VButton.swift rename to clients/shared/DesignSystem/Core/Buttons/VButton.swift index 51bc3c84c93..430bd02dcee 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Core/Buttons/VButton.swift +++ b/clients/shared/DesignSystem/Core/Buttons/VButton.swift @@ -1,23 +1,44 @@ import SwiftUI +#if os(macOS) +import AppKit +#endif -struct VButton: View { - enum Style: Hashable { case primary, ghost, danger } +public struct VButton: View { + public enum Style: Hashable { case primary, ghost, danger } - let label: String - var style: Style = .primary - var isFullWidth: Bool = false - var isDisabled: Bool = false - let action: () -> Void + public let label: String + public var style: Style = .primary + public var isFullWidth: Bool = false + public var isDisabled: Bool = false + public let action: () -> Void @State private var isHovered = false - var body: some View { + public init(label: String, style: Style = .primary, isFullWidth: Bool = false, isDisabled: Bool = false, action: @escaping () -> Void) { + self.label = label + self.style = style + self.isFullWidth = isFullWidth + self.isDisabled = isDisabled + self.action = action + } + + public var body: some View { Button(action: action) { Text(label) .font(VFont.bodyMedium) } .buttonStyle(VButtonStyle(style: style, isHovered: isHovered, isFullWidth: isFullWidth)) + #if os(macOS) + .onHover { hovering in + isHovered = isDisabled ? false : hovering + if !isDisabled { + if hovering { NSCursor.pointingHand.set() } + else { NSCursor.arrow.set() } + } + } + #else .onHover { isHovered = isDisabled ? false : $0 } + #endif .disabled(isDisabled) .opacity(isDisabled ? 0.5 : 1.0) .accessibilityHint(isDisabled ? "Button is currently disabled" : "") diff --git a/clients/macos/vellum-assistant/DesignSystem/Core/Buttons/VCircleButton.swift b/clients/shared/DesignSystem/Core/Buttons/VCircleButton.swift similarity index 58% rename from clients/macos/vellum-assistant/DesignSystem/Core/Buttons/VCircleButton.swift rename to clients/shared/DesignSystem/Core/Buttons/VCircleButton.swift index 260e2e5341a..ee26bdf18ed 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Core/Buttons/VCircleButton.swift +++ b/clients/shared/DesignSystem/Core/Buttons/VCircleButton.swift @@ -1,17 +1,30 @@ import SwiftUI +#if os(macOS) +import AppKit +#endif -struct VCircleButton: View { - let icon: String // SF Symbol name - let label: String // Human-readable accessibility label - var fillColor: Color = Emerald._600 - var iconColor: Color = .white - var size: CGFloat = 36 - var iconSize: CGFloat = 14 - let action: () -> Void +public struct VCircleButton: View { + public let icon: String // SF Symbol name + public let label: String // Human-readable accessibility label + public var fillColor: Color = Emerald._600 + public var iconColor: Color = .white + public var size: CGFloat = 36 + public var iconSize: CGFloat = 14 + public let action: () -> Void @State private var isHovered = false - var body: some View { + public init(icon: String, label: String, fillColor: Color = Emerald._600, iconColor: Color = .white, size: CGFloat = 36, iconSize: CGFloat = 14, action: @escaping () -> Void) { + self.icon = icon + self.label = label + self.fillColor = fillColor + self.iconColor = iconColor + self.size = size + self.iconSize = iconSize + self.action = action + } + + public var body: some View { Button(action: action) { Circle() .fill(fillColor) @@ -23,14 +36,15 @@ struct VCircleButton: View { ) } .buttonStyle(VCircleButtonStyle(isHovered: isHovered)) + #if os(macOS) .onHover { hovering in isHovered = hovering - if hovering { - NSCursor.pointingHand.set() - } else { - NSCursor.arrow.set() - } + if hovering { NSCursor.pointingHand.set() } + else { NSCursor.arrow.set() } } + #else + .onHover { isHovered = $0 } + #endif .accessibilityLabel(label) } } diff --git a/clients/macos/vellum-assistant/DesignSystem/Core/Buttons/VIconButton.swift b/clients/shared/DesignSystem/Core/Buttons/VIconButton.swift similarity index 75% rename from clients/macos/vellum-assistant/DesignSystem/Core/Buttons/VIconButton.swift rename to clients/shared/DesignSystem/Core/Buttons/VIconButton.swift index 51a3ad6f83f..15fa542e13e 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Core/Buttons/VIconButton.swift +++ b/clients/shared/DesignSystem/Core/Buttons/VIconButton.swift @@ -1,16 +1,28 @@ import SwiftUI +#if os(macOS) +import AppKit +#endif -struct VIconButton: View { - let label: String - var icon: String = "" - var customIcon: Image? = nil - var isActive: Bool = false - var iconOnly: Bool = false - let action: () -> Void +public struct VIconButton: View { + public let label: String + public var icon: String = "" + public var customIcon: Image? = nil + public var isActive: Bool = false + public var iconOnly: Bool = false + public let action: () -> Void @State private var isHovered = false - var body: some View { + public init(label: String, icon: String = "", customIcon: Image? = nil, isActive: Bool = false, iconOnly: Bool = false, action: @escaping () -> Void) { + self.label = label + self.icon = icon + self.customIcon = customIcon + self.isActive = isActive + self.iconOnly = iconOnly + self.action = action + } + + public var body: some View { Button(action: action) { HStack(spacing: VSpacing.xs) { if let customIcon { @@ -27,14 +39,15 @@ struct VIconButton: View { } } .buttonStyle(VIconButtonStyle(isActive: isActive, isHovered: isHovered, iconOnly: iconOnly)) + #if os(macOS) .onHover { hovering in isHovered = hovering - if hovering { - NSCursor.pointingHand.set() - } else { - NSCursor.arrow.set() - } + if hovering { NSCursor.pointingHand.set() } + else { NSCursor.arrow.set() } } + #else + .onHover { isHovered = $0 } + #endif .accessibilityLabel(label) } } diff --git a/clients/macos/vellum-assistant/DesignSystem/Core/Display/VListRow.swift b/clients/shared/DesignSystem/Core/Display/VListRow.swift similarity index 80% rename from clients/macos/vellum-assistant/DesignSystem/Core/Display/VListRow.swift rename to clients/shared/DesignSystem/Core/Display/VListRow.swift index 9f9048fd36c..c271bdb7ba3 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Core/Display/VListRow.swift +++ b/clients/shared/DesignSystem/Core/Display/VListRow.swift @@ -1,12 +1,17 @@ import SwiftUI -struct VListRow: View { - var onTap: (() -> Void)? = nil - @ViewBuilder let content: () -> Content +public struct VListRow: View { + public var onTap: (() -> Void)? = nil + @ViewBuilder public let content: () -> Content @State private var isHovered = false - var body: some View { + public init(onTap: (() -> Void)? = nil, @ViewBuilder content: @escaping () -> Content) { + self.onTap = onTap + self.content = content + } + + public var body: some View { Group { if let onTap = onTap { Button(action: onTap) { diff --git a/clients/macos/vellum-assistant/DesignSystem/Core/Feedback/VBadge.swift b/clients/shared/DesignSystem/Core/Feedback/VBadge.swift similarity index 87% rename from clients/macos/vellum-assistant/DesignSystem/Core/Feedback/VBadge.swift rename to clients/shared/DesignSystem/Core/Feedback/VBadge.swift index 269348a5114..4b01606387a 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Core/Feedback/VBadge.swift +++ b/clients/shared/DesignSystem/Core/Feedback/VBadge.swift @@ -1,16 +1,21 @@ import SwiftUI -struct VBadge: View { - enum Style { +public struct VBadge: View { + public enum Style { case count(Int) case dot case label(String) } - let style: Style - var color: Color = VColor.accent + public let style: Style + public var color: Color = VColor.accent - var body: some View { + public init(style: Style, color: Color = VColor.accent) { + self.style = style + self.color = color + } + + public var body: some View { switch style { case .count(let count): Text("\(count)") diff --git a/clients/macos/vellum-assistant/DesignSystem/Core/Feedback/VLoadingIndicator.swift b/clients/shared/DesignSystem/Core/Feedback/VLoadingIndicator.swift similarity index 77% rename from clients/macos/vellum-assistant/DesignSystem/Core/Feedback/VLoadingIndicator.swift rename to clients/shared/DesignSystem/Core/Feedback/VLoadingIndicator.swift index fe2770c0b80..02e72593860 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Core/Feedback/VLoadingIndicator.swift +++ b/clients/shared/DesignSystem/Core/Feedback/VLoadingIndicator.swift @@ -1,12 +1,17 @@ import SwiftUI -struct VLoadingIndicator: View { - var size: CGFloat = 20 - var color: Color = VColor.accent +public struct VLoadingIndicator: View { + public var size: CGFloat = 20 + public var color: Color = VColor.accent @State private var isAnimating = false - var body: some View { + public init(size: CGFloat = 20, color: Color = VColor.accent) { + self.size = size + self.color = color + } + + public var body: some View { Circle() .trim(from: 0, to: 0.7) .stroke(color, lineWidth: 2) diff --git a/clients/macos/vellum-assistant/DesignSystem/Core/Feedback/VToast.swift b/clients/shared/DesignSystem/Core/Feedback/VToast.swift similarity index 79% rename from clients/macos/vellum-assistant/DesignSystem/Core/Feedback/VToast.swift rename to clients/shared/DesignSystem/Core/Feedback/VToast.swift index 9b1d25d2a66..500545bd619 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Core/Feedback/VToast.swift +++ b/clients/shared/DesignSystem/Core/Feedback/VToast.swift @@ -1,12 +1,22 @@ import SwiftUI +#if os(macOS) import AppKit +#elseif os(iOS) +import UIKit +#endif -struct VToast: View { - enum Style { case info, success, warning, error } +public struct VToast: View { + public enum Style { case info, success, warning, error } - let message: String - var style: Style = .info - var body: some View { + public let message: String + public var style: Style = .info + + public init(message: String, style: Style = .info) { + self.message = message + self.style = style + } + + public var body: some View { HStack(spacing: VSpacing.md) { Image(systemName: iconName) .foregroundColor(iconColor) @@ -26,6 +36,7 @@ struct VToast: View { .accessibilityElement(children: .ignore) .accessibilityLabel(Text("\(String(describing: style)): \(message)")) .onAppear { + #if os(macOS) NSAccessibility.post( element: NSApp as Any, notification: .announcementRequested, @@ -34,6 +45,9 @@ struct VToast: View { .priority: NSAccessibilityPriorityLevel.high.rawValue ] ) + #elseif os(iOS) + UIAccessibility.post(notification: .announcement, argument: "\(style): \(message)") + #endif } } diff --git a/clients/macos/vellum-assistant/DesignSystem/Core/Inputs/VSlider.swift b/clients/shared/DesignSystem/Core/Inputs/VSlider.swift similarity index 92% rename from clients/macos/vellum-assistant/DesignSystem/Core/Inputs/VSlider.swift rename to clients/shared/DesignSystem/Core/Inputs/VSlider.swift index ef5fb26ad88..654f90d6e7f 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Core/Inputs/VSlider.swift +++ b/clients/shared/DesignSystem/Core/Inputs/VSlider.swift @@ -1,10 +1,17 @@ import SwiftUI -struct VSlider: View { - @Binding var value: Double - var range: ClosedRange = 0...100 - var step: Double = 1 - var showTickMarks: Bool = false +public struct VSlider: View { + @Binding public var value: Double + public var range: ClosedRange = 0...100 + public var step: Double = 1 + public var showTickMarks: Bool = false + + public init(value: Binding, range: ClosedRange = 0...100, step: Double = 1, showTickMarks: Bool = false) { + self._value = value + self.range = range + self.step = step + self.showTickMarks = showTickMarks + } // MARK: - Layout Constants @@ -22,7 +29,7 @@ struct VSlider: View { // MARK: - Body - var body: some View { + public var body: some View { GeometryReader { geometry in let trackWidth = geometry.size.width - thumbWidth let fraction = (value - range.lowerBound) / (range.upperBound - range.lowerBound) diff --git a/clients/macos/vellum-assistant/DesignSystem/Core/Inputs/VTextEditor.swift b/clients/shared/DesignSystem/Core/Inputs/VTextEditor.swift similarity index 79% rename from clients/macos/vellum-assistant/DesignSystem/Core/Inputs/VTextEditor.swift rename to clients/shared/DesignSystem/Core/Inputs/VTextEditor.swift index 58feae10ce6..7907736360c 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Core/Inputs/VTextEditor.swift +++ b/clients/shared/DesignSystem/Core/Inputs/VTextEditor.swift @@ -1,14 +1,21 @@ import SwiftUI -struct VTextEditor: View { - let placeholder: String - @Binding var text: String - var minHeight: CGFloat = 80 - var maxHeight: CGFloat = 200 +public struct VTextEditor: View { + public let placeholder: String + @Binding public var text: String + public var minHeight: CGFloat = 80 + public var maxHeight: CGFloat = 200 @FocusState private var isFocused: Bool - var body: some View { + public init(placeholder: String, text: Binding, minHeight: CGFloat = 80, maxHeight: CGFloat = 200) { + self.placeholder = placeholder + self._text = text + self.minHeight = minHeight + self.maxHeight = maxHeight + } + + public var body: some View { ZStack(alignment: .topLeading) { if text.isEmpty { Text(placeholder) diff --git a/clients/macos/vellum-assistant/DesignSystem/Core/Inputs/VTextField.swift b/clients/shared/DesignSystem/Core/Inputs/VTextField.swift similarity index 78% rename from clients/macos/vellum-assistant/DesignSystem/Core/Inputs/VTextField.swift rename to clients/shared/DesignSystem/Core/Inputs/VTextField.swift index 982daa8f8d2..1254b3d9c2c 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Core/Inputs/VTextField.swift +++ b/clients/shared/DesignSystem/Core/Inputs/VTextField.swift @@ -1,15 +1,23 @@ import SwiftUI -struct VTextField: View { - let placeholder: String - @Binding var text: String - var leadingIcon: String? = nil - var trailingIcon: String? = nil - var onSubmit: (() -> Void)? = nil +public struct VTextField: View { + public let placeholder: String + @Binding public var text: String + public var leadingIcon: String? = nil + public var trailingIcon: String? = nil + public var onSubmit: (() -> Void)? = nil @FocusState private var isFocused: Bool - var body: some View { + public init(placeholder: String, text: Binding, leadingIcon: String? = nil, trailingIcon: String? = nil, onSubmit: (() -> Void)? = nil) { + self.placeholder = placeholder + self._text = text + self.leadingIcon = leadingIcon + self.trailingIcon = trailingIcon + self.onSubmit = onSubmit + } + + public var body: some View { HStack(spacing: VSpacing.md) { if let leadingIcon = leadingIcon { Image(systemName: leadingIcon) diff --git a/clients/macos/vellum-assistant/DesignSystem/Core/Inputs/VToggle.swift b/clients/shared/DesignSystem/Core/Inputs/VToggle.swift similarity index 89% rename from clients/macos/vellum-assistant/DesignSystem/Core/Inputs/VToggle.swift rename to clients/shared/DesignSystem/Core/Inputs/VToggle.swift index 116e59bd76c..d43647b4dfd 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Core/Inputs/VToggle.swift +++ b/clients/shared/DesignSystem/Core/Inputs/VToggle.swift @@ -1,8 +1,13 @@ import SwiftUI -struct VToggle: View { - @Binding var isOn: Bool - var label: String? = nil +public struct VToggle: View { + @Binding public var isOn: Bool + public var label: String? = nil + + public init(isOn: Binding, label: String? = nil) { + self._isOn = isOn + self.label = label + } // MARK: - Layout Constants @@ -11,7 +16,7 @@ struct VToggle: View { private let knobSize: CGFloat = 16 private let knobPadding: CGFloat = 3 - var body: some View { + public var body: some View { HStack(spacing: VSpacing.sm) { toggleTrack diff --git a/clients/macos/vellum-assistant/DesignSystem/Core/Navigation/VTab.swift b/clients/shared/DesignSystem/Core/Navigation/VTab.swift similarity index 78% rename from clients/macos/vellum-assistant/DesignSystem/Core/Navigation/VTab.swift rename to clients/shared/DesignSystem/Core/Navigation/VTab.swift index 1218347493a..94ad4dbc42e 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Core/Navigation/VTab.swift +++ b/clients/shared/DesignSystem/Core/Navigation/VTab.swift @@ -1,22 +1,32 @@ import SwiftUI -enum VTabStyle { +public enum VTabStyle { case pill // Shows background fill on selected/hover, fully rounded case flat // No background fill, only text color changes case rectangular // Same as pill but with VRadius.md corners (matches VButton) } -struct VTab: View { - let label: String - var icon: String? = nil // SF Symbol - var isSelected: Bool = false - var isCloseable: Bool = true - var style: VTabStyle = .pill - var onSelect: () -> Void - var onClose: (() -> Void)? = nil +public struct VTab: View { + public let label: String + public var icon: String? = nil // SF Symbol + public var isSelected: Bool = false + public var isCloseable: Bool = true + public var style: VTabStyle = .pill + public var onSelect: () -> Void + public var onClose: (() -> Void)? = nil @State private var isHovered = false + public init(label: String, icon: String? = nil, isSelected: Bool = false, isCloseable: Bool = true, style: VTabStyle = .pill, onSelect: @escaping () -> Void, onClose: (() -> Void)? = nil) { + self.label = label + self.icon = icon + self.isSelected = isSelected + self.isCloseable = isCloseable + self.style = style + self.onSelect = onSelect + self.onClose = onClose + } + private var background: Color { switch style { case .pill, .rectangular: @@ -33,7 +43,7 @@ struct VTab: View { } } - var body: some View { + public var body: some View { Button(action: onSelect) { HStack(spacing: VSpacing.xs) { if let icon = icon { diff --git a/clients/macos/vellum-assistant/DesignSystem/Gallery/ComponentGalleryView.swift b/clients/shared/DesignSystem/Gallery/ComponentGalleryView.swift similarity index 100% rename from clients/macos/vellum-assistant/DesignSystem/Gallery/ComponentGalleryView.swift rename to clients/shared/DesignSystem/Gallery/ComponentGalleryView.swift diff --git a/clients/macos/vellum-assistant/DesignSystem/Gallery/ComponentGalleryWindow.swift b/clients/shared/DesignSystem/Gallery/ComponentGalleryWindow.swift similarity index 89% rename from clients/macos/vellum-assistant/DesignSystem/Gallery/ComponentGalleryWindow.swift rename to clients/shared/DesignSystem/Gallery/ComponentGalleryWindow.swift index cb9777e5395..a1054ad3cf2 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Gallery/ComponentGalleryWindow.swift +++ b/clients/shared/DesignSystem/Gallery/ComponentGalleryWindow.swift @@ -1,12 +1,14 @@ -#if DEBUG +#if DEBUG && os(macOS) import AppKit import SwiftUI @MainActor -final class ComponentGalleryWindow { +public final class ComponentGalleryWindow { private var window: NSWindow? - func show() { + public init() {} + + public func show() { if let existing = window { existing.makeKeyAndOrderFront(nil) NSApp.activate(ignoringOtherApps: true) @@ -38,7 +40,7 @@ final class ComponentGalleryWindow { self.window = window } - func close() { + public func close() { window?.close() window = nil } diff --git a/clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/ButtonsGallerySection.swift b/clients/shared/DesignSystem/Gallery/Sections/ButtonsGallerySection.swift similarity index 100% rename from clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/ButtonsGallerySection.swift rename to clients/shared/DesignSystem/Gallery/Sections/ButtonsGallerySection.swift diff --git a/clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/DisplayGallerySection.swift b/clients/shared/DesignSystem/Gallery/Sections/DisplayGallerySection.swift similarity index 100% rename from clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/DisplayGallerySection.swift rename to clients/shared/DesignSystem/Gallery/Sections/DisplayGallerySection.swift diff --git a/clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/FeedbackGallerySection.swift b/clients/shared/DesignSystem/Gallery/Sections/FeedbackGallerySection.swift similarity index 100% rename from clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/FeedbackGallerySection.swift rename to clients/shared/DesignSystem/Gallery/Sections/FeedbackGallerySection.swift diff --git a/clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/InputsGallerySection.swift b/clients/shared/DesignSystem/Gallery/Sections/InputsGallerySection.swift similarity index 100% rename from clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/InputsGallerySection.swift rename to clients/shared/DesignSystem/Gallery/Sections/InputsGallerySection.swift diff --git a/clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/LayoutGallerySection.swift b/clients/shared/DesignSystem/Gallery/Sections/LayoutGallerySection.swift similarity index 100% rename from clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/LayoutGallerySection.swift rename to clients/shared/DesignSystem/Gallery/Sections/LayoutGallerySection.swift diff --git a/clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/ModifiersGallerySection.swift b/clients/shared/DesignSystem/Gallery/Sections/ModifiersGallerySection.swift similarity index 100% rename from clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/ModifiersGallerySection.swift rename to clients/shared/DesignSystem/Gallery/Sections/ModifiersGallerySection.swift diff --git a/clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/NavigationGallerySection.swift b/clients/shared/DesignSystem/Gallery/Sections/NavigationGallerySection.swift similarity index 100% rename from clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/NavigationGallerySection.swift rename to clients/shared/DesignSystem/Gallery/Sections/NavigationGallerySection.swift diff --git a/clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/TokensGallerySection.swift b/clients/shared/DesignSystem/Gallery/Sections/TokensGallerySection.swift similarity index 100% rename from clients/macos/vellum-assistant/DesignSystem/Gallery/Sections/TokensGallerySection.swift rename to clients/shared/DesignSystem/Gallery/Sections/TokensGallerySection.swift diff --git a/clients/macos/vellum-assistant/DesignSystem/Modifiers/CardModifier.swift b/clients/shared/DesignSystem/Modifiers/CardModifier.swift similarity index 70% rename from clients/macos/vellum-assistant/DesignSystem/Modifiers/CardModifier.swift rename to clients/shared/DesignSystem/Modifiers/CardModifier.swift index 476c19c2728..d029102f2ed 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Modifiers/CardModifier.swift +++ b/clients/shared/DesignSystem/Modifiers/CardModifier.swift @@ -1,10 +1,15 @@ import SwiftUI -struct CardModifier: ViewModifier { - var radius: CGFloat = VRadius.md - var background: Color = VColor.surface +public struct CardModifier: ViewModifier { + public var radius: CGFloat = VRadius.md + public var background: Color = VColor.surface - func body(content: Content) -> some View { + public init(radius: CGFloat = VRadius.md, background: Color = VColor.surface) { + self.radius = radius + self.background = background + } + + public func body(content: Content) -> some View { content .background(background) .clipShape(RoundedRectangle(cornerRadius: radius)) @@ -15,7 +20,7 @@ struct CardModifier: ViewModifier { } } -extension View { +public extension View { func vCard(radius: CGFloat = VRadius.md, background: Color = VColor.surface) -> some View { modifier(CardModifier(radius: radius, background: background)) } diff --git a/clients/macos/vellum-assistant/DesignSystem/Modifiers/HoverEffect.swift b/clients/shared/DesignSystem/Modifiers/HoverEffect.swift similarity index 86% rename from clients/macos/vellum-assistant/DesignSystem/Modifiers/HoverEffect.swift rename to clients/shared/DesignSystem/Modifiers/HoverEffect.swift index 13d8b8ef924..6cd13c19440 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Modifiers/HoverEffect.swift +++ b/clients/shared/DesignSystem/Modifiers/HoverEffect.swift @@ -1,9 +1,11 @@ import SwiftUI -struct HoverEffectModifier: ViewModifier { +public struct HoverEffectModifier: ViewModifier { @State private var isHovered = false - func body(content: Content) -> some View { + public init() {} + + public func body(content: Content) -> some View { content .background(isHovered ? VColor.surfaceBorder.opacity(0.5) : .clear) .onHover { hovering in @@ -12,7 +14,7 @@ struct HoverEffectModifier: ViewModifier { } } -extension View { +public extension View { func vHover() -> some View { modifier(HoverEffectModifier()) } diff --git a/clients/macos/vellum-assistant/DesignSystem/Modifiers/PanelBackground.swift b/clients/shared/DesignSystem/Modifiers/PanelBackground.swift similarity index 82% rename from clients/macos/vellum-assistant/DesignSystem/Modifiers/PanelBackground.swift rename to clients/shared/DesignSystem/Modifiers/PanelBackground.swift index b2e331c1eef..630571cb182 100644 --- a/clients/macos/vellum-assistant/DesignSystem/Modifiers/PanelBackground.swift +++ b/clients/shared/DesignSystem/Modifiers/PanelBackground.swift @@ -1,14 +1,16 @@ import SwiftUI -struct PanelBackgroundModifier: ViewModifier { - func body(content: Content) -> some View { +public struct PanelBackgroundModifier: ViewModifier { + public init() {} + + public func body(content: Content) -> some View { content .frame(maxWidth: .infinity, maxHeight: .infinity) .background(VColor.backgroundSubtle) } } -extension View { +public extension View { func vPanelBackground() -> some View { modifier(PanelBackgroundModifier()) } diff --git a/clients/shared/DesignSystem/Tokens/AnimationTokens.swift b/clients/shared/DesignSystem/Tokens/AnimationTokens.swift new file mode 100644 index 00000000000..e2e1a1e0496 --- /dev/null +++ b/clients/shared/DesignSystem/Tokens/AnimationTokens.swift @@ -0,0 +1,21 @@ +import SwiftUI + +/// Animation presets. Use instead of raw Animation values. +public enum VAnimation { + public static let fast = Animation.easeOut(duration: 0.15) + public static let standard = Animation.easeInOut(duration: 0.25) + public static let slow = Animation.easeInOut(duration: 0.4) + public static let spring = Animation.spring(response: 0.3, dampingFraction: 0.8) + + /// Gentle spring for panel open/close + public static let panel = Animation.spring(response: 0.35, dampingFraction: 0.85) + + /// Bouncy spring for celebratory/attention-grabbing motion + public static let bouncy = Animation.spring(response: 0.3, dampingFraction: 0.5) + + // MARK: - Durations (for use with withAnimation or explicit timing) + + public static let durationFast: TimeInterval = 0.15 + public static let durationStandard: TimeInterval = 0.25 + public static let durationSlow: TimeInterval = 0.4 +} diff --git a/clients/shared/DesignSystem/Tokens/ColorTokens.swift b/clients/shared/DesignSystem/Tokens/ColorTokens.swift new file mode 100644 index 00000000000..d6e2af7b4f9 --- /dev/null +++ b/clients/shared/DesignSystem/Tokens/ColorTokens.swift @@ -0,0 +1,126 @@ +import SwiftUI + +// MARK: - Color Extension + +public extension Color { + init(hex: UInt, alpha: Double = 1.0) { + self.init( + .sRGB, + red: Double((hex >> 16) & 0xFF) / 255, + green: Double((hex >> 8) & 0xFF) / 255, + blue: Double(hex & 0xFF) / 255, + opacity: alpha + ) + } +} + +// MARK: - Color Scales + +public enum Slate { + public static let _950 = Color(hex: 0x070D19) + public static let _900 = Color(hex: 0x0F172A) + public static let _800 = Color(hex: 0x1E293B) + public static let _700 = Color(hex: 0x334155) + public static let _600 = Color(hex: 0x475569) + public static let _500 = Color(hex: 0x64748B) + public static let _400 = Color(hex: 0x94A3B8) + public static let _300 = Color(hex: 0xCBD5E1) + public static let _200 = Color(hex: 0xE2E8F0) + public static let _100 = Color(hex: 0xF1F5F9) + public static let _50 = Color(hex: 0xF8FAFC) +} + +public enum Emerald { + public static let _950 = Color(hex: 0x073D2E) + public static let _900 = Color(hex: 0x0A5843) + public static let _800 = Color(hex: 0x0C7356) + public static let _700 = Color(hex: 0x10906A) + public static let _600 = Color(hex: 0x18B07A) + public static let _500 = Color(hex: 0x38CF93) + public static let _400 = Color(hex: 0x6EE7B5) + public static let _300 = Color(hex: 0xA6F2D1) + public static let _200 = Color(hex: 0xD2F9E8) + public static let _100 = Color(hex: 0xECFDF5) +} + +public enum Violet { + public static let _950 = Color(hex: 0x321669) + public static let _900 = Color(hex: 0x4A2390) + public static let _800 = Color(hex: 0x5C2FB2) + public static let _700 = Color(hex: 0x7240CC) + public static let _600 = Color(hex: 0x8A5BE0) + public static let _500 = Color(hex: 0x9878EA) + public static let _400 = Color(hex: 0xB8A6F1) + public static let _300 = Color(hex: 0xD4C8F7) + public static let _200 = Color(hex: 0xE8E1FB) + public static let _100 = Color(hex: 0xF4F0FD) +} + +public enum Indigo { + public static let _950 = Color(hex: 0x180F66) + public static let _900 = Color(hex: 0x261A96) + public static let _800 = Color(hex: 0x3525C4) + public static let _700 = Color(hex: 0x4636E8) + public static let _600 = Color(hex: 0x5B4EFF) + public static let _500 = Color(hex: 0x7B6BFF) + public static let _400 = Color(hex: 0x9488FF) + public static let _300 = Color(hex: 0xB8B4FF) + public static let _200 = Color(hex: 0xD8D8FF) + public static let _100 = Color(hex: 0xEEEEFF) +} + +public enum Rose { + public static let _950 = Color(hex: 0x620F21) + public static let _900 = Color(hex: 0x85142F) + public static let _800 = Color(hex: 0xA8183E) + public static let _700 = Color(hex: 0xD02050) + public static let _600 = Color(hex: 0xE84060) + public static let _500 = Color(hex: 0xF06A86) + public static let _400 = Color(hex: 0xF99AAE) + public static let _300 = Color(hex: 0xFCBFC9) + public static let _200 = Color(hex: 0xFFE1E6) + public static let _100 = Color(hex: 0xFFF1F3) +} + +public enum Amber { + public static let _950 = Color(hex: 0x5E3207) + public static let _900 = Color(hex: 0x7A4409) + public static let _800 = Color(hex: 0xA35E0C) + public static let _700 = Color(hex: 0xC97C10) + public static let _600 = Color(hex: 0xE8A020) + public static let _500 = Color(hex: 0xFAC426) + public static let _400 = Color(hex: 0xFDD94E) + public static let _300 = Color(hex: 0xFEEC94) + public static let _200 = Color(hex: 0xFEF7CD) + public static let _100 = Color(hex: 0xFEFCE8) +} + +// MARK: - Semantic Color Tokens + +public enum VColor { + // Backgrounds + public static let background = Slate._950 + public static let backgroundSubtle = Slate._800 + public static let chatBackground = Slate._900 + public static let surface = Slate._800 + public static let surfaceBorder = Slate._700 + + // Text + public static let textPrimary = Slate._50 + public static let textSecondary = Slate._400 + public static let textMuted = Slate._500 + + // Accent (violet = primary) + public static let accent = Violet._600 + public static let accentSubtle = Violet._100 + + // Onboarding accent (amber) + public static let onboardingAccent = Amber._500 + public static let onboardingAccentDark = Amber._600 + public static let onboardingAccentDarker = Amber._800 + + // Status + public static let success = Emerald._600 + public static let error = Rose._600 + public static let warning = Amber._600 +} diff --git a/clients/shared/DesignSystem/Tokens/MeadowTokens.swift b/clients/shared/DesignSystem/Tokens/MeadowTokens.swift new file mode 100644 index 00000000000..573ae47c8ca --- /dev/null +++ b/clients/shared/DesignSystem/Tokens/MeadowTokens.swift @@ -0,0 +1,28 @@ +import SwiftUI + +/// Onboarding-specific design tokens for the Pixel Meadow theme. +public enum Meadow { + // Panel + public static let panelBackground = Slate._900.opacity(0.75) + public static let panelBorder = Slate._700.opacity(0.4) + + // Egg glow + public static let eggGlow = Amber._500 + public static let eggGlowIntense = Amber._400 + public static let crackLight = Amber._200 + + // Bottom caption + public static let captionText = Color.white.opacity(0.5) + + // Pixel scaling factor + public static let pixelScale: CGFloat = 2.0 + + // Art pixel size — each pixel-art cell renders as this many points + public static let artPixelSize: CGFloat = 5.0 + + // Interview palette + public static let avatarGradientStart = Violet._600 + public static let avatarGradientEnd = Violet._400 + public static let userBubbleGradientStart = Violet._600 + public static let userBubbleGradientEnd = Violet._400 +} diff --git a/clients/shared/DesignSystem/Tokens/RadiusTokens.swift b/clients/shared/DesignSystem/Tokens/RadiusTokens.swift new file mode 100644 index 00000000000..2a547f701cb --- /dev/null +++ b/clients/shared/DesignSystem/Tokens/RadiusTokens.swift @@ -0,0 +1,13 @@ +import Foundation + +/// Corner radius scale. Use `VRadius.pill` for capsule shapes. +public enum VRadius { + public static let xs: CGFloat = 2 + public static let sm: CGFloat = 4 + public static let md: CGFloat = 8 + public static let lg: CGFloat = 12 + public static let xl: CGFloat = 16 + + /// Use for fully rounded pill/capsule shapes + public static let pill: CGFloat = 999 +} diff --git a/clients/shared/DesignSystem/Tokens/ShadowTokens.swift b/clients/shared/DesignSystem/Tokens/ShadowTokens.swift new file mode 100644 index 00000000000..2c4e44a82d2 --- /dev/null +++ b/clients/shared/DesignSystem/Tokens/ShadowTokens.swift @@ -0,0 +1,34 @@ +import SwiftUI + +/// Shadow presets. Apply via `.vShadow(.md)` or `.shadow(color:radius:y:)`. +public enum VShadow { + public struct Definition { + public let color: Color + public let radius: CGFloat + public let x: CGFloat + public let y: CGFloat + + public init(color: Color, radius: CGFloat, x: CGFloat, y: CGFloat) { + self.color = color + self.radius = radius + self.x = x + self.y = y + } + } + + public static let sm = Definition(color: .black.opacity(0.2), radius: 4, x: 0, y: 2) + public static let md = Definition(color: .black.opacity(0.3), radius: 8, x: 0, y: 4) + public static let lg = Definition(color: .black.opacity(0.4), radius: 16, x: 0, y: 8) + + /// Amber glow effect for brand elements (orb, highlights) + public static let glow = Definition(color: Amber._500.opacity(0.3), radius: 12, x: 0, y: 0) + + /// Violet glow for accent elements (focused inputs, active buttons) + public static let accentGlow = Definition(color: Violet._600.opacity(0.3), radius: 8, x: 0, y: 0) +} + +public extension View { + func vShadow(_ definition: VShadow.Definition) -> some View { + shadow(color: definition.color, radius: definition.radius, x: definition.x, y: definition.y) + } +} diff --git a/clients/shared/DesignSystem/Tokens/SpacingTokens.swift b/clients/shared/DesignSystem/Tokens/SpacingTokens.swift new file mode 100644 index 00000000000..c633a1b00c8 --- /dev/null +++ b/clients/shared/DesignSystem/Tokens/SpacingTokens.swift @@ -0,0 +1,27 @@ +import Foundation + +/// Spacing scale based on 4pt grid. +/// Usage: `.padding(VSpacing.lg)` or `.padding(.horizontal, VSpacing.xl)` +public enum VSpacing { + public static let xxs: CGFloat = 2 + public static let xs: CGFloat = 4 + public static let sm: CGFloat = 8 + public static let md: CGFloat = 12 + public static let lg: CGFloat = 16 + public static let xl: CGFloat = 24 + public static let xxl: CGFloat = 32 + public static let xxxl: CGFloat = 48 + + // MARK: - Semantic Aliases + + /// Standard gap between inline elements (icons + text, etc.) + public static let inline: CGFloat = sm + /// Standard content padding inside cards and panels + public static let content: CGFloat = lg + /// Standard section gap between major UI blocks + public static let section: CGFloat = xl + /// Standard window/page-level margin + public static let page: CGFloat = xxl + /// Compact vertical padding for buttons + public static let buttonV: CGFloat = 5.5 +} diff --git a/clients/shared/DesignSystem/Tokens/TypographyTokens.swift b/clients/shared/DesignSystem/Tokens/TypographyTokens.swift new file mode 100644 index 00000000000..e2dac1e0fc7 --- /dev/null +++ b/clients/shared/DesignSystem/Tokens/TypographyTokens.swift @@ -0,0 +1,78 @@ +import SwiftUI +#if os(macOS) +import AppKit +#elseif os(iOS) +import UIKit +#endif + +/// Font presets for the app. Always use these instead of raw Font.system() calls. +/// +/// **Silkscreen** — pixelated bitmap font for headings and display text. +/// **DM Mono** — monospaced font for body/UI text. +public enum VFont { + + /// DM Mono's default "f" has an exaggerated italic-style hook. + /// Stylistic Set 5 (ss05) provides a conventional "f" glyph. + private static func dmMono(_ name: String, size: CGFloat) -> Font { + #if os(macOS) + guard let nsFont = NSFont(name: name, size: size) else { + return Font.custom(name, size: size) + } + let descriptor = nsFont.fontDescriptor.addingAttributes([ + .featureSettings: [[ + NSFontDescriptor.FeatureKey.typeIdentifier: kStylisticAlternativesType, + NSFontDescriptor.FeatureKey.selectorIdentifier: kStylisticAltFiveOnSelector, + ]] + ]) + return Font(NSFont(descriptor: descriptor, size: size) ?? nsFont) + #elseif os(iOS) + guard let uiFont = UIFont(name: name, size: size) else { + return Font.custom(name, size: size) + } + let descriptor = uiFont.fontDescriptor.addingAttributes([ + .featureSettings: [[ + UIFontDescriptor.FeatureKey.featureIdentifier: kStylisticAlternativesType, + UIFontDescriptor.FeatureKey.typeIdentifier: kStylisticAltFiveOnSelector, + ]] + ]) + return Font(UIFont(descriptor: descriptor, size: size)) + #else + // Fallback for unsupported platforms (visionOS, tvOS, watchOS) + return Font.custom(name, size: size) + #endif + } + // MARK: - Onboarding (Silkscreen pixel font) + + public static let onboardingTitle = Font.custom("Silkscreen-Regular", size: 28) + public static let onboardingSubtitle = Font.custom("Silkscreen-Regular", size: 15) + + // MARK: - Headings (Silkscreen) + // TODO: Clean up typography once we solidify the design system - we dont seem to use Bold + public static let largeTitle = Font.custom("Silkscreen-Bold", size: 26) + public static let title = Font.custom("Silkscreen-Bold", size: 22) + public static let headline = Font.custom("Silkscreen-Bold", size: 13) + + // MARK: - Body / UI (DM Mono) + + public static let body = dmMono("DMMono-Regular", size: 13) + public static let bodyMedium = dmMono("DMMono-Medium", size: 13) + public static let bodyBold = dmMono("DMMono-Medium", size: 13) + public static let caption = dmMono("DMMono-Regular", size: 11) + public static let captionMedium = dmMono("DMMono-Medium", size: 11) + public static let small = dmMono("DMMono-Regular", size: 10) + + // MARK: - Specialized + + public static let cardTitle = dmMono("DMMono-Medium", size: 17) + public static let cardEmoji = Font.system(size: 32) + public static let mono = dmMono("DMMono-Regular", size: 13) + public static let monoSmall = dmMono("DMMono-Regular", size: 11) + + /// All-caps pixel display font (used for panel headers like "AGENT", "GENERATED CONTENT") + public static let display = Font.custom("Silkscreen-Bold", size: 18) + public static let panelTitle = Font.custom("Silkscreen-Regular", size: 24) + public static let sectionTitle = Font.custom("Silkscreen-Regular", size: 18) + + /// Small Silkscreen label (used for thread tab names) + public static let tabLabel = Font.custom("Silkscreen-Regular", size: 11) +}