~cytrogen/masto-fe

9021f5aff4df98f75d1cb53d7c420a369cbaccab — Cytrogen 14 days ago d640c03
Build: split CSS/SCSS webpack rules + generate CSS custom properties

- Split webpack css rule into separate .css and .scss rules so pure
  CSS files skip sass-loader (Phase 1)
- Generate properties.css for dark/light/contrast themes with all
  pre-calculated color values as CSS custom properties (Phase 2)
- Add extract-colors.js helper script for color value generation
A app/javascript/flavours/glitch/styles/properties-contrast.css => app/javascript/flavours/glitch/styles/properties-contrast.css +236 -0
@@ 0,0 1,236 @@
:root {
  --black: #000000;
  --white: #ffffff;
  --red-600: #b7253d;
  --red-500: #df405a;
  --blurple-600: #563acc;
  --blurple-500: #6364ff;
  --blurple-300: #858afa;
  --grey-600: #4e4c5a;
  --grey-100: #dadaf3;
  --success-green: #79bd9a;
  --error-red: #df405a;
  --warning-red: #ff5050;
  --gold-star: #ca8f04;
  --red-bookmark: #ff5050;
  --classic-base-color: #282c37;
  --classic-primary-color: #9baec8;
  --classic-secondary-color: #d9e1e8;
  --classic-highlight-color: #6364ff;
  --base-shadow-color: #000000;
  --base-overlay-background: #000000;
  --base-border-color: #ffffff;
  --simple-background-color: #ffffff;
  --valid-value-color: #79bd9a;
  --error-value-color: #df405a;
  --ui-base-color: #282c37;
  --ui-base-lighter-color: #606984;
  --ui-primary-color: #9baec8;
  --ui-secondary-color: #d9e1e8;
  --ui-highlight-color: #6364ff;
  --ui-button-color: #ffffff;
  --ui-button-background-color: #6364ff;
  --ui-button-focus-background-color: #563acc;
  --ui-button-secondary-color: #dadaf3;
  --ui-button-secondary-border-color: #dadaf3;
  --ui-button-secondary-focus-background-color: #4e4c5a;
  --ui-button-secondary-focus-color: #ffffff;
  --ui-button-tertiary-color: #858afa;
  --ui-button-tertiary-border-color: #858afa;
  --ui-button-tertiary-focus-background-color: #563acc;
  --ui-button-tertiary-focus-color: #ffffff;
  --ui-button-destructive-background-color: #df405a;
  --ui-button-destructive-focus-background-color: #b7253d;
  --primary-text-color: #ffffff;
  --darker-text-color: #dde3ec;
  --dark-text-color: #c2cede;
  --secondary-text-color: #ecf0f4;
  --highlight-text-color: #9697ff;
  --action-button-color: #a2a9bc;
  --action-button-focus-color: #687390;
  --passive-text-color: #ca8f04;
  --active-passive-text-color: #79bd9a;
  --inverted-text-color: #000000;
  --lighter-text-color: #1b1e25;
  --light-text-color: #364861;
  --action-button-color-lighten-7: #b7bccb;
  --action-button-color-lighten-13: #c9cdd8;
  --darker-text-color-lighten-4: #eaeef3;
  --darker-text-color-lighten-7: #f4f6f9;
  --darker-text-color-lighten-8: #f7f9fb;
  --darker-text-color-lighten-10: #fefefe;
  --dark-text-color-lighten-4: #d0d9e5;
  --dark-text-color-lighten-7: #dae1ea;
  --error-red-lighten-4: #e25169;
  --error-red-lighten-12: #e87487;
  --error-value-color-lighten-12: #e87487;
  --gold-star-lighten-6: #e8a405;
  --gold-star-lighten-16: #fbbb25;
  --highlight-text-color-lighten-4: #aaabff;
  --highlight-text-color-lighten-6: #b5b5ff;
  --highlight-text-color-lighten-8: #bfbfff;
  --highlight-text-color-lighten-13: #d8d9ff;
  --inverted-text-color-lighten-4: #0a0a0a;
  --inverted-text-color-lighten-10: #1a1a1a;
  --inverted-text-color-lighten-15: #262626;
  --inverted-text-color-lighten-16: #292929;
  --lighter-text-color-lighten-7: #2a2e3a;
  --lighter-text-color-lighten-20: #464d60;
  --secondary-text-color-lighten-4: #f9fafb;
  --secondary-text-color-lighten-7: #ffffff;
  --secondary-text-color-lighten-8: #ffffff;
  --ui-base-color-lighten-2: #2c313d;
  --ui-base-color-lighten-3: #2e3340;
  --ui-base-color-lighten-4: #313543;
  --ui-base-color-lighten-5: #333846;
  --ui-base-color-lighten-6: #353a49;
  --ui-base-color-lighten-8: #393f4f;
  --ui-base-color-lighten-11: #404657;
  --ui-base-color-lighten-12: #42485a;
  --ui-base-color-lighten-13: #444b5d;
  --ui-base-color-lighten-14: #464d60;
  --ui-base-color-lighten-16: #4a5266;
  --ui-base-color-lighten-20: #535b72;
  --ui-base-color-lighten-26: #606984;
  --ui-base-color-lighten-27: #626c87;
  --ui-base-color-lighten-29: #66718d;
  --ui-base-color-lighten-30: #687390;
  --ui-base-color-lighten-33: #707b97;
  --ui-base-color-lighten-34: #737d99;
  --ui-base-color-lighten-50: #a2a9bc;
  --ui-base-lighter-color-lighten-4: #687390;
  --ui-base-lighter-color-lighten-7: #707b97;
  --ui-highlight-color-lighten-4: #7778ff;
  --ui-highlight-color-lighten-8: #8c8dff;
  --ui-highlight-color-lighten-10: #9697ff;
  --ui-highlight-color-lighten-12: #a0a1ff;
  --ui-primary-color-lighten-8: #b5c3d6;
  --ui-primary-color-lighten-12: #c2cede;
  --ui-primary-color-lighten-20: #dde3ec;
  --ui-secondary-color-lighten-6: #ecf0f4;
  --ui-secondary-color-lighten-8: #f2f5f7;
  --valid-value-color-lighten-8: #94caaf;
  --valid-value-color-lighten-15: #acd6c1;
  --warning-red-lighten-12: #ff8d8d;
  --white-lighten-4: #ffffff;
  --white-lighten-7: #ffffff;
  --action-button-color-darken-13: #7c86a0;
  --darker-text-color-darken-13: #b2c1d5;
  --highlight-text-color-darken-4: #8282ff;
  --lighter-text-color-darken-4: #131419;
  --lighter-text-color-darken-7: #0c0d11;
  --simple-background-color-darken-2: #fafafa;
  --simple-background-color-darken-8: #ebebeb;
  --simple-background-color-darken-14: #dbdbdb;
  --simple-background-color-darken-24: #c2c2c2;
  --ui-base-color-darken-2: #242731;
  --ui-base-color-darken-4: #1f232b;
  --ui-base-color-darken-5: #1d2028;
  --ui-base-color-darken-6: #1b1e25;
  --ui-base-color-darken-7: #191b22;
  --ui-base-color-darken-8: #17191f;
  --ui-base-color-darken-10: #131419;
  --ui-base-color-darken-12: #0e1014;
  --ui-base-color-darken-13: #0c0d11;
  --ui-base-color-darken-14: #0a0b0e;
  --ui-base-color-darken-20: #000000;
  --ui-highlight-color-darken-2: #595aff;
  --ui-highlight-color-darken-3: #5455ff;
  --ui-highlight-color-darken-5: #4a4bff;
  --ui-highlight-color-darken-8: #3a3bff;
  --ui-primary-color-darken-5: #8ba1bf;
  --ui-primary-color-darken-14: #6d89af;
  --ui-primary-color-darken-40: #364861;
  --ui-secondary-color-darken-8: #c0cdd9;
  --ui-secondary-color-darken-10: #b9c8d5;
  --ui-secondary-color-darken-16: #a6b9c9;
  --ui-secondary-color-darken-18: #a0b4c5;
  --ui-secondary-color-darken-24: #8da5ba;
  --action-button-color-a15: #a2a9bc26;
  --action-button-color-a30: #a2a9bc4d;
  --base-overlay-background-a0: #00000000;
  --base-overlay-background-a10: #0000001a;
  --base-overlay-background-a30: #0000004d;
  --base-overlay-background-a50: #00000080;
  --base-overlay-background-a60: #00000099;
  --base-overlay-background-a70: #000000b3;
  --base-overlay-background-a80: #000000cc;
  --base-overlay-background-a90: #000000e6;
  --base-shadow-color-a10: #0000001a;
  --base-shadow-color-a20: #00000033;
  --base-shadow-color-a25: #00000040;
  --base-shadow-color-a30: #0000004d;
  --base-shadow-color-a35: #00000059;
  --base-shadow-color-a40: #00000066;
  --base-shadow-color-a45: #00000073;
  --base-shadow-color-a60: #00000099;
  --base-shadow-color-a65: #000000a6;
  --base-shadow-color-a75: #000000bf;
  --base-shadow-color-a80: #000000cc;
  --base-shadow-color-a85: #000000d9;
  --black-a45: #00000073;
  --black-a65: #000000a6;
  --black-a85: #000000d9;
  --black-a90: #000000e6;
  --darker-text-color-a15: #dde3ec26;
  --darker-text-color-a30: #dde3ec4d;
  --dark-text-color-a10: #c2cede1a;
  --error-red-a50: #df405a80;
  --error-value-color-a10: #df405a1a;
  --error-value-color-a50: #df405a80;
  --gold-star-a15: #ca8f0426;
  --gold-star-a25: #ca8f0440;
  --gold-star-a30: #ca8f044d;
  --gold-star-a50: #ca8f0480;
  --highlight-text-color-a15: #9697ff26;
  --highlight-text-color-a25: #9697ff40;
  --highlight-text-color-a30: #9697ff4d;
  --highlight-text-color-a40: #9697ff66;
  --lighter-text-color-a15: #1b1e2526;
  --lighter-text-color-a30: #1b1e254d;
  --primary-text-color-a70: #ffffffb3;
  --primary-text-color-a80: #ffffffcc;
  --success-green-a10: #79bd9a1a;
  --success-green-a50: #79bd9a80;
  --ui-base-color-a0: #282c3700;
  --ui-base-color-a15: #282c3726;
  --ui-base-color-a25: #282c3740;
  --ui-base-color-a30: #282c374d;
  --ui-base-color-a85: #282c37d9;
  --ui-base-color-a100: #282c37;
  --ui-base-lighter-color-a60: #60698499;
  --ui-highlight-color-a0: #6364ff00;
  --ui-highlight-color-a10: #6364ff1a;
  --ui-highlight-color-a15: #6364ff26;
  --ui-highlight-color-a23: #6364ff3b;
  --ui-highlight-color-a40: #6364ff66;
  --ui-highlight-color-a50: #6364ff80;
  --ui-secondary-color-a10: #d9e1e81a;
  --ui-secondary-color-a30: #d9e1e84d;
  --ui-secondary-color-a40: #d9e1e866;
  --ui-secondary-color-a50: #d9e1e880;
  --ui-secondary-color-a70: #d9e1e8b3;
  --valid-value-color-a25: #79bd9a40;
  --valid-value-color-a50: #79bd9a80;
  --warning-red-a15: #ff505026;
  --white-a15: #ffffff26;
  --white-a20: #ffffff33;
  --white-a30: #ffffff4d;
  --white-a35: #ffffff59;
  --white-a70: #ffffffb3;
  --white-a75: #ffffffbf;
  --white-a80: #ffffffcc;
  --mix-ui-base-highlight-95: #2b2f41;
  --mix-white-highlight-80: #e0e0ff;
  --mix-ui-base-lighten4-highlight-95: #33384c;
  --mix-ui-base-lighten8-highlight-95: #3b4157;
  --mix-ui-base-lighten12-highlight-80: #484e7b;
  --font-sans-serif: 'mastodon-font-sans-serif';
  --font-display: 'mastodon-font-display';
  --font-monospace: 'mastodon-font-monospace';
  --no-gap-breakpoint: 1175px;
  --media-modal-media-max-width: 100%;
  --media-modal-media-max-height: 80%;
  --ui-avatar-border-size: 8%;
  --dismiss-overlay-width: 4rem;
}

A app/javascript/flavours/glitch/styles/properties-light.css => app/javascript/flavours/glitch/styles/properties-light.css +236 -0
@@ 0,0 1,236 @@
:root {
  --black: #000000;
  --white: #ffffff;
  --red-600: #b7253d;
  --red-500: #df405a;
  --blurple-600: #563acc;
  --blurple-500: #6364ff;
  --blurple-300: #858afa;
  --grey-600: #4e4c5a;
  --grey-100: #dadaf3;
  --success-green: #4a905f;
  --error-red: #df405a;
  --warning-red: #ff5050;
  --gold-star: #ca8f04;
  --red-bookmark: #ff5050;
  --classic-base-color: #282c37;
  --classic-primary-color: #9baec8;
  --classic-secondary-color: #d9e1e8;
  --classic-highlight-color: #6364ff;
  --base-shadow-color: #000000;
  --base-overlay-background: #ffffff;
  --base-border-color: #ffffff;
  --simple-background-color: #ffffff;
  --valid-value-color: #4a905f;
  --error-value-color: #df405a;
  --ui-base-color: #d9e1e8;
  --ui-base-lighter-color: #b0c0cf;
  --ui-primary-color: #9bcbed;
  --ui-secondary-color: #282c37;
  --ui-highlight-color: #6364ff;
  --ui-button-color: #ffffff;
  --ui-button-background-color: #6364ff;
  --ui-button-focus-background-color: #563acc;
  --ui-button-secondary-color: #4e4c5a;
  --ui-button-secondary-border-color: #4e4c5a;
  --ui-button-secondary-focus-background-color: #4e4c5a;
  --ui-button-secondary-focus-color: #ffffff;
  --ui-button-tertiary-color: #6364ff;
  --ui-button-tertiary-border-color: #6364ff;
  --ui-button-tertiary-focus-background-color: #563acc;
  --ui-button-tertiary-focus-color: #ffffff;
  --ui-button-destructive-background-color: #df405a;
  --ui-button-destructive-focus-background-color: #b7253d;
  --primary-text-color: #000000;
  --darker-text-color: #282c37;
  --dark-text-color: #444b5d;
  --secondary-text-color: #282c37;
  --highlight-text-color: #3a3bff;
  --action-button-color: #606984;
  --action-button-focus-color: #a3b6c7;
  --passive-text-color: #ca8f04;
  --active-passive-text-color: #4a905f;
  --inverted-text-color: #000000;
  --lighter-text-color: #282c37;
  --light-text-color: #444b5d;
  --action-button-color-lighten-7: #51596f;
  --action-button-color-lighten-13: #444a5e;
  --darker-text-color-lighten-4: #1f232b;
  --darker-text-color-lighten-7: #191b22;
  --darker-text-color-lighten-8: #17191f;
  --darker-text-color-lighten-10: #131419;
  --dark-text-color-lighten-4: #3b4151;
  --dark-text-color-lighten-7: #353a48;
  --error-red-lighten-4: #dc2f4b;
  --error-red-lighten-12: #c1203b;
  --error-value-color-lighten-12: #c1203b;
  --gold-star-lighten-6: #ac7a03;
  --gold-star-lighten-16: #7a5602;
  --highlight-text-color-lighten-4: #2627ff;
  --highlight-text-color-lighten-6: #1c1dff;
  --highlight-text-color-lighten-8: #1113ff;
  --highlight-text-color-lighten-13: #0002f7;
  --inverted-text-color-lighten-4: #000000;
  --inverted-text-color-lighten-10: #000000;
  --inverted-text-color-lighten-15: #000000;
  --inverted-text-color-lighten-16: #000000;
  --lighter-text-color-lighten-7: #191b22;
  --lighter-text-color-lighten-20: #000000;
  --secondary-text-color-lighten-4: #1f232b;
  --secondary-text-color-lighten-7: #191b22;
  --secondary-text-color-lighten-8: #17191f;
  --ui-base-color-lighten-2: #d3dce4;
  --ui-base-color-lighten-3: #cfd9e2;
  --ui-base-color-lighten-4: #ccd7e0;
  --ui-base-color-lighten-5: #c9d4de;
  --ui-base-color-lighten-6: #c6d2dc;
  --ui-base-color-lighten-8: #c0cdd9;
  --ui-base-color-lighten-11: #b6c5d3;
  --ui-base-color-lighten-12: #b3c3d1;
  --ui-base-color-lighten-13: #b0c0cf;
  --ui-base-color-lighten-14: #adbecd;
  --ui-base-color-lighten-16: #a6b9c9;
  --ui-base-color-lighten-20: #99afc2;
  --ui-base-color-lighten-26: #86a0b6;
  --ui-base-color-lighten-27: #839db4;
  --ui-base-color-lighten-29: #7d98b0;
  --ui-base-color-lighten-30: #7a96ae;
  --ui-base-color-lighten-33: #708ea9;
  --ui-base-color-lighten-34: #6d8ca7;
  --ui-base-color-lighten-50: #496379;
  --ui-base-lighter-color-lighten-4: #a3b6c7;
  --ui-base-lighter-color-lighten-7: #9aaec2;
  --ui-highlight-color-lighten-4: #4f50ff;
  --ui-highlight-color-lighten-8: #3a3bff;
  --ui-highlight-color-lighten-10: #3031ff;
  --ui-highlight-color-lighten-12: #2627ff;
  --ui-primary-color-lighten-8: #78b9e7;
  --ui-primary-color-lighten-12: #67b0e4;
  --ui-primary-color-lighten-20: #459edd;
  --ui-secondary-color-lighten-6: #1b1e25;
  --ui-secondary-color-lighten-8: #17191f;
  --valid-value-color-lighten-8: #3c754d;
  --valid-value-color-lighten-15: #305d3d;
  --warning-red-lighten-12: #ff1313;
  --white-lighten-4: #f5f5f5;
  --white-lighten-7: #ededed;
  --action-button-color-darken-13: #828ba4;
  --darker-text-color-darken-13: #444b5d;
  --highlight-text-color-darken-4: #4f50ff;
  --lighter-text-color-darken-4: #313543;
  --lighter-text-color-darken-7: #373d4c;
  --simple-background-color-darken-2: #ffffff;
  --simple-background-color-darken-8: #ffffff;
  --simple-background-color-darken-14: #ffffff;
  --simple-background-color-darken-24: #ffffff;
  --ui-base-color-darken-2: #dfe6ec;
  --ui-base-color-darken-4: #e6ebf0;
  --ui-base-color-darken-5: #e9eef2;
  --ui-base-color-darken-6: #ecf0f4;
  --ui-base-color-darken-7: #eff3f5;
  --ui-base-color-darken-8: #f2f5f7;
  --ui-base-color-darken-10: #f9fafb;
  --ui-base-color-darken-12: #ffffff;
  --ui-base-color-darken-13: #ffffff;
  --ui-base-color-darken-14: #ffffff;
  --ui-base-color-darken-20: #ffffff;
  --ui-highlight-color-darken-2: #6d6eff;
  --ui-highlight-color-darken-3: #7273ff;
  --ui-highlight-color-darken-5: #7d7dff;
  --ui-highlight-color-darken-8: #8c8dff;
  --ui-primary-color-darken-5: #b1d6f1;
  --ui-primary-color-darken-14: #d8eaf8;
  --ui-primary-color-darken-40: #ffffff;
  --ui-secondary-color-darken-8: #393f4f;
  --ui-secondary-color-darken-10: #3d4455;
  --ui-secondary-color-darken-16: #4a5266;
  --ui-secondary-color-darken-18: #4f576c;
  --ui-secondary-color-darken-24: #5c657e;
  --action-button-color-a15: #60698426;
  --action-button-color-a30: #6069844d;
  --base-overlay-background-a0: #ffffff00;
  --base-overlay-background-a10: #ffffff1a;
  --base-overlay-background-a30: #ffffff4d;
  --base-overlay-background-a50: #ffffff80;
  --base-overlay-background-a60: #ffffff99;
  --base-overlay-background-a70: #ffffffb3;
  --base-overlay-background-a80: #ffffffcc;
  --base-overlay-background-a90: #ffffffe6;
  --base-shadow-color-a10: #0000001a;
  --base-shadow-color-a20: #00000033;
  --base-shadow-color-a25: #00000040;
  --base-shadow-color-a30: #0000004d;
  --base-shadow-color-a35: #00000059;
  --base-shadow-color-a40: #00000066;
  --base-shadow-color-a45: #00000073;
  --base-shadow-color-a60: #00000099;
  --base-shadow-color-a65: #000000a6;
  --base-shadow-color-a75: #000000bf;
  --base-shadow-color-a80: #000000cc;
  --base-shadow-color-a85: #000000d9;
  --black-a45: #00000073;
  --black-a65: #000000a6;
  --black-a85: #000000d9;
  --black-a90: #000000e6;
  --darker-text-color-a15: #282c3726;
  --darker-text-color-a30: #282c374d;
  --dark-text-color-a10: #444b5d1a;
  --error-red-a50: #df405a80;
  --error-value-color-a10: #df405a1a;
  --error-value-color-a50: #df405a80;
  --gold-star-a15: #ca8f0426;
  --gold-star-a25: #ca8f0440;
  --gold-star-a30: #ca8f044d;
  --gold-star-a50: #ca8f0480;
  --highlight-text-color-a15: #3a3bff26;
  --highlight-text-color-a25: #3a3bff40;
  --highlight-text-color-a30: #3a3bff4d;
  --highlight-text-color-a40: #3a3bff66;
  --lighter-text-color-a15: #282c3726;
  --lighter-text-color-a30: #282c374d;
  --primary-text-color-a70: #000000b3;
  --primary-text-color-a80: #000000cc;
  --success-green-a10: #4a905f1a;
  --success-green-a50: #4a905f80;
  --ui-base-color-a0: #d9e1e800;
  --ui-base-color-a15: #d9e1e826;
  --ui-base-color-a25: #d9e1e840;
  --ui-base-color-a30: #d9e1e84d;
  --ui-base-color-a85: #d9e1e8d9;
  --ui-base-color-a100: #d9e1e8;
  --ui-base-lighter-color-a60: #b0c0cf99;
  --ui-highlight-color-a0: #6364ff00;
  --ui-highlight-color-a10: #6364ff1a;
  --ui-highlight-color-a15: #6364ff26;
  --ui-highlight-color-a23: #6364ff3b;
  --ui-highlight-color-a40: #6364ff66;
  --ui-highlight-color-a50: #6364ff80;
  --ui-secondary-color-a10: #282c371a;
  --ui-secondary-color-a30: #282c374d;
  --ui-secondary-color-a40: #282c3766;
  --ui-secondary-color-a50: #282c3780;
  --ui-secondary-color-a70: #282c37b3;
  --valid-value-color-a25: #4a905f40;
  --valid-value-color-a50: #4a905f80;
  --warning-red-a15: #ff505026;
  --white-a15: #ffffff26;
  --white-a20: #ffffff33;
  --white-a30: #ffffff4d;
  --white-a35: #ffffff59;
  --white-a70: #ffffffb3;
  --white-a75: #ffffffbf;
  --white-a80: #ffffffcc;
  --mix-ui-base-highlight-95: #d3dbe9;
  --mix-white-highlight-80: #e0e0ff;
  --mix-ui-base-lighten4-highlight-95: #c7d1e2;
  --mix-ui-base-lighten8-highlight-95: #bbc8db;
  --mix-ui-base-lighten12-highlight-80: #a3b0da;
  --font-sans-serif: 'mastodon-font-sans-serif';
  --font-display: 'mastodon-font-display';
  --font-monospace: 'mastodon-font-monospace';
  --no-gap-breakpoint: 1175px;
  --media-modal-media-max-width: 100%;
  --media-modal-media-max-height: 80%;
  --ui-avatar-border-size: 8%;
  --dismiss-overlay-width: 4rem;
}

A app/javascript/flavours/glitch/styles/properties.css => app/javascript/flavours/glitch/styles/properties.css +236 -0
@@ 0,0 1,236 @@
:root {
  --black: #000000;
  --white: #ffffff;
  --red-600: #b7253d;
  --red-500: #df405a;
  --blurple-600: #563acc;
  --blurple-500: #6364ff;
  --blurple-300: #858afa;
  --grey-600: #4e4c5a;
  --grey-100: #dadaf3;
  --success-green: #79bd9a;
  --error-red: #df405a;
  --warning-red: #ff5050;
  --gold-star: #ca8f04;
  --red-bookmark: #ff5050;
  --classic-base-color: #282c37;
  --classic-primary-color: #9baec8;
  --classic-secondary-color: #d9e1e8;
  --classic-highlight-color: #6364ff;
  --base-shadow-color: #000000;
  --base-overlay-background: #000000;
  --base-border-color: #ffffff;
  --simple-background-color: #ffffff;
  --valid-value-color: #79bd9a;
  --error-value-color: #df405a;
  --ui-base-color: #282c37;
  --ui-base-lighter-color: #606984;
  --ui-primary-color: #9baec8;
  --ui-secondary-color: #d9e1e8;
  --ui-highlight-color: #6364ff;
  --ui-button-color: #ffffff;
  --ui-button-background-color: #6364ff;
  --ui-button-focus-background-color: #563acc;
  --ui-button-secondary-color: #dadaf3;
  --ui-button-secondary-border-color: #dadaf3;
  --ui-button-secondary-focus-background-color: #4e4c5a;
  --ui-button-secondary-focus-color: #ffffff;
  --ui-button-tertiary-color: #858afa;
  --ui-button-tertiary-border-color: #858afa;
  --ui-button-tertiary-focus-background-color: #563acc;
  --ui-button-tertiary-focus-color: #ffffff;
  --ui-button-destructive-background-color: #df405a;
  --ui-button-destructive-focus-background-color: #b7253d;
  --primary-text-color: #ffffff;
  --darker-text-color: #9baec8;
  --dark-text-color: #606984;
  --secondary-text-color: #d9e1e8;
  --highlight-text-color: #8c8dff;
  --action-button-color: #606984;
  --action-button-focus-color: #687390;
  --passive-text-color: #ca8f04;
  --active-passive-text-color: #79bd9a;
  --inverted-text-color: #282c37;
  --lighter-text-color: #606984;
  --light-text-color: #9baec8;
  --action-button-color-lighten-7: #707b97;
  --action-button-color-lighten-13: #828ba4;
  --darker-text-color-lighten-4: #a8b9cf;
  --darker-text-color-lighten-7: #b2c1d5;
  --darker-text-color-lighten-8: #b5c3d6;
  --darker-text-color-lighten-10: #bcc9da;
  --dark-text-color-lighten-4: #687390;
  --dark-text-color-lighten-7: #707b97;
  --error-red-lighten-4: #e25169;
  --error-red-lighten-12: #e87487;
  --error-value-color-lighten-12: #e87487;
  --gold-star-lighten-6: #e8a405;
  --gold-star-lighten-16: #fbbb25;
  --highlight-text-color-lighten-4: #a0a1ff;
  --highlight-text-color-lighten-6: #aaabff;
  --highlight-text-color-lighten-8: #b5b5ff;
  --highlight-text-color-lighten-13: #ceceff;
  --inverted-text-color-lighten-4: #313543;
  --inverted-text-color-lighten-10: #3d4455;
  --inverted-text-color-lighten-15: #484f63;
  --inverted-text-color-lighten-16: #4a5266;
  --lighter-text-color-lighten-7: #707b97;
  --lighter-text-color-lighten-20: #979eb3;
  --secondary-text-color-lighten-4: #e6ebf0;
  --secondary-text-color-lighten-7: #eff3f5;
  --secondary-text-color-lighten-8: #f2f5f7;
  --ui-base-color-lighten-2: #2c313d;
  --ui-base-color-lighten-3: #2e3340;
  --ui-base-color-lighten-4: #313543;
  --ui-base-color-lighten-5: #333846;
  --ui-base-color-lighten-6: #353a49;
  --ui-base-color-lighten-8: #393f4f;
  --ui-base-color-lighten-11: #404657;
  --ui-base-color-lighten-12: #42485a;
  --ui-base-color-lighten-13: #444b5d;
  --ui-base-color-lighten-14: #464d60;
  --ui-base-color-lighten-16: #4a5266;
  --ui-base-color-lighten-20: #535b72;
  --ui-base-color-lighten-26: #606984;
  --ui-base-color-lighten-27: #626c87;
  --ui-base-color-lighten-29: #66718d;
  --ui-base-color-lighten-30: #687390;
  --ui-base-color-lighten-33: #707b97;
  --ui-base-color-lighten-34: #737d99;
  --ui-base-color-lighten-50: #a2a9bc;
  --ui-base-lighter-color-lighten-4: #687390;
  --ui-base-lighter-color-lighten-7: #707b97;
  --ui-highlight-color-lighten-4: #7778ff;
  --ui-highlight-color-lighten-8: #8c8dff;
  --ui-highlight-color-lighten-10: #9697ff;
  --ui-highlight-color-lighten-12: #a0a1ff;
  --ui-primary-color-lighten-8: #b5c3d6;
  --ui-primary-color-lighten-12: #c2cede;
  --ui-primary-color-lighten-20: #dde3ec;
  --ui-secondary-color-lighten-6: #ecf0f4;
  --ui-secondary-color-lighten-8: #f2f5f7;
  --valid-value-color-lighten-8: #94caaf;
  --valid-value-color-lighten-15: #acd6c1;
  --warning-red-lighten-12: #ff8d8d;
  --white-lighten-4: #ffffff;
  --white-lighten-7: #ffffff;
  --action-button-color-darken-13: #444b5d;
  --darker-text-color-darken-13: #708bb0;
  --highlight-text-color-darken-4: #7778ff;
  --lighter-text-color-darken-4: #576078;
  --lighter-text-color-darken-7: #51596f;
  --simple-background-color-darken-2: #fafafa;
  --simple-background-color-darken-8: #ebebeb;
  --simple-background-color-darken-14: #dbdbdb;
  --simple-background-color-darken-24: #c2c2c2;
  --ui-base-color-darken-2: #242731;
  --ui-base-color-darken-4: #1f232b;
  --ui-base-color-darken-5: #1d2028;
  --ui-base-color-darken-6: #1b1e25;
  --ui-base-color-darken-7: #191b22;
  --ui-base-color-darken-8: #17191f;
  --ui-base-color-darken-10: #131419;
  --ui-base-color-darken-12: #0e1014;
  --ui-base-color-darken-13: #0c0d11;
  --ui-base-color-darken-14: #0a0b0e;
  --ui-base-color-darken-20: #000000;
  --ui-highlight-color-darken-2: #595aff;
  --ui-highlight-color-darken-3: #5455ff;
  --ui-highlight-color-darken-5: #4a4bff;
  --ui-highlight-color-darken-8: #3a3bff;
  --ui-primary-color-darken-5: #8ba1bf;
  --ui-primary-color-darken-14: #6d89af;
  --ui-primary-color-darken-40: #364861;
  --ui-secondary-color-darken-8: #c0cdd9;
  --ui-secondary-color-darken-10: #b9c8d5;
  --ui-secondary-color-darken-16: #a6b9c9;
  --ui-secondary-color-darken-18: #a0b4c5;
  --ui-secondary-color-darken-24: #8da5ba;
  --action-button-color-a15: #60698426;
  --action-button-color-a30: #6069844d;
  --base-overlay-background-a0: #00000000;
  --base-overlay-background-a10: #0000001a;
  --base-overlay-background-a30: #0000004d;
  --base-overlay-background-a50: #00000080;
  --base-overlay-background-a60: #00000099;
  --base-overlay-background-a70: #000000b3;
  --base-overlay-background-a80: #000000cc;
  --base-overlay-background-a90: #000000e6;
  --base-shadow-color-a10: #0000001a;
  --base-shadow-color-a20: #00000033;
  --base-shadow-color-a25: #00000040;
  --base-shadow-color-a30: #0000004d;
  --base-shadow-color-a35: #00000059;
  --base-shadow-color-a40: #00000066;
  --base-shadow-color-a45: #00000073;
  --base-shadow-color-a60: #00000099;
  --base-shadow-color-a65: #000000a6;
  --base-shadow-color-a75: #000000bf;
  --base-shadow-color-a80: #000000cc;
  --base-shadow-color-a85: #000000d9;
  --black-a45: #00000073;
  --black-a65: #000000a6;
  --black-a85: #000000d9;
  --black-a90: #000000e6;
  --darker-text-color-a15: #9baec826;
  --darker-text-color-a30: #9baec84d;
  --dark-text-color-a10: #6069841a;
  --error-red-a50: #df405a80;
  --error-value-color-a10: #df405a1a;
  --error-value-color-a50: #df405a80;
  --gold-star-a15: #ca8f0426;
  --gold-star-a25: #ca8f0440;
  --gold-star-a30: #ca8f044d;
  --gold-star-a50: #ca8f0480;
  --highlight-text-color-a15: #8c8dff26;
  --highlight-text-color-a25: #8c8dff40;
  --highlight-text-color-a30: #8c8dff4d;
  --highlight-text-color-a40: #8c8dff66;
  --lighter-text-color-a15: #60698426;
  --lighter-text-color-a30: #6069844d;
  --primary-text-color-a70: #ffffffb3;
  --primary-text-color-a80: #ffffffcc;
  --success-green-a10: #79bd9a1a;
  --success-green-a50: #79bd9a80;
  --ui-base-color-a0: #282c3700;
  --ui-base-color-a15: #282c3726;
  --ui-base-color-a25: #282c3740;
  --ui-base-color-a30: #282c374d;
  --ui-base-color-a85: #282c37d9;
  --ui-base-color-a100: #282c37;
  --ui-base-lighter-color-a60: #60698499;
  --ui-highlight-color-a0: #6364ff00;
  --ui-highlight-color-a10: #6364ff1a;
  --ui-highlight-color-a15: #6364ff26;
  --ui-highlight-color-a23: #6364ff3b;
  --ui-highlight-color-a40: #6364ff66;
  --ui-highlight-color-a50: #6364ff80;
  --ui-secondary-color-a10: #d9e1e81a;
  --ui-secondary-color-a30: #d9e1e84d;
  --ui-secondary-color-a40: #d9e1e866;
  --ui-secondary-color-a50: #d9e1e880;
  --ui-secondary-color-a70: #d9e1e8b3;
  --valid-value-color-a25: #79bd9a40;
  --valid-value-color-a50: #79bd9a80;
  --warning-red-a15: #ff505026;
  --white-a15: #ffffff26;
  --white-a20: #ffffff33;
  --white-a30: #ffffff4d;
  --white-a35: #ffffff59;
  --white-a70: #ffffffb3;
  --white-a75: #ffffffbf;
  --white-a80: #ffffffcc;
  --mix-ui-base-highlight-95: #2b2f41;
  --mix-white-highlight-80: #e0e0ff;
  --mix-ui-base-lighten4-highlight-95: #33384c;
  --mix-ui-base-lighten8-highlight-95: #3b4157;
  --mix-ui-base-lighten12-highlight-80: #484e7b;
  --font-sans-serif: 'mastodon-font-sans-serif';
  --font-display: 'mastodon-font-display';
  --font-monospace: 'mastodon-font-monospace';
  --no-gap-breakpoint: 1175px;
  --media-modal-media-max-width: 100%;
  --media-modal-media-max-height: 80%;
  --ui-avatar-border-size: 8%;
  --dismiss-overlay-width: 4rem;
}

M config/webpack/rules/css.js => config/webpack/rules/css.js +28 -15
@@ 1,22 1,33 @@
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  test: /\.s?css$/i,
  use: [
    MiniCssExtractPlugin.loader,
    {
      loader: "css-loader",
      options: {
        sourceMap: true,
        importLoaders: 2,
      },
const cssLoaders = [
  MiniCssExtractPlugin.loader,
  {
    loader: "css-loader",
    options: {
      sourceMap: true,
      importLoaders: 2,
    },
    {
      loader: "postcss-loader",
      options: {
        sourceMap: true,
      },
  },
  {
    loader: "postcss-loader",
    options: {
      sourceMap: true,
    },
  },
];

// Pure CSS files: skip sass-loader
const cssRule = {
  test: /\.css$/i,
  use: cssLoaders,
};

// SCSS files: include sass-loader
const scssRule = {
  test: /\.scss$/i,
  use: [
    ...cssLoaders,
    {
      loader: "sass-loader",
      options: {


@@ 29,3 40,5 @@ module.exports = {
    },
  ],
};

module.exports = [cssRule, scssRule];

M config/webpack/shared.js => config/webpack/shared.js +1 -1
@@ 100,7 100,7 @@ module.exports = {
  },

  module: {
    rules: Object.keys(rules).map(key => rules[key]),
    rules: Object.keys(rules).flatMap(key => rules[key]),
    strictExportPresence: true,
  },


A scripts/extract-colors.js => scripts/extract-colors.js +334 -0
@@ 0,0 1,334 @@
#!/usr/bin/env node
/**
 * Extract all SCSS variable values and derived colors for each theme.
 * Outputs JSON with pre-calculated hex values for CSS custom properties.
 */
const sass = require("sass");
const path = require("path");

const stylesDir = path.resolve(__dirname, "../app/javascript/flavours/glitch/styles");

// All SCSS variables we need to extract
const baseVars = [
  "black", "white",
  "red-600", "red-500",
  "blurple-600", "blurple-500", "blurple-300",
  "grey-600", "grey-100",
  "success-green", "error-red", "warning-red", "gold-star", "red-bookmark",
  "classic-base-color", "classic-primary-color", "classic-secondary-color", "classic-highlight-color",
  "base-shadow-color", "base-overlay-background", "base-border-color",
  "simple-background-color", "valid-value-color", "error-value-color",
  "ui-base-color", "ui-base-lighter-color", "ui-primary-color", "ui-secondary-color",
  "ui-highlight-color", "ui-button-color",
  "ui-button-background-color", "ui-button-focus-background-color",
  "ui-button-secondary-color", "ui-button-secondary-border-color",
  "ui-button-secondary-focus-background-color", "ui-button-secondary-focus-color",
  "ui-button-tertiary-color", "ui-button-tertiary-border-color",
  "ui-button-tertiary-focus-background-color", "ui-button-tertiary-focus-color",
  "ui-button-destructive-background-color", "ui-button-destructive-focus-background-color",
  "primary-text-color", "darker-text-color", "dark-text-color",
  "secondary-text-color", "highlight-text-color",
  "action-button-color", "action-button-focus-color",
  "passive-text-color", "active-passive-text-color",
  "inverted-text-color", "lighter-text-color", "light-text-color",
];

// Derived colors: [variable, function, amount]
// ALL unique lighten/darken/rgba calls found across the SCSS codebase
const derivedColors = [
  // === lighten calls (61 unique) ===
  // action-button-color
  ["action-button-color", "lighten", 7],
  ["action-button-color", "lighten", 13],
  // darker-text-color
  ["darker-text-color", "lighten", 4],
  ["darker-text-color", "lighten", 7],
  ["darker-text-color", "lighten", 8],
  ["darker-text-color", "lighten", 10],
  // dark-text-color
  ["dark-text-color", "lighten", 4],
  ["dark-text-color", "lighten", 7],
  // error-red
  ["error-red", "lighten", 4],
  ["error-red", "lighten", 12],
  // error-value-color
  ["error-value-color", "lighten", 12],
  // gold-star
  ["gold-star", "lighten", 6],
  ["gold-star", "lighten", 16],
  // highlight-text-color
  ["highlight-text-color", "lighten", 4],
  ["highlight-text-color", "lighten", 6],
  ["highlight-text-color", "lighten", 8],
  ["highlight-text-color", "lighten", 13],
  // inverted-text-color
  ["inverted-text-color", "lighten", 4],
  ["inverted-text-color", "lighten", 10],
  ["inverted-text-color", "lighten", 15],
  ["inverted-text-color", "lighten", 16],
  // lighter-text-color
  ["lighter-text-color", "lighten", 7],
  ["lighter-text-color", "lighten", 20],
  // secondary-text-color
  ["secondary-text-color", "lighten", 4],
  ["secondary-text-color", "lighten", 7],
  ["secondary-text-color", "lighten", 8],
  // ui-base-color
  ["ui-base-color", "lighten", 2],
  ["ui-base-color", "lighten", 3],
  ["ui-base-color", "lighten", 4],
  ["ui-base-color", "lighten", 5],
  ["ui-base-color", "lighten", 6],
  ["ui-base-color", "lighten", 8],
  ["ui-base-color", "lighten", 11],
  ["ui-base-color", "lighten", 12],
  ["ui-base-color", "lighten", 13],
  ["ui-base-color", "lighten", 14],
  ["ui-base-color", "lighten", 16],
  ["ui-base-color", "lighten", 20],
  ["ui-base-color", "lighten", 26],
  ["ui-base-color", "lighten", 27],
  ["ui-base-color", "lighten", 29],
  ["ui-base-color", "lighten", 30],
  ["ui-base-color", "lighten", 33],
  ["ui-base-color", "lighten", 34],
  ["ui-base-color", "lighten", 50],
  // ui-base-lighter-color
  ["ui-base-lighter-color", "lighten", 4],
  ["ui-base-lighter-color", "lighten", 7],
  // ui-highlight-color
  ["ui-highlight-color", "lighten", 4],
  ["ui-highlight-color", "lighten", 8],
  ["ui-highlight-color", "lighten", 10],
  ["ui-highlight-color", "lighten", 12],
  // ui-primary-color
  ["ui-primary-color", "lighten", 8],
  ["ui-primary-color", "lighten", 12],
  ["ui-primary-color", "lighten", 20],
  // ui-secondary-color
  ["ui-secondary-color", "lighten", 6],
  ["ui-secondary-color", "lighten", 8],
  // valid-value-color
  ["valid-value-color", "lighten", 8],
  ["valid-value-color", "lighten", 15],
  // warning-red
  ["warning-red", "lighten", 12],
  // white
  ["white", "lighten", 4],
  ["white", "lighten", 7],

  // === darken calls (33 unique) ===
  // action-button-color
  ["action-button-color", "darken", 13],
  // darker-text-color
  ["darker-text-color", "darken", 13],
  // highlight-text-color
  ["highlight-text-color", "darken", 4],
  // lighter-text-color
  ["lighter-text-color", "darken", 4],
  ["lighter-text-color", "darken", 7],
  // simple-background-color
  ["simple-background-color", "darken", 2],
  ["simple-background-color", "darken", 8],
  ["simple-background-color", "darken", 14],
  ["simple-background-color", "darken", 24],
  // ui-base-color
  ["ui-base-color", "darken", 2],
  ["ui-base-color", "darken", 4],
  ["ui-base-color", "darken", 5],
  ["ui-base-color", "darken", 6],
  ["ui-base-color", "darken", 7],
  ["ui-base-color", "darken", 8],
  ["ui-base-color", "darken", 10],
  ["ui-base-color", "darken", 12],
  ["ui-base-color", "darken", 13],
  ["ui-base-color", "darken", 14],
  ["ui-base-color", "darken", 20],
  // ui-highlight-color
  ["ui-highlight-color", "darken", 2],
  ["ui-highlight-color", "darken", 3],
  ["ui-highlight-color", "darken", 5],
  ["ui-highlight-color", "darken", 8],
  // ui-primary-color
  ["ui-primary-color", "darken", 5],
  ["ui-primary-color", "darken", 14],
  ["ui-primary-color", "darken", 40],
  // ui-secondary-color
  ["ui-secondary-color", "darken", 8],
  ["ui-secondary-color", "darken", 10],
  ["ui-secondary-color", "darken", 16],
  ["ui-secondary-color", "darken", 18],
  ["ui-secondary-color", "darken", 24],

  // === rgba calls (74 unique) ===
  // action-button-color
  ["action-button-color", "rgba", 0.15],
  ["action-button-color", "rgba", 0.3],
  // base-overlay-background
  ["base-overlay-background", "rgba", 0],
  ["base-overlay-background", "rgba", 0.1],
  ["base-overlay-background", "rgba", 0.3],
  ["base-overlay-background", "rgba", 0.5],
  ["base-overlay-background", "rgba", 0.6],
  ["base-overlay-background", "rgba", 0.7],
  ["base-overlay-background", "rgba", 0.8],
  ["base-overlay-background", "rgba", 0.9],
  // base-shadow-color
  ["base-shadow-color", "rgba", 0.1],
  ["base-shadow-color", "rgba", 0.2],
  ["base-shadow-color", "rgba", 0.25],
  ["base-shadow-color", "rgba", 0.3],
  ["base-shadow-color", "rgba", 0.35],
  ["base-shadow-color", "rgba", 0.4],
  ["base-shadow-color", "rgba", 0.45],
  ["base-shadow-color", "rgba", 0.6],
  ["base-shadow-color", "rgba", 0.65],
  ["base-shadow-color", "rgba", 0.75],
  ["base-shadow-color", "rgba", 0.8],
  ["base-shadow-color", "rgba", 0.85],
  // black
  ["black", "rgba", 0.45],
  ["black", "rgba", 0.65],
  ["black", "rgba", 0.85],
  ["black", "rgba", 0.9],
  // darker-text-color
  ["darker-text-color", "rgba", 0.15],
  ["darker-text-color", "rgba", 0.3],
  // dark-text-color
  ["dark-text-color", "rgba", 0.1],
  // error-red
  ["error-red", "rgba", 0.5],
  // error-value-color
  ["error-value-color", "rgba", 0.1],
  ["error-value-color", "rgba", 0.5],
  // gold-star
  ["gold-star", "rgba", 0.15],
  ["gold-star", "rgba", 0.25],
  ["gold-star", "rgba", 0.3],
  ["gold-star", "rgba", 0.5],
  // highlight-text-color
  ["highlight-text-color", "rgba", 0.15],
  ["highlight-text-color", "rgba", 0.25],
  ["highlight-text-color", "rgba", 0.3],
  ["highlight-text-color", "rgba", 0.4],
  // lighter-text-color
  ["lighter-text-color", "rgba", 0.15],
  ["lighter-text-color", "rgba", 0.3],
  // primary-text-color
  ["primary-text-color", "rgba", 0.7],
  ["primary-text-color", "rgba", 0.8],
  // success-green
  ["success-green", "rgba", 0.1],
  ["success-green", "rgba", 0.5],
  // ui-base-color
  ["ui-base-color", "rgba", 0],
  ["ui-base-color", "rgba", 0.15],
  ["ui-base-color", "rgba", 0.25],
  ["ui-base-color", "rgba", 0.3],
  ["ui-base-color", "rgba", 0.85],
  ["ui-base-color", "rgba", 1],
  // ui-base-lighter-color
  ["ui-base-lighter-color", "rgba", 0.6],
  // ui-highlight-color
  ["ui-highlight-color", "rgba", 0],
  ["ui-highlight-color", "rgba", 0.1],
  ["ui-highlight-color", "rgba", 0.15],
  ["ui-highlight-color", "rgba", 0.23],
  ["ui-highlight-color", "rgba", 0.4],
  ["ui-highlight-color", "rgba", 0.5],
  // ui-secondary-color
  ["ui-secondary-color", "rgba", 0.1],
  ["ui-secondary-color", "rgba", 0.3],
  ["ui-secondary-color", "rgba", 0.4],
  ["ui-secondary-color", "rgba", 0.5],
  ["ui-secondary-color", "rgba", 0.7],
  // valid-value-color
  ["valid-value-color", "rgba", 0.25],
  ["valid-value-color", "rgba", 0.5],
  // warning-red
  ["warning-red", "rgba", 0.15],
  // white
  ["white", "rgba", 0.15],
  ["white", "rgba", 0.2],
  ["white", "rgba", 0.3],
  ["white", "rgba", 0.35],
  ["white", "rgba", 0.7],
  ["white", "rgba", 0.75],
  ["white", "rgba", 0.8],
];

// Mix calls: [name, scssExpression]
const mixColors = [
  ["mix-ui-base-highlight-95", "mix($ui-base-color, $ui-highlight-color, 95%)"],
  ["mix-white-highlight-80", "mix($white, $ui-highlight-color, 80%)"],
  ["mix-ui-base-lighten4-highlight-95", "mix(lighten($ui-base-color, 4%), $ui-highlight-color, 95%)"],
  ["mix-ui-base-lighten8-highlight-95", "mix(lighten($ui-base-color, 8%), $ui-highlight-color, 95%)"],
  ["mix-ui-base-lighten12-highlight-80", "mix(lighten($ui-base-color, 12%), $ui-highlight-color, 80%)"],
];

function generateScss(themeImport) {
  let scss = "";
  if (themeImport) {
    scss += `@import '${themeImport}';\n`;
  }
  scss += `@import 'variables';\n\n`;

  // Output base variables
  scss += `:root {\n`;
  for (const v of baseVars) {
    scss += `  --extract-${v}: #{$${v}};\n`;
  }

  // Output derived colors
  for (const [varName, fn, amount] of derivedColors) {
    if (fn === "lighten") {
      scss += `  --extract-${varName}-lighten-${amount}: #{lighten($${varName}, ${amount}%)};\n`;
    } else if (fn === "darken") {
      scss += `  --extract-${varName}-darken-${amount}: #{darken($${varName}, ${amount}%)};\n`;
    } else if (fn === "rgba") {
      scss += `  --extract-${varName}-a${Math.round(amount * 100)}: #{rgba($${varName}, ${amount})};\n`;
    }
  }

  // Output mix colors
  for (const [name, expr] of mixColors) {
    scss += `  --extract-${name}: #{${expr}};\n`;
  }

  scss += `}\n`;

  return scss;
}

function extractValues(css) {
  const values = {};
  const regex = /--extract-([\w-]+):\s*([^;]+);/g;
  let match;
  while ((match = regex.exec(css)) !== null) {
    values[match[1]] = match[2].trim();
  }
  return values;
}

const themes = {
  dark: null,
  light: "mastodon-light/variables",
  contrast: "contrast/variables",
};

const results = {};

for (const [name, themeImport] of Object.entries(themes)) {
  const scss = generateScss(themeImport);
  try {
    const result = sass.compileString(scss, {
      loadPaths: [stylesDir, path.resolve(__dirname, "../app/javascript")],
    });
    results[name] = extractValues(result.css);
  } catch (err) {
    console.error(`Error compiling ${name} theme:`, err.message);
    results[name] = { error: err.message };
  }
}

console.log(JSON.stringify(results, null, 2));