| author | |
| committer | |
| log | 0f1b572b9865256dd61e245b4dd09f6a7b15f0e1 |
| tree | a4eef2cee02beff66f05aadaa3eb90fd9037a9f3 |
| parent | 5378f87f99175bded2b9241876319567875aca03 |
| signature | Signed by PGP key B5690EEEBB952194 |
84 files changed, 1913 insertions(+), 1281 deletions(-)
apps/mobile/clerk-theme.json+27-27| ... | @@ -1,36 +1,36 @@ | ... | @@ -1,36 +1,36 @@ |
| 1 | { | 1 | { |
| 2 | "colors": { | 2 | "colors": { |
| 3 | "primary": "#262626", | 3 | "primary": "#1b4ed8", |
| 4 | "background": "#F2F2F7", | 4 | "background": "#fcfcfc", |
| 5 | "input": "#FFFFFF", | 5 | "input": "#ffffff", |
| 6 | "danger": "#DC2626", | 6 | "danger": "#c10007", |
| 7 | "success": "#059669", | 7 | "success": "#059669", |
| 8 | "warning": "#D97706", | 8 | "warning": "#bb4d00", |
| 9 | "foreground": "#262626", | 9 | "foreground": "#27272a", |
| 10 | "mutedForeground": "#737373", | 10 | "mutedForeground": "#71717b", |
| 11 | "primaryForeground": "#FFFFFF", | 11 | "primaryForeground": "#ffffff", |
| 12 | "inputForeground": "#262626", | 12 | "inputForeground": "#27272a", |
| 13 | "neutral": "#F5F5F5", | 13 | "neutral": "#fafafa", |
| 14 | "border": "#E5E5EA", | 14 | "border": "#e4e4e7", |
| 15 | "ring": "#A3A3A3", | 15 | "ring": "#1b4ed8", |
| 16 | "muted": "#F2F2F7", | 16 | "muted": "#fafafa", |
| 17 | "shadow": "#000000" | 17 | "shadow": "#000000" |
| 18 | }, | 18 | }, |
| 19 | "darkColors": { | 19 | "darkColors": { |
| 20 | "primary": "#F5F5F5", | 20 | "primary": "#346bf1", |
| 21 | "background": "#0E0E0E", | 21 | "background": "#0a0a0a", |
| 22 | "input": "#171717", | 22 | "input": "#111111", |
| 23 | "danger": "#FCA5A5", | 23 | "danger": "#ff6467", |
| 24 | "success": "#34D399", | 24 | "success": "#34d399", |
| 25 | "warning": "#FBBF24", | 25 | "warning": "#ffb900", |
| 26 | "foreground": "#F5F5F5", | 26 | "foreground": "#f5f5f5", |
| 27 | "mutedForeground": "#A3A3A3", | 27 | "mutedForeground": "#818181", |
| 28 | "primaryForeground": "#0A0A0A", | 28 | "primaryForeground": "#ffffff", |
| 29 | "inputForeground": "#F5F5F5", | 29 | "inputForeground": "#f5f5f5", |
| 30 | "neutral": "#1C1C1C", | 30 | "neutral": "#111111", |
| 31 | "border": "#2A2A2A", | 31 | "border": "#191919", |
| 32 | "ring": "#525252", | 32 | "ring": "#346bf1", |
| 33 | "muted": "#0E0E0E", | 33 | "muted": "#111111", |
| 34 | "shadow": "#000000" | 34 | "shadow": "#000000" |
| 35 | }, | 35 | }, |
| 36 | "design": { | 36 | "design": { |
apps/mobile/generated-uniwind-default-theme-variables.json+150-126| ... | @@ -1,156 +1,180 @@ | ... | @@ -1,156 +1,180 @@ |
| 1 | { | 1 | { |
| 2 | "light": { | 2 | "light": { |
| 3 | "--color-screen": "#f2f2f7", | 3 | "--color-screen": "#fcfcfc", |
| 4 | "--color-sheet": "rgba(242, 242, 247, 0.98)", | 4 | "--color-sheet": "rgba(252, 252, 252, 0.98)", |
| 5 | "--color-sheet-solid": "#f2f2f7", | 5 | "--color-sheet-solid": "#fcfcfc", |
| 6 | "--color-card": "#ffffff", | 6 | "--color-card": "#ffffff", |
| 7 | "--color-card-alt": "#f5f5f5", | 7 | "--color-grouped-card": "#f4f4f5", |
| 8 | "--color-card-alt": "#fcfcfc", | ||
| 8 | "--color-card-translucent": "rgba(255, 255, 255, 0.8)", | 9 | "--color-card-translucent": "rgba(255, 255, 255, 0.8)", |
| 9 | "--color-thread-canvas": "#f5f5f5", | 10 | "--color-thread-canvas": "#fcfcfc", |
| 10 | "--color-thread-selected": "#ffffff", | 11 | "--color-thread-selected": "#ffffff", |
| 11 | "--color-thread-selected-foreground": "#262626", | 12 | "--color-thread-selected-foreground": "#27272a", |
| 12 | "--color-thread-selected-foreground-muted": "#737373", | 13 | "--color-thread-selected-foreground-muted": "#71717b", |
| 13 | "--color-composer-panel": "rgba(245, 245, 245, 0.88)", | 14 | "--color-thread-hover": "#fcfcfc", |
| 14 | "--color-composer-surface": "rgba(255, 255, 255, 0.94)", | 15 | "--color-row-hover": "#f4f4f5", |
| 15 | "--color-composer-border": "rgba(0, 0, 0, 0.1)", | 16 | "--color-composer-panel": "rgba(252, 252, 252, 0.88)", |
| 16 | "--color-foreground": "#262626", | 17 | "--color-composer-surface": "rgba(244, 244, 245, 0.94)", |
| 17 | "--color-foreground-secondary": "#525252", | 18 | "--color-composer-border": "rgba(228, 228, 231, 0.8)", |
| 18 | "--color-foreground-muted": "#737373", | 19 | "--color-foreground": "#27272a", |
| 19 | "--color-foreground-tertiary": "#8e8e93", | 20 | "--color-foreground-secondary": "#6f6f79", |
| 20 | "--color-border": "rgba(0, 0, 0, 0.08)", | 21 | "--color-foreground-muted": "#6f6f79", |
| 21 | "--color-border-subtle": "rgba(0, 0, 0, 0.06)", | 22 | "--color-foreground-tertiary": "#71717b", |
| 22 | "--color-separator": "rgba(0, 0, 0, 0.04)", | 23 | "--color-border": "#e4e4e7", |
| 23 | "--color-subtle": "rgba(0, 0, 0, 0.04)", | 24 | "--color-focus": "#1b4ed8", |
| 24 | "--color-subtle-strong": "rgba(0, 0, 0, 0.08)", | 25 | "--color-border-subtle": "rgba(228, 228, 231, 0.7)", |
| 25 | "--color-inline-skill-background": "rgba(217, 70, 239, 0.12)", | 26 | "--color-separator": "rgba(228, 228, 231, 0.55)", |
| 26 | "--color-inline-skill-border": "rgba(217, 70, 239, 0.25)", | 27 | "--color-subtle": "#fafafa", |
| 27 | "--color-inline-skill-foreground": "#a21caf", | 28 | "--color-subtle-strong": "#fafafa", |
| 28 | "--color-primary": "#262626", | 29 | "--color-inline-skill-background": "#f4f4f5", |
| 30 | "--color-inline-skill-border": "rgba(27, 78, 216, 0.42)", | ||
| 31 | "--color-inline-skill-foreground": "#18181b", | ||
| 32 | "--color-primary": "#1b4ed8", | ||
| 29 | "--color-primary-foreground": "#ffffff", | 33 | "--color-primary-foreground": "#ffffff", |
| 34 | "--color-primary-text": "#1b4ed8", | ||
| 30 | "--color-primary-shadow": "#000000", | 35 | "--color-primary-shadow": "#000000", |
| 31 | "--color-secondary": "#ffffff", | 36 | "--color-secondary": "#fafafa", |
| 32 | "--color-secondary-foreground": "#262626", | 37 | "--color-secondary-foreground": "#27272a", |
| 33 | "--color-secondary-border": "rgba(0, 0, 0, 0.08)", | 38 | "--color-secondary-border": "#e4e4e7", |
| 34 | "--color-switch-active-track": "#34c759", | 39 | "--color-switch-active-track": "#1b4ed8", |
| 35 | "--color-switch-active-thumb": "#ffffff", | 40 | "--color-switch-active-thumb": "#ffffff", |
| 36 | "--color-switch-inactive-track": "rgba(0, 0, 0, 0.08)", | 41 | "--color-switch-inactive-track": "#fafafa", |
| 37 | "--color-switch-inactive-thumb": "#8e8e93", | 42 | "--color-switch-inactive-thumb": "#71717b", |
| 38 | "--color-warning": "#fffbeb", | 43 | "--color-warning": "#fcf4e8", |
| 39 | "--color-warning-border": "#fde68a", | 44 | "--color-warning-border": "rgba(254, 154, 0, 0.32)", |
| 40 | "--color-warning-foreground": "#b45309", | 45 | "--color-warning-foreground": "#bb4d00", |
| 41 | "--color-danger": "#fef2f2", | 46 | "--color-danger": "#fcebec", |
| 42 | "--color-danger-border": "rgba(239, 68, 68, 0.12)", | 47 | "--color-danger-border": "rgba(251, 44, 54, 0.32)", |
| 43 | "--color-danger-foreground": "#dc2626", | 48 | "--color-danger-foreground": "#c10007", |
| 49 | "--color-update": "#e0e6f7", | ||
| 50 | "--color-update-foreground": "#1b4ed8", | ||
| 44 | "--color-input": "#ffffff", | 51 | "--color-input": "#ffffff", |
| 45 | "--color-input-border": "rgba(0, 0, 0, 0.1)", | 52 | "--color-input-border": "#d4d4d8", |
| 46 | "--color-sidebar-search": "rgba(118, 118, 128, 0.12)", | 53 | "--color-sidebar-search": "#f4f4f5", |
| 47 | "--color-placeholder": "#737373", | 54 | "--color-placeholder": "#6f6f79", |
| 48 | "--color-icon": "#262626", | 55 | "--color-icon": "#27272a", |
| 49 | "--color-icon-muted": "#525252", | 56 | "--color-icon-muted": "#71717b", |
| 50 | "--color-icon-subtle": "#a3a3a3", | 57 | "--color-icon-subtle": "#71717b", |
| 51 | "--color-header": "rgba(255, 255, 255, 0.97)", | 58 | "--color-header": "rgba(252, 252, 252, 0.97)", |
| 52 | "--color-header-border": "rgba(0, 0, 0, 0.06)", | 59 | "--color-header-foreground": "#27272a", |
| 53 | "--color-glass-surface": "rgba(255, 255, 255, 0.72)", | 60 | "--color-header-border": "#e4e4e7", |
| 54 | "--color-glass-tint": "rgba(255, 255, 255, 0.18)", | 61 | "--color-glass-surface": "rgba(255, 255, 255, 0.74)", |
| 55 | "--color-status-bar": "#f2f2f7", | 62 | "--color-glass-fallback": "rgba(244, 244, 245, 0.94)", |
| 56 | "--color-md-body": "#111111", | 63 | "--color-glass-tint": "rgba(255, 255, 255, 0.22)", |
| 57 | "--color-md-strong": "#000000", | 64 | "--color-status-bar": "#fcfcfc", |
| 58 | "--color-md-link": "#2563eb", | 65 | "--color-md-body": "#27272a", |
| 59 | "--color-md-blockquote-border": "rgba(0, 0, 0, 0.08)", | 66 | "--color-md-strong": "#27272a", |
| 60 | "--color-md-blockquote-bg": "rgba(0, 0, 0, 0.02)", | 67 | "--color-md-link": "#1b4ed8", |
| 61 | "--color-md-code-bg": "rgba(0, 0, 0, 0.04)", | 68 | "--color-md-blockquote-border": "#e4e4e7", |
| 62 | "--color-md-code-text": "#262626", | 69 | "--color-md-blockquote-bg": "#fafafa", |
| 63 | "--color-md-user-code-bg": "rgba(0, 0, 0, 0.04)", | 70 | "--color-md-code-bg": "#ffffff", |
| 64 | "--color-md-user-code-text": "#262626", | 71 | "--color-md-code-text": "#27272a", |
| 65 | "--color-md-user-fence-bg": "rgba(0, 0, 0, 0.06)", | 72 | "--color-md-user-code-bg": "rgba(39, 39, 42, 0.18)", |
| 66 | "--color-md-user-fence-text": "#262626", | 73 | "--color-md-user-code-text": "#27272a", |
| 67 | "--color-md-hr": "rgba(0, 0, 0, 0.08)", | 74 | "--color-md-user-fence-bg": "rgba(0, 0, 0, 0.16)", |
| 68 | "--color-user-bubble": "#ffffff", | 75 | "--color-md-user-fence-text": "#27272a", |
| 69 | "--color-user-bubble-foreground": "#262626", | 76 | "--color-md-hr": "#e4e4e7", |
| 70 | "--color-user-bubble-foreground-muted": "rgba(38, 38, 38, 0.78)", | 77 | "--color-user-bubble": "#efeff1", |
| 71 | "--color-user-bubble-skill-foreground": "#2563eb", | 78 | "--color-user-bubble-foreground": "#27272a", |
| 79 | "--color-user-bubble-foreground-muted": "rgba(39, 39, 42, 0.78)", | ||
| 80 | "--color-user-bubble-skill-foreground": "#1b4ed8", | ||
| 72 | "--color-backdrop": "rgba(0, 0, 0, 0.22)", | 81 | "--color-backdrop": "rgba(0, 0, 0, 0.22)", |
| 73 | "--color-drawer": "rgba(255, 255, 255, 0.99)", | 82 | "--color-drawer": "#fafafa", |
| 83 | "--color-drawer-foreground": "#27272a", | ||
| 84 | "--color-drawer-foreground-muted": "#71717b", | ||
| 85 | "--color-drawer-border": "#e4e4e7", | ||
| 74 | "--color-drawer-shadow": "rgba(0, 0, 0, 0.12)", | 86 | "--color-drawer-shadow": "rgba(0, 0, 0, 0.12)", |
| 75 | "--color-dot-separator": "rgba(0, 0, 0, 0.2)", | 87 | "--color-dot-separator": "rgba(113, 113, 123, 0.35)", |
| 76 | "--color-wordmark": "#262626", | 88 | "--color-wordmark": "#27272a", |
| 77 | "--color-chevron": "rgba(0, 0, 0, 0.2)" | 89 | "--color-chevron": "rgba(113, 113, 123, 0.42)" |
| 78 | }, | 90 | }, |
| 79 | "dark": { | 91 | "dark": { |
| 80 | "--color-screen": "#0a0a0a", | 92 | "--color-screen": "#0a0a0a", |
| 81 | "--color-sheet": "rgba(14, 14, 14, 0.98)", | 93 | "--color-sheet": "rgba(10, 10, 10, 0.98)", |
| 82 | "--color-sheet-solid": "#0e0e0e", | 94 | "--color-sheet-solid": "#0a0a0a", |
| 83 | "--color-card": "#171717", | 95 | "--color-card": "#111111", |
| 84 | "--color-card-alt": "#1c1c1c", | 96 | "--color-grouped-card": "#1a1b1b", |
| 97 | "--color-card-alt": "#111111", | ||
| 85 | "--color-card-translucent": "rgba(17, 17, 17, 0.8)", | 98 | "--color-card-translucent": "rgba(17, 17, 17, 0.8)", |
| 86 | "--color-thread-canvas": "#1c1c1c", | 99 | "--color-thread-canvas": "#0a0a0a", |
| 87 | "--color-thread-selected": "#171717", | 100 | "--color-thread-selected": "#1a1b1b", |
| 88 | "--color-thread-selected-foreground": "#f5f5f5", | 101 | "--color-thread-selected-foreground": "#f1f3f7", |
| 89 | "--color-thread-selected-foreground-muted": "#8e8e93", | 102 | "--color-thread-selected-foreground-muted": "#a3a3a3", |
| 90 | "--color-composer-panel": "rgba(28, 28, 28, 0.92)", | 103 | "--color-thread-hover": "#131313", |
| 91 | "--color-composer-surface": "rgba(23, 23, 23, 0.9)", | 104 | "--color-row-hover": "#141414", |
| 92 | "--color-composer-border": "rgba(255, 255, 255, 0.08)", | 105 | "--color-composer-panel": "rgba(10, 10, 10, 0.92)", |
| 106 | "--color-composer-surface": "rgba(26, 27, 27, 0.9)", | ||
| 107 | "--color-composer-border": "rgba(25, 25, 25, 0.8)", | ||
| 93 | "--color-foreground": "#f5f5f5", | 108 | "--color-foreground": "#f5f5f5", |
| 94 | "--color-foreground-secondary": "#a3a3a3", | 109 | "--color-foreground-secondary": "#838383", |
| 95 | "--color-foreground-muted": "#8e8e93", | 110 | "--color-foreground-muted": "#838383", |
| 96 | "--color-foreground-tertiary": "#636366", | 111 | "--color-foreground-tertiary": "#818181", |
| 97 | "--color-border": "rgba(255, 255, 255, 0.06)", | 112 | "--color-border": "#191919", |
| 98 | "--color-border-subtle": "rgba(255, 255, 255, 0.04)", | 113 | "--color-focus": "#346bf1", |
| 99 | "--color-separator": "rgba(255, 255, 255, 0.03)", | 114 | "--color-border-subtle": "rgba(25, 25, 25, 0.7)", |
| 100 | "--color-subtle": "rgba(255, 255, 255, 0.04)", | 115 | "--color-separator": "rgba(25, 25, 25, 0.55)", |
| 101 | "--color-subtle-strong": "rgba(255, 255, 255, 0.08)", | 116 | "--color-subtle": "#111111", |
| 102 | "--color-inline-skill-background": "rgba(217, 70, 239, 0.12)", | 117 | "--color-subtle-strong": "#111111", |
| 103 | "--color-inline-skill-border": "rgba(217, 70, 239, 0.25)", | 118 | "--color-inline-skill-background": "#141414", |
| 104 | "--color-inline-skill-foreground": "#f0abfc", | 119 | "--color-inline-skill-border": "rgba(52, 107, 241, 0.42)", |
| 105 | "--color-primary": "#f5f5f5", | 120 | "--color-inline-skill-foreground": "#f5f5f5", |
| 106 | "--color-primary-foreground": "#0a0a0a", | 121 | "--color-primary": "#346bf1", |
| 122 | "--color-primary-foreground": "#ffffff", | ||
| 123 | "--color-primary-text": "#4b7cf3", | ||
| 107 | "--color-primary-shadow": "#000000", | 124 | "--color-primary-shadow": "#000000", |
| 108 | "--color-secondary": "rgba(255, 255, 255, 0.04)", | 125 | "--color-secondary": "#111111", |
| 109 | "--color-secondary-foreground": "#f5f5f5", | 126 | "--color-secondary-foreground": "#f5f5f5", |
| 110 | "--color-secondary-border": "rgba(255, 255, 255, 0.06)", | 127 | "--color-secondary-border": "#191919", |
| 111 | "--color-switch-active-track": "#30d158", | 128 | "--color-switch-active-track": "#346bf1", |
| 112 | "--color-switch-active-thumb": "#ffffff", | 129 | "--color-switch-active-thumb": "#ffffff", |
| 113 | "--color-switch-inactive-track": "rgba(255, 255, 255, 0.06)", | 130 | "--color-switch-inactive-track": "#111111", |
| 114 | "--color-switch-inactive-thumb": "#8e8e93", | 131 | "--color-switch-inactive-thumb": "#818181", |
| 115 | "--color-warning": "rgba(69, 26, 3, 0.4)", | 132 | "--color-warning": "#312108", |
| 116 | "--color-warning-border": "rgba(120, 53, 15, 0.6)", | 133 | "--color-warning-border": "rgba(254, 154, 0, 0.32)", |
| 117 | "--color-warning-foreground": "#fcd34d", | 134 | "--color-warning-foreground": "#ffb900", |
| 118 | "--color-danger": "rgba(239, 68, 68, 0.14)", | 135 | "--color-danger": "#301214", |
| 119 | "--color-danger-border": "rgba(248, 113, 113, 0.18)", | 136 | "--color-danger-border": "rgba(251, 65, 74, 0.32)", |
| 120 | "--color-danger-foreground": "#fca5a5", | 137 | "--color-danger-foreground": "#ff6467", |
| 121 | "--color-input": "#141414", | 138 | "--color-update": "#121b34", |
| 122 | "--color-input-border": "rgba(255, 255, 255, 0.08)", | 139 | "--color-update-foreground": "#51a2ff", |
| 123 | "--color-sidebar-search": "rgba(118, 118, 128, 0.24)", | 140 | "--color-input": "#111111", |
| 124 | "--color-placeholder": "#8e8e93", | 141 | "--color-input-border": "#1e1e1e", |
| 142 | "--color-sidebar-search": "#0a0a0a", | ||
| 143 | "--color-placeholder": "#838383", | ||
| 125 | "--color-icon": "#f5f5f5", | 144 | "--color-icon": "#f5f5f5", |
| 126 | "--color-icon-muted": "#a3a3a3", | 145 | "--color-icon-muted": "#818181", |
| 127 | "--color-icon-subtle": "#8e8e93", | 146 | "--color-icon-subtle": "#818181", |
| 128 | "--color-header": "rgba(10, 10, 10, 0.97)", | 147 | "--color-header": "rgba(10, 10, 10, 0.97)", |
| 129 | "--color-header-border": "rgba(255, 255, 255, 0.06)", | 148 | "--color-header-foreground": "#f5f5f5", |
| 130 | "--color-glass-surface": "rgba(23, 23, 23, 0.78)", | 149 | "--color-header-border": "#191919", |
| 131 | "--color-glass-tint": "rgba(23, 23, 23, 0.24)", | 150 | "--color-glass-surface": "rgba(17, 17, 17, 0.74)", |
| 151 | "--color-glass-fallback": "rgba(26, 27, 27, 0.9)", | ||
| 152 | "--color-glass-tint": "rgba(17, 17, 17, 0.22)", | ||
| 132 | "--color-status-bar": "#0a0a0a", | 153 | "--color-status-bar": "#0a0a0a", |
| 133 | "--color-md-body": "#e5e5e5", | 154 | "--color-md-body": "#f5f5f5", |
| 134 | "--color-md-strong": "#f5f5f5", | 155 | "--color-md-strong": "#f5f5f5", |
| 135 | "--color-md-link": "#60a5fa", | 156 | "--color-md-link": "#3b70f1", |
| 136 | "--color-md-blockquote-border": "rgba(255, 255, 255, 0.1)", | 157 | "--color-md-blockquote-border": "#191919", |
| 137 | "--color-md-blockquote-bg": "rgba(255, 255, 255, 0.03)", | 158 | "--color-md-blockquote-bg": "#111111", |
| 138 | "--color-md-code-bg": "rgba(255, 255, 255, 0.06)", | 159 | "--color-md-code-bg": "#111111", |
| 139 | "--color-md-code-text": "#e5e5e5", | 160 | "--color-md-code-text": "#f5f5f5", |
| 140 | "--color-md-user-code-bg": "rgba(255, 255, 255, 0.06)", | 161 | "--color-md-user-code-bg": "rgba(245, 245, 245, 0.18)", |
| 141 | "--color-md-user-code-text": "#e5e5e5", | 162 | "--color-md-user-code-text": "#f5f5f5", |
| 142 | "--color-md-user-fence-bg": "rgba(255, 255, 255, 0.09)", | 163 | "--color-md-user-fence-bg": "rgba(0, 0, 0, 0.28)", |
| 143 | "--color-md-user-fence-text": "#e5e5e5", | 164 | "--color-md-user-fence-text": "#f5f5f5", |
| 144 | "--color-md-hr": "rgba(255, 255, 255, 0.08)", | 165 | "--color-md-hr": "#191919", |
| 145 | "--color-user-bubble": "#171717", | 166 | "--color-user-bubble": "#161616", |
| 146 | "--color-user-bubble-foreground": "#f5f5f5", | 167 | "--color-user-bubble-foreground": "#f5f5f5", |
| 147 | "--color-user-bubble-foreground-muted": "rgba(245, 245, 245, 0.78)", | 168 | "--color-user-bubble-foreground-muted": "rgba(245, 245, 245, 0.78)", |
| 148 | "--color-user-bubble-skill-foreground": "#60a5fa", | 169 | "--color-user-bubble-skill-foreground": "#4678f2", |
| 149 | "--color-backdrop": "rgba(0, 0, 0, 0.48)", | 170 | "--color-backdrop": "rgba(0, 0, 0, 0.48)", |
| 150 | "--color-drawer": "rgba(14, 14, 14, 0.99)", | 171 | "--color-drawer": "#000000", |
| 172 | "--color-drawer-foreground": "#f1f3f7", | ||
| 173 | "--color-drawer-foreground-muted": "#a3a3a3", | ||
| 174 | "--color-drawer-border": "#141414", | ||
| 151 | "--color-drawer-shadow": "rgba(0, 0, 0, 0.32)", | 175 | "--color-drawer-shadow": "rgba(0, 0, 0, 0.32)", |
| 152 | "--color-dot-separator": "rgba(255, 255, 255, 0.2)", | 176 | "--color-dot-separator": "rgba(129, 129, 129, 0.35)", |
| 153 | "--color-wordmark": "#f5f5f5", | 177 | "--color-wordmark": "#f5f5f5", |
| 154 | "--color-chevron": "rgba(255, 255, 255, 0.2)" | 178 | "--color-chevron": "rgba(129, 129, 129, 0.42)" |
| 155 | } | 179 | } |
| 156 | } | 180 | } |
apps/mobile/generated-uniwind-themes.css+470-176| ... | @@ -2,6 +2,93 @@ | ... | @@ -2,6 +2,93 @@ |
| 2 | @layer theme { | 2 | @layer theme { |
| 3 | :root { | 3 | :root { |
| 4 | @variant light { | 4 | @variant light { |
| 5 | --color-screen: #fcfcfc; | ||
| 6 | --color-sheet: rgba(252, 252, 252, 0.98); | ||
| 7 | --color-sheet-solid: #fcfcfc; | ||
| 8 | --color-card: #ffffff; | ||
| 9 | --color-grouped-card: #f4f4f5; | ||
| 10 | --color-card-alt: #fcfcfc; | ||
| 11 | --color-card-translucent: rgba(255, 255, 255, 0.8); | ||
| 12 | --color-thread-canvas: #fcfcfc; | ||
| 13 | --color-thread-selected: #ffffff; | ||
| 14 | --color-thread-selected-foreground: #27272a; | ||
| 15 | --color-thread-selected-foreground-muted: #71717b; | ||
| 16 | --color-thread-hover: #fcfcfc; | ||
| 17 | --color-row-hover: #f4f4f5; | ||
| 18 | --color-composer-panel: rgba(252, 252, 252, 0.88); | ||
| 19 | --color-composer-surface: rgba(244, 244, 245, 0.94); | ||
| 20 | --color-composer-border: rgba(228, 228, 231, 0.8); | ||
| 21 | --color-foreground: #27272a; | ||
| 22 | --color-foreground-secondary: #6f6f79; | ||
| 23 | --color-foreground-muted: #6f6f79; | ||
| 24 | --color-foreground-tertiary: #71717b; | ||
| 25 | --color-border: #e4e4e7; | ||
| 26 | --color-focus: #1b4ed8; | ||
| 27 | --color-border-subtle: rgba(228, 228, 231, 0.7); | ||
| 28 | --color-separator: rgba(228, 228, 231, 0.55); | ||
| 29 | --color-subtle: #fafafa; | ||
| 30 | --color-subtle-strong: #fafafa; | ||
| 31 | --color-inline-skill-background: #f4f4f5; | ||
| 32 | --color-inline-skill-border: rgba(27, 78, 216, 0.42); | ||
| 33 | --color-inline-skill-foreground: #18181b; | ||
| 34 | --color-primary: #1b4ed8; | ||
| 35 | --color-primary-foreground: #ffffff; | ||
| 36 | --color-primary-text: #1b4ed8; | ||
| 37 | --color-primary-shadow: #000000; | ||
| 38 | --color-secondary: #fafafa; | ||
| 39 | --color-secondary-foreground: #27272a; | ||
| 40 | --color-secondary-border: #e4e4e7; | ||
| 41 | --color-switch-active-track: #1b4ed8; | ||
| 42 | --color-switch-active-thumb: #ffffff; | ||
| 43 | --color-switch-inactive-track: #fafafa; | ||
| 44 | --color-switch-inactive-thumb: #71717b; | ||
| 45 | --color-warning: #fcf4e8; | ||
| 46 | --color-warning-border: rgba(254, 154, 0, 0.32); | ||
| 47 | --color-warning-foreground: #bb4d00; | ||
| 48 | --color-danger: #fcebec; | ||
| 49 | --color-danger-border: rgba(251, 44, 54, 0.32); | ||
| 50 | --color-danger-foreground: #c10007; | ||
| 51 | --color-update: #e0e6f7; | ||
| 52 | --color-update-foreground: #1b4ed8; | ||
| 53 | --color-input: #ffffff; | ||
| 54 | --color-input-border: #d4d4d8; | ||
| 55 | --color-sidebar-search: #f4f4f5; | ||
| 56 | --color-placeholder: #6f6f79; | ||
| 57 | --color-icon: #27272a; | ||
| 58 | --color-icon-muted: #71717b; | ||
| 59 | --color-icon-subtle: #71717b; | ||
| 60 | --color-header: rgba(252, 252, 252, 0.97); | ||
| 61 | --color-header-foreground: #27272a; | ||
| 62 | --color-header-border: #e4e4e7; | ||
| 63 | --color-glass-surface: rgba(255, 255, 255, 0.74); | ||
| 64 | --color-glass-fallback: rgba(244, 244, 245, 0.94); | ||
| 65 | --color-glass-tint: rgba(255, 255, 255, 0.22); | ||
| 66 | --color-status-bar: #fcfcfc; | ||
| 67 | --color-md-body: #27272a; | ||
| 68 | --color-md-strong: #27272a; | ||
| 69 | --color-md-link: #1b4ed8; | ||
| 70 | --color-md-blockquote-border: #e4e4e7; | ||
| 71 | --color-md-blockquote-bg: #fafafa; | ||
| 72 | --color-md-code-bg: #ffffff; | ||
| 73 | --color-md-code-text: #27272a; | ||
| 74 | --color-md-user-code-bg: rgba(39, 39, 42, 0.18); | ||
| 75 | --color-md-user-code-text: #27272a; | ||
| 76 | --color-md-user-fence-bg: rgba(0, 0, 0, 0.16); | ||
| 77 | --color-md-user-fence-text: #27272a; | ||
| 78 | --color-md-hr: #e4e4e7; | ||
| 79 | --color-user-bubble: #efeff1; | ||
| 80 | --color-user-bubble-foreground: #27272a; | ||
| 81 | --color-user-bubble-foreground-muted: rgba(39, 39, 42, 0.78); | ||
| 82 | --color-user-bubble-skill-foreground: #1b4ed8; | ||
| 83 | --color-backdrop: rgba(0, 0, 0, 0.22); | ||
| 84 | --color-drawer: #fafafa; | ||
| 85 | --color-drawer-foreground: #27272a; | ||
| 86 | --color-drawer-foreground-muted: #71717b; | ||
| 87 | --color-drawer-border: #e4e4e7; | ||
| 88 | --color-drawer-shadow: rgba(0, 0, 0, 0.12); | ||
| 89 | --color-dot-separator: rgba(113, 113, 123, 0.35); | ||
| 90 | --color-wordmark: #27272a; | ||
| 91 | --color-chevron: rgba(113, 113, 123, 0.42); | ||
| 5 | --color-adaptive-amber-50-950-a40: oklch(98.7% 0.022 95.277); | 92 | --color-adaptive-amber-50-950-a40: oklch(98.7% 0.022 95.277); |
| 6 | --color-adaptive-amber-200-900-a60: oklch(92.4% 0.12 95.746); | 93 | --color-adaptive-amber-200-900-a60: oklch(92.4% 0.12 95.746); |
| 7 | --color-adaptive-amber-500-a12-a16: oklch(76.9% 0.188 70.08 / 12%); | 94 | --color-adaptive-amber-500-a12-a16: oklch(76.9% 0.188 70.08 / 12%); |
| ... | @@ -59,14 +146,101 @@ | ... | @@ -59,14 +146,101 @@ |
| 59 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); | 146 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); |
| 60 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); | 147 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); |
| 61 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); | 148 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); |
| 62 | --color-clerk-page: #f2f2f7; | 149 | --color-clerk-page: #fcfcfc; |
| 63 | --color-clerk-foreground: #262626; | 150 | --color-clerk-foreground: #27272a; |
| 64 | --color-clerk-foreground-muted: #737373; | 151 | --color-clerk-foreground-muted: #71717b; |
| 65 | --color-clerk-border: rgba(229, 229, 234, 0.06); | 152 | --color-clerk-border: #e4e4e7; |
| 66 | --color-clerk-danger: #dc2626; | 153 | --color-clerk-danger: #c10007; |
| 67 | } | 154 | } |
| 68 | 155 | ||
| 69 | @variant dark { | 156 | @variant dark { |
| 157 | --color-screen: #0a0a0a; | ||
| 158 | --color-sheet: rgba(10, 10, 10, 0.98); | ||
| 159 | --color-sheet-solid: #0a0a0a; | ||
| 160 | --color-card: #111111; | ||
| 161 | --color-grouped-card: #1a1b1b; | ||
| 162 | --color-card-alt: #111111; | ||
| 163 | --color-card-translucent: rgba(17, 17, 17, 0.8); | ||
| 164 | --color-thread-canvas: #0a0a0a; | ||
| 165 | --color-thread-selected: #1a1b1b; | ||
| 166 | --color-thread-selected-foreground: #f1f3f7; | ||
| 167 | --color-thread-selected-foreground-muted: #a3a3a3; | ||
| 168 | --color-thread-hover: #131313; | ||
| 169 | --color-row-hover: #141414; | ||
| 170 | --color-composer-panel: rgba(10, 10, 10, 0.92); | ||
| 171 | --color-composer-surface: rgba(26, 27, 27, 0.9); | ||
| 172 | --color-composer-border: rgba(25, 25, 25, 0.8); | ||
| 173 | --color-foreground: #f5f5f5; | ||
| 174 | --color-foreground-secondary: #838383; | ||
| 175 | --color-foreground-muted: #838383; | ||
| 176 | --color-foreground-tertiary: #818181; | ||
| 177 | --color-border: #191919; | ||
| 178 | --color-focus: #346bf1; | ||
| 179 | --color-border-subtle: rgba(25, 25, 25, 0.7); | ||
| 180 | --color-separator: rgba(25, 25, 25, 0.55); | ||
| 181 | --color-subtle: #111111; | ||
| 182 | --color-subtle-strong: #111111; | ||
| 183 | --color-inline-skill-background: #141414; | ||
| 184 | --color-inline-skill-border: rgba(52, 107, 241, 0.42); | ||
| 185 | --color-inline-skill-foreground: #f5f5f5; | ||
| 186 | --color-primary: #346bf1; | ||
| 187 | --color-primary-foreground: #ffffff; | ||
| 188 | --color-primary-text: #4b7cf3; | ||
| 189 | --color-primary-shadow: #000000; | ||
| 190 | --color-secondary: #111111; | ||
| 191 | --color-secondary-foreground: #f5f5f5; | ||
| 192 | --color-secondary-border: #191919; | ||
| 193 | --color-switch-active-track: #346bf1; | ||
| 194 | --color-switch-active-thumb: #ffffff; | ||
| 195 | --color-switch-inactive-track: #111111; | ||
| 196 | --color-switch-inactive-thumb: #818181; | ||
| 197 | --color-warning: #312108; | ||
| 198 | --color-warning-border: rgba(254, 154, 0, 0.32); | ||
| 199 | --color-warning-foreground: #ffb900; | ||
| 200 | --color-danger: #301214; | ||
| 201 | --color-danger-border: rgba(251, 65, 74, 0.32); | ||
| 202 | --color-danger-foreground: #ff6467; | ||
| 203 | --color-update: #121b34; | ||
| 204 | --color-update-foreground: #51a2ff; | ||
| 205 | --color-input: #111111; | ||
| 206 | --color-input-border: #1e1e1e; | ||
| 207 | --color-sidebar-search: #0a0a0a; | ||
| 208 | --color-placeholder: #838383; | ||
| 209 | --color-icon: #f5f5f5; | ||
| 210 | --color-icon-muted: #818181; | ||
| 211 | --color-icon-subtle: #818181; | ||
| 212 | --color-header: rgba(10, 10, 10, 0.97); | ||
| 213 | --color-header-foreground: #f5f5f5; | ||
| 214 | --color-header-border: #191919; | ||
| 215 | --color-glass-surface: rgba(17, 17, 17, 0.74); | ||
| 216 | --color-glass-fallback: rgba(26, 27, 27, 0.9); | ||
| 217 | --color-glass-tint: rgba(17, 17, 17, 0.22); | ||
| 218 | --color-status-bar: #0a0a0a; | ||
| 219 | --color-md-body: #f5f5f5; | ||
| 220 | --color-md-strong: #f5f5f5; | ||
| 221 | --color-md-link: #3b70f1; | ||
| 222 | --color-md-blockquote-border: #191919; | ||
| 223 | --color-md-blockquote-bg: #111111; | ||
| 224 | --color-md-code-bg: #111111; | ||
| 225 | --color-md-code-text: #f5f5f5; | ||
| 226 | --color-md-user-code-bg: rgba(245, 245, 245, 0.18); | ||
| 227 | --color-md-user-code-text: #f5f5f5; | ||
| 228 | --color-md-user-fence-bg: rgba(0, 0, 0, 0.28); | ||
| 229 | --color-md-user-fence-text: #f5f5f5; | ||
| 230 | --color-md-hr: #191919; | ||
| 231 | --color-user-bubble: #161616; | ||
| 232 | --color-user-bubble-foreground: #f5f5f5; | ||
| 233 | --color-user-bubble-foreground-muted: rgba(245, 245, 245, 0.78); | ||
| 234 | --color-user-bubble-skill-foreground: #4678f2; | ||
| 235 | --color-backdrop: rgba(0, 0, 0, 0.48); | ||
| 236 | --color-drawer: #000000; | ||
| 237 | --color-drawer-foreground: #f1f3f7; | ||
| 238 | --color-drawer-foreground-muted: #a3a3a3; | ||
| 239 | --color-drawer-border: #141414; | ||
| 240 | --color-drawer-shadow: rgba(0, 0, 0, 0.32); | ||
| 241 | --color-dot-separator: rgba(129, 129, 129, 0.35); | ||
| 242 | --color-wordmark: #f5f5f5; | ||
| 243 | --color-chevron: rgba(129, 129, 129, 0.42); | ||
| 70 | --color-adaptive-amber-50-950-a40: oklch(27.9% 0.077 45.635 / 40%); | 244 | --color-adaptive-amber-50-950-a40: oklch(27.9% 0.077 45.635 / 40%); |
| 71 | --color-adaptive-amber-200-900-a60: oklch(41.4% 0.112 45.904 / 60%); | 245 | --color-adaptive-amber-200-900-a60: oklch(41.4% 0.112 45.904 / 60%); |
| 72 | --color-adaptive-amber-500-a12-a16: oklch(76.9% 0.188 70.08 / 16%); | 246 | --color-adaptive-amber-500-a12-a16: oklch(76.9% 0.188 70.08 / 16%); |
| ... | @@ -124,32 +298,36 @@ | ... | @@ -124,32 +298,36 @@ |
| 124 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); | 298 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); |
| 125 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); | 299 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); |
| 126 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); | 300 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); |
| 127 | --color-clerk-page: #0e0e0e; | 301 | --color-clerk-page: #0a0a0a; |
| 128 | --color-clerk-foreground: #f5f5f5; | 302 | --color-clerk-foreground: #f5f5f5; |
| 129 | --color-clerk-foreground-muted: #a3a3a3; | 303 | --color-clerk-foreground-muted: #818181; |
| 130 | --color-clerk-border: rgba(42, 42, 42, 0.06); | 304 | --color-clerk-border: #191919; |
| 131 | --color-clerk-danger: #fca5a5; | 305 | --color-clerk-danger: #ff6467; |
| 132 | } | 306 | } |
| 133 | 307 | ||
| 134 | @variant t3-chat-light { | 308 | @variant t3-chat-light { |
| 135 | --color-screen: #fdf7fd; | 309 | --color-screen: #fdf7fd; |
| 136 | --color-sheet: rgba(253, 247, 253, 0.98); | 310 | --color-sheet: rgba(253, 247, 253, 0.98); |
| 137 | --color-sheet-solid: #fdf7fd; | 311 | --color-sheet-solid: #fdf7fd; |
| 138 | --color-card: #fdfafd; | 312 | --color-card: #faf3fb; |
| 139 | --color-card-alt: #faf3fb; | 313 | --color-grouped-card: #faf3fb; |
| 140 | --color-card-translucent: rgba(253, 250, 253, 0.8); | 314 | --color-card-alt: #fdfafd; |
| 141 | --color-thread-canvas: #faf3fb; | 315 | --color-card-translucent: rgba(250, 243, 251, 0.8); |
| 142 | --color-thread-selected: #fdfafd; | 316 | --color-thread-canvas: #fdf7fd; |
| 143 | --color-thread-selected-foreground: #501854; | 317 | --color-thread-selected: #f8f8f7; |
| 318 | --color-thread-selected-foreground: #454554; | ||
| 144 | --color-thread-selected-foreground-muted: #ac1668; | 319 | --color-thread-selected-foreground-muted: #ac1668; |
| 145 | --color-composer-panel: rgba(250, 243, 251, 0.88); | 320 | --color-thread-hover: #f8f8f7; |
| 146 | --color-composer-surface: rgba(253, 250, 253, 0.94); | 321 | --color-row-hover: #eccfe3; |
| 322 | --color-composer-panel: rgba(253, 247, 253, 0.88); | ||
| 323 | --color-composer-surface: rgba(250, 243, 251, 0.94); | ||
| 147 | --color-composer-border: rgba(238, 225, 237, 0.54); | 324 | --color-composer-border: rgba(238, 225, 237, 0.54); |
| 148 | --color-foreground: #501854; | 325 | --color-foreground: #501854; |
| 149 | --color-foreground-secondary: #ac1668; | 326 | --color-foreground-secondary: #ac1668; |
| 150 | --color-foreground-muted: #8d1255; | 327 | --color-foreground-muted: #8d1255; |
| 151 | --color-foreground-tertiary: #ac1668; | 328 | --color-foreground-tertiary: #ac1668; |
| 152 | --color-border: #eee1ed; | 329 | --color-border: #eee1ed; |
| 330 | --color-focus: #db2777; | ||
| 153 | --color-border-subtle: rgba(238, 225, 237, 0.7); | 331 | --color-border-subtle: rgba(238, 225, 237, 0.7); |
| 154 | --color-separator: rgba(238, 225, 237, 0.55); | 332 | --color-separator: rgba(238, 225, 237, 0.55); |
| 155 | --color-subtle: #eaa7cb; | 333 | --color-subtle: #eaa7cb; |
| ... | @@ -159,6 +337,7 @@ | ... | @@ -159,6 +337,7 @@ |
| 159 | --color-inline-skill-foreground: #454554; | 337 | --color-inline-skill-foreground: #454554; |
| 160 | --color-primary: #db2777; | 338 | --color-primary: #db2777; |
| 161 | --color-primary-foreground: #ffffff; | 339 | --color-primary-foreground: #ffffff; |
| 340 | --color-primary-text: #d32572; | ||
| 162 | --color-primary-shadow: #000000; | 341 | --color-primary-shadow: #000000; |
| 163 | --color-secondary: #f1c4e6; | 342 | --color-secondary: #f1c4e6; |
| 164 | --color-secondary-foreground: #77347c; | 343 | --color-secondary-foreground: #77347c; |
| ... | @@ -173,7 +352,9 @@ | ... | @@ -173,7 +352,9 @@ |
| 173 | --color-danger: #fde4f1; | 352 | --color-danger: #fde4f1; |
| 174 | --color-danger-border: rgba(247, 8, 108, 0.32); | 353 | --color-danger-border: rgba(247, 8, 108, 0.32); |
| 175 | --color-danger-foreground: #9d174d; | 354 | --color-danger-foreground: #9d174d; |
| 176 | --color-input: #fdfafd; | 355 | --color-update: #fadfef; |
| 356 | --color-update-foreground: #ac1668; | ||
| 357 | --color-input: #faf3fb; | ||
| 177 | --color-input-border: #e7c1dc; | 358 | --color-input-border: #e7c1dc; |
| 178 | --color-sidebar-search: #f8f8f7; | 359 | --color-sidebar-search: #f8f8f7; |
| 179 | --color-placeholder: #8b5f90; | 360 | --color-placeholder: #8b5f90; |
| ... | @@ -181,13 +362,15 @@ | ... | @@ -181,13 +362,15 @@ |
| 181 | --color-icon-muted: #ac1668; | 362 | --color-icon-muted: #ac1668; |
| 182 | --color-icon-subtle: #ac1668; | 363 | --color-icon-subtle: #ac1668; |
| 183 | --color-header: rgba(253, 247, 253, 0.97); | 364 | --color-header: rgba(253, 247, 253, 0.97); |
| 365 | --color-header-foreground: #501854; | ||
| 184 | --color-header-border: #efbdeb; | 366 | --color-header-border: #efbdeb; |
| 185 | --color-glass-surface: rgba(255, 255, 255, 0.74); | 367 | --color-glass-surface: rgba(255, 255, 255, 0.74); |
| 368 | --color-glass-fallback: rgba(250, 243, 251, 0.94); | ||
| 186 | --color-glass-tint: rgba(255, 255, 255, 0.22); | 369 | --color-glass-tint: rgba(255, 255, 255, 0.22); |
| 187 | --color-status-bar: #fdf7fd; | 370 | --color-status-bar: #fdf7fd; |
| 188 | --color-md-body: #501854; | 371 | --color-md-body: #501854; |
| 189 | --color-md-strong: #501854; | 372 | --color-md-strong: #501854; |
| 190 | --color-md-link: #db2777; | 373 | --color-md-link: #d62675; |
| 191 | --color-md-blockquote-border: #eee1ed; | 374 | --color-md-blockquote-border: #eee1ed; |
| 192 | --color-md-blockquote-bg: #eaa7cb; | 375 | --color-md-blockquote-bg: #eaa7cb; |
| 193 | --color-md-code-bg: #f5ecf9; | 376 | --color-md-code-bg: #f5ecf9; |
| ... | @@ -202,7 +385,10 @@ | ... | @@ -202,7 +385,10 @@ |
| 202 | --color-user-bubble-foreground-muted: rgba(73, 44, 97, 0.78); | 385 | --color-user-bubble-foreground-muted: rgba(73, 44, 97, 0.78); |
| 203 | --color-user-bubble-skill-foreground: #c12269; | 386 | --color-user-bubble-skill-foreground: #c12269; |
| 204 | --color-backdrop: rgba(0, 0, 0, 0.22); | 387 | --color-backdrop: rgba(0, 0, 0, 0.22); |
| 205 | --color-drawer: rgba(242, 225, 244, 0.99); | 388 | --color-drawer: #f2e1f4; |
| 389 | --color-drawer-foreground: #454554; | ||
| 390 | --color-drawer-foreground-muted: #ac1668; | ||
| 391 | --color-drawer-border: #eceae9; | ||
| 206 | --color-drawer-shadow: rgba(0, 0, 0, 0.12); | 392 | --color-drawer-shadow: rgba(0, 0, 0, 0.12); |
| 207 | --color-dot-separator: rgba(172, 22, 104, 0.35); | 393 | --color-dot-separator: rgba(172, 22, 104, 0.35); |
| 208 | --color-wordmark: #501854; | 394 | --color-wordmark: #501854; |
| ... | @@ -264,32 +450,36 @@ | ... | @@ -264,32 +450,36 @@ |
| 264 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); | 450 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); |
| 265 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); | 451 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); |
| 266 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); | 452 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); |
| 267 | --color-clerk-page: #f2f2f7; | 453 | --color-clerk-page: #fcfcfc; |
| 268 | --color-clerk-foreground: #262626; | 454 | --color-clerk-foreground: #27272a; |
| 269 | --color-clerk-foreground-muted: #737373; | 455 | --color-clerk-foreground-muted: #71717b; |
| 270 | --color-clerk-border: rgba(229, 229, 234, 0.06); | 456 | --color-clerk-border: #e4e4e7; |
| 271 | --color-clerk-danger: #dc2626; | 457 | --color-clerk-danger: #c10007; |
| 272 | } | 458 | } |
| 273 | 459 | ||
| 274 | @variant t3-chat-dark { | 460 | @variant t3-chat-dark { |
| 275 | --color-screen: #1f1a24; | 461 | --color-screen: #1f1a24; |
| 276 | --color-sheet: rgba(31, 26, 36, 0.98); | 462 | --color-sheet: rgba(31, 26, 36, 0.98); |
| 277 | --color-sheet-solid: #1f1a24; | 463 | --color-sheet-solid: #1f1a24; |
| 278 | --color-card: #2c2631; | 464 | --color-card: #29232d; |
| 279 | --color-card-alt: #29232d; | 465 | --color-grouped-card: #29232d; |
| 280 | --color-card-translucent: rgba(44, 38, 49, 0.8); | 466 | --color-card-alt: #2c2631; |
| 281 | --color-thread-canvas: #29232d; | 467 | --color-card-translucent: rgba(41, 35, 45, 0.8); |
| 282 | --color-thread-selected: #2c2631; | 468 | --color-thread-canvas: #1f1a24; |
| 283 | --color-thread-selected-foreground: #f9f8fb; | 469 | --color-thread-selected: #261922; |
| 470 | --color-thread-selected-foreground: #f4f4f5; | ||
| 284 | --color-thread-selected-foreground-muted: #e7d0dd; | 471 | --color-thread-selected-foreground-muted: #e7d0dd; |
| 285 | --color-composer-panel: rgba(41, 35, 45, 0.92); | 472 | --color-thread-hover: #261922; |
| 286 | --color-composer-surface: rgba(44, 38, 49, 0.9); | 473 | --color-row-hover: #463753; |
| 474 | --color-composer-panel: rgba(31, 26, 36, 0.92); | ||
| 475 | --color-composer-surface: rgba(41, 35, 45, 0.9); | ||
| 287 | --color-composer-border: rgba(39, 36, 44, 0.46); | 476 | --color-composer-border: rgba(39, 36, 44, 0.46); |
| 288 | --color-foreground: #f9f8fb; | 477 | --color-foreground: #f9f8fb; |
| 289 | --color-foreground-secondary: #e7d0dd; | 478 | --color-foreground-secondary: #e7d0dd; |
| 290 | --color-foreground-muted: #e7d0dd; | 479 | --color-foreground-muted: #e7d0dd; |
| 291 | --color-foreground-tertiary: #e7d0dd; | 480 | --color-foreground-tertiary: #e7d0dd; |
| 292 | --color-border: #27242c; | 481 | --color-border: #27242c; |
| 482 | --color-focus: #db2777; | ||
| 293 | --color-border-subtle: rgba(39, 36, 44, 0.7); | 483 | --color-border-subtle: rgba(39, 36, 44, 0.7); |
| 294 | --color-separator: rgba(39, 36, 44, 0.55); | 484 | --color-separator: rgba(39, 36, 44, 0.55); |
| 295 | --color-subtle: #423a45; | 485 | --color-subtle: #423a45; |
| ... | @@ -299,6 +489,7 @@ | ... | @@ -299,6 +489,7 @@ |
| 299 | --color-inline-skill-foreground: #f8f1f5; | 489 | --color-inline-skill-foreground: #f8f1f5; |
| 300 | --color-primary: #a3004c; | 490 | --color-primary: #a3004c; |
| 301 | --color-primary-foreground: #fbd0e8; | 491 | --color-primary-foreground: #fbd0e8; |
| 492 | --color-primary-text: #cc729c; | ||
| 302 | --color-primary-shadow: #000000; | 493 | --color-primary-shadow: #000000; |
| 303 | --color-secondary: #362d3d; | 494 | --color-secondary: #362d3d; |
| 304 | --color-secondary-foreground: #d4c7e1; | 495 | --color-secondary-foreground: #d4c7e1; |
| ... | @@ -313,7 +504,9 @@ | ... | @@ -313,7 +504,9 @@ |
| 313 | --color-danger: #331a2b; | 504 | --color-danger: #331a2b; |
| 314 | --color-danger-border: rgba(157, 23, 77, 0.32); | 505 | --color-danger-border: rgba(157, 23, 77, 0.32); |
| 315 | --color-danger-foreground: #fbd0e8; | 506 | --color-danger-foreground: #fbd0e8; |
| 316 | --color-input: #2c2631; | 507 | --color-update: #37152b; |
| 508 | --color-update-foreground: #fbd0e8; | ||
| 509 | --color-input: #29232d; | ||
| 317 | --color-input-border: #302029; | 510 | --color-input-border: #302029; |
| 318 | --color-sidebar-search: #261922; | 511 | --color-sidebar-search: #261922; |
| 319 | --color-placeholder: #968d9f; | 512 | --color-placeholder: #968d9f; |
| ... | @@ -321,13 +514,15 @@ | ... | @@ -321,13 +514,15 @@ |
| 321 | --color-icon-muted: #d4c7e1; | 514 | --color-icon-muted: #d4c7e1; |
| 322 | --color-icon-subtle: #e7d0dd; | 515 | --color-icon-subtle: #e7d0dd; |
| 323 | --color-header: rgba(31, 26, 36, 0.97); | 516 | --color-header: rgba(31, 26, 36, 0.97); |
| 517 | --color-header-foreground: #f9f8fb; | ||
| 324 | --color-header-border: #27242c; | 518 | --color-header-border: #27242c; |
| 325 | --color-glass-surface: rgba(16, 10, 14, 0.74); | 519 | --color-glass-surface: rgba(16, 10, 14, 0.74); |
| 520 | --color-glass-fallback: rgba(41, 35, 45, 0.9); | ||
| 326 | --color-glass-tint: rgba(16, 10, 14, 0.22); | 521 | --color-glass-tint: rgba(16, 10, 14, 0.22); |
| 327 | --color-status-bar: #1f1a24; | 522 | --color-status-bar: #1f1a24; |
| 328 | --color-md-body: #f9f8fb; | 523 | --color-md-body: #f9f8fb; |
| 329 | --color-md-strong: #f9f8fb; | 524 | --color-md-strong: #f9f8fb; |
| 330 | --color-md-link: #a3004c; | 525 | --color-md-link: #c66290; |
| 331 | --color-md-blockquote-border: #27242c; | 526 | --color-md-blockquote-border: #27242c; |
| 332 | --color-md-blockquote-bg: #423a45; | 527 | --color-md-blockquote-bg: #423a45; |
| 333 | --color-md-code-bg: #1f1a24; | 528 | --color-md-code-bg: #1f1a24; |
| ... | @@ -342,7 +537,10 @@ | ... | @@ -342,7 +537,10 @@ |
| 342 | --color-user-bubble-foreground-muted: rgba(242, 235, 250, 0.78); | 537 | --color-user-bubble-foreground-muted: rgba(242, 235, 250, 0.78); |
| 343 | --color-user-bubble-skill-foreground: #cb709a; | 538 | --color-user-bubble-skill-foreground: #cb709a; |
| 344 | --color-backdrop: rgba(0, 0, 0, 0.48); | 539 | --color-backdrop: rgba(0, 0, 0, 0.48); |
| 345 | --color-drawer: rgba(23, 16, 24, 0.99); | 540 | --color-drawer: #171018; |
| 541 | --color-drawer-foreground: #f4f4f5; | ||
| 542 | --color-drawer-foreground-muted: #e7d0dd; | ||
| 543 | --color-drawer-border: #322028; | ||
| 346 | --color-drawer-shadow: rgba(0, 0, 0, 0.32); | 544 | --color-drawer-shadow: rgba(0, 0, 0, 0.32); |
| 347 | --color-dot-separator: rgba(231, 208, 221, 0.35); | 545 | --color-dot-separator: rgba(231, 208, 221, 0.35); |
| 348 | --color-wordmark: #f9f8fb; | 546 | --color-wordmark: #f9f8fb; |
| ... | @@ -404,32 +602,36 @@ | ... | @@ -404,32 +602,36 @@ |
| 404 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); | 602 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); |
| 405 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); | 603 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); |
| 406 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); | 604 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); |
| 407 | --color-clerk-page: #0e0e0e; | 605 | --color-clerk-page: #0a0a0a; |
| 408 | --color-clerk-foreground: #f5f5f5; | 606 | --color-clerk-foreground: #f5f5f5; |
| 409 | --color-clerk-foreground-muted: #a3a3a3; | 607 | --color-clerk-foreground-muted: #818181; |
| 410 | --color-clerk-border: rgba(42, 42, 42, 0.06); | 608 | --color-clerk-border: #191919; |
| 411 | --color-clerk-danger: #fca5a5; | 609 | --color-clerk-danger: #ff6467; |
| 412 | } | 610 | } |
| 413 | 611 | ||
| 414 | @variant grove-light { | 612 | @variant grove-light { |
| 415 | --color-screen: #f3f7f4; | 613 | --color-screen: #f3f7f4; |
| 416 | --color-sheet: rgba(243, 247, 244, 0.98); | 614 | --color-sheet: rgba(243, 247, 244, 0.98); |
| 417 | --color-sheet-solid: #f3f7f4; | 615 | --color-sheet-solid: #f3f7f4; |
| 418 | --color-card: #ecefed; | 616 | --color-card: #f3f7f4; |
| 419 | --color-card-alt: #f3f7f4; | 617 | --color-grouped-card: #f3f7f4; |
| 420 | --color-card-translucent: rgba(236, 239, 237, 0.8); | 618 | --color-card-alt: #ecefed; |
| 619 | --color-card-translucent: rgba(243, 247, 244, 0.8); | ||
| 421 | --color-thread-canvas: #f3f7f4; | 620 | --color-thread-canvas: #f3f7f4; |
| 422 | --color-thread-selected: #ecefed; | 621 | --color-thread-selected: #bad7c9; |
| 423 | --color-thread-selected-foreground: #241523; | 622 | --color-thread-selected-foreground: #241523; |
| 424 | --color-thread-selected-foreground-muted: #746c73; | 623 | --color-thread-selected-foreground-muted: #5d585e; |
| 624 | --color-thread-hover: #cae0d5; | ||
| 625 | --color-row-hover: #d5e6dd; | ||
| 425 | --color-composer-panel: rgba(243, 247, 244, 0.88); | 626 | --color-composer-panel: rgba(243, 247, 244, 0.88); |
| 426 | --color-composer-surface: rgba(236, 239, 237, 0.94); | 627 | --color-composer-surface: rgba(243, 247, 244, 0.94); |
| 427 | --color-composer-border: rgba(203, 213, 209, 0.54); | 628 | --color-composer-border: rgba(203, 213, 209, 0.54); |
| 428 | --color-foreground: #241523; | 629 | --color-foreground: #241523; |
| 429 | --color-foreground-secondary: #746c73; | 630 | --color-foreground-secondary: #726a71; |
| 430 | --color-foreground-muted: #6e696f; | 631 | --color-foreground-muted: #6e696f; |
| 431 | --color-foreground-tertiary: #746c73; | 632 | --color-foreground-tertiary: #746c73; |
| 432 | --color-border: #cbd5d1; | 633 | --color-border: #cbd5d1; |
| 634 | --color-focus: #1b7d50; | ||
| 433 | --color-border-subtle: rgba(203, 213, 209, 0.7); | 635 | --color-border-subtle: rgba(203, 213, 209, 0.7); |
| 434 | --color-separator: rgba(203, 213, 209, 0.55); | 636 | --color-separator: rgba(203, 213, 209, 0.55); |
| 435 | --color-subtle: #e6f0ea; | 637 | --color-subtle: #e6f0ea; |
| ... | @@ -437,13 +639,14 @@ | ... | @@ -437,13 +639,14 @@ |
| 437 | --color-inline-skill-background: #d5e6dd; | 639 | --color-inline-skill-background: #d5e6dd; |
| 438 | --color-inline-skill-border: rgba(27, 125, 80, 0.42); | 640 | --color-inline-skill-border: rgba(27, 125, 80, 0.42); |
| 439 | --color-inline-skill-foreground: #241523; | 641 | --color-inline-skill-foreground: #241523; |
| 440 | --color-primary: #1b7d50; | 642 | --color-primary: #8f6410; |
| 441 | --color-primary-foreground: #fffaff; | 643 | --color-primary-foreground: #fffaff; |
| 644 | --color-primary-text: #8f6410; | ||
| 442 | --color-primary-shadow: #000000; | 645 | --color-primary-shadow: #000000; |
| 443 | --color-secondary: #e2ede7; | 646 | --color-secondary: #e2ede7; |
| 444 | --color-secondary-foreground: #241523; | 647 | --color-secondary-foreground: #241523; |
| 445 | --color-secondary-border: #cbd5d1; | 648 | --color-secondary-border: #cbd5d1; |
| 446 | --color-switch-active-track: #1b7d50; | 649 | --color-switch-active-track: #8f6410; |
| 447 | --color-switch-active-thumb: #fffaff; | 650 | --color-switch-active-thumb: #fffaff; |
| 448 | --color-switch-inactive-track: #e2ede7; | 651 | --color-switch-inactive-track: #e2ede7; |
| 449 | --color-switch-inactive-thumb: #6e696f; | 652 | --color-switch-inactive-thumb: #6e696f; |
| ... | @@ -453,7 +656,9 @@ | ... | @@ -453,7 +656,9 @@ |
| 453 | --color-danger: #f4e7e5; | 656 | --color-danger: #f4e7e5; |
| 454 | --color-danger-border: rgba(251, 44, 54, 0.32); | 657 | --color-danger-border: rgba(251, 44, 54, 0.32); |
| 455 | --color-danger-foreground: #c10007; | 658 | --color-danger-foreground: #c10007; |
| 456 | --color-input: #ecefed; | 659 | --color-update: #d0e3da; |
| 660 | --color-update-foreground: #125134; | ||
| 661 | --color-input: #f3f7f4; | ||
| 457 | --color-input-border: #becbc5; | 662 | --color-input-border: #becbc5; |
| 458 | --color-sidebar-search: #d3dcd8; | 663 | --color-sidebar-search: #d3dcd8; |
| 459 | --color-placeholder: #716971; | 664 | --color-placeholder: #716971; |
| ... | @@ -461,13 +666,15 @@ | ... | @@ -461,13 +666,15 @@ |
| 461 | --color-icon-muted: #746c73; | 666 | --color-icon-muted: #746c73; |
| 462 | --color-icon-subtle: #746c73; | 667 | --color-icon-subtle: #746c73; |
| 463 | --color-header: rgba(243, 247, 244, 0.97); | 668 | --color-header: rgba(243, 247, 244, 0.97); |
| 669 | --color-header-foreground: #241523; | ||
| 464 | --color-header-border: #d5e6dd; | 670 | --color-header-border: #d5e6dd; |
| 465 | --color-glass-surface: rgba(231, 233, 232, 0.74); | 671 | --color-glass-surface: rgba(231, 233, 232, 0.74); |
| 672 | --color-glass-fallback: rgba(243, 247, 244, 0.94); | ||
| 466 | --color-glass-tint: rgba(231, 233, 232, 0.22); | 673 | --color-glass-tint: rgba(231, 233, 232, 0.22); |
| 467 | --color-status-bar: #f3f7f4; | 674 | --color-status-bar: #f3f7f4; |
| 468 | --color-md-body: #241523; | 675 | --color-md-body: #241523; |
| 469 | --color-md-strong: #241523; | 676 | --color-md-strong: #241523; |
| 470 | --color-md-link: #1b7d50; | 677 | --color-md-link: #8f6410; |
| 471 | --color-md-blockquote-border: #cbd5d1; | 678 | --color-md-blockquote-border: #cbd5d1; |
| 472 | --color-md-blockquote-bg: #e6f0ea; | 679 | --color-md-blockquote-bg: #e6f0ea; |
| 473 | --color-md-code-bg: #eef1ef; | 680 | --color-md-code-bg: #eef1ef; |
| ... | @@ -482,7 +689,10 @@ | ... | @@ -482,7 +689,10 @@ |
| 482 | --color-user-bubble-foreground-muted: rgba(36, 21, 35, 0.78); | 689 | --color-user-bubble-foreground-muted: rgba(36, 21, 35, 0.78); |
| 483 | --color-user-bubble-skill-foreground: #815a0e; | 690 | --color-user-bubble-skill-foreground: #815a0e; |
| 484 | --color-backdrop: rgba(0, 0, 0, 0.22); | 691 | --color-backdrop: rgba(0, 0, 0, 0.22); |
| 485 | --color-drawer: rgba(226, 237, 231, 0.99); | 692 | --color-drawer: #e2ede7; |
| 693 | --color-drawer-foreground: #241523; | ||
| 694 | --color-drawer-foreground-muted: #645f64; | ||
| 695 | --color-drawer-border: #cbd3d0; | ||
| 486 | --color-drawer-shadow: rgba(0, 0, 0, 0.12); | 696 | --color-drawer-shadow: rgba(0, 0, 0, 0.12); |
| 487 | --color-dot-separator: rgba(116, 108, 115, 0.35); | 697 | --color-dot-separator: rgba(116, 108, 115, 0.35); |
| 488 | --color-wordmark: #241523; | 698 | --color-wordmark: #241523; |
| ... | @@ -544,32 +754,36 @@ | ... | @@ -544,32 +754,36 @@ |
| 544 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); | 754 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); |
| 545 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); | 755 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); |
| 546 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); | 756 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); |
| 547 | --color-clerk-page: #f2f2f7; | 757 | --color-clerk-page: #fcfcfc; |
| 548 | --color-clerk-foreground: #262626; | 758 | --color-clerk-foreground: #27272a; |
| 549 | --color-clerk-foreground-muted: #737373; | 759 | --color-clerk-foreground-muted: #71717b; |
| 550 | --color-clerk-border: rgba(229, 229, 234, 0.06); | 760 | --color-clerk-border: #e4e4e7; |
| 551 | --color-clerk-danger: #dc2626; | 761 | --color-clerk-danger: #c10007; |
| 552 | } | 762 | } |
| 553 | 763 | ||
| 554 | @variant grove-dark { | 764 | @variant grove-dark { |
| 555 | --color-screen: #1b2821; | 765 | --color-screen: #1b2821; |
| 556 | --color-sheet: rgba(27, 40, 33, 0.98); | 766 | --color-sheet: rgba(27, 40, 33, 0.98); |
| 557 | --color-sheet-solid: #1b2821; | 767 | --color-sheet-solid: #1b2821; |
| 558 | --color-card: #36413c; | 768 | --color-card: #1b2821; |
| 559 | --color-card-alt: #1b2821; | 769 | --color-grouped-card: #1b2821; |
| 560 | --color-card-translucent: rgba(54, 65, 60, 0.8); | 770 | --color-card-alt: #36413c; |
| 771 | --color-card-translucent: rgba(27, 40, 33, 0.8); | ||
| 561 | --color-thread-canvas: #1b2821; | 772 | --color-thread-canvas: #1b2821; |
| 562 | --color-thread-selected: #36413c; | 773 | --color-thread-selected: #2f5641; |
| 563 | --color-thread-selected-foreground: #fffaff; | 774 | --color-thread-selected-foreground: #fffaff; |
| 564 | --color-thread-selected-foreground-muted: #919595; | 775 | --color-thread-selected-foreground-muted: #bbc0bf; |
| 776 | --color-thread-hover: #2a4938; | ||
| 777 | --color-row-hover: #325c46; | ||
| 565 | --color-composer-panel: rgba(27, 40, 33, 0.92); | 778 | --color-composer-panel: rgba(27, 40, 33, 0.92); |
| 566 | --color-composer-surface: rgba(54, 65, 60, 0.9); | 779 | --color-composer-surface: rgba(27, 40, 33, 0.9); |
| 567 | --color-composer-border: rgba(65, 95, 79, 0.46); | 780 | --color-composer-border: rgba(65, 95, 79, 0.46); |
| 568 | --color-foreground: #fffaff; | 781 | --color-foreground: #fffaff; |
| 569 | --color-foreground-secondary: #919595; | 782 | --color-foreground-secondary: #a6aaaa; |
| 570 | --color-foreground-muted: #9da5a2; | 783 | --color-foreground-muted: #a3aba8; |
| 571 | --color-foreground-tertiary: #919595; | 784 | --color-foreground-tertiary: #919595; |
| 572 | --color-border: #415f4f; | 785 | --color-border: #415f4f; |
| 786 | --color-focus: #69d69a; | ||
| 573 | --color-border-subtle: rgba(65, 95, 79, 0.7); | 787 | --color-border-subtle: rgba(65, 95, 79, 0.7); |
| 574 | --color-separator: rgba(65, 95, 79, 0.55); | 788 | --color-separator: rgba(65, 95, 79, 0.55); |
| 575 | --color-subtle: #253e31; | 789 | --color-subtle: #253e31; |
| ... | @@ -577,13 +791,14 @@ | ... | @@ -577,13 +791,14 @@ |
| 577 | --color-inline-skill-background: #325c46; | 791 | --color-inline-skill-background: #325c46; |
| 578 | --color-inline-skill-border: rgba(105, 214, 154, 0.42); | 792 | --color-inline-skill-border: rgba(105, 214, 154, 0.42); |
| 579 | --color-inline-skill-foreground: #fffaff; | 793 | --color-inline-skill-foreground: #fffaff; |
| 580 | --color-primary: #69d69a; | 794 | --color-primary: #e3b34e; |
| 581 | --color-primary-foreground: #241523; | 795 | --color-primary-foreground: #241523; |
| 796 | --color-primary-text: #e3b34e; | ||
| 582 | --color-primary-shadow: #000000; | 797 | --color-primary-shadow: #000000; |
| 583 | --color-secondary: #2a4b39; | 798 | --color-secondary: #2a4b39; |
| 584 | --color-secondary-foreground: #fffaff; | 799 | --color-secondary-foreground: #fffaff; |
| 585 | --color-secondary-border: #415f4f; | 800 | --color-secondary-border: #415f4f; |
| 586 | --color-switch-active-track: #69d69a; | 801 | --color-switch-active-track: #e3b34e; |
| 587 | --color-switch-active-thumb: #241523; | 802 | --color-switch-active-thumb: #241523; |
| 588 | --color-switch-inactive-track: #2a4b39; | 803 | --color-switch-inactive-track: #2a4b39; |
| 589 | --color-switch-inactive-thumb: #9da5a2; | 804 | --color-switch-inactive-thumb: #9da5a2; |
| ... | @@ -593,7 +808,9 @@ | ... | @@ -593,7 +808,9 @@ |
| 593 | --color-danger: #3f2c28; | 808 | --color-danger: #3f2c28; |
| 594 | --color-danger-border: rgba(251, 65, 74, 0.32); | 809 | --color-danger-border: rgba(251, 65, 74, 0.32); |
| 595 | --color-danger-foreground: #ff6668; | 810 | --color-danger-foreground: #ff6668; |
| 596 | --color-input: #36413c; | 811 | --color-update: #345f48; |
| 812 | --color-update-foreground: #9ee4be; | ||
| 813 | --color-input: #1b2821; | ||
| 597 | --color-input-border: #4f725f; | 814 | --color-input-border: #4f725f; |
| 598 | --color-sidebar-search: #45554d; | 815 | --color-sidebar-search: #45554d; |
| 599 | --color-placeholder: #a9abab; | 816 | --color-placeholder: #a9abab; |
| ... | @@ -601,13 +818,15 @@ | ... | @@ -601,13 +818,15 @@ |
| 601 | --color-icon-muted: #919595; | 818 | --color-icon-muted: #919595; |
| 602 | --color-icon-subtle: #919595; | 819 | --color-icon-subtle: #919595; |
| 603 | --color-header: rgba(27, 40, 33, 0.97); | 820 | --color-header: rgba(27, 40, 33, 0.97); |
| 821 | --color-header-foreground: #fffaff; | ||
| 604 | --color-header-border: #36654c; | 822 | --color-header-border: #36654c; |
| 605 | --color-glass-surface: rgba(68, 77, 73, 0.74); | 823 | --color-glass-surface: rgba(68, 77, 73, 0.74); |
| 824 | --color-glass-fallback: rgba(27, 40, 33, 0.9); | ||
| 606 | --color-glass-tint: rgba(68, 77, 73, 0.22); | 825 | --color-glass-tint: rgba(68, 77, 73, 0.22); |
| 607 | --color-status-bar: #1b2821; | 826 | --color-status-bar: #1b2821; |
| 608 | --color-md-body: #fffaff; | 827 | --color-md-body: #fffaff; |
| 609 | --color-md-strong: #fffaff; | 828 | --color-md-strong: #fffaff; |
| 610 | --color-md-link: #69d69a; | 829 | --color-md-link: #e3b34e; |
| 611 | --color-md-blockquote-border: #415f4f; | 830 | --color-md-blockquote-border: #415f4f; |
| 612 | --color-md-blockquote-bg: #253e31; | 831 | --color-md-blockquote-bg: #253e31; |
| 613 | --color-md-code-bg: #28342e; | 832 | --color-md-code-bg: #28342e; |
| ... | @@ -622,7 +841,10 @@ | ... | @@ -622,7 +841,10 @@ |
| 622 | --color-user-bubble-foreground-muted: rgba(255, 250, 255, 0.78); | 841 | --color-user-bubble-foreground-muted: rgba(255, 250, 255, 0.78); |
| 623 | --color-user-bubble-skill-foreground: #eed295; | 842 | --color-user-bubble-skill-foreground: #eed295; |
| 624 | --color-backdrop: rgba(0, 0, 0, 0.48); | 843 | --color-backdrop: rgba(0, 0, 0, 0.48); |
| 625 | --color-drawer: rgba(33, 54, 43, 0.99); | 844 | --color-drawer: #21362b; |
| 845 | --color-drawer-foreground: #fffaff; | ||
| 846 | --color-drawer-foreground-muted: #aab0af; | ||
| 847 | --color-drawer-border: #6f7a75; | ||
| 626 | --color-drawer-shadow: rgba(0, 0, 0, 0.32); | 848 | --color-drawer-shadow: rgba(0, 0, 0, 0.32); |
| 627 | --color-dot-separator: rgba(145, 149, 149, 0.35); | 849 | --color-dot-separator: rgba(145, 149, 149, 0.35); |
| 628 | --color-wordmark: #fffaff; | 850 | --color-wordmark: #fffaff; |
| ... | @@ -684,32 +906,36 @@ | ... | @@ -684,32 +906,36 @@ |
| 684 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); | 906 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); |
| 685 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); | 907 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); |
| 686 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); | 908 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); |
| 687 | --color-clerk-page: #0e0e0e; | 909 | --color-clerk-page: #0a0a0a; |
| 688 | --color-clerk-foreground: #f5f5f5; | 910 | --color-clerk-foreground: #f5f5f5; |
| 689 | --color-clerk-foreground-muted: #a3a3a3; | 911 | --color-clerk-foreground-muted: #818181; |
| 690 | --color-clerk-border: rgba(42, 42, 42, 0.06); | 912 | --color-clerk-border: #191919; |
| 691 | --color-clerk-danger: #fca5a5; | 913 | --color-clerk-danger: #ff6467; |
| 692 | } | 914 | } |
| 693 | 915 | ||
| 694 | @variant ocean-light { | 916 | @variant ocean-light { |
| 695 | --color-screen: #f5f7f8; | 917 | --color-screen: #f5f7f8; |
| 696 | --color-sheet: rgba(245, 247, 248, 0.98); | 918 | --color-sheet: rgba(245, 247, 248, 0.98); |
| 697 | --color-sheet-solid: #f5f7f8; | 919 | --color-sheet-solid: #f5f7f8; |
| 698 | --color-card: #edeff1; | 920 | --color-card: #f5f7f8; |
| 699 | --color-card-alt: #f5f7f8; | 921 | --color-grouped-card: #f5f7f8; |
| 700 | --color-card-translucent: rgba(237, 239, 241, 0.8); | 922 | --color-card-alt: #edeff1; |
| 923 | --color-card-translucent: rgba(245, 247, 248, 0.8); | ||
| 701 | --color-thread-canvas: #f5f7f8; | 924 | --color-thread-canvas: #f5f7f8; |
| 702 | --color-thread-selected: #edeff1; | 925 | --color-thread-selected: #bed4e5; |
| 703 | --color-thread-selected-foreground: #241523; | 926 | --color-thread-selected-foreground: #241523; |
| 704 | --color-thread-selected-foreground-muted: #746c75; | 927 | --color-thread-selected-foreground-muted: #5e5862; |
| 928 | --color-thread-hover: #cdddea; | ||
| 929 | --color-row-hover: #d8e4ee; | ||
| 705 | --color-composer-panel: rgba(245, 247, 248, 0.88); | 930 | --color-composer-panel: rgba(245, 247, 248, 0.88); |
| 706 | --color-composer-surface: rgba(237, 239, 241, 0.94); | 931 | --color-composer-surface: rgba(245, 247, 248, 0.94); |
| 707 | --color-composer-border: rgba(205, 212, 220, 0.54); | 932 | --color-composer-border: rgba(205, 212, 220, 0.54); |
| 708 | --color-foreground: #241523; | 933 | --color-foreground: #241523; |
| 709 | --color-foreground-secondary: #746c75; | 934 | --color-foreground-secondary: #726a73; |
| 710 | --color-foreground-muted: #6f6873; | 935 | --color-foreground-muted: #6f6873; |
| 711 | --color-foreground-tertiary: #746c75; | 936 | --color-foreground-tertiary: #746c75; |
| 712 | --color-border: #cdd4dc; | 937 | --color-border: #cdd4dc; |
| 938 | --color-focus: #2672af; | ||
| 713 | --color-border-subtle: rgba(205, 212, 220, 0.7); | 939 | --color-border-subtle: rgba(205, 212, 220, 0.7); |
| 714 | --color-separator: rgba(205, 212, 220, 0.55); | 940 | --color-separator: rgba(205, 212, 220, 0.55); |
| 715 | --color-subtle: #e8eff4; | 941 | --color-subtle: #e8eff4; |
| ... | @@ -717,13 +943,14 @@ | ... | @@ -717,13 +943,14 @@ |
| 717 | --color-inline-skill-background: #d8e4ee; | 943 | --color-inline-skill-background: #d8e4ee; |
| 718 | --color-inline-skill-border: rgba(38, 114, 175, 0.42); | 944 | --color-inline-skill-border: rgba(38, 114, 175, 0.42); |
| 719 | --color-inline-skill-foreground: #241523; | 945 | --color-inline-skill-foreground: #241523; |
| 720 | --color-primary: #2672af; | 946 | --color-primary: #0a6f75; |
| 721 | --color-primary-foreground: #fffaff; | 947 | --color-primary-foreground: #fffaff; |
| 948 | --color-primary-text: #0a6f75; | ||
| 722 | --color-primary-shadow: #000000; | 949 | --color-primary-shadow: #000000; |
| 723 | --color-secondary: #e4ecf2; | 950 | --color-secondary: #e4ecf2; |
| 724 | --color-secondary-foreground: #241523; | 951 | --color-secondary-foreground: #241523; |
| 725 | --color-secondary-border: #cdd4dc; | 952 | --color-secondary-border: #cdd4dc; |
| 726 | --color-switch-active-track: #2672af; | 953 | --color-switch-active-track: #0a6f75; |
| 727 | --color-switch-active-thumb: #fffaff; | 954 | --color-switch-active-thumb: #fffaff; |
| 728 | --color-switch-inactive-track: #e4ecf2; | 955 | --color-switch-inactive-track: #e4ecf2; |
| 729 | --color-switch-inactive-thumb: #6f6873; | 956 | --color-switch-inactive-thumb: #6f6873; |
| ... | @@ -733,7 +960,9 @@ | ... | @@ -733,7 +960,9 @@ |
| 733 | --color-danger: #f5e6e9; | 960 | --color-danger: #f5e6e9; |
| 734 | --color-danger-border: rgba(251, 44, 54, 0.32); | 961 | --color-danger-border: rgba(251, 44, 54, 0.32); |
| 735 | --color-danger-foreground: #c10007; | 962 | --color-danger-foreground: #c10007; |
| 736 | --color-input: #edeff1; | 963 | --color-update: #d4e1ed; |
| 964 | --color-update-foreground: #194a72; | ||
| 965 | --color-input: #f5f7f8; | ||
| 737 | --color-input-border: #c0c9d4; | 966 | --color-input-border: #c0c9d4; |
| 738 | --color-sidebar-search: #d5dbe2; | 967 | --color-sidebar-search: #d5dbe2; |
| 739 | --color-placeholder: #716972; | 968 | --color-placeholder: #716972; |
| ... | @@ -741,13 +970,15 @@ | ... | @@ -741,13 +970,15 @@ |
| 741 | --color-icon-muted: #746c75; | 970 | --color-icon-muted: #746c75; |
| 742 | --color-icon-subtle: #746c75; | 971 | --color-icon-subtle: #746c75; |
| 743 | --color-header: rgba(245, 247, 248, 0.97); | 972 | --color-header: rgba(245, 247, 248, 0.97); |
| 973 | --color-header-foreground: #241523; | ||
| 744 | --color-header-border: #d8e4ee; | 974 | --color-header-border: #d8e4ee; |
| 745 | --color-glass-surface: rgba(232, 233, 235, 0.74); | 975 | --color-glass-surface: rgba(232, 233, 235, 0.74); |
| 976 | --color-glass-fallback: rgba(245, 247, 248, 0.94); | ||
| 746 | --color-glass-tint: rgba(232, 233, 235, 0.22); | 977 | --color-glass-tint: rgba(232, 233, 235, 0.22); |
| 747 | --color-status-bar: #f5f7f8; | 978 | --color-status-bar: #f5f7f8; |
| 748 | --color-md-body: #241523; | 979 | --color-md-body: #241523; |
| 749 | --color-md-strong: #241523; | 980 | --color-md-strong: #241523; |
| 750 | --color-md-link: #2672af; | 981 | --color-md-link: #0a6f75; |
| 751 | --color-md-blockquote-border: #cdd4dc; | 982 | --color-md-blockquote-border: #cdd4dc; |
| 752 | --color-md-blockquote-bg: #e8eff4; | 983 | --color-md-blockquote-bg: #e8eff4; |
| 753 | --color-md-code-bg: #f0f1f3; | 984 | --color-md-code-bg: #f0f1f3; |
| ... | @@ -762,7 +993,10 @@ | ... | @@ -762,7 +993,10 @@ |
| 762 | --color-user-bubble-foreground-muted: rgba(36, 21, 35, 0.78); | 993 | --color-user-bubble-foreground-muted: rgba(36, 21, 35, 0.78); |
| 763 | --color-user-bubble-skill-foreground: #0a6c72; | 994 | --color-user-bubble-skill-foreground: #0a6c72; |
| 764 | --color-backdrop: rgba(0, 0, 0, 0.22); | 995 | --color-backdrop: rgba(0, 0, 0, 0.22); |
| 765 | --color-drawer: rgba(228, 236, 242, 0.99); | 996 | --color-drawer: #e4ecf2; |
| 997 | --color-drawer-foreground: #241523; | ||
| 998 | --color-drawer-foreground-muted: #655e69; | ||
| 999 | --color-drawer-border: #cdd2d9; | ||
| 766 | --color-drawer-shadow: rgba(0, 0, 0, 0.12); | 1000 | --color-drawer-shadow: rgba(0, 0, 0, 0.12); |
| 767 | --color-dot-separator: rgba(116, 108, 117, 0.35); | 1001 | --color-dot-separator: rgba(116, 108, 117, 0.35); |
| 768 | --color-wordmark: #241523; | 1002 | --color-wordmark: #241523; |
| ... | @@ -824,32 +1058,36 @@ | ... | @@ -824,32 +1058,36 @@ |
| 824 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); | 1058 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); |
| 825 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); | 1059 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); |
| 826 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); | 1060 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); |
| 827 | --color-clerk-page: #f2f2f7; | 1061 | --color-clerk-page: #fcfcfc; |
| 828 | --color-clerk-foreground: #262626; | 1062 | --color-clerk-foreground: #27272a; |
| 829 | --color-clerk-foreground-muted: #737373; | 1063 | --color-clerk-foreground-muted: #71717b; |
| 830 | --color-clerk-border: rgba(229, 229, 234, 0.06); | 1064 | --color-clerk-border: #e4e4e7; |
| 831 | --color-clerk-danger: #dc2626; | 1065 | --color-clerk-danger: #c10007; |
| 832 | } | 1066 | } |
| 833 | 1067 | ||
| 834 | @variant ocean-dark { | 1068 | @variant ocean-dark { |
| 835 | --color-screen: #17212b; | 1069 | --color-screen: #17212b; |
| 836 | --color-sheet: rgba(23, 33, 43, 0.98); | 1070 | --color-sheet: rgba(23, 33, 43, 0.98); |
| 837 | --color-sheet-solid: #17212b; | 1071 | --color-sheet-solid: #17212b; |
| 838 | --color-card: #333b45; | 1072 | --color-card: #17212b; |
| 839 | --color-card-alt: #17212b; | 1073 | --color-grouped-card: #17212b; |
| 840 | --color-card-translucent: rgba(51, 59, 69, 0.8); | 1074 | --color-card-alt: #333b45; |
| 1075 | --color-card-translucent: rgba(23, 33, 43, 0.8); | ||
| 841 | --color-thread-canvas: #17212b; | 1076 | --color-thread-canvas: #17212b; |
| 842 | --color-thread-selected: #333b45; | 1077 | --color-thread-selected: #2f495f; |
| 843 | --color-thread-selected-foreground: #fffaff; | 1078 | --color-thread-selected-foreground: #fffaff; |
| 844 | --color-thread-selected-foreground-muted: #8d8f97; | 1079 | --color-thread-selected-foreground-muted: #b0b4ba; |
| 1080 | --color-thread-hover: #283e50; | ||
| 1081 | --color-row-hover: #324e66; | ||
| 845 | --color-composer-panel: rgba(23, 33, 43, 0.92); | 1082 | --color-composer-panel: rgba(23, 33, 43, 0.92); |
| 846 | --color-composer-surface: rgba(51, 59, 69, 0.9); | 1083 | --color-composer-surface: rgba(23, 33, 43, 0.9); |
| 847 | --color-composer-border: rgba(64, 85, 103, 0.46); | 1084 | --color-composer-border: rgba(64, 85, 103, 0.46); |
| 848 | --color-foreground: #fffaff; | 1085 | --color-foreground: #fffaff; |
| 849 | --color-foreground-secondary: #8d8f97; | 1086 | --color-foreground-secondary: #a2a3aa; |
| 850 | --color-foreground-muted: #969ca6; | 1087 | --color-foreground-muted: #9ea4ad; |
| 851 | --color-foreground-tertiary: #8d8f97; | 1088 | --color-foreground-tertiary: #8d8f97; |
| 852 | --color-border: #405567; | 1089 | --color-border: #405567; |
| 1090 | --color-focus: #70b9ee; | ||
| 853 | --color-border-subtle: rgba(64, 85, 103, 0.7); | 1091 | --color-border-subtle: rgba(64, 85, 103, 0.7); |
| 854 | --color-separator: rgba(64, 85, 103, 0.55); | 1092 | --color-separator: rgba(64, 85, 103, 0.55); |
| 855 | --color-subtle: #233544; | 1093 | --color-subtle: #233544; |
| ... | @@ -857,13 +1095,14 @@ | ... | @@ -857,13 +1095,14 @@ |
| 857 | --color-inline-skill-background: #324e66; | 1095 | --color-inline-skill-background: #324e66; |
| 858 | --color-inline-skill-border: rgba(112, 185, 238, 0.42); | 1096 | --color-inline-skill-border: rgba(112, 185, 238, 0.42); |
| 859 | --color-inline-skill-foreground: #fffaff; | 1097 | --color-inline-skill-foreground: #fffaff; |
| 860 | --color-primary: #70b9ee; | 1098 | --color-primary: #5bd0d6; |
| 861 | --color-primary-foreground: #241523; | 1099 | --color-primary-foreground: #241523; |
| 1100 | --color-primary-text: #5bd0d6; | ||
| 862 | --color-primary-shadow: #000000; | 1101 | --color-primary-shadow: #000000; |
| 863 | --color-secondary: #293f52; | 1102 | --color-secondary: #293f52; |
| 864 | --color-secondary-foreground: #fffaff; | 1103 | --color-secondary-foreground: #fffaff; |
| 865 | --color-secondary-border: #405567; | 1104 | --color-secondary-border: #405567; |
| 866 | --color-switch-active-track: #70b9ee; | 1105 | --color-switch-active-track: #5bd0d6; |
| 867 | --color-switch-active-thumb: #241523; | 1106 | --color-switch-active-thumb: #241523; |
| 868 | --color-switch-inactive-track: #293f52; | 1107 | --color-switch-inactive-track: #293f52; |
| 869 | --color-switch-inactive-thumb: #969ca6; | 1108 | --color-switch-inactive-thumb: #969ca6; |
| ... | @@ -873,7 +1112,9 @@ | ... | @@ -873,7 +1112,9 @@ |
| 873 | --color-danger: #3c2630; | 1112 | --color-danger: #3c2630; |
| 874 | --color-danger-border: rgba(251, 65, 74, 0.32); | 1113 | --color-danger-border: rgba(251, 65, 74, 0.32); |
| 875 | --color-danger-foreground: #ff6467; | 1114 | --color-danger-foreground: #ff6467; |
| 876 | --color-input: #333b45; | 1115 | --color-update: #345269; |
| 1116 | --color-update-foreground: #a2d2f4; | ||
| 1117 | --color-input: #17212b; | ||
| 877 | --color-input-border: #4f677b; | 1118 | --color-input-border: #4f677b; |
| 878 | --color-sidebar-search: #424e5a; | 1119 | --color-sidebar-search: #424e5a; |
| 879 | --color-placeholder: #a4a4ac; | 1120 | --color-placeholder: #a4a4ac; |
| ... | @@ -881,13 +1122,15 @@ | ... | @@ -881,13 +1122,15 @@ |
| 881 | --color-icon-muted: #8d8f97; | 1122 | --color-icon-muted: #8d8f97; |
| 882 | --color-icon-subtle: #8d8f97; | 1123 | --color-icon-subtle: #8d8f97; |
| 883 | --color-header: rgba(23, 33, 43, 0.97); | 1124 | --color-header: rgba(23, 33, 43, 0.97); |
| 1125 | --color-header-foreground: #fffaff; | ||
| 884 | --color-header-border: #36566f; | 1126 | --color-header-border: #36566f; |
| 885 | --color-glass-surface: rgba(65, 72, 81, 0.74); | 1127 | --color-glass-surface: rgba(65, 72, 81, 0.74); |
| 1128 | --color-glass-fallback: rgba(23, 33, 43, 0.9); | ||
| 886 | --color-glass-tint: rgba(65, 72, 81, 0.22); | 1129 | --color-glass-tint: rgba(65, 72, 81, 0.22); |
| 887 | --color-status-bar: #17212b; | 1130 | --color-status-bar: #17212b; |
| 888 | --color-md-body: #fffaff; | 1131 | --color-md-body: #fffaff; |
| 889 | --color-md-strong: #fffaff; | 1132 | --color-md-strong: #fffaff; |
| 890 | --color-md-link: #70b9ee; | 1133 | --color-md-link: #5bd0d6; |
| 891 | --color-md-blockquote-border: #405567; | 1134 | --color-md-blockquote-border: #405567; |
| 892 | --color-md-blockquote-bg: #233544; | 1135 | --color-md-blockquote-bg: #233544; |
| 893 | --color-md-code-bg: #252e38; | 1136 | --color-md-code-bg: #252e38; |
| ... | @@ -902,7 +1145,10 @@ | ... | @@ -902,7 +1145,10 @@ |
| 902 | --color-user-bubble-foreground-muted: rgba(255, 250, 255, 0.78); | 1145 | --color-user-bubble-foreground-muted: rgba(255, 250, 255, 0.78); |
| 903 | --color-user-bubble-skill-foreground: #75d8dd; | 1146 | --color-user-bubble-skill-foreground: #75d8dd; |
| 904 | --color-backdrop: rgba(0, 0, 0, 0.48); | 1147 | --color-backdrop: rgba(0, 0, 0, 0.48); |
| 905 | --color-drawer: rgba(30, 45, 59, 0.99); | 1148 | --color-drawer: #1e2d3b; |
| 1149 | --color-drawer-foreground: #fffaff; | ||
| 1150 | --color-drawer-foreground-muted: #a2a5ae; | ||
| 1151 | --color-drawer-border: #6d757f; | ||
| 906 | --color-drawer-shadow: rgba(0, 0, 0, 0.32); | 1152 | --color-drawer-shadow: rgba(0, 0, 0, 0.32); |
| 907 | --color-dot-separator: rgba(141, 143, 151, 0.35); | 1153 | --color-dot-separator: rgba(141, 143, 151, 0.35); |
| 908 | --color-wordmark: #fffaff; | 1154 | --color-wordmark: #fffaff; |
| ... | @@ -964,32 +1210,36 @@ | ... | @@ -964,32 +1210,36 @@ |
| 964 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); | 1210 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); |
| 965 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); | 1211 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); |
| 966 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); | 1212 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); |
| 967 | --color-clerk-page: #0e0e0e; | 1213 | --color-clerk-page: #0a0a0a; |
| 968 | --color-clerk-foreground: #f5f5f5; | 1214 | --color-clerk-foreground: #f5f5f5; |
| 969 | --color-clerk-foreground-muted: #a3a3a3; | 1215 | --color-clerk-foreground-muted: #818181; |
| 970 | --color-clerk-border: rgba(42, 42, 42, 0.06); | 1216 | --color-clerk-border: #191919; |
| 971 | --color-clerk-danger: #fca5a5; | 1217 | --color-clerk-danger: #ff6467; |
| 972 | } | 1218 | } |
| 973 | 1219 | ||
| 974 | @variant ember-light { | 1220 | @variant ember-light { |
| 975 | --color-screen: #f9f7f5; | 1221 | --color-screen: #f9f7f5; |
| 976 | --color-sheet: rgba(249, 247, 245, 0.98); | 1222 | --color-sheet: rgba(249, 247, 245, 0.98); |
| 977 | --color-sheet-solid: #f9f7f5; | 1223 | --color-sheet-solid: #f9f7f5; |
| 978 | --color-card: #f1efee; | 1224 | --color-card: #f9f7f5; |
| 979 | --color-card-alt: #f9f7f5; | 1225 | --color-grouped-card: #f9f7f5; |
| 980 | --color-card-translucent: rgba(241, 239, 238, 0.8); | 1226 | --color-card-alt: #f1efee; |
| 1227 | --color-card-translucent: rgba(249, 247, 245, 0.8); | ||
| 981 | --color-thread-canvas: #f9f7f5; | 1228 | --color-thread-canvas: #f9f7f5; |
| 982 | --color-thread-selected: #f1efee; | 1229 | --color-thread-selected: #e5ccc0; |
| 983 | --color-thread-selected-foreground: #241523; | 1230 | --color-thread-selected-foreground: #241523; |
| 984 | --color-thread-selected-foreground-muted: #766c74; | 1231 | --color-thread-selected-foreground-muted: #62575d; |
| 1232 | --color-thread-hover: #ead8cf; | ||
| 1233 | --color-row-hover: #eee0d9; | ||
| 985 | --color-composer-panel: rgba(249, 247, 245, 0.88); | 1234 | --color-composer-panel: rgba(249, 247, 245, 0.88); |
| 986 | --color-composer-surface: rgba(241, 239, 238, 0.94); | 1235 | --color-composer-surface: rgba(249, 247, 245, 0.94); |
| 987 | --color-composer-border: rgba(221, 210, 206, 0.54); | 1236 | --color-composer-border: rgba(221, 210, 206, 0.54); |
| 988 | --color-foreground: #241523; | 1237 | --color-foreground: #241523; |
| 989 | --color-foreground-secondary: #766c74; | 1238 | --color-foreground-secondary: #746a72; |
| 990 | --color-foreground-muted: #74686f; | 1239 | --color-foreground-muted: #74686f; |
| 991 | --color-foreground-tertiary: #766c74; | 1240 | --color-foreground-tertiary: #766c74; |
| 992 | --color-border: #ddd2ce; | 1241 | --color-border: #ddd2ce; |
| 1242 | --color-focus: #ae552a; | ||
| 993 | --color-border-subtle: rgba(221, 210, 206, 0.7); | 1243 | --color-border-subtle: rgba(221, 210, 206, 0.7); |
| 994 | --color-separator: rgba(221, 210, 206, 0.55); | 1244 | --color-separator: rgba(221, 210, 206, 0.55); |
| 995 | --color-subtle: #f4ede9; | 1245 | --color-subtle: #f4ede9; |
| ... | @@ -997,13 +1247,14 @@ | ... | @@ -997,13 +1247,14 @@ |
| 997 | --color-inline-skill-background: #eee0d9; | 1247 | --color-inline-skill-background: #eee0d9; |
| 998 | --color-inline-skill-border: rgba(174, 85, 42, 0.42); | 1248 | --color-inline-skill-border: rgba(174, 85, 42, 0.42); |
| 999 | --color-inline-skill-foreground: #241523; | 1249 | --color-inline-skill-foreground: #241523; |
| 1000 | --color-primary: #ae552a; | 1250 | --color-primary: #b23535; |
| 1001 | --color-primary-foreground: #fffaff; | 1251 | --color-primary-foreground: #fffaff; |
| 1252 | --color-primary-text: #b23535; | ||
| 1002 | --color-primary-shadow: #000000; | 1253 | --color-primary-shadow: #000000; |
| 1003 | --color-secondary: #f3eae5; | 1254 | --color-secondary: #f3eae5; |
| 1004 | --color-secondary-foreground: #241523; | 1255 | --color-secondary-foreground: #241523; |
| 1005 | --color-secondary-border: #ddd2ce; | 1256 | --color-secondary-border: #ddd2ce; |
| 1006 | --color-switch-active-track: #ae552a; | 1257 | --color-switch-active-track: #b23535; |
| 1007 | --color-switch-active-thumb: #fffaff; | 1258 | --color-switch-active-thumb: #fffaff; |
| 1008 | --color-switch-inactive-track: #f3eae5; | 1259 | --color-switch-inactive-track: #f3eae5; |
| 1009 | --color-switch-inactive-thumb: #74686f; | 1260 | --color-switch-inactive-thumb: #74686f; |
| ... | @@ -1013,7 +1264,9 @@ | ... | @@ -1013,7 +1264,9 @@ |
| 1013 | --color-danger: #f9e7e6; | 1264 | --color-danger: #f9e7e6; |
| 1014 | --color-danger-border: rgba(251, 44, 54, 0.32); | 1265 | --color-danger-border: rgba(251, 44, 54, 0.32); |
| 1015 | --color-danger-foreground: #c10007; | 1266 | --color-danger-foreground: #c10007; |
| 1016 | --color-input: #f1efee; | 1267 | --color-update: #edddd5; |
| 1268 | --color-update-foreground: #71381b; | ||
| 1269 | --color-input: #f9f7f5; | ||
| 1017 | --color-input-border: #d4c6c1; | 1270 | --color-input-border: #d4c6c1; |
| 1018 | --color-sidebar-search: #e2d9d6; | 1271 | --color-sidebar-search: #e2d9d6; |
| 1019 | --color-placeholder: #736971; | 1272 | --color-placeholder: #736971; |
| ... | @@ -1021,13 +1274,15 @@ | ... | @@ -1021,13 +1274,15 @@ |
| 1021 | --color-icon-muted: #766c74; | 1274 | --color-icon-muted: #766c74; |
| 1022 | --color-icon-subtle: #766c74; | 1275 | --color-icon-subtle: #766c74; |
| 1023 | --color-header: rgba(249, 247, 245, 0.97); | 1276 | --color-header: rgba(249, 247, 245, 0.97); |
| 1277 | --color-header-foreground: #241523; | ||
| 1024 | --color-header-border: #eee0d9; | 1278 | --color-header-border: #eee0d9; |
| 1025 | --color-glass-surface: rgba(236, 233, 233, 0.74); | 1279 | --color-glass-surface: rgba(236, 233, 233, 0.74); |
| 1280 | --color-glass-fallback: rgba(249, 247, 245, 0.94); | ||
| 1026 | --color-glass-tint: rgba(236, 233, 233, 0.22); | 1281 | --color-glass-tint: rgba(236, 233, 233, 0.22); |
| 1027 | --color-status-bar: #f9f7f5; | 1282 | --color-status-bar: #f9f7f5; |
| 1028 | --color-md-body: #241523; | 1283 | --color-md-body: #241523; |
| 1029 | --color-md-strong: #241523; | 1284 | --color-md-strong: #241523; |
| 1030 | --color-md-link: #ae552a; | 1285 | --color-md-link: #b23535; |
| 1031 | --color-md-blockquote-border: #ddd2ce; | 1286 | --color-md-blockquote-border: #ddd2ce; |
| 1032 | --color-md-blockquote-bg: #f4ede9; | 1287 | --color-md-blockquote-bg: #f4ede9; |
| 1033 | --color-md-code-bg: #f3f1f0; | 1288 | --color-md-code-bg: #f3f1f0; |
| ... | @@ -1042,7 +1297,10 @@ | ... | @@ -1042,7 +1297,10 @@ |
| 1042 | --color-user-bubble-foreground-muted: rgba(36, 21, 35, 0.78); | 1297 | --color-user-bubble-foreground-muted: rgba(36, 21, 35, 0.78); |
| 1043 | --color-user-bubble-skill-foreground: #b13535; | 1298 | --color-user-bubble-skill-foreground: #b13535; |
| 1044 | --color-backdrop: rgba(0, 0, 0, 0.22); | 1299 | --color-backdrop: rgba(0, 0, 0, 0.22); |
| 1045 | --color-drawer: rgba(243, 234, 229, 0.99); | 1300 | --color-drawer: #f3eae5; |
| 1301 | --color-drawer-foreground: #241523; | ||
| 1302 | --color-drawer-foreground-muted: #6a5d64; | ||
| 1303 | --color-drawer-border: #dad0ce; | ||
| 1046 | --color-drawer-shadow: rgba(0, 0, 0, 0.12); | 1304 | --color-drawer-shadow: rgba(0, 0, 0, 0.12); |
| 1047 | --color-dot-separator: rgba(118, 108, 116, 0.35); | 1305 | --color-dot-separator: rgba(118, 108, 116, 0.35); |
| 1048 | --color-wordmark: #241523; | 1306 | --color-wordmark: #241523; |
| ... | @@ -1104,32 +1362,36 @@ | ... | @@ -1104,32 +1362,36 @@ |
| 1104 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); | 1362 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); |
| 1105 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); | 1363 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); |
| 1106 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); | 1364 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); |
| 1107 | --color-clerk-page: #f2f2f7; | 1365 | --color-clerk-page: #fcfcfc; |
| 1108 | --color-clerk-foreground: #262626; | 1366 | --color-clerk-foreground: #27272a; |
| 1109 | --color-clerk-foreground-muted: #737373; | 1367 | --color-clerk-foreground-muted: #71717b; |
| 1110 | --color-clerk-border: rgba(229, 229, 234, 0.06); | 1368 | --color-clerk-border: #e4e4e7; |
| 1111 | --color-clerk-danger: #dc2626; | 1369 | --color-clerk-danger: #c10007; |
| 1112 | } | 1370 | } |
| 1113 | 1371 | ||
| 1114 | @variant ember-dark { | 1372 | @variant ember-dark { |
| 1115 | --color-screen: #291e1a; | 1373 | --color-screen: #291e1a; |
| 1116 | --color-sheet: rgba(41, 30, 26, 0.98); | 1374 | --color-sheet: rgba(41, 30, 26, 0.98); |
| 1117 | --color-sheet-solid: #291e1a; | 1375 | --color-sheet-solid: #291e1a; |
| 1118 | --color-card: #433835; | 1376 | --color-card: #291e1a; |
| 1119 | --color-card-alt: #291e1a; | 1377 | --color-grouped-card: #291e1a; |
| 1120 | --color-card-translucent: rgba(67, 56, 53, 0.8); | 1378 | --color-card-alt: #433835; |
| 1379 | --color-card-translucent: rgba(41, 30, 26, 0.8); | ||
| 1121 | --color-thread-canvas: #291e1a; | 1380 | --color-thread-canvas: #291e1a; |
| 1122 | --color-thread-selected: #433835; | 1381 | --color-thread-selected: #5d3f2d; |
| 1123 | --color-thread-selected-foreground: #fffaff; | 1382 | --color-thread-selected-foreground: #fffaff; |
| 1124 | --color-thread-selected-foreground-muted: #968e8f; | 1383 | --color-thread-selected-foreground-muted: #b9b1b0; |
| 1384 | --color-thread-hover: #4f3528; | ||
| 1385 | --color-row-hover: #644330; | ||
| 1125 | --color-composer-panel: rgba(41, 30, 26, 0.92); | 1386 | --color-composer-panel: rgba(41, 30, 26, 0.92); |
| 1126 | --color-composer-surface: rgba(67, 56, 53, 0.9); | 1387 | --color-composer-surface: rgba(41, 30, 26, 0.9); |
| 1127 | --color-composer-border: rgba(102, 76, 63, 0.46); | 1388 | --color-composer-border: rgba(102, 76, 63, 0.46); |
| 1128 | --color-foreground: #fffaff; | 1389 | --color-foreground: #fffaff; |
| 1129 | --color-foreground-secondary: #968e8f; | 1390 | --color-foreground-secondary: #a8a2a2; |
| 1130 | --color-foreground-muted: #a59996; | 1391 | --color-foreground-muted: #aca19f; |
| 1131 | --color-foreground-tertiary: #968e8f; | 1392 | --color-foreground-tertiary: #968e8f; |
| 1132 | --color-border: #664c3f; | 1393 | --color-border: #664c3f; |
| 1394 | --color-focus: #f09a64; | ||
| 1133 | --color-border-subtle: rgba(102, 76, 63, 0.7); | 1395 | --color-border-subtle: rgba(102, 76, 63, 0.7); |
| 1134 | --color-separator: rgba(102, 76, 63, 0.55); | 1396 | --color-separator: rgba(102, 76, 63, 0.55); |
| 1135 | --color-subtle: #432e23; | 1397 | --color-subtle: #432e23; |
| ... | @@ -1137,13 +1399,14 @@ | ... | @@ -1137,13 +1399,14 @@ |
| 1137 | --color-inline-skill-background: #644330; | 1399 | --color-inline-skill-background: #644330; |
| 1138 | --color-inline-skill-border: rgba(240, 154, 100, 0.42); | 1400 | --color-inline-skill-border: rgba(240, 154, 100, 0.42); |
| 1139 | --color-inline-skill-foreground: #fffaff; | 1401 | --color-inline-skill-foreground: #fffaff; |
| 1140 | --color-primary: #f09a64; | 1402 | --color-primary: #f78a7a; |
| 1141 | --color-primary-foreground: #241523; | 1403 | --color-primary-foreground: #241523; |
| 1404 | --color-primary-text: #f78a7a; | ||
| 1142 | --color-primary-shadow: #000000; | 1405 | --color-primary-shadow: #000000; |
| 1143 | --color-secondary: #513728; | 1406 | --color-secondary: #513728; |
| 1144 | --color-secondary-foreground: #fffaff; | 1407 | --color-secondary-foreground: #fffaff; |
| 1145 | --color-secondary-border: #664c3f; | 1408 | --color-secondary-border: #664c3f; |
| 1146 | --color-switch-active-track: #f09a64; | 1409 | --color-switch-active-track: #f78a7a; |
| 1147 | --color-switch-active-thumb: #241523; | 1410 | --color-switch-active-thumb: #241523; |
| 1148 | --color-switch-inactive-track: #513728; | 1411 | --color-switch-inactive-track: #513728; |
| 1149 | --color-switch-inactive-thumb: #a59996; | 1412 | --color-switch-inactive-thumb: #a59996; |
| ... | @@ -1153,7 +1416,9 @@ | ... | @@ -1153,7 +1416,9 @@ |
| 1153 | --color-danger: #4a2321; | 1416 | --color-danger: #4a2321; |
| 1154 | --color-danger-border: rgba(251, 65, 74, 0.32); | 1417 | --color-danger-border: rgba(251, 65, 74, 0.32); |
| 1155 | --color-danger-foreground: #ff6467; | 1418 | --color-danger-foreground: #ff6467; |
| 1156 | --color-input: #433835; | 1419 | --color-update: #684631; |
| 1420 | --color-update-foreground: #f5bd9a; | ||
| 1421 | --color-input: #291e1a; | ||
| 1157 | --color-input-border: #7a5d4d; | 1422 | --color-input-border: #7a5d4d; |
| 1158 | --color-sidebar-search: #584943; | 1423 | --color-sidebar-search: #584943; |
| 1159 | --color-placeholder: #aba3a5; | 1424 | --color-placeholder: #aba3a5; |
| ... | @@ -1161,13 +1426,15 @@ | ... | @@ -1161,13 +1426,15 @@ |
| 1161 | --color-icon-muted: #968e8f; | 1426 | --color-icon-muted: #968e8f; |
| 1162 | --color-icon-subtle: #968e8f; | 1427 | --color-icon-subtle: #968e8f; |
| 1163 | --color-header: rgba(41, 30, 26, 0.97); | 1428 | --color-header: rgba(41, 30, 26, 0.97); |
| 1429 | --color-header-foreground: #fffaff; | ||
| 1164 | --color-header-border: #6e4934; | 1430 | --color-header-border: #6e4934; |
| 1165 | --color-glass-surface: rgba(79, 69, 67, 0.74); | 1431 | --color-glass-surface: rgba(79, 69, 67, 0.74); |
| 1432 | --color-glass-fallback: rgba(41, 30, 26, 0.9); | ||
| 1166 | --color-glass-tint: rgba(79, 69, 67, 0.22); | 1433 | --color-glass-tint: rgba(79, 69, 67, 0.22); |
| 1167 | --color-status-bar: #291e1a; | 1434 | --color-status-bar: #291e1a; |
| 1168 | --color-md-body: #fffaff; | 1435 | --color-md-body: #fffaff; |
| 1169 | --color-md-strong: #fffaff; | 1436 | --color-md-strong: #fffaff; |
| 1170 | --color-md-link: #f09a64; | 1437 | --color-md-link: #f78a7a; |
| 1171 | --color-md-blockquote-border: #664c3f; | 1438 | --color-md-blockquote-border: #664c3f; |
| 1172 | --color-md-blockquote-bg: #432e23; | 1439 | --color-md-blockquote-bg: #432e23; |
| 1173 | --color-md-code-bg: #362b27; | 1440 | --color-md-code-bg: #362b27; |
| ... | @@ -1182,7 +1449,10 @@ | ... | @@ -1182,7 +1449,10 @@ |
| 1182 | --color-user-bubble-foreground-muted: rgba(255, 250, 255, 0.78); | 1449 | --color-user-bubble-foreground-muted: rgba(255, 250, 255, 0.78); |
| 1183 | --color-user-bubble-skill-foreground: #fab6ad; | 1450 | --color-user-bubble-skill-foreground: #fab6ad; |
| 1184 | --color-backdrop: rgba(0, 0, 0, 0.48); | 1451 | --color-backdrop: rgba(0, 0, 0, 0.48); |
| 1185 | --color-drawer: rgba(57, 40, 31, 0.99); | 1452 | --color-drawer: #39281f; |
| 1453 | --color-drawer-foreground: #fffaff; | ||
| 1454 | --color-drawer-foreground-muted: #aca2a1; | ||
| 1455 | --color-drawer-border: #7e716e; | ||
| 1186 | --color-drawer-shadow: rgba(0, 0, 0, 0.32); | 1456 | --color-drawer-shadow: rgba(0, 0, 0, 0.32); |
| 1187 | --color-dot-separator: rgba(150, 142, 143, 0.35); | 1457 | --color-dot-separator: rgba(150, 142, 143, 0.35); |
| 1188 | --color-wordmark: #fffaff; | 1458 | --color-wordmark: #fffaff; |
| ... | @@ -1244,32 +1514,36 @@ | ... | @@ -1244,32 +1514,36 @@ |
| 1244 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); | 1514 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); |
| 1245 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); | 1515 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); |
| 1246 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); | 1516 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); |
| 1247 | --color-clerk-page: #0e0e0e; | 1517 | --color-clerk-page: #0a0a0a; |
| 1248 | --color-clerk-foreground: #f5f5f5; | 1518 | --color-clerk-foreground: #f5f5f5; |
| 1249 | --color-clerk-foreground-muted: #a3a3a3; | 1519 | --color-clerk-foreground-muted: #818181; |
| 1250 | --color-clerk-border: rgba(42, 42, 42, 0.06); | 1520 | --color-clerk-border: #191919; |
| 1251 | --color-clerk-danger: #fca5a5; | 1521 | --color-clerk-danger: #ff6467; |
| 1252 | } | 1522 | } |
| 1253 | 1523 | ||
| 1254 | @variant iris-light { | 1524 | @variant iris-light { |
| 1255 | --color-screen: #f8f7f9; | 1525 | --color-screen: #f8f7f9; |
| 1256 | --color-sheet: rgba(248, 247, 249, 0.98); | 1526 | --color-sheet: rgba(248, 247, 249, 0.98); |
| 1257 | --color-sheet-solid: #f8f7f9; | 1527 | --color-sheet-solid: #f8f7f9; |
| 1258 | --color-card: #f0eff2; | 1528 | --color-card: #f8f7f9; |
| 1259 | --color-card-alt: #f8f7f9; | 1529 | --color-grouped-card: #f8f7f9; |
| 1260 | --color-card-translucent: rgba(240, 239, 242, 0.8); | 1530 | --color-card-alt: #f0eff2; |
| 1531 | --color-card-translucent: rgba(248, 247, 249, 0.8); | ||
| 1261 | --color-thread-canvas: #f8f7f9; | 1532 | --color-thread-canvas: #f8f7f9; |
| 1262 | --color-thread-selected: #f0eff2; | 1533 | --color-thread-selected: #d4cce8; |
| 1263 | --color-thread-selected-foreground: #241523; | 1534 | --color-thread-selected-foreground: #241523; |
| 1264 | --color-thread-selected-foreground-muted: #766c76; | 1535 | --color-thread-selected-foreground-muted: #605662; |
| 1536 | --color-thread-hover: #ded8ed; | ||
| 1537 | --color-row-hover: #e5e0f0; | ||
| 1265 | --color-composer-panel: rgba(248, 247, 249, 0.88); | 1538 | --color-composer-panel: rgba(248, 247, 249, 0.88); |
| 1266 | --color-composer-surface: rgba(240, 239, 242, 0.94); | 1539 | --color-composer-surface: rgba(248, 247, 249, 0.94); |
| 1267 | --color-composer-border: rgba(214, 209, 222, 0.54); | 1540 | --color-composer-border: rgba(214, 209, 222, 0.54); |
| 1268 | --color-foreground: #241523; | 1541 | --color-foreground: #241523; |
| 1269 | --color-foreground-secondary: #766c76; | 1542 | --color-foreground-secondary: #746a74; |
| 1270 | --color-foreground-muted: #726874; | 1543 | --color-foreground-muted: #726874; |
| 1271 | --color-foreground-tertiary: #766c76; | 1544 | --color-foreground-tertiary: #766c76; |
| 1272 | --color-border: #d6d1de; | 1545 | --color-border: #d6d1de; |
| 1546 | --color-focus: #7253b9; | ||
| 1273 | --color-border-subtle: rgba(214, 209, 222, 0.7); | 1547 | --color-border-subtle: rgba(214, 209, 222, 0.7); |
| 1274 | --color-separator: rgba(214, 209, 222, 0.55); | 1548 | --color-separator: rgba(214, 209, 222, 0.55); |
| 1275 | --color-subtle: #f0edf6; | 1549 | --color-subtle: #f0edf6; |
| ... | @@ -1277,13 +1551,14 @@ | ... | @@ -1277,13 +1551,14 @@ |
| 1277 | --color-inline-skill-background: #e5e0f0; | 1551 | --color-inline-skill-background: #e5e0f0; |
| 1278 | --color-inline-skill-border: rgba(114, 83, 185, 0.42); | 1552 | --color-inline-skill-border: rgba(114, 83, 185, 0.42); |
| 1279 | --color-inline-skill-foreground: #241523; | 1553 | --color-inline-skill-foreground: #241523; |
| 1280 | --color-primary: #7253b9; | 1554 | --color-primary: #a82c87; |
| 1281 | --color-primary-foreground: #fffaff; | 1555 | --color-primary-foreground: #fffaff; |
| 1556 | --color-primary-text: #a82c87; | ||
| 1282 | --color-primary-shadow: #000000; | 1557 | --color-primary-shadow: #000000; |
| 1283 | --color-secondary: #edeaf4; | 1558 | --color-secondary: #edeaf4; |
| 1284 | --color-secondary-foreground: #241523; | 1559 | --color-secondary-foreground: #241523; |
| 1285 | --color-secondary-border: #d6d1de; | 1560 | --color-secondary-border: #d6d1de; |
| 1286 | --color-switch-active-track: #7253b9; | 1561 | --color-switch-active-track: #a82c87; |
| 1287 | --color-switch-active-thumb: #fffaff; | 1562 | --color-switch-active-thumb: #fffaff; |
| 1288 | --color-switch-inactive-track: #edeaf4; | 1563 | --color-switch-inactive-track: #edeaf4; |
| 1289 | --color-switch-inactive-thumb: #726874; | 1564 | --color-switch-inactive-thumb: #726874; |
| ... | @@ -1293,7 +1568,9 @@ | ... | @@ -1293,7 +1568,9 @@ |
| 1293 | --color-danger: #f8e6ea; | 1568 | --color-danger: #f8e6ea; |
| 1294 | --color-danger-border: rgba(251, 44, 54, 0.32); | 1569 | --color-danger-border: rgba(251, 44, 54, 0.32); |
| 1295 | --color-danger-foreground: #c10007; | 1570 | --color-danger-foreground: #c10007; |
| 1296 | --color-input: #f0eff2; | 1571 | --color-update: #e2ddef; |
| 1572 | --color-update-foreground: #4a3678; | ||
| 1573 | --color-input: #f8f7f9; | ||
| 1297 | --color-input-border: #ccc5d6; | 1574 | --color-input-border: #ccc5d6; |
| 1298 | --color-sidebar-search: #ddd9e3; | 1575 | --color-sidebar-search: #ddd9e3; |
| 1299 | --color-placeholder: #736973; | 1576 | --color-placeholder: #736973; |
| ... | @@ -1301,13 +1578,15 @@ | ... | @@ -1301,13 +1578,15 @@ |
| 1301 | --color-icon-muted: #766c76; | 1578 | --color-icon-muted: #766c76; |
| 1302 | --color-icon-subtle: #766c76; | 1579 | --color-icon-subtle: #766c76; |
| 1303 | --color-header: rgba(248, 247, 249, 0.97); | 1580 | --color-header: rgba(248, 247, 249, 0.97); |
| 1581 | --color-header-foreground: #241523; | ||
| 1304 | --color-header-border: #e5e0f0; | 1582 | --color-header-border: #e5e0f0; |
| 1305 | --color-glass-surface: rgba(235, 233, 237, 0.74); | 1583 | --color-glass-surface: rgba(235, 233, 237, 0.74); |
| 1584 | --color-glass-fallback: rgba(248, 247, 249, 0.94); | ||
| 1306 | --color-glass-tint: rgba(235, 233, 237, 0.22); | 1585 | --color-glass-tint: rgba(235, 233, 237, 0.22); |
| 1307 | --color-status-bar: #f8f7f9; | 1586 | --color-status-bar: #f8f7f9; |
| 1308 | --color-md-body: #241523; | 1587 | --color-md-body: #241523; |
| 1309 | --color-md-strong: #241523; | 1588 | --color-md-strong: #241523; |
| 1310 | --color-md-link: #7253b9; | 1589 | --color-md-link: #a82c87; |
| 1311 | --color-md-blockquote-border: #d6d1de; | 1590 | --color-md-blockquote-border: #d6d1de; |
| 1312 | --color-md-blockquote-bg: #f0edf6; | 1591 | --color-md-blockquote-bg: #f0edf6; |
| 1313 | --color-md-code-bg: #f2f1f4; | 1592 | --color-md-code-bg: #f2f1f4; |
| ... | @@ -1322,7 +1601,10 @@ | ... | @@ -1322,7 +1601,10 @@ |
| 1322 | --color-user-bubble-foreground-muted: rgba(36, 21, 35, 0.78); | 1601 | --color-user-bubble-foreground-muted: rgba(36, 21, 35, 0.78); |
| 1323 | --color-user-bubble-skill-foreground: #a82c87; | 1602 | --color-user-bubble-skill-foreground: #a82c87; |
| 1324 | --color-backdrop: rgba(0, 0, 0, 0.22); | 1603 | --color-backdrop: rgba(0, 0, 0, 0.22); |
| 1325 | --color-drawer: rgba(237, 234, 244, 0.99); | 1604 | --color-drawer: #edeaf4; |
| 1605 | --color-drawer-foreground: #241523; | ||
| 1606 | --color-drawer-foreground-muted: #685d6a; | ||
| 1607 | --color-drawer-border: #d5d0db; | ||
| 1326 | --color-drawer-shadow: rgba(0, 0, 0, 0.12); | 1608 | --color-drawer-shadow: rgba(0, 0, 0, 0.12); |
| 1327 | --color-dot-separator: rgba(118, 108, 118, 0.35); | 1609 | --color-dot-separator: rgba(118, 108, 118, 0.35); |
| 1328 | --color-wordmark: #241523; | 1610 | --color-wordmark: #241523; |
| ... | @@ -1384,32 +1666,36 @@ | ... | @@ -1384,32 +1666,36 @@ |
| 1384 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); | 1666 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); |
| 1385 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); | 1667 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); |
| 1386 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); | 1668 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); |
| 1387 | --color-clerk-page: #f2f2f7; | 1669 | --color-clerk-page: #fcfcfc; |
| 1388 | --color-clerk-foreground: #262626; | 1670 | --color-clerk-foreground: #27272a; |
| 1389 | --color-clerk-foreground-muted: #737373; | 1671 | --color-clerk-foreground-muted: #71717b; |
| 1390 | --color-clerk-border: rgba(229, 229, 234, 0.06); | 1672 | --color-clerk-border: #e4e4e7; |
| 1391 | --color-clerk-danger: #dc2626; | 1673 | --color-clerk-danger: #c10007; |
| 1392 | } | 1674 | } |
| 1393 | 1675 | ||
| 1394 | @variant iris-dark { | 1676 | @variant iris-dark { |
| 1395 | --color-screen: #1d1929; | 1677 | --color-screen: #1d1929; |
| 1396 | --color-sheet: rgba(29, 25, 41, 0.98); | 1678 | --color-sheet: rgba(29, 25, 41, 0.98); |
| 1397 | --color-sheet-solid: #1d1929; | 1679 | --color-sheet-solid: #1d1929; |
| 1398 | --color-card: #383443; | 1680 | --color-card: #1d1929; |
| 1399 | --color-card-alt: #1d1929; | 1681 | --color-grouped-card: #1d1929; |
| 1400 | --color-card-translucent: rgba(56, 52, 67, 0.8); | 1682 | --color-card-alt: #383443; |
| 1683 | --color-card-translucent: rgba(29, 25, 41, 0.8); | ||
| 1401 | --color-thread-canvas: #1d1929; | 1684 | --color-thread-canvas: #1d1929; |
| 1402 | --color-thread-selected: #383443; | 1685 | --color-thread-selected: #3f345e; |
| 1403 | --color-thread-selected-foreground: #fffaff; | 1686 | --color-thread-selected-foreground: #fffaff; |
| 1404 | --color-thread-selected-foreground-muted: #8e8a95; | 1687 | --color-thread-selected-foreground-muted: #a6a2ae; |
| 1688 | --color-thread-hover: #352c4f; | ||
| 1689 | --color-row-hover: #433765; | ||
| 1405 | --color-composer-panel: rgba(29, 25, 41, 0.92); | 1690 | --color-composer-panel: rgba(29, 25, 41, 0.92); |
| 1406 | --color-composer-surface: rgba(56, 52, 67, 0.9); | 1691 | --color-composer-surface: rgba(29, 25, 41, 0.9); |
| 1407 | --color-composer-border: rgba(77, 67, 102, 0.46); | 1692 | --color-composer-border: rgba(77, 67, 102, 0.46); |
| 1408 | --color-foreground: #fffaff; | 1693 | --color-foreground: #fffaff; |
| 1409 | --color-foreground-secondary: #8e8a95; | 1694 | --color-foreground-secondary: #a09da6; |
| 1410 | --color-foreground-muted: #9690a1; | 1695 | --color-foreground-muted: #a19cab; |
| 1411 | --color-foreground-tertiary: #8e8a95; | 1696 | --color-foreground-tertiary: #8e8a95; |
| 1412 | --color-border: #4d4366; | 1697 | --color-border: #4d4366; |
| 1698 | --color-focus: #9d7df2; | ||
| 1413 | --color-border-subtle: rgba(77, 67, 102, 0.7); | 1699 | --color-border-subtle: rgba(77, 67, 102, 0.7); |
| 1414 | --color-separator: rgba(77, 67, 102, 0.55); | 1700 | --color-separator: rgba(77, 67, 102, 0.55); |
| 1415 | --color-subtle: #2d2643; | 1701 | --color-subtle: #2d2643; |
| ... | @@ -1417,13 +1703,14 @@ | ... | @@ -1417,13 +1703,14 @@ |
| 1417 | --color-inline-skill-background: #433765; | 1703 | --color-inline-skill-background: #433765; |
| 1418 | --color-inline-skill-border: rgba(157, 125, 242, 0.42); | 1704 | --color-inline-skill-border: rgba(157, 125, 242, 0.42); |
| 1419 | --color-inline-skill-foreground: #fffaff; | 1705 | --color-inline-skill-foreground: #fffaff; |
| 1420 | --color-primary: #9d7df2; | 1706 | --color-primary: #f099d8; |
| 1421 | --color-primary-foreground: #241523; | 1707 | --color-primary-foreground: #241523; |
| 1708 | --color-primary-text: #f099d8; | ||
| 1422 | --color-primary-shadow: #000000; | 1709 | --color-primary-shadow: #000000; |
| 1423 | --color-secondary: #362d51; | 1710 | --color-secondary: #362d51; |
| 1424 | --color-secondary-foreground: #fffaff; | 1711 | --color-secondary-foreground: #fffaff; |
| 1425 | --color-secondary-border: #4d4366; | 1712 | --color-secondary-border: #4d4366; |
| 1426 | --color-switch-active-track: #9d7df2; | 1713 | --color-switch-active-track: #f099d8; |
| 1427 | --color-switch-active-thumb: #241523; | 1714 | --color-switch-active-thumb: #241523; |
| 1428 | --color-switch-inactive-track: #362d51; | 1715 | --color-switch-inactive-track: #362d51; |
| 1429 | --color-switch-inactive-thumb: #9690a1; | 1716 | --color-switch-inactive-thumb: #9690a1; |
| ... | @@ -1433,7 +1720,9 @@ | ... | @@ -1433,7 +1720,9 @@ |
| 1433 | --color-danger: #40202e; | 1720 | --color-danger: #40202e; |
| 1434 | --color-danger-border: rgba(251, 65, 74, 0.32); | 1721 | --color-danger-border: rgba(251, 65, 74, 0.32); |
| 1435 | --color-danger-foreground: #ff6467; | 1722 | --color-danger-foreground: #ff6467; |
| 1436 | --color-input: #383443; | 1723 | --color-update: #463969; |
| 1724 | --color-update-foreground: #bfabf7; | ||
| 1725 | --color-input: #1d1929; | ||
| 1437 | --color-input-border: #5d527b; | 1726 | --color-input-border: #5d527b; |
| 1438 | --color-sidebar-search: #494459; | 1727 | --color-sidebar-search: #494459; |
| 1439 | --color-placeholder: #a29ea8; | 1728 | --color-placeholder: #a29ea8; |
| ... | @@ -1441,13 +1730,15 @@ | ... | @@ -1441,13 +1730,15 @@ |
| 1441 | --color-icon-muted: #8e8a95; | 1730 | --color-icon-muted: #8e8a95; |
| 1442 | --color-icon-subtle: #8e8a95; | 1731 | --color-icon-subtle: #8e8a95; |
| 1443 | --color-header: rgba(29, 25, 41, 0.97); | 1732 | --color-header: rgba(29, 25, 41, 0.97); |
| 1733 | --color-header-foreground: #fffaff; | ||
| 1444 | --color-header-border: #4a3c70; | 1734 | --color-header-border: #4a3c70; |
| 1445 | --color-glass-surface: rgba(69, 66, 80, 0.74); | 1735 | --color-glass-surface: rgba(69, 66, 80, 0.74); |
| 1736 | --color-glass-fallback: rgba(29, 25, 41, 0.9); | ||
| 1446 | --color-glass-tint: rgba(69, 66, 80, 0.22); | 1737 | --color-glass-tint: rgba(69, 66, 80, 0.22); |
| 1447 | --color-status-bar: #1d1929; | 1738 | --color-status-bar: #1d1929; |
| 1448 | --color-md-body: #fffaff; | 1739 | --color-md-body: #fffaff; |
| 1449 | --color-md-strong: #fffaff; | 1740 | --color-md-strong: #fffaff; |
| 1450 | --color-md-link: #9d7df2; | 1741 | --color-md-link: #f099d8; |
| 1451 | --color-md-blockquote-border: #4d4366; | 1742 | --color-md-blockquote-border: #4d4366; |
| 1452 | --color-md-blockquote-bg: #2d2643; | 1743 | --color-md-blockquote-bg: #2d2643; |
| 1453 | --color-md-code-bg: #2a2736; | 1744 | --color-md-code-bg: #2a2736; |
| ... | @@ -1462,7 +1753,10 @@ | ... | @@ -1462,7 +1753,10 @@ |
| 1462 | --color-user-bubble-foreground-muted: rgba(255, 250, 255, 0.78); | 1753 | --color-user-bubble-foreground-muted: rgba(255, 250, 255, 0.78); |
| 1463 | --color-user-bubble-skill-foreground: #f099d8; | 1754 | --color-user-bubble-skill-foreground: #f099d8; |
| 1464 | --color-backdrop: rgba(0, 0, 0, 0.48); | 1755 | --color-backdrop: rgba(0, 0, 0, 0.48); |
| 1465 | --color-drawer: rgba(39, 33, 57, 0.99); | 1756 | --color-drawer: #272139; |
| 1757 | --color-drawer-foreground: #fffaff; | ||
| 1758 | --color-drawer-foreground-muted: #9b97a4; | ||
| 1759 | --color-drawer-border: #736d7e; | ||
| 1466 | --color-drawer-shadow: rgba(0, 0, 0, 0.32); | 1760 | --color-drawer-shadow: rgba(0, 0, 0, 0.32); |
| 1467 | --color-dot-separator: rgba(142, 138, 149, 0.35); | 1761 | --color-dot-separator: rgba(142, 138, 149, 0.35); |
| 1468 | --color-wordmark: #fffaff; | 1762 | --color-wordmark: #fffaff; |
| ... | @@ -1524,11 +1818,11 @@ | ... | @@ -1524,11 +1818,11 @@ |
| 1524 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); | 1818 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); |
| 1525 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); | 1819 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); |
| 1526 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); | 1820 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); |
| 1527 | --color-clerk-page: #0e0e0e; | 1821 | --color-clerk-page: #0a0a0a; |
| 1528 | --color-clerk-foreground: #f5f5f5; | 1822 | --color-clerk-foreground: #f5f5f5; |
| 1529 | --color-clerk-foreground-muted: #a3a3a3; | 1823 | --color-clerk-foreground-muted: #818181; |
| 1530 | --color-clerk-border: rgba(42, 42, 42, 0.06); | 1824 | --color-clerk-border: #191919; |
| 1531 | --color-clerk-danger: #fca5a5; | 1825 | --color-clerk-danger: #ff6467; |
| 1532 | } | 1826 | } |
| 1533 | } | 1827 | } |
| 1534 | } | 1828 | } |
apps/mobile/global.css-222| ... | @@ -8,228 +8,6 @@ | ... | @@ -8,228 +8,6 @@ |
| 8 | @variant android { | 8 | @variant android { |
| 9 | --font-mono: "monospace"; | 9 | --font-mono: "monospace"; |
| 10 | } | 10 | } |
| 11 | |||
| 12 | @variant light { | ||
| 13 | /* Page backgrounds */ | ||
| 14 | --color-screen: #f2f2f7; | ||
| 15 | --color-sheet: rgba(242, 242, 247, 0.98); | ||
| 16 | --color-sheet-solid: #f2f2f7; | ||
| 17 | |||
| 18 | /* Card / surface */ | ||
| 19 | --color-card: #ffffff; | ||
| 20 | --color-card-alt: #f5f5f5; | ||
| 21 | --color-card-translucent: rgba(255, 255, 255, 0.8); | ||
| 22 | --color-thread-canvas: #f5f5f5; | ||
| 23 | --color-thread-selected: #ffffff; | ||
| 24 | --color-thread-selected-foreground: #262626; | ||
| 25 | --color-thread-selected-foreground-muted: #737373; | ||
| 26 | --color-composer-panel: rgba(245, 245, 245, 0.88); | ||
| 27 | --color-composer-surface: rgba(255, 255, 255, 0.94); | ||
| 28 | --color-composer-border: rgba(0, 0, 0, 0.1); | ||
| 29 | |||
| 30 | /* Text */ | ||
| 31 | --color-foreground: #262626; | ||
| 32 | --color-foreground-secondary: #525252; | ||
| 33 | --color-foreground-muted: #737373; | ||
| 34 | --color-foreground-tertiary: #8e8e93; | ||
| 35 | |||
| 36 | /* Borders & separators */ | ||
| 37 | --color-border: rgba(0, 0, 0, 0.08); | ||
| 38 | --color-border-subtle: rgba(0, 0, 0, 0.06); | ||
| 39 | --color-separator: rgba(0, 0, 0, 0.04); | ||
| 40 | |||
| 41 | /* Subtle backgrounds (badges, pills, overlays) */ | ||
| 42 | --color-subtle: rgba(0, 0, 0, 0.04); | ||
| 43 | --color-subtle-strong: rgba(0, 0, 0, 0.08); | ||
| 44 | --color-inline-skill-background: rgba(217, 70, 239, 0.12); | ||
| 45 | --color-inline-skill-border: rgba(217, 70, 239, 0.25); | ||
| 46 | --color-inline-skill-foreground: #a21caf; | ||
| 47 | |||
| 48 | /* Primary action */ | ||
| 49 | --color-primary: #262626; | ||
| 50 | --color-primary-foreground: #ffffff; | ||
| 51 | --color-primary-shadow: #000000; | ||
| 52 | |||
| 53 | /* Secondary action */ | ||
| 54 | --color-secondary: #ffffff; | ||
| 55 | --color-secondary-foreground: #262626; | ||
| 56 | --color-secondary-border: rgba(0, 0, 0, 0.08); | ||
| 57 | --color-switch-active-track: #34c759; | ||
| 58 | --color-switch-active-thumb: #ffffff; | ||
| 59 | --color-switch-inactive-track: rgba(0, 0, 0, 0.08); | ||
| 60 | --color-switch-inactive-thumb: #8e8e93; | ||
| 61 | |||
| 62 | /* Warning */ | ||
| 63 | --color-warning: #fffbeb; | ||
| 64 | --color-warning-border: #fde68a; | ||
| 65 | --color-warning-foreground: #b45309; | ||
| 66 | |||
| 67 | /* Danger */ | ||
| 68 | --color-danger: #fef2f2; | ||
| 69 | --color-danger-border: rgba(239, 68, 68, 0.12); | ||
| 70 | --color-danger-foreground: #dc2626; | ||
| 71 | |||
| 72 | /* Inputs */ | ||
| 73 | --color-input: #ffffff; | ||
| 74 | --color-input-border: rgba(0, 0, 0, 0.1); | ||
| 75 | --color-sidebar-search: rgba(118, 118, 128, 0.12); | ||
| 76 | --color-placeholder: #737373; | ||
| 77 | |||
| 78 | /* Icons */ | ||
| 79 | --color-icon: #262626; | ||
| 80 | --color-icon-muted: #525252; | ||
| 81 | --color-icon-subtle: #a3a3a3; | ||
| 82 | |||
| 83 | /* Header / glass chrome */ | ||
| 84 | --color-header: rgba(255, 255, 255, 0.97); | ||
| 85 | --color-header-border: rgba(0, 0, 0, 0.06); | ||
| 86 | --color-glass-surface: rgba(255, 255, 255, 0.72); | ||
| 87 | --color-glass-tint: rgba(255, 255, 255, 0.18); | ||
| 88 | |||
| 89 | /* StatusBar */ | ||
| 90 | --color-status-bar: #f2f2f7; | ||
| 91 | |||
| 92 | /* Markdown */ | ||
| 93 | --color-md-body: #111111; | ||
| 94 | --color-md-strong: #000000; | ||
| 95 | --color-md-link: #2563eb; | ||
| 96 | --color-md-blockquote-border: rgba(0, 0, 0, 0.08); | ||
| 97 | --color-md-blockquote-bg: rgba(0, 0, 0, 0.02); | ||
| 98 | --color-md-code-bg: rgba(0, 0, 0, 0.04); | ||
| 99 | --color-md-code-text: #262626; | ||
| 100 | --color-md-user-code-bg: rgba(0, 0, 0, 0.04); | ||
| 101 | --color-md-user-code-text: #262626; | ||
| 102 | --color-md-user-fence-bg: rgba(0, 0, 0, 0.06); | ||
| 103 | --color-md-user-fence-text: #262626; | ||
| 104 | --color-md-hr: rgba(0, 0, 0, 0.08); | ||
| 105 | |||
| 106 | /* User bubble: a raised card on the thread canvas, matching web's message surface */ | ||
| 107 | --color-user-bubble: #ffffff; | ||
| 108 | --color-user-bubble-foreground: #262626; | ||
| 109 | --color-user-bubble-foreground-muted: rgba(38, 38, 38, 0.78); | ||
| 110 | --color-user-bubble-skill-foreground: #2563eb; | ||
| 111 | |||
| 112 | /* Drawer / modal backdrop */ | ||
| 113 | --color-backdrop: rgba(0, 0, 0, 0.22); | ||
| 114 | --color-drawer: rgba(255, 255, 255, 0.99); | ||
| 115 | --color-drawer-shadow: rgba(0, 0, 0, 0.12); | ||
| 116 | |||
| 117 | /* Misc */ | ||
| 118 | --color-dot-separator: rgba(0, 0, 0, 0.2); | ||
| 119 | --color-wordmark: #262626; | ||
| 120 | --color-chevron: rgba(0, 0, 0, 0.2); | ||
| 121 | } | ||
| 122 | |||
| 123 | @variant dark { | ||
| 124 | /* Page backgrounds */ | ||
| 125 | --color-screen: #0a0a0a; | ||
| 126 | --color-sheet: rgba(14, 14, 14, 0.98); | ||
| 127 | --color-sheet-solid: #0e0e0e; | ||
| 128 | |||
| 129 | /* Card / surface */ | ||
| 130 | --color-card: #171717; | ||
| 131 | --color-card-alt: #1c1c1c; | ||
| 132 | --color-card-translucent: rgba(17, 17, 17, 0.8); | ||
| 133 | --color-thread-canvas: #1c1c1c; | ||
| 134 | --color-thread-selected: #171717; | ||
| 135 | --color-thread-selected-foreground: #f5f5f5; | ||
| 136 | --color-thread-selected-foreground-muted: #8e8e93; | ||
| 137 | --color-composer-panel: rgba(28, 28, 28, 0.92); | ||
| 138 | --color-composer-surface: rgba(23, 23, 23, 0.9); | ||
| 139 | --color-composer-border: rgba(255, 255, 255, 0.08); | ||
| 140 | |||
| 141 | /* Text */ | ||
| 142 | --color-foreground: #f5f5f5; | ||
| 143 | --color-foreground-secondary: #a3a3a3; | ||
| 144 | --color-foreground-muted: #8e8e93; | ||
| 145 | --color-foreground-tertiary: #636366; | ||
| 146 | |||
| 147 | /* Borders & separators */ | ||
| 148 | --color-border: rgba(255, 255, 255, 0.06); | ||
| 149 | --color-border-subtle: rgba(255, 255, 255, 0.04); | ||
| 150 | --color-separator: rgba(255, 255, 255, 0.03); | ||
| 151 | |||
| 152 | /* Subtle backgrounds (badges, pills, overlays) */ | ||
| 153 | --color-subtle: rgba(255, 255, 255, 0.04); | ||
| 154 | --color-subtle-strong: rgba(255, 255, 255, 0.08); | ||
| 155 | --color-inline-skill-background: rgba(217, 70, 239, 0.12); | ||
| 156 | --color-inline-skill-border: rgba(217, 70, 239, 0.25); | ||
| 157 | --color-inline-skill-foreground: #f0abfc; | ||
| 158 | |||
| 159 | /* Primary action */ | ||
| 160 | --color-primary: #f5f5f5; | ||
| 161 | --color-primary-foreground: #0a0a0a; | ||
| 162 | --color-primary-shadow: #000000; | ||
| 163 | |||
| 164 | /* Secondary action */ | ||
| 165 | --color-secondary: rgba(255, 255, 255, 0.04); | ||
| 166 | --color-secondary-foreground: #f5f5f5; | ||
| 167 | --color-secondary-border: rgba(255, 255, 255, 0.06); | ||
| 168 | --color-switch-active-track: #30d158; | ||
| 169 | --color-switch-active-thumb: #ffffff; | ||
| 170 | --color-switch-inactive-track: rgba(255, 255, 255, 0.06); | ||
| 171 | --color-switch-inactive-thumb: #8e8e93; | ||
| 172 | |||
| 173 | /* Warning */ | ||
| 174 | --color-warning: rgba(69, 26, 3, 0.4); | ||
| 175 | --color-warning-border: rgba(120, 53, 15, 0.6); | ||
| 176 | --color-warning-foreground: #fcd34d; | ||
| 177 | |||
| 178 | /* Danger */ | ||
| 179 | --color-danger: rgba(239, 68, 68, 0.14); | ||
| 180 | --color-danger-border: rgba(248, 113, 113, 0.18); | ||
| 181 | --color-danger-foreground: #fca5a5; | ||
| 182 | |||
| 183 | /* Inputs */ | ||
| 184 | --color-input: #141414; | ||
| 185 | --color-input-border: rgba(255, 255, 255, 0.08); | ||
| 186 | --color-sidebar-search: rgba(118, 118, 128, 0.24); | ||
| 187 | --color-placeholder: #8e8e93; | ||
| 188 | |||
| 189 | /* Icons */ | ||
| 190 | --color-icon: #f5f5f5; | ||
| 191 | --color-icon-muted: #a3a3a3; | ||
| 192 | --color-icon-subtle: #8e8e93; | ||
| 193 | |||
| 194 | /* Header / glass chrome */ | ||
| 195 | --color-header: rgba(10, 10, 10, 0.97); | ||
| 196 | --color-header-border: rgba(255, 255, 255, 0.06); | ||
| 197 | --color-glass-surface: rgba(23, 23, 23, 0.78); | ||
| 198 | --color-glass-tint: rgba(23, 23, 23, 0.24); | ||
| 199 | |||
| 200 | /* StatusBar */ | ||
| 201 | --color-status-bar: #0a0a0a; | ||
| 202 | |||
| 203 | /* Markdown */ | ||
| 204 | --color-md-body: #e5e5e5; | ||
| 205 | --color-md-strong: #f5f5f5; | ||
| 206 | --color-md-link: #60a5fa; | ||
| 207 | --color-md-blockquote-border: rgba(255, 255, 255, 0.1); | ||
| 208 | --color-md-blockquote-bg: rgba(255, 255, 255, 0.03); | ||
| 209 | --color-md-code-bg: rgba(255, 255, 255, 0.06); | ||
| 210 | --color-md-code-text: #e5e5e5; | ||
| 211 | --color-md-user-code-bg: rgba(255, 255, 255, 0.06); | ||
| 212 | --color-md-user-code-text: #e5e5e5; | ||
| 213 | --color-md-user-fence-bg: rgba(255, 255, 255, 0.09); | ||
| 214 | --color-md-user-fence-text: #e5e5e5; | ||
| 215 | --color-md-hr: rgba(255, 255, 255, 0.08); | ||
| 216 | |||
| 217 | /* User bubble: a raised card on the thread canvas, matching web's message surface */ | ||
| 218 | --color-user-bubble: #171717; | ||
| 219 | --color-user-bubble-foreground: #f5f5f5; | ||
| 220 | --color-user-bubble-foreground-muted: rgba(245, 245, 245, 0.78); | ||
| 221 | --color-user-bubble-skill-foreground: #60a5fa; | ||
| 222 | |||
| 223 | /* Drawer / modal backdrop */ | ||
| 224 | --color-backdrop: rgba(0, 0, 0, 0.48); | ||
| 225 | --color-drawer: rgba(14, 14, 14, 0.99); | ||
| 226 | --color-drawer-shadow: rgba(0, 0, 0, 0.32); | ||
| 227 | |||
| 228 | /* Misc */ | ||
| 229 | --color-dot-separator: rgba(255, 255, 255, 0.2); | ||
| 230 | --color-wordmark: #f5f5f5; | ||
| 231 | --color-chevron: rgba(255, 255, 255, 0.2); | ||
| 232 | } | ||
| 233 | } | 11 | } |
| 234 | } | 12 | } |
| 235 | 13 |
apps/mobile/modules/t3-markdown-text/android/src/main/java/expo/modules/t3markdowntext/T3ContextChip.kt+9-1| ... | @@ -114,7 +114,15 @@ class T3ContextChip( | ... | @@ -114,7 +114,15 @@ class T3ContextChip( |
| 114 | fun color( | 114 | fun color( |
| 115 | value: String, | 115 | value: String, |
| 116 | fallback: Int | 116 | fallback: Int |
| 117 | ): Int = runCatching { Color.parseColor(value) }.getOrDefault(fallback) | 117 | ): Int = runCatching { |
| 118 | // React Native hex colors put alpha last; Android's parser puts it first. | ||
| 119 | val androidColor = if (value.length == 9 && value.startsWith("#")) { | ||
| 120 | "#${value.takeLast(2)}${value.substring(1, 7)}" | ||
| 121 | } else { | ||
| 122 | value | ||
| 123 | } | ||
| 124 | Color.parseColor(androidColor) | ||
| 125 | }.getOrDefault(fallback) | ||
| 118 | 126 | ||
| 119 | private fun blend(accent: Int, base: Int, weight: Float): Int = Color.rgb( | 127 | private fun blend(accent: Int, base: Int, weight: Float): Int = Color.rgb( |
| 120 | (Color.red(accent) * weight + Color.red(base) * (1 - weight)).toInt(), | 128 | (Color.red(accent) * weight + Color.red(base) * (1 - weight)).toInt(), |
apps/mobile/plugins/withAndroidModernAlertDialog.cjs+15-16| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const fs = require("node:fs"); | 1 | const fs = require("node:fs"); |
| 2 | const path = require("node:path"); | 2 | const path = require("node:path"); |
| 3 | const themeVariables = require("../generated-uniwind-default-theme-variables.json"); | ||
| 3 | const { | 4 | const { |
| 4 | AndroidConfig, | 5 | AndroidConfig, |
| 5 | withAndroidColors, | 6 | withAndroidColors, |
| ... | @@ -11,9 +12,10 @@ const { | ... | @@ -11,9 +12,10 @@ const { |
| 11 | // React Native's Alert renders an AppCompat AlertDialog on Android, which | 12 | // React Native's Alert renders an AppCompat AlertDialog on Android, which |
| 12 | // inherits the dated framework dialog chrome (square gray panel, teal | 13 | // inherits the dated framework dialog chrome (square gray panel, teal |
| 13 | // all-caps buttons) from the app theme. These resources restyle it with the | 14 | // all-caps buttons) from the app theme. These resources restyle it with the |
| 14 | // app's uniwind tokens from global.css: --color-card panel, --color-foreground | 15 | // generated default palette: card panel, foreground text, readable primary |
| 15 | // text, --color-primary buttons, DM Sans type. The @font resources referenced | 16 | // buttons, DM Sans type. Alert exposes no runtime custom-palette API, so these |
| 16 | // here are embedded by the expo-font plugin config in app.config.ts. | 17 | // build-time resources use the stock palette for each native appearance. |
| 18 | // The fonts are embedded by the expo-font plugin config in app.config.ts. | ||
| 17 | 19 | ||
| 18 | // AppCompat's default dialog window background is an inset rounded rect, so | 20 | // AppCompat's default dialog window background is an inset rounded rect, so |
| 19 | // the replacement keeps the same 16dp inset to preserve the dialog's margins. | 21 | // the replacement keeps the same 16dp inset to preserve the dialog's margins. |
| ... | @@ -30,21 +32,18 @@ const DIALOG_BACKGROUND_DRAWABLE = `<?xml version="1.0" encoding="utf-8"?> | ... | @@ -30,21 +32,18 @@ const DIALOG_BACKGROUND_DRAWABLE = `<?xml version="1.0" encoding="utf-8"?> |
| 30 | </inset> | 32 | </inset> |
| 31 | `; | 33 | `; |
| 32 | 34 | ||
| 33 | const COLORS = { | 35 | const colorsFor = (appearance) => { |
| 34 | light: { | 36 | const variables = themeVariables[appearance]; |
| 35 | background: "#FFFFFF", // --color-card | 37 | return { |
| 36 | text: "#262626", // --color-foreground | 38 | background: variables["--color-card"], |
| 37 | secondaryText: "#525252", // --color-foreground-secondary | 39 | text: variables["--color-foreground"], |
| 38 | buttonText: "#262626", // --color-primary | 40 | secondaryText: variables["--color-foreground-secondary"], |
| 39 | }, | 41 | buttonText: variables["--color-primary-text"], |
| 40 | night: { | 42 | }; |
| 41 | background: "#171717", | ||
| 42 | text: "#F5F5F5", | ||
| 43 | secondaryText: "#A3A3A3", | ||
| 44 | buttonText: "#F5F5F5", | ||
| 45 | }, | ||
| 46 | }; | 43 | }; |
| 47 | 44 | ||
| 45 | const COLORS = { light: colorsFor("light"), night: colorsFor("dark") }; | ||
| 46 | |||
| 48 | function assignStyleItem(style, name, value) { | 47 | function assignStyleItem(style, name, value) { |
| 49 | style.item = style.item ?? []; | 48 | style.item = style.item ?? []; |
| 50 | const existing = style.item.find((item) => item.$?.name === name); | 49 | const existing = style.item.find((item) => item.$?.name === name); |
apps/mobile/scripts/generate-uniwind-themes.mts+46-44| ... | @@ -5,17 +5,15 @@ import * as NodePath from "node:path"; | ... | @@ -5,17 +5,15 @@ import * as NodePath from "node:path"; |
| 5 | import tailwindColors from "tailwindcss/colors"; | 5 | import tailwindColors from "tailwindcss/colors"; |
| 6 | import { BUILT_IN_THEME_IDS, type BuiltInThemeId } from "@t3tools/shared/themePalettes"; | 6 | import { BUILT_IN_THEME_IDS, type BuiltInThemeId } from "@t3tools/shared/themePalettes"; |
| 7 | 7 | ||
| 8 | import clerkTheme from "../clerk-theme.json" with { type: "json" }; | ||
| 9 | import { | 8 | import { |
| 9 | createMobileThemeVariables, | ||
| 10 | getMobileThemeColors, | ||
| 10 | getMobileThemeVariables, | 11 | getMobileThemeVariables, |
| 11 | MOBILE_THEME_VARIABLE_NAMES, | 12 | DEFAULT_MOBILE_THEME_ID, |
| 12 | themeColorWithAlpha, | ||
| 13 | type MobileThemeAppearance, | 13 | type MobileThemeAppearance, |
| 14 | type MobileThemeVariables, | ||
| 15 | } from "../src/lib/mobileTheme.ts"; | 14 | } from "../src/lib/mobileTheme.ts"; |
| 16 | 15 | ||
| 17 | const APPEARANCES = ["light", "dark"] as const; | 16 | const APPEARANCES = ["light", "dark"] as const; |
| 18 | const GLOBAL_CSS_PATH = NodePath.resolve(import.meta.dirname, "../global.css"); | ||
| 19 | const GENERATED_CSS_PATH = NodePath.resolve(import.meta.dirname, "../generated-uniwind-themes.css"); | 17 | const GENERATED_CSS_PATH = NodePath.resolve(import.meta.dirname, "../generated-uniwind-themes.css"); |
| 20 | const GENERATED_NAMES_PATH = NodePath.resolve( | 18 | const GENERATED_NAMES_PATH = NodePath.resolve( |
| 21 | import.meta.dirname, | 19 | import.meta.dirname, |
| ... | @@ -25,6 +23,7 @@ const GENERATED_DEFAULT_VARIABLES_PATH = NodePath.resolve( | ... | @@ -25,6 +23,7 @@ const GENERATED_DEFAULT_VARIABLES_PATH = NodePath.resolve( |
| 25 | import.meta.dirname, | 23 | import.meta.dirname, |
| 26 | "../generated-uniwind-default-theme-variables.json", | 24 | "../generated-uniwind-default-theme-variables.json", |
| 27 | ); | 25 | ); |
| 26 | const GENERATED_CLERK_THEME_PATH = NodePath.resolve(import.meta.dirname, "../clerk-theme.json"); | ||
| 28 | 27 | ||
| 29 | type TailwindColorFamily = keyof typeof tailwindColors; | 28 | type TailwindColorFamily = keyof typeof tailwindColors; |
| 30 | type TailwindColorShade = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950; | 29 | type TailwindColorShade = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950; |
| ... | @@ -159,13 +158,38 @@ const variablesFor = (themeId: BuiltInThemeId, appearance: MobileThemeAppearance | ... | @@ -159,13 +158,38 @@ const variablesFor = (themeId: BuiltInThemeId, appearance: MobileThemeAppearance |
| 159 | 158 | ||
| 160 | // Clerk's native screens use one build-time palette per appearance. Custom | 159 | // Clerk's native screens use one build-time palette per appearance. Custom |
| 161 | // profile pages must match it even when the rest of the app uses a named theme. | 160 | // profile pages must match it even when the rest of the app uses a named theme. |
| 161 | const clerkColorsFor = (appearance: MobileThemeAppearance) => { | ||
| 162 | // Native authentication uses plain cards, rather than tonal settings groups. | ||
| 163 | const variables = createMobileThemeVariables( | ||
| 164 | getMobileThemeColors(DEFAULT_MOBILE_THEME_ID, appearance), | ||
| 165 | appearance, | ||
| 166 | ); | ||
| 167 | return { | ||
| 168 | primary: variables["--color-primary"], | ||
| 169 | background: variables["--color-sheet-solid"], | ||
| 170 | input: variables["--color-input"], | ||
| 171 | danger: variables["--color-danger-foreground"], | ||
| 172 | success: appearance === "dark" ? "#34d399" : "#059669", | ||
| 173 | warning: variables["--color-warning-foreground"], | ||
| 174 | foreground: variables["--color-foreground"], | ||
| 175 | mutedForeground: variables["--color-foreground-muted"], | ||
| 176 | primaryForeground: variables["--color-primary-foreground"], | ||
| 177 | inputForeground: variables["--color-foreground"], | ||
| 178 | neutral: variables["--color-secondary"], | ||
| 179 | border: variables["--color-border"], | ||
| 180 | ring: variables["--color-focus"], | ||
| 181 | muted: variables["--color-subtle"], | ||
| 182 | shadow: variables["--color-primary-shadow"], | ||
| 183 | }; | ||
| 184 | }; | ||
| 185 | |||
| 162 | const clerkVariablesFor = (appearance: MobileThemeAppearance) => { | 186 | const clerkVariablesFor = (appearance: MobileThemeAppearance) => { |
| 163 | const colors = appearance === "dark" ? clerkTheme.darkColors : clerkTheme.colors; | 187 | const colors = clerkColorsFor(appearance); |
| 164 | return { | 188 | return { |
| 165 | "--color-clerk-page": colors.background.toLowerCase(), | 189 | "--color-clerk-page": colors.background.toLowerCase(), |
| 166 | "--color-clerk-foreground": colors.foreground.toLowerCase(), | 190 | "--color-clerk-foreground": colors.foreground.toLowerCase(), |
| 167 | "--color-clerk-foreground-muted": colors.mutedForeground.toLowerCase(), | 191 | "--color-clerk-foreground-muted": colors.mutedForeground.toLowerCase(), |
| 168 | "--color-clerk-border": themeColorWithAlpha(colors.border, 0.06), | 192 | "--color-clerk-border": colors.border, |
| 169 | "--color-clerk-danger": colors.danger.toLowerCase(), | 193 | "--color-clerk-danger": colors.danger.toLowerCase(), |
| 170 | }; | 194 | }; |
| 171 | }; | 195 | }; |
| ... | @@ -181,6 +205,7 @@ export const renderUniwindThemesCSS = () => { | ... | @@ -181,6 +205,7 @@ export const renderUniwindThemesCSS = () => { |
| 181 | const variants = [ | 205 | const variants = [ |
| 182 | ...APPEARANCES.map((appearance) => | 206 | ...APPEARANCES.map((appearance) => |
| 183 | renderVariant(appearance, { | 207 | renderVariant(appearance, { |
| 208 | ...getMobileThemeVariables(DEFAULT_MOBILE_THEME_ID, appearance), | ||
| 184 | ...adaptiveVariablesFor(appearance), | 209 | ...adaptiveVariablesFor(appearance), |
| 185 | ...clerkVariablesFor(appearance), | 210 | ...clerkVariablesFor(appearance), |
| 186 | }), | 211 | }), |
| ... | @@ -202,50 +227,27 @@ export const renderUniwindThemesCSS = () => { | ... | @@ -202,50 +227,27 @@ export const renderUniwindThemesCSS = () => { |
| 202 | ].join("\n"); | 227 | ].join("\n"); |
| 203 | }; | 228 | }; |
| 204 | 229 | ||
| 205 | const readVariantBody = (css: string, appearance: MobileThemeAppearance): string => { | 230 | export const renderDefaultThemeVariablesJSON = () => |
| 206 | const marker = `@variant ${appearance} {`; | 231 | `${JSON.stringify( |
| 207 | const markerIndex = css.indexOf(marker); | 232 | Object.fromEntries( |
| 208 | if (markerIndex === -1) throw new Error(`Could not find ${marker} in global.css.`); | 233 | APPEARANCES.map((appearance) => [ |
| 209 | 234 | appearance, | |
| 210 | const openingBraceIndex = css.indexOf("{", markerIndex); | 235 | getMobileThemeVariables(DEFAULT_MOBILE_THEME_ID, appearance), |
| 211 | let depth = 0; | 236 | ]), |
| 212 | for (let index = openingBraceIndex; index < css.length; index += 1) { | 237 | ), |
| 213 | if (css[index] === "{") depth += 1; | 238 | null, |
| 214 | if (css[index] !== "}") continue; | 239 | 2, |
| 215 | depth -= 1; | 240 | )}\n`; |
| 216 | if (depth === 0) return css.slice(openingBraceIndex + 1, index); | ||
| 217 | } | ||
| 218 | throw new Error(`Could not find the end of ${marker} in global.css.`); | ||
| 219 | }; | ||
| 220 | |||
| 221 | export const readDefaultThemeVariables = (css: string) => | ||
| 222 | Object.fromEntries( | ||
| 223 | APPEARANCES.map((appearance) => { | ||
| 224 | const body = readVariantBody(css, appearance); | ||
| 225 | const variables = Object.fromEntries( | ||
| 226 | MOBILE_THEME_VARIABLE_NAMES.map((name) => { | ||
| 227 | const match = new RegExp(`^\\s*${name}:\\s*([^;]+);`, "mu").exec(body); | ||
| 228 | if (!match?.[1]) { | ||
| 229 | throw new Error(`Default ${appearance} theme is missing ${name}.`); | ||
| 230 | } | ||
| 231 | return [name, match[1].trim()]; | ||
| 232 | }), | ||
| 233 | ) as MobileThemeVariables; | ||
| 234 | return [appearance, variables]; | ||
| 235 | }), | ||
| 236 | ) as Readonly<Record<MobileThemeAppearance, MobileThemeVariables>>; | ||
| 237 | |||
| 238 | export const renderDefaultThemeVariablesJSON = (css: string) => | ||
| 239 | `${JSON.stringify(readDefaultThemeVariables(css), null, 2)}\n`; | ||
| 240 | 241 | ||
| 241 | export const getGeneratedUniwindThemeOutputs = (): ReadonlyArray< | 242 | export const getGeneratedUniwindThemeOutputs = (): ReadonlyArray< |
| 242 | readonly [filename: string, contents: string] | 243 | readonly [filename: string, contents: string] |
| 243 | > => [ | 244 | > => [ |
| 244 | [GENERATED_CSS_PATH, renderUniwindThemesCSS()], | 245 | [GENERATED_CSS_PATH, renderUniwindThemesCSS()], |
| 245 | [GENERATED_NAMES_PATH, `${JSON.stringify(customThemeNames, null, 2)}\n`], | 246 | [GENERATED_NAMES_PATH, `${JSON.stringify(customThemeNames, null, 2)}\n`], |
| 247 | [GENERATED_DEFAULT_VARIABLES_PATH, renderDefaultThemeVariablesJSON()], | ||
| 246 | [ | 248 | [ |
| 247 | GENERATED_DEFAULT_VARIABLES_PATH, | 249 | GENERATED_CLERK_THEME_PATH, |
| 248 | renderDefaultThemeVariablesJSON(NodeFS.readFileSync(GLOBAL_CSS_PATH, "utf8")), | 250 | `${JSON.stringify({ colors: clerkColorsFor("light"), darkColors: clerkColorsFor("dark"), design: { borderRadius: 18 } }, null, 2)}\n`, |
| 249 | ], | 251 | ], |
| 250 | ]; | 252 | ]; |
| 251 | 253 |
apps/mobile/scripts/generate-uniwind-themes.test.ts+14-10| ... | @@ -5,9 +5,10 @@ import { describe, expect, it } from "vite-plus/test"; | ... | @@ -5,9 +5,10 @@ import { describe, expect, it } from "vite-plus/test"; |
| 5 | import { | 5 | import { |
| 6 | customThemeNames, | 6 | customThemeNames, |
| 7 | getGeneratedUniwindThemeOutputs, | 7 | getGeneratedUniwindThemeOutputs, |
| 8 | readDefaultThemeVariables, | 8 | renderDefaultThemeVariablesJSON, |
| 9 | renderUniwindThemesCSS, | 9 | renderUniwindThemesCSS, |
| 10 | } from "./generate-uniwind-themes.mts"; | 10 | } from "./generate-uniwind-themes.mts"; |
| 11 | import { readDefaultMobileThemeVariables } from "../src/lib/mobileTheme.test-support"; | ||
| 11 | 12 | ||
| 12 | describe("generate mobile Uniwind themes", () => { | 13 | describe("generate mobile Uniwind themes", () => { |
| 13 | it("keeps the committed outputs current", () => { | 14 | it("keeps the committed outputs current", () => { |
| ... | @@ -44,12 +45,15 @@ describe("generate mobile Uniwind themes", () => { | ... | @@ -44,12 +45,15 @@ describe("generate mobile Uniwind themes", () => { |
| 44 | } | 45 | } |
| 45 | }); | 46 | }); |
| 46 | 47 | ||
| 47 | it("generates the default runtime bridge from the authored CSS", () => { | 48 | it("keeps the default runtime bridge and generated CSS on the same palette", () => { |
| 48 | const css = NodeFS.readFileSync(NodePath.resolve(import.meta.dirname, "../global.css"), "utf8"); | 49 | const variables = JSON.parse(renderDefaultThemeVariablesJSON()); |
| 49 | const variables = readDefaultThemeVariables(css); | ||
| 50 | 50 | ||
| 51 | expect(variables.light["--color-screen"]).toBe("#f2f2f7"); | 51 | expect(variables.light).toEqual(readDefaultMobileThemeVariables("light")); |
| 52 | expect(variables.dark).toEqual(readDefaultMobileThemeVariables("dark")); | ||
| 53 | expect(variables.light["--color-screen"]).toBe("#fcfcfc"); | ||
| 54 | expect(variables.light["--color-drawer"]).toBe("#fafafa"); | ||
| 52 | expect(variables.dark["--color-screen"]).toBe("#0a0a0a"); | 55 | expect(variables.dark["--color-screen"]).toBe("#0a0a0a"); |
| 56 | expect(variables.dark["--color-drawer"]).toBe("#000000"); | ||
| 53 | expect(Object.keys(variables.light)).toEqual(Object.keys(variables.dark)); | 57 | expect(Object.keys(variables.light)).toEqual(Object.keys(variables.dark)); |
| 54 | }); | 58 | }); |
| 55 | 59 | ||
| ... | @@ -77,11 +81,11 @@ describe("generate mobile Uniwind themes", () => { | ... | @@ -77,11 +81,11 @@ describe("generate mobile Uniwind themes", () => { |
| 77 | ), | 81 | ), |
| 78 | name, | 82 | name, |
| 79 | ).toEqual({ | 83 | ).toEqual({ |
| 80 | "--color-clerk-page": isDark ? "#0e0e0e" : "#f2f2f7", | 84 | "--color-clerk-page": isDark ? "#0a0a0a" : "#fcfcfc", |
| 81 | "--color-clerk-foreground": isDark ? "#f5f5f5" : "#262626", | 85 | "--color-clerk-foreground": isDark ? "#f5f5f5" : "#27272a", |
| 82 | "--color-clerk-foreground-muted": isDark ? "#a3a3a3" : "#737373", | 86 | "--color-clerk-foreground-muted": isDark ? "#818181" : "#71717b", |
| 83 | "--color-clerk-border": isDark ? "rgba(42, 42, 42, 0.06)" : "rgba(229, 229, 234, 0.06)", | 87 | "--color-clerk-border": isDark ? "#191919" : "#e4e4e7", |
| 84 | "--color-clerk-danger": isDark ? "#fca5a5" : "#dc2626", | 88 | "--color-clerk-danger": isDark ? "#ff6467" : "#c10007", |
| 85 | }); | 89 | }); |
| 86 | } | 90 | } |
| 87 | }); | 91 | }); |
apps/mobile/src/components/AndroidScreenHeader.tsx+10-2| ... | @@ -25,7 +25,13 @@ export function AndroidHeaderIconButton(props: { | ... | @@ -25,7 +25,13 @@ export function AndroidHeaderIconButton(props: { |
| 25 | readonly disabled?: boolean; | 25 | readonly disabled?: boolean; |
| 26 | readonly selected?: boolean; | 26 | readonly selected?: boolean; |
| 27 | }) { | 27 | }) { |
| 28 | return <MaterialIconButton {...props} variant={props.selected ? "tonal" : "standard"} />; | 28 | return ( |
| 29 | <MaterialIconButton | ||
| 30 | {...props} | ||
| 31 | tintColorClassName="accent-header-foreground" | ||
| 32 | variant={props.selected ? "tonal" : "standard"} | ||
| 33 | /> | ||
| 34 | ); | ||
| 29 | } | 35 | } |
| 30 | 36 | ||
| 31 | export function AndroidScreenHeader(props: { | 37 | export function AndroidScreenHeader(props: { |
| ... | @@ -65,6 +71,7 @@ export function AndroidScreenHeader(props: { | ... | @@ -65,6 +71,7 @@ export function AndroidScreenHeader(props: { |
| 65 | <MaterialIconButton | 71 | <MaterialIconButton |
| 66 | accessibilityLabel="Navigate up" | 72 | accessibilityLabel="Navigate up" |
| 67 | icon="arrow.left" | 73 | icon="arrow.left" |
| 74 | tintColorClassName="accent-header-foreground" | ||
| 68 | onPress={props.onBack} | 75 | onPress={props.onBack} |
| 69 | /> | 76 | /> |
| 70 | ) : null} | 77 | ) : null} |
| ... | @@ -72,7 +79,7 @@ export function AndroidScreenHeader(props: { | ... | @@ -72,7 +79,7 @@ export function AndroidScreenHeader(props: { |
| 72 | {props.leading} | 79 | {props.leading} |
| 73 | 80 | ||
| 74 | <View className={cn("min-w-0 flex-1", !props.onBack && "pl-1")}> | 81 | <View className={cn("min-w-0 flex-1", !props.onBack && "pl-1")}> |
| 75 | <Text numberOfLines={1} style={titleTypography} className="text-foreground"> | 82 | <Text numberOfLines={1} style={titleTypography} className="text-header-foreground"> |
| 76 | {props.title} | 83 | {props.title} |
| 77 | </Text> | 84 | </Text> |
| 78 | {props.subtitle ? ( | 85 | {props.subtitle ? ( |
| ... | @@ -114,6 +121,7 @@ export function AndroidScreenHeader(props: { | ... | @@ -114,6 +121,7 @@ export function AndroidScreenHeader(props: { |
| 114 | <MaterialIconButton | 121 | <MaterialIconButton |
| 115 | accessibilityLabel="More actions" | 122 | accessibilityLabel="More actions" |
| 116 | icon="ellipsis" | 123 | icon="ellipsis" |
| 124 | tintColorClassName="accent-header-foreground" | ||
| 117 | onPress={open} | 125 | onPress={open} |
| 118 | /> | 126 | /> |
| 119 | )} | 127 | )} |
apps/mobile/src/components/AppText.tsx+4-8| ... | @@ -18,7 +18,7 @@ export function AppText({ className, ...props }: AppTextProps) { | ... | @@ -18,7 +18,7 @@ export function AppText({ className, ...props }: AppTextProps) { |
| 18 | return ( | 18 | return ( |
| 19 | <RNText | 19 | <RNText |
| 20 | className={cn("font-sans text-foreground", className)} | 20 | className={cn("font-sans text-foreground", className)} |
| 21 | selectionColorClassName={Platform.OS === "android" ? "accent-primary/32" : undefined} | 21 | selectionColorClassName={Platform.OS === "android" ? "accent-focus/32" : undefined} |
| 22 | {...props} | 22 | {...props} |
| 23 | /> | 23 | /> |
| 24 | ); | 24 | ); |
| ... | @@ -42,13 +42,9 @@ export function AppTextInput({ className, ref, ...props }: AppTextInputProps) { | ... | @@ -42,13 +42,9 @@ export function AppTextInput({ className, ref, ...props }: AppTextInputProps) { |
| 42 | className, | 42 | className, |
| 43 | )} | 43 | )} |
| 44 | placeholderTextColorClassName="accent-placeholder" | 44 | placeholderTextColorClassName="accent-placeholder" |
| 45 | selectionColorClassName={ | 45 | selectionColorClassName={"accent-focus/32"} |
| 46 | Platform.OS === "android" ? "accent-primary/32" : "accent-foreground-secondary" | 46 | cursorColorClassName={"accent-focus"} |
| 47 | } | 47 | selectionHandleColorClassName={Platform.OS === "android" ? "accent-focus" : undefined} |
| 48 | cursorColorClassName={ | ||
| 49 | Platform.OS === "android" ? "accent-primary" : "accent-foreground-secondary" | ||
| 50 | } | ||
| 51 | selectionHandleColorClassName={Platform.OS === "android" ? "accent-primary" : undefined} | ||
| 52 | {...props} | 48 | {...props} |
| 53 | /> | 49 | /> |
| 54 | ); | 50 | ); |
apps/mobile/src/components/ComposerContextSheet.tsx+3-5| ... | @@ -187,11 +187,9 @@ export function ComposerContextSheet(props: { | ... | @@ -187,11 +187,9 @@ export function ComposerContextSheet(props: { |
| 187 | onRequestClose={props.onClose} | 187 | onRequestClose={props.onClose} |
| 188 | > | 188 | > |
| 189 | <View | 189 | <View |
| 190 | style={{ | 190 | className={ |
| 191 | flex: 1, | 191 | Platform.OS === "android" ? "flex-1 justify-end bg-backdrop" : "flex-1 justify-end" |
| 192 | justifyContent: "flex-end", | 192 | } |
| 193 | backgroundColor: Platform.OS === "android" ? "#00000066" : undefined, | ||
| 194 | }} | ||
| 195 | > | 193 | > |
| 196 | {Platform.OS === "android" ? ( | 194 | {Platform.OS === "android" ? ( |
| 197 | <Pressable | 195 | <Pressable |
apps/mobile/src/components/ControlPill.tsx+3-1| ... | @@ -72,7 +72,9 @@ export function ControlPill(props: { | ... | @@ -72,7 +72,9 @@ export function ControlPill(props: { |
| 72 | ? props.disabled | 72 | ? props.disabled |
| 73 | ? "text-foreground-muted" | 73 | ? "text-foreground-muted" |
| 74 | : "text-primary-foreground" | 74 | : "text-primary-foreground" |
| 75 | : "", | 75 | : variant === "danger" |
| 76 | ? "text-danger-foreground" | ||
| 77 | : "text-foreground", | ||
| 76 | ); | 78 | ); |
| 77 | 79 | ||
| 78 | if ( | 80 | if ( |
apps/mobile/src/components/FilePreview.tsx+1-1| ... | @@ -46,7 +46,7 @@ function DocumentPreview(props: { | ... | @@ -46,7 +46,7 @@ function DocumentPreview(props: { |
| 46 | }, [uri, name, props.source.mimeType, props.source.kind]); | 46 | }, [uri, name, props.source.mimeType, props.source.kind]); |
| 47 | return ( | 47 | return ( |
| 48 | <Modal transparent animationType="fade" onRequestClose={props.onRequestClose}> | 48 | <Modal transparent animationType="fade" onRequestClose={props.onRequestClose}> |
| 49 | <View className="flex-1 items-center justify-center bg-black/40 p-6"> | 49 | <View className="flex-1 items-center justify-center bg-backdrop p-6"> |
| 50 | <View className="w-full max-w-sm gap-4 rounded-2xl bg-sheet-solid p-6"> | 50 | <View className="w-full max-w-sm gap-4 rounded-2xl bg-sheet-solid p-6"> |
| 51 | <Text className="font-t3-semibold text-foreground">Opening document…</Text> | 51 | <Text className="font-t3-semibold text-foreground">Opening document…</Text> |
| 52 | <Text className="text-foreground-muted" numberOfLines={2}> | 52 | <Text className="text-foreground-muted" numberOfLines={2}> |
apps/mobile/src/components/GlassBackdrop.tsx+8-10| ... | @@ -6,12 +6,13 @@ import { themeColorWithAlpha } from "../lib/mobileTheme"; | ... | @@ -6,12 +6,13 @@ import { themeColorWithAlpha } from "../lib/mobileTheme"; |
| 6 | 6 | ||
| 7 | /** Frosted backdrop for containers that clip their children to their shape. */ | 7 | /** Frosted backdrop for containers that clip their children to their shape. */ |
| 8 | export function GlassBackdrop(props: { readonly fallbackColor?: ColorValue }) { | 8 | export function GlassBackdrop(props: { readonly fallbackColor?: ColorValue }) { |
| 9 | const { themeAppearance } = useAppearancePreferences(); | 9 | const { themeAppearance, themeVariables } = useAppearancePreferences(); |
| 10 | const supportsBlur = Platform.OS === "ios"; | 10 | const supportsBlur = Platform.OS === "ios"; |
| 11 | const colorStyle = | 11 | const color = props.fallbackColor ?? themeVariables["--color-glass-fallback"]; |
| 12 | props.fallbackColor === undefined | 12 | const colorStyle = { |
| 13 | ? undefined | 13 | backgroundColor: |
| 14 | : { backgroundColor: themeColorWithAlpha(String(props.fallbackColor), 1) }; | 14 | supportsBlur || typeof color !== "string" ? color : themeColorWithAlpha(color, 1), |
| 15 | }; | ||
| 15 | 16 | ||
| 16 | return ( | 17 | return ( |
| 17 | <> | 18 | <> |
| ... | @@ -25,11 +26,8 @@ export function GlassBackdrop(props: { readonly fallbackColor?: ColorValue }) { | ... | @@ -25,11 +26,8 @@ export function GlassBackdrop(props: { readonly fallbackColor?: ColorValue }) { |
| 25 | ) : null} | 26 | ) : null} |
| 26 | <View | 27 | <View |
| 27 | pointerEvents="none" | 28 | pointerEvents="none" |
| 28 | className="absolute inset-0 bg-card" | 29 | className="absolute inset-0 bg-glass-fallback" |
| 29 | style={[ | 30 | style={colorStyle} |
| 30 | colorStyle, | ||
| 31 | { opacity: supportsBlur ? (themeAppearance === "dark" ? 0.25 : 0.55) : 1 }, | ||
| 32 | ]} | ||
| 33 | /> | 31 | /> |
| 34 | </> | 32 | </> |
| 35 | ); | 33 | ); |
apps/mobile/src/components/GlassSurface.tsx+4-9| ... | @@ -1,16 +1,10 @@ | ... | @@ -1,16 +1,10 @@ |
| 1 | import { GlassView, isGlassEffectAPIAvailable } from "expo-glass-effect"; | 1 | import { GlassView, isGlassEffectAPIAvailable } from "expo-glass-effect"; |
| 2 | import type { ReactNode, Ref } from "react"; | 2 | import type { ReactNode, Ref } from "react"; |
| 3 | import { | 3 | import { Platform, View, type ColorValue, type ViewProps, type ViewStyle } from "react-native"; |
| 4 | Platform, | ||
| 5 | useColorScheme, | ||
| 6 | View, | ||
| 7 | type ColorValue, | ||
| 8 | type ViewProps, | ||
| 9 | type ViewStyle, | ||
| 10 | } from "react-native"; | ||
| 11 | import { withUniwind } from "uniwind"; | 4 | import { withUniwind } from "uniwind"; |
| 12 | 5 | ||
| 13 | import { cn } from "../lib/cn"; | 6 | import { cn } from "../lib/cn"; |
| 7 | import { useAppearancePreferences } from "../features/settings/appearance/AppearancePreferencesProvider"; | ||
| 14 | import { GlassBackdrop } from "./GlassBackdrop"; | 8 | import { GlassBackdrop } from "./GlassBackdrop"; |
| 15 | 9 | ||
| 16 | // Explicit mappings keep the native glassEffectStyle enum out of style-array conversion. | 10 | // Explicit mappings keep the native glassEffectStyle enum out of style-array conversion. |
| ... | @@ -45,7 +39,8 @@ export function GlassSurface({ | ... | @@ -45,7 +39,8 @@ export function GlassSurface({ |
| 45 | style, | 39 | style, |
| 46 | ...props | 40 | ...props |
| 47 | }: GlassSurfaceProps) { | 41 | }: GlassSurfaceProps) { |
| 48 | const isDarkMode = useColorScheme() === "dark"; | 42 | const { themeAppearance } = useAppearancePreferences(); |
| 43 | const isDarkMode = themeAppearance === "dark"; | ||
| 49 | const supportsGlass = Platform.OS === "ios" && isGlassEffectAPIAvailable(); | 44 | const supportsGlass = Platform.OS === "ios" && isGlassEffectAPIAvailable(); |
| 50 | const hasShadow = chrome !== "none" && Platform.OS !== "android"; | 45 | const hasShadow = chrome !== "none" && Platform.OS !== "android"; |
| 51 | const surfaceStyle: ViewStyle = { | 46 | const surfaceStyle: ViewStyle = { |
apps/mobile/src/components/MaterialButton.android.tsx+1-1| ... | @@ -35,7 +35,7 @@ export function MaterialButton(props: MaterialButtonProps) { | ... | @@ -35,7 +35,7 @@ export function MaterialButton(props: MaterialButtonProps) { |
| 35 | : tone === "danger" | 35 | : tone === "danger" |
| 36 | ? colors["--color-danger-foreground"] | 36 | ? colors["--color-danger-foreground"] |
| 37 | : tone === "text" | 37 | : tone === "text" |
| 38 | ? colors["--color-primary"] | 38 | ? colors["--color-primary-text"] |
| 39 | : colors["--color-secondary-foreground"]; | 39 | : colors["--color-secondary-foreground"]; |
| 40 | return ( | 40 | return ( |
| 41 | <View | 41 | <View |
apps/mobile/src/components/MaterialButton.tsx+25-3| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | import { Pressable } from "react-native"; | 1 | import { Pressable } from "react-native"; |
| 2 | import { AppText } from "./AppText"; | 2 | import { AppText } from "./AppText"; |
| 3 | import { cn } from "../lib/cn"; | ||
| 3 | 4 | ||
| 4 | export interface MaterialButtonProps { | 5 | export interface MaterialButtonProps { |
| 5 | readonly label: string; | 6 | readonly label: string; |
| ... | @@ -10,15 +11,36 @@ export interface MaterialButtonProps { | ... | @@ -10,15 +11,36 @@ export interface MaterialButtonProps { |
| 10 | readonly fullWidth?: boolean; | 11 | readonly fullWidth?: boolean; |
| 11 | } | 12 | } |
| 12 | 13 | ||
| 14 | const TONE_CLASS_NAMES = { | ||
| 15 | primary: ["bg-primary", "text-primary-foreground"], | ||
| 16 | secondary: ["bg-secondary", "text-secondary-foreground"], | ||
| 17 | danger: ["bg-danger", "text-danger-foreground"], | ||
| 18 | text: ["bg-transparent", "text-primary-text"], | ||
| 19 | } as const; | ||
| 20 | |||
| 13 | export function MaterialButton(props: MaterialButtonProps) { | 21 | export function MaterialButton(props: MaterialButtonProps) { |
| 22 | const [containerClassName, labelClassName] = TONE_CLASS_NAMES[props.tone ?? "secondary"]; | ||
| 23 | const disabled = Boolean(props.disabled || props.loading); | ||
| 14 | return ( | 24 | return ( |
| 15 | <Pressable | 25 | <Pressable |
| 16 | accessibilityRole="button" | 26 | accessibilityRole="button" |
| 17 | disabled={props.disabled} | 27 | accessibilityState={{ disabled }} |
| 28 | disabled={disabled} | ||
| 18 | onPress={props.onPress} | 29 | onPress={props.onPress} |
| 19 | className="min-h-12 justify-center rounded-full bg-secondary px-6" | 30 | className={cn( |
| 31 | "min-h-12 justify-center rounded-full px-6 active:opacity-70", | ||
| 32 | props.fullWidth ? "w-full" : "self-start", | ||
| 33 | disabled ? "bg-subtle-strong" : containerClassName, | ||
| 34 | )} | ||
| 20 | > | 35 | > |
| 21 | <AppText>{props.label}</AppText> | 36 | <AppText |
| 37 | className={cn( | ||
| 38 | "text-center font-t3-medium", | ||
| 39 | disabled ? "text-foreground-muted" : labelClassName, | ||
| 40 | )} | ||
| 41 | > | ||
| 42 | {props.label} | ||
| 43 | </AppText> | ||
| 22 | </Pressable> | 44 | </Pressable> |
| 23 | ); | 45 | ); |
| 24 | } | 46 | } |
apps/mobile/src/components/MaterialConfirmDialog.android.tsx+9-4| ... | @@ -58,9 +58,9 @@ export function MaterialConfirmDialog(props: MaterialConfirmDialogProps) { | ... | @@ -58,9 +58,9 @@ export function MaterialConfirmDialog(props: MaterialConfirmDialogProps) { |
| 58 | colors={{ | 58 | colors={{ |
| 59 | focusedTextColor: colors["--color-foreground"], | 59 | focusedTextColor: colors["--color-foreground"], |
| 60 | unfocusedTextColor: colors["--color-foreground"], | 60 | unfocusedTextColor: colors["--color-foreground"], |
| 61 | focusedIndicatorColor: colors["--color-primary"], | 61 | focusedIndicatorColor: colors["--color-focus"], |
| 62 | unfocusedIndicatorColor: colors["--color-border"], | 62 | unfocusedIndicatorColor: colors["--color-border"], |
| 63 | cursorColor: colors["--color-primary"], | 63 | cursorColor: colors["--color-focus"], |
| 64 | }} | 64 | }} |
| 65 | > | 65 | > |
| 66 | <OutlinedTextField.Label> | 66 | <OutlinedTextField.Label> |
| ... | @@ -74,7 +74,10 @@ export function MaterialConfirmDialog(props: MaterialConfirmDialogProps) { | ... | @@ -74,7 +74,10 @@ export function MaterialConfirmDialog(props: MaterialConfirmDialogProps) { |
| 74 | </AlertDialog.Text> | 74 | </AlertDialog.Text> |
| 75 | ) : null} | 75 | ) : null} |
| 76 | <AlertDialog.DismissButton> | 76 | <AlertDialog.DismissButton> |
| 77 | <TextButton onClick={props.onCancel} colors={{ contentColor: colors["--color-primary"] }}> | 77 | <TextButton |
| 78 | onClick={props.onCancel} | ||
| 79 | colors={{ contentColor: colors["--color-primary-text"] }} | ||
| 80 | > | ||
| 78 | <Text style={bodyTypography}>{props.request.cancelText ?? "Cancel"}</Text> | 81 | <Text style={bodyTypography}>{props.request.cancelText ?? "Cancel"}</Text> |
| 79 | </TextButton> | 82 | </TextButton> |
| 80 | </AlertDialog.DismissButton> | 83 | </AlertDialog.DismissButton> |
| ... | @@ -84,7 +87,9 @@ export function MaterialConfirmDialog(props: MaterialConfirmDialogProps) { | ... | @@ -84,7 +87,9 @@ export function MaterialConfirmDialog(props: MaterialConfirmDialogProps) { |
| 84 | enabled={!props.confirmDisabled} | 87 | enabled={!props.confirmDisabled} |
| 85 | colors={{ | 88 | colors={{ |
| 86 | contentColor: | 89 | contentColor: |
| 87 | colors[props.request.destructive ? "--color-danger" : "--color-primary"], | 90 | colors[ |
| 91 | props.request.destructive ? "--color-danger-foreground" : "--color-primary-text" | ||
| 92 | ], | ||
| 88 | }} | 93 | }} |
| 89 | > | 94 | > |
| 90 | <Text style={bodyTypography}>{props.request.confirmText}</Text> | 95 | <Text style={bodyTypography}>{props.request.confirmText}</Text> |
apps/mobile/src/components/MaterialFloatingActionButton.android.tsx+3-5| ... | @@ -25,9 +25,9 @@ export function MaterialFloatingActionButton(props: { | ... | @@ -25,9 +25,9 @@ export function MaterialFloatingActionButton(props: { |
| 25 | const { themeAppearance, themeVariables: colors } = useAppearancePreferences(); | 25 | const { themeAppearance, themeVariables: colors } = useAppearancePreferences(); |
| 26 | const typography = useScaledTextRole("footnote"); | 26 | const typography = useScaledTextRole("footnote"); |
| 27 | const primary = props.tone === "primary"; | 27 | const primary = props.tone === "primary"; |
| 28 | const containerColor = colors[primary ? "--color-primary" : "--color-thread-selected"]; | 28 | const containerColor = colors[primary ? "--color-primary" : "--color-secondary"]; |
| 29 | const contentColor = | 29 | const contentColor = |
| 30 | colors[primary ? "--color-primary-foreground" : "--color-thread-selected-foreground"]; | 30 | colors[primary ? "--color-primary-foreground" : "--color-secondary-foreground"]; |
| 31 | const Component = | 31 | const Component = |
| 32 | props.variant === "extended" | 32 | props.variant === "extended" |
| 33 | ? ExtendedFloatingActionButton | 33 | ? ExtendedFloatingActionButton |
| ... | @@ -76,9 +76,7 @@ export function MaterialFloatingActionButton(props: { | ... | @@ -76,9 +76,7 @@ export function MaterialFloatingActionButton(props: { |
| 76 | <SymbolView | 76 | <SymbolView |
| 77 | name={props.icon} | 77 | name={props.icon} |
| 78 | size={iconSize} | 78 | size={iconSize} |
| 79 | tintColorClassName={ | 79 | tintColorClassName={primary ? "accent-primary-foreground" : "accent-secondary-foreground"} |
| 80 | primary ? "accent-primary-foreground" : "accent-thread-selected-foreground" | ||
| 81 | } | ||
| 82 | /> | 80 | /> |
| 83 | </View> | 81 | </View> |
| 84 | </View> | 82 | </View> |
apps/mobile/src/components/MaterialFloatingActionButton.tsx+3-7| ... | @@ -15,7 +15,7 @@ export function MaterialFloatingActionButton( | ... | @@ -15,7 +15,7 @@ export function MaterialFloatingActionButton( |
| 15 | onPress={props.onPress} | 15 | onPress={props.onPress} |
| 16 | className={cn( | 16 | className={cn( |
| 17 | "min-h-14 min-w-14 flex-row items-center justify-center gap-2 rounded-2xl px-4", | 17 | "min-h-14 min-w-14 flex-row items-center justify-center gap-2 rounded-2xl px-4", |
| 18 | props.tone === "primary" ? "bg-primary" : "bg-thread-selected", | 18 | props.tone === "primary" ? "bg-primary" : "bg-secondary", |
| 19 | props.className, | 19 | props.className, |
| 20 | )} | 20 | )} |
| 21 | style={props.style} | 21 | style={props.style} |
| ... | @@ -24,18 +24,14 @@ export function MaterialFloatingActionButton( | ... | @@ -24,18 +24,14 @@ export function MaterialFloatingActionButton( |
| 24 | name={props.icon} | 24 | name={props.icon} |
| 25 | size={24} | 25 | size={24} |
| 26 | tintColorClassName={ | 26 | tintColorClassName={ |
| 27 | props.tone === "primary" | 27 | props.tone === "primary" ? "accent-primary-foreground" : "accent-secondary-foreground" |
| 28 | ? "accent-primary-foreground" | ||
| 29 | : "accent-thread-selected-foreground" | ||
| 30 | } | 28 | } |
| 31 | /> | 29 | /> |
| 32 | {props.variant === "extended" && props.expanded !== false ? ( | 30 | {props.variant === "extended" && props.expanded !== false ? ( |
| 33 | <AppText | 31 | <AppText |
| 34 | className={cn( | 32 | className={cn( |
| 35 | "text-sm", | 33 | "text-sm", |
| 36 | props.tone === "primary" | 34 | props.tone === "primary" ? "text-primary-foreground" : "text-secondary-foreground", |
| 37 | ? "text-primary-foreground" | ||
| 38 | : "text-thread-selected-foreground", | ||
| 39 | )} | 35 | )} |
| 40 | > | 36 | > |
| 41 | {props.label} | 37 | {props.label} |
apps/mobile/src/components/MaterialIconButton.android.tsx+2-1| ... | @@ -17,6 +17,7 @@ export function MaterialIconButton(props: { | ... | @@ -17,6 +17,7 @@ export function MaterialIconButton(props: { |
| 17 | readonly disabled?: boolean; | 17 | readonly disabled?: boolean; |
| 18 | readonly selected?: boolean; | 18 | readonly selected?: boolean; |
| 19 | readonly variant?: "standard" | "primary" | "tonal" | "danger"; | 19 | readonly variant?: "standard" | "primary" | "tonal" | "danger"; |
| 20 | readonly tintColorClassName?: string; | ||
| 20 | }) { | 21 | }) { |
| 21 | const { themeAppearance, themeVariables: colors } = useAppearancePreferences(); | 22 | const { themeAppearance, themeVariables: colors } = useAppearancePreferences(); |
| 22 | const variant = props.variant ?? "standard"; | 23 | const variant = props.variant ?? "standard"; |
| ... | @@ -40,7 +41,7 @@ export function MaterialIconButton(props: { | ... | @@ -40,7 +41,7 @@ export function MaterialIconButton(props: { |
| 40 | ? "accent-danger-foreground" | 41 | ? "accent-danger-foreground" |
| 41 | : variant === "tonal" | 42 | : variant === "tonal" |
| 42 | ? "accent-secondary-foreground" | 43 | ? "accent-secondary-foreground" |
| 43 | : "accent-foreground"; | 44 | : (props.tintColorClassName ?? "accent-foreground"); |
| 44 | return ( | 45 | return ( |
| 45 | <View | 46 | <View |
| 46 | accessible | 47 | accessible |
apps/mobile/src/components/MaterialIconButton.tsx+31-3| ... | @@ -1,7 +1,15 @@ | ... | @@ -1,7 +1,15 @@ |
| 1 | import { cn } from "../lib/cn"; | ||
| 1 | import { Pressable } from "react-native"; | 2 | import { Pressable } from "react-native"; |
| 2 | 3 | ||
| 3 | import { SymbolView, type AppSymbolName } from "./AppSymbol"; | 4 | import { SymbolView, type AppSymbolName } from "./AppSymbol"; |
| 4 | 5 | ||
| 6 | const VARIANT_CLASS_NAMES = { | ||
| 7 | standard: ["", "accent-foreground"], | ||
| 8 | primary: ["rounded-full bg-primary", "accent-primary-foreground"], | ||
| 9 | danger: ["rounded-full bg-danger", "accent-danger-foreground"], | ||
| 10 | tonal: ["rounded-full bg-secondary", "accent-secondary-foreground"], | ||
| 11 | } as const; | ||
| 12 | |||
| 5 | export function MaterialIconButton(props: { | 13 | export function MaterialIconButton(props: { |
| 6 | readonly accessibilityLabel: string; | 14 | readonly accessibilityLabel: string; |
| 7 | readonly icon: AppSymbolName; | 15 | readonly icon: AppSymbolName; |
| ... | @@ -9,15 +17,35 @@ export function MaterialIconButton(props: { | ... | @@ -9,15 +17,35 @@ export function MaterialIconButton(props: { |
| 9 | readonly disabled?: boolean; | 17 | readonly disabled?: boolean; |
| 10 | readonly selected?: boolean; | 18 | readonly selected?: boolean; |
| 11 | readonly variant?: "standard" | "primary" | "tonal" | "danger"; | 19 | readonly variant?: "standard" | "primary" | "tonal" | "danger"; |
| 20 | readonly tintColorClassName?: string; | ||
| 12 | }) { | 21 | }) { |
| 22 | const variant = props.variant ?? "standard"; | ||
| 23 | const [containerClassName, iconTintClassName] = VARIANT_CLASS_NAMES[variant]; | ||
| 13 | return ( | 24 | return ( |
| 14 | <Pressable | 25 | <Pressable |
| 15 | {...props} | 26 | onPress={props.onPress} |
| 27 | disabled={props.disabled} | ||
| 28 | accessibilityLabel={props.accessibilityLabel} | ||
| 16 | accessibilityRole="button" | 29 | accessibilityRole="button" |
| 17 | accessibilityState={{ disabled: Boolean(props.disabled), selected: props.selected }} | 30 | accessibilityState={{ disabled: Boolean(props.disabled), selected: props.selected }} |
| 18 | className="size-12 items-center justify-center" | 31 | className={cn( |
| 32 | "size-12 items-center justify-center", | ||
| 33 | props.disabled && variant !== "standard" | ||
| 34 | ? "rounded-full bg-subtle-strong" | ||
| 35 | : containerClassName, | ||
| 36 | )} | ||
| 19 | > | 37 | > |
| 20 | <SymbolView name={props.icon} size={24} tintColorClassName="accent-foreground" /> | 38 | <SymbolView |
| 39 | name={props.icon} | ||
| 40 | size={24} | ||
| 41 | tintColorClassName={ | ||
| 42 | props.disabled | ||
| 43 | ? "accent-icon-subtle" | ||
| 44 | : variant === "standard" | ||
| 45 | ? (props.tintColorClassName ?? iconTintClassName) | ||
| 46 | : iconTintClassName | ||
| 47 | } | ||
| 48 | /> | ||
| 21 | </Pressable> | 49 | </Pressable> |
| 22 | ); | 50 | ); |
| 23 | } | 51 | } |
apps/mobile/src/components/MaterialSearchField.tsx+3-3| ... | @@ -30,9 +30,9 @@ export function MaterialSearchField({ | ... | @@ -30,9 +30,9 @@ export function MaterialSearchField({ |
| 30 | returnKeyType="search" | 30 | returnKeyType="search" |
| 31 | placeholder={placeholder} | 31 | placeholder={placeholder} |
| 32 | placeholderTextColorClassName="accent-placeholder" | 32 | placeholderTextColorClassName="accent-placeholder" |
| 33 | selectionColorClassName="accent-primary/32" | 33 | selectionColorClassName="accent-focus/32" |
| 34 | cursorColorClassName="accent-primary" | 34 | cursorColorClassName="accent-focus" |
| 35 | selectionHandleColorClassName="accent-primary" | 35 | selectionHandleColorClassName="accent-focus" |
| 36 | className="min-w-0 flex-1 py-2 font-sans text-base text-foreground" | 36 | className="min-w-0 flex-1 py-2 font-sans text-base text-foreground" |
| 37 | value={value} | 37 | value={value} |
| 38 | onChangeText={onChangeText} | 38 | onChangeText={onChangeText} |
apps/mobile/src/components/RowPressable.tsx+5-3| ... | @@ -9,22 +9,24 @@ import { useHoverGesture } from "../lib/useHoverGesture"; | ... | @@ -9,22 +9,24 @@ import { useHoverGesture } from "../lib/useHoverGesture"; |
| 9 | export function RowPressable({ | 9 | export function RowPressable({ |
| 10 | children, | 10 | children, |
| 11 | className, | 11 | className, |
| 12 | interactionClassName = "bg-primary", | 12 | interactionClassName = "bg-row-hover", |
| 13 | interactionOpacity = 1, | ||
| 13 | ...props | 14 | ...props |
| 14 | }: Omit<ComponentProps<typeof Pressable>, "children"> & { | 15 | }: Omit<ComponentProps<typeof Pressable>, "children"> & { |
| 15 | readonly children: ReactNode; | 16 | readonly children: ReactNode; |
| 16 | readonly interactionClassName?: string; | 17 | readonly interactionClassName?: string; |
| 18 | readonly interactionOpacity?: number; | ||
| 17 | }) { | 19 | }) { |
| 18 | const { hovered, hoverGesture } = useHoverGesture(props.disabled ?? false); | 20 | const { hovered, hoverGesture } = useHoverGesture(props.disabled ?? false); |
| 19 | return ( | 21 | return ( |
| 20 | <GestureDetector gesture={hoverGesture}> | 22 | <GestureDetector gesture={hoverGesture}> |
| 21 | <Pressable {...props} className={cn("relative overflow-hidden", className)}> | 23 | <Pressable {...props} className={cn("relative overflow-hidden", className)}> |
| 22 | {({ pressed }) => ( | 24 | {() => ( |
| 23 | <> | 25 | <> |
| 24 | <View | 26 | <View |
| 25 | pointerEvents="none" | 27 | pointerEvents="none" |
| 26 | className={cn("absolute inset-0", interactionClassName)} | 28 | className={cn("absolute inset-0", interactionClassName)} |
| 27 | style={{ opacity: props.disabled || !hovered ? 0 : pressed ? 0.2 : 0.1 }} | 29 | style={{ opacity: props.disabled || !hovered ? 0 : interactionOpacity }} |
| 28 | /> | 30 | /> |
| 29 | {children} | 31 | {children} |
| 30 | </> | 32 | </> |
apps/mobile/src/components/ScreenHeader.android.tsx+4-4| ... | @@ -53,7 +53,7 @@ export function ScreenHeader(props: ScreenHeaderProps) { | ... | @@ -53,7 +53,7 @@ export function ScreenHeader(props: ScreenHeaderProps) { |
| 53 | <SymbolView | 53 | <SymbolView |
| 54 | name={menu.icon} | 54 | name={menu.icon} |
| 55 | size={16} | 55 | size={16} |
| 56 | tintColorClassName="accent-icon" | 56 | tintColorClassName="accent-header-foreground" |
| 57 | type="monochrome" | 57 | type="monochrome" |
| 58 | /> | 58 | /> |
| 59 | </Pressable> | 59 | </Pressable> |
| ... | @@ -95,7 +95,7 @@ export function ScreenHeader(props: ScreenHeaderProps) { | ... | @@ -95,7 +95,7 @@ export function ScreenHeader(props: ScreenHeaderProps) { |
| 95 | <SymbolView | 95 | <SymbolView |
| 96 | name="chevron.left" | 96 | name="chevron.left" |
| 97 | size={24} | 97 | size={24} |
| 98 | tintColorClassName="accent-foreground" | 98 | tintColorClassName="accent-header-foreground" |
| 99 | type="monochrome" | 99 | type="monochrome" |
| 100 | /> | 100 | /> |
| 101 | </Pressable> | 101 | </Pressable> |
| ... | @@ -104,7 +104,7 @@ export function ScreenHeader(props: ScreenHeaderProps) { | ... | @@ -104,7 +104,7 @@ export function ScreenHeader(props: ScreenHeaderProps) { |
| 104 | <SymbolView | 104 | <SymbolView |
| 105 | name="magnifyingglass" | 105 | name="magnifyingglass" |
| 106 | size={17} | 106 | size={17} |
| 107 | tintColorClassName="accent-icon" | 107 | tintColorClassName="accent-header-foreground" |
| 108 | type="monochrome" | 108 | type="monochrome" |
| 109 | /> | 109 | /> |
| 110 | <TextInput | 110 | <TextInput |
| ... | @@ -114,7 +114,7 @@ export function ScreenHeader(props: ScreenHeaderProps) { | ... | @@ -114,7 +114,7 @@ export function ScreenHeader(props: ScreenHeaderProps) { |
| 114 | value={search.value} | 114 | value={search.value} |
| 115 | placeholder={search.placeholder} | 115 | placeholder={search.placeholder} |
| 116 | placeholderTextColorClassName="accent-placeholder" | 116 | placeholderTextColorClassName="accent-placeholder" |
| 117 | className="flex-1 py-2 text-base font-sans text-foreground" | 117 | className="flex-1 py-2 text-base font-sans text-header-foreground" |
| 118 | /> | 118 | /> |
| 119 | </View> | 119 | </View> |
| 120 | {menuView} | 120 | {menuView} |
apps/mobile/src/components/SegmentedControl.tsx+2-2| ... | @@ -40,7 +40,7 @@ export function SegmentedControl<Value extends number | string>( | ... | @@ -40,7 +40,7 @@ export function SegmentedControl<Value extends number | string>( |
| 40 | layout={LinearTransition.duration(200) | 40 | layout={LinearTransition.duration(200) |
| 41 | .easing(Easing.out(Easing.cubic)) | 41 | .easing(Easing.out(Easing.cubic)) |
| 42 | .reduceMotion(ReduceMotion.System)} | 42 | .reduceMotion(ReduceMotion.System)} |
| 43 | className="absolute inset-y-0 rounded-full bg-subtle-strong" | 43 | className="absolute inset-y-0 rounded-full bg-secondary" |
| 44 | style={{ | 44 | style={{ |
| 45 | width: `${100 / props.options.length}%`, | 45 | width: `${100 / props.options.length}%`, |
| 46 | start: `${ | 46 | start: `${ |
| ... | @@ -70,7 +70,7 @@ export function SegmentedControl<Value extends number | string>( | ... | @@ -70,7 +70,7 @@ export function SegmentedControl<Value extends number | string>( |
| 70 | <Text | 70 | <Text |
| 71 | className={cn( | 71 | className={cn( |
| 72 | compact ? "text-xs" : "text-sm", | 72 | compact ? "text-xs" : "text-sm", |
| 73 | active ? "font-t3-medium text-foreground" : "text-foreground-muted", | 73 | active ? "font-t3-medium text-secondary-foreground" : "text-foreground-muted", |
| 74 | )} | 74 | )} |
| 75 | > | 75 | > |
| 76 | {option.label} | 76 | {option.label} |
apps/mobile/src/features/connection/ConnectionStatusDot.tsx+17-10| ... | @@ -10,10 +10,16 @@ import Animated, { | ... | @@ -10,10 +10,16 @@ import Animated, { |
| 10 | } from "react-native-reanimated"; | 10 | } from "react-native-reanimated"; |
| 11 | 11 | ||
| 12 | import type { RemoteClientConnectionState } from "../../lib/connection"; | 12 | import type { RemoteClientConnectionState } from "../../lib/connection"; |
| 13 | import { useAppearancePreferences } from "../settings/appearance/AppearancePreferencesProvider"; | ||
| 14 | import { themeColorWithAlpha, type MobileThemeVariables } from "../../lib/mobileTheme"; | ||
| 13 | 15 | ||
| 14 | export type ConnectionStatusDotState = RemoteClientConnectionState; | 16 | export type ConnectionStatusDotState = RemoteClientConnectionState; |
| 15 | 17 | ||
| 16 | function statusDotTone(state: ConnectionStatusDotState): { | 18 | function statusDotTone( |
| 19 | state: ConnectionStatusDotState, | ||
| 20 | theme: MobileThemeVariables, | ||
| 21 | dark: boolean, | ||
| 22 | ): { | ||
| 17 | readonly dotColor: string; | 23 | readonly dotColor: string; |
| 18 | readonly haloColor: string; | 24 | readonly haloColor: string; |
| 19 | } { | 25 | } { |
| ... | @@ -23,25 +29,25 @@ function statusDotTone(state: ConnectionStatusDotState): { | ... | @@ -23,25 +29,25 @@ function statusDotTone(state: ConnectionStatusDotState): { |
| 23 | case "available": | 29 | case "available": |
| 24 | case "unsupported": | 30 | case "unsupported": |
| 25 | return { | 31 | return { |
| 26 | dotColor: "#9ca3af", | 32 | dotColor: theme["--color-icon-muted"], |
| 27 | haloColor: "rgba(156,163,175,0.42)", | 33 | haloColor: themeColorWithAlpha(theme["--color-icon-muted"], 0.42), |
| 28 | }; | 34 | }; |
| 29 | case "connected": | 35 | case "connected": |
| 30 | return { | 36 | return { |
| 31 | dotColor: "#34d399", | 37 | dotColor: dark ? "#34d399" : "#059669", |
| 32 | haloColor: "rgba(52,211,153,0.48)", | 38 | haloColor: themeColorWithAlpha(dark ? "#34d399" : "#059669", 0.48), |
| 33 | }; | 39 | }; |
| 34 | case "connecting": | 40 | case "connecting": |
| 35 | case "reconnecting": | 41 | case "reconnecting": |
| 36 | return { | 42 | return { |
| 37 | dotColor: "#f59e0b", | 43 | dotColor: theme["--color-warning-foreground"], |
| 38 | haloColor: "rgba(245,158,11,0.5)", | 44 | haloColor: themeColorWithAlpha(theme["--color-warning-foreground"], 0.5), |
| 39 | }; | 45 | }; |
| 40 | case "offline": | 46 | case "offline": |
| 41 | case "error": | 47 | case "error": |
| 42 | return { | 48 | return { |
| 43 | dotColor: "#ef4444", | 49 | dotColor: theme["--color-danger-foreground"], |
| 44 | haloColor: "rgba(239,68,68,0.48)", | 50 | haloColor: themeColorWithAlpha(theme["--color-danger-foreground"], 0.48), |
| 45 | }; | 51 | }; |
| 46 | } | 52 | } |
| 47 | } | 53 | } |
| ... | @@ -78,7 +84,8 @@ export function ConnectionStatusDot(props: { | ... | @@ -78,7 +84,8 @@ export function ConnectionStatusDot(props: { |
| 78 | readonly size?: number; | 84 | readonly size?: number; |
| 79 | }) { | 85 | }) { |
| 80 | const pulseProgress = usePulseAnimation(props.pulse); | 86 | const pulseProgress = usePulseAnimation(props.pulse); |
| 81 | const tone = statusDotTone(props.state); | 87 | const { themeAppearance, themeVariables } = useAppearancePreferences(); |
| 88 | const tone = statusDotTone(props.state, themeVariables, themeAppearance === "dark"); | ||
| 82 | const dotSize = props.size ?? 10; | 89 | const dotSize = props.size ?? 10; |
| 83 | const haloSize = dotSize + 4; | 90 | const haloSize = dotSize + 4; |
| 84 | const containerSize = haloSize + 4; | 91 | const containerSize = haloSize + 4; |
apps/mobile/src/features/connection/connectionTone.ts+2-2| ... | @@ -18,8 +18,8 @@ export function connectionTone(state: RemoteClientConnectionState): StatusTone { | ... | @@ -18,8 +18,8 @@ export function connectionTone(state: RemoteClientConnectionState): StatusTone { |
| 18 | case "connecting": | 18 | case "connecting": |
| 19 | return { | 19 | return { |
| 20 | label: "Connecting", | 20 | label: "Connecting", |
| 21 | pillClassName: "bg-primary/10", | 21 | pillClassName: "bg-update", |
| 22 | textClassName: "text-foreground-secondary", | 22 | textClassName: "text-update-foreground", |
| 23 | }; | 23 | }; |
| 24 | case "unsupported": | 24 | case "unsupported": |
| 25 | return { | 25 | return { |
apps/mobile/src/features/devices/DevicePreviewRouteScreen.tsx+7-5| ... | @@ -231,10 +231,10 @@ function DevicePreviewScreen({ | ... | @@ -231,10 +231,10 @@ function DevicePreviewScreen({ |
| 231 | </AppText> | 231 | </AppText> |
| 232 | <Pressable | 232 | <Pressable |
| 233 | accessibilityRole="button" | 233 | accessibilityRole="button" |
| 234 | className="rounded-full bg-subtle px-6 py-3" | 234 | className="rounded-full border border-secondary-border bg-secondary px-6 py-3" |
| 235 | onPress={state.refresh} | 235 | onPress={state.refresh} |
| 236 | > | 236 | > |
| 237 | <AppText>Retry</AppText> | 237 | <AppText className="text-secondary-foreground">Retry</AppText> |
| 238 | </Pressable> | 238 | </Pressable> |
| 239 | </> | 239 | </> |
| 240 | ) : focused && foreground ? ( | 240 | ) : focused && foreground ? ( |
| ... | @@ -278,7 +278,9 @@ function OpenDevicePreview({ | ... | @@ -278,7 +278,9 @@ function OpenDevicePreview({ |
| 278 | background: themeVariables["--color-sheet-solid"], | 278 | background: themeVariables["--color-sheet-solid"], |
| 279 | foreground: themeVariables["--color-foreground"], | 279 | foreground: themeVariables["--color-foreground"], |
| 280 | muted: themeVariables["--color-foreground-muted"], | 280 | muted: themeVariables["--color-foreground-muted"], |
| 281 | buttonBackground: themeVariables["--color-subtle"], | 281 | buttonBackground: themeVariables["--color-secondary"], |
| 282 | buttonForeground: themeVariables["--color-secondary-foreground"], | ||
| 283 | buttonBorder: themeVariables["--color-secondary-border"], | ||
| 282 | }} | 284 | }} |
| 283 | onUnauthorized={onUnauthorized} | 285 | onUnauthorized={onUnauthorized} |
| 284 | onInputConnected={onInputConnected} | 286 | onInputConnected={onInputConnected} |
| ... | @@ -292,10 +294,10 @@ function OpenDevicePreview({ | ... | @@ -292,10 +294,10 @@ function OpenDevicePreview({ |
| 292 | </AppText> | 294 | </AppText> |
| 293 | <Pressable | 295 | <Pressable |
| 294 | accessibilityRole="button" | 296 | accessibilityRole="button" |
| 295 | className="rounded-full bg-subtle px-6 py-3" | 297 | className="rounded-full border border-secondary-border bg-secondary px-6 py-3" |
| 296 | onPress={refresh} | 298 | onPress={refresh} |
| 297 | > | 299 | > |
| 298 | <AppText>Retry</AppText> | 300 | <AppText className="text-secondary-foreground">Retry</AppText> |
| 299 | </Pressable> | 301 | </Pressable> |
| 300 | </> | 302 | </> |
| 301 | ) : ( | 303 | ) : ( |
apps/mobile/src/features/devices/device-stream-document.ts+2| ... | @@ -10,6 +10,8 @@ export interface DeviceStreamConfiguration { | ... | @@ -10,6 +10,8 @@ export interface DeviceStreamConfiguration { |
| 10 | readonly foreground: string; | 10 | readonly foreground: string; |
| 11 | readonly muted: string; | 11 | readonly muted: string; |
| 12 | readonly buttonBackground: string; | 12 | readonly buttonBackground: string; |
| 13 | readonly buttonForeground: string; | ||
| 14 | readonly buttonBorder: string; | ||
| 13 | }; | 15 | }; |
| 14 | } | 16 | } |
| 15 | 17 |
apps/mobile/src/features/devices/device-stream.browser.ts+2-2| ... | @@ -90,9 +90,9 @@ export function start(configuration: DeviceStreamConfiguration) { | ... | @@ -90,9 +90,9 @@ export function start(configuration: DeviceStreamConfiguration) { |
| 90 | Object.assign(retry.style, { | 90 | Object.assign(retry.style, { |
| 91 | padding: "12px 24px", | 91 | padding: "12px 24px", |
| 92 | borderRadius: "20px", | 92 | borderRadius: "20px", |
| 93 | border: "0", | 93 | border: `1px solid ${colors.buttonBorder}`, |
| 94 | background: colors.buttonBackground, | 94 | background: colors.buttonBackground, |
| 95 | color: colors.foreground, | 95 | color: colors.buttonForeground, |
| 96 | font: "inherit", | 96 | font: "inherit", |
| 97 | display: "none", | 97 | display: "none", |
| 98 | }); | 98 | }); |
apps/mobile/src/features/files/SourceFileSurface.tsx+3-3| ... | @@ -74,7 +74,7 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: { | ... | @@ -74,7 +74,7 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: { |
| 74 | </NativeText> | 74 | </NativeText> |
| 75 | <NativeText | 75 | <NativeText |
| 76 | selectable | 76 | selectable |
| 77 | selectionColorClassName={Platform.OS === "android" ? "accent-primary/32" : undefined} | 77 | selectionColorClassName={Platform.OS === "android" ? "accent-focus/32" : undefined} |
| 78 | numberOfLines={props.wordBreak ? undefined : 1} | 78 | numberOfLines={props.wordBreak ? undefined : 1} |
| 79 | className="flex-1 font-normal text-foreground" | 79 | className="flex-1 font-normal text-foreground" |
| 80 | style={{ | 80 | style={{ |
| ... | @@ -105,7 +105,7 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: { | ... | @@ -105,7 +105,7 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: { |
| 105 | key={`${start}:${token.content.length}:${token.color ?? ""}`} | 105 | key={`${start}:${token.content.length}:${token.color ?? ""}`} |
| 106 | selectable | 106 | selectable |
| 107 | selectionColorClassName={ | 107 | selectionColorClassName={ |
| 108 | Platform.OS === "android" ? "accent-primary/32" : undefined | 108 | Platform.OS === "android" ? "accent-focus/32" : undefined |
| 109 | } | 109 | } |
| 110 | style={{ | 110 | style={{ |
| 111 | color: token.color ?? undefined, | 111 | color: token.color ?? undefined, |
| ... | @@ -279,7 +279,7 @@ function JavaScriptSourceFileSurface(props: SourceFileSurfaceProps) { | ... | @@ -279,7 +279,7 @@ function JavaScriptSourceFileSurface(props: SourceFileSurfaceProps) { |
| 279 | <MarkdownTextPrimitive | 279 | <MarkdownTextPrimitive |
| 280 | uiTextView | 280 | uiTextView |
| 281 | selectable | 281 | selectable |
| 282 | selectionColorClassName={Platform.OS === "android" ? "accent-primary/32" : undefined} | 282 | selectionColorClassName={Platform.OS === "android" ? "accent-focus/32" : undefined} |
| 283 | style={{ | 283 | style={{ |
| 284 | color: foreground, | 284 | color: foreground, |
| 285 | fontFamily: REVIEW_MONO_FONT_FAMILY, | 285 | fontFamily: REVIEW_MONO_FONT_FAMILY, |
apps/mobile/src/features/keyboard/CommandPalette.tsx+30-8| ... | @@ -20,6 +20,7 @@ import { GlassSurface } from "../../components/GlassSurface"; | ... | @@ -20,6 +20,7 @@ import { GlassSurface } from "../../components/GlassSurface"; |
| 20 | import { RowPressable } from "../../components/RowPressable"; | 20 | import { RowPressable } from "../../components/RowPressable"; |
| 21 | import { AppText as Text } from "../../components/AppText"; | 21 | import { AppText as Text } from "../../components/AppText"; |
| 22 | import { SymbolView, type AppSymbolName } from "../../components/AppSymbol"; | 22 | import { SymbolView, type AppSymbolName } from "../../components/AppSymbol"; |
| 23 | import { cn } from "../../lib/cn"; | ||
| 23 | import { scopedProjectKey, scopedThreadKey } from "../../lib/scopedEntities"; | 24 | import { scopedProjectKey, scopedThreadKey } from "../../lib/scopedEntities"; |
| 24 | import { T3KeyboardCommands } from "../../native/T3KeyboardCommands"; | 25 | import { T3KeyboardCommands } from "../../native/T3KeyboardCommands"; |
| 25 | import { useProjects, useThreadShell, useThreadShells } from "../../state/entities"; | 26 | import { useProjects, useThreadShell, useThreadShells } from "../../state/entities"; |
| ... | @@ -27,6 +28,7 @@ import { useThreadSearch } from "../../state/queries"; | ... | @@ -27,6 +28,7 @@ import { useThreadSearch } from "../../state/queries"; |
| 27 | import { useWorkspaceState } from "../../state/workspace"; | 28 | import { useWorkspaceState } from "../../state/workspace"; |
| 28 | import { useSavedRemoteConnections } from "../../state/use-remote-environment-registry"; | 29 | import { useSavedRemoteConnections } from "../../state/use-remote-environment-registry"; |
| 29 | import { useAdaptiveWorkspaceLayout } from "../layout/AdaptiveWorkspaceLayout"; | 30 | import { useAdaptiveWorkspaceLayout } from "../layout/AdaptiveWorkspaceLayout"; |
| 31 | import { useAppearancePreferences } from "../settings/appearance/AppearancePreferencesProvider"; | ||
| 30 | import { ThreadSearchMatchExcerpt } from "../threads/thread-search-match"; | 32 | import { ThreadSearchMatchExcerpt } from "../threads/thread-search-match"; |
| 31 | import { | 33 | import { |
| 32 | filterCommandPaletteItems, | 34 | filterCommandPaletteItems, |
| ... | @@ -74,35 +76,53 @@ function PaletteRow(props: { | ... | @@ -74,35 +76,53 @@ function PaletteRow(props: { |
| 74 | readonly searchQuery: string; | 76 | readonly searchQuery: string; |
| 75 | readonly onSelect: () => void; | 77 | readonly onSelect: () => void; |
| 76 | }) { | 78 | }) { |
| 79 | const foregroundClassName = props.selected | ||
| 80 | ? "text-thread-selected-foreground" | ||
| 81 | : "text-foreground"; | ||
| 82 | const mutedForegroundClassName = props.selected | ||
| 83 | ? "text-thread-selected-foreground-muted" | ||
| 84 | : "text-foreground-muted"; | ||
| 77 | return ( | 85 | return ( |
| 78 | <RowPressable | 86 | <RowPressable |
| 79 | accessibilityRole="button" | 87 | accessibilityRole="button" |
| 88 | interactionOpacity={props.selected ? 0 : 1} | ||
| 80 | accessibilityState={{ selected: props.selected }} | 89 | accessibilityState={{ selected: props.selected }} |
| 81 | onPress={props.onSelect} | 90 | onPress={props.onSelect} |
| 82 | className={ | 91 | className={ |
| 83 | props.selected | 92 | props.selected |
| 84 | ? "mx-2 flex-row items-center gap-3 rounded-xl bg-primary/10 px-3" | 93 | ? "mx-2 flex-row items-center gap-3 rounded-xl bg-thread-selected px-3" |
| 85 | : "mx-2 flex-row items-center gap-3 rounded-xl px-3" | 94 | : "mx-2 flex-row items-center gap-3 rounded-xl px-3" |
| 86 | } | 95 | } |
| 87 | style={{ height: ROW_HEIGHT }} | 96 | style={{ height: ROW_HEIGHT }} |
| 88 | > | 97 | > |
| 89 | <View className="w-7 items-center"> | 98 | <View className="w-7 items-center"> |
| 90 | <SymbolView name={itemIcon(props.item)} size={20} tintColorClassName="accent-icon" /> | 99 | <SymbolView |
| 100 | name={itemIcon(props.item)} | ||
| 101 | size={20} | ||
| 102 | tintColorClassName={props.selected ? "accent-thread-selected-foreground" : "accent-icon"} | ||
| 103 | /> | ||
| 91 | </View> | 104 | </View> |
| 92 | <View className="flex-1"> | 105 | <View className="flex-1"> |
| 93 | <Text numberOfLines={1} className="text-base"> | 106 | <Text numberOfLines={1} className={cn("text-base", foregroundClassName)}> |
| 94 | {props.item.title} | 107 | {props.item.title} |
| 95 | </Text> | 108 | </Text> |
| 96 | {props.searchMatch ? ( | 109 | {props.searchMatch ? ( |
| 97 | <ThreadSearchMatchExcerpt match={props.searchMatch} query={props.searchQuery} compact /> | 110 | <ThreadSearchMatchExcerpt |
| 111 | match={props.searchMatch} | ||
| 112 | query={props.searchQuery} | ||
| 113 | selected={props.selected} | ||
| 114 | compact | ||
| 115 | /> | ||
| 98 | ) : props.item.detail ? ( | 116 | ) : props.item.detail ? ( |
| 99 | <Text numberOfLines={1} className="text-sm text-foreground-muted"> | 117 | <Text numberOfLines={1} className={cn("text-sm", mutedForegroundClassName)}> |
| 100 | {props.item.detail} | 118 | {props.item.detail} |
| 101 | </Text> | 119 | </Text> |
| 102 | ) : null} | 120 | ) : null} |
| 103 | </View> | 121 | </View> |
| 104 | {props.index < 9 ? ( | 122 | {props.index < 9 ? ( |
| 105 | <NativeText className="w-8 shrink-0 text-right text-sm tabular-nums text-foreground-muted"> | 123 | <NativeText |
| 124 | className={cn("w-8 shrink-0 text-right text-sm tabular-nums", mutedForegroundClassName)} | ||
| 125 | > | ||
| 106 | ⌘{props.index + 1} | 126 | ⌘{props.index + 1} |
| 107 | </NativeText> | 127 | </NativeText> |
| 108 | ) : null} | 128 | ) : null} |
| ... | @@ -117,6 +137,7 @@ export function CommandPalette(props: { | ... | @@ -117,6 +137,7 @@ export function CommandPalette(props: { |
| 117 | readonly onCommand: (command: HardwareKeyboardCommand) => void; | 137 | readonly onCommand: (command: HardwareKeyboardCommand) => void; |
| 118 | }) { | 138 | }) { |
| 119 | const navigation = useNavigation(); | 139 | const navigation = useNavigation(); |
| 140 | const { themeVariables } = useAppearancePreferences(); | ||
| 120 | const { selectThread } = useAdaptiveWorkspaceLayout(); | 141 | const { selectThread } = useAdaptiveWorkspaceLayout(); |
| 121 | const runCommand = props.onCommand; | 142 | const runCommand = props.onCommand; |
| 122 | const projects = useProjects(); | 143 | const projects = useProjects(); |
| ... | @@ -392,14 +413,15 @@ export function CommandPalette(props: { | ... | @@ -392,14 +413,15 @@ export function CommandPalette(props: { |
| 392 | className="flex-1 items-center justify-center p-4" | 413 | className="flex-1 items-center justify-center p-4" |
| 393 | > | 414 | > |
| 394 | <Pressable | 415 | <Pressable |
| 395 | className="absolute inset-0 bg-black/15" | 416 | className="absolute inset-0 bg-backdrop" |
| 396 | accessibilityLabel="Close command palette" | 417 | accessibilityLabel="Close command palette" |
| 397 | onPress={() => close()} | 418 | onPress={() => close()} |
| 398 | /> | 419 | /> |
| 399 | <GlassSurface | 420 | <GlassSurface |
| 400 | accessibilityViewIsModal | 421 | accessibilityViewIsModal |
| 401 | className="bg-sheet/70" | 422 | className="bg-sheet" |
| 402 | tintColorClassName="accent-sheet/20" | 423 | tintColorClassName="accent-sheet/20" |
| 424 | fallbackColor={themeVariables["--color-sheet"]} | ||
| 403 | style={{ | 425 | style={{ |
| 404 | width: Math.min(600, width - 32), | 426 | width: Math.min(600, width - 32), |
| 405 | height: Math.min(520, height - 80), | 427 | height: Math.min(520, height - 80), |
apps/mobile/src/features/projects/AddProjectScreen.tsx+1-1| ... | @@ -129,7 +129,7 @@ function SectionTitle(props: { readonly children: string }) { | ... | @@ -129,7 +129,7 @@ function SectionTitle(props: { readonly children: string }) { |
| 129 | <Text | 129 | <Text |
| 130 | className={ | 130 | className={ |
| 131 | Platform.OS === "android" | 131 | Platform.OS === "android" |
| 132 | ? "px-4 text-sm font-t3-medium text-primary" | 132 | ? "px-4 text-sm font-t3-medium text-primary-text" |
| 133 | : "px-1 text-2xs font-t3-bold tracking-[0.7px] uppercase text-foreground-muted" | 133 | : "px-1 text-2xs font-t3-bold tracking-[0.7px] uppercase text-foreground-muted" |
| 134 | } | 134 | } |
| 135 | > | 135 | > |
apps/mobile/src/features/review/ReviewSheet.tsx+5-3| ... | @@ -262,7 +262,7 @@ const ReviewFileNavigatorRow = memo(function ReviewFileNavigatorRow(props: { | ... | @@ -262,7 +262,7 @@ const ReviewFileNavigatorRow = memo(function ReviewFileNavigatorRow(props: { |
| 262 | Platform.OS === "android" | 262 | Platform.OS === "android" |
| 263 | ? cn( | 263 | ? cn( |
| 264 | "mt-1 min-h-12 justify-center rounded-[20px] px-3 py-2 active:bg-subtle", | 264 | "mt-1 min-h-12 justify-center rounded-[20px] px-3 py-2 active:bg-subtle", |
| 265 | selected && "bg-thread-selected", | 265 | selected && "bg-subtle-strong", |
| 266 | ) | 266 | ) |
| 267 | : selected | 267 | : selected |
| 268 | ? "mt-1 min-h-12 justify-center rounded-xl bg-subtle-strong px-3 py-2" | 268 | ? "mt-1 min-h-12 justify-center rounded-xl bg-subtle-strong px-3 py-2" |
| ... | @@ -281,8 +281,10 @@ const ReviewFileNavigatorRow = memo(function ReviewFileNavigatorRow(props: { | ... | @@ -281,8 +281,10 @@ const ReviewFileNavigatorRow = memo(function ReviewFileNavigatorRow(props: { |
| 281 | {file.path} | 281 | {file.path} |
| 282 | </Text> | 282 | </Text> |
| 283 | <View className="mt-1 flex-row gap-2"> | 283 | <View className="mt-1 flex-row gap-2"> |
| 284 | <Text className="text-2xs font-t3-bold text-emerald-600">+{file.additions}</Text> | 284 | <Text className="text-2xs font-t3-bold text-adaptive-emerald-700-300"> |
| 285 | <Text className="text-2xs font-t3-bold text-rose-600">-{file.deletions}</Text> | 285 | +{file.additions} |
| 286 | </Text> | ||
| 287 | <Text className="text-2xs font-t3-bold text-adaptive-rose-700-300">-{file.deletions}</Text> | ||
| 286 | </View> | 288 | </View> |
| 287 | </Pressable> | 289 | </Pressable> |
| 288 | ); | 290 | ); |
apps/mobile/src/features/review/nativeReviewDiffAdapter.test.ts+19-2| ... | @@ -97,6 +97,19 @@ function appTheme(themeId: MobileThemeId, appearance: MobileThemeAppearance) { | ... | @@ -97,6 +97,19 @@ function appTheme(themeId: MobileThemeId, appearance: MobileThemeAppearance) { |
| 97 | : getMobileThemeVariables(themeId, appearance); | 97 | : getMobileThemeVariables(themeId, appearance); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | function contrastRatio(first: string, second: string): number { | ||
| 101 | const luminance = (hex: string) => { | ||
| 102 | const [red, green, blue] = [1, 3, 5].map((offset) => { | ||
| 103 | const channel = Number.parseInt(hex.slice(offset, offset + 2), 16) / 255; | ||
| 104 | return channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4; | ||
| 105 | }); | ||
| 106 | return 0.2126 * red! + 0.7152 * green! + 0.0722 * blue!; | ||
| 107 | }; | ||
| 108 | const a = luminance(first); | ||
| 109 | const b = luminance(second); | ||
| 110 | return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05); | ||
| 111 | } | ||
| 112 | |||
| 100 | describe("getCachedNativeReviewDiffData", () => { | 113 | describe("getCachedNativeReviewDiffData", () => { |
| 101 | it.each([true, false])( | 114 | it.each([true, false])( |
| 102 | "preserves available diff rows before a notice (has excerpt: %s)", | 115 | "preserves available diff rows before a notice (has excerpt: %s)", |
| ... | @@ -251,6 +264,10 @@ describe("createNativeReviewDiffTheme", () => { | ... | @@ -251,6 +264,10 @@ describe("createNativeReviewDiffTheme", () => { |
| 251 | for (const color of Object.values(theme)) { | 264 | for (const color of Object.values(theme)) { |
| 252 | expect(color, `${themeId}/${appearance}`).toMatch(/^#[\da-f]{6}$/i); | 265 | expect(color, `${themeId}/${appearance}`).toMatch(/^#[\da-f]{6}$/i); |
| 253 | } | 266 | } |
| 267 | expect( | ||
| 268 | contrastRatio(theme.hunkText, theme.hunkBackground), | ||
| 269 | `${themeId}/${appearance} hunk text`, | ||
| 270 | ).toBeGreaterThanOrEqual(4.5); | ||
| 254 | } | 271 | } |
| 255 | } | 272 | } |
| 256 | }); | 273 | }); |
| ... | @@ -261,7 +278,7 @@ describe("createNativeReviewDiffTheme", () => { | ... | @@ -261,7 +278,7 @@ describe("createNativeReviewDiffTheme", () => { |
| 261 | const variables = { | 278 | const variables = { |
| 262 | ...appTheme("material-you", appearance), | 279 | ...appTheme("material-you", appearance), |
| 263 | "--color-screen": "#101214FF", | 280 | "--color-screen": "#101214FF", |
| 264 | "--color-sheet": "#20222480", | 281 | "--color-md-code-bg": "#20222480", |
| 265 | "--color-md-code-text": "#E3E2E6FF", | 282 | "--color-md-code-text": "#E3E2E6FF", |
| 266 | "--color-foreground-muted": "#C7C5D080", | 283 | "--color-foreground-muted": "#C7C5D080", |
| 267 | "--color-border": "#44464F80", | 284 | "--color-border": "#44464F80", |
| ... | @@ -273,7 +290,7 @@ describe("createNativeReviewDiffTheme", () => { | ... | @@ -273,7 +290,7 @@ describe("createNativeReviewDiffTheme", () => { |
| 273 | expect(theme.text).toBe("#e3e2e6"); | 290 | expect(theme.text).toBe("#e3e2e6"); |
| 274 | expect(theme.mutedText).toBe("#707076"); | 291 | expect(theme.mutedText).toBe("#707076"); |
| 275 | expect(theme.border).toBe("#2e3036"); | 292 | expect(theme.border).toBe("#2e3036"); |
| 276 | expect(theme.hunkText).toBe("#a8c7fa"); | 293 | expect(contrastRatio(theme.hunkText, theme.hunkBackground)).toBeGreaterThanOrEqual(4.5); |
| 277 | for (const color of Object.values(theme)) { | 294 | for (const color of Object.values(theme)) { |
| 278 | expect(color).toMatch(/^#[\da-f]{6}$/i); | 295 | expect(color).toMatch(/^#[\da-f]{6}$/i); |
| 279 | } | 296 | } |
apps/mobile/src/features/review/nativeReviewDiffAdapter.ts+4-7| ... | @@ -177,20 +177,19 @@ export function createNativeReviewDiffTheme( | ... | @@ -177,20 +177,19 @@ export function createNativeReviewDiffTheme( |
| 177 | appTheme["--color-screen"], | 177 | appTheme["--color-screen"], |
| 178 | scheme === "dark" ? "#000000" : "#ffffff", | 178 | scheme === "dark" ? "#000000" : "#ffffff", |
| 179 | ); | 179 | ); |
| 180 | const background = opaqueNativeHexColor(appTheme["--color-sheet"], screen); | 180 | const background = opaqueNativeHexColor(appTheme["--color-md-code-bg"], screen); |
| 181 | const nativeColor = (color: string) => opaqueNativeHexColor(color, background); | 181 | const nativeColor = (color: string) => opaqueNativeHexColor(color, background); |
| 182 | 182 | ||
| 183 | if (scheme === "dark") { | 183 | if (scheme === "dark") { |
| 184 | return { | 184 | return { |
| 185 | // Match the app surface (--color-sheet) so code views blend with the rest of | 185 | // Code surfaces share the desktop palette rather than the sheet behind them. |
| 186 | // the app instead of using a distinct code-editor background. | ||
| 187 | background, | 186 | background, |
| 188 | text: nativeColor(appTheme["--color-md-code-text"]), | 187 | text: nativeColor(appTheme["--color-md-code-text"]), |
| 189 | mutedText: nativeColor(appTheme["--color-foreground-muted"]), | 188 | mutedText: nativeColor(appTheme["--color-foreground-muted"]), |
| 190 | headerBackground: background, | 189 | headerBackground: background, |
| 191 | border: nativeColor(appTheme["--color-border"]), | 190 | border: nativeColor(appTheme["--color-border"]), |
| 192 | hunkBackground: nativeColor(appTheme["--color-subtle-strong"]), | 191 | hunkBackground: nativeColor(appTheme["--color-subtle-strong"]), |
| 193 | hunkText: nativeColor(appTheme["--color-primary"]), | 192 | hunkText: nativeColor(appTheme["--color-foreground"]), |
| 194 | addBackground: "#0d2f28", | 193 | addBackground: "#0d2f28", |
| 195 | deleteBackground: "#391415", | 194 | deleteBackground: "#391415", |
| 196 | addBar: "#00cab1", | 195 | addBar: "#00cab1", |
| ... | @@ -201,15 +200,13 @@ export function createNativeReviewDiffTheme( | ... | @@ -201,15 +200,13 @@ export function createNativeReviewDiffTheme( |
| 201 | } | 200 | } |
| 202 | 201 | ||
| 203 | return { | 202 | return { |
| 204 | // Match the app surface (--color-sheet) so code views blend with the rest of the | ||
| 205 | // app instead of using a distinct code-editor background. | ||
| 206 | background, | 203 | background, |
| 207 | text: nativeColor(appTheme["--color-md-code-text"]), | 204 | text: nativeColor(appTheme["--color-md-code-text"]), |
| 208 | mutedText: nativeColor(appTheme["--color-foreground-muted"]), | 205 | mutedText: nativeColor(appTheme["--color-foreground-muted"]), |
| 209 | headerBackground: background, | 206 | headerBackground: background, |
| 210 | border: nativeColor(appTheme["--color-border"]), | 207 | border: nativeColor(appTheme["--color-border"]), |
| 211 | hunkBackground: nativeColor(appTheme["--color-subtle-strong"]), | 208 | hunkBackground: nativeColor(appTheme["--color-subtle-strong"]), |
| 212 | hunkText: nativeColor(appTheme["--color-primary"]), | 209 | hunkText: nativeColor(appTheme["--color-foreground"]), |
| 213 | addBackground: "#e5f8f5", | 210 | addBackground: "#e5f8f5", |
| 214 | deleteBackground: "#ffe6e7", | 211 | deleteBackground: "#ffe6e7", |
| 215 | addBar: "#00cab1", | 212 | addBar: "#00cab1", |
apps/mobile/src/features/settings/SettingsOpenSourceLicensesRouteScreen.tsx+4-4| ... | @@ -44,7 +44,7 @@ function LicenseRow(props: { | ... | @@ -44,7 +44,7 @@ function LicenseRow(props: { |
| 44 | accessibilityLabel={`${props.entry.name}, ${props.entry.license}`} | 44 | accessibilityLabel={`${props.entry.name}, ${props.entry.license}`} |
| 45 | accessibilityRole="button" | 45 | accessibilityRole="button" |
| 46 | onPress={props.onPress} | 46 | onPress={props.onPress} |
| 47 | className="border-b border-border bg-card px-5 py-4 active:bg-card-alt" | 47 | className="border-b border-border bg-grouped-card px-5 py-4 active:bg-card-alt" |
| 48 | > | 48 | > |
| 49 | <View className="flex-row items-start gap-3"> | 49 | <View className="flex-row items-start gap-3"> |
| 50 | <View className="min-w-0 flex-1 gap-1"> | 50 | <View className="min-w-0 flex-1 gap-1"> |
| ... | @@ -235,11 +235,11 @@ export function SettingsOpenSourceLicenseRouteScreen({ route }: LicenseDetailPro | ... | @@ -235,11 +235,11 @@ export function SettingsOpenSourceLicenseRouteScreen({ route }: LicenseDetailPro |
| 235 | onPress={() => void Linking.openURL(sourceUrl)} | 235 | onPress={() => void Linking.openURL(sourceUrl)} |
| 236 | className="min-h-12 flex-row items-center gap-2 self-start py-2 active:opacity-60" | 236 | className="min-h-12 flex-row items-center gap-2 self-start py-2 active:opacity-60" |
| 237 | > | 237 | > |
| 238 | <Text className="font-t3-medium text-primary">Project source</Text> | 238 | <Text className="font-t3-medium text-primary-text">Project source</Text> |
| 239 | <SymbolView | 239 | <SymbolView |
| 240 | name="arrow.up.right" | 240 | name="arrow.up.right" |
| 241 | size={16} | 241 | size={16} |
| 242 | tintColorClassName={"accent-primary"} | 242 | tintColorClassName={"accent-primary-text"} |
| 243 | type="monochrome" | 243 | type="monochrome" |
| 244 | weight="semibold" | 244 | weight="semibold" |
| 245 | /> | 245 | /> |
| ... | @@ -247,7 +247,7 @@ export function SettingsOpenSourceLicenseRouteScreen({ route }: LicenseDetailPro | ... | @@ -247,7 +247,7 @@ export function SettingsOpenSourceLicenseRouteScreen({ route }: LicenseDetailPro |
| 247 | ) : null} | 247 | ) : null} |
| 248 | </View> | 248 | </View> |
| 249 | 249 | ||
| 250 | <View className="overflow-hidden rounded-[24px] border-continuous bg-card p-4"> | 250 | <View className="overflow-hidden rounded-[24px] border-continuous bg-grouped-card p-4"> |
| 251 | <Text selectable className="font-mono text-base leading-normal text-foreground"> | 251 | <Text selectable className="font-mono text-base leading-normal text-foreground"> |
| 252 | {entry.noticeText} | 252 | {entry.noticeText} |
| 253 | </Text> | 253 | </Text> |
apps/mobile/src/features/settings/appearance/sections/ThemeAppearanceSection.tsx+4-2| ... | @@ -151,7 +151,7 @@ function ThemeCard(props: { | ... | @@ -151,7 +151,7 @@ function ThemeCard(props: { |
| 151 | ); | 151 | ); |
| 152 | 152 | ||
| 153 | return ( | 153 | return ( |
| 154 | <View className="min-w-36 flex-1 basis-[47%] gap-3 rounded-[24px] border border-border bg-card px-2 py-4"> | 154 | <View className="min-w-36 flex-1 basis-[47%] gap-3 rounded-[24px] border border-border bg-grouped-card px-2 py-4"> |
| 155 | <Pressable | 155 | <Pressable |
| 156 | accessibilityHint="Sets both light and dark appearances" | 156 | accessibilityHint="Sets both light and dark appearances" |
| 157 | accessibilityLabel={`${props.label} theme`} | 157 | accessibilityLabel={`${props.label} theme`} |
| ... | @@ -259,7 +259,9 @@ function ModeCard(props: { | ... | @@ -259,7 +259,9 @@ function ModeCard(props: { |
| 259 | accessibilityState={{ checked: props.selected, disabled: props.disabled }} | 259 | accessibilityState={{ checked: props.selected, disabled: props.disabled }} |
| 260 | className={cn( | 260 | className={cn( |
| 261 | "min-w-0 flex-1 gap-2 rounded-[24px] p-2 active:scale-[0.97]", | 261 | "min-w-0 flex-1 gap-2 rounded-[24px] p-2 active:scale-[0.97]", |
| 262 | props.selected ? "border-2 border-primary bg-subtle" : "border border-border bg-card", | 262 | props.selected |
| 263 | ? "border-2 border-primary bg-subtle" | ||
| 264 | : "border border-border bg-grouped-card", | ||
| 263 | )} | 265 | )} |
| 264 | disabled={props.disabled} | 266 | disabled={props.disabled} |
| 265 | onPress={props.onPress} | 267 | onPress={props.onPress} |
apps/mobile/src/features/settings/components/AutoSettleDaysField.ios.tsx+3-3| ... | @@ -44,7 +44,7 @@ export function AutoSettleDaysField(props: AutoSettleDaysFieldProps) { | ... | @@ -44,7 +44,7 @@ export function AutoSettleDaysField(props: AutoSettleDaysFieldProps) { |
| 44 | disabled(props.disabled), | 44 | disabled(props.disabled), |
| 45 | accessibilityLabel(`Days before auto-settle: ${props.value}`), | 45 | accessibilityLabel(`Days before auto-settle: ${props.value}`), |
| 46 | frame({ minWidth: 64, minHeight: 44 }), | 46 | frame({ minWidth: 64, minHeight: 44 }), |
| 47 | foregroundStyle(colors["--color-primary"]), | 47 | foregroundStyle(colors["--color-primary-text"]), |
| 48 | font({ size: appearance.baseFontSize }), | 48 | font({ size: appearance.baseFontSize }), |
| 49 | ]} | 49 | ]} |
| 50 | > | 50 | > |
| ... | @@ -78,7 +78,7 @@ export function AutoSettleDaysField(props: AutoSettleDaysFieldProps) { | ... | @@ -78,7 +78,7 @@ export function AutoSettleDaysField(props: AutoSettleDaysFieldProps) { |
| 78 | <Button | 78 | <Button |
| 79 | label="Cancel" | 79 | label="Cancel" |
| 80 | onPress={() => setOpen(false)} | 80 | onPress={() => setOpen(false)} |
| 81 | modifiers={[foregroundStyle(colors["--color-primary"])]} | 81 | modifiers={[foregroundStyle(colors["--color-primary-text"])]} |
| 82 | /> | 82 | /> |
| 83 | <Button | 83 | <Button |
| 84 | label="Done" | 84 | label="Done" |
| ... | @@ -86,7 +86,7 @@ export function AutoSettleDaysField(props: AutoSettleDaysFieldProps) { | ... | @@ -86,7 +86,7 @@ export function AutoSettleDaysField(props: AutoSettleDaysFieldProps) { |
| 86 | setOpen(false); | 86 | setOpen(false); |
| 87 | if (!props.disabled && draft !== props.value) props.onValueChange(draft); | 87 | if (!props.disabled && draft !== props.value) props.onValueChange(draft); |
| 88 | }} | 88 | }} |
| 89 | modifiers={[foregroundStyle(colors["--color-primary"])]} | 89 | modifiers={[foregroundStyle(colors["--color-primary-text"])]} |
| 90 | /> | 90 | /> |
| 91 | </HStack> | 91 | </HStack> |
| 92 | </VStack> | 92 | </VStack> |
apps/mobile/src/features/settings/components/SettingsActionRow.tsx+1| ... | @@ -31,6 +31,7 @@ export function SettingsActionRow(props: { | ... | @@ -31,6 +31,7 @@ export function SettingsActionRow(props: { |
| 31 | if (Platform.OS === "android") { | 31 | if (Platform.OS === "android") { |
| 32 | return ( | 32 | return ( |
| 33 | <MaterialListRow | 33 | <MaterialListRow |
| 34 | className="bg-grouped-card" | ||
| 34 | title={props.label} | 35 | title={props.label} |
| 35 | titleClassName={textClassName} | 36 | titleClassName={textClassName} |
| 36 | leading={icon} | 37 | leading={icon} |
apps/mobile/src/features/settings/components/SettingsProjectOverridesSection.tsx+1-1| ... | @@ -23,7 +23,7 @@ export function SettingsProjectOverridesSection(props: { | ... | @@ -23,7 +23,7 @@ export function SettingsProjectOverridesSection(props: { |
| 23 | onPress={props.onClear} | 23 | onPress={props.onClear} |
| 24 | className="px-2 py-2 active:opacity-70" | 24 | className="px-2 py-2 active:opacity-70" |
| 25 | > | 25 | > |
| 26 | <Text className="text-sm font-t3-medium text-primary">Use defaults</Text> | 26 | <Text className="text-sm font-t3-medium text-primary-text">Use defaults</Text> |
| 27 | </Pressable> | 27 | </Pressable> |
| 28 | ) : null} | 28 | ) : null} |
| 29 | </View> | 29 | </View> |
apps/mobile/src/features/settings/components/SettingsRow.tsx+1| ... | @@ -24,6 +24,7 @@ export function SettingsRow(props: { | ... | @@ -24,6 +24,7 @@ export function SettingsRow(props: { |
| 24 | if (Platform.OS === "android") { | 24 | if (Platform.OS === "android") { |
| 25 | return ( | 25 | return ( |
| 26 | <MaterialListRow | 26 | <MaterialListRow |
| 27 | className="bg-grouped-card" | ||
| 27 | title={props.label} | 28 | title={props.label} |
| 28 | subtitle={props.valuePosition === "trailing" ? undefined : props.value} | 29 | subtitle={props.valuePosition === "trailing" ? undefined : props.value} |
| 29 | accessibilityLabel={[props.label, props.value].filter(Boolean).join(", ")} | 30 | accessibilityLabel={[props.label, props.value].filter(Boolean).join(", ")} |
apps/mobile/src/features/settings/components/SettingsSection.tsx+3-3| ... | @@ -15,7 +15,7 @@ export function SettingsSection(props: { | ... | @@ -15,7 +15,7 @@ export function SettingsSection(props: { |
| 15 | <Text | 15 | <Text |
| 16 | className={ | 16 | className={ |
| 17 | Platform.OS === "android" | 17 | Platform.OS === "android" |
| 18 | ? "px-4 text-sm font-t3-medium text-primary" | 18 | ? "px-4 text-sm font-t3-medium text-primary-text" |
| 19 | : "px-2 text-sm font-t3-medium text-foreground-muted" | 19 | : "px-2 text-sm font-t3-medium text-foreground-muted" |
| 20 | } | 20 | } |
| 21 | > | 21 | > |
| ... | @@ -27,8 +27,8 @@ export function SettingsSection(props: { | ... | @@ -27,8 +27,8 @@ export function SettingsSection(props: { |
| 27 | <View | 27 | <View |
| 28 | className={ | 28 | className={ |
| 29 | Platform.OS === "android" | 29 | Platform.OS === "android" |
| 30 | ? "overflow-hidden rounded-[28px] bg-card" | 30 | ? "overflow-hidden rounded-[28px] bg-grouped-card" |
| 31 | : "overflow-hidden rounded-[24px] border-continuous bg-card" | 31 | : "overflow-hidden rounded-[24px] border-continuous bg-grouped-card" |
| 32 | } | 32 | } |
| 33 | > | 33 | > |
| 34 | {props.children} | 34 | {props.children} |
apps/mobile/src/features/terminal/terminalTheme.test.ts+10-10| ... | @@ -6,20 +6,20 @@ import { themeColorToNativeColor } from "../../lib/mobileTheme"; | ... | @@ -6,20 +6,20 @@ import { themeColorToNativeColor } from "../../lib/mobileTheme"; |
| 6 | import { buildGhosttyThemeConfig, getMobileTerminalTheme } from "./terminalTheme"; | 6 | import { buildGhosttyThemeConfig, getMobileTerminalTheme } from "./terminalTheme"; |
| 7 | 7 | ||
| 8 | describe("getMobileTerminalTheme", () => { | 8 | describe("getMobileTerminalTheme", () => { |
| 9 | it("preserves the default light terminal palette", () => { | 9 | it("uses the shared default light terminal colors", () => { |
| 10 | expect(getMobileTerminalTheme("t3-code", "light")).toMatchObject({ | 10 | expect(getMobileTerminalTheme("t3-code", "light")).toMatchObject({ |
| 11 | background: "#f2f2f7", | 11 | background: "#fcfcfc", |
| 12 | foreground: "#6C6C71", | 12 | foreground: "#27272a", |
| 13 | cursorForeground: "#009fff", | 13 | cursorForeground: "#26384e", |
| 14 | cursorBackground: "#f2f2f7", | 14 | cursorBackground: "#fcfcfc", |
| 15 | }); | 15 | }); |
| 16 | }); | 16 | }); |
| 17 | 17 | ||
| 18 | it("preserves the default dark terminal palette", () => { | 18 | it("uses the shared default dark terminal colors", () => { |
| 19 | expect(getMobileTerminalTheme("t3-code", "dark")).toMatchObject({ | 19 | expect(getMobileTerminalTheme("t3-code", "dark")).toMatchObject({ |
| 20 | background: "#0a0a0a", | 20 | background: "#0a0a0a", |
| 21 | foreground: "#adadb1", | 21 | foreground: "#f5f5f5", |
| 22 | cursorForeground: "#009fff", | 22 | cursorForeground: "#b4cbff", |
| 23 | cursorBackground: "#0a0a0a", | 23 | cursorBackground: "#0a0a0a", |
| 24 | }); | 24 | }); |
| 25 | }); | 25 | }); |
| ... | @@ -48,8 +48,8 @@ describe("buildGhosttyThemeConfig", () => { | ... | @@ -48,8 +48,8 @@ describe("buildGhosttyThemeConfig", () => { |
| 48 | const config = buildGhosttyThemeConfig(getMobileTerminalTheme("t3-code", "dark")); | 48 | const config = buildGhosttyThemeConfig(getMobileTerminalTheme("t3-code", "dark")); |
| 49 | 49 | ||
| 50 | expect(config).toContain("background = #0a0a0a"); | 50 | expect(config).toContain("background = #0a0a0a"); |
| 51 | expect(config).toContain("foreground = #adadb1"); | 51 | expect(config).toContain("foreground = #f5f5f5"); |
| 52 | expect(config).toContain("cursor-color = #009fff"); | 52 | expect(config).toContain("cursor-color = #b4cbff"); |
| 53 | expect(config).toContain("palette = 0=#141415"); | 53 | expect(config).toContain("palette = 0=#141415"); |
| 54 | expect(config).toContain("palette = 15=#c6c6c8"); | 54 | expect(config).toContain("palette = 15=#c6c6c8"); |
| 55 | expect(config.endsWith("\n")).toBe(true); | 55 | expect(config.endsWith("\n")).toBe(true); |
apps/mobile/src/features/terminal/terminalTheme.ts+6-13| ... | @@ -1,10 +1,5 @@ | ... | @@ -1,10 +1,5 @@ |
| 1 | import { | 1 | import { |
| 2 | BUILT_IN_THEMES, | 2 | getMobileThemeColors, |
| 3 | T3_CHAT_THEME, | ||
| 4 | getThemeColorsForAppearance, | ||
| 5 | } from "@t3tools/shared/themePalettes"; | ||
| 6 | |||
| 7 | import { | ||
| 8 | getMobileThemeVariables, | 3 | getMobileThemeVariables, |
| 9 | themeColorToNativeColor, | 4 | themeColorToNativeColor, |
| 10 | type MobileThemeId, | 5 | type MobileThemeId, |
| ... | @@ -44,12 +39,12 @@ type TerminalPalette = readonly [ | ... | @@ -44,12 +39,12 @@ type TerminalPalette = readonly [ |
| 44 | 39 | ||
| 45 | const PIERRE_LIGHT_THEME: TerminalTheme = { | 40 | const PIERRE_LIGHT_THEME: TerminalTheme = { |
| 46 | // Pierre terminal palette with the app's shared screen background. | 41 | // Pierre terminal palette with the app's shared screen background. |
| 47 | background: "#f2f2f7", | 42 | background: "#fcfcfc", |
| 48 | foreground: "#6C6C71", | 43 | foreground: "#6C6C71", |
| 49 | mutedForeground: "#8E8E95", | 44 | mutedForeground: "#8E8E95", |
| 50 | border: "#eeeeef", | 45 | border: "#eeeeef", |
| 51 | cursorForeground: "#009fff", | 46 | cursorForeground: "#009fff", |
| 52 | cursorBackground: "#f2f2f7", | 47 | cursorBackground: "#fcfcfc", |
| 53 | palette: [ | 48 | palette: [ |
| 54 | "#1F1F21", | 49 | "#1F1F21", |
| 55 | "#ff2e3f", | 50 | "#ff2e3f", |
| ... | @@ -107,11 +102,9 @@ export function getMobileTerminalTheme( | ... | @@ -107,11 +102,9 @@ export function getMobileTerminalTheme( |
| 107 | scheme: TerminalAppearanceScheme, | 102 | scheme: TerminalAppearanceScheme, |
| 108 | ): TerminalTheme { | 103 | ): TerminalTheme { |
| 109 | const base = getPierreTerminalTheme(scheme); | 104 | const base = getPierreTerminalTheme(scheme); |
| 110 | if (themeId === "t3-code" || themeId === "material-you") return base; | 105 | const paletteId = themeId === "material-you" ? "t3-code" : themeId; |
| 111 | 106 | const palette = getMobileThemeColors(paletteId, scheme); | |
| 112 | const theme = BUILT_IN_THEMES.find((candidate) => candidate.id === themeId) ?? T3_CHAT_THEME; | 107 | const colors = getMobileThemeVariables(paletteId, scheme); |
| 113 | const palette = getThemeColorsForAppearance(theme, scheme) ?? theme.colors; | ||
| 114 | const colors = getMobileThemeVariables(themeId, scheme); | ||
| 115 | const background = themeColorToNativeColor(palette.terminalBackground); | 108 | const background = themeColorToNativeColor(palette.terminalBackground); |
| 116 | return { | 109 | return { |
| 117 | ...base, | 110 | ...base, |
apps/mobile/src/features/threads/CustomSnoozeSheet.shared.tsx+1-1| ... | @@ -31,7 +31,7 @@ export function CustomSnoozeSheet(props: { | ... | @@ -31,7 +31,7 @@ export function CustomSnoozeSheet(props: { |
| 31 | return ( | 31 | return ( |
| 32 | <Modal visible transparent animationType="fade" onRequestClose={props.onClose}> | 32 | <Modal visible transparent animationType="fade" onRequestClose={props.onClose}> |
| 33 | <KeyboardAvoidingView | 33 | <KeyboardAvoidingView |
| 34 | className="flex-1 items-center justify-center bg-black/40 px-6" | 34 | className="flex-1 items-center justify-center bg-backdrop px-6" |
| 35 | behavior={Platform.OS === "ios" ? "padding" : undefined} | 35 | behavior={Platform.OS === "ios" ? "padding" : undefined} |
| 36 | > | 36 | > |
| 37 | <ScrollView | 37 | <ScrollView |
apps/mobile/src/features/threads/NewTaskContextPickerScreens.tsx+4-4| ... | @@ -66,7 +66,7 @@ function SelectionRow(props: { | ... | @@ -66,7 +66,7 @@ function SelectionRow(props: { |
| 66 | } | 66 | } |
| 67 | trailing={ | 67 | trailing={ |
| 68 | props.selected ? ( | 68 | props.selected ? ( |
| 69 | <SymbolView name="checkmark" size={20} tintColorClassName="accent-primary" /> | 69 | <SymbolView name="checkmark" size={20} tintColorClassName="accent-focus" /> |
| 70 | ) : null | 70 | ) : null |
| 71 | } | 71 | } |
| 72 | accessibilityRole="radio" | 72 | accessibilityRole="radio" |
| ... | @@ -482,9 +482,9 @@ export function NewTaskBranchPickerRouteScreen() { | ... | @@ -482,9 +482,9 @@ export function NewTaskBranchPickerRouteScreen() { |
| 482 | autoCorrect={false} | 482 | autoCorrect={false} |
| 483 | accessibilityLabel="Find a branch" | 483 | accessibilityLabel="Find a branch" |
| 484 | className="h-12 rounded-full border border-input-border bg-input px-4 font-sans text-base text-foreground" | 484 | className="h-12 rounded-full border border-input-border bg-input px-4 font-sans text-base text-foreground" |
| 485 | selectionColorClassName="accent-primary/32" | 485 | selectionColorClassName="accent-focus/32" |
| 486 | cursorColorClassName="accent-primary" | 486 | cursorColorClassName="accent-focus" |
| 487 | selectionHandleColorClassName="accent-primary" | 487 | selectionHandleColorClassName="accent-focus" |
| 488 | onChangeText={flow.setBranchQuery} | 488 | onChangeText={flow.setBranchQuery} |
| 489 | placeholder="Find a branch" | 489 | placeholder="Find a branch" |
| 490 | placeholderTextColorClassName="accent-placeholder" | 490 | placeholderTextColorClassName="accent-placeholder" |
apps/mobile/src/features/threads/ThreadArrangementSheet.tsx+1-1| ... | @@ -379,7 +379,7 @@ export function ThreadArrangementSheet(props: { onClose: () => void }) { | ... | @@ -379,7 +379,7 @@ export function ThreadArrangementSheet(props: { onClose: () => void }) { |
| 379 | onPress={props.onClose} | 379 | onPress={props.onClose} |
| 380 | className="min-h-11 justify-center px-3" | 380 | className="min-h-11 justify-center px-3" |
| 381 | > | 381 | > |
| 382 | <Text className="text-base text-primary">Done</Text> | 382 | <Text className="text-base text-primary-text">Done</Text> |
| 383 | </Pressable> | 383 | </Pressable> |
| 384 | </View> | 384 | </View> |
| 385 | <Text className="px-5 pb-3 text-sm text-foreground-muted"> | 385 | <Text className="px-5 pb-3 text-sm text-foreground-muted"> |
apps/mobile/src/features/threads/ThreadComposer.tsx+2-6| ... | @@ -244,12 +244,8 @@ export function ComposerSurface(props: { | ... | @@ -244,12 +244,8 @@ export function ComposerSurface(props: { |
| 244 | > | 244 | > |
| 245 | <AnimatedGlassSurface | 245 | <AnimatedGlassSurface |
| 246 | chrome="none" | 246 | chrome="none" |
| 247 | fallbackColor={ | 247 | fallbackColor={colors["--color-composer-surface"]} |
| 248 | Platform.OS === "android" ? colors["--color-composer-surface"] : colors["--color-card"] | 248 | fallbackClassName="border border-composer-border" |
| 249 | } | ||
| 250 | fallbackClassName={ | ||
| 251 | Platform.OS === "android" ? "border border-composer-border" : "border border-border" | ||
| 252 | } | ||
| 253 | glassEffectStyle="regular" | 249 | glassEffectStyle="regular" |
| 254 | // The composer is a passive material containing interactive controls. | 250 | // The composer is a passive material containing interactive controls. |
| 255 | // Keep native glass out of the interactive content's layout path. | 251 | // Keep native glass out of the interactive content's layout path. |
apps/mobile/src/features/threads/ThreadCreationFailedCard.tsx+4-4| ... | @@ -13,14 +13,14 @@ export function ThreadCreationFailedCard(props: { | ... | @@ -13,14 +13,14 @@ export function ThreadCreationFailedCard(props: { |
| 13 | readonly onEditTask: () => void; | 13 | readonly onEditTask: () => void; |
| 14 | }) { | 14 | }) { |
| 15 | return ( | 15 | return ( |
| 16 | <View className="gap-2.5 rounded-[20px] border border-adaptive-neutral-200-white-a6 bg-adaptive-neutral-100-900 p-4"> | 16 | <View className="gap-2.5 rounded-[20px] border border-border-subtle bg-card-alt p-4"> |
| 17 | <Text className="font-t3-bold text-2xs uppercase tracking-[1.1px] text-adaptive-rose-700-300"> | 17 | <Text className="font-t3-bold text-2xs uppercase tracking-[1.1px] text-danger-foreground"> |
| 18 | Could not start task | 18 | Could not start task |
| 19 | </Text> | 19 | </Text> |
| 20 | <Text className="font-sans text-sm leading-normal text-adaptive-neutral-600-400"> | 20 | <Text className="font-sans text-sm leading-normal text-foreground-secondary"> |
| 21 | {props.reason} | 21 | {props.reason} |
| 22 | </Text> | 22 | </Text> |
| 23 | <Text className="font-sans text-xs leading-normal text-adaptive-neutral-600-400"> | 23 | <Text className="font-sans text-xs leading-normal text-foreground-secondary"> |
| 24 | Your prompt was kept in the project draft. | 24 | Your prompt was kept in the project draft. |
| 25 | </Text> | 25 | </Text> |
| 26 | <View className="flex-row"> | 26 | <View className="flex-row"> |
apps/mobile/src/features/threads/ThreadFeed.tsx+9-9| ... | @@ -888,7 +888,7 @@ function MarkdownCodeBlock(props: { | ... | @@ -888,7 +888,7 @@ function MarkdownCodeBlock(props: { |
| 888 | > | 888 | > |
| 889 | <NativeText | 889 | <NativeText |
| 890 | selectable | 890 | selectable |
| 891 | selectionColorClassName={Platform.OS === "android" ? "accent-primary/32" : undefined} | 891 | selectionColorClassName={Platform.OS === "android" ? "accent-focus/32" : undefined} |
| 892 | className="font-mono" | 892 | className="font-mono" |
| 893 | style={{ | 893 | style={{ |
| 894 | color: props.textColor, | 894 | color: props.textColor, |
| ... | @@ -1400,7 +1400,7 @@ function renderFeedEntry( | ... | @@ -1400,7 +1400,7 @@ function renderFeedEntry( |
| 1400 | accessibilityState={{ expanded: entry.expanded }} | 1400 | accessibilityState={{ expanded: entry.expanded }} |
| 1401 | onPress={() => props.onToggleTurnFold(entry.turnId)} | 1401 | onPress={() => props.onToggleTurnFold(entry.turnId)} |
| 1402 | hitSlop={4} | 1402 | hitSlop={4} |
| 1403 | className="mb-1 min-h-11 flex-row items-center gap-2 border-b border-adaptive-neutral-200-a80-white-a8 px-2" | 1403 | className="mb-1 min-h-11 flex-row items-center gap-2 border-b border-border-subtle px-2" |
| 1404 | style={{ | 1404 | style={{ |
| 1405 | minHeight: Math.max(TURN_FOLD_HEIGHT - 3.5, props.workRowSizing.estimatedRowHeight), | 1405 | minHeight: Math.max(TURN_FOLD_HEIGHT - 3.5, props.workRowSizing.estimatedRowHeight), |
| 1406 | }} | 1406 | }} |
| ... | @@ -1467,7 +1467,7 @@ function renderFeedEntry( | ... | @@ -1467,7 +1467,7 @@ function renderFeedEntry( |
| 1467 | accessibilityLabel={label} | 1467 | accessibilityLabel={label} |
| 1468 | className="mb-3 flex-row items-center gap-3 px-1 py-1" | 1468 | className="mb-3 flex-row items-center gap-3 px-1 py-1" |
| 1469 | > | 1469 | > |
| 1470 | <View className="h-px flex-1 bg-adaptive-neutral-200-a80-white-a8" /> | 1470 | <View className="h-px flex-1 bg-subtle" /> |
| 1471 | <View className="shrink-0 flex-row items-center gap-1.5"> | 1471 | <View className="shrink-0 flex-row items-center gap-1.5"> |
| 1472 | <SymbolView | 1472 | <SymbolView |
| 1473 | name="arrow.down.right.and.arrow.up.left" | 1473 | name="arrow.down.right.and.arrow.up.left" |
| ... | @@ -1477,7 +1477,7 @@ function renderFeedEntry( | ... | @@ -1477,7 +1477,7 @@ function renderFeedEntry( |
| 1477 | /> | 1477 | /> |
| 1478 | <Text className="font-t3-medium text-xs text-foreground-muted">{label}</Text> | 1478 | <Text className="font-t3-medium text-xs text-foreground-muted">{label}</Text> |
| 1479 | </View> | 1479 | </View> |
| 1480 | <View className="h-px flex-1 bg-adaptive-neutral-200-a80-white-a8" /> | 1480 | <View className="h-px flex-1 bg-subtle" /> |
| 1481 | </View> | 1481 | </View> |
| 1482 | ); | 1482 | ); |
| 1483 | } | 1483 | } |
| ... | @@ -1599,8 +1599,8 @@ function renderFeedEntry( | ... | @@ -1599,8 +1599,8 @@ function renderFeedEntry( |
| 1599 | mimeType={attachment.mimeType} | 1599 | mimeType={attachment.mimeType} |
| 1600 | className={ | 1600 | className={ |
| 1601 | inlineAttachmentIds.size | 1601 | inlineAttachmentIds.size |
| 1602 | ? "h-24 w-24 rounded-[14px] bg-white/15" | 1602 | ? "h-24 w-24 rounded-[14px] bg-user-bubble-foreground/15" |
| 1603 | : "aspect-[1.3] w-full rounded-[14px] bg-white/15" | 1603 | : "aspect-[1.3] w-full rounded-[14px] bg-user-bubble-foreground/15" |
| 1604 | } | 1604 | } |
| 1605 | onPressPreview={props.onPressPreview} | 1605 | onPressPreview={props.onPressPreview} |
| 1606 | /> | 1606 | /> |
| ... | @@ -1636,7 +1636,7 @@ function renderFeedEntry( | ... | @@ -1636,7 +1636,7 @@ function renderFeedEntry( |
| 1636 | ) : null} | 1636 | ) : null} |
| 1637 | </View> | 1637 | </View> |
| 1638 | <View className="mt-1 flex-row items-center justify-end gap-1 pr-0.5"> | 1638 | <View className="mt-1 flex-row items-center justify-end gap-1 pr-0.5"> |
| 1639 | <Text className="font-t3-medium text-xs tabular-nums text-adaptive-neutral-600-400"> | 1639 | <Text className="font-t3-medium text-xs tabular-nums text-foreground-secondary"> |
| 1640 | {entry.pendingMessage && !entry.acknowledged ? "Pending" : timestampLabel} | 1640 | {entry.pendingMessage && !entry.acknowledged ? "Pending" : timestampLabel} |
| 1641 | </Text> | 1641 | </Text> |
| 1642 | {entry.pendingMessage && | 1642 | {entry.pendingMessage && |
| ... | @@ -1715,7 +1715,7 @@ function renderFeedEntry( | ... | @@ -1715,7 +1715,7 @@ function renderFeedEntry( |
| 1715 | attachmentId={attachment.id} | 1715 | attachmentId={attachment.id} |
| 1716 | name={attachment.name} | 1716 | name={attachment.name} |
| 1717 | mimeType={attachment.mimeType} | 1717 | mimeType={attachment.mimeType} |
| 1718 | className="mt-1.5 aspect-[1.3] w-full rounded-[18px] bg-adaptive-neutral-200-800" | 1718 | className="mt-1.5 aspect-[1.3] w-full rounded-[18px] bg-subtle-strong" |
| 1719 | onPressPreview={props.onPressPreview} | 1719 | onPressPreview={props.onPressPreview} |
| 1720 | /> | 1720 | /> |
| 1721 | ) : isFileAttachment(attachment) ? ( | 1721 | ) : isFileAttachment(attachment) ? ( |
| ... | @@ -1739,7 +1739,7 @@ function renderFeedEntry( | ... | @@ -1739,7 +1739,7 @@ function renderFeedEntry( |
| 1739 | buttonSize={28} | 1739 | buttonSize={28} |
| 1740 | iconSize={13} | 1740 | iconSize={13} |
| 1741 | /> | 1741 | /> |
| 1742 | <Text className="font-t3-medium text-xs tabular-nums text-adaptive-neutral-600-400"> | 1742 | <Text className="font-t3-medium text-xs tabular-nums text-foreground-secondary"> |
| 1743 | {timestampLabel} | 1743 | {timestampLabel} |
| 1744 | </Text> | 1744 | </Text> |
| 1745 | </View> | 1745 | </View> |
apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx+17-13| ... | @@ -152,7 +152,7 @@ function ThreadNavigationSidebarPane( | ... | @@ -152,7 +152,7 @@ function ThreadNavigationSidebarPane( |
| 152 | props: ThreadNavigationSidebarProps & { readonly nativeChrome: boolean }, | 152 | props: ThreadNavigationSidebarProps & { readonly nativeChrome: boolean }, |
| 153 | ) { | 153 | ) { |
| 154 | const { themeVariables: materialTheme } = useAppearancePreferences(); | 154 | const { themeVariables: materialTheme } = useAppearancePreferences(); |
| 155 | const screenColor = materialTheme["--color-screen"]; | 155 | const drawerColor = materialTheme["--color-drawer"]; |
| 156 | 156 | ||
| 157 | const insets = useSafeAreaInsets(); | 157 | const insets = useSafeAreaInsets(); |
| 158 | const projects = useProjects(); | 158 | const projects = useProjects(); |
| ... | @@ -935,7 +935,7 @@ function ThreadNavigationSidebarPane( | ... | @@ -935,7 +935,7 @@ function ThreadNavigationSidebarPane( |
| 935 | }), | 935 | }), |
| 936 | )} | 936 | )} |
| 937 | searchQuery={props.searchQuery} | 937 | searchQuery={props.searchQuery} |
| 938 | pane={Platform.OS === "android" ? "screen" : "sidebar"} | 938 | pane="sidebar" |
| 939 | selected={ | 939 | selected={ |
| 940 | scopedThreadKey(thread.environmentId, thread.id) === props.selectedThreadKey | 940 | scopedThreadKey(thread.environmentId, thread.id) === props.selectedThreadKey |
| 941 | } | 941 | } |
| ... | @@ -976,7 +976,7 @@ function ThreadNavigationSidebarPane( | ... | @@ -976,7 +976,7 @@ function ThreadNavigationSidebarPane( |
| 976 | disabled={!shelfPreferencesLoaded} | 976 | disabled={!shelfPreferencesLoaded} |
| 977 | expanded={item.expanded} | 977 | expanded={item.expanded} |
| 978 | onToggle={toggleSnoozedShelf} | 978 | onToggle={toggleSnoozedShelf} |
| 979 | pane={Platform.OS === "android" ? "screen" : "sidebar"} | 979 | pane="sidebar" |
| 980 | /> | 980 | /> |
| 981 | ); | 981 | ); |
| 982 | case "v2-settled-shelf": | 982 | case "v2-settled-shelf": |
| ... | @@ -986,17 +986,21 @@ function ThreadNavigationSidebarPane( | ... | @@ -986,17 +986,21 @@ function ThreadNavigationSidebarPane( |
| 986 | disabled={!shelfPreferencesLoaded} | 986 | disabled={!shelfPreferencesLoaded} |
| 987 | expanded={item.expanded} | 987 | expanded={item.expanded} |
| 988 | onToggle={toggleSettledShelf} | 988 | onToggle={toggleSettledShelf} |
| 989 | pane={Platform.OS === "android" ? "screen" : "sidebar"} | 989 | pane="sidebar" |
| 990 | /> | 990 | /> |
| 991 | ); | 991 | ); |
| 992 | case "v2-show-more": | 992 | case "v2-show-more": |
| 993 | return ( | 993 | return ( |
| 994 | <ThreadListV2ShowMoreRow hiddenCount={item.hiddenCount} onPress={showMoreSettled} /> | 994 | <ThreadListV2ShowMoreRow |
| 995 | pane="sidebar" | ||
| 996 | hiddenCount={item.hiddenCount} | ||
| 997 | onPress={showMoreSettled} | ||
| 998 | /> | ||
| 995 | ); | 999 | ); |
| 996 | case "header": | 1000 | case "header": |
| 997 | return ( | 1001 | return ( |
| 998 | <ThreadListGroupHeader | 1002 | <ThreadListGroupHeader |
| 999 | variant={Platform.OS === "android" ? "compact" : "sidebar"} | 1003 | variant="sidebar" |
| 1000 | collapsed={item.collapsed} | 1004 | collapsed={item.collapsed} |
| 1001 | isFirst={item.isFirst} | 1005 | isFirst={item.isFirst} |
| 1002 | groupKey={item.group.key} | 1006 | groupKey={item.group.key} |
| ... | @@ -1014,7 +1018,7 @@ function ThreadNavigationSidebarPane( | ... | @@ -1014,7 +1018,7 @@ function ThreadNavigationSidebarPane( |
| 1014 | case "pending-task": | 1018 | case "pending-task": |
| 1015 | return ( | 1019 | return ( |
| 1016 | <PendingTaskListRow | 1020 | <PendingTaskListRow |
| 1017 | variant={Platform.OS === "android" ? "compact" : "sidebar"} | 1021 | variant="sidebar" |
| 1018 | pendingTask={item.pendingTask} | 1022 | pendingTask={item.pendingTask} |
| 1019 | environmentLabel={ | 1023 | environmentLabel={ |
| 1020 | savedConnectionsById[item.pendingTask.environmentId]?.environmentLabel ?? null | 1024 | savedConnectionsById[item.pendingTask.environmentId]?.environmentLabel ?? null |
| ... | @@ -1064,7 +1068,7 @@ function ThreadNavigationSidebarPane( | ... | @@ -1064,7 +1068,7 @@ function ThreadNavigationSidebarPane( |
| 1064 | case "show-more": | 1068 | case "show-more": |
| 1065 | return ( | 1069 | return ( |
| 1066 | <ThreadListShowMoreRow | 1070 | <ThreadListShowMoreRow |
| 1067 | variant={Platform.OS === "android" ? "compact" : "sidebar"} | 1071 | variant="sidebar" |
| 1068 | hiddenCount={item.hiddenCount} | 1072 | hiddenCount={item.hiddenCount} |
| 1069 | canShowLess={item.canShowLess} | 1073 | canShowLess={item.canShowLess} |
| 1070 | groupKey={item.groupKey} | 1074 | groupKey={item.groupKey} |
| ... | @@ -1168,8 +1172,8 @@ function ThreadNavigationSidebarPane( | ... | @@ -1168,8 +1172,8 @@ function ThreadNavigationSidebarPane( |
| 1168 | <Text | 1172 | <Text |
| 1169 | className={ | 1173 | className={ |
| 1170 | Platform.OS === "android" | 1174 | Platform.OS === "android" |
| 1171 | ? "px-4 py-4 text-center text-sm text-foreground-muted" | 1175 | ? "px-4 py-4 text-center text-sm text-drawer-foreground-muted" |
| 1172 | : "px-2 py-4 text-sm text-foreground-muted" | 1176 | : "px-2 py-4 text-sm text-drawer-foreground-muted" |
| 1173 | } | 1177 | } |
| 1174 | > | 1178 | > |
| 1175 | {catalogState.isLoadingConnections | 1179 | {catalogState.isLoadingConnections |
| ... | @@ -1277,7 +1281,7 @@ function ThreadNavigationSidebarPane( | ... | @@ -1277,7 +1281,7 @@ function ThreadNavigationSidebarPane( |
| 1277 | marginTop: stickyHeaderHeight, | 1281 | marginTop: stickyHeaderHeight, |
| 1278 | marginHorizontal: 4, | 1282 | marginHorizontal: 4, |
| 1279 | paddingBottom: insets.bottom, | 1283 | paddingBottom: insets.bottom, |
| 1280 | backgroundColor: screenColor, | 1284 | backgroundColor: drawerColor, |
| 1281 | borderTopLeftRadius: 28, | 1285 | borderTopLeftRadius: 28, |
| 1282 | borderTopRightRadius: 28, | 1286 | borderTopRightRadius: 28, |
| 1283 | overflow: "hidden", | 1287 | overflow: "hidden", |
| ... | @@ -1374,7 +1378,7 @@ function ThreadNavigationSidebarPane( | ... | @@ -1374,7 +1378,7 @@ function ThreadNavigationSidebarPane( |
| 1374 | <SymbolView | 1378 | <SymbolView |
| 1375 | name="magnifyingglass" | 1379 | name="magnifyingglass" |
| 1376 | size={15} | 1380 | size={15} |
| 1377 | tintColorClassName="accent-foreground-muted" | 1381 | tintColorClassName="accent-drawer-foreground-muted" |
| 1378 | type="monochrome" | 1382 | type="monochrome" |
| 1379 | /> | 1383 | /> |
| 1380 | <TextInput | 1384 | <TextInput |
| ... | @@ -1390,7 +1394,7 @@ function ThreadNavigationSidebarPane( | ... | @@ -1390,7 +1394,7 @@ function ThreadNavigationSidebarPane( |
| 1390 | cursorColorClassName={undefined} | 1394 | cursorColorClassName={undefined} |
| 1391 | selectionHandleColorClassName={undefined} | 1395 | selectionHandleColorClassName={undefined} |
| 1392 | returnKeyType="search" | 1396 | returnKeyType="search" |
| 1393 | className="h-[34px] flex-1 px-0 py-0 font-sans text-base text-foreground" | 1397 | className="h-[34px] flex-1 px-0 py-0 font-sans text-base text-drawer-foreground" |
| 1394 | value={props.searchQuery} | 1398 | value={props.searchQuery} |
| 1395 | /> | 1399 | /> |
| 1396 | </View> | 1400 | </View> |
apps/mobile/src/features/threads/ThreadSettingsRows.android.tsx+1-1| ... | @@ -12,7 +12,7 @@ export function ModelRow(props: ModelRowProps) { | ... | @@ -12,7 +12,7 @@ export function ModelRow(props: ModelRowProps) { |
| 12 | {...props} | 12 | {...props} |
| 13 | labelNumberOfLines={2} | 13 | labelNumberOfLines={2} |
| 14 | minimumHeight={56} | 14 | minimumHeight={56} |
| 15 | selectedClassName={props.selected ? "bg-thread-selected" : undefined} | 15 | selectedClassName={props.selected ? "bg-secondary" : undefined} |
| 16 | leadingSelection={<MaterialRadioIndicator selected={props.selected} />} | 16 | leadingSelection={<MaterialRadioIndicator selected={props.selected} />} |
| 17 | /> | 17 | /> |
| 18 | ); | 18 | ); |
apps/mobile/src/features/threads/ThreadSettingsSheet.tsx+3-3| ... | @@ -896,9 +896,9 @@ function ThreadSettingsMainContent(props: { | ... | @@ -896,9 +896,9 @@ function ThreadSettingsMainContent(props: { |
| 896 | onChangeText={session.setSearchQuery} | 896 | onChangeText={session.setSearchQuery} |
| 897 | placeholder="Find a model" | 897 | placeholder="Find a model" |
| 898 | placeholderTextColorClassName="accent-placeholder" | 898 | placeholderTextColorClassName="accent-placeholder" |
| 899 | selectionColorClassName="accent-primary/32" | 899 | selectionColorClassName="accent-focus/32" |
| 900 | cursorColorClassName="accent-primary" | 900 | cursorColorClassName="accent-focus" |
| 901 | selectionHandleColorClassName="accent-primary" | 901 | selectionHandleColorClassName="accent-focus" |
| 902 | value={session.searchQuery} | 902 | value={session.searchQuery} |
| 903 | /> | 903 | /> |
| 904 | {session.searchQuery.length > 0 ? ( | 904 | {session.searchQuery.length > 0 ? ( |
apps/mobile/src/features/threads/floating-working-control.tsx+3-3| ... | @@ -213,7 +213,7 @@ export function FloatingWorkingControl(props: { | ... | @@ -213,7 +213,7 @@ export function FloatingWorkingControl(props: { |
| 213 | <View pointerEvents="box-none" className="flex-row items-center gap-4"> | 213 | <View pointerEvents="box-none" className="flex-row items-center gap-4"> |
| 214 | <Animated.View | 214 | <Animated.View |
| 215 | pointerEvents={capsuleInteractive ? "box-none" : "none"} | 215 | pointerEvents={capsuleInteractive ? "box-none" : "none"} |
| 216 | className="h-11 items-center justify-center overflow-hidden rounded-full border border-border bg-card shadow-md shadow-black/10" | 216 | className="h-11 items-center justify-center overflow-hidden rounded-full border border-border bg-glass-fallback shadow-md shadow-black/10" |
| 217 | style={capsuleStyle} | 217 | style={capsuleStyle} |
| 218 | > | 218 | > |
| 219 | {capsuleContent} | 219 | {capsuleContent} |
| ... | @@ -228,7 +228,7 @@ export function FloatingWorkingControl(props: { | ... | @@ -228,7 +228,7 @@ export function FloatingWorkingControl(props: { |
| 228 | <ControlPill | 228 | <ControlPill |
| 229 | accessibilityLabel="Scroll to end" | 229 | accessibilityLabel="Scroll to end" |
| 230 | activateOnPressIn | 230 | activateOnPressIn |
| 231 | className="h-11 w-11 border border-border bg-card shadow-md shadow-black/10" | 231 | className="h-11 w-11 border border-border bg-glass-fallback shadow-md shadow-black/10" |
| 232 | disabled={!props.showScrollToEnd} | 232 | disabled={!props.showScrollToEnd} |
| 233 | icon={{ ios: "chevron.down", android: "keyboard_arrow_down" }} | 233 | icon={{ ios: "chevron.down", android: "keyboard_arrow_down" }} |
| 234 | onPress={props.onScrollToEnd} | 234 | onPress={props.onScrollToEnd} |
| ... | @@ -248,7 +248,7 @@ export function FloatingWorkingControl(props: { | ... | @@ -248,7 +248,7 @@ export function FloatingWorkingControl(props: { |
| 248 | <ControlPill | 248 | <ControlPill |
| 249 | accessibilityLabel="Scroll to end" | 249 | accessibilityLabel="Scroll to end" |
| 250 | activateOnPressIn | 250 | activateOnPressIn |
| 251 | className="h-11 w-11 border border-border bg-card shadow-md shadow-black/10" | 251 | className="h-11 w-11 border border-border bg-glass-fallback shadow-md shadow-black/10" |
| 252 | icon={{ ios: "chevron.down", android: "keyboard_arrow_down" }} | 252 | icon={{ ios: "chevron.down", android: "keyboard_arrow_down" }} |
| 253 | onPress={props.onScrollToEnd} | 253 | onPress={props.onScrollToEnd} |
| 254 | /> | 254 | /> |
apps/mobile/src/features/threads/git/GitCommitSheet.tsx+8-6| ... | @@ -164,7 +164,7 @@ export function GitCommitSheet(_props: GitCommitSheetProps) { | ... | @@ -164,7 +164,7 @@ export function GitCommitSheet(_props: GitCommitSheetProps) { |
| 164 | <Text | 164 | <Text |
| 165 | className={ | 165 | className={ |
| 166 | Platform.OS === "android" | 166 | Platform.OS === "android" |
| 167 | ? "text-primary text-sm font-t3-medium" | 167 | ? "text-primary-text text-sm font-t3-medium" |
| 168 | : "text-foreground text-2xs font-t3-bold uppercase" | 168 | : "text-foreground text-2xs font-t3-bold uppercase" |
| 169 | } | 169 | } |
| 170 | > | 170 | > |
| ... | @@ -183,7 +183,7 @@ export function GitCommitSheet(_props: GitCommitSheetProps) { | ... | @@ -183,7 +183,7 @@ export function GitCommitSheet(_props: GitCommitSheetProps) { |
| 183 | <Text | 183 | <Text |
| 184 | className={ | 184 | className={ |
| 185 | Platform.OS === "android" | 185 | Platform.OS === "android" |
| 186 | ? "text-primary text-sm font-t3-medium" | 186 | ? "text-primary-text text-sm font-t3-medium" |
| 187 | : "text-foreground text-2xs font-t3-bold uppercase" | 187 | : "text-foreground text-2xs font-t3-bold uppercase" |
| 188 | } | 188 | } |
| 189 | > | 189 | > |
| ... | @@ -204,10 +204,12 @@ export function GitCommitSheet(_props: GitCommitSheetProps) { | ... | @@ -204,10 +204,12 @@ export function GitCommitSheet(_props: GitCommitSheetProps) { |
| 204 | <Text className="text-foreground flex-1 text-sm font-medium" numberOfLines={1}> | 204 | <Text className="text-foreground flex-1 text-sm font-medium" numberOfLines={1}> |
| 205 | {file.path} | 205 | {file.path} |
| 206 | </Text> | 206 | </Text> |
| 207 | <Text className="text-xs font-t3-bold text-emerald-500"> | 207 | <Text className="text-xs font-t3-bold text-adaptive-emerald-700-300"> |
| 208 | +{file.insertions} | 208 | +{file.insertions} |
| 209 | </Text> | 209 | </Text> |
| 210 | <Text className="text-xs font-t3-bold text-rose-500">-{file.deletions}</Text> | 210 | <Text className="text-xs font-t3-bold text-adaptive-rose-700-300"> |
| 211 | -{file.deletions} | ||
| 212 | </Text> | ||
| 211 | </View> | 213 | </View> |
| 212 | ))} | 214 | ))} |
| 213 | {selectedFiles.length > selectedFilePreview.length ? ( | 215 | {selectedFiles.length > selectedFilePreview.length ? ( |
| ... | @@ -286,10 +288,10 @@ export function GitCommitSheet(_props: GitCommitSheetProps) { | ... | @@ -286,10 +288,10 @@ export function GitCommitSheet(_props: GitCommitSheetProps) { |
| 286 | ) : null} | 288 | ) : null} |
| 287 | </View> | 289 | </View> |
| 288 | <View className="items-end gap-1"> | 290 | <View className="items-end gap-1"> |
| 289 | <Text className="text-xs font-t3-bold text-emerald-500"> | 291 | <Text className="text-xs font-t3-bold text-adaptive-emerald-700-300"> |
| 290 | +{file.insertions} | 292 | +{file.insertions} |
| 291 | </Text> | 293 | </Text> |
| 292 | <Text className="text-xs font-t3-bold text-rose-500"> | 294 | <Text className="text-xs font-t3-bold text-adaptive-rose-700-300"> |
| 293 | -{file.deletions} | 295 | -{file.deletions} |
| 294 | </Text> | 296 | </Text> |
| 295 | </View> | 297 | </View> |
apps/mobile/src/features/threads/sidebar-navigation-shell.tsx+1-1| ... | @@ -52,7 +52,7 @@ const SidebarStack = createNativeStackNavigator(); | ... | @@ -52,7 +52,7 @@ const SidebarStack = createNativeStackNavigator(); |
| 52 | * navigation hooks used for header configuration inside the pane. | 52 | * navigation hooks used for header configuration inside the pane. |
| 53 | */ | 53 | */ |
| 54 | export function SidebarNavigationShell(props: { readonly children: ReactNode }) { | 54 | export function SidebarNavigationShell(props: { readonly children: ReactNode }) { |
| 55 | const navigationTheme = useMobileNavigationTheme(); | 55 | const navigationTheme = useMobileNavigationTheme("sidebar"); |
| 56 | 56 | ||
| 57 | return ( | 57 | return ( |
| 58 | <NavigationIndependentTree> | 58 | <NavigationIndependentTree> |
apps/mobile/src/features/threads/thread-list-items.tsx+76-95| ... | @@ -157,7 +157,7 @@ export const ThreadListGroupHeader = memo(function ThreadListGroupHeader(props: | ... | @@ -157,7 +157,7 @@ export const ThreadListGroupHeader = memo(function ThreadListGroupHeader(props: |
| 157 | className={ | 157 | className={ |
| 158 | compact | 158 | compact |
| 159 | ? "flex-shrink text-base font-t3-bold tracking-[0.2px] text-foreground-muted" | 159 | ? "flex-shrink text-base font-t3-bold tracking-[0.2px] text-foreground-muted" |
| 160 | : "flex-shrink text-sm font-t3-bold tracking-[0.2px] text-foreground-muted" | 160 | : "flex-shrink text-sm font-t3-bold tracking-[0.2px] text-drawer-foreground-muted" |
| 161 | } | 161 | } |
| 162 | numberOfLines={1} | 162 | numberOfLines={1} |
| 163 | > | 163 | > |
| ... | @@ -167,7 +167,7 @@ export const ThreadListGroupHeader = memo(function ThreadListGroupHeader(props: | ... | @@ -167,7 +167,7 @@ export const ThreadListGroupHeader = memo(function ThreadListGroupHeader(props: |
| 167 | className={ | 167 | className={ |
| 168 | compact | 168 | compact |
| 169 | ? "flex-1 text-sm font-t3-medium text-foreground-tertiary" | 169 | ? "flex-1 text-sm font-t3-medium text-foreground-tertiary" |
| 170 | : "flex-1 text-xs font-t3-medium text-foreground-tertiary" | 170 | : "flex-1 text-xs font-t3-medium text-drawer-foreground-muted" |
| 171 | } | 171 | } |
| 172 | > | 172 | > |
| 173 | {props.threadCount} | 173 | {props.threadCount} |
| ... | @@ -241,7 +241,7 @@ export const ThreadListShowMoreRow = memo(function ThreadListShowMoreRow(props: | ... | @@ -241,7 +241,7 @@ export const ThreadListShowMoreRow = memo(function ThreadListShowMoreRow(props: |
| 241 | className={ | 241 | className={ |
| 242 | compact | 242 | compact |
| 243 | ? "text-sm font-t3-medium text-foreground-muted" | 243 | ? "text-sm font-t3-medium text-foreground-muted" |
| 244 | : "text-xs font-t3-medium text-foreground-muted" | 244 | : "text-xs font-t3-medium text-drawer-foreground-muted" |
| 245 | } | 245 | } |
| 246 | > | 246 | > |
| 247 | {label} | 247 | {label} |
| ... | @@ -320,7 +320,14 @@ export const PendingTaskListRow = memo(function PendingTaskListRow(props: { | ... | @@ -320,7 +320,14 @@ export const PendingTaskListRow = memo(function PendingTaskListRow(props: { |
| 320 | </View> | 320 | </View> |
| 321 | ) : ( | 321 | ) : ( |
| 322 | <View className="rounded-full bg-subtle px-1.5 py-0.5"> | 322 | <View className="rounded-full bg-subtle px-1.5 py-0.5"> |
| 323 | <Text className="text-3xs font-t3-bold text-foreground-muted">Pending</Text> | 323 | <Text |
| 324 | className={cn( | ||
| 325 | "text-3xs font-t3-bold text-foreground-muted", | ||
| 326 | !compact && "text-drawer-foreground-muted", | ||
| 327 | )} | ||
| 328 | > | ||
| 329 | Pending | ||
| 330 | </Text> | ||
| 324 | </View> | 331 | </View> |
| 325 | ); | 332 | ); |
| 326 | 333 | ||
| ... | @@ -330,21 +337,21 @@ export const PendingTaskListRow = memo(function PendingTaskListRow(props: { | ... | @@ -330,21 +337,21 @@ export const PendingTaskListRow = memo(function PendingTaskListRow(props: { |
| 330 | <SymbolView | 337 | <SymbolView |
| 331 | name={isDraft ? "square.and.pencil" : "tray.and.arrow.up"} | 338 | name={isDraft ? "square.and.pencil" : "tray.and.arrow.up"} |
| 332 | size={10} | 339 | size={10} |
| 333 | tintColorClassName={compact ? "accent-icon-subtle" : "accent-foreground-muted"} | 340 | tintColorClassName={compact ? "accent-icon-subtle" : "accent-drawer-foreground-muted"} |
| 334 | type="monochrome" | 341 | type="monochrome" |
| 335 | /> | 342 | /> |
| 336 | {props.environmentLabel && props.environmentMachine ? ( | 343 | {props.environmentLabel && props.environmentMachine ? ( |
| 337 | <EnvironmentMachineSymbol | 344 | <EnvironmentMachineSymbol |
| 338 | kind={props.environmentMachine} | 345 | kind={props.environmentMachine} |
| 339 | size={compact ? 12 : 10} | 346 | size={compact ? 12 : 10} |
| 340 | tintColorClassName={compact ? "accent-icon-subtle" : "accent-foreground-muted"} | 347 | tintColorClassName={compact ? "accent-icon-subtle" : "accent-drawer-foreground-muted"} |
| 341 | /> | 348 | /> |
| 342 | ) : null} | 349 | ) : null} |
| 343 | <Text | 350 | <Text |
| 344 | className={ | 351 | className={ |
| 345 | compact | 352 | compact |
| 346 | ? "shrink text-sm text-foreground-muted" | 353 | ? "shrink text-sm text-foreground-muted" |
| 347 | : "shrink text-xs text-foreground-muted" | 354 | : "shrink text-xs text-drawer-foreground-muted" |
| 348 | } | 355 | } |
| 349 | numberOfLines={1} | 356 | numberOfLines={1} |
| 350 | > | 357 | > |
| ... | @@ -369,13 +376,26 @@ export const PendingTaskListRow = memo(function PendingTaskListRow(props: { | ... | @@ -369,13 +376,26 @@ export const PendingTaskListRow = memo(function PendingTaskListRow(props: { |
| 369 | <View className="pr-[18px] pt-[10px]" style={{ paddingLeft: THREAD_LIST_COMPACT_INSET }}> | 376 | <View className="pr-[18px] pt-[10px]" style={{ paddingLeft: THREAD_LIST_COMPACT_INSET }}> |
| 370 | <View className={cn("gap-[3px] pb-[10px]", !props.isLast && "border-b border-separator")}> | 377 | <View className={cn("gap-[3px] pb-[10px]", !props.isLast && "border-b border-separator")}> |
| 371 | <View className="flex-row items-center justify-between gap-2"> | 378 | <View className="flex-row items-center justify-between gap-2"> |
| 372 | <Text className="flex-1 text-lg font-t3-bold text-foreground" numberOfLines={1}> | 379 | <Text |
| 380 | className={cn( | ||
| 381 | "flex-1 text-lg font-t3-bold text-foreground", | ||
| 382 | !compact && "text-drawer-foreground", | ||
| 383 | )} | ||
| 384 | numberOfLines={1} | ||
| 385 | > | ||
| 373 | {pendingTask.title} | 386 | {pendingTask.title} |
| 374 | </Text> | 387 | </Text> |
| 375 | <View className="flex-row items-center gap-2"> | 388 | <View className="flex-row items-center gap-2"> |
| 376 | {statusPill} | 389 | {statusPill} |
| 377 | {timestamp !== null ? ( | 390 | {timestamp !== null ? ( |
| 378 | <Text className="text-base tabular-nums text-foreground-tertiary">{timestamp}</Text> | 391 | <Text |
| 392 | className={cn( | ||
| 393 | "text-base tabular-nums text-foreground-tertiary", | ||
| 394 | !compact && "text-drawer-foreground-muted", | ||
| 395 | )} | ||
| 396 | > | ||
| 397 | {timestamp} | ||
| 398 | </Text> | ||
| 379 | ) : null} | 399 | ) : null} |
| 380 | <SymbolView | 400 | <SymbolView |
| 381 | name="chevron.right" | 401 | name="chevron.right" |
| ... | @@ -395,6 +415,7 @@ export const PendingTaskListRow = memo(function PendingTaskListRow(props: { | ... | @@ -395,6 +415,7 @@ export const PendingTaskListRow = memo(function PendingTaskListRow(props: { |
| 395 | accessibilityHint={accessibilityHint} | 415 | accessibilityHint={accessibilityHint} |
| 396 | accessibilityLabel={pendingTask.title} | 416 | accessibilityLabel={pendingTask.title} |
| 397 | accessibilityRole="button" | 417 | accessibilityRole="button" |
| 418 | interactionClassName="bg-thread-hover" | ||
| 398 | onPress={() => onSelectPendingTask(pendingTask)} | 419 | onPress={() => onSelectPendingTask(pendingTask)} |
| 399 | style={{ | 420 | style={{ |
| 400 | borderRadius: SIDEBAR_ROW_RADIUS, | 421 | borderRadius: SIDEBAR_ROW_RADIUS, |
| ... | @@ -406,13 +427,22 @@ export const PendingTaskListRow = memo(function PendingTaskListRow(props: { | ... | @@ -406,13 +427,22 @@ export const PendingTaskListRow = memo(function PendingTaskListRow(props: { |
| 406 | > | 427 | > |
| 407 | <View className="gap-[3px]"> | 428 | <View className="gap-[3px]"> |
| 408 | <View className="flex-row items-center justify-between gap-2"> | 429 | <View className="flex-row items-center justify-between gap-2"> |
| 409 | <Text className="flex-1 text-base font-t3-medium text-foreground" numberOfLines={1}> | 430 | <Text |
| 431 | className="flex-1 text-base font-t3-medium text-drawer-foreground" | ||
| 432 | numberOfLines={1} | ||
| 433 | > | ||
| 410 | {pendingTask.title} | 434 | {pendingTask.title} |
| 411 | </Text> | 435 | </Text> |
| 412 | <View className="flex-row items-center gap-2"> | 436 | <View className="flex-row items-center gap-2"> |
| 413 | {statusPill} | 437 | {statusPill} |
| 414 | {timestamp !== null ? ( | 438 | {timestamp !== null ? ( |
| 415 | <Text className="text-xs tabular-nums text-foreground-muted" numberOfLines={1}> | 439 | <Text |
| 440 | className={cn( | ||
| 441 | "text-xs tabular-nums text-foreground-muted", | ||
| 442 | !compact && "text-drawer-foreground-muted", | ||
| 443 | )} | ||
| 444 | numberOfLines={1} | ||
| 445 | > | ||
| 416 | {timestamp} | 446 | {timestamp} |
| 417 | </Text> | 447 | </Text> |
| 418 | ) : null} | 448 | ) : null} |
| ... | @@ -477,10 +507,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -477,10 +507,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 477 | const theme = useUniwindTheme(); | 507 | const theme = useUniwindTheme(); |
| 478 | const screenColor = theme["--color-screen"]; | 508 | const screenColor = theme["--color-screen"]; |
| 479 | const drawerColor = theme["--color-drawer"]; | 509 | const drawerColor = theme["--color-drawer"]; |
| 480 | const selectedBackgroundColor = theme["--color-user-bubble"]; | 510 | const selectedBackgroundColor = theme["--color-thread-selected"]; |
| 481 | const materialSelectedBackgroundColor = theme["--color-thread-selected"]; | ||
| 482 | const materialSelectedForegroundColor = theme["--color-thread-selected-foreground"]; | ||
| 483 | const selectedForegroundColor = theme["--color-user-bubble-foreground"]; | ||
| 484 | 511 | ||
| 485 | const { | 512 | const { |
| 486 | thread, | 513 | thread, |
| ... | @@ -508,24 +535,6 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -508,24 +535,6 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 508 | ); | 535 | ); |
| 509 | 536 | ||
| 510 | const backgroundColor = compact ? screenColor : drawerColor; | 537 | const backgroundColor = compact ? screenColor : drawerColor; |
| 511 | const effectiveSelectedBackground = | ||
| 512 | Platform.OS === "android" ? materialSelectedBackgroundColor : selectedBackgroundColor; | ||
| 513 | const effectiveSelectedForeground = | ||
| 514 | Platform.OS === "android" ? materialSelectedForegroundColor : selectedForegroundColor; | ||
| 515 | const effectiveStatus = | ||
| 516 | visuallySelected && status | ||
| 517 | ? { | ||
| 518 | ...status, | ||
| 519 | pillClassName: | ||
| 520 | Platform.OS === "android" | ||
| 521 | ? "bg-thread-selected-foreground/20" | ||
| 522 | : "bg-user-bubble-foreground/20", | ||
| 523 | textClassName: | ||
| 524 | Platform.OS === "android" | ||
| 525 | ? "text-thread-selected-foreground" | ||
| 526 | : "text-user-bubble-foreground", | ||
| 527 | } | ||
| 528 | : status; | ||
| 529 | 538 | ||
| 530 | const handleDelete = useCallback(() => onDeleteThread(thread), [onDeleteThread, thread]); | 539 | const handleDelete = useCallback(() => onDeleteThread(thread), [onDeleteThread, thread]); |
| 531 | const handleArchive = useCallback(() => onArchiveThread(thread), [onArchiveThread, thread]); | 540 | const handleArchive = useCallback(() => onArchiveThread(thread), [onArchiveThread, thread]); |
| ... | @@ -580,11 +589,9 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -580,11 +589,9 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 580 | [handleArchive, handleDelete, handleRegenerateTitle, handleRename, onNewThreadOnBranch, thread], | 589 | [handleArchive, handleDelete, handleRegenerateTitle, handleRename, onNewThreadOnBranch, thread], |
| 581 | ); | 590 | ); |
| 582 | 591 | ||
| 583 | const statusPill = effectiveStatus ? ( | 592 | const statusPill = status ? ( |
| 584 | <View className={`${effectiveStatus.pillClassName} rounded-full px-1.5 py-0.5`}> | 593 | <View className={`${status.pillClassName} rounded-full px-1.5 py-0.5`}> |
| 585 | <Text className={`text-3xs font-t3-bold ${effectiveStatus.textClassName}`}> | 594 | <Text className={`text-3xs font-t3-bold ${status.textClassName}`}>{status.label}</Text> |
| 586 | {effectiveStatus.label} | ||
| 587 | </Text> | ||
| 588 | </View> | 595 | </View> |
| 589 | ) : null; | 596 | ) : null; |
| 590 | 597 | ||
| ... | @@ -601,10 +608,8 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -601,10 +608,8 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 601 | compact | 608 | compact |
| 602 | ? "accent-icon-subtle" | 609 | ? "accent-icon-subtle" |
| 603 | : selected | 610 | : selected |
| 604 | ? Platform.OS === "android" | 611 | ? "accent-thread-selected-foreground-muted" |
| 605 | ? "accent-thread-selected-foreground-muted" | 612 | : "accent-drawer-foreground-muted" |
| 606 | : "accent-user-bubble-foreground-muted" | ||
| 607 | : "accent-foreground-muted" | ||
| 608 | } | 613 | } |
| 609 | /> | 614 | /> |
| 610 | ) : null} | 615 | ) : null} |
| ... | @@ -613,10 +618,10 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -613,10 +618,10 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 613 | "shrink", | 618 | "shrink", |
| 614 | compact ? "text-sm" : "text-xs", | 619 | compact ? "text-sm" : "text-xs", |
| 615 | visuallySelected | 620 | visuallySelected |
| 616 | ? Platform.OS === "android" | 621 | ? "text-thread-selected-foreground-muted" |
| 617 | ? "text-thread-selected-foreground-muted" | 622 | : compact |
| 618 | : "text-user-bubble-foreground-muted" | 623 | ? "text-foreground-muted" |
| 619 | : "text-foreground-muted", | 624 | : "text-drawer-foreground-muted", |
| 620 | )} | 625 | )} |
| 621 | numberOfLines={1} | 626 | numberOfLines={1} |
| 622 | > | 627 | > |
| ... | @@ -633,30 +638,16 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -633,30 +638,16 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 633 | <SymbolView | 638 | <SymbolView |
| 634 | name="square.3.layers.3d" | 639 | name="square.3.layers.3d" |
| 635 | size={compact ? 13 : 11} | 640 | size={compact ? 13 : 11} |
| 636 | tintColor={ | 641 | tintColor={pullRequestTintColor(pr, colorScheme)} |
| 637 | visuallySelected | ||
| 638 | ? String(effectiveSelectedForeground) | ||
| 639 | : pullRequestTintColor(pr, colorScheme) | ||
| 640 | } | ||
| 641 | /> | 642 | /> |
| 642 | ) : ( | 643 | ) : ( |
| 643 | <PullRequestIcon | 644 | <PullRequestIcon |
| 644 | size={compact ? 13 : 11} | 645 | size={compact ? 13 : 11} |
| 645 | color={ | 646 | color={pullRequestTintColor(pr, colorScheme)} |
| 646 | visuallySelected | ||
| 647 | ? String(effectiveSelectedForeground) | ||
| 648 | : pullRequestTintColor(pr, colorScheme) | ||
| 649 | } | ||
| 650 | /> | 647 | /> |
| 651 | )} | 648 | )} |
| 652 | <Text | 649 | <Text |
| 653 | className={`${compact ? "text-sm" : "text-xs"} font-t3-medium ${ | 650 | className={`${compact ? "text-sm" : "text-xs"} font-t3-medium ${pr.textClassName}`} |
| 654 | visuallySelected | ||
| 655 | ? Platform.OS === "android" | ||
| 656 | ? "text-thread-selected-foreground" | ||
| 657 | : "text-user-bubble-foreground" | ||
| 658 | : pr.textClassName | ||
| 659 | }`} | ||
| 660 | > | 651 | > |
| 661 | {pr.label} | 652 | {pr.label} |
| 662 | </Text> | 653 | </Text> |
| ... | @@ -669,13 +660,8 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -669,13 +660,8 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 669 | compact ? ( | 660 | compact ? ( |
| 670 | <RowPressable | 661 | <RowPressable |
| 671 | key={`${thread.environmentId}:${thread.id}`} | 662 | key={`${thread.environmentId}:${thread.id}`} |
| 672 | interactionClassName={ | 663 | interactionClassName="bg-row-hover" |
| 673 | visuallySelected | 664 | interactionOpacity={visuallySelected ? 0 : 1} |
| 674 | ? Platform.OS === "android" | ||
| 675 | ? "bg-thread-selected-foreground" | ||
| 676 | : "bg-user-bubble-foreground" | ||
| 677 | : "bg-primary" | ||
| 678 | } | ||
| 679 | accessibilityHint="Swipe left for archive and delete actions" | 665 | accessibilityHint="Swipe left for archive and delete actions" |
| 680 | accessibilityLabel={threadAccessibilityLabel} | 666 | accessibilityLabel={threadAccessibilityLabel} |
| 681 | accessibilityRole="button" | 667 | accessibilityRole="button" |
| ... | @@ -683,7 +669,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -683,7 +669,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 683 | style={ | 669 | style={ |
| 684 | Platform.OS === "android" | 670 | Platform.OS === "android" |
| 685 | ? { | 671 | ? { |
| 686 | backgroundColor: visuallySelected ? effectiveSelectedBackground : backgroundColor, | 672 | backgroundColor: visuallySelected ? selectedBackgroundColor : backgroundColor, |
| 687 | borderRadius: 20, | 673 | borderRadius: 20, |
| 688 | } | 674 | } |
| 689 | : undefined | 675 | : undefined |
| ... | @@ -705,10 +691,10 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -705,10 +691,10 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 705 | className={cn( | 691 | className={cn( |
| 706 | "flex-1 text-lg font-t3-bold", | 692 | "flex-1 text-lg font-t3-bold", |
| 707 | visuallySelected | 693 | visuallySelected |
| 708 | ? Platform.OS === "android" | 694 | ? "text-thread-selected-foreground" |
| 709 | ? "text-thread-selected-foreground" | 695 | : compact |
| 710 | : "text-user-bubble-foreground" | 696 | ? "text-foreground" |
| 711 | : "text-foreground", | 697 | : "text-drawer-foreground", |
| 712 | )} | 698 | )} |
| 713 | numberOfLines={1} | 699 | numberOfLines={1} |
| 714 | > | 700 | > |
| ... | @@ -723,10 +709,8 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -723,10 +709,8 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 723 | className={cn( | 709 | className={cn( |
| 724 | "text-base tabular-nums", | 710 | "text-base tabular-nums", |
| 725 | visuallySelected | 711 | visuallySelected |
| 726 | ? Platform.OS === "android" | 712 | ? "text-thread-selected-foreground-muted" |
| 727 | ? "text-thread-selected-foreground-muted" | 713 | : "text-drawer-foreground-muted", |
| 728 | : "text-user-bubble-foreground-muted" | ||
| 729 | : "text-foreground-tertiary", | ||
| 730 | )} | 714 | )} |
| 731 | > | 715 | > |
| 732 | {timestamp} | 716 | {timestamp} |
| ... | @@ -742,6 +726,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -742,6 +726,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 742 | {props.searchMatch ? ( | 726 | {props.searchMatch ? ( |
| 743 | <ThreadSearchMatchExcerpt | 727 | <ThreadSearchMatchExcerpt |
| 744 | compact | 728 | compact |
| 729 | sidebar={!compact} | ||
| 745 | match={props.searchMatch} | 730 | match={props.searchMatch} |
| 746 | query={props.searchQuery ?? ""} | 731 | query={props.searchQuery ?? ""} |
| 747 | selected={visuallySelected} | 732 | selected={visuallySelected} |
| ... | @@ -754,13 +739,8 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -754,13 +739,8 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 754 | ) : ( | 739 | ) : ( |
| 755 | <RowPressable | 740 | <RowPressable |
| 756 | key={`${thread.environmentId}:${thread.id}`} | 741 | key={`${thread.environmentId}:${thread.id}`} |
| 757 | interactionClassName={ | 742 | interactionClassName="bg-thread-hover" |
| 758 | visuallySelected | 743 | interactionOpacity={visuallySelected ? 0 : 1} |
| 759 | ? Platform.OS === "android" | ||
| 760 | ? "bg-thread-selected-foreground" | ||
| 761 | : "bg-user-bubble-foreground" | ||
| 762 | : "bg-primary" | ||
| 763 | } | ||
| 764 | accessibilityHint="Opens the thread" | 744 | accessibilityHint="Opens the thread" |
| 765 | accessibilityLabel={threadAccessibilityLabel} | 745 | accessibilityLabel={threadAccessibilityLabel} |
| 766 | accessibilityRole="button" | 746 | accessibilityRole="button" |
| ... | @@ -770,7 +750,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -770,7 +750,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 770 | onSelectThread(thread); | 750 | onSelectThread(thread); |
| 771 | }} | 751 | }} |
| 772 | style={{ | 752 | style={{ |
| 773 | backgroundColor: visuallySelected ? effectiveSelectedBackground : backgroundColor, | 753 | backgroundColor: visuallySelected ? selectedBackgroundColor : backgroundColor, |
| 774 | borderRadius: Platform.OS === "android" ? 20 : SIDEBAR_ROW_RADIUS, | 754 | borderRadius: Platform.OS === "android" ? 20 : SIDEBAR_ROW_RADIUS, |
| 775 | minHeight: 64, | 755 | minHeight: 64, |
| 776 | justifyContent: "center", | 756 | justifyContent: "center", |
| ... | @@ -784,10 +764,10 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -784,10 +764,10 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 784 | className={cn( | 764 | className={cn( |
| 785 | "flex-1 text-base font-t3-medium", | 765 | "flex-1 text-base font-t3-medium", |
| 786 | visuallySelected | 766 | visuallySelected |
| 787 | ? Platform.OS === "android" | 767 | ? "text-thread-selected-foreground" |
| 788 | ? "text-thread-selected-foreground" | 768 | : compact |
| 789 | : "text-user-bubble-foreground" | 769 | ? "text-foreground" |
| 790 | : "text-foreground", | 770 | : "text-drawer-foreground", |
| 791 | )} | 771 | )} |
| 792 | numberOfLines={1} | 772 | numberOfLines={1} |
| 793 | > | 773 | > |
| ... | @@ -802,10 +782,10 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -802,10 +782,10 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 802 | className={cn( | 782 | className={cn( |
| 803 | "text-xs tabular-nums", | 783 | "text-xs tabular-nums", |
| 804 | visuallySelected | 784 | visuallySelected |
| 805 | ? Platform.OS === "android" | 785 | ? "text-thread-selected-foreground-muted" |
| 806 | ? "text-thread-selected-foreground-muted" | 786 | : compact |
| 807 | : "text-user-bubble-foreground-muted" | 787 | ? "text-foreground-muted" |
| 808 | : "text-foreground-muted", | 788 | : "text-drawer-foreground-muted", |
| 809 | )} | 789 | )} |
| 810 | numberOfLines={1} | 790 | numberOfLines={1} |
| 811 | > | 791 | > |
| ... | @@ -815,6 +795,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: { | ... | @@ -815,6 +795,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: { |
| 815 | </View> | 795 | </View> |
| 816 | {props.searchMatch ? ( | 796 | {props.searchMatch ? ( |
| 817 | <ThreadSearchMatchExcerpt | 797 | <ThreadSearchMatchExcerpt |
| 798 | sidebar={!compact} | ||
| 818 | match={props.searchMatch} | 799 | match={props.searchMatch} |
| 819 | query={props.searchQuery ?? ""} | 800 | query={props.searchQuery ?? ""} |
| 820 | selected={visuallySelected} | 801 | selected={visuallySelected} |
apps/mobile/src/features/threads/thread-list-v2-items.tsx+109-40| ... | @@ -64,7 +64,7 @@ const STATUS_LABEL_BY_STATUS: Partial< | ... | @@ -64,7 +64,7 @@ const STATUS_LABEL_BY_STATUS: Partial< |
| 64 | Record<ThreadListV2Status, { label: string; className: string }> | 64 | Record<ThreadListV2Status, { label: string; className: string }> |
| 65 | > = { | 65 | > = { |
| 66 | approval: { label: "Approval", className: "text-warning-foreground" }, | 66 | approval: { label: "Approval", className: "text-warning-foreground" }, |
| 67 | input: { label: "Input", className: "text-foreground-secondary" }, | 67 | input: { label: "Input", className: "text-adaptive-indigo-600-300" }, |
| 68 | working: { label: "Working", className: "text-adaptive-sky-600-400" }, | 68 | working: { label: "Working", className: "text-adaptive-sky-600-400" }, |
| 69 | failed: { label: "Failed", className: "text-danger-foreground" }, | 69 | failed: { label: "Failed", className: "text-danger-foreground" }, |
| 70 | }; | 70 | }; |
| ... | @@ -112,6 +112,7 @@ function ThreadListV2Section(props: { | ... | @@ -112,6 +112,7 @@ function ThreadListV2Section(props: { |
| 112 | }; | 112 | }; |
| 113 | }) { | 113 | }) { |
| 114 | const snoozed = props.tone === "snoozed"; | 114 | const snoozed = props.tone === "snoozed"; |
| 115 | const sidebarPane = props.pane === "sidebar"; | ||
| 115 | const className = cn( | 116 | const className = cn( |
| 116 | "mb-1.5 mt-4 flex-row items-center gap-2.5", | 117 | "mb-1.5 mt-4 flex-row items-center gap-2.5", |
| 117 | props.pane === "sidebar" ? "px-3" : "px-5", | 118 | props.pane === "sidebar" ? "px-3" : "px-5", |
| ... | @@ -121,17 +122,32 @@ function ThreadListV2Section(props: { | ... | @@ -121,17 +122,32 @@ function ThreadListV2Section(props: { |
| 121 | <Text | 122 | <Text |
| 122 | className={cn( | 123 | className={cn( |
| 123 | "text-xs font-t3-medium", | 124 | "text-xs font-t3-medium", |
| 124 | snoozed ? "text-foreground-secondary" : "text-foreground-tertiary", | 125 | sidebarPane |
| 126 | ? "text-drawer-foreground-muted" | ||
| 127 | : snoozed | ||
| 128 | ? "text-foreground-secondary" | ||
| 129 | : "text-foreground-tertiary", | ||
| 125 | )} | 130 | )} |
| 126 | > | 131 | > |
| 127 | {props.label} | 132 | {props.label} |
| 128 | </Text> | 133 | </Text> |
| 129 | <View className={cn("h-px flex-1", snoozed ? "bg-primary/20" : "bg-border")} /> | 134 | <View |
| 135 | className={cn( | ||
| 136 | "h-px flex-1", | ||
| 137 | snoozed ? "bg-primary/20" : sidebarPane ? "bg-drawer-border" : "bg-border", | ||
| 138 | )} | ||
| 139 | /> | ||
| 130 | {props.disclosure ? ( | 140 | {props.disclosure ? ( |
| 131 | <SymbolView | 141 | <SymbolView |
| 132 | name="chevron.down" | 142 | name="chevron.down" |
| 133 | size={10} | 143 | size={10} |
| 134 | tintColorClassName={snoozed ? "accent-icon-muted" : "accent-foreground-muted"} | 144 | tintColorClassName={ |
| 145 | sidebarPane | ||
| 146 | ? "accent-drawer-foreground-muted" | ||
| 147 | : snoozed | ||
| 148 | ? "accent-icon-muted" | ||
| 149 | : "accent-foreground-muted" | ||
| 150 | } | ||
| 135 | type="monochrome" | 151 | type="monochrome" |
| 136 | style={{ transform: [{ rotate: props.disclosure.expanded ? "180deg" : "0deg" }] }} | 152 | style={{ transform: [{ rotate: props.disclosure.expanded ? "180deg" : "0deg" }] }} |
| 137 | /> | 153 | /> |
| ... | @@ -209,6 +225,7 @@ export const ThreadListV2SettledShelfHeader = memo(function ThreadListV2SettledS | ... | @@ -209,6 +225,7 @@ export const ThreadListV2SettledShelfHeader = memo(function ThreadListV2SettledS |
| 209 | }); | 225 | }); |
| 210 | 226 | ||
| 211 | export const ThreadListV2ShowMoreRow = memo(function ThreadListV2ShowMoreRow(props: { | 227 | export const ThreadListV2ShowMoreRow = memo(function ThreadListV2ShowMoreRow(props: { |
| 228 | readonly pane?: "screen" | "sidebar"; | ||
| 212 | readonly hiddenCount: number; | 229 | readonly hiddenCount: number; |
| 213 | readonly onPress: () => void; | 230 | readonly onPress: () => void; |
| 214 | }) { | 231 | }) { |
| ... | @@ -220,7 +237,13 @@ export const ThreadListV2ShowMoreRow = memo(function ThreadListV2ShowMoreRow(pro | ... | @@ -220,7 +237,13 @@ export const ThreadListV2ShowMoreRow = memo(function ThreadListV2ShowMoreRow(pro |
| 220 | className="mx-4 mt-2 items-center rounded-lg border border-dashed border-border py-2.5" | 237 | className="mx-4 mt-2 items-center rounded-lg border border-dashed border-border py-2.5" |
| 221 | style={({ pressed }) => ({ opacity: pressed ? 0.6 : 1 })} | 238 | style={({ pressed }) => ({ opacity: pressed ? 0.6 : 1 })} |
| 222 | > | 239 | > |
| 223 | <Text className="text-xs font-t3-medium text-foreground-muted"> | 240 | <Text |
| 241 | className={ | ||
| 242 | props.pane === "sidebar" | ||
| 243 | ? "text-xs font-t3-medium text-drawer-foreground-muted" | ||
| 244 | : "text-xs font-t3-medium text-foreground-muted" | ||
| 245 | } | ||
| 246 | > | ||
| 224 | Show more ({props.hiddenCount} settled hidden) | 247 | Show more ({props.hiddenCount} settled hidden) |
| 225 | </Text> | 248 | </Text> |
| 226 | </Pressable> | 249 | </Pressable> |
| ... | @@ -282,7 +305,13 @@ export const ThreadListV2PendingRow = memo(function ThreadListV2PendingRow(props | ... | @@ -282,7 +305,13 @@ export const ThreadListV2PendingRow = memo(function ThreadListV2PendingRow(props |
| 282 | workspaceRoot={props.project.workspaceRoot} | 305 | workspaceRoot={props.project.workspaceRoot} |
| 283 | /> | 306 | /> |
| 284 | ) : null} | 307 | ) : null} |
| 285 | <Text className="flex-1 text-sm font-t3-medium text-foreground-muted" numberOfLines={1}> | 308 | <Text |
| 309 | className={cn( | ||
| 310 | "flex-1 text-sm font-t3-medium text-foreground-muted", | ||
| 311 | sidebarPane && "text-drawer-foreground-muted", | ||
| 312 | )} | ||
| 313 | numberOfLines={1} | ||
| 314 | > | ||
| 286 | {projectTitle} | 315 | {projectTitle} |
| 287 | </Text> | 316 | </Text> |
| 288 | {isDraft ? ( | 317 | {isDraft ? ( |
| ... | @@ -296,33 +325,67 @@ export const ThreadListV2PendingRow = memo(function ThreadListV2PendingRow(props | ... | @@ -296,33 +325,67 @@ export const ThreadListV2PendingRow = memo(function ThreadListV2PendingRow(props |
| 296 | <Text className="text-xs text-adaptive-amber-700-300">Draft</Text> | 325 | <Text className="text-xs text-adaptive-amber-700-300">Draft</Text> |
| 297 | </View> | 326 | </View> |
| 298 | ) : ( | 327 | ) : ( |
| 299 | <Text className="text-xs text-foreground-tertiary">Sends on reconnect</Text> | 328 | <Text |
| 329 | className={cn( | ||
| 330 | "text-xs text-foreground-tertiary", | ||
| 331 | sidebarPane && "text-drawer-foreground-muted", | ||
| 332 | )} | ||
| 333 | > | ||
| 334 | Sends on reconnect | ||
| 335 | </Text> | ||
| 300 | )} | 336 | )} |
| 301 | </View> | 337 | </View> |
| 302 | {/* One line, unlike the two an active row allows: a queued title is | 338 | {/* One line, unlike the two an active row allows: a queued title is |
| 303 | derived from the whole prompt rather than written as a title, so the | 339 | derived from the whole prompt rather than written as a title, so the |
| 304 | second line is usually a stray word or emoji rather than meaning. */} | 340 | second line is usually a stray word or emoji rather than meaning. */} |
| 305 | <Text className="mt-1 text-base font-t3-medium text-foreground" numberOfLines={1}> | 341 | <Text |
| 342 | className={cn( | ||
| 343 | "mt-1 text-base font-t3-medium text-foreground", | ||
| 344 | sidebarPane && "text-drawer-foreground", | ||
| 345 | )} | ||
| 346 | numberOfLines={1} | ||
| 347 | > | ||
| 306 | {pendingTask.title} | 348 | {pendingTask.title} |
| 307 | </Text> | 349 | </Text> |
| 308 | {branch || props.environmentLabel ? ( | 350 | {branch || props.environmentLabel ? ( |
| 309 | <View className="mt-1 flex-row items-center gap-1"> | 351 | <View className="mt-1 flex-row items-center gap-1"> |
| 310 | <Text className="shrink text-xs text-foreground-muted" numberOfLines={1}> | 352 | <Text |
| 353 | className={cn( | ||
| 354 | "shrink text-xs text-foreground-muted", | ||
| 355 | sidebarPane && "text-drawer-foreground-muted", | ||
| 356 | )} | ||
| 357 | numberOfLines={1} | ||
| 358 | > | ||
| 311 | {branch ? ( | 359 | {branch ? ( |
| 312 | <Text className="text-xs text-foreground-muted" style={{ fontFamily: MONO_FONT }}> | 360 | <Text |
| 361 | className={cn( | ||
| 362 | "text-xs text-foreground-muted", | ||
| 363 | sidebarPane && "text-drawer-foreground-muted", | ||
| 364 | )} | ||
| 365 | style={{ fontFamily: MONO_FONT }} | ||
| 366 | > | ||
| 313 | {branch} | 367 | {branch} |
| 314 | </Text> | 368 | </Text> |
| 315 | ) : null} | 369 | ) : null} |
| 316 | {branch && props.environmentLabel ? " · " : null} | 370 | {branch && props.environmentLabel ? " · " : null} |
| 317 | {props.environmentLabel ? ( | 371 | {props.environmentLabel ? ( |
| 318 | <Text className="text-xs text-foreground-tertiary">{props.environmentLabel}</Text> | 372 | <Text |
| 373 | className={cn( | ||
| 374 | "text-xs text-foreground-tertiary", | ||
| 375 | sidebarPane && "text-drawer-foreground-muted", | ||
| 376 | )} | ||
| 377 | > | ||
| 378 | {props.environmentLabel} | ||
| 379 | </Text> | ||
| 319 | ) : null} | 380 | ) : null} |
| 320 | </Text> | 381 | </Text> |
| 321 | {props.environmentLabel && props.environmentMachine ? ( | 382 | {props.environmentLabel && props.environmentMachine ? ( |
| 322 | <EnvironmentMachineSymbol | 383 | <EnvironmentMachineSymbol |
| 323 | kind={props.environmentMachine} | 384 | kind={props.environmentMachine} |
| 324 | size={11} | 385 | size={11} |
| 325 | tintColorClassName="accent-foreground-tertiary" | 386 | tintColorClassName={ |
| 387 | sidebarPane ? "accent-drawer-foreground-muted" : "accent-foreground-tertiary" | ||
| 388 | } | ||
| 326 | /> | 389 | /> |
| 327 | ) : null} | 390 | ) : null} |
| 328 | </View> | 391 | </View> |
| ... | @@ -350,6 +413,7 @@ export const ThreadListV2PendingRow = memo(function ThreadListV2PendingRow(props | ... | @@ -350,6 +413,7 @@ export const ThreadListV2PendingRow = memo(function ThreadListV2PendingRow(props |
| 350 | accessibilityRole="button" | 413 | accessibilityRole="button" |
| 351 | key={pendingTask.key} | 414 | key={pendingTask.key} |
| 352 | className={sidebarPane ? "bg-drawer" : "bg-screen"} | 415 | className={sidebarPane ? "bg-drawer" : "bg-screen"} |
| 416 | interactionClassName={sidebarPane ? "bg-thread-hover" : "bg-row-hover"} | ||
| 353 | onPress={() => onSelectPendingTask(pendingTask)} | 417 | onPress={() => onSelectPendingTask(pendingTask)} |
| 354 | style={ | 418 | style={ |
| 355 | sidebarPane | 419 | sidebarPane |
| ... | @@ -759,8 +823,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -759,8 +823,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 759 | ? `Opens the thread. Swipe left to ${primaryAction.label.toLowerCase()}.` | 823 | ? `Opens the thread. Swipe left to ${primaryAction.label.toLowerCase()}.` |
| 760 | : `Opens the thread. Swipe left for ${primaryAction.label.toLowerCase()} and snooze actions.`; | 824 | : `Opens the thread. Swipe left for ${primaryAction.label.toLowerCase()} and snooze actions.`; |
| 761 | 825 | ||
| 762 | // The sidebar pane fills selected rows with the theme's message surface, so | 826 | // Sidebar rows use navigation foregrounds on their active and idle surfaces. |
| 763 | // every piece of row text must use that surface's paired foreground. | ||
| 764 | const cardContent = ( | 827 | const cardContent = ( |
| 765 | <> | 828 | <> |
| 766 | <View className="flex-row items-center gap-1.5"> | 829 | <View className="flex-row items-center gap-1.5"> |
| ... | @@ -776,7 +839,9 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -776,7 +839,9 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 776 | <Text | 839 | <Text |
| 777 | className={cn( | 840 | className={cn( |
| 778 | "flex-1 text-sm font-t3-medium", | 841 | "flex-1 text-sm font-t3-medium", |
| 779 | selected ? selectedThreadRowColors.mutedForegroundClassName : "text-foreground-muted", | 842 | selected |
| 843 | ? selectedThreadRowColors.mutedForegroundClassName | ||
| 844 | : rowAppearance.mutedForegroundClassName, | ||
| 780 | )} | 845 | )} |
| 781 | numberOfLines={1} | 846 | numberOfLines={1} |
| 782 | > | 847 | > |
| ... | @@ -787,16 +852,17 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -787,16 +852,17 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 787 | <SymbolView | 852 | <SymbolView |
| 788 | name="pin" | 853 | name="pin" |
| 789 | size={11} | 854 | size={11} |
| 790 | tintColorClassName="accent-foreground-muted" | 855 | tintColorClassName={rowAppearance.mutedIconTintClassName} |
| 791 | type="monochrome" | 856 | type="monochrome" |
| 792 | /> | 857 | /> |
| 793 | ) : null} | 858 | ) : null} |
| 794 | <Text | 859 | <Text |
| 795 | className={cn( | 860 | className={cn( |
| 796 | "text-xs tabular-nums", | 861 | "text-xs tabular-nums", |
| 797 | selected | 862 | statusLabel?.className ?? |
| 798 | ? selectedThreadRowColors.foregroundClassName | 863 | (selected |
| 799 | : (statusLabel?.className ?? "text-foreground-tertiary"), | 864 | ? selectedThreadRowColors.foregroundClassName |
| 865 | : rowAppearance.tertiaryForegroundClassName), | ||
| 800 | )} | 866 | )} |
| 801 | > | 867 | > |
| 802 | {statusLabel?.label ?? timeLabel} | 868 | {statusLabel?.label ?? timeLabel} |
| ... | @@ -805,7 +871,9 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -805,7 +871,9 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 805 | <Text | 871 | <Text |
| 806 | className={cn( | 872 | className={cn( |
| 807 | "mt-1 text-base font-t3-medium", | 873 | "mt-1 text-base font-t3-medium", |
| 808 | selected ? selectedThreadRowColors.foregroundClassName : "text-foreground", | 874 | selected |
| 875 | ? selectedThreadRowColors.foregroundClassName | ||
| 876 | : rowAppearance.foregroundClassName, | ||
| 809 | )} | 877 | )} |
| 810 | numberOfLines={2} | 878 | numberOfLines={2} |
| 811 | > | 879 | > |
| ... | @@ -814,6 +882,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -814,6 +882,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 814 | {props.searchMatch ? ( | 882 | {props.searchMatch ? ( |
| 815 | <View className="mt-1"> | 883 | <View className="mt-1"> |
| 816 | <ThreadSearchMatchExcerpt | 884 | <ThreadSearchMatchExcerpt |
| 885 | sidebar={sidebarPane} | ||
| 817 | match={props.searchMatch} | 886 | match={props.searchMatch} |
| 818 | query={props.searchQuery ?? ""} | 887 | query={props.searchQuery ?? ""} |
| 819 | selected={selected} | 888 | selected={selected} |
| ... | @@ -846,7 +915,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -846,7 +915,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 846 | "shrink text-xs", | 915 | "shrink text-xs", |
| 847 | selected | 916 | selected |
| 848 | ? selectedThreadRowColors.mutedForegroundClassName | 917 | ? selectedThreadRowColors.mutedForegroundClassName |
| 849 | : "text-foreground-muted", | 918 | : rowAppearance.mutedForegroundClassName, |
| 850 | )} | 919 | )} |
| 851 | numberOfLines={1} | 920 | numberOfLines={1} |
| 852 | > | 921 | > |
| ... | @@ -856,7 +925,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -856,7 +925,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 856 | "text-xs", | 925 | "text-xs", |
| 857 | selected | 926 | selected |
| 858 | ? selectedThreadRowColors.mutedForegroundClassName | 927 | ? selectedThreadRowColors.mutedForegroundClassName |
| 859 | : "text-foreground-muted", | 928 | : rowAppearance.mutedForegroundClassName, |
| 860 | )} | 929 | )} |
| 861 | style={{ fontFamily: MONO_FONT }} | 930 | style={{ fontFamily: MONO_FONT }} |
| 862 | > | 931 | > |
| ... | @@ -870,7 +939,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -870,7 +939,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 870 | "text-xs", | 939 | "text-xs", |
| 871 | selected | 940 | selected |
| 872 | ? selectedThreadRowColors.mutedForegroundClassName | 941 | ? selectedThreadRowColors.mutedForegroundClassName |
| 873 | : "text-foreground-tertiary", | 942 | : rowAppearance.tertiaryForegroundClassName, |
| 874 | )} | 943 | )} |
| 875 | > | 944 | > |
| 876 | {props.environmentLabel} | 945 | {props.environmentLabel} |
| ... | @@ -884,7 +953,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -884,7 +953,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 884 | tintColorClassName={ | 953 | tintColorClassName={ |
| 885 | selected | 954 | selected |
| 886 | ? selectedThreadRowColors.mutedIconTintClassName | 955 | ? selectedThreadRowColors.mutedIconTintClassName |
| 887 | : "accent-foreground-tertiary" | 956 | : rowAppearance.tertiaryIconTintClassName |
| 888 | } | 957 | } |
| 889 | /> | 958 | /> |
| 890 | ) : null} | 959 | ) : null} |
| ... | @@ -899,24 +968,19 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -899,24 +968,19 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 899 | name={pr.kind === "stack" ? "square.3.layers.3d" : "arrow.triangle.pull"} | 968 | name={pr.kind === "stack" ? "square.3.layers.3d" : "arrow.triangle.pull"} |
| 900 | size={12} | 969 | size={12} |
| 901 | tintColorClassName={ | 970 | tintColorClassName={ |
| 902 | selected | 971 | pr.state === null || pr.isDraft |
| 903 | ? selectedThreadRowColors.iconTintClassName | 972 | ? rowAppearance.mutedIconTintClassName |
| 904 | : pr.state === null || pr.isDraft | 973 | : pr.state === "open" |
| 905 | ? "accent-foreground-muted" | 974 | ? "accent-adaptive-emerald-600-400" |
| 906 | : pr.state === "open" | 975 | : pr.state === "closed" |
| 907 | ? "accent-adaptive-emerald-600-400" | 976 | ? "accent-adaptive-rose-600-400" |
| 908 | : pr.state === "closed" | 977 | : "accent-adaptive-violet-600-400" |
| 909 | ? "accent-adaptive-rose-600-400" | ||
| 910 | : "accent-adaptive-violet-600-400" | ||
| 911 | } | 978 | } |
| 912 | /> | 979 | /> |
| 913 | ) : null} | 980 | ) : null} |
| 914 | <Text | 981 | <Text |
| 915 | accessibilityLabel={pr.accessibilityLabel} | 982 | accessibilityLabel={pr.accessibilityLabel} |
| 916 | className={cn( | 983 | className={cn("text-xs", pr.textClassName)} |
| 917 | "text-xs", | ||
| 918 | selected ? selectedThreadRowColors.foregroundClassName : pr.textClassName, | ||
| 919 | )} | ||
| 920 | style={{ fontFamily: MONO_FONT }} | 984 | style={{ fontFamily: MONO_FONT }} |
| 921 | > | 985 | > |
| 922 | {pr.kind === "stack" || pr.others > 0 ? pr.label : `#${pr.label}`} | 986 | {pr.kind === "stack" || pr.others > 0 ? pr.label : `#${pr.label}`} |
| ... | @@ -942,6 +1006,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -942,6 +1006,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 942 | <RowPressable | 1006 | <RowPressable |
| 943 | key={`${thread.environmentId}:${thread.id}`} | 1007 | key={`${thread.environmentId}:${thread.id}`} |
| 944 | interactionClassName={rowAppearance.interactionClassName} | 1008 | interactionClassName={rowAppearance.interactionClassName} |
| 1009 | interactionOpacity={rowAppearance.interactionOpacity} | ||
| 945 | className={rowAppearance.className} | 1010 | className={rowAppearance.className} |
| 946 | accessibilityHint={swipeAccessibilityHint} | 1011 | accessibilityHint={swipeAccessibilityHint} |
| 947 | accessibilityLabel={ | 1012 | accessibilityLabel={ |
| ... | @@ -974,6 +1039,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -974,6 +1039,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 974 | <RowPressable | 1039 | <RowPressable |
| 975 | key={`${thread.environmentId}:${thread.id}`} | 1040 | key={`${thread.environmentId}:${thread.id}`} |
| 976 | interactionClassName={rowAppearance.interactionClassName} | 1041 | interactionClassName={rowAppearance.interactionClassName} |
| 1042 | interactionOpacity={rowAppearance.interactionOpacity} | ||
| 977 | accessibilityHint={swipeAccessibilityHint} | 1043 | accessibilityHint={swipeAccessibilityHint} |
| 978 | accessibilityLabel={ | 1044 | accessibilityLabel={ |
| 979 | props.hasQueuedMessages ? `${thread.title}, messages queued to send` : thread.title | 1045 | props.hasQueuedMessages ? `${thread.title}, messages queued to send` : thread.title |
| ... | @@ -1009,7 +1075,9 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -1009,7 +1075,9 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 1009 | <Text | 1075 | <Text |
| 1010 | className={cn( | 1076 | className={cn( |
| 1011 | "text-base", | 1077 | "text-base", |
| 1012 | selected ? selectedThreadRowColors.foregroundClassName : "text-foreground-muted", | 1078 | selected |
| 1079 | ? selectedThreadRowColors.foregroundClassName | ||
| 1080 | : rowAppearance.mutedForegroundClassName, | ||
| 1013 | )} | 1081 | )} |
| 1014 | numberOfLines={1} | 1082 | numberOfLines={1} |
| 1015 | > | 1083 | > |
| ... | @@ -1017,6 +1085,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -1017,6 +1085,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 1017 | </Text> | 1085 | </Text> |
| 1018 | {props.searchMatch ? ( | 1086 | {props.searchMatch ? ( |
| 1019 | <ThreadSearchMatchExcerpt | 1087 | <ThreadSearchMatchExcerpt |
| 1088 | sidebar={sidebarPane} | ||
| 1020 | match={props.searchMatch} | 1089 | match={props.searchMatch} |
| 1021 | query={props.searchQuery ?? ""} | 1090 | query={props.searchQuery ?? ""} |
| 1022 | selected={selected} | 1091 | selected={selected} |
| ... | @@ -1030,8 +1099,8 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { | ... | @@ -1030,8 +1099,8 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { |
| 1030 | selected | 1099 | selected |
| 1031 | ? selectedThreadRowColors.mutedForegroundClassName | 1100 | ? selectedThreadRowColors.mutedForegroundClassName |
| 1032 | : snoozedRow | 1101 | : snoozedRow |
| 1033 | ? "text-foreground-secondary" | 1102 | ? rowAppearance.mutedForegroundClassName |
| 1034 | : "text-foreground-tertiary", | 1103 | : rowAppearance.tertiaryForegroundClassName, |
| 1035 | )} | 1104 | )} |
| 1036 | style={{ fontFamily: MONO_FONT }} | 1105 | style={{ fontFamily: MONO_FONT }} |
| 1037 | > | 1106 | > |
apps/mobile/src/features/threads/thread-list-v2-row-appearance.android.ts+19-5| ... | @@ -22,8 +22,9 @@ export function getThreadListV2RowAppearance( | ... | @@ -22,8 +22,9 @@ export function getThreadListV2RowAppearance( |
| 22 | selected: boolean, | 22 | selected: boolean, |
| 23 | ) { | 23 | ) { |
| 24 | const selectedBackgroundColor = theme["--color-thread-selected"]; | 24 | const selectedBackgroundColor = theme["--color-thread-selected"]; |
| 25 | const backgroundColor = theme[sidebarPane ? "--color-drawer" : "--color-screen"]; | ||
| 25 | const style: ViewStyle = { | 26 | const style: ViewStyle = { |
| 26 | backgroundColor: selected ? selectedBackgroundColor : theme["--color-screen"], | 27 | backgroundColor: selected ? selectedBackgroundColor : backgroundColor, |
| 27 | borderRadius: 20, | 28 | borderRadius: 20, |
| 28 | }; | 29 | }; |
| 29 | const swipeContainerStyle: ViewStyle = { | 30 | const swipeContainerStyle: ViewStyle = { |
| ... | @@ -35,12 +36,25 @@ export function getThreadListV2RowAppearance( | ... | @@ -35,12 +36,25 @@ export function getThreadListV2RowAppearance( |
| 35 | 36 | ||
| 36 | return { | 37 | return { |
| 37 | className: undefined, | 38 | className: undefined, |
| 38 | interactionClassName: selected ? "bg-thread-selected-foreground" : "bg-primary", | 39 | interactionClassName: sidebarPane ? "bg-thread-hover" : "bg-row-hover", |
| 40 | interactionOpacity: selected ? 0 : 1, | ||
| 41 | foregroundClassName: sidebarPane ? "text-drawer-foreground" : "text-foreground", | ||
| 42 | mutedForegroundClassName: sidebarPane | ||
| 43 | ? "text-drawer-foreground-muted" | ||
| 44 | : "text-foreground-muted", | ||
| 45 | tertiaryForegroundClassName: sidebarPane | ||
| 46 | ? "text-drawer-foreground-muted" | ||
| 47 | : "text-foreground-tertiary", | ||
| 48 | mutedIconTintClassName: sidebarPane | ||
| 49 | ? "accent-drawer-foreground-muted" | ||
| 50 | : "accent-foreground-muted", | ||
| 51 | tertiaryIconTintClassName: sidebarPane | ||
| 52 | ? "accent-drawer-foreground-muted" | ||
| 53 | : "accent-foreground-tertiary", | ||
| 39 | style, | 54 | style, |
| 40 | cardStyle: sidebarPane ? { ...style, paddingHorizontal: 12, paddingVertical: 10 } : style, | 55 | cardStyle: sidebarPane ? { ...style, paddingHorizontal: 12, paddingVertical: 10 } : style, |
| 41 | swipeContainerStyle, | 56 | swipeContainerStyle, |
| 42 | swipeBackgroundColor: theme["--color-screen"], | 57 | swipeBackgroundColor: backgroundColor, |
| 43 | providerIconSurfaceColor: | 58 | providerIconSurfaceColor: selected ? selectedBackgroundColor : backgroundColor, |
| 44 | sidebarPane && selected ? selectedBackgroundColor : theme["--color-screen"], | ||
| 45 | }; | 59 | }; |
| 46 | } | 60 | } |
apps/mobile/src/features/threads/thread-list-v2-row-appearance.test.ts created+37| ... | @@ -0,0 +1,37 @@ | ||
| 1 | import { describe, expect, it } from "vite-plus/test"; | ||
| 2 | import { MOBILE_THEME_IDS } from "@t3tools/shared/themePalettes"; | ||
| 3 | |||
| 4 | import { getMobileThemeVariables } from "../../lib/mobileTheme"; | ||
| 5 | import { getThreadListV2RowAppearance as iosAppearance } from "./thread-list-v2-row-appearance"; | ||
| 6 | import { getThreadListV2RowAppearance as androidAppearance } from "./thread-list-v2-row-appearance.android"; | ||
| 7 | |||
| 8 | describe.each([ | ||
| 9 | ["ios", iosAppearance], | ||
| 10 | ["android", androidAppearance], | ||
| 11 | ] as const)("%s thread row colors", (_platform, appearanceFor) => { | ||
| 12 | it.each(MOBILE_THEME_IDS)( | ||
| 13 | "preserves active selection and uses neutral hover for %s", | ||
| 14 | (themeId) => { | ||
| 15 | for (const appearance of ["light", "dark"] as const) { | ||
| 16 | const theme = getMobileThemeVariables(themeId, appearance); | ||
| 17 | const idle = appearanceFor(theme, true, false); | ||
| 18 | const active = appearanceFor(theme, true, true); | ||
| 19 | |||
| 20 | expect(idle.style?.backgroundColor).toBe(theme["--color-drawer"]); | ||
| 21 | expect(idle.interactionClassName).toBe("bg-thread-hover"); | ||
| 22 | expect(idle.interactionOpacity).toBe(1); | ||
| 23 | expect(active.style?.backgroundColor).toBe(theme["--color-thread-selected"]); | ||
| 24 | // Pointer feedback must not mix a second color into the active background. | ||
| 25 | expect(active.interactionOpacity).toBe(0); | ||
| 26 | expect(active.providerIconSurfaceColor).toBe(active.style?.backgroundColor); | ||
| 27 | expect(idle.foregroundClassName).toBe("text-drawer-foreground"); | ||
| 28 | expect(idle.mutedForegroundClassName).toBe("text-drawer-foreground-muted"); | ||
| 29 | |||
| 30 | const phone = appearanceFor(theme, false, false); | ||
| 31 | expect(phone.swipeBackgroundColor).toBe(theme["--color-screen"]); | ||
| 32 | expect(phone.interactionClassName).toBe("bg-row-hover"); | ||
| 33 | expect(phone.foregroundClassName).toBe("text-foreground"); | ||
| 34 | } | ||
| 35 | }, | ||
| 36 | ); | ||
| 37 | }); | ||
apps/mobile/src/features/threads/thread-list-v2-row-appearance.ts+20-6| ... | @@ -6,10 +6,10 @@ export const THREAD_LIST_V2_ROW_CONTENT_CLASS_NAME = "px-5 py-2.5"; | ... | @@ -6,10 +6,10 @@ export const THREAD_LIST_V2_ROW_CONTENT_CLASS_NAME = "px-5 py-2.5"; |
| 6 | export const THREAD_LIST_V2_ROW_DIVIDERS = true; | 6 | export const THREAD_LIST_V2_ROW_DIVIDERS = true; |
| 7 | 7 | ||
| 8 | export const selectedThreadRowColors = { | 8 | export const selectedThreadRowColors = { |
| 9 | foregroundClassName: "text-user-bubble-foreground", | 9 | foregroundClassName: "text-thread-selected-foreground", |
| 10 | mutedForegroundClassName: "text-user-bubble-foreground-muted", | 10 | mutedForegroundClassName: "text-thread-selected-foreground-muted", |
| 11 | iconTintClassName: "accent-user-bubble-foreground", | 11 | iconTintClassName: "accent-thread-selected-foreground", |
| 12 | mutedIconTintClassName: "accent-user-bubble-foreground-muted", | 12 | mutedIconTintClassName: "accent-thread-selected-foreground-muted", |
| 13 | }; | 13 | }; |
| 14 | 14 | ||
| 15 | export function getThreadListV2NewBranchMenuTitle(_branch: string) { | 15 | export function getThreadListV2NewBranchMenuTitle(_branch: string) { |
| ... | @@ -21,7 +21,7 @@ export function getThreadListV2RowAppearance( | ... | @@ -21,7 +21,7 @@ export function getThreadListV2RowAppearance( |
| 21 | sidebarPane: boolean, | 21 | sidebarPane: boolean, |
| 22 | selected: boolean, | 22 | selected: boolean, |
| 23 | ) { | 23 | ) { |
| 24 | const selectedBackgroundColor = theme["--color-user-bubble"]; | 24 | const selectedBackgroundColor = theme["--color-thread-selected"]; |
| 25 | const style: ViewStyle | undefined = sidebarPane | 25 | const style: ViewStyle | undefined = sidebarPane |
| 26 | ? { | 26 | ? { |
| 27 | backgroundColor: selected ? selectedBackgroundColor : theme["--color-drawer"], | 27 | backgroundColor: selected ? selectedBackgroundColor : theme["--color-drawer"], |
| ... | @@ -34,7 +34,21 @@ export function getThreadListV2RowAppearance( | ... | @@ -34,7 +34,21 @@ export function getThreadListV2RowAppearance( |
| 34 | 34 | ||
| 35 | return { | 35 | return { |
| 36 | className: sidebarPane ? undefined : "bg-screen", | 36 | className: sidebarPane ? undefined : "bg-screen", |
| 37 | interactionClassName: selected && sidebarPane ? "bg-user-bubble-foreground" : "bg-primary", | 37 | interactionClassName: sidebarPane ? "bg-thread-hover" : "bg-row-hover", |
| 38 | interactionOpacity: selected ? 0 : 1, | ||
| 39 | foregroundClassName: sidebarPane ? "text-drawer-foreground" : "text-foreground", | ||
| 40 | mutedForegroundClassName: sidebarPane | ||
| 41 | ? "text-drawer-foreground-muted" | ||
| 42 | : "text-foreground-muted", | ||
| 43 | tertiaryForegroundClassName: sidebarPane | ||
| 44 | ? "text-drawer-foreground-muted" | ||
| 45 | : "text-foreground-tertiary", | ||
| 46 | mutedIconTintClassName: sidebarPane | ||
| 47 | ? "accent-drawer-foreground-muted" | ||
| 48 | : "accent-foreground-muted", | ||
| 49 | tertiaryIconTintClassName: sidebarPane | ||
| 50 | ? "accent-drawer-foreground-muted" | ||
| 51 | : "accent-foreground-tertiary", | ||
| 38 | style, | 52 | style, |
| 39 | cardStyle: sidebarPane ? { ...style, paddingHorizontal: 12, paddingVertical: 10 } : undefined, | 53 | cardStyle: sidebarPane ? { ...style, paddingHorizontal: 12, paddingVertical: 10 } : undefined, |
| 40 | swipeContainerStyle, | 54 | swipeContainerStyle, |
apps/mobile/src/features/threads/thread-search-match.tsx+16-14| ... | @@ -1,4 +1,3 @@ | ... | @@ -1,4 +1,3 @@ |
| 1 | import { Platform } from "react-native"; | ||
| 2 | import type { EnvironmentThreadSearchMatch } from "@t3tools/client-runtime/state/thread-search"; | 1 | import type { EnvironmentThreadSearchMatch } from "@t3tools/client-runtime/state/thread-search"; |
| 3 | 2 | ||
| 4 | import { AppText as Text } from "../../components/AppText"; | 3 | import { AppText as Text } from "../../components/AppText"; |
| ... | @@ -49,6 +48,7 @@ export function ThreadSearchMatchExcerpt(props: { | ... | @@ -49,6 +48,7 @@ export function ThreadSearchMatchExcerpt(props: { |
| 49 | readonly query: string; | 48 | readonly query: string; |
| 50 | readonly selected?: boolean; | 49 | readonly selected?: boolean; |
| 51 | readonly compact?: boolean; | 50 | readonly compact?: boolean; |
| 51 | readonly sidebar?: boolean; | ||
| 52 | }) { | 52 | }) { |
| 53 | const isUser = props.match.source === "user"; | 53 | const isUser = props.match.source === "user"; |
| 54 | const parts = splitHighlightParts(props.match.snippet, props.query); | 54 | const parts = splitHighlightParts(props.match.snippet, props.query); |
| ... | @@ -57,10 +57,10 @@ export function ThreadSearchMatchExcerpt(props: { | ... | @@ -57,10 +57,10 @@ export function ThreadSearchMatchExcerpt(props: { |
| 57 | className={cn( | 57 | className={cn( |
| 58 | props.compact ? "text-sm" : "text-xs", | 58 | props.compact ? "text-sm" : "text-xs", |
| 59 | props.selected | 59 | props.selected |
| 60 | ? Platform.OS === "android" | 60 | ? "text-thread-selected-foreground-muted" |
| 61 | ? "text-thread-selected-foreground-muted" | 61 | : props.sidebar |
| 62 | : "text-user-bubble-foreground-muted" | 62 | ? "text-drawer-foreground-muted" |
| 63 | : "text-foreground-muted", | 63 | : "text-foreground-muted", |
| 64 | )} | 64 | )} |
| 65 | numberOfLines={1} | 65 | numberOfLines={1} |
| 66 | > | 66 | > |
| ... | @@ -68,11 +68,11 @@ export function ThreadSearchMatchExcerpt(props: { | ... | @@ -68,11 +68,11 @@ export function ThreadSearchMatchExcerpt(props: { |
| 68 | className={cn( | 68 | className={cn( |
| 69 | props.compact ? "text-sm font-t3-medium" : "text-xs font-t3-medium", | 69 | props.compact ? "text-sm font-t3-medium" : "text-xs font-t3-medium", |
| 70 | props.selected | 70 | props.selected |
| 71 | ? Platform.OS === "android" | 71 | ? "text-thread-selected-foreground" |
| 72 | ? "text-thread-selected-foreground" | ||
| 73 | : "text-user-bubble-foreground" | ||
| 74 | : isUser | 72 | : isUser |
| 75 | ? "text-foreground-secondary" | 73 | ? props.sidebar |
| 74 | ? "text-drawer-foreground-muted" | ||
| 75 | : "text-foreground-secondary" | ||
| 76 | : "text-adaptive-emerald-600-400", | 76 | : "text-adaptive-emerald-600-400", |
| 77 | )} | 77 | )} |
| 78 | > | 78 | > |
| ... | @@ -84,12 +84,14 @@ export function ThreadSearchMatchExcerpt(props: { | ... | @@ -84,12 +84,14 @@ export function ThreadSearchMatchExcerpt(props: { |
| 84 | props.compact ? "text-sm" : "text-xs", | 84 | props.compact ? "text-sm" : "text-xs", |
| 85 | part.highlighted && "font-t3-bold", | 85 | part.highlighted && "font-t3-bold", |
| 86 | props.selected | 86 | props.selected |
| 87 | ? Platform.OS === "android" | 87 | ? "text-thread-selected-foreground" |
| 88 | ? "text-thread-selected-foreground" | ||
| 89 | : "text-user-bubble-foreground" | ||
| 90 | : part.highlighted | 88 | : part.highlighted |
| 91 | ? "text-foreground" | 89 | ? props.sidebar |
| 92 | : "text-foreground-muted", | 90 | ? "text-drawer-foreground" |
| 91 | : "text-foreground" | ||
| 92 | : props.sidebar | ||
| 93 | ? "text-drawer-foreground-muted" | ||
| 94 | : "text-foreground-muted", | ||
| 93 | )} | 95 | )} |
| 94 | key={part.start} | 96 | key={part.start} |
| 95 | > | 97 | > |
apps/mobile/src/features/threads/thread-work-log.tsx+3-3| ... | @@ -882,7 +882,7 @@ const ThreadWorkLogRow = memo(function ThreadWorkLogRow( | ... | @@ -882,7 +882,7 @@ const ThreadWorkLogRow = memo(function ThreadWorkLogRow( |
| 882 | entering={WORK_LOG_DETAIL_ENTER_TRANSITION} | 882 | entering={WORK_LOG_DETAIL_ENTER_TRANSITION} |
| 883 | exiting={WORK_LOG_DETAIL_EXIT_TRANSITION} | 883 | exiting={WORK_LOG_DETAIL_EXIT_TRANSITION} |
| 884 | layout={WORK_LOG_LAYOUT_TRANSITION} | 884 | layout={WORK_LOG_LAYOUT_TRANSITION} |
| 885 | className="ml-7 border-l border-adaptive-neutral-300-a60-white-a12 pb-1 pl-3 pt-0.5" | 885 | className="ml-7 border-l border-border pb-1 pl-3 pt-0.5" |
| 886 | > | 886 | > |
| 887 | {row.workEntry.questionAnswer ? ( | 887 | {row.workEntry.questionAnswer ? ( |
| 888 | <QuestionAnswerHistory | 888 | <QuestionAnswerHistory |
| ... | @@ -1037,7 +1037,7 @@ export const ThreadAgentSpawnCard = memo(function ThreadAgentSpawnCard(props: { | ... | @@ -1037,7 +1037,7 @@ export const ThreadAgentSpawnCard = memo(function ThreadAgentSpawnCard(props: { |
| 1037 | props.onToggle(); | 1037 | props.onToggle(); |
| 1038 | }} | 1038 | }} |
| 1039 | onLongPress={props.onCopy} | 1039 | onLongPress={props.onCopy} |
| 1040 | className="rounded-xl border border-adaptive-neutral-200-a80-white-a8 bg-card px-2.5 py-2 active:bg-subtle" | 1040 | className="rounded-xl border border-border-subtle bg-card px-2.5 py-2 active:bg-subtle" |
| 1041 | > | 1041 | > |
| 1042 | <View className="flex-row items-center gap-2"> | 1042 | <View className="flex-row items-center gap-2"> |
| 1043 | <View className="h-6 w-6 shrink-0 items-center justify-center"> | 1043 | <View className="h-6 w-6 shrink-0 items-center justify-center"> |
| ... | @@ -1094,7 +1094,7 @@ export const ThreadAgentSpawnCard = memo(function ThreadAgentSpawnCard(props: { | ... | @@ -1094,7 +1094,7 @@ export const ThreadAgentSpawnCard = memo(function ThreadAgentSpawnCard(props: { |
| 1094 | entering={WORK_LOG_DETAIL_ENTER_TRANSITION} | 1094 | entering={WORK_LOG_DETAIL_ENTER_TRANSITION} |
| 1095 | exiting={WORK_LOG_DETAIL_EXIT_TRANSITION} | 1095 | exiting={WORK_LOG_DETAIL_EXIT_TRANSITION} |
| 1096 | layout={WORK_LOG_LAYOUT_TRANSITION} | 1096 | layout={WORK_LOG_LAYOUT_TRANSITION} |
| 1097 | className="ml-8 mt-1.5 gap-1.5 border-l border-adaptive-neutral-300-a60-white-a12 pl-3" | 1097 | className="ml-8 mt-1.5 gap-1.5 border-l border-border pl-3" |
| 1098 | > | 1098 | > |
| 1099 | {summary.members.map((member) => ( | 1099 | {summary.members.map((member) => ( |
| 1100 | <View key={member.title} className="gap-px"> | 1100 | <View key={member.title} className="gap-px"> |
apps/mobile/src/features/threads/threadPresentation.ts+7-23| ... | @@ -12,10 +12,6 @@ export type ThreadStatusKind = | ... | @@ -12,10 +12,6 @@ export type ThreadStatusKind = |
| 12 | 12 | ||
| 13 | export interface ThreadStatusPresentation extends StatusTone { | 13 | export interface ThreadStatusPresentation extends StatusTone { |
| 14 | readonly kind: ThreadStatusKind; | 14 | readonly kind: ThreadStatusKind; |
| 15 | /** Foreground color for the leading status icon. */ | ||
| 16 | readonly iconColor: string; | ||
| 17 | /** Background color for the leading status icon circle. */ | ||
| 18 | readonly iconBackground: string; | ||
| 19 | /** Whether the indicator represents in-flight activity. */ | 15 | /** Whether the indicator represents in-flight activity. */ |
| 20 | readonly pulse: boolean; | 16 | readonly pulse: boolean; |
| 21 | } | 17 | } |
| ... | @@ -44,8 +40,6 @@ export function resolveThreadStatus( | ... | @@ -44,8 +40,6 @@ export function resolveThreadStatus( |
| 44 | label: "Needs Approval", | 40 | label: "Needs Approval", |
| 45 | pillClassName: "bg-warning", | 41 | pillClassName: "bg-warning", |
| 46 | textClassName: "text-warning-foreground", | 42 | textClassName: "text-warning-foreground", |
| 47 | iconColor: "#ff9f0a", | ||
| 48 | iconBackground: "rgba(255,159,10,0.22)", | ||
| 49 | pulse: false, | 43 | pulse: false, |
| 50 | }; | 44 | }; |
| 51 | } | 45 | } |
| ... | @@ -54,10 +48,8 @@ export function resolveThreadStatus( | ... | @@ -54,10 +48,8 @@ export function resolveThreadStatus( |
| 54 | return { | 48 | return { |
| 55 | kind: "awaiting-input", | 49 | kind: "awaiting-input", |
| 56 | label: "Awaiting Input", | 50 | label: "Awaiting Input", |
| 57 | pillClassName: "bg-primary/10", | 51 | pillClassName: "bg-adaptive-indigo-500-a12-a16", |
| 58 | textClassName: "text-foreground-secondary", | 52 | textClassName: "text-adaptive-indigo-600-300", |
| 59 | iconColor: "#5e5ce6", | ||
| 60 | iconBackground: "rgba(94,92,230,0.22)", | ||
| 61 | pulse: false, | 53 | pulse: false, |
| 62 | }; | 54 | }; |
| 63 | } | 55 | } |
| ... | @@ -66,10 +58,8 @@ export function resolveThreadStatus( | ... | @@ -66,10 +58,8 @@ export function resolveThreadStatus( |
| 66 | return { | 58 | return { |
| 67 | kind: "working", | 59 | kind: "working", |
| 68 | label: "Working", | 60 | label: "Working", |
| 69 | pillClassName: "bg-primary/10", | 61 | pillClassName: "bg-adaptive-sky-500-a12-a16", |
| 70 | textClassName: "text-adaptive-sky-600-400", | 62 | textClassName: "text-adaptive-sky-600-400", |
| 71 | iconColor: "#0a84ff", | ||
| 72 | iconBackground: "rgba(10,132,255,0.22)", | ||
| 73 | pulse: true, | 63 | pulse: true, |
| 74 | }; | 64 | }; |
| 75 | } | 65 | } |
| ... | @@ -78,10 +68,8 @@ export function resolveThreadStatus( | ... | @@ -78,10 +68,8 @@ export function resolveThreadStatus( |
| 78 | return { | 68 | return { |
| 79 | kind: "connecting", | 69 | kind: "connecting", |
| 80 | label: "Connecting", | 70 | label: "Connecting", |
| 81 | pillClassName: "bg-primary/10", | 71 | pillClassName: "bg-adaptive-sky-500-a12-a16", |
| 82 | textClassName: "text-foreground-secondary", | 72 | textClassName: "text-adaptive-sky-600-400", |
| 83 | iconColor: "#0a84ff", | ||
| 84 | iconBackground: "rgba(10,132,255,0.22)", | ||
| 85 | pulse: true, | 73 | pulse: true, |
| 86 | }; | 74 | }; |
| 87 | } | 75 | } |
| ... | @@ -92,8 +80,6 @@ export function resolveThreadStatus( | ... | @@ -92,8 +80,6 @@ export function resolveThreadStatus( |
| 92 | label: "Error", | 80 | label: "Error", |
| 93 | pillClassName: "bg-danger", | 81 | pillClassName: "bg-danger", |
| 94 | textClassName: "text-danger-foreground", | 82 | textClassName: "text-danger-foreground", |
| 95 | iconColor: "#ff453a", | ||
| 96 | iconBackground: "rgba(255,69,58,0.22)", | ||
| 97 | pulse: false, | 83 | pulse: false, |
| 98 | }; | 84 | }; |
| 99 | } | 85 | } |
| ... | @@ -106,10 +92,8 @@ export function resolveThreadStatus( | ... | @@ -106,10 +92,8 @@ export function resolveThreadStatus( |
| 106 | return { | 92 | return { |
| 107 | kind: "plan-ready", | 93 | kind: "plan-ready", |
| 108 | label: "Plan Ready", | 94 | label: "Plan Ready", |
| 109 | pillClassName: "bg-primary/10", | 95 | pillClassName: "bg-adaptive-violet-500-a12-a16", |
| 110 | textClassName: "text-foreground-secondary", | 96 | textClassName: "text-adaptive-violet-600-400", |
| 111 | iconColor: "#bf5af2", | ||
| 112 | iconBackground: "rgba(191,90,242,0.22)", | ||
| 113 | pulse: false, | 97 | pulse: false, |
| 114 | }; | 98 | }; |
| 115 | } | 99 | } |
apps/mobile/src/features/threads/worktree-setup-card.tsx+26-28| ... | @@ -72,7 +72,7 @@ export function WorktreeSetupCard(props: WorktreeSetupCardProps) { | ... | @@ -72,7 +72,7 @@ export function WorktreeSetupCard(props: WorktreeSetupCardProps) { |
| 72 | /> | 72 | /> |
| 73 | {!handedOff ? ( | 73 | {!handedOff ? ( |
| 74 | <Text | 74 | <Text |
| 75 | className="text-2xs text-adaptive-neutral-600-400" | 75 | className="text-2xs text-foreground-secondary" |
| 76 | style={{ fontVariant: ["tabular-nums"] }} | 76 | style={{ fontVariant: ["tabular-nums"] }} |
| 77 | > | 77 | > |
| 78 | {elapsed(snapshot.startedAt, snapshot.endedAt, now)} | 78 | {elapsed(snapshot.startedAt, snapshot.endedAt, now)} |
| ... | @@ -99,25 +99,21 @@ export function WorktreeSetupCard(props: WorktreeSetupCardProps) { | ... | @@ -99,25 +99,21 @@ export function WorktreeSetupCard(props: WorktreeSetupCardProps) { |
| 99 | {backgroundSetup ? ( | 99 | {backgroundSetup ? ( |
| 100 | <ActivityIndicator | 100 | <ActivityIndicator |
| 101 | size="small" | 101 | size="small" |
| 102 | colorClassName="accent-adaptive-neutral-500-400" | 102 | colorClassName="accent-icon-muted" |
| 103 | style={{ width: 12, height: 12, transform: [{ scale: 0.65 }] }} | 103 | style={{ width: 12, height: 12, transform: [{ scale: 0.65 }] }} |
| 104 | /> | 104 | /> |
| 105 | ) : failed ? ( | 105 | ) : failed ? ( |
| 106 | <SymbolView | 106 | <SymbolView |
| 107 | name="exclamationmark.circle" | 107 | name="exclamationmark.circle" |
| 108 | size={12} | 108 | size={12} |
| 109 | tintColorClassName="accent-adaptive-rose-700-300" | 109 | tintColorClassName="accent-danger-foreground" |
| 110 | /> | 110 | /> |
| 111 | ) : null} | 111 | ) : null} |
| 112 | <Text numberOfLines={1} className="shrink text-2xs text-adaptive-neutral-600-400"> | 112 | <Text numberOfLines={1} className="shrink text-2xs text-foreground-secondary"> |
| 113 | {backgroundSetup ? scriptName : "Details"} | 113 | {backgroundSetup ? scriptName : "Details"} |
| 114 | </Text> | 114 | </Text> |
| 115 | {!backgroundSetup ? ( | 115 | {!backgroundSetup ? ( |
| 116 | <SymbolView | 116 | <SymbolView name="chevron.right" size={10} tintColorClassName="accent-icon-muted" /> |
| 117 | name="chevron.right" | ||
| 118 | size={10} | ||
| 119 | tintColorClassName="accent-adaptive-neutral-500-400" | ||
| 120 | /> | ||
| 121 | ) : null} | 117 | ) : null} |
| 122 | </View> | 118 | </View> |
| 123 | </Pressable> | 119 | </Pressable> |
| ... | @@ -166,14 +162,19 @@ function HeaderLabel({ | ... | @@ -166,14 +162,19 @@ function HeaderLabel({ |
| 166 | failed?: boolean; | 162 | failed?: boolean; |
| 167 | }) { | 163 | }) { |
| 168 | return active ? ( | 164 | return active ? ( |
| 169 | <ShimmeringWorkContent icon="clock" iconSubtleColor="#737373" label={label} showIcon={false} /> | 165 | <ShimmeringWorkContent |
| 166 | icon="clock" | ||
| 167 | iconSubtleColor="transparent" | ||
| 168 | label={label} | ||
| 169 | showIcon={false} | ||
| 170 | /> | ||
| 170 | ) : ( | 171 | ) : ( |
| 171 | <Text | 172 | <Text |
| 172 | numberOfLines={1} | 173 | numberOfLines={1} |
| 173 | className={ | 174 | className={ |
| 174 | failed | 175 | failed |
| 175 | ? "flex-1 text-sm text-adaptive-rose-700-300" | 176 | ? "flex-1 text-sm text-danger-foreground" |
| 176 | : "flex-1 text-sm text-adaptive-neutral-600-400" | 177 | : "flex-1 text-sm text-foreground-secondary" |
| 177 | } | 178 | } |
| 178 | style={{ fontVariant: ["tabular-nums"] }} | 179 | style={{ fontVariant: ["tabular-nums"] }} |
| 179 | > | 180 | > |
| ... | @@ -232,7 +233,7 @@ function SetupDetailsSheet({ | ... | @@ -232,7 +233,7 @@ function SetupDetailsSheet({ |
| 232 | </View> | 233 | </View> |
| 233 | ))} | 234 | ))} |
| 234 | {snapshot.phase === "failed" && snapshot.error ? ( | 235 | {snapshot.phase === "failed" && snapshot.error ? ( |
| 235 | <Text selectable className="ml-8 mt-2 text-xs text-adaptive-rose-700-300"> | 236 | <Text selectable className="ml-8 mt-2 text-xs text-danger-foreground"> |
| 236 | {snapshot.error} | 237 | {snapshot.error} |
| 237 | </Text> | 238 | </Text> |
| 238 | ) : null} | 239 | ) : null} |
| ... | @@ -303,7 +304,7 @@ function StageRow({ | ... | @@ -303,7 +304,7 @@ function StageRow({ |
| 303 | {stage.status === "running" && animate ? ( | 304 | {stage.status === "running" && animate ? ( |
| 304 | <ActivityIndicator | 305 | <ActivityIndicator |
| 305 | size="small" | 306 | size="small" |
| 306 | colorClassName="accent-adaptive-neutral-500-400" | 307 | colorClassName="accent-icon-muted" |
| 307 | style={{ transform: [{ scale: 0.75 }] }} | 308 | style={{ transform: [{ scale: 0.75 }] }} |
| 308 | /> | 309 | /> |
| 309 | ) : ( | 310 | ) : ( |
| ... | @@ -312,10 +313,10 @@ function StageRow({ | ... | @@ -312,10 +313,10 @@ function StageRow({ |
| 312 | size={14} | 313 | size={14} |
| 313 | tintColorClassName={ | 314 | tintColorClassName={ |
| 314 | stage.status === "failed" | 315 | stage.status === "failed" |
| 315 | ? "accent-adaptive-rose-700-300" | 316 | ? "accent-danger-foreground" |
| 316 | : stage.status === "warning" | 317 | : stage.status === "warning" |
| 317 | ? "accent-warning-foreground" | 318 | ? "accent-warning-foreground" |
| 318 | : "accent-adaptive-neutral-500-400" | 319 | : "accent-icon-muted" |
| 319 | } | 320 | } |
| 320 | /> | 321 | /> |
| 321 | )} | 322 | )} |
| ... | @@ -323,7 +324,7 @@ function StageRow({ | ... | @@ -323,7 +324,7 @@ function StageRow({ |
| 323 | {stage.status === "running" && animate ? ( | 324 | {stage.status === "running" && animate ? ( |
| 324 | <ShimmeringWorkContent | 325 | <ShimmeringWorkContent |
| 325 | icon="clock" | 326 | icon="clock" |
| 326 | iconSubtleColor="#737373" | 327 | iconSubtleColor="transparent" |
| 327 | label={label} | 328 | label={label} |
| 328 | showIcon={false} | 329 | showIcon={false} |
| 329 | /> | 330 | /> |
| ... | @@ -332,24 +333,21 @@ function StageRow({ | ... | @@ -332,24 +333,21 @@ function StageRow({ |
| 332 | numberOfLines={1} | 333 | numberOfLines={1} |
| 333 | className={ | 334 | className={ |
| 334 | stage.status === "failed" | 335 | stage.status === "failed" |
| 335 | ? "flex-1 text-sm text-adaptive-rose-700-300" | 336 | ? "flex-1 text-sm text-danger-foreground" |
| 336 | : "flex-1 text-sm text-adaptive-neutral-600-400" | 337 | : "flex-1 text-sm text-foreground-secondary" |
| 337 | } | 338 | } |
| 338 | > | 339 | > |
| 339 | {label} | 340 | {label} |
| 340 | </Text> | 341 | </Text> |
| 341 | )} | 342 | )} |
| 342 | {detail ? ( | 343 | {detail ? ( |
| 343 | <Text | 344 | <Text numberOfLines={1} className="max-w-[25%] shrink text-2xs text-foreground-secondary"> |
| 344 | numberOfLines={1} | ||
| 345 | className="max-w-[25%] shrink text-2xs text-adaptive-neutral-600-400" | ||
| 346 | > | ||
| 347 | {detail} | 345 | {detail} |
| 348 | </Text> | 346 | </Text> |
| 349 | ) : null} | 347 | ) : null} |
| 350 | {stage.status !== "pending" && stage.status !== "skipped" ? ( | 348 | {stage.status !== "pending" && stage.status !== "skipped" ? ( |
| 351 | <Text | 349 | <Text |
| 352 | className="text-2xs text-adaptive-neutral-600-400" | 350 | className="text-2xs text-foreground-secondary" |
| 353 | style={{ fontVariant: ["tabular-nums"] }} | 351 | style={{ fontVariant: ["tabular-nums"] }} |
| 354 | > | 352 | > |
| 355 | {elapsed(stage.startedAt, stage.endedAt, now)} | 353 | {elapsed(stage.startedAt, stage.endedAt, now)} |
| ... | @@ -368,8 +366,8 @@ function OutputTail({ lines, failed }: { lines: ReadonlyArray<string>; failed: b | ... | @@ -368,8 +366,8 @@ function OutputTail({ lines, failed }: { lines: ReadonlyArray<string>; failed: b |
| 368 | accessibilityLabel="Setup script output" | 366 | accessibilityLabel="Setup script output" |
| 369 | className={ | 367 | className={ |
| 370 | failed | 368 | failed |
| 371 | ? "mb-2 ml-8 rounded-md border border-adaptive-rose-700-300/20 bg-adaptive-rose-50-950 px-3 py-2" | 369 | ? "mb-2 ml-8 rounded-md border border-danger-border bg-danger px-3 py-2" |
| 372 | : "mb-2 ml-8 rounded-md border border-border bg-adaptive-neutral-100-900 px-3 py-2" | 370 | : "mb-2 ml-8 rounded-md border border-border bg-card-alt px-3 py-2" |
| 373 | } | 371 | } |
| 374 | > | 372 | > |
| 375 | {OUTPUT_TAIL_SLOTS.map((slot) => ( | 373 | {OUTPUT_TAIL_SLOTS.map((slot) => ( |
| ... | @@ -379,8 +377,8 @@ function OutputTail({ lines, failed }: { lines: ReadonlyArray<string>; failed: b | ... | @@ -379,8 +377,8 @@ function OutputTail({ lines, failed }: { lines: ReadonlyArray<string>; failed: b |
| 379 | numberOfLines={1} | 377 | numberOfLines={1} |
| 380 | className={ | 378 | className={ |
| 381 | failed | 379 | failed |
| 382 | ? "text-2xs leading-5 text-adaptive-rose-700-300 ios:font-[family-name:Menlo] android:font-mono" | 380 | ? "text-2xs leading-5 text-danger-foreground ios:font-[family-name:Menlo] android:font-mono" |
| 383 | : "text-2xs leading-5 text-adaptive-neutral-600-400 ios:font-[family-name:Menlo] android:font-mono" | 381 | : "text-2xs leading-5 text-foreground-secondary ios:font-[family-name:Menlo] android:font-mono" |
| 384 | } | 382 | } |
| 385 | > | 383 | > |
| 386 | {lines[lines.length - OUTPUT_TAIL_SLOTS.length + slot] || "\u00a0"} | 384 | {lines[lines.length - OUTPUT_TAIL_SLOTS.length + slot] || "\u00a0"} |
apps/mobile/src/features/voice-input/ComposerDictationControl.tsx+1-1| ... | @@ -300,7 +300,7 @@ export function ComposerDictationStatus(props: { | ... | @@ -300,7 +300,7 @@ export function ComposerDictationStatus(props: { |
| 300 | <View className="relative h-11 min-w-0 flex-1 justify-center"> | 300 | <View className="relative h-11 min-w-0 flex-1 justify-center"> |
| 301 | {isError ? ( | 301 | {isError ? ( |
| 302 | <View className="min-w-0 flex-row items-center gap-1.5 px-2"> | 302 | <View className="min-w-0 flex-row items-center gap-1.5 px-2"> |
| 303 | <Text className="min-w-0 flex-1 text-sm text-red-400" numberOfLines={2}> | 303 | <Text className="min-w-0 flex-1 text-sm text-danger-foreground" numberOfLines={2}> |
| 304 | {props.presentation.statusLabel} | 304 | {props.presentation.statusLabel} |
| 305 | </Text> | 305 | </Text> |
| 306 | <Pressable | 306 | <Pressable |
apps/mobile/src/lib/materialYouTheme.android.ts+12| ... | @@ -36,12 +36,15 @@ export function materialYouPaletteToMobileThemeVariables( | ... | @@ -36,12 +36,15 @@ export function materialYouPaletteToMobileThemeVariables( |
| 36 | "--color-sheet": withAlpha(palette.surfaceContainerLow, 0.98), | 36 | "--color-sheet": withAlpha(palette.surfaceContainerLow, 0.98), |
| 37 | "--color-sheet-solid": palette.surfaceContainerLow, | 37 | "--color-sheet-solid": palette.surfaceContainerLow, |
| 38 | "--color-card": palette.surfaceContainer, | 38 | "--color-card": palette.surfaceContainer, |
| 39 | "--color-grouped-card": palette.surfaceContainer, | ||
| 39 | "--color-card-alt": palette.surfaceContainerHigh, | 40 | "--color-card-alt": palette.surfaceContainerHigh, |
| 40 | "--color-card-translucent": withAlpha(palette.surfaceContainer, 0.8), | 41 | "--color-card-translucent": withAlpha(palette.surfaceContainer, 0.8), |
| 41 | "--color-thread-canvas": palette.surfaceContainerLow, | 42 | "--color-thread-canvas": palette.surfaceContainerLow, |
| 42 | "--color-thread-selected": palette.surfaceContainer, | 43 | "--color-thread-selected": palette.surfaceContainer, |
| 43 | "--color-thread-selected-foreground": palette.onSurface, | 44 | "--color-thread-selected-foreground": palette.onSurface, |
| 44 | "--color-thread-selected-foreground-muted": palette.onSurfaceVariant, | 45 | "--color-thread-selected-foreground-muted": palette.onSurfaceVariant, |
| 46 | "--color-thread-hover": palette.surfaceContainerHigh, | ||
| 47 | "--color-row-hover": palette.surfaceContainerHigh, | ||
| 45 | "--color-composer-panel": withAlpha(palette.surfaceContainerLow, dark ? 0.92 : 0.88), | 48 | "--color-composer-panel": withAlpha(palette.surfaceContainerLow, dark ? 0.92 : 0.88), |
| 46 | "--color-composer-surface": withAlpha(palette.surfaceContainerHigh, dark ? 0.9 : 0.94), | 49 | "--color-composer-surface": withAlpha(palette.surfaceContainerHigh, dark ? 0.9 : 0.94), |
| 47 | "--color-composer-border": withAlpha(palette.outlineVariant, dark ? 0.34 : 0.46), | 50 | "--color-composer-border": withAlpha(palette.outlineVariant, dark ? 0.34 : 0.46), |
| ... | @@ -50,6 +53,7 @@ export function materialYouPaletteToMobileThemeVariables( | ... | @@ -50,6 +53,7 @@ export function materialYouPaletteToMobileThemeVariables( |
| 50 | "--color-foreground-muted": palette.onSurfaceVariant, | 53 | "--color-foreground-muted": palette.onSurfaceVariant, |
| 51 | "--color-foreground-tertiary": withAlpha(palette.onSurfaceVariant, 0.58), | 54 | "--color-foreground-tertiary": withAlpha(palette.onSurfaceVariant, 0.58), |
| 52 | "--color-border": withAlpha(palette.outlineVariant, dark ? 0.5 : 0.65), | 55 | "--color-border": withAlpha(palette.outlineVariant, dark ? 0.5 : 0.65), |
| 56 | "--color-focus": palette.primary, | ||
| 53 | "--color-border-subtle": withAlpha(palette.outlineVariant, dark ? 0.34 : 0.46), | 57 | "--color-border-subtle": withAlpha(palette.outlineVariant, dark ? 0.34 : 0.46), |
| 54 | "--color-separator": withAlpha(palette.outlineVariant, dark ? 0.24 : 0.34), | 58 | "--color-separator": withAlpha(palette.outlineVariant, dark ? 0.24 : 0.34), |
| 55 | "--color-subtle": withAlpha(palette.onSurface, 0.05), | 59 | "--color-subtle": withAlpha(palette.onSurface, 0.05), |
| ... | @@ -59,6 +63,7 @@ export function materialYouPaletteToMobileThemeVariables( | ... | @@ -59,6 +63,7 @@ export function materialYouPaletteToMobileThemeVariables( |
| 59 | "--color-inline-skill-foreground": palette.onTertiaryContainer, | 63 | "--color-inline-skill-foreground": palette.onTertiaryContainer, |
| 60 | "--color-primary": palette.primary, | 64 | "--color-primary": palette.primary, |
| 61 | "--color-primary-foreground": palette.onPrimary, | 65 | "--color-primary-foreground": palette.onPrimary, |
| 66 | "--color-primary-text": palette.primary, | ||
| 62 | "--color-primary-shadow": withAlpha(palette.scrim, dark ? 0.22 : 0.18), | 67 | "--color-primary-shadow": withAlpha(palette.scrim, dark ? 0.22 : 0.18), |
| 63 | "--color-secondary": palette.secondaryContainer, | 68 | "--color-secondary": palette.secondaryContainer, |
| 64 | "--color-secondary-foreground": palette.onSecondaryContainer, | 69 | "--color-secondary-foreground": palette.onSecondaryContainer, |
| ... | @@ -70,6 +75,8 @@ export function materialYouPaletteToMobileThemeVariables( | ... | @@ -70,6 +75,8 @@ export function materialYouPaletteToMobileThemeVariables( |
| 70 | "--color-danger": palette.errorContainer, | 75 | "--color-danger": palette.errorContainer, |
| 71 | "--color-danger-border": withAlpha(palette.onErrorContainer, dark ? 0.42 : 0.5), | 76 | "--color-danger-border": withAlpha(palette.onErrorContainer, dark ? 0.42 : 0.5), |
| 72 | "--color-danger-foreground": palette.onErrorContainer, | 77 | "--color-danger-foreground": palette.onErrorContainer, |
| 78 | "--color-update": palette.primaryContainer, | ||
| 79 | "--color-update-foreground": palette.onPrimaryContainer, | ||
| 73 | "--color-input": palette.surfaceContainerLowest, | 80 | "--color-input": palette.surfaceContainerLowest, |
| 74 | "--color-input-border": withAlpha(palette.outline, dark ? 0.42 : 0.5), | 81 | "--color-input-border": withAlpha(palette.outline, dark ? 0.42 : 0.5), |
| 75 | "--color-sidebar-search": palette.surfaceContainerLowest, | 82 | "--color-sidebar-search": palette.surfaceContainerLowest, |
| ... | @@ -78,8 +85,10 @@ export function materialYouPaletteToMobileThemeVariables( | ... | @@ -78,8 +85,10 @@ export function materialYouPaletteToMobileThemeVariables( |
| 78 | "--color-icon-muted": palette.onSurfaceVariant, | 85 | "--color-icon-muted": palette.onSurfaceVariant, |
| 79 | "--color-icon-subtle": withAlpha(palette.onSurfaceVariant, 0.68), | 86 | "--color-icon-subtle": withAlpha(palette.onSurfaceVariant, 0.68), |
| 80 | "--color-header": palette.surfaceContainerHigh, | 87 | "--color-header": palette.surfaceContainerHigh, |
| 88 | "--color-header-foreground": palette.onSurface, | ||
| 81 | "--color-header-border": withAlpha(palette.outlineVariant, dark ? 0.36 : 0.48), | 89 | "--color-header-border": withAlpha(palette.outlineVariant, dark ? 0.36 : 0.48), |
| 82 | "--color-glass-surface": withAlpha(palette.surfaceContainerHigh, dark ? 0.78 : 0.72), | 90 | "--color-glass-surface": withAlpha(palette.surfaceContainerHigh, dark ? 0.78 : 0.72), |
| 91 | "--color-glass-fallback": withAlpha(palette.surfaceContainerHigh, dark ? 0.9 : 0.94), | ||
| 83 | "--color-glass-tint": withAlpha(palette.primaryContainer, dark ? 0.24 : 0.18), | 92 | "--color-glass-tint": withAlpha(palette.primaryContainer, dark ? 0.24 : 0.18), |
| 84 | "--color-status-bar": palette.surfaceContainerLow, | 93 | "--color-status-bar": palette.surfaceContainerLow, |
| 85 | "--color-md-body": materialTone(palette.onSurfaceVariant, dark ? 90 : 10), | 94 | "--color-md-body": materialTone(palette.onSurfaceVariant, dark ? 90 : 10), |
| ... | @@ -100,6 +109,9 @@ export function materialYouPaletteToMobileThemeVariables( | ... | @@ -100,6 +109,9 @@ export function materialYouPaletteToMobileThemeVariables( |
| 100 | "--color-user-bubble-skill-foreground": userBubbleForeground, | 109 | "--color-user-bubble-skill-foreground": userBubbleForeground, |
| 101 | "--color-backdrop": withAlpha(palette.scrim, dark ? 0.48 : 0.22), | 110 | "--color-backdrop": withAlpha(palette.scrim, dark ? 0.48 : 0.22), |
| 102 | "--color-drawer": palette.surface, | 111 | "--color-drawer": palette.surface, |
| 112 | "--color-drawer-foreground": palette.onSurface, | ||
| 113 | "--color-drawer-foreground-muted": palette.onSurfaceVariant, | ||
| 114 | "--color-drawer-border": withAlpha(palette.outlineVariant, dark ? 0.36 : 0.48), | ||
| 103 | "--color-drawer-shadow": withAlpha(palette.scrim, dark ? 0.32 : 0.12), | 115 | "--color-drawer-shadow": withAlpha(palette.scrim, dark ? 0.32 : 0.12), |
| 104 | "--color-dot-separator": withAlpha(palette.onSurface, 0.2), | 116 | "--color-dot-separator": withAlpha(palette.onSurface, 0.2), |
| 105 | "--color-wordmark": palette.onSurface, | 117 | "--color-wordmark": palette.onSurface, |
apps/mobile/src/lib/materialYouTheme.test.ts+1| ... | @@ -54,6 +54,7 @@ describe("Material You system colors", () => { | ... | @@ -54,6 +54,7 @@ describe("Material You system colors", () => { |
| 54 | expect(variables["--color-thread-canvas"]).toBe(palette.surfaceContainerLow); | 54 | expect(variables["--color-thread-canvas"]).toBe(palette.surfaceContainerLow); |
| 55 | expect(variables["--color-thread-selected"]).toBe(palette.surfaceContainer); | 55 | expect(variables["--color-thread-selected"]).toBe(palette.surfaceContainer); |
| 56 | expect(variables["--color-header"]).toBe(palette.surfaceContainerHigh); | 56 | expect(variables["--color-header"]).toBe(palette.surfaceContainerHigh); |
| 57 | expect(variables["--color-grouped-card"]).toBe(palette.surfaceContainer); | ||
| 57 | expect(variables["--color-primary"]).toBe(palette.primary); | 58 | expect(variables["--color-primary"]).toBe(palette.primary); |
| 58 | expect(variables["--color-placeholder"]).toBe("#1C1B1F9E"); | 59 | expect(variables["--color-placeholder"]).toBe("#1C1B1F9E"); |
| 59 | }); | 60 | }); |
apps/mobile/src/lib/mobileTheme.test-support.ts+13-4| ... | @@ -1,20 +1,29 @@ | ... | @@ -1,20 +1,29 @@ |
| 1 | import * as NodeFS from "node:fs"; | 1 | import * as NodeFS from "node:fs"; |
| 2 | 2 | ||
| 3 | import type { MobileThemeAppearance, MobileThemeVariables } from "./mobileTheme"; | 3 | import { |
| 4 | MOBILE_THEME_VARIABLE_NAMES, | ||
| 5 | type MobileThemeAppearance, | ||
| 6 | type MobileThemeVariables, | ||
| 7 | } from "./mobileTheme"; | ||
| 4 | 8 | ||
| 5 | export function readDefaultMobileThemeVariables( | 9 | export function readDefaultMobileThemeVariables( |
| 6 | appearance: MobileThemeAppearance, | 10 | appearance: MobileThemeAppearance, |
| 7 | ): MobileThemeVariables { | 11 | ): MobileThemeVariables { |
| 8 | const stylesheet = NodeFS.readFileSync(new URL("../../global.css", import.meta.url), "utf8"); | 12 | const stylesheet = NodeFS.readFileSync( |
| 13 | new URL("../../generated-uniwind-themes.css", import.meta.url), | ||
| 14 | "utf8", | ||
| 15 | ); | ||
| 9 | const variant = new RegExp(`@variant ${appearance} \\{([\\s\\S]*?)\\n \\}`, "u").exec( | 16 | const variant = new RegExp(`@variant ${appearance} \\{([\\s\\S]*?)\\n \\}`, "u").exec( |
| 10 | stylesheet, | 17 | stylesheet, |
| 11 | )?.[1]; | 18 | )?.[1]; |
| 12 | if (variant === undefined) throw new Error(`Missing default ${appearance} theme in global.css.`); | 19 | if (variant === undefined) throw new Error(`Missing generated default ${appearance} theme.`); |
| 13 | 20 | ||
| 14 | return Object.fromEntries( | 21 | return Object.fromEntries( |
| 15 | Array.from(variant.matchAll(/(--color-[a-z0-9-]+):\s*([^;]+);/gu), ([, name, value]) => [ | 22 | Array.from(variant.matchAll(/(--color-[a-z0-9-]+):\s*([^;]+);/gu), ([, name, value]) => [ |
| 16 | name, | 23 | name, |
| 17 | (value ?? "").trim(), | 24 | (value ?? "").trim(), |
| 18 | ]), | 25 | ]).filter(([name]) => |
| 26 | MOBILE_THEME_VARIABLE_NAMES.includes(name as (typeof MOBILE_THEME_VARIABLE_NAMES)[number]), | ||
| 27 | ), | ||
| 19 | ) as MobileThemeVariables; | 28 | ) as MobileThemeVariables; |
| 20 | } | 29 | } |
apps/mobile/src/lib/mobileTheme.test.ts+147-10| ... | @@ -1,12 +1,22 @@ | ... | @@ -1,12 +1,22 @@ |
| 1 | import { describe, expect, it } from "vite-plus/test"; | 1 | import { describe, expect, it } from "vite-plus/test"; |
| 2 | import { BUILT_IN_THEME_IDS, BUILT_IN_THEMES, T3_CHAT_THEME } from "@t3tools/shared/themePalettes"; | 2 | import { |
| 3 | BUILT_IN_THEME_IDS, | ||
| 4 | BUILT_IN_THEMES, | ||
| 5 | T3_CHAT_THEME, | ||
| 6 | T3_CODE_LIGHT_THEME_COLORS, | ||
| 7 | T3_CODE_DARK_THEME_COLORS, | ||
| 8 | MOBILE_THEME_IDS, | ||
| 9 | getThemeColorsForAppearance, | ||
| 10 | } from "@t3tools/shared/themePalettes"; | ||
| 3 | import { readDefaultMobileThemeVariables } from "./mobileTheme.test-support"; | 11 | import { readDefaultMobileThemeVariables } from "./mobileTheme.test-support"; |
| 12 | import { getMobileThemeRuntimeVariables } from "./mobileThemeVariables"; | ||
| 4 | 13 | ||
| 5 | import { | 14 | import { |
| 6 | createMobileThemePairPatch, | 15 | createMobileThemePairPatch, |
| 7 | createMobileThemeSelectionPatch, | 16 | createMobileThemeSelectionPatch, |
| 8 | createMobileThemeVariables, | 17 | createMobileThemeVariables, |
| 9 | DEFAULT_MOBILE_THEME_ID, | 18 | DEFAULT_MOBILE_THEME_ID, |
| 19 | flattenThemeColor, | ||
| 10 | getMobileThemePreviewColors, | 20 | getMobileThemePreviewColors, |
| 11 | getMobileThemeVariables, | 21 | getMobileThemeVariables, |
| 12 | normalizeMobileThemeId, | 22 | normalizeMobileThemeId, |
| ... | @@ -66,12 +76,86 @@ describe("mobile themes", () => { | ... | @@ -66,12 +76,86 @@ describe("mobile themes", () => { |
| 66 | } | 76 | } |
| 67 | }); | 77 | }); |
| 68 | 78 | ||
| 69 | it("preserves the existing mobile palette as the default", () => { | 79 | it.each(MOBILE_THEME_IDS)("uses the web color roles for %s in both appearances", (themeId) => { |
| 70 | expect(readDefaultMobileThemeVariables("light")["--color-screen"]).toBe("#f2f2f7"); | 80 | for (const appearance of ["light", "dark"] as const) { |
| 71 | expect(readDefaultMobileThemeVariables("dark")["--color-screen"]).toBe("#0a0a0a"); | 81 | const theme = BUILT_IN_THEMES.find((candidate) => candidate.id === themeId); |
| 72 | expect(readDefaultMobileThemeVariables("light")["--color-user-bubble-skill-foreground"]).toBe( | 82 | const colors = theme |
| 73 | "#2563eb", | 83 | ? getThemeColorsForAppearance(theme, appearance)! |
| 74 | ); | 84 | : appearance === "dark" |
| 85 | ? T3_CODE_DARK_THEME_COLORS | ||
| 86 | : T3_CODE_LIGHT_THEME_COLORS; | ||
| 87 | const variables = | ||
| 88 | themeId === DEFAULT_MOBILE_THEME_ID | ||
| 89 | ? readDefaultMobileThemeVariables(appearance) | ||
| 90 | : getMobileThemeVariables(themeId, appearance); | ||
| 91 | expect(variables["--color-screen"]).toBe(themeColorToNativeColor(colors.canvas)); | ||
| 92 | expect(variables["--color-thread-canvas"]).toBe(variables["--color-screen"]); | ||
| 93 | expect(variables["--color-drawer"]).toBe(themeColorToNativeColor(colors.sidebar)); | ||
| 94 | expect(variables["--color-thread-hover"]).toBe( | ||
| 95 | themeColorToNativeColor(colors.sidebarRowHover), | ||
| 96 | ); | ||
| 97 | expect(variables["--color-card"]).toBe(themeColorToNativeColor(colors.surface)); | ||
| 98 | expect(variables["--color-composer-surface"]).toBe( | ||
| 99 | themeColorWithAlpha( | ||
| 100 | themeId === DEFAULT_MOBILE_THEME_ID | ||
| 101 | ? variables["--color-grouped-card"] | ||
| 102 | : themeColorToNativeColor(colors.surface), | ||
| 103 | appearance === "dark" ? 0.9 : 0.94, | ||
| 104 | ), | ||
| 105 | ); | ||
| 106 | expect(variables["--color-thread-selected"]).toBe( | ||
| 107 | themeColorToNativeColor(colors.sidebarRowActive), | ||
| 108 | ); | ||
| 109 | expect(variables["--color-thread-selected-foreground"]).toBe( | ||
| 110 | themeColorToNativeColor(colors.sidebarForeground), | ||
| 111 | ); | ||
| 112 | expect(variables["--color-primary"]).toBe(themeColorToNativeColor(colors.messageAction)); | ||
| 113 | if (themeId !== DEFAULT_MOBILE_THEME_ID) { | ||
| 114 | expect(variables["--color-user-bubble"]).toBe( | ||
| 115 | themeColorToNativeColor(colors.messageSurface), | ||
| 116 | ); | ||
| 117 | } | ||
| 118 | expect( | ||
| 119 | contrastRatio(variables["--color-foreground"], variables["--color-screen"]), | ||
| 120 | ).toBeGreaterThanOrEqual(4.5); | ||
| 121 | for (const [foreground, surface] of [ | ||
| 122 | ["--color-drawer-foreground", "--color-drawer"], | ||
| 123 | ["--color-drawer-foreground-muted", "--color-drawer"], | ||
| 124 | ["--color-drawer-foreground", "--color-thread-hover"], | ||
| 125 | ["--color-drawer-foreground-muted", "--color-thread-hover"], | ||
| 126 | ["--color-thread-selected-foreground-muted", "--color-thread-selected"], | ||
| 127 | ["--color-primary-foreground", "--color-primary"], | ||
| 128 | ["--color-primary-text", "--color-screen"], | ||
| 129 | ["--color-primary-text", "--color-card"], | ||
| 130 | ["--color-primary-text", "--color-card-alt"], | ||
| 131 | ["--color-primary-text", "--color-sheet-solid"], | ||
| 132 | ["--color-foreground", "--color-sheet-solid"], | ||
| 133 | ["--color-foreground-muted", "--color-sheet-solid"], | ||
| 134 | ["--color-primary-text", "--color-grouped-card"], | ||
| 135 | ["--color-foreground", "--color-grouped-card"], | ||
| 136 | ["--color-foreground-muted", "--color-grouped-card"], | ||
| 137 | ["--color-placeholder", "--color-grouped-card"], | ||
| 138 | ["--color-secondary-foreground", "--color-secondary"], | ||
| 139 | ["--color-user-bubble-foreground", "--color-user-bubble"], | ||
| 140 | ["--color-warning-foreground", "--color-warning"], | ||
| 141 | ["--color-danger-foreground", "--color-danger"], | ||
| 142 | ["--color-md-body", "--color-screen"], | ||
| 143 | ["--color-md-strong", "--color-screen"], | ||
| 144 | ["--color-md-link", "--color-screen"], | ||
| 145 | ["--color-md-code-text", "--color-md-code-bg"], | ||
| 146 | ] as const) { | ||
| 147 | expect( | ||
| 148 | contrastRatio(variables[foreground], variables[surface]), | ||
| 149 | `${appearance}: ${foreground} on ${surface}`, | ||
| 150 | ).toBeGreaterThanOrEqual(4.5); | ||
| 151 | } | ||
| 152 | expect( | ||
| 153 | contrastRatio( | ||
| 154 | variables["--color-thread-selected-foreground"], | ||
| 155 | variables["--color-thread-selected"], | ||
| 156 | ), | ||
| 157 | ).toBeGreaterThanOrEqual(4.5); | ||
| 158 | } | ||
| 75 | }); | 159 | }); |
| 76 | 160 | ||
| 77 | it("applies palette overrides on top of the selected built-in theme", () => { | 161 | it("applies palette overrides on top of the selected built-in theme", () => { |
| ... | @@ -83,6 +167,62 @@ describe("mobile themes", () => { | ... | @@ -83,6 +167,62 @@ describe("mobile themes", () => { |
| 83 | expect(variables["--color-screen"]).toMatch(/^#/); | 167 | expect(variables["--color-screen"]).toMatch(/^#/); |
| 84 | }); | 168 | }); |
| 85 | 169 | ||
| 170 | it.each(["light", "dark"] as const)( | ||
| 171 | "separates default settings groups from their %s background", | ||
| 172 | (appearance) => { | ||
| 173 | const variables = getMobileThemeVariables("t3-code", appearance); | ||
| 174 | expect( | ||
| 175 | contrastRatio(variables["--color-grouped-card"], variables["--color-sheet-solid"]), | ||
| 176 | ).toBeGreaterThanOrEqual(1.06); | ||
| 177 | expect(variables["--color-grouped-card"]).not.toBe(variables["--color-card"]); | ||
| 178 | for (const platform of ["ios", "android"]) { | ||
| 179 | const runtime = getMobileThemeRuntimeVariables("t3-code", appearance, platform); | ||
| 180 | const sidebar = flattenThemeColor(runtime["--color-drawer"], runtime["--color-screen"]); | ||
| 181 | const chrome = flattenThemeColor( | ||
| 182 | runtime[platform === "android" ? "--color-header" : "--color-drawer"], | ||
| 183 | runtime["--color-screen"], | ||
| 184 | ); | ||
| 185 | expect(relativeLuminance(sidebar)).toBeLessThan( | ||
| 186 | relativeLuminance(runtime["--color-thread-canvas"]), | ||
| 187 | ); | ||
| 188 | expect(contrastRatio(chrome, runtime["--color-screen"])).toBeGreaterThanOrEqual(1.06); | ||
| 189 | const foregroundRoles = | ||
| 190 | platform === "android" | ||
| 191 | ? (["--color-header-foreground", "--color-foreground-muted"] as const) | ||
| 192 | : (["--color-drawer-foreground", "--color-drawer-foreground-muted"] as const); | ||
| 193 | for (const role of foregroundRoles) { | ||
| 194 | expect(contrastRatio(runtime[role], chrome)).toBeGreaterThanOrEqual(4.5); | ||
| 195 | } | ||
| 196 | } | ||
| 197 | }, | ||
| 198 | ); | ||
| 199 | |||
| 200 | it.each(["light", "dark"] as const)( | ||
| 201 | "slightly strengthens default %s messages and separates fallback materials", | ||
| 202 | (appearance) => { | ||
| 203 | const variables = getMobileThemeVariables("t3-code", appearance); | ||
| 204 | const desktop = | ||
| 205 | appearance === "dark" ? T3_CODE_DARK_THEME_COLORS : T3_CODE_LIGHT_THEME_COLORS; | ||
| 206 | const bubbleContrast = contrastRatio( | ||
| 207 | variables["--color-user-bubble"], | ||
| 208 | variables["--color-screen"], | ||
| 209 | ); | ||
| 210 | expect(bubbleContrast).toBeGreaterThan(contrastRatio(desktop.messageSurface, desktop.canvas)); | ||
| 211 | expect(bubbleContrast).toBeLessThan(1.2); | ||
| 212 | for (const role of ["--color-composer-surface", "--color-glass-fallback"] as const) { | ||
| 213 | const surface = flattenThemeColor(variables[role], variables["--color-screen"]); | ||
| 214 | expect(contrastRatio(surface, variables["--color-screen"])).toBeGreaterThanOrEqual(1.06); | ||
| 215 | for (const foreground of [ | ||
| 216 | "--color-foreground", | ||
| 217 | "--color-placeholder", | ||
| 218 | "--color-primary-text", | ||
| 219 | ] as const) { | ||
| 220 | expect(contrastRatio(variables[foreground], surface)).toBeGreaterThanOrEqual(4.5); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | }, | ||
| 224 | ); | ||
| 225 | |||
| 86 | it("uses the same preview roles and standard artwork as desktop", () => { | 226 | it("uses the same preview roles and standard artwork as desktop", () => { |
| 87 | expect(getMobileThemePreviewColors(DEFAULT_MOBILE_THEME_ID, "light")).toEqual({ | 227 | expect(getMobileThemePreviewColors(DEFAULT_MOBILE_THEME_ID, "light")).toEqual({ |
| 88 | canvas: "#fcfcfc", | 228 | canvas: "#fcfcfc", |
| ... | @@ -153,7 +293,6 @@ describe("mobile themes", () => { | ... | @@ -153,7 +293,6 @@ describe("mobile themes", () => { |
| 153 | 293 | ||
| 154 | it("maps semantic palette roles onto every mobile color variable", () => { | 294 | it("maps semantic palette roles onto every mobile color variable", () => { |
| 155 | const variables = createMobileThemeVariables(T3_CHAT_THEME.colors, "light"); | 295 | const variables = createMobileThemeVariables(T3_CHAT_THEME.colors, "light"); |
| 156 | expect(Object.keys(variables)).toHaveLength(75); | ||
| 157 | expect(variables["--color-sheet-solid"]).toBe( | 296 | expect(variables["--color-sheet-solid"]).toBe( |
| 158 | themeColorToNativeColor(T3_CHAT_THEME.colors.chrome), | 297 | themeColorToNativeColor(T3_CHAT_THEME.colors.chrome), |
| 159 | ); | 298 | ); |
| ... | @@ -219,8 +358,6 @@ describe("mobile themes", () => { | ... | @@ -219,8 +358,6 @@ describe("mobile themes", () => { |
| 219 | } | 358 | } |
| 220 | }); | 359 | }); |
| 221 | 360 | ||
| 222 | // The default palette lives in global.css rather than BUILT_IN_THEMES, so the loops above | ||
| 223 | // never reached it; it kept an unreadable hardcoded bubble until this covered it. | ||
| 224 | it("keeps the default user bubble readable in both appearances", () => { | 361 | it("keeps the default user bubble readable in both appearances", () => { |
| 225 | for (const appearance of ["light", "dark"] as const) { | 362 | for (const appearance of ["light", "dark"] as const) { |
| 226 | const variables = readDefaultMobileThemeVariables(appearance); | 363 | const variables = readDefaultMobileThemeVariables(appearance); |
apps/mobile/src/lib/mobileTheme.ts+106-43| ... | @@ -1,10 +1,11 @@ | ... | @@ -1,10 +1,11 @@ |
| 1 | import { | 1 | import { |
| 2 | BUILT_IN_THEMES, | 2 | BUILT_IN_THEMES, |
| 3 | T3_CHAT_THEME, | 3 | T3_CHAT_THEME, |
| 4 | T3_CODE_LIGHT_THEME_COLORS, | ||
| 5 | T3_CODE_DARK_THEME_COLORS, | ||
| 4 | getThemeColorsForAppearance, | 6 | getThemeColorsForAppearance, |
| 5 | MOBILE_DEFAULT_THEME_ID, | 7 | MOBILE_DEFAULT_THEME_ID, |
| 6 | MOBILE_THEME_IDS as SHARED_MOBILE_THEME_IDS, | 8 | MOBILE_THEME_IDS as SHARED_MOBILE_THEME_IDS, |
| 7 | type BuiltInThemeId, | ||
| 8 | type MobileThemeId as SharedMobileThemeId, | 9 | type MobileThemeId as SharedMobileThemeId, |
| 9 | type ThemeAppearance, | 10 | type ThemeAppearance, |
| 10 | type ThemeColors, | 11 | type ThemeColors, |
| ... | @@ -138,7 +139,7 @@ function withAlpha(color: string, alpha: number): string { | ... | @@ -138,7 +139,7 @@ function withAlpha(color: string, alpha: number): string { |
| 138 | } | 139 | } |
| 139 | 140 | ||
| 140 | function rgbChannels(color: string): readonly [number, number, number] | null { | 141 | function rgbChannels(color: string): readonly [number, number, number] | null { |
| 141 | const match = /^#([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i.exec(color); | 142 | const match = /^#([\da-f]{2})([\da-f]{2})([\da-f]{2})(?:[\da-f]{2})?$/i.exec(color); |
| 142 | if (!match) return null; | 143 | if (!match) return null; |
| 143 | const [, red = "0", green = "0", blue = "0"] = match; | 144 | const [, red = "0", green = "0", blue = "0"] = match; |
| 144 | return [Number.parseInt(red, 16), Number.parseInt(green, 16), Number.parseInt(blue, 16)]; | 145 | return [Number.parseInt(red, 16), Number.parseInt(green, 16), Number.parseInt(blue, 16)]; |
| ... | @@ -150,6 +151,14 @@ function rgbChannels(color: string): readonly [number, number, number] | null { | ... | @@ -150,6 +151,14 @@ function rgbChannels(color: string): readonly [number, number, number] | null { |
| 150 | * colour asked for — so a translucent role like `--color-border` has to be flattened first. | 151 | * colour asked for — so a translucent role like `--color-border` has to be flattened first. |
| 151 | */ | 152 | */ |
| 152 | export function flattenThemeColor(color: string, surface: string): string { | 153 | export function flattenThemeColor(color: string, surface: string): string { |
| 154 | const alphaHex = /^#([\da-f]{6})([\da-f]{2})$/i.exec(color); | ||
| 155 | if (alphaHex) { | ||
| 156 | const channels = rgbChannels(color)!; | ||
| 157 | return flattenThemeColor( | ||
| 158 | `rgba(${channels[0]}, ${channels[1]}, ${channels[2]}, ${Number.parseInt(alphaHex[2]!, 16) / 255})`, | ||
| 159 | surface, | ||
| 160 | ); | ||
| 161 | } | ||
| 153 | const match = /^rgba?\(\s*(\d+)[,\s]+(\d+)[,\s]+(\d+)(?:[,\s/]+([\d.]+))?\s*\)$/i.exec( | 162 | const match = /^rgba?\(\s*(\d+)[,\s]+(\d+)[,\s]+(\d+)(?:[,\s/]+([\d.]+))?\s*\)$/i.exec( |
| 154 | color.trim(), | 163 | color.trim(), |
| 155 | ); | 164 | ); |
| ... | @@ -182,22 +191,21 @@ function contrastRatio( | ... | @@ -182,22 +191,21 @@ function contrastRatio( |
| 182 | ); | 191 | ); |
| 183 | } | 192 | } |
| 184 | 193 | ||
| 185 | /** Preserve the theme's action hue while making it readable as skill text on a message bubble. */ | 194 | /** Preserve the color's hue while giving text 4.5:1 contrast on every supplied surface. */ |
| 186 | function readableMessageAccent(accent: string, surface: string): string { | 195 | function readableTextColor(accent: string, surface: string | ReadonlyArray<string>): string { |
| 187 | const accentChannels = rgbChannels(accent); | 196 | const accentChannels = rgbChannels(accent); |
| 188 | const surfaceChannels = rgbChannels(surface); | 197 | const surfaceChannels = (typeof surface === "string" ? [surface] : surface) |
| 189 | if ( | 198 | .map(rgbChannels) |
| 190 | !accentChannels || | 199 | .filter((channels) => channels !== null); |
| 191 | !surfaceChannels || | 200 | const minimumContrast = (channels: readonly [number, number, number]) => |
| 192 | contrastRatio(accentChannels, surfaceChannels) >= 4.5 | 201 | Math.min(...surfaceChannels.map((surface) => contrastRatio(channels, surface))); |
| 193 | ) { | 202 | if (!accentChannels || surfaceChannels.length === 0 || minimumContrast(accentChannels) >= 4.5) { |
| 194 | return accent; | 203 | return accent; |
| 195 | } | 204 | } |
| 196 | 205 | ||
| 197 | const black = [0, 0, 0] as const; | 206 | const black = [0, 0, 0] as const; |
| 198 | const white = [255, 255, 255] as const; | 207 | const white = [255, 255, 255] as const; |
| 199 | const target = | 208 | const target = minimumContrast(black) >= minimumContrast(white) ? black : white; |
| 200 | contrastRatio(black, surfaceChannels) >= contrastRatio(white, surfaceChannels) ? black : white; | ||
| 201 | let readable: readonly [number, number, number] = target; | 209 | let readable: readonly [number, number, number] = target; |
| 202 | let lowerAmount = 0; | 210 | let lowerAmount = 0; |
| 203 | let upperAmount = 1; | 211 | let upperAmount = 1; |
| ... | @@ -208,7 +216,7 @@ function readableMessageAccent(accent: string, surface: string): string { | ... | @@ -208,7 +216,7 @@ function readableMessageAccent(accent: string, surface: string): string { |
| 208 | Math.round(accentChannels[1] + (target[1] - accentChannels[1]) * amount), | 216 | Math.round(accentChannels[1] + (target[1] - accentChannels[1]) * amount), |
| 209 | Math.round(accentChannels[2] + (target[2] - accentChannels[2]) * amount), | 217 | Math.round(accentChannels[2] + (target[2] - accentChannels[2]) * amount), |
| 210 | ]; | 218 | ]; |
| 211 | if (contrastRatio(candidate, surfaceChannels) >= 4.5) { | 219 | if (minimumContrast(candidate) >= 4.5) { |
| 212 | readable = candidate; | 220 | readable = candidate; |
| 213 | upperAmount = amount; | 221 | upperAmount = amount; |
| 214 | } else { | 222 | } else { |
| ... | @@ -227,30 +235,46 @@ export function themeColorWithAlpha(color: string, alpha: number): string { | ... | @@ -227,30 +235,46 @@ export function themeColorWithAlpha(color: string, alpha: number): string { |
| 227 | return rgb ? `rgba(${rgb[1]}, ${rgb[2]}, ${rgb[3]}, ${alpha})` : color; | 235 | return rgb ? `rgba(${rgb[1]}, ${rgb[2]}, ${rgb[3]}, ${alpha})` : color; |
| 228 | } | 236 | } |
| 229 | 237 | ||
| 230 | export function createMobileThemeVariables(colors: ThemeColors, appearance: MobileThemeAppearance) { | 238 | export function createMobileThemeVariables( |
| 239 | colors: ThemeColors, | ||
| 240 | appearance: MobileThemeAppearance, | ||
| 241 | groupedCardColor = colors.surface, | ||
| 242 | ) { | ||
| 231 | const c = nativeColors(colors); | 243 | const c = nativeColors(colors); |
| 244 | const groupedCard = themeColorToNativeColor(groupedCardColor); | ||
| 245 | const textSurfaces = [c.canvas, c.surface, c.surfaceRaised, c.chrome, groupedCard]; | ||
| 232 | return { | 246 | return { |
| 233 | "--color-screen": c.canvas, | 247 | "--color-screen": c.canvas, |
| 234 | "--color-sheet": withAlpha(c.chrome, 0.98), | 248 | "--color-sheet": withAlpha(c.chrome, 0.98), |
| 235 | "--color-sheet-solid": c.chrome, | 249 | "--color-sheet-solid": c.chrome, |
| 236 | "--color-card": c.surfaceRaised, | 250 | "--color-card": c.surface, |
| 237 | "--color-card-alt": c.surface, | 251 | "--color-grouped-card": groupedCard, |
| 238 | "--color-card-translucent": withAlpha(c.surfaceRaised, 0.8), | 252 | "--color-card-alt": c.surfaceRaised, |
| 239 | "--color-thread-canvas": c.surface, | 253 | "--color-card-translucent": withAlpha(c.surface, 0.8), |
| 240 | "--color-thread-selected": c.surfaceRaised, | 254 | "--color-thread-canvas": c.canvas, |
| 241 | "--color-thread-selected-foreground": c.text, | 255 | "--color-thread-selected": c.sidebarRowActive, |
| 242 | "--color-thread-selected-foreground-muted": c.textMuted, | 256 | "--color-thread-selected-foreground": c.sidebarForeground, |
| 243 | "--color-composer-panel": themeColorWithAlpha(c.surface, appearance === "dark" ? 0.92 : 0.88), | 257 | "--color-thread-selected-foreground-muted": readableTextColor( |
| 258 | c.sidebarMutedForeground, | ||
| 259 | c.sidebarRowActive, | ||
| 260 | ), | ||
| 261 | "--color-thread-hover": c.sidebarRowHover, | ||
| 262 | "--color-row-hover": c.toolbarControlHover, | ||
| 263 | "--color-composer-panel": themeColorWithAlpha(c.canvas, appearance === "dark" ? 0.92 : 0.88), | ||
| 244 | "--color-composer-surface": themeColorWithAlpha( | 264 | "--color-composer-surface": themeColorWithAlpha( |
| 245 | c.surfaceRaised, | 265 | groupedCard, |
| 246 | appearance === "dark" ? 0.9 : 0.94, | 266 | appearance === "dark" ? 0.9 : 0.94, |
| 247 | ), | 267 | ), |
| 248 | "--color-composer-border": themeColorWithAlpha(c.border, appearance === "dark" ? 0.46 : 0.54), | 268 | "--color-composer-border": themeColorWithAlpha( |
| 269 | c.border, | ||
| 270 | groupedCard === c.surface ? (appearance === "dark" ? 0.46 : 0.54) : 0.8, | ||
| 271 | ), | ||
| 249 | "--color-foreground": c.text, | 272 | "--color-foreground": c.text, |
| 250 | "--color-foreground-secondary": c.textMuted, | 273 | "--color-foreground-secondary": readableTextColor(c.textMuted, textSurfaces), |
| 251 | "--color-foreground-muted": c.mutedForeground, | 274 | "--color-foreground-muted": readableTextColor(c.mutedForeground, textSurfaces), |
| 252 | "--color-foreground-tertiary": c.secondaryLabel, | 275 | "--color-foreground-tertiary": c.secondaryLabel, |
| 253 | "--color-border": c.border, | 276 | "--color-border": c.border, |
| 277 | "--color-focus": c.focus, | ||
| 254 | "--color-border-subtle": withAlpha(c.border, 0.7), | 278 | "--color-border-subtle": withAlpha(c.border, 0.7), |
| 255 | "--color-separator": withAlpha(c.border, 0.55), | 279 | "--color-separator": withAlpha(c.border, 0.55), |
| 256 | "--color-subtle": c.muted, | 280 | "--color-subtle": c.muted, |
| ... | @@ -258,14 +282,15 @@ export function createMobileThemeVariables(colors: ThemeColors, appearance: Mobi | ... | @@ -258,14 +282,15 @@ export function createMobileThemeVariables(colors: ThemeColors, appearance: Mobi |
| 258 | "--color-inline-skill-background": c.accentSurface, | 282 | "--color-inline-skill-background": c.accentSurface, |
| 259 | "--color-inline-skill-border": withAlpha(c.accent, 0.42), | 283 | "--color-inline-skill-border": withAlpha(c.accent, 0.42), |
| 260 | "--color-inline-skill-foreground": c.accentSurfaceForeground, | 284 | "--color-inline-skill-foreground": c.accentSurfaceForeground, |
| 261 | "--color-primary": c.accent, | 285 | "--color-primary": c.messageAction, |
| 262 | "--color-primary-foreground": c.accentForeground, | 286 | "--color-primary-foreground": c.messageActionForeground, |
| 287 | "--color-primary-text": readableTextColor(c.messageAction, textSurfaces), | ||
| 263 | "--color-primary-shadow": "#000000", | 288 | "--color-primary-shadow": "#000000", |
| 264 | "--color-secondary": c.secondary, | 289 | "--color-secondary": c.secondary, |
| 265 | "--color-secondary-foreground": c.secondaryForeground, | 290 | "--color-secondary-foreground": c.secondaryForeground, |
| 266 | "--color-secondary-border": c.border, | 291 | "--color-secondary-border": c.border, |
| 267 | "--color-switch-active-track": c.accent, | 292 | "--color-switch-active-track": c.messageAction, |
| 268 | "--color-switch-active-thumb": c.accentForeground, | 293 | "--color-switch-active-thumb": c.messageActionForeground, |
| 269 | "--color-switch-inactive-track": c.secondary, | 294 | "--color-switch-inactive-track": c.secondary, |
| 270 | "--color-switch-inactive-thumb": c.mutedForeground, | 295 | "--color-switch-inactive-thumb": c.mutedForeground, |
| 271 | "--color-warning": c.warningSurface, | 296 | "--color-warning": c.warningSurface, |
| ... | @@ -274,21 +299,25 @@ export function createMobileThemeVariables(colors: ThemeColors, appearance: Mobi | ... | @@ -274,21 +299,25 @@ export function createMobileThemeVariables(colors: ThemeColors, appearance: Mobi |
| 274 | "--color-danger": c.errorSurface, | 299 | "--color-danger": c.errorSurface, |
| 275 | "--color-danger-border": withAlpha(c.error, 0.32), | 300 | "--color-danger-border": withAlpha(c.error, 0.32), |
| 276 | "--color-danger-foreground": c.errorForeground, | 301 | "--color-danger-foreground": c.errorForeground, |
| 277 | "--color-input": c.surfaceRaised, | 302 | "--color-update": c.updateSurface, |
| 303 | "--color-update-foreground": c.updateForeground, | ||
| 304 | "--color-input": c.surface, | ||
| 278 | "--color-input-border": c.input, | 305 | "--color-input-border": c.input, |
| 279 | "--color-sidebar-search": c.sidebarControlSurface, | 306 | "--color-sidebar-search": c.sidebarControlSurface, |
| 280 | "--color-placeholder": c.placeholder, | 307 | "--color-placeholder": readableTextColor(c.placeholder, textSurfaces), |
| 281 | "--color-icon": c.text, | 308 | "--color-icon": c.text, |
| 282 | "--color-icon-muted": c.iconMuted, | 309 | "--color-icon-muted": c.iconMuted, |
| 283 | "--color-icon-subtle": c.secondaryLabel, | 310 | "--color-icon-subtle": c.secondaryLabel, |
| 284 | "--color-header": withAlpha(c.toolbar, 0.97), | 311 | "--color-header": withAlpha(c.toolbar, 0.97), |
| 312 | "--color-header-foreground": c.toolbarForeground, | ||
| 285 | "--color-header-border": c.toolbarBorder, | 313 | "--color-header-border": c.toolbarBorder, |
| 286 | "--color-glass-surface": withAlpha(c.surfaceOverlay, 0.74), | 314 | "--color-glass-surface": withAlpha(c.surfaceOverlay, 0.74), |
| 315 | "--color-glass-fallback": themeColorWithAlpha(groupedCard, appearance === "dark" ? 0.9 : 0.94), | ||
| 287 | "--color-glass-tint": withAlpha(c.surfaceOverlay, 0.22), | 316 | "--color-glass-tint": withAlpha(c.surfaceOverlay, 0.22), |
| 288 | "--color-status-bar": c.canvas, | 317 | "--color-status-bar": c.canvas, |
| 289 | "--color-md-body": c.text, | 318 | "--color-md-body": c.text, |
| 290 | "--color-md-strong": c.toolbarForeground, | 319 | "--color-md-strong": c.text, |
| 291 | "--color-md-link": c.accent, | 320 | "--color-md-link": readableTextColor(c.messageAction, c.canvas), |
| 292 | "--color-md-blockquote-border": c.border, | 321 | "--color-md-blockquote-border": c.border, |
| 293 | "--color-md-blockquote-bg": c.muted, | 322 | "--color-md-blockquote-bg": c.muted, |
| 294 | "--color-md-code-bg": c.codeBackground, | 323 | "--color-md-code-bg": c.codeBackground, |
| ... | @@ -301,12 +330,15 @@ export function createMobileThemeVariables(colors: ThemeColors, appearance: Mobi | ... | @@ -301,12 +330,15 @@ export function createMobileThemeVariables(colors: ThemeColors, appearance: Mobi |
| 301 | "--color-user-bubble": c.messageSurface, | 330 | "--color-user-bubble": c.messageSurface, |
| 302 | "--color-user-bubble-foreground": c.messageForeground, | 331 | "--color-user-bubble-foreground": c.messageForeground, |
| 303 | "--color-user-bubble-foreground-muted": withAlpha(c.messageForeground, 0.78), | 332 | "--color-user-bubble-foreground-muted": withAlpha(c.messageForeground, 0.78), |
| 304 | "--color-user-bubble-skill-foreground": readableMessageAccent( | 333 | "--color-user-bubble-skill-foreground": readableTextColor(c.messageAction, c.messageSurface), |
| 305 | c.messageAction, | ||
| 306 | c.messageSurface, | ||
| 307 | ), | ||
| 308 | "--color-backdrop": withAlpha("#000000", appearance === "dark" ? 0.48 : 0.22), | 334 | "--color-backdrop": withAlpha("#000000", appearance === "dark" ? 0.48 : 0.22), |
| 309 | "--color-drawer": withAlpha(c.sidebar, 0.99), | 335 | "--color-drawer": c.sidebar, |
| 336 | "--color-drawer-foreground": c.sidebarForeground, | ||
| 337 | "--color-drawer-foreground-muted": readableTextColor(c.sidebarMutedForeground, [ | ||
| 338 | c.sidebar, | ||
| 339 | c.sidebarRowHover, | ||
| 340 | ]), | ||
| 341 | "--color-drawer-border": c.sidebarBorder, | ||
| 310 | "--color-drawer-shadow": withAlpha("#000000", appearance === "dark" ? 0.32 : 0.12), | 342 | "--color-drawer-shadow": withAlpha("#000000", appearance === "dark" ? 0.32 : 0.12), |
| 311 | "--color-dot-separator": withAlpha(c.textMuted, 0.35), | 343 | "--color-dot-separator": withAlpha(c.textMuted, 0.35), |
| 312 | "--color-wordmark": c.text, | 344 | "--color-wordmark": c.text, |
| ... | @@ -318,14 +350,45 @@ export const MOBILE_THEME_VARIABLE_NAMES = Object.keys( | ... | @@ -318,14 +350,45 @@ export const MOBILE_THEME_VARIABLE_NAMES = Object.keys( |
| 318 | createMobileThemeVariables(T3_CHAT_THEME.colors, "light"), | 350 | createMobileThemeVariables(T3_CHAT_THEME.colors, "light"), |
| 319 | ) as ReadonlyArray<MobileThemeVariable>; | 351 | ) as ReadonlyArray<MobileThemeVariable>; |
| 320 | 352 | ||
| 353 | export function getMobileThemeColors( | ||
| 354 | themeId: SharedMobileThemeId, | ||
| 355 | appearance: MobileThemeAppearance, | ||
| 356 | ): ThemeColors { | ||
| 357 | if (themeId === DEFAULT_MOBILE_THEME_ID) { | ||
| 358 | return appearance === "dark" ? T3_CODE_DARK_THEME_COLORS : T3_CODE_LIGHT_THEME_COLORS; | ||
| 359 | } | ||
| 360 | const theme = BUILT_IN_THEMES.find((candidate) => candidate.id === themeId) ?? T3_CHAT_THEME; | ||
| 361 | return getThemeColorsForAppearance(theme, appearance) ?? theme.colors; | ||
| 362 | } | ||
| 363 | |||
| 321 | export function getMobileThemeVariables( | 364 | export function getMobileThemeVariables( |
| 322 | themeId: BuiltInThemeId, | 365 | themeId: SharedMobileThemeId, |
| 323 | appearance: MobileThemeAppearance, | 366 | appearance: MobileThemeAppearance, |
| 324 | overrides: Partial<MobileThemeVariables> | null = null, | 367 | overrides: Partial<MobileThemeVariables> | null = null, |
| 325 | ): MobileThemeVariables { | 368 | ): MobileThemeVariables { |
| 326 | const theme = BUILT_IN_THEMES.find((candidate) => candidate.id === themeId) ?? T3_CHAT_THEME; | 369 | const colors = getMobileThemeColors(themeId, appearance); |
| 327 | const colors = getThemeColorsForAppearance(theme, appearance) ?? theme.colors; | 370 | // Mobile settings groups and fallback materials use tonal fills where desktop |
| 328 | const baseVariables = createMobileThemeVariables(colors, appearance); | 371 | // uses outlined cards. Regular cards retain their shared desktop surface. |
| 372 | const groupedCard = | ||
| 373 | themeId === DEFAULT_MOBILE_THEME_ID | ||
| 374 | ? appearance === "light" | ||
| 375 | ? colors.toolbarControlHover | ||
| 376 | : colors.sidebarRowActive | ||
| 377 | : colors.surface; | ||
| 378 | const mobileColors = | ||
| 379 | themeId === DEFAULT_MOBILE_THEME_ID | ||
| 380 | ? { | ||
| 381 | ...colors, | ||
| 382 | messageSurface: flattenThemeColor( | ||
| 383 | themeColorWithAlpha( | ||
| 384 | appearance === "dark" ? colors.sidebarRowActive : colors.border, | ||
| 385 | 0.3, | ||
| 386 | ), | ||
| 387 | colors.messageSurface, | ||
| 388 | ), | ||
| 389 | } | ||
| 390 | : colors; | ||
| 391 | const baseVariables = createMobileThemeVariables(mobileColors, appearance, groupedCard); | ||
| 329 | 392 | ||
| 330 | // The complete base record guarantees that optional overrides cannot leave a token undefined. | 393 | // The complete base record guarantees that optional overrides cannot leave a token undefined. |
| 331 | return overrides ? ({ ...baseVariables, ...overrides } as MobileThemeVariables) : baseVariables; | 394 | return overrides ? ({ ...baseVariables, ...overrides } as MobileThemeVariables) : baseVariables; |
apps/mobile/src/lib/mobileThemeVariables.test.ts+56-13| ... | @@ -5,11 +5,11 @@ import { getMobileThemeVariables, MOBILE_THEME_IDS, themeColorWithAlpha } from " | ... | @@ -5,11 +5,11 @@ import { getMobileThemeVariables, MOBILE_THEME_IDS, themeColorWithAlpha } from " |
| 5 | import { getMobileThemeRuntimeVariables } from "./mobileThemeVariables"; | 5 | import { getMobileThemeRuntimeVariables } from "./mobileThemeVariables"; |
| 6 | 6 | ||
| 7 | describe("mobile theme runtime variables", () => { | 7 | describe("mobile theme runtime variables", () => { |
| 8 | it("derives the standard runtime palette from global.css", () => { | 8 | it("matches the standard base palette to the generated stylesheet", () => { |
| 9 | expect(getMobileThemeRuntimeVariables("t3-code", "light", "ios")).toEqual( | 9 | expect(getMobileThemeRuntimeVariables("t3-code", "light", "web")).toEqual( |
| 10 | readDefaultMobileThemeVariables("light"), | 10 | readDefaultMobileThemeVariables("light"), |
| 11 | ); | 11 | ); |
| 12 | expect(getMobileThemeRuntimeVariables("t3-code", "dark", "ios")).toEqual( | 12 | expect(getMobileThemeRuntimeVariables("t3-code", "dark", "web")).toEqual( |
| 13 | readDefaultMobileThemeVariables("dark"), | 13 | readDefaultMobileThemeVariables("dark"), |
| 14 | ); | 14 | ); |
| 15 | }); | 15 | }); |
| ... | @@ -27,18 +27,22 @@ describe("mobile theme runtime variables", () => { | ... | @@ -27,18 +27,22 @@ describe("mobile theme runtime variables", () => { |
| 27 | "keeps %s colors on Android with an opaque Material frame", | 27 | "keeps %s colors on Android with an opaque Material frame", |
| 28 | (themeId) => { | 28 | (themeId) => { |
| 29 | for (const appearance of ["light", "dark"] as const) { | 29 | for (const appearance of ["light", "dark"] as const) { |
| 30 | const ios = getMobileThemeRuntimeVariables(themeId, appearance, "ios"); | 30 | const base = getMobileThemeVariables( |
| 31 | themeId === "material-you" ? "t3-code" : themeId, | ||
| 32 | appearance, | ||
| 33 | ); | ||
| 31 | const android = getMobileThemeRuntimeVariables(themeId, appearance, "android"); | 34 | const android = getMobileThemeRuntimeVariables(themeId, appearance, "android"); |
| 32 | expect(android).toEqual({ | 35 | expect(android).toEqual({ |
| 33 | ...ios, | 36 | ...base, |
| 34 | "--color-header": themeColorWithAlpha( | 37 | "--color-header": themeColorWithAlpha( |
| 35 | ios[ | 38 | base[ |
| 36 | themeId === "t3-code" || themeId === "material-you" | 39 | themeId === "t3-code" || themeId === "material-you" |
| 37 | ? "--color-card" | 40 | ? "--color-row-hover" |
| 38 | : "--color-drawer" | 41 | : "--color-drawer" |
| 39 | ], | 42 | ], |
| 40 | 1, | 43 | 1, |
| 41 | ), | 44 | ), |
| 45 | "--color-header-foreground": base["--color-drawer-foreground"], | ||
| 42 | }); | 46 | }); |
| 43 | expect(android["--color-header"]).toMatch(/^rgba\(\d+, \d+, \d+, 1\)$/); | 47 | expect(android["--color-header"]).toMatch(/^rgba\(\d+, \d+, \d+, 1\)$/); |
| 44 | } | 48 | } |
| ... | @@ -46,13 +50,52 @@ describe("mobile theme runtime variables", () => { | ... | @@ -46,13 +50,52 @@ describe("mobile theme runtime variables", () => { |
| 46 | ); | 50 | ); |
| 47 | 51 | ||
| 48 | it.each(["t3-code", "material-you"] as const)( | 52 | it.each(["t3-code", "material-you"] as const)( |
| 49 | "keeps the %s default dark frame distinct from the rounded settings body", | 53 | "keeps the %s default Material frame distinct in both appearances", |
| 54 | (themeId) => { | ||
| 55 | for (const appearance of ["light", "dark"] as const) { | ||
| 56 | const variables = getMobileThemeRuntimeVariables(themeId, appearance, "android"); | ||
| 57 | expect(variables["--color-header"]).toBe( | ||
| 58 | appearance === "light" ? "rgba(244, 244, 245, 1)" : "rgba(20, 20, 20, 1)", | ||
| 59 | ); | ||
| 60 | for (const pane of ["--color-screen", "--color-sheet-solid", "--color-drawer"] as const) { | ||
| 61 | expect(variables["--color-header"]).not.toBe(themeColorWithAlpha(variables[pane], 1)); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | }, | ||
| 65 | ); | ||
| 66 | |||
| 67 | it.each(["t3-code", "material-you"] as const)( | ||
| 68 | "adapts %s iPad chrome without reversing the dark desktop hierarchy", | ||
| 50 | (themeId) => { | 69 | (themeId) => { |
| 51 | const variables = getMobileThemeRuntimeVariables(themeId, "dark", "android"); | 70 | for (const appearance of ["light", "dark"] as const) { |
| 52 | expect(variables["--color-header"]).toBe("rgba(23, 23, 23, 1)"); | 71 | const ios = getMobileThemeRuntimeVariables(themeId, appearance, "ios"); |
| 53 | expect(variables["--color-header"]).not.toBe( | 72 | const android = getMobileThemeRuntimeVariables(themeId, appearance, "android"); |
| 54 | themeColorWithAlpha(variables["--color-sheet-solid"], 1), | 73 | if (appearance === "light") { |
| 55 | ); | 74 | expect(ios["--color-drawer"]).toBe(android["--color-header"]); |
| 75 | expect(ios["--color-header"]).toBe(android["--color-header"]); | ||
| 76 | expect(ios["--color-header-foreground"]).toBe(ios["--color-drawer-foreground"]); | ||
| 77 | } else { | ||
| 78 | expect(ios).toEqual(getMobileThemeVariables("t3-code", appearance)); | ||
| 79 | expect(ios["--color-drawer"]).toBe(android["--color-drawer"]); | ||
| 80 | expect(ios["--color-drawer"]).toBe("#000000"); | ||
| 81 | expect(ios["--color-thread-canvas"]).toBe("#0a0a0a"); | ||
| 82 | } | ||
| 83 | expect(themeColorWithAlpha(ios["--color-thread-hover"], 1)).not.toBe( | ||
| 84 | themeColorWithAlpha(ios["--color-drawer"], 1), | ||
| 85 | ); | ||
| 86 | expect(themeColorWithAlpha(ios["--color-thread-hover"], 1)).not.toBe( | ||
| 87 | themeColorWithAlpha(ios["--color-thread-selected"], 1), | ||
| 88 | ); | ||
| 89 | for (const role of [ | ||
| 90 | "--color-screen", | ||
| 91 | "--color-thread-canvas", | ||
| 92 | "--color-card", | ||
| 93 | "--color-composer-surface", | ||
| 94 | "--color-grouped-card", | ||
| 95 | ] as const) { | ||
| 96 | expect(ios[role]).toBe(android[role]); | ||
| 97 | } | ||
| 98 | } | ||
| 56 | }, | 99 | }, |
| 57 | ); | 100 | ); |
| 58 | }); | 101 | }); |
apps/mobile/src/lib/mobileThemeVariables.ts+20-9| ... | @@ -14,8 +14,8 @@ const defaults = defaultThemeVariables as Readonly< | ... | @@ -14,8 +14,8 @@ const defaults = defaultThemeVariables as Readonly< |
| 14 | 14 | ||
| 15 | /** | 15 | /** |
| 16 | * Complete palette for native and third-party APIs that cannot consume a | 16 | * Complete palette for native and third-party APIs that cannot consume a |
| 17 | * Uniwind className. The standard palette is generated from global.css; custom | 17 | * Uniwind className. Every palette shares the source that generates its |
| 18 | * palettes share the same source that generates their registered CSS themes. | 18 | * registered CSS theme. |
| 19 | */ | 19 | */ |
| 20 | export function getMobileThemeRuntimeVariables( | 20 | export function getMobileThemeRuntimeVariables( |
| 21 | themeId: MobileThemeId, | 21 | themeId: MobileThemeId, |
| ... | @@ -26,16 +26,27 @@ export function getMobileThemeRuntimeVariables( | ... | @@ -26,16 +26,27 @@ export function getMobileThemeRuntimeVariables( |
| 26 | const variables = usesDefaultPalette | 26 | const variables = usesDefaultPalette |
| 27 | ? defaults[appearance] | 27 | ? defaults[appearance] |
| 28 | : getMobileThemeVariables(themeId, appearance); | 28 | : getMobileThemeVariables(themeId, appearance); |
| 29 | // Android's frame surrounds the sidebar and chat panes. Light iPad sidebars | ||
| 30 | // reuse that stronger tonal fill; dark sidebars retain the shared black pane | ||
| 31 | // beneath the near-black chat canvas. System colors replace these roles later. | ||
| 32 | const frame = themeColorWithAlpha( | ||
| 33 | variables[usesDefaultPalette ? "--color-row-hover" : "--color-drawer"], | ||
| 34 | 1, | ||
| 35 | ); | ||
| 36 | if (platform === "ios" && usesDefaultPalette && appearance === "light") { | ||
| 37 | return { | ||
| 38 | ...variables, | ||
| 39 | "--color-header": frame, | ||
| 40 | "--color-header-foreground": variables["--color-drawer-foreground"], | ||
| 41 | "--color-drawer": frame, | ||
| 42 | "--color-drawer-foreground-muted": variables["--color-foreground-muted"], | ||
| 43 | }; | ||
| 44 | } | ||
| 29 | if (platform !== "android") return variables; | 45 | if (platform !== "android") return variables; |
| 30 | 46 | ||
| 31 | // Rounded panes share one opaque frame. The default dark drawer matches the | ||
| 32 | // settings body, so use its card tone to keep the rounded edge visible. | ||
| 33 | // System colors replace this with their own surfaceContainerHigh afterwards. | ||
| 34 | return { | 47 | return { |
| 35 | ...variables, | 48 | ...variables, |
| 36 | "--color-header": themeColorWithAlpha( | 49 | "--color-header": frame, |
| 37 | variables[usesDefaultPalette ? "--color-card" : "--color-drawer"], | 50 | "--color-header-foreground": variables["--color-drawer-foreground"], |
| 38 | 1, | ||
| 39 | ), | ||
| 40 | }; | 51 | }; |
| 41 | } | 52 | } |
apps/mobile/src/lib/nativeComposerTheme.test.ts created+32| ... | @@ -0,0 +1,32 @@ | ||
| 1 | import { describe, expect, it } from "vite-plus/test"; | ||
| 2 | import { MOBILE_THEME_IDS } from "@t3tools/shared/themePalettes"; | ||
| 3 | |||
| 4 | import { getMobileThemeVariables } from "./mobileTheme"; | ||
| 5 | import { createNativeComposerTheme } from "./nativeComposerTheme"; | ||
| 6 | |||
| 7 | describe("native composer colors", () => { | ||
| 8 | it.each(MOBILE_THEME_IDS)("delivers parsable colors for %s in both appearances", (themeId) => { | ||
| 9 | for (const appearance of ["light", "dark"] as const) { | ||
| 10 | const variables = getMobileThemeVariables(themeId, appearance); | ||
| 11 | const theme = createNativeComposerTheme(variables); | ||
| 12 | for (const color of Object.values(theme)) expect(color).toMatch(/^#[\da-f]{6}$/i); | ||
| 13 | expect(theme.text).toBe(variables["--color-foreground"]); | ||
| 14 | expect(theme.skillBorder).not.toBe(theme.skillBackground); | ||
| 15 | } | ||
| 16 | }); | ||
| 17 | |||
| 18 | it("flattens Material You alpha colors over the composer rather than falling back to defaults", () => { | ||
| 19 | const theme = createNativeComposerTheme({ | ||
| 20 | ...getMobileThemeVariables("t3-code", "light"), | ||
| 21 | "--color-screen": "#ffffffff", | ||
| 22 | "--color-composer-surface": "#ffffffff", | ||
| 23 | "--color-subtle": "#0000000d", | ||
| 24 | "--color-placeholder": "#0000009e", | ||
| 25 | "--color-inline-skill-background": "#ffffffff", | ||
| 26 | "--color-inline-skill-border": "#00000080", | ||
| 27 | }); | ||
| 28 | expect(theme.chipBackground).toBe("#f2f2f2"); | ||
| 29 | expect(theme.placeholder).toBe("#616161"); | ||
| 30 | expect(theme.skillBorder).toBe("#7f7f7f"); | ||
| 31 | }); | ||
| 32 | }); | ||
apps/mobile/src/lib/nativeComposerTheme.ts created+19| ... | @@ -0,0 +1,19 @@ | ||
| 1 | import { flattenThemeColor, type MobileThemeVariables } from "./mobileTheme"; | ||
| 2 | |||
| 3 | /** Native chip parsers need opaque hex instead of CSS rgba or platform-specific alpha order. */ | ||
| 4 | export function createNativeComposerTheme(theme: MobileThemeVariables) { | ||
| 5 | const surface = flattenThemeColor(theme["--color-composer-surface"], theme["--color-screen"]); | ||
| 6 | const chipBackground = flattenThemeColor(theme["--color-subtle"], surface); | ||
| 7 | const skillBackground = flattenThemeColor(theme["--color-inline-skill-background"], surface); | ||
| 8 | return { | ||
| 9 | text: flattenThemeColor(theme["--color-foreground"], surface), | ||
| 10 | placeholder: flattenThemeColor(theme["--color-placeholder"], surface), | ||
| 11 | chipBackground, | ||
| 12 | chipBorder: flattenThemeColor(theme["--color-border"], chipBackground), | ||
| 13 | chipText: flattenThemeColor(theme["--color-foreground"], chipBackground), | ||
| 14 | skillBackground, | ||
| 15 | skillBorder: flattenThemeColor(theme["--color-inline-skill-border"], skillBackground), | ||
| 16 | skillText: flattenThemeColor(theme["--color-inline-skill-foreground"], skillBackground), | ||
| 17 | fileTint: flattenThemeColor(theme["--color-icon-muted"], chipBackground), | ||
| 18 | }; | ||
| 19 | } | ||
apps/mobile/src/lib/useMobileNavigationTheme.ts+10-7| ... | @@ -10,7 +10,7 @@ import { useUniwindTheme } from "./useUniwindTheme"; | ... | @@ -10,7 +10,7 @@ import { useUniwindTheme } from "./useUniwindTheme"; |
| 10 | * preferences provider applies the registered Uniwind theme first, then | 10 | * preferences provider applies the registered Uniwind theme first, then |
| 11 | * publishes this matching navigation palette through React. | 11 | * publishes this matching navigation palette through React. |
| 12 | */ | 12 | */ |
| 13 | export function useMobileNavigationTheme(): Theme { | 13 | export function useMobileNavigationTheme(surface: "screen" | "sidebar" = "screen"): Theme { |
| 14 | const { themeAppearance: appearance } = useAppearancePreferences(); | 14 | const { themeAppearance: appearance } = useAppearancePreferences(); |
| 15 | const variables = useUniwindTheme(); | 15 | const variables = useUniwindTheme(); |
| 16 | return useMemo(() => { | 16 | return useMemo(() => { |
| ... | @@ -19,13 +19,16 @@ export function useMobileNavigationTheme(): Theme { | ... | @@ -19,13 +19,16 @@ export function useMobileNavigationTheme(): Theme { |
| 19 | ...base, | 19 | ...base, |
| 20 | colors: { | 20 | colors: { |
| 21 | ...base.colors, | 21 | ...base.colors, |
| 22 | primary: variables["--color-primary"], | 22 | primary: variables["--color-primary-text"], |
| 23 | background: variables["--color-screen"], | 23 | background: variables[surface === "sidebar" ? "--color-drawer" : "--color-screen"], |
| 24 | card: variables["--color-sheet-solid"], | 24 | card: variables[surface === "sidebar" ? "--color-drawer" : "--color-sheet-solid"], |
| 25 | text: variables["--color-foreground"], | 25 | text: variables[ |
| 26 | border: variables["--color-header-border"], | 26 | surface === "sidebar" ? "--color-drawer-foreground" : "--color-header-foreground" |
| 27 | ], | ||
| 28 | border: | ||
| 29 | variables[surface === "sidebar" ? "--color-drawer-border" : "--color-header-border"], | ||
| 27 | notification: variables["--color-danger-foreground"], | 30 | notification: variables["--color-danger-foreground"], |
| 28 | }, | 31 | }, |
| 29 | }; | 32 | }; |
| 30 | }, [appearance, variables]); | 33 | }, [appearance, surface, variables]); |
| 31 | } | 34 | } |
apps/mobile/src/native/SelectableMarkdownText.android.tsx+2-2| ... | @@ -24,8 +24,8 @@ export function hasNativeSelectableMarkdownText(): boolean { | ... | @@ -24,8 +24,8 @@ export function hasNativeSelectableMarkdownText(): boolean { |
| 24 | 24 | ||
| 25 | export function SelectableMarkdownText(props: MobileSelectableMarkdownTextProps) { | 25 | export function SelectableMarkdownText(props: MobileSelectableMarkdownTextProps) { |
| 26 | const theme = useUniwindTheme(); | 26 | const theme = useUniwindTheme(); |
| 27 | const selectionColor = themeColorWithAlpha(theme["--color-primary"], 0.32); | 27 | const selectionColor = themeColorWithAlpha(theme["--color-focus"], 0.32); |
| 28 | const selectionHandleColor = theme["--color-primary"]; | 28 | const selectionHandleColor = theme["--color-focus"]; |
| 29 | const textStyle = useMemo( | 29 | const textStyle = useMemo( |
| 30 | () => ({ selectionColor, selectionHandleColor, ...props.textStyle }), | 30 | () => ({ selectionColor, selectionHandleColor, ...props.textStyle }), |
| 31 | [props.textStyle, selectionColor, selectionHandleColor], | 31 | [props.textStyle, selectionColor, selectionHandleColor], |
apps/mobile/src/native/T3ComposerEditor.ios.tsx+2-13| ... | @@ -22,7 +22,7 @@ import { | ... | @@ -22,7 +22,7 @@ import { |
| 22 | } from "@t3tools/mobile-markdown-text/markdown"; | 22 | } from "@t3tools/mobile-markdown-text/markdown"; |
| 23 | import { resolveMarkdownFileIcon } from "@t3tools/mobile-markdown-text/links"; | 23 | import { resolveMarkdownFileIcon } from "@t3tools/mobile-markdown-text/links"; |
| 24 | import { useUniwindTheme } from "../lib/useUniwindTheme"; | 24 | import { useUniwindTheme } from "../lib/useUniwindTheme"; |
| 25 | import { flattenThemeColor } from "../lib/mobileTheme"; | 25 | import { createNativeComposerTheme } from "../lib/nativeComposerTheme"; |
| 26 | import { useFontFamily } from "../lib/useFontFamily"; | 26 | import { useFontFamily } from "../lib/useFontFamily"; |
| 27 | import { useScaledTextRole } from "../features/settings/appearance/useScaledTextRole"; | 27 | import { useScaledTextRole } from "../features/settings/appearance/useScaledTextRole"; |
| 28 | import { | 28 | import { |
| ... | @@ -257,18 +257,7 @@ export function ComposerEditor({ | ... | @@ -257,18 +257,7 @@ export function ComposerEditor({ |
| 257 | }, | 257 | }, |
| 258 | [], | 258 | [], |
| 259 | ); | 259 | ); |
| 260 | const themeJson = JSON.stringify({ | 260 | const themeJson = JSON.stringify(createNativeComposerTheme(theme)); |
| 261 | text: theme["--color-foreground"], | ||
| 262 | placeholder: theme["--color-placeholder"], | ||
| 263 | chipBackground: theme["--color-subtle"], | ||
| 264 | // Native chip drawing parses opaque hex only, and this role is translucent. | ||
| 265 | chipBorder: flattenThemeColor(theme["--color-border"], theme["--color-user-bubble"]), | ||
| 266 | chipText: theme["--color-foreground"], | ||
| 267 | skillBackground: theme["--color-inline-skill-background"], | ||
| 268 | skillBorder: theme["--color-inline-skill-border"], | ||
| 269 | skillText: theme["--color-inline-skill-foreground"], | ||
| 270 | fileTint: theme["--color-icon-muted"], | ||
| 271 | }); | ||
| 272 | const resolvedTextStyle = StyleSheet.flatten(textStyle) ?? {}; | 261 | const resolvedTextStyle = StyleSheet.flatten(textStyle) ?? {}; |
| 273 | return ( | 262 | return ( |
| 274 | <NativeView | 263 | <NativeView |
apps/mobile/src/native/T3ComposerEditor.native.tsx+3-12| ... | @@ -27,7 +27,7 @@ import { useNativePaste } from "../lib/useNativePaste"; | ... | @@ -27,7 +27,7 @@ import { useNativePaste } from "../lib/useNativePaste"; |
| 27 | import { useFontFamily } from "../lib/useFontFamily"; | 27 | import { useFontFamily } from "../lib/useFontFamily"; |
| 28 | import { useAppearancePreferences } from "../features/settings/appearance/AppearancePreferencesProvider"; | 28 | import { useAppearancePreferences } from "../features/settings/appearance/AppearancePreferencesProvider"; |
| 29 | import { useUniwindTheme } from "../lib/useUniwindTheme"; | 29 | import { useUniwindTheme } from "../lib/useUniwindTheme"; |
| 30 | import { flattenThemeColor } from "../lib/mobileTheme"; | 30 | import { createNativeComposerTheme } from "../lib/nativeComposerTheme"; |
| 31 | import { | 31 | import { |
| 32 | acknowledgeComposerNativeEvent, | 32 | acknowledgeComposerNativeEvent, |
| 33 | assumeComposerControlledState, | 33 | assumeComposerControlledState, |
| ... | @@ -259,17 +259,8 @@ export function ComposerEditor({ | ... | @@ -259,17 +259,8 @@ export function ComposerEditor({ |
| 259 | ); | 259 | ); |
| 260 | const { systemColorsActive } = useAppearancePreferences(); | 260 | const { systemColorsActive } = useAppearancePreferences(); |
| 261 | const themeJson = JSON.stringify({ | 261 | const themeJson = JSON.stringify({ |
| 262 | selection: Platform.OS === "android" || systemColorsActive ? theme["--color-primary"] : null, | 262 | ...createNativeComposerTheme(theme), |
| 263 | text: theme["--color-foreground"], | 263 | selection: Platform.OS === "android" || systemColorsActive ? theme["--color-focus"] : null, |
| 264 | placeholder: theme["--color-placeholder"], | ||
| 265 | chipBackground: theme["--color-subtle"], | ||
| 266 | // Native chip drawing parses opaque hex only, and this role is translucent. | ||
| 267 | chipBorder: flattenThemeColor(theme["--color-border"], theme["--color-user-bubble"]), | ||
| 268 | chipText: theme["--color-foreground"], | ||
| 269 | skillBackground: theme["--color-inline-skill-background"], | ||
| 270 | skillBorder: theme["--color-inline-skill-border"], | ||
| 271 | skillText: theme["--color-inline-skill-foreground"], | ||
| 272 | fileTint: theme["--color-icon-muted"], | ||
| 273 | }); | 264 | }); |
| 274 | const resolvedTextStyle = StyleSheet.flatten(textStyle) ?? {}; | 265 | const resolvedTextStyle = StyleSheet.flatten(textStyle) ?? {}; |
| 275 | const regularFontFamily = useFontFamily("regular"); | 266 | const regularFontFamily = useFontFamily("regular"); |
apps/web/src/themePalette.test.ts+15| ... | @@ -103,6 +103,21 @@ describe("theme files", () => { | ... | @@ -103,6 +103,21 @@ describe("theme files", () => { |
| 103 | }); | 103 | }); |
| 104 | }); | 104 | }); |
| 105 | 105 | ||
| 106 | it("keeps the stock sidebar and chat on distinct surfaces in both appearances", () => { | ||
| 107 | expectThemeColors(getStandardThemeColors("light"), { | ||
| 108 | canvas: "#fcfcfc", | ||
| 109 | sidebar: "#fafafa", | ||
| 110 | sidebarRowActive: "#ffffff", | ||
| 111 | messageSurface: "#f4f4f5", | ||
| 112 | }); | ||
| 113 | expectThemeColors(getStandardThemeColors("dark"), { | ||
| 114 | canvas: "#0a0a0a", | ||
| 115 | sidebar: "#000000", | ||
| 116 | sidebarRowActive: "#1a1b1b", | ||
| 117 | messageSurface: "#141414", | ||
| 118 | }); | ||
| 119 | }); | ||
| 120 | |||
| 106 | it("derives readable, distinctive vivid palettes from exact seeds", () => { | 121 | it("derives readable, distinctive vivid palettes from exact seeds", () => { |
| 107 | const seeds: ReadonlyArray<["light" | "dark", string, string]> = [ | 122 | const seeds: ReadonlyArray<["light" | "dark", string, string]> = [ |
| 108 | ["light", "#f4f9f2", "#1d8a4e"], | 123 | ["light", "#f4f9f2", "#1d8a4e"], |
apps/web/src/themePalette.ts+2-127| ... | @@ -9,6 +9,8 @@ import { | ... | @@ -9,6 +9,8 @@ import { |
| 9 | IRIS_THEME, | 9 | IRIS_THEME, |
| 10 | OCEAN_THEME, | 10 | OCEAN_THEME, |
| 11 | T3_CHAT_THEME, | 11 | T3_CHAT_THEME, |
| 12 | T3_CODE_LIGHT_THEME_COLORS, | ||
| 13 | T3_CODE_DARK_THEME_COLORS, | ||
| 12 | RESERVED_THEME_IDS, | 14 | RESERVED_THEME_IDS, |
| 13 | THEME_COLOR_ROLES, | 15 | THEME_COLOR_ROLES, |
| 14 | type ThemeAppearance, | 16 | type ThemeAppearance, |
| ... | @@ -326,133 +328,6 @@ function legacyThemeMode(theme: ThemePreference): ThemeAppearance | null { | ... | @@ -326,133 +328,6 @@ function legacyThemeMode(theme: ThemePreference): ThemeAppearance | null { |
| 326 | return theme === LEGACY_T3_CHAT_DARK_THEME_ID ? "dark" : null; | 328 | return theme === LEGACY_T3_CHAT_DARK_THEME_ID ? "dark" : null; |
| 327 | } | 329 | } |
| 328 | 330 | ||
| 329 | /** | ||
| 330 | * The palette T3 Code wears with no theme installed, captured from the app's | ||
| 331 | * stock tokens (index.css) so a draft seeded from the default look paints the | ||
| 332 | * pixels the user is already seeing. Alpha-bearing tokens are flattened over | ||
| 333 | * their real backdrops (canvas, or the sidebar for its rows) because theme | ||
| 334 | * colors are stored as opaque OKLCH tokens. | ||
| 335 | */ | ||
| 336 | const T3_CODE_LIGHT_THEME_COLORS: ThemeColors = { | ||
| 337 | canvas: "#fcfcfc", | ||
| 338 | chrome: "#fcfcfc", | ||
| 339 | toolbar: "#fcfcfc", | ||
| 340 | toolbarForeground: "#27272a", | ||
| 341 | toolbarBorder: "#e4e4e7", | ||
| 342 | toolbarControl: "#ffffff", | ||
| 343 | toolbarControlForeground: "#27272a", | ||
| 344 | toolbarControlHover: "#f4f4f5", | ||
| 345 | surface: "#ffffff", | ||
| 346 | surfaceRaised: "#fcfcfc", | ||
| 347 | surfaceOverlay: "#ffffff", | ||
| 348 | text: "#27272a", | ||
| 349 | textMuted: "#71717b", | ||
| 350 | border: "#e4e4e7", | ||
| 351 | input: "#d4d4d8", | ||
| 352 | focus: "#1b4ed8", | ||
| 353 | accent: "#1b4ed8", | ||
| 354 | accentForeground: "#ffffff", | ||
| 355 | secondary: "#fafafa", | ||
| 356 | secondaryForeground: "#27272a", | ||
| 357 | muted: "#fafafa", | ||
| 358 | mutedForeground: "#71717b", | ||
| 359 | placeholder: "#71717b", | ||
| 360 | secondaryLabel: "#71717b", | ||
| 361 | iconMuted: "#71717b", | ||
| 362 | error: "#fb2c36", | ||
| 363 | errorForeground: "#c10007", | ||
| 364 | errorSurface: "#fcebec", | ||
| 365 | warning: "#fe9a00", | ||
| 366 | warningForeground: "#bb4d00", | ||
| 367 | warningSurface: "#fcf4e8", | ||
| 368 | update: "#1b4ed8", | ||
| 369 | updateForeground: "#1b4ed8", | ||
| 370 | updateSurface: "#e0e6f7", | ||
| 371 | accentSurface: "#f4f4f5", | ||
| 372 | accentSurfaceForeground: "#18181b", | ||
| 373 | messageSurface: "#f4f4f5", | ||
| 374 | messageForeground: "#27272a", | ||
| 375 | messageAction: "#1b4ed8", | ||
| 376 | messageActionForeground: "#ffffff", | ||
| 377 | messageActionHover: "#3160db", | ||
| 378 | codeBackground: "#ffffff", | ||
| 379 | codeForeground: "#27272a", | ||
| 380 | sidebar: "#fafafa", | ||
| 381 | sidebarForeground: "#27272a", | ||
| 382 | sidebarMutedForeground: "#71717b", | ||
| 383 | sidebarControlSurface: "#f4f4f5", | ||
| 384 | sidebarRowHover: "#fcfcfc", | ||
| 385 | sidebarRowActive: "#ffffff", | ||
| 386 | sidebarRowSelected: "#ffffff", | ||
| 387 | sidebarBorder: "#e4e4e7", | ||
| 388 | terminalBackground: "#fcfcfc", | ||
| 389 | terminalForeground: "#27272a", | ||
| 390 | terminalCursor: "#26384e", | ||
| 391 | terminalSelection: "#d0d6dd", | ||
| 392 | terminalScrollbar: "#d6d6d6", | ||
| 393 | terminalScrollbarHover: "#bdbdbd", | ||
| 394 | }; | ||
| 395 | |||
| 396 | const T3_CODE_DARK_THEME_COLORS: ThemeColors = { | ||
| 397 | canvas: "#0a0a0a", | ||
| 398 | chrome: "#0a0a0a", | ||
| 399 | toolbar: "#0a0a0a", | ||
| 400 | toolbarForeground: "#f5f5f5", | ||
| 401 | toolbarBorder: "#191919", | ||
| 402 | toolbarControl: "#111111", | ||
| 403 | toolbarControlForeground: "#f5f5f5", | ||
| 404 | toolbarControlHover: "#141414", | ||
| 405 | surface: "#111111", | ||
| 406 | surfaceRaised: "#111111", | ||
| 407 | surfaceOverlay: "#111111", | ||
| 408 | text: "#f5f5f5", | ||
| 409 | textMuted: "#818181", | ||
| 410 | border: "#191919", | ||
| 411 | input: "#1e1e1e", | ||
| 412 | focus: "#346bf1", | ||
| 413 | accent: "#346bf1", | ||
| 414 | accentForeground: "#ffffff", | ||
| 415 | secondary: "#111111", | ||
| 416 | secondaryForeground: "#f5f5f5", | ||
| 417 | muted: "#111111", | ||
| 418 | mutedForeground: "#818181", | ||
| 419 | placeholder: "#818181", | ||
| 420 | secondaryLabel: "#818181", | ||
| 421 | iconMuted: "#818181", | ||
| 422 | error: "#fb414a", | ||
| 423 | errorForeground: "#ff6467", | ||
| 424 | errorSurface: "#301214", | ||
| 425 | warning: "#fe9a00", | ||
| 426 | warningForeground: "#ffb900", | ||
| 427 | warningSurface: "#312108", | ||
| 428 | update: "#346bf1", | ||
| 429 | updateForeground: "#51a2ff", | ||
| 430 | updateSurface: "#121b34", | ||
| 431 | accentSurface: "#141414", | ||
| 432 | accentSurfaceForeground: "#f5f5f5", | ||
| 433 | messageSurface: "#141414", | ||
| 434 | messageForeground: "#f5f5f5", | ||
| 435 | messageAction: "#346bf1", | ||
| 436 | messageActionForeground: "#ffffff", | ||
| 437 | messageActionHover: "#3061d9", | ||
| 438 | codeBackground: "#111111", | ||
| 439 | codeForeground: "#f5f5f5", | ||
| 440 | sidebar: "#000000", | ||
| 441 | sidebarForeground: "#f1f3f7", | ||
| 442 | sidebarMutedForeground: "#a3a3a3", | ||
| 443 | sidebarControlSurface: "#0a0a0a", | ||
| 444 | sidebarRowHover: "#131313", | ||
| 445 | sidebarRowActive: "#1a1b1b", | ||
| 446 | sidebarRowSelected: "#111111", | ||
| 447 | sidebarBorder: "#141414", | ||
| 448 | terminalBackground: "#0a0a0a", | ||
| 449 | terminalForeground: "#f5f5f5", | ||
| 450 | terminalCursor: "#b4cbff", | ||
| 451 | terminalSelection: "#343a47", | ||
| 452 | terminalScrollbar: "#222222", | ||
| 453 | terminalScrollbarHover: "#363636", | ||
| 454 | }; | ||
| 455 | |||
| 456 | /** | 331 | /** |
| 457 | * The standard T3 Code look as a theme palette, for seeding a new theme when | 332 | * The standard T3 Code look as a theme palette, for seeding a new theme when |
| 458 | * no theme is installed. Distinct from {@link getDefaultThemeColors}, which | 333 | * no theme is installed. Distinct from {@link getDefaultThemeColors}, which |
packages/shared/src/themePalettes.ts+128-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | export const BUILT_IN_THEME_IDS = ["t3-chat", "grove", "ocean", "ember", "iris"] as const; | 1 | export const BUILT_IN_THEME_IDS = ["t3-chat", "grove", "ocean", "ember", "iris"] as const; |
| 2 | 2 | ||
| 3 | /** The mobile app's own hand-tuned palette, which is not part of the built-in library. */ | 3 | /** The standard T3 Code palette, kept separate from the optional built-in theme library. */ |
| 4 | export const MOBILE_DEFAULT_THEME_ID = "t3-code"; | 4 | export const MOBILE_DEFAULT_THEME_ID = "t3-code"; |
| 5 | 5 | ||
| 6 | /** | 6 | /** |
| ... | @@ -121,6 +121,133 @@ export type ThemeDefinition = Readonly<{ | ... | @@ -121,6 +121,133 @@ export type ThemeDefinition = Readonly<{ |
| 121 | managed?: boolean; | 121 | managed?: boolean; |
| 122 | }>; | 122 | }>; |
| 123 | 123 | ||
| 124 | /** | ||
| 125 | * The palette T3 Code wears with no theme installed, captured from the app's | ||
| 126 | * stock tokens (index.css) so a draft seeded from the default look paints the | ||
| 127 | * pixels the user is already seeing. Alpha-bearing tokens are flattened over | ||
| 128 | * their real backdrops (canvas, or the sidebar for its rows) because theme | ||
| 129 | * colors are stored as opaque OKLCH tokens. | ||
| 130 | */ | ||
| 131 | export const T3_CODE_LIGHT_THEME_COLORS: ThemeColors = { | ||
| 132 | canvas: "#fcfcfc", | ||
| 133 | chrome: "#fcfcfc", | ||
| 134 | toolbar: "#fcfcfc", | ||
| 135 | toolbarForeground: "#27272a", | ||
| 136 | toolbarBorder: "#e4e4e7", | ||
| 137 | toolbarControl: "#ffffff", | ||
| 138 | toolbarControlForeground: "#27272a", | ||
| 139 | toolbarControlHover: "#f4f4f5", | ||
| 140 | surface: "#ffffff", | ||
| 141 | surfaceRaised: "#fcfcfc", | ||
| 142 | surfaceOverlay: "#ffffff", | ||
| 143 | text: "#27272a", | ||
| 144 | textMuted: "#71717b", | ||
| 145 | border: "#e4e4e7", | ||
| 146 | input: "#d4d4d8", | ||
| 147 | focus: "#1b4ed8", | ||
| 148 | accent: "#1b4ed8", | ||
| 149 | accentForeground: "#ffffff", | ||
| 150 | secondary: "#fafafa", | ||
| 151 | secondaryForeground: "#27272a", | ||
| 152 | muted: "#fafafa", | ||
| 153 | mutedForeground: "#71717b", | ||
| 154 | placeholder: "#71717b", | ||
| 155 | secondaryLabel: "#71717b", | ||
| 156 | iconMuted: "#71717b", | ||
| 157 | error: "#fb2c36", | ||
| 158 | errorForeground: "#c10007", | ||
| 159 | errorSurface: "#fcebec", | ||
| 160 | warning: "#fe9a00", | ||
| 161 | warningForeground: "#bb4d00", | ||
| 162 | warningSurface: "#fcf4e8", | ||
| 163 | update: "#1b4ed8", | ||
| 164 | updateForeground: "#1b4ed8", | ||
| 165 | updateSurface: "#e0e6f7", | ||
| 166 | accentSurface: "#f4f4f5", | ||
| 167 | accentSurfaceForeground: "#18181b", | ||
| 168 | messageSurface: "#f4f4f5", | ||
| 169 | messageForeground: "#27272a", | ||
| 170 | messageAction: "#1b4ed8", | ||
| 171 | messageActionForeground: "#ffffff", | ||
| 172 | messageActionHover: "#3160db", | ||
| 173 | codeBackground: "#ffffff", | ||
| 174 | codeForeground: "#27272a", | ||
| 175 | sidebar: "#fafafa", | ||
| 176 | sidebarForeground: "#27272a", | ||
| 177 | sidebarMutedForeground: "#71717b", | ||
| 178 | sidebarControlSurface: "#f4f4f5", | ||
| 179 | sidebarRowHover: "#fcfcfc", | ||
| 180 | sidebarRowActive: "#ffffff", | ||
| 181 | sidebarRowSelected: "#ffffff", | ||
| 182 | sidebarBorder: "#e4e4e7", | ||
| 183 | terminalBackground: "#fcfcfc", | ||
| 184 | terminalForeground: "#27272a", | ||
| 185 | terminalCursor: "#26384e", | ||
| 186 | terminalSelection: "#d0d6dd", | ||
| 187 | terminalScrollbar: "#d6d6d6", | ||
| 188 | terminalScrollbarHover: "#bdbdbd", | ||
| 189 | }; | ||
| 190 | |||
| 191 | export const T3_CODE_DARK_THEME_COLORS: ThemeColors = { | ||
| 192 | canvas: "#0a0a0a", | ||
| 193 | chrome: "#0a0a0a", | ||
| 194 | toolbar: "#0a0a0a", | ||
| 195 | toolbarForeground: "#f5f5f5", | ||
| 196 | toolbarBorder: "#191919", | ||
| 197 | toolbarControl: "#111111", | ||
| 198 | toolbarControlForeground: "#f5f5f5", | ||
| 199 | toolbarControlHover: "#141414", | ||
| 200 | surface: "#111111", | ||
| 201 | surfaceRaised: "#111111", | ||
| 202 | surfaceOverlay: "#111111", | ||
| 203 | text: "#f5f5f5", | ||
| 204 | textMuted: "#818181", | ||
| 205 | border: "#191919", | ||
| 206 | input: "#1e1e1e", | ||
| 207 | focus: "#346bf1", | ||
| 208 | accent: "#346bf1", | ||
| 209 | accentForeground: "#ffffff", | ||
| 210 | secondary: "#111111", | ||
| 211 | secondaryForeground: "#f5f5f5", | ||
| 212 | muted: "#111111", | ||
| 213 | mutedForeground: "#818181", | ||
| 214 | placeholder: "#818181", | ||
| 215 | secondaryLabel: "#818181", | ||
| 216 | iconMuted: "#818181", | ||
| 217 | error: "#fb414a", | ||
| 218 | errorForeground: "#ff6467", | ||
| 219 | errorSurface: "#301214", | ||
| 220 | warning: "#fe9a00", | ||
| 221 | warningForeground: "#ffb900", | ||
| 222 | warningSurface: "#312108", | ||
| 223 | update: "#346bf1", | ||
| 224 | updateForeground: "#51a2ff", | ||
| 225 | updateSurface: "#121b34", | ||
| 226 | accentSurface: "#141414", | ||
| 227 | accentSurfaceForeground: "#f5f5f5", | ||
| 228 | messageSurface: "#141414", | ||
| 229 | messageForeground: "#f5f5f5", | ||
| 230 | messageAction: "#346bf1", | ||
| 231 | messageActionForeground: "#ffffff", | ||
| 232 | messageActionHover: "#3061d9", | ||
| 233 | codeBackground: "#111111", | ||
| 234 | codeForeground: "#f5f5f5", | ||
| 235 | sidebar: "#000000", | ||
| 236 | sidebarForeground: "#f1f3f7", | ||
| 237 | sidebarMutedForeground: "#a3a3a3", | ||
| 238 | sidebarControlSurface: "#0a0a0a", | ||
| 239 | sidebarRowHover: "#131313", | ||
| 240 | sidebarRowActive: "#1a1b1b", | ||
| 241 | sidebarRowSelected: "#111111", | ||
| 242 | sidebarBorder: "#141414", | ||
| 243 | terminalBackground: "#0a0a0a", | ||
| 244 | terminalForeground: "#f5f5f5", | ||
| 245 | terminalCursor: "#b4cbff", | ||
| 246 | terminalSelection: "#343a47", | ||
| 247 | terminalScrollbar: "#222222", | ||
| 248 | terminalScrollbarHover: "#363636", | ||
| 249 | }; | ||
| 250 | |||
| 124 | export const T3_CHAT_THEME: ThemeDefinition = { | 251 | export const T3_CHAT_THEME: ThemeDefinition = { |
| 125 | id: "t3-chat", | 252 | id: "t3-chat", |
| 126 | label: "T3 Chat", | 253 | label: "T3 Chat", |