mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-01-12 15:22:55 +01:00
fix(preview): add missing font MIME types to web server
- Added MIME type mappings for .otf, .woff, and .woff2 font formats - Fixed missing break statement after .wav case (was falling through to .mp4) - Fonts now load correctly in editor preview without 404 errors - Resolves OTS parsing error messages in console The web server was already serving project directory files correctly, but browsers were rejecting font files due to missing/incorrect MIME types. Related to TASK-006
This commit is contained in:
@@ -454,6 +454,7 @@ export class MigrationSessionManager extends EventDispatcher {
|
||||
|
||||
/**
|
||||
* Recursively copies a directory and its contents
|
||||
* Uses copyFile to preserve binary files (fonts, images, etc.)
|
||||
*/
|
||||
private async copyDirectoryRecursive(sourcePath: string, targetPath: string): Promise<void> {
|
||||
const entries = await filesystem.listDirectory(sourcePath);
|
||||
@@ -472,9 +473,8 @@ export class MigrationSessionManager extends EventDispatcher {
|
||||
await filesystem.makeDirectory(targetItemPath);
|
||||
await this.copyDirectoryRecursive(sourceItemPath, targetItemPath);
|
||||
} else {
|
||||
// Copy file
|
||||
const content = await filesystem.readFile(sourceItemPath);
|
||||
await filesystem.writeFile(targetItemPath, content);
|
||||
// Copy file using copyFile to preserve binary files correctly
|
||||
await filesystem.copyFile(sourceItemPath, targetItemPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,191 +1,343 @@
|
||||
/* BASE COLORS. DO NOT USE. USE THE THEME COLORS INSTEAD. */
|
||||
/* =============================================================================
|
||||
NOODL DESIGN SYSTEM - COLORS
|
||||
Minimal palette: Red + Black + White
|
||||
============================================================================= */
|
||||
|
||||
:root {
|
||||
/* Success */
|
||||
--base-color-success-100: #e8f9ee;
|
||||
--base-color-success-200: #9ce4b9;
|
||||
--base-color-success-300: #62cb91;
|
||||
--base-color-success-400: #41ac74;
|
||||
--base-color-success-500: #1b8f59;
|
||||
--base-color-success-600: #007442;
|
||||
--base-color-success-700: #005c2c;
|
||||
--base-color-success-800: #004619;
|
||||
--base-color-success-900: #003001;
|
||||
--base-color-success-1000: #001900;
|
||||
/* ---------------------------------------------------------------------------
|
||||
BASE COLORS
|
||||
A deliberately minimal palette - one accent, pure neutrals
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* Error */
|
||||
--base-color-error-100: #fff2f0;
|
||||
--base-color-error-200: #fcc8c0;
|
||||
--base-color-error-300: #f4a196;
|
||||
--base-color-error-400: #e8786b;
|
||||
--base-color-error-500: #cc594f;
|
||||
--base-color-error-600: #af3f38;
|
||||
--base-color-error-700: #942725;
|
||||
--base-color-error-800: #7c0a13;
|
||||
--base-color-error-900: #590000;
|
||||
--base-color-error-1000: #000000;
|
||||
/* Primary - Noodl Red */
|
||||
--base-color-red-100: #fef2f3;
|
||||
--base-color-red-200: #fde3e5;
|
||||
--base-color-red-300: #fbc5c9;
|
||||
--base-color-red-400: #f7969e;
|
||||
--base-color-red-500: #ef5662;
|
||||
--base-color-red-600: #d21f3c;
|
||||
--base-color-red-700: #b91830;
|
||||
--base-color-red-800: #9a1729;
|
||||
--base-color-red-900: #801827;
|
||||
--base-color-red-950: #460a11;
|
||||
|
||||
--base-color-grey-100: #f5f5f5;
|
||||
--base-color-grey-100-transparent: #f5f5f522;
|
||||
--base-color-grey-200: #d4d4d4;
|
||||
--base-color-grey-300: #b8b8b8;
|
||||
--base-color-grey-400: #9a9999;
|
||||
--base-color-grey-500: #7e7d7d;
|
||||
--base-color-grey-600: #666565;
|
||||
--base-color-grey-700: #504f4f;
|
||||
--base-color-grey-800: #3c3c3c;
|
||||
--base-color-grey-900: #292828;
|
||||
--base-color-grey-1000: #151414;
|
||||
--base-color-grey-1000-transparent: #151414b3;
|
||||
--base-color-grey-1000-transparent-2: #00000069;
|
||||
/* Neutrals - Pure black to white, no color tint */
|
||||
--base-color-neutral-0: #000000;
|
||||
--base-color-neutral-50: #0a0a0a;
|
||||
--base-color-neutral-100: #121212;
|
||||
--base-color-neutral-200: #1a1a1a;
|
||||
--base-color-neutral-300: #262626;
|
||||
--base-color-neutral-400: #333333;
|
||||
--base-color-neutral-500: #525252;
|
||||
--base-color-neutral-600: #737373;
|
||||
--base-color-neutral-700: #a3a3a3;
|
||||
--base-color-neutral-800: #d4d4d4;
|
||||
--base-color-neutral-900: #e5e5e5;
|
||||
--base-color-neutral-950: #f5f5f5;
|
||||
--base-color-neutral-1000: #ffffff;
|
||||
|
||||
--base-color-teal-100: #f0f7f9;
|
||||
--base-color-teal-200: #b6dbe3;
|
||||
--base-color-teal-300: #7ec2cf;
|
||||
--base-color-teal-400: #2ba7ba;
|
||||
--base-color-teal-500: #008a9d;
|
||||
--base-color-teal-600: #006f82;
|
||||
--base-color-teal-700: #005769;
|
||||
--base-color-teal-800: #004153;
|
||||
--base-color-teal-900: #002c3d;
|
||||
--base-color-teal-1000: #001623;
|
||||
/* Transparent variants */
|
||||
--base-color-black-transparent-90: rgba(0, 0, 0, 0.9);
|
||||
--base-color-black-transparent-80: rgba(0, 0, 0, 0.8);
|
||||
--base-color-black-transparent-50: rgba(0, 0, 0, 0.5);
|
||||
--base-color-white-transparent-10: rgba(255, 255, 255, 0.1);
|
||||
--base-color-white-transparent-15: rgba(255, 255, 255, 0.15);
|
||||
--base-color-white-transparent-50: rgba(255, 255, 255, 0.5);
|
||||
|
||||
--base-color-yellow-100: #fff4e2;
|
||||
--base-color-yellow-200: #fccd75;
|
||||
--base-color-yellow-300: #e5ae32;
|
||||
--base-color-yellow-400: #c39108;
|
||||
--base-color-yellow-500: #a37500;
|
||||
--base-color-yellow-600: #875d00;
|
||||
--base-color-yellow-700: #6d4800;
|
||||
--base-color-yellow-800: #583400;
|
||||
--base-color-yellow-900: #431e00;
|
||||
--base-color-yellow-1000: #330000;
|
||||
/* ---------------------------------------------------------------------------
|
||||
SEMANTIC COLORS (Status indicators)
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
--base-color-node-pink-100: #f9f4f6;
|
||||
--base-color-node-pink-200: #e4cfd9;
|
||||
--base-color-node-pink-300: #d0adbe;
|
||||
--base-color-node-pink-400: #bb8ba3;
|
||||
--base-color-node-pink-500: #a66b8b;
|
||||
--base-color-node-pink-600: #944e74;
|
||||
--base-color-node-pink-700: #7e3660;
|
||||
--base-color-node-pink-800: #67214b;
|
||||
--base-color-node-pink-900: #500837;
|
||||
--base-color-node-pink-1000: #30001b;
|
||||
/* Success - Keeping a green for semantic meaning */
|
||||
--base-color-success-100: #ecfdf5;
|
||||
--base-color-success-200: #a7f3d0;
|
||||
--base-color-success-300: #6ee7b7;
|
||||
--base-color-success-400: #34d399;
|
||||
--base-color-success-500: #10b981;
|
||||
--base-color-success-600: #059669;
|
||||
--base-color-success-700: #047857;
|
||||
--base-color-success-800: #065f46;
|
||||
--base-color-success-900: #064e3b;
|
||||
--base-color-success-1000: #022c22;
|
||||
|
||||
--base-color-node-purple-100: #f8f5f9;
|
||||
--base-color-node-purple-200: #dbd0e4;
|
||||
--base-color-node-purple-300: #c2b0d1;
|
||||
--base-color-node-purple-400: #a98fbe;
|
||||
--base-color-node-purple-500: #8f71ab;
|
||||
--base-color-node-purple-600: #79559b;
|
||||
--base-color-node-purple-700: #643d8b;
|
||||
--base-color-node-purple-800: #4e2877;
|
||||
--base-color-node-purple-900: #371360;
|
||||
--base-color-node-purple-1000: #1d0047;
|
||||
/* Error - Uses the brand red */
|
||||
--base-color-error-100: var(--base-color-red-100);
|
||||
--base-color-error-200: var(--base-color-red-200);
|
||||
--base-color-error-300: var(--base-color-red-300);
|
||||
--base-color-error-400: var(--base-color-red-400);
|
||||
--base-color-error-500: var(--base-color-red-500);
|
||||
--base-color-error-600: var(--base-color-red-600);
|
||||
--base-color-error-700: var(--base-color-red-700);
|
||||
--base-color-error-800: var(--base-color-red-800);
|
||||
--base-color-error-900: var(--base-color-red-900);
|
||||
--base-color-error-1000: var(--base-color-red-950);
|
||||
|
||||
--base-color-node-green-100: #f6f6f3;
|
||||
--base-color-node-green-200: #d2d6c5;
|
||||
--base-color-node-green-300: #b3ba9e;
|
||||
--base-color-node-green-400: #939e77;
|
||||
--base-color-node-green-500: #758353;
|
||||
--base-color-node-green-600: #5b6a37;
|
||||
--base-color-node-green-700: #465524;
|
||||
--base-color-node-green-800: #314110;
|
||||
--base-color-node-green-900: #1f2c00;
|
||||
--base-color-node-green-1000: #0c1700;
|
||||
/* ---------------------------------------------------------------------------
|
||||
NODE TYPE COLORS
|
||||
Subtle variations to distinguish node types on canvas
|
||||
Using desaturated colors so they don't compete with the red accent
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* Node-Pink - For Custom/User nodes */
|
||||
--base-color-node-pink-100: #fdf2f8;
|
||||
--base-color-node-pink-200: #f5d0e5;
|
||||
--base-color-node-pink-300: #e8a8ca;
|
||||
--base-color-node-pink-400: #d87caa;
|
||||
--base-color-node-pink-500: #c2578a;
|
||||
--base-color-node-pink-600: #a63d6f;
|
||||
--base-color-node-pink-700: #862d56;
|
||||
--base-color-node-pink-800: #6b2445;
|
||||
--base-color-node-pink-900: #521c35;
|
||||
--base-color-node-pink-1000: #2d0e1c;
|
||||
|
||||
/* Node-Purple - For Component nodes */
|
||||
--base-color-node-purple-100: #f8f5fa;
|
||||
--base-color-node-purple-200: #e8dff0;
|
||||
--base-color-node-purple-300: #d4c4e3;
|
||||
--base-color-node-purple-400: #b8a0cf;
|
||||
--base-color-node-purple-500: #9a7bb8;
|
||||
--base-color-node-purple-600: #7d5a9e;
|
||||
--base-color-node-purple-700: #624382;
|
||||
--base-color-node-purple-800: #4b3366;
|
||||
--base-color-node-purple-900: #37264b;
|
||||
--base-color-node-purple-1000: #1e1429;
|
||||
|
||||
/* Node-Green - For Data nodes */
|
||||
--base-color-node-green-100: #f4f7f4;
|
||||
--base-color-node-green-200: #d8e5d8;
|
||||
--base-color-node-green-300: #b5cfb5;
|
||||
--base-color-node-green-400: #8eb58e;
|
||||
--base-color-node-green-500: #6a996a;
|
||||
--base-color-node-green-600: #4d7d4d;
|
||||
--base-color-node-green-700: #3a613a;
|
||||
--base-color-node-green-800: #2c4a2c;
|
||||
--base-color-node-green-900: #203520;
|
||||
--base-color-node-green-1000: #111c11;
|
||||
|
||||
/* Node-Gray - For Logic nodes */
|
||||
--base-color-node-grey-100: #f5f5f5;
|
||||
--base-color-node-grey-200: #d3d4d6;
|
||||
--base-color-node-grey-300: #b6b7bb;
|
||||
--base-color-node-grey-400: #97999f;
|
||||
--base-color-node-grey-500: #7b7d85;
|
||||
--base-color-node-grey-600: #62656e;
|
||||
--base-color-node-grey-700: #4c4f59;
|
||||
--base-color-node-grey-800: #373b45;
|
||||
--base-color-node-grey-900: #252832;
|
||||
--base-color-node-grey-1000: #11141d;
|
||||
--base-color-node-grey-200: #e0e0e0;
|
||||
--base-color-node-grey-300: #c2c2c2;
|
||||
--base-color-node-grey-400: #9e9e9e;
|
||||
--base-color-node-grey-500: #757575;
|
||||
--base-color-node-grey-600: #5c5c5c;
|
||||
--base-color-node-grey-700: #454545;
|
||||
--base-color-node-grey-800: #333333;
|
||||
--base-color-node-grey-900: #212121;
|
||||
--base-color-node-grey-1000: #0d0d0d;
|
||||
|
||||
--base-color-node-blue-100: #f5f6f8;
|
||||
--base-color-node-blue-200: #cfd5de;
|
||||
--base-color-node-blue-300: #adb8c6;
|
||||
--base-color-node-blue-400: #8b9bae;
|
||||
--base-color-node-blue-500: #6b7f98;
|
||||
--base-color-node-blue-600: #4d6784;
|
||||
--base-color-node-blue-700: #315272;
|
||||
--base-color-node-blue-800: #173e5d;
|
||||
--base-color-node-blue-900: #002a47;
|
||||
--base-color-node-blue-1000: #00142f;
|
||||
/* Node-Blue - For Visual nodes */
|
||||
--base-color-node-blue-100: #f4f6f8;
|
||||
--base-color-node-blue-200: #dce3eb;
|
||||
--base-color-node-blue-300: #bccad9;
|
||||
--base-color-node-blue-400: #96adc2;
|
||||
--base-color-node-blue-500: #7090a9;
|
||||
--base-color-node-blue-600: #53758f;
|
||||
--base-color-node-blue-700: #3e5a72;
|
||||
--base-color-node-blue-800: #2f4557;
|
||||
--base-color-node-blue-900: #22323f;
|
||||
--base-color-node-blue-1000: #121b22;
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
LEGACY ALIASES - For backwards compatibility
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* Grey -> Neutral */
|
||||
--base-color-grey-100: var(--base-color-neutral-950);
|
||||
--base-color-grey-100-transparent: var(--base-color-white-transparent-10);
|
||||
--base-color-grey-200: var(--base-color-neutral-800);
|
||||
--base-color-grey-300: var(--base-color-neutral-700);
|
||||
--base-color-grey-400: var(--base-color-neutral-600);
|
||||
--base-color-grey-500: var(--base-color-neutral-500);
|
||||
--base-color-grey-600: var(--base-color-neutral-400);
|
||||
--base-color-grey-700: var(--base-color-neutral-300);
|
||||
--base-color-grey-800: var(--base-color-neutral-200);
|
||||
--base-color-grey-900: var(--base-color-neutral-100);
|
||||
--base-color-grey-1000: var(--base-color-neutral-50);
|
||||
--base-color-grey-1000-transparent: var(--base-color-black-transparent-80);
|
||||
--base-color-grey-1000-transparent-2: var(--base-color-black-transparent-50);
|
||||
|
||||
/* Teal -> Neutral (secondary is now white/gray) */
|
||||
--base-color-teal-100: var(--base-color-neutral-1000);
|
||||
--base-color-teal-200: var(--base-color-neutral-900);
|
||||
--base-color-teal-300: var(--base-color-neutral-800);
|
||||
--base-color-teal-400: var(--base-color-neutral-700);
|
||||
--base-color-teal-500: var(--base-color-neutral-600);
|
||||
--base-color-teal-600: var(--base-color-neutral-500);
|
||||
--base-color-teal-700: var(--base-color-neutral-400);
|
||||
--base-color-teal-800: var(--base-color-neutral-300);
|
||||
--base-color-teal-900: var(--base-color-neutral-200);
|
||||
--base-color-teal-1000: var(--base-color-neutral-100);
|
||||
|
||||
/* Yellow -> Red (primary is now red) */
|
||||
--base-color-yellow-100: var(--base-color-red-100);
|
||||
--base-color-yellow-200: var(--base-color-red-200);
|
||||
--base-color-yellow-300: var(--base-color-red-400);
|
||||
--base-color-yellow-400: var(--base-color-red-500);
|
||||
--base-color-yellow-500: var(--base-color-red-600);
|
||||
--base-color-yellow-600: var(--base-color-red-700);
|
||||
--base-color-yellow-700: var(--base-color-red-800);
|
||||
--base-color-yellow-800: var(--base-color-red-900);
|
||||
--base-color-yellow-900: var(--base-color-red-950);
|
||||
--base-color-yellow-1000: var(--base-color-red-950);
|
||||
}
|
||||
|
||||
/* THEME COLOR TOKENS. USE THESE. */
|
||||
|
||||
/* =============================================================================
|
||||
THEME COLOR TOKENS - USE THESE IN COMPONENTS
|
||||
============================================================================= */
|
||||
|
||||
:root {
|
||||
/* ---------------------------------------------------------------------------
|
||||
BACKGROUNDS
|
||||
Pure blacks with subtle elevation through lightness
|
||||
--------------------------------------------------------------------------- */
|
||||
--theme-color-bg-0: #000000;
|
||||
--theme-color-bg-1: var(--base-color-grey-1000);
|
||||
--theme-color-bg-1-transparent: var(--base-color-grey-1000-transparent);
|
||||
--theme-color-bg-1-transparent-2: var(--base-color-grey-1000-transparent-2);
|
||||
--theme-color-bg-2: var(--base-color-grey-900);
|
||||
--theme-color-bg-3: var(--base-color-grey-800);
|
||||
--theme-color-bg-4: var(--base-color-grey-700);
|
||||
--theme-color-bg-1: var(--base-color-neutral-50);
|
||||
--theme-color-bg-1-transparent: var(--base-color-black-transparent-80);
|
||||
--theme-color-bg-1-transparent-2: var(--base-color-black-transparent-50);
|
||||
--theme-color-bg-2: var(--base-color-neutral-100);
|
||||
--theme-color-bg-3: var(--base-color-neutral-200);
|
||||
--theme-color-bg-4: var(--base-color-neutral-300);
|
||||
--theme-color-bg-5: var(--base-color-neutral-400);
|
||||
--theme-color-bg-hover: var(--base-color-white-transparent-10);
|
||||
|
||||
--theme-color-fg-highlight: var(--base-color-grey-100);
|
||||
--theme-color-fg-default-contrast: var(--base-color-grey-200);
|
||||
--theme-color-fg-default: var(--base-color-grey-300);
|
||||
--theme-color-fg-default-shy: var(--base-color-grey-400);
|
||||
--theme-color-fg-muted: var(--base-color-grey-500);
|
||||
--theme-color-fg-transparent: var(--base-color-grey-100-transparent);
|
||||
/* ---------------------------------------------------------------------------
|
||||
FOREGROUNDS
|
||||
Pure whites with subtle hierarchy
|
||||
--------------------------------------------------------------------------- */
|
||||
--theme-color-fg-highlight: #ffffff;
|
||||
--theme-color-fg-default-contrast: var(--base-color-neutral-900);
|
||||
--theme-color-fg-default: var(--base-color-neutral-800);
|
||||
--theme-color-fg-default-shy: var(--base-color-neutral-700);
|
||||
--theme-color-fg-muted: var(--base-color-neutral-600);
|
||||
--theme-color-fg-transparent: var(--base-color-white-transparent-15);
|
||||
|
||||
--theme-color-primary: var(--base-color-yellow-300);
|
||||
--theme-color-primary-highlight: var(--base-color-yellow-200);
|
||||
--theme-color-primary-dim: var(--base-color-yellow-500);
|
||||
--theme-color-on-primary: var(--base-color-grey-1000);
|
||||
/* ---------------------------------------------------------------------------
|
||||
PRIMARY - Noodl Red
|
||||
The one accent color - used sparingly for maximum impact
|
||||
--------------------------------------------------------------------------- */
|
||||
--theme-color-primary: #d21f3c;
|
||||
--theme-color-primary-highlight: var(--base-color-red-500);
|
||||
--theme-color-primary-dim: var(--base-color-red-800);
|
||||
--theme-color-on-primary: #ffffff;
|
||||
|
||||
--theme-color-secondary: var(--base-color-teal-700);
|
||||
--theme-color-secondary-dim: var(--base-color-teal-800);
|
||||
--theme-color-secondary-highlight: var(--base-color-teal-600);
|
||||
--theme-color-on-secondary: var(--base-color-teal-100);
|
||||
--theme-color-secondary-bright: var(--base-color-teal-500);
|
||||
--theme-color-secondary-as-fg: var(--base-color-teal-300);
|
||||
/* ---------------------------------------------------------------------------
|
||||
SECONDARY - White/Light
|
||||
For secondary actions, using white as the complement to red
|
||||
--------------------------------------------------------------------------- */
|
||||
--theme-color-secondary: #ffffff;
|
||||
--theme-color-secondary-dim: var(--base-color-neutral-700);
|
||||
--theme-color-secondary-highlight: #ffffff;
|
||||
--theme-color-secondary-bright: #ffffff;
|
||||
--theme-color-secondary-as-fg: var(--base-color-neutral-800);
|
||||
--theme-color-on-secondary: var(--base-color-neutral-100);
|
||||
|
||||
--theme-color-node-data-1: var(--base-color-node-green-800);
|
||||
--theme-color-node-data-2: var(--base-color-node-green-700);
|
||||
--theme-color-node-data-3: var(--base-color-node-green-600);
|
||||
--theme-color-node-data-dim: var(--base-color-node-green-1000);
|
||||
/* ---------------------------------------------------------------------------
|
||||
NODE COLORS
|
||||
Muted, desaturated to not compete with the red accent
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
--theme-color-node-visual-1: var(--base-color-node-blue-800);
|
||||
--theme-color-node-visual-2: var(--base-color-node-blue-700);
|
||||
--theme-color-node-visual-2-highlight: var(--base-color-node-blue-600);
|
||||
--theme-color-node-visual-highlight: var(--base-color-node-blue-100);
|
||||
--theme-color-node-visual-default: var(--base-color-node-blue-200);
|
||||
--theme-color-node-visual-shy: var(--base-color-node-blue-300);
|
||||
--theme-color-node-visual-dim: var(--base-color-node-blue-1000);
|
||||
--theme-color-node-visual-3: var(--base-color-node-blue-600);
|
||||
/* Data nodes - Muted Green */
|
||||
--theme-color-node-data-1: var(--base-color-node-green-700);
|
||||
--theme-color-node-data-2: var(--base-color-node-green-600);
|
||||
--theme-color-node-data-3: var(--base-color-node-green-500);
|
||||
--theme-color-node-data-dim: var(--base-color-node-green-900);
|
||||
|
||||
--theme-color-node-custom-1: var(--base-color-node-pink-800);
|
||||
--theme-color-node-custom-2: var(--base-color-node-pink-700);
|
||||
--theme-color-node-custom-3: var(--base-color-node-pink-600);
|
||||
--theme-color-node-custom-dim: var(--base-color-node-pink-1000);
|
||||
/* Visual nodes - Muted Blue */
|
||||
--theme-color-node-visual-1: var(--base-color-node-blue-700);
|
||||
--theme-color-node-visual-2: var(--base-color-node-blue-600);
|
||||
--theme-color-node-visual-2-highlight: var(--base-color-node-blue-500);
|
||||
--theme-color-node-visual-highlight: var(--base-color-node-blue-200);
|
||||
--theme-color-node-visual-default: var(--base-color-node-blue-300);
|
||||
--theme-color-node-visual-shy: var(--base-color-node-blue-400);
|
||||
--theme-color-node-visual-dim: var(--base-color-node-blue-900);
|
||||
|
||||
--theme-color-node-logic-1: var(--base-color-node-grey-800);
|
||||
--theme-color-node-logic-2: var(--base-color-node-grey-700);
|
||||
--theme-color-node-logic-3: var(--base-color-node-grey-600);
|
||||
--theme-color-node-logic-dim: var(--base-color-node-grey-1000);
|
||||
/* Custom nodes - Muted Pink */
|
||||
--theme-color-node-custom-1: var(--base-color-node-pink-700);
|
||||
--theme-color-node-custom-2: var(--base-color-node-pink-600);
|
||||
--theme-color-node-custom-dim: var(--base-color-node-pink-900);
|
||||
|
||||
--theme-color-node-component-1: var(--base-color-node-purple-800);
|
||||
--theme-color-node-component-2: var(--base-color-node-purple-700);
|
||||
--theme-color-node-component-3: var(--base-color-node-purple-600);
|
||||
--theme-color-node-component-dim: var(--base-color-node-purple-1000);
|
||||
/* Logic nodes - Gray */
|
||||
--theme-color-node-logic-1: var(--base-color-node-grey-700);
|
||||
--theme-color-node-logic-2: var(--base-color-node-grey-600);
|
||||
--theme-color-node-logic-dim: var(--base-color-node-grey-900);
|
||||
|
||||
--theme-color-success: #5bf59e;
|
||||
--theme-color-success-light: var(--base-color-success-300);
|
||||
--theme-color-success-dark: var(--base-color-success-600);
|
||||
--theme-color-notice: var(--base-color-yellow-300);
|
||||
--theme-color-notice-dark: var(--base-color-yellow-400);
|
||||
/* Component nodes - Muted Purple */
|
||||
--theme-color-node-component-1: var(--base-color-node-purple-700);
|
||||
--theme-color-node-component-2: var(--base-color-node-purple-600);
|
||||
--theme-color-node-component-dim: var(--base-color-node-purple-900);
|
||||
|
||||
--theme-color-danger-dark: var(--base-color-error-600);
|
||||
--theme-color-danger: var(--base-color-error-400);
|
||||
--theme-color-danger-light: var(--base-color-error-300);
|
||||
/* ---------------------------------------------------------------------------
|
||||
STATUS COLORS
|
||||
Success stays green, everything else maps to the palette
|
||||
--------------------------------------------------------------------------- */
|
||||
--theme-color-success: var(--base-color-success-400);
|
||||
--theme-color-success-dim: var(--base-color-success-600);
|
||||
--theme-color-success-bg: var(--base-color-success-900);
|
||||
|
||||
--theme-color-signal: var(--base-color-yellow-300);
|
||||
--theme-color-data: var(--base-color-teal-600);
|
||||
--theme-color-notice: var(--base-color-red-400);
|
||||
--theme-color-notice-dim: var(--base-color-red-600);
|
||||
--theme-color-notice-bg: var(--base-color-red-950);
|
||||
|
||||
--theme-color-danger: var(--base-color-red-500);
|
||||
--theme-color-danger-light: var(--base-color-red-400);
|
||||
--theme-color-danger-dim: var(--base-color-red-700);
|
||||
--theme-color-danger-bg: var(--base-color-red-950);
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
CONNECTION COLORS
|
||||
--------------------------------------------------------------------------- */
|
||||
--theme-color-signal: var(--base-color-red-500);
|
||||
--theme-color-data: var(--base-color-neutral-700);
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
BORDERS
|
||||
Subtle white borders for dark backgrounds
|
||||
--------------------------------------------------------------------------- */
|
||||
--theme-color-border-default: var(--base-color-neutral-300);
|
||||
--theme-color-border-subtle: var(--base-color-neutral-200);
|
||||
--theme-color-border-strong: var(--base-color-neutral-400);
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
FOCUS
|
||||
Red focus ring for accessibility
|
||||
--------------------------------------------------------------------------- */
|
||||
--theme-color-focus-ring: #d21f3c;
|
||||
--theme-color-focus-ring-offset: var(--base-color-neutral-50);
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
FUTURE: LIGHT THEME
|
||||
=============================================================================
|
||||
|
||||
.theme-light {
|
||||
--theme-color-bg-0: #ffffff;
|
||||
--theme-color-bg-1: var(--base-color-neutral-950);
|
||||
--theme-color-bg-1-transparent: rgba(255, 255, 255, 0.9);
|
||||
--theme-color-bg-1-transparent-2: rgba(255, 255, 255, 0.5);
|
||||
--theme-color-bg-2: #ffffff;
|
||||
--theme-color-bg-3: var(--base-color-neutral-900);
|
||||
--theme-color-bg-4: var(--base-color-neutral-800);
|
||||
--theme-color-bg-5: var(--base-color-neutral-700);
|
||||
--theme-color-bg-hover: rgba(0, 0, 0, 0.04);
|
||||
|
||||
--theme-color-fg-highlight: #000000;
|
||||
--theme-color-fg-default-contrast: var(--base-color-neutral-100);
|
||||
--theme-color-fg-default: var(--base-color-neutral-200);
|
||||
--theme-color-fg-default-shy: var(--base-color-neutral-400);
|
||||
--theme-color-fg-muted: var(--base-color-neutral-500);
|
||||
|
||||
--theme-color-primary: #d21f3c;
|
||||
--theme-color-on-primary: #ffffff;
|
||||
|
||||
--theme-color-secondary: var(--base-color-neutral-100);
|
||||
--theme-color-on-secondary: #ffffff;
|
||||
|
||||
--theme-color-border-default: var(--base-color-neutral-800);
|
||||
--theme-color-border-subtle: var(--base-color-neutral-900);
|
||||
--theme-color-border-strong: var(--base-color-neutral-700);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
@@ -2,10 +2,7 @@ import path from 'node:path';
|
||||
import { GitStore } from '@noodl-store/GitStore';
|
||||
import Store from 'electron-store';
|
||||
import { isEqual } from 'underscore';
|
||||
import {
|
||||
RequestGitAccountFuncReturn,
|
||||
setRequestGitAccount
|
||||
} from '@noodl/git/src/core/trampoline/trampoline-askpass-handler';
|
||||
import { setRequestGitAccount } from '@noodl/git/src/core/trampoline/trampoline-askpass-handler';
|
||||
import { filesystem, platform } from '@noodl/platform';
|
||||
|
||||
import { ProjectModel } from '@noodl-models/projectmodel';
|
||||
@@ -44,9 +41,17 @@ export class LocalProjectsModel extends Model {
|
||||
name: 'recently_opened_project'
|
||||
});
|
||||
|
||||
/**
|
||||
* Persistent store for runtime version cache
|
||||
* Survives app restarts to avoid re-detecting runtime on every launch
|
||||
*/
|
||||
private runtimeCacheStore = new Store({
|
||||
name: 'project_runtime_cache'
|
||||
});
|
||||
|
||||
/**
|
||||
* Cache for runtime version info - keyed by project directory path
|
||||
* Not persisted, re-detected on each app session
|
||||
* Loaded from persistent store on init, saved on updates
|
||||
*/
|
||||
private runtimeInfoCache: Map<string, RuntimeVersionInfo> = new Map();
|
||||
|
||||
@@ -56,6 +61,9 @@ export class LocalProjectsModel extends Model {
|
||||
private detectingProjects: Set<string> = new Set();
|
||||
|
||||
async fetch() {
|
||||
// Load runtime cache from persistent store
|
||||
this.loadRuntimeCache();
|
||||
|
||||
// Fetch projects from local storage and verify project folders
|
||||
const folders = (this.recentProjectsStore.get('recentProjects') || []) as ProjectItem[];
|
||||
|
||||
@@ -101,7 +109,7 @@ export class LocalProjectsModel extends Model {
|
||||
loadProject(projectEntry: ProjectItem) {
|
||||
tracker.track('Load Local Project');
|
||||
|
||||
return new Promise<ProjectModel>((resolve, reject) => {
|
||||
return new Promise<ProjectModel>((resolve) => {
|
||||
projectFromDirectory(projectEntry.retainedProjectDirectory, (project) => {
|
||||
if (!project) {
|
||||
resolve(null);
|
||||
@@ -325,6 +333,33 @@ export class LocalProjectsModel extends Model {
|
||||
// Runtime Version Detection Methods
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Load runtime cache from persistent store
|
||||
*/
|
||||
private loadRuntimeCache(): void {
|
||||
try {
|
||||
const cached = this.runtimeCacheStore.get('cache') as Record<string, RuntimeVersionInfo> | undefined;
|
||||
if (cached) {
|
||||
this.runtimeInfoCache = new Map(Object.entries(cached));
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Failed to load runtime cache:', error);
|
||||
this.runtimeInfoCache = new Map();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save runtime cache to persistent store
|
||||
*/
|
||||
private saveRuntimeCache(): void {
|
||||
try {
|
||||
const cacheObject = Object.fromEntries(this.runtimeInfoCache.entries());
|
||||
this.runtimeCacheStore.set('cache', cacheObject);
|
||||
} catch (error) {
|
||||
console.error('Failed to save runtime cache:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached runtime info for a project, or null if not yet detected
|
||||
* @param projectPath - The project directory path
|
||||
@@ -392,6 +427,7 @@ export class LocalProjectsModel extends Model {
|
||||
try {
|
||||
const runtimeInfo = await detectRuntimeVersion(projectPath);
|
||||
this.runtimeInfoCache.set(projectPath, runtimeInfo);
|
||||
this.saveRuntimeCache(); // Persist to disk
|
||||
this.notifyListeners('runtimeDetectionComplete', projectPath, runtimeInfo);
|
||||
return runtimeInfo;
|
||||
} catch (error) {
|
||||
@@ -402,6 +438,7 @@ export class LocalProjectsModel extends Model {
|
||||
indicators: ['Detection error: ' + (error instanceof Error ? error.message : 'Unknown error')]
|
||||
};
|
||||
this.runtimeInfoCache.set(projectPath, fallback);
|
||||
this.saveRuntimeCache(); // Persist to disk
|
||||
this.notifyListeners('runtimeDetectionComplete', projectPath, fallback);
|
||||
return fallback;
|
||||
} finally {
|
||||
@@ -442,6 +479,16 @@ export class LocalProjectsModel extends Model {
|
||||
*/
|
||||
clearRuntimeCache(projectPath: string): void {
|
||||
this.runtimeInfoCache.delete(projectPath);
|
||||
this.saveRuntimeCache(); // Persist the change
|
||||
this.notifyListeners('runtimeCacheCleared', projectPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all runtime cache (useful for debugging or forcing re-detection)
|
||||
*/
|
||||
clearAllRuntimeCache(): void {
|
||||
this.runtimeInfoCache.clear();
|
||||
this.saveRuntimeCache();
|
||||
this.notifyListeners('allRuntimeCacheCleared');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ function getContentType(request) {
|
||||
break;
|
||||
case '.wav':
|
||||
contentType = 'audio/wav';
|
||||
// eslint-disable-next-line no-fallthrough
|
||||
break;
|
||||
case '.mp4':
|
||||
case '.m4v':
|
||||
contentType = 'video/mp4';
|
||||
@@ -316,6 +316,15 @@ function getContentType(request) {
|
||||
case '.ttf':
|
||||
contentType = 'font/ttf';
|
||||
break;
|
||||
case '.otf':
|
||||
contentType = 'font/otf';
|
||||
break;
|
||||
case '.woff':
|
||||
contentType = 'font/woff';
|
||||
break;
|
||||
case '.woff2':
|
||||
contentType = 'font/woff2';
|
||||
break;
|
||||
}
|
||||
|
||||
return contentType;
|
||||
|
||||
Reference in New Issue
Block a user