Monorepo for Aesthetic.Computer
aesthetic.computer
1import fs from 'fs';
2import path from 'path';
3import { fileURLToPath } from 'url';
4
5const __dirname = path.dirname(fileURLToPath(import.meta.url));
6const themesDir = path.join(__dirname, 'themes');
7
8// Color mappings from dark to light theme
9const colorMap = {
10 // Backgrounds: dark -> light
11 '#181010': '#fef8f0', // editor bg (red tint)
12 '#181018': '#f8f0fe', // editor bg (violet tint)
13 '#101810': '#f0fef8', // editor bg (green tint)
14 '#101018': '#f0f8fe', // editor bg (blue tint)
15 '#181810': '#fefef0', // editor bg (yellow tint)
16 '#101010': '#e8e0e0', // darker panels
17 '#140c0c': '#f5f0e8', // sidebar
18 '#0c140c': '#f0f5e8', // sidebar (green)
19 '#0c0c14': '#f0f0f5', // sidebar (blue)
20 '#14140c': '#f5f5e8', // sidebar (yellow)
21 '#301010': '#d0c0c0', // status bar
22 '#103010': '#c0d0c0', // status bar (green)
23 '#101030': '#c0c0d0', // status bar (blue)
24 '#303010': '#d0d0c0', // status bar (yellow)
25
26 // Foregrounds: white -> dark
27 '#ffffff': '#281e5a',
28 '#ffffffcc': '#281e5a',
29 '#ffffff80': '#281e5a80',
30 '#ffffff60': '#281e5a60',
31 '#ffffff50': '#281e5a50',
32 '#ffffff25': '#281e5a40',
33
34 // Grays
35 '#707070': '#606060',
36 '#a0a0a0': '#505050',
37 '#b0a0a8': '#281e5a',
38 '#d0c0c8': '#281e5a',
39 '#d0d0d0': '#404040',
40 '#606060': '#a0a0a0',
41 '#404060': '#c0c0e0',
42 '#606080': '#a0a0c0',
43 '#483848': '#d0c0d0',
44};
45
46// Function to lighten a hex color
47function lightenColor(hex, accentHex) {
48 // Remove # if present
49 hex = hex.replace('#', '');
50 accentHex = accentHex ? accentHex.replace('#', '') : null;
51
52 // Parse hex to RGB
53 let r = parseInt(hex.substring(0, 2), 16);
54 let g = parseInt(hex.substring(2, 4), 16);
55 let b = parseInt(hex.substring(4, 6), 16);
56 let alpha = hex.length === 8 ? hex.substring(6, 8) : '';
57
58 // Get accent color if provided
59 let ar, ag, ab;
60 if (accentHex && accentHex.length >= 6) {
61 ar = parseInt(accentHex.substring(0, 2), 16);
62 ag = parseInt(accentHex.substring(2, 4), 16);
63 ab = parseInt(accentHex.substring(4, 6), 16);
64 }
65
66 // If it's a very dark color (bg), make it very light with accent tint
67 if (r < 40 && g < 40 && b < 40) {
68 if (ar !== undefined) {
69 // Add slight accent tint to light background
70 r = 250 + Math.floor((ar - 128) * 0.05);
71 g = 250 + Math.floor((ag - 128) * 0.05);
72 b = 250 + Math.floor((ab - 128) * 0.05);
73 } else {
74 r = 252; g = 247; b = 245;
75 }
76 }
77 // If it's a light color (fg), make it dark
78 else if (r > 180 && g > 180 && b > 180) {
79 r = 40; g = 30; b = 90;
80 }
81 // If it's a medium color, invert brightness
82 else {
83 r = 255 - r;
84 g = 255 - g;
85 b = 255 - b;
86 }
87
88 // Clamp values
89 r = Math.min(255, Math.max(0, r));
90 g = Math.min(255, Math.max(0, g));
91 b = Math.min(255, Math.max(0, b));
92
93 return '#' + [r, g, b].map(x => x.toString(16).padStart(2, '0')).join('') + alpha;
94}
95
96// Function to transform a dark theme to light
97function transformToLight(darkTheme, accentColor) {
98 const lightTheme = JSON.parse(JSON.stringify(darkTheme));
99
100 // Update theme metadata
101 lightTheme.name = lightTheme.name.replace('Dark ', 'Light ');
102 lightTheme.type = 'light';
103
104 // Transform colors
105 for (const [key, value] of Object.entries(lightTheme.colors)) {
106 if (typeof value === 'string' && value.startsWith('#')) {
107 // Check if we have a direct mapping
108 if (colorMap[value]) {
109 lightTheme.colors[key] = colorMap[value];
110 }
111 // If it's the accent color or contains it, keep it but adjust for light theme
112 else if (value.toLowerCase().startsWith(accentColor.toLowerCase().substring(0, 4))) {
113 // Keep accent colors but ensure they work on light background
114 lightTheme.colors[key] = value;
115 }
116 // Otherwise, transform the color
117 else {
118 lightTheme.colors[key] = lightenColor(value, accentColor);
119 }
120 }
121 }
122
123 // Special adjustments for light theme
124 lightTheme.colors['editor.foreground'] = '#281e5a';
125 lightTheme.colors['sideBar.foreground'] = '#281e5a';
126 lightTheme.colors['activityBar.foreground'] = '#281e5a';
127 lightTheme.colors['titleBar.activeForeground'] = '#281e5a';
128 lightTheme.colors['statusBar.foreground'] = '#ffffff'; // Keep white on colored status bar
129
130 return lightTheme;
131}
132
133// Process each dark rainbow theme
134const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet', 'pink', 'pencil'];
135const accentColors = {
136 red: '#ff5555',
137 orange: '#ff8833',
138 yellow: '#ffdd44',
139 green: '#55ff55',
140 blue: '#5588ff',
141 indigo: '#6655ff',
142 violet: '#aa55ff',
143 pink: '#ff88cc',
144 pencil: '#888888'
145};
146
147for (const color of colors) {
148 const darkFilePath = path.join(themesDir, `aesthetic-dark-${color}-color-theme.json`);
149 const lightFilePath = path.join(themesDir, `aesthetic-light-${color}-color-theme.json`);
150
151 try {
152 const darkTheme = JSON.parse(fs.readFileSync(darkFilePath, 'utf8'));
153 const lightTheme = transformToLight(darkTheme, accentColors[color]);
154
155 fs.writeFileSync(lightFilePath, JSON.stringify(lightTheme, null, 2));
156 console.log(`✓ Created ${color} light theme`);
157 } catch (error) {
158 console.error(`✗ Failed to create ${color} light theme:`, error.message);
159 }
160}
161
162console.log('\nDone! Generated all light theme variations.');