@collagejs/core 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  > Micro library for framework-agnostic micro-frontends
4
4
 
5
- **🚧🚧 YOU'RE EARLY. WORK IN PROGRESS... ETA: Early January, 2026 🚧🚧**
5
+ **🚧🚧 YOU'RE EARLY. WORK IN PROGRESS... ETA: Early February, 2026 🚧🚧**
6
6
 
7
- **If you're interested, star the repository to get updates on the progress in your GH homepage.**
7
+ **If you're interested, star ⭐ the repository to get updates on the progress in your GH homepage.**
8
8
 
9
- *If you would like to express youself, head to the [Discussions board](https://github.com/collagejs/collagejs/discussions).*
9
+ *If you would like to express yourself, head to the [Discussions board](https://github.com/collagejs/collagejs/discussions).*
10
10
 
11
11
  [Full Documentation](https://collagejs.dev)
12
12
 
13
- *CollageJS* is a very, very small library that enables the composition of a web user interface with micro-frontends created with any technology (Svelte, React, Vue, Solid, HTMX, etc.). It is heavily inspired by the *parcel* concept in the excellent `single-spa` routing library.
13
+ *CollageJS* is a very, very small library that enables the composition of a web user interface with micro-frontends created with any technology (Svelte, React, Vue, SolidJS, HTMX, etc.). It is heavily inspired by the *parcel* concept in the excellent `single-spa` routing library.
14
14
 
15
15
  ## How It Works
16
16
 
@@ -18,14 +18,10 @@
18
18
 
19
19
  ```typescript
20
20
  type UnmountFn = () => Promise<void>;
21
- type MountFn<TProps> = (target: HTMLElement, props?: TProps) => Promise<UnmountFn>;
22
- type Mount<TProps> = MountFn<TProps> | MountFn<TProps>[] | Mount<TProps>[];
23
- type UpdateFn<TProps> = (props: TProps) => Promise<void>;
24
- type Update<TProps> = UpdateFn<TProps> | UpdateFn<TProps>[] | Update[];
25
21
 
26
22
  interface CorePiece<TProps> {
27
- mount: Mount<TProps>;
28
- update?: Update<TProps>;
23
+ mount: (target: HTMLElement, props?: TProps) => Promise<UnmountFn>;
24
+ update?: (props: TProps) => Promise<void>;
29
25
  };
30
26
  ```
31
27
  > â„đïļ These types were simplified. See the real ones after installing the library.
@@ -53,6 +49,7 @@ export function buildTestPiece<TProps extends Record<string, any> = Record<strin
53
49
  ): CorePiece<TProps> {
54
50
  let pre: HTMLElement;
55
51
  return {
52
+ // Here's mount():
56
53
  async mount(target: HTMLElement, props?: MountProps<TProps>) {
57
54
  const delayMountCb = callbacks?.mount?.(target, props);
58
55
  pre = document.createElement('pre');
@@ -63,12 +60,14 @@ export function buildTestPiece<TProps extends Record<string, any> = Record<strin
63
60
  await delay();
64
61
  delayMountCb();
65
62
  }
63
+ // Here's the unmounting function:
66
64
  return () => {
67
65
  callbacks?.unmount?.();
68
66
  target.removeChild(pre);
69
67
  return Promise.resolve();
70
68
  };
71
69
  },
70
+ // Here's update():
72
71
  update(props: TProps) {
73
72
  callbacks?.update?.(props);
74
73
  pre.textContent = JSON.stringify(props, null, 2);
@@ -82,11 +81,11 @@ export function buildTestPiece<TProps extends Record<string, any> = Record<strin
82
81
  The key learnings here are:
83
82
 
84
83
  1. We can export functions that create *CollageJS* pieces. This is the simplest and most flexible approach: **Factory functions**.
85
- 2. We do whatever we need to do to mount our user interface inside the target element.
84
+ 2. Inside `mount()`, we do whatever we need to do to mount our user interface inside the target element.
86
85
  3. We return a cleanup function that unmounts the user interface.
87
86
  4. We optionally provide the `update()` method for property reactivity.
88
87
 
89
- You can export from a single project as many of these factory functions as desired. You are not constrained to expose just one *CollageJS* piece per project. Export as many as needed.
88
+ You can export from a single project as many of these factory functions as desired. You are not constrained to expose just one *CollageJS* piece per project. Export as many as needed/wanted.
90
89
 
91
90
  This is how packages like `@collagejs/svelte` work: When mounting, it calls Svelte's `mount()` function with the given options (if any are given), and returns a cleanup function that calls `unmount()` on the component. Updating properties is as simple as using a reactive object, at which point Svelte itself takes over the reacting part.
92
91
 
@@ -107,11 +106,27 @@ Maintenance is an issue. The `single-spa` core team has had hard times trying t
107
106
 
108
107
  So, the conclusion here is: *CollageJS* takes care of micro-frontends. Just that.
109
108
 
110
- Do you disagree with this? Perhaps you need a router and don't know which one would work best? No problem! We can recommend one: Create a "root" **Vite + Svelte** project and use `@svelte-router/core` ([documentation](https://svelte-router.dev)). This is a multi-route-matching router designed for micro-frontends. It is very simple to use and learn, even if you have never used Svelte before.
109
+ ### Gimme a Router!
111
110
 
112
- **"But I don't want to learn Svelte"**, you might say. Well, it's understandable. However, if you're coming from a `single-spa` experience, learning a bit of Svelte to configure the root router is no different than learning `single-spa`'s layout web component. Furthermore, the author of *CollageJS* is the author of `@svelte-router/core` as well.
111
+ Ok, so you really want routing capabilities. Understood.
113
112
 
114
- In the end, it is your choice.
113
+ The creator of *CollageJS* has also created an advanced, highly efficient and unique client-side router that:
114
+
115
+ - Matches multiple routes
116
+ - Can simultaneously do path routing and hash fragment routing
117
+ - Can support multiple named paths in the hash fragment
118
+ - Can render any number of user interface pieces for a single route anywhere in the document
119
+ - And many more features...
120
+
121
+ [webJose's Svelte Router](https://svelte-router.dev) is our recommendation. Furthermore, we provide a starter GitHub template repository to get you started quickly: [Template Repository](https://github.com/collagejs/root-template)
122
+
123
+ You can easily create a new *CollageJS* root project by telling GitHub to create a new repository for you using the above template. Once you do that, you get a **Vite + Svelte + TS** project configured with the router and fully working. The project, among other things, teaches:
124
+
125
+ - How the router can be configured
126
+ - How routers and routes are laid out in markup
127
+ - How fallback content works
128
+
129
+ > ðŸŠĪ**The Catch**: It is a Svelte project. Ideally, you should know [Svelte](https://svelte.dev) to take full advantage of it. With `single-spa`, you would have to learn how it worked, and how its layout web component worked. With this one, you should learn at least a little Svelte. Some learning curve on both sides. The good thing about this one is that Svelte knowledge is much more far-reaching. Svelte is very easy and fun. We promise.
115
130
 
116
131
  ## For the `single-spa` Savvy
117
132
 
@@ -123,7 +138,11 @@ Then the micro-frontends: The concept doesn't exist. At this point (after crea
123
138
 
124
139
  While `single-spa` asks you to shape your module exports in a particular way (the lifecycle functions), *CollageJS* imposes no such restriction. It is just not necessary. Just make sure you can get an object of type `CorePiece` to the `<Piece>` component of your preferred framework. Then use your framework's marvels to make the `<Piece>` component appear or disappear.
125
140
 
126
- Yes, you can still use import maps, and can even continue using the excellent `import-map-overrides` package. It is encouraged.
141
+ Yes, you'll still be working with import maps. They are super handy. We provide an enhanced (and simplified at the same time) version of `import-map-overrides` named `@collagejs/imo`. It only supports the `overridable-importmap` type (and therefore only native import maps for native ES modules), but carries support for our `@collagejs/aim` plug-in that let's you statically import from micro-frontends. **That's right! We are free from dynamic `import()` calls!** We can statically import from micro-frontends. Furthermore, it has a more modern user interface:
142
+
143
+ ![Main screen of @collagejs/imo](./_docs/collagejs-imo.png)
144
+
145
+ > 🌟 **Fun Fact**: This user interface is a *CollageJS* piece.
127
146
 
128
147
  #### Where Did the `unmount` Lifecycle Function Go?
129
148
 
@@ -137,10 +156,20 @@ Gone. There's no equivalent in *CollageJS*, as experience with `single-spa` has
137
156
 
138
157
  | Package | Status | Links | Description |
139
158
  | - | - | - | - |
140
- | `@collagejs/core` | ✔ïļ | (This repo) | Core functionality. Provides the general mounting and unmouting logic. |
141
- | `@collagejs/vite` | 🚧 | [Repo](https://github.com/collagejs/vite) | **Coming soon**. Vite plug-in that offers a CSS-mounting algorithm that is fully compatible with Vite's CSS bundling, including split CSS. |
159
+ | `@collagejs/core` | ✔ïļ | (This repo) | Core functionality. Provides the general mounting and unmounting logic. |
160
+ | `@collagejs/vite-css` | ✔ïļ | [Repo](https://github.com/collagejs/vite) | Vite plug-in that offers a CSS-mounting algorithm that is fully compatible with Vite's CSS bundling, including split CSS. It also features FOUC prevention. |
161
+ | `@collagejs/vite-im` | 🚧 | [Repo](https://github.com/collagejs/vite) | **Coming soon**. Vite plug-in that injects an import map and optionally the `import-map-overrides` package to define bare module identifiers for easy micro-frontend loading and debugging. |
162
+ | `@collagejs/vite-aim` | 🚧 | [Repo](https://github.com/collagejs/vite) | **Coming soon**. Vite-plugin that gives the Vite development server the ability to accept import maps from the client, which are used to resolve modules in the Vite pipeline, enabling static imports from micro-frontend bare module identifiers. |
163
+ | `@collagejs/imo` | 🚧 | [Repo](https://github.com/collagejs/imo) | **Coming soon**. Our version of `import-map-overrides` that does the usual overriding of import map entries, plus it transmits the final import map to Vite development servers found in it. |
142
164
  | `@collagejs/svelte` | ✔ïļ | [Repo](https://github.com/collagejs/svelte) | Svelte component library that can be used to create `CorePiece`-compliant objects and to mount `CorePiece` objects (of any technology) by providing the `<Piece>` component. |
143
165
  | `@collagejs/react` | ❌ | [Repo](https://github.com/collagejs/react) | **Next priority**. React component library that can be used to create `CorePiece`-compliant objects and to mount `CorePiece` objects (of any technology) by providing the `<Piece>` component. |
144
166
  | `@collagejs/solidjs` | ❌ | [Repo](https://github.com/collagejs/vite) | SolidJS component library that can be used to create `CorePiece`-compliant objects and to mount `CorePiece` objects (of any technology) by providing the `<Piece>` component. |
145
167
  | `@collagejs/vue` | ❌ | [Repo](https://github.com/collagejs/vue) | VueJS component library that can be used to create `CorePiece`-compliant objects and to mount `CorePiece` objects (of any technology) by providing the `<Piece>` component. |
146
168
  | `@collagejs/angular` | ❌ | | **External help needed.** We don't have expertise in Angular, nor do we want to acquire it. If you're an Angular developer, please consider contributing. |
169
+
170
+ ## Other Repositories
171
+
172
+ | Repository | Description |
173
+ | - | - |
174
+ | [Root Template](https://github.com/collagejs/root-template) | Root template repository that can be used to create new repositories for *CollageJS* root projects, with client-side routing already configured. |
175
+ | (-) | Repository of *CollageJS* pieces made in various front-end technologies for your reference and inspiration. |
@@ -26,41 +26,41 @@
26
26
 
27
27
  <!-- Simplified collage pieces -->
28
28
  <!-- Main piece (top-left) -->
29
- <path d="M20 30 L55 25 L60 45 L50 60 L30 55 L20 40 Z"
29
+ <path d="M12 22 L59 16 L66 42 L52 62 L26 56 L12 36 Z"
30
30
  fill="url(#primaryGrad)"
31
31
  filter="url(#dropShadow)"
32
32
  opacity="0.9"/>
33
33
 
34
34
  <!-- Secondary piece (top-right) -->
35
- <path d="M70 20 L105 30 L100 50 L90 45 L80 35 L70 30 Z"
35
+ <path d="M78 12 L118 22 L112 48 L100 42 L87 30 L78 24 Z"
36
36
  fill="url(#secondaryGrad)"
37
37
  filter="url(#dropShadow)"
38
38
  opacity="0.85"/>
39
39
 
40
40
  <!-- Third piece (center-left) -->
41
- <path d="M15 65 L45 60 L50 80 L40 90 L25 85 L15 75 Z"
41
+ <path d="M8 70 L48 64 L54 86 L42 98 L22 91 L8 80 Z"
42
42
  fill="url(#accentGrad)"
43
43
  filter="url(#dropShadow)"
44
44
  opacity="0.8"/>
45
45
 
46
46
  <!-- Fourth piece (bottom-right) -->
47
- <path d="M55 75 L95 80 L90 100 L75 105 L60 95 L55 85 Z"
47
+ <path d="M58 80 L106 86 L100 112 L82 118 L64 106 L58 91 Z"
48
48
  fill="url(#warningGrad)"
49
49
  filter="url(#dropShadow)"
50
50
  opacity="0.85"/>
51
51
 
52
52
  <!-- Small connecting dots for detail -->
53
- <circle cx="60" cy="50" r="4" fill="url(#secondaryGrad)" opacity="0.8"/>
54
- <circle cx="80" cy="65" r="3" fill="url(#accentGrad)" opacity="0.8"/>
53
+ <circle cx="66" cy="54" r="4.7" fill="url(#secondaryGrad)" opacity="0.8"/>
54
+ <circle cx="88" cy="72" r="3.5" fill="url(#accentGrad)" opacity="0.8"/>
55
55
 
56
56
  <!-- Central JS text with enhanced visibility -->
57
- <text x="64" y="74"
57
+ <text x="64" y="78"
58
58
  font-family="'SF Pro Display', 'Segoe UI', -apple-system, sans-serif"
59
- font-size="24"
59
+ font-size="28"
60
60
  font-weight="700"
61
61
  text-anchor="middle"
62
62
  fill="url(#primaryGrad)"
63
63
  stroke="#FFFFFF"
64
- stroke-width="1"
64
+ stroke-width="1.1"
65
65
  paint-order="stroke fill">JS</text>
66
66
  </svg>
@@ -35,65 +35,65 @@
35
35
 
36
36
  <!-- Main collage pieces - representing micro-frontend components -->
37
37
  <!-- Large primary piece (top-left) -->
38
- <path d="M80 120 L220 100 L240 180 L200 240 L120 220 L80 160 Z"
38
+ <path d="M50 85 L240 60 L265 170 L215 255 L110 225 L50 145 Z"
39
39
  fill="url(#primaryGrad)"
40
40
  filter="url(#glow)"
41
41
  opacity="0.95"/>
42
42
 
43
43
  <!-- Secondary piece (top-right) -->
44
- <path d="M280 80 L420 120 L400 200 L360 180 L320 140 L280 120 Z"
44
+ <path d="M295 50 L460 85 L435 200 L385 170 L330 125 L295 100 Z"
45
45
  fill="url(#secondaryGrad)"
46
46
  filter="url(#dropShadow)"
47
47
  opacity="0.85"/>
48
48
 
49
49
  <!-- Third piece (center-left) -->
50
- <path d="M60 260 L180 240 L200 320 L160 360 L100 340 L60 300 Z"
50
+ <path d="M30 245 L190 225 L215 325 L165 375 L85 350 L30 295 Z"
51
51
  fill="url(#accentGrad)"
52
52
  filter="url(#dropShadow)"
53
53
  opacity="0.8"/>
54
54
 
55
55
  <!-- Fourth piece (bottom-center) -->
56
- <path d="M220 300 L380 320 L360 400 L300 420 L240 380 L220 340 Z"
56
+ <path d="M235 285 L410 310 L385 425 L315 450 L250 395 L235 335 Z"
57
57
  fill="url(#warningGrad)"
58
58
  filter="url(#dropShadow)"
59
59
  opacity="0.85"/>
60
60
 
61
61
  <!-- Fifth piece (right) -->
62
- <path d="M380 200 L460 240 L440 320 L400 300 L380 260 Z"
62
+ <path d="M405 185 L485 225 L460 325 L415 300 L405 245 Z"
63
63
  fill="url(#primaryGrad)"
64
64
  filter="url(#dropShadow)"
65
65
  opacity="0.7"/>
66
66
 
67
67
  <!-- Small connecting pieces for detail -->
68
- <circle cx="240" cy="200" r="16" fill="url(#secondaryGrad)" opacity="0.8"/>
69
- <circle cx="320" cy="260" r="12" fill="url(#accentGrad)" opacity="0.8"/>
70
- <circle cx="180" cy="300" r="10" fill="url(#primaryGrad)" opacity="0.8"/>
68
+ <circle cx="255" cy="190" r="19" fill="url(#secondaryGrad)" opacity="0.8"/>
69
+ <circle cx="340" cy="250" r="14" fill="url(#accentGrad)" opacity="0.8"/>
70
+ <circle cx="190" cy="295" r="12" fill="url(#primaryGrad)" opacity="0.8"/>
71
71
 
72
72
  <!-- Stylized "JS" text with enhanced visibility -->
73
- <g transform="translate(256, 400)">
73
+ <g transform="translate(256, 420)">
74
74
  <text x="0" y="0"
75
75
  font-family="'SF Pro Display', 'Segoe UI', -apple-system, sans-serif"
76
- font-size="72"
76
+ font-size="85"
77
77
  font-weight="700"
78
78
  text-anchor="middle"
79
79
  fill="url(#primaryGrad)"
80
80
  stroke="#FFFFFF"
81
- stroke-width="2"
81
+ stroke-width="2.3"
82
82
  paint-order="stroke fill">JS</text>
83
83
  </g>
84
84
 
85
85
  <!-- CollageJS text -->
86
- <g transform="translate(256, 450)">
86
+ <g transform="translate(256, 475)">
87
87
  <text x="0" y="0"
88
88
  font-family="'SF Pro Display', 'Segoe UI', -apple-system, sans-serif"
89
- font-size="28"
89
+ font-size="33"
90
90
  font-weight="500"
91
91
  text-anchor="middle"
92
92
  fill="#374151">Collage</text>
93
93
  </g>
94
94
 
95
95
  <!-- Subtle connection lines showing pieces working together -->
96
- <line x1="150" y1="160" x2="200" y2="200" stroke="url(#primaryGrad)" stroke-width="3" opacity="0.3"/>
97
- <line x1="280" y1="140" x2="320" y2="180" stroke="url(#secondaryGrad)" stroke-width="3" opacity="0.3"/>
98
- <line x1="200" y1="280" x2="280" y2="300" stroke="url(#accentGrad)" stroke-width="3" opacity="0.3"/>
96
+ <line x1="140" y1="145" x2="210" y2="190" stroke="url(#primaryGrad)" stroke-width="3.5" opacity="0.3"/>
97
+ <line x1="300" y1="120" x2="345" y2="165" stroke="url(#secondaryGrad)" stroke-width="3.5" opacity="0.3"/>
98
+ <line x1="210" y1="270" x2="300" y2="290" stroke="url(#accentGrad)" stroke-width="3.5" opacity="0.3"/>
99
99
  </svg>
@@ -22,33 +22,33 @@
22
22
  <!-- No background - minimal clean design -->
23
23
 
24
24
  <!-- Simplified geometric pieces -->
25
- <path d="M10 15 L28 12 L30 22 L25 30 L15 28 L10 20 Z"
25
+ <path d="M6 11 L31 7 L34 24 L27 34 L14 31 L6 18 Z"
26
26
  fill="url(#primaryGrad)"
27
27
  opacity="0.9"/>
28
28
 
29
- <path d="M35 10 L52 15 L50 25 L45 22 L40 17 L35 15 Z"
29
+ <path d="M39 6 L58 12 L56 27 L49 23 L42 16 L39 13 Z"
30
30
  fill="url(#secondaryGrad)"
31
31
  opacity="0.85"/>
32
32
 
33
- <path d="M8 32 L22 30 L25 40 L20 45 L12 42 L8 37 Z"
33
+ <path d="M7 36 L25 34 L28 46 L22 52 L12 48 L7 41 Z"
34
34
  fill="url(#accentGrad)"
35
35
  opacity="0.8"/>
36
36
 
37
- <path d="M28 37 L47 40 L45 50 L37 52 L30 47 L28 42 Z"
37
+ <path d="M30 42 L53 46 L50 58 L40 61 L32 54 L30 47 Z"
38
38
  fill="url(#warningGrad)"
39
39
  opacity="0.85"/>
40
40
 
41
41
  <!-- Small connecting dot for detail -->
42
- <circle cx="40" cy="32" r="2" fill="url(#secondaryGrad)" opacity="0.8"/>
42
+ <circle cx="44" cy="35" r="2.4" fill="url(#secondaryGrad)" opacity="0.8"/>
43
43
 
44
44
  <!-- Central JS with stroke for visibility -->
45
- <text x="32" y="37"
45
+ <text x="32" y="40"
46
46
  font-family="'SF Pro Display', 'Segoe UI', -apple-system, sans-serif"
47
- font-size="12"
47
+ font-size="14"
48
48
  font-weight="700"
49
49
  text-anchor="middle"
50
50
  fill="url(#primaryGrad)"
51
51
  stroke="#FFFFFF"
52
- stroke-width="0.8"
52
+ stroke-width="0.9"
53
53
  paint-order="stroke fill">JS</text>
54
54
  </svg>
@@ -0,0 +1,38 @@
1
+ /**
2
+ * CollageJS Theme - Base Definitions
3
+ *
4
+ * Fundamental CSS variables that are too small to warrant their own files.
5
+ * This file should ALWAYS be imported first as other modules may depend on these definitions.
6
+ *
7
+ * Contains:
8
+ * - Font family stacks
9
+ * - Other fundamental values that don't fit neatly into color/component/utility categories
10
+ */
11
+
12
+ /* ===== TYPOGRAPHY ===== */
13
+
14
+ /* Font family stacks */
15
+ [data-collagejs-theme],
16
+ .cjs-themed {
17
+ /* Sans-serif font stack - used as default body font */
18
+ --cjs-font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
19
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
20
+ sans-serif;
21
+
22
+ /* Monospace font stack - used for code and technical content */
23
+ --cjs-font-mono: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas,
24
+ 'DejaVu Sans Mono', monospace;
25
+ }
26
+
27
+ /* ===== BORDER RADIUS ===== */
28
+
29
+ [data-collagejs-theme],
30
+ .cjs-themed {
31
+ /* Border radius scale */
32
+ --cjs-radius-sm: 0.25rem; /* Small elements */
33
+ --cjs-radius: 0.375rem; /* Default for most components */
34
+ --cjs-radius-lg: 0.5rem; /* Cards and larger elements */
35
+ --cjs-radius-xl: 0.75rem; /* Extra large elements */
36
+ --cjs-radius-pill: 9999px; /* Pill shape (fully rounded ends) */
37
+ --cjs-radius-circle: 50%; /* Perfect circle (use on square elements) */
38
+ }
@@ -0,0 +1,181 @@
1
+ /**
2
+ * CollageJS Theme - Color Definitions
3
+ *
4
+ * This file defines the color palette using CSS custom properties.
5
+ * Colors are sourced from the CollageJS logo gradients.
6
+ *
7
+ * MICRO-FRONTEND READY: Use any selector to scope your theme.
8
+ * Examples:
9
+ * - [data-collagejs-theme] { ... }
10
+ * - .my-app { ... }
11
+ * - #my-micro-frontend { ... }
12
+ * - .cjs-themed { ... }
13
+ */
14
+
15
+ /* ===== DEFAULT THEME CONTAINER ===== */
16
+ /* You can replace this selector with your own scoping selector */
17
+ [data-collagejs-theme],
18
+ .cjs-themed {
19
+ /* ===== BRAND COLORS ===== */
20
+ /* These are the 8 colors from your CollageJS logo gradients */
21
+
22
+ /* Primary Gradient (Indigo-Purple) */
23
+ --cjs-brand-indigo-start: #4F46E5;
24
+ --cjs-brand-indigo-start-rgb: 79, 70, 229;
25
+ --cjs-brand-indigo-end: #7C3AED;
26
+ --cjs-brand-indigo-end-rgb: 124, 58, 237;
27
+
28
+ /* Secondary Gradient (Cyan-Blue) */
29
+ --cjs-brand-cyan-start: #06B6D4;
30
+ --cjs-brand-cyan-start-rgb: 6, 182, 212;
31
+ --cjs-brand-cyan-end: #0EA5E9;
32
+ --cjs-brand-cyan-end-rgb: 14, 165, 233;
33
+
34
+ /* Accent Gradient (Green) */
35
+ --cjs-brand-green-start: #10B981;
36
+ --cjs-brand-green-start-rgb: 16, 185, 129;
37
+ --cjs-brand-green-end: #059669;
38
+ --cjs-brand-green-end-rgb: 5, 150, 105;
39
+
40
+ /* Warning Gradient (Orange) */
41
+ --cjs-brand-orange-start: #F59E0B;
42
+ --cjs-brand-orange-start-rgb: 245, 158, 11;
43
+ --cjs-brand-orange-end: #D97706;
44
+ --cjs-brand-orange-end-rgb: 217, 119, 6;
45
+
46
+ /* ===== OPACITY SYSTEM (Bootstrap-style) ===== */
47
+ /* Configure these to achieve glass effects and transparency */
48
+ --cjs-bg-opacity: 1;
49
+ --cjs-border-opacity: 1;
50
+ --cjs-text-opacity: 1;
51
+ --cjs-highlight-opacity: 0.11;
52
+
53
+ /* ===== CONTRASTING FOREGROUND COLORS ===== */
54
+ /* Solve the "what text color goes with this background?" problem */
55
+
56
+ /* For use on LIGHT backgrounds (so these are dark colors) */
57
+ --cjs-foreground-on-light: #1F2937; /* Dark gray with subtle cool tone */
58
+ --cjs-foreground-on-light-rgb: 31, 41, 55;
59
+ --cjs-foreground-on-light-muted: #4B5563; /* Lighter version for secondary text */
60
+ --cjs-foreground-on-light-muted-rgb: 75, 85, 99;
61
+
62
+ /* For use on DARK backgrounds (so these are light colors) */
63
+ --cjs-foreground-on-dark: #F9FAFB; /* Soft white with subtle warmth */
64
+ --cjs-foreground-on-dark-rgb: 249, 250, 251;
65
+ --cjs-foreground-on-dark-muted: #D1D5DB; /* Darker version for secondary text */
66
+ --cjs-foreground-on-dark-muted-rgb: 209, 213, 219;
67
+
68
+ /* Perfect contrast pairs - these work beautifully together */
69
+ --cjs-contrast-light-bg: var(--cjs-foreground-on-dark); /* Light background */
70
+ --cjs-contrast-light-bg-rgb: var(--cjs-foreground-on-dark-rgb);
71
+ --cjs-contrast-light-text: var(--cjs-foreground-on-light); /* Dark text */
72
+ --cjs-contrast-light-text-rgb: var(--cjs-foreground-on-light-rgb);
73
+ --cjs-contrast-dark-bg: var(--cjs-foreground-on-light); /* Dark background */
74
+ --cjs-contrast-dark-bg-rgb: var(--cjs-foreground-on-light-rgb);
75
+ --cjs-contrast-dark-text: var(--cjs-foreground-on-dark); /* Light text */
76
+ --cjs-contrast-dark-text-rgb: var(--cjs-foreground-on-dark-rgb);
77
+
78
+ /* ===== GLASS EFFECT SYSTEM ===== */
79
+ /* Configurable for accessibility - users can adjust to their needs */
80
+ --cjs-glass-blur: 9px; /* Blur intensity (0px = no blur) */
81
+ --cjs-glass-saturation: 120%; /* Color saturation (100% = normal) */
82
+ --cjs-glass-bg-opacity: 0.1; /* Background transparency */
83
+ --cjs-glass-border-opacity: 0.2; /* Border transparency */
84
+
85
+ /* ===== THEME COLORS (Configurable) ===== */
86
+ /* Override these in theme variants to create different looks */
87
+
88
+ /* Primary colors - defaults to indigo */
89
+ --cjs-primary: var(--cjs-brand-indigo-start);
90
+ --cjs-primary-rgb: var(--cjs-brand-indigo-start-rgb);
91
+ --cjs-primary-end: var(--cjs-brand-indigo-end);
92
+ --cjs-primary-end-rgb: var(--cjs-brand-indigo-end-rgb);
93
+ --cjs-primary-gradient: linear-gradient(135deg, var(--cjs-primary), var(--cjs-primary-end));
94
+
95
+ /* Secondary colors - defaults to cyan */
96
+ --cjs-secondary: var(--cjs-brand-cyan-start);
97
+ --cjs-secondary-rgb: var(--cjs-brand-cyan-start-rgb);
98
+ --cjs-secondary-end: var(--cjs-brand-cyan-end);
99
+ --cjs-secondary-end-rgb: var(--cjs-brand-cyan-end-rgb);
100
+ --cjs-secondary-gradient: linear-gradient(135deg, var(--cjs-secondary), var(--cjs-secondary-end));
101
+
102
+ /* Accent colors - defaults to green */
103
+ --cjs-accent: var(--cjs-brand-green-start);
104
+ --cjs-accent-rgb: var(--cjs-brand-green-start-rgb);
105
+ --cjs-accent-end: var(--cjs-brand-green-end);
106
+ --cjs-accent-end-rgb: var(--cjs-brand-green-end-rgb);
107
+ --cjs-accent-gradient: linear-gradient(135deg, var(--cjs-accent), var(--cjs-accent-end));
108
+
109
+ /* Warning colors - defaults to orange */
110
+ --cjs-warning: var(--cjs-brand-orange-start);
111
+ --cjs-warning-rgb: var(--cjs-brand-orange-start-rgb);
112
+ --cjs-warning-end: var(--cjs-brand-orange-end);
113
+ --cjs-warning-end-rgb: var(--cjs-brand-orange-end-rgb);
114
+ --cjs-warning-gradient: linear-gradient(135deg, var(--cjs-warning), var(--cjs-warning-end));
115
+
116
+ /* ===== COMPUTED VARIANTS ===== */
117
+ /* These are generated from the theme colors above */
118
+
119
+ /* Primary variants */
120
+ --cjs-primary-50: color-mix(in srgb, var(--cjs-primary) 10%, white);
121
+ --cjs-primary-100: color-mix(in srgb, var(--cjs-primary) 20%, white);
122
+ --cjs-primary-200: color-mix(in srgb, var(--cjs-primary) 40%, white);
123
+ --cjs-primary-300: color-mix(in srgb, var(--cjs-primary) 60%, white);
124
+ --cjs-primary-400: color-mix(in srgb, var(--cjs-primary) 80%, white);
125
+ --cjs-primary-500: var(--cjs-primary);
126
+ --cjs-primary-600: color-mix(in srgb, var(--cjs-primary) 80%, black);
127
+ --cjs-primary-700: color-mix(in srgb, var(--cjs-primary) 60%, black);
128
+ --cjs-primary-800: color-mix(in srgb, var(--cjs-primary) 40%, black);
129
+ --cjs-primary-900: color-mix(in srgb, var(--cjs-primary) 20%, black);
130
+
131
+ /* Neutral colors */
132
+ --cjs-white: #FAFAFA;
133
+ --cjs-white-rgb: 250, 250, 250;
134
+ --cjs-gray-50: #F9FAFB;
135
+ --cjs-gray-50-rgb: 249, 250, 251;
136
+ --cjs-gray-100: #F3F4F6;
137
+ --cjs-gray-100-rgb: 243, 244, 246;
138
+ --cjs-gray-200: #E5E7EB;
139
+ --cjs-gray-200-rgb: 229, 231, 235;
140
+ --cjs-gray-300: #D1D5DB;
141
+ --cjs-gray-300-rgb: 209, 213, 219;
142
+ --cjs-gray-400: #9CA3AF;
143
+ --cjs-gray-400-rgb: 156, 163, 175;
144
+ --cjs-gray-500: #6B7280;
145
+ --cjs-gray-500-rgb: 107, 114, 128;
146
+ --cjs-gray-600: #4B5563;
147
+ --cjs-gray-600-rgb: 75, 85, 99;
148
+ --cjs-gray-700: #374151;
149
+ --cjs-gray-700-rgb: 55, 65, 81;
150
+ --cjs-gray-800: #1F2937;
151
+ --cjs-gray-800-rgb: 31, 41, 55;
152
+ --cjs-gray-900: #111827;
153
+ --cjs-gray-900-rgb: 17, 24, 39;
154
+ --cjs-black: #0F172A;
155
+ --cjs-black-rgb: 15, 23, 42;
156
+
157
+ /* Semantic colors */
158
+ --cjs-success: var(--cjs-brand-green-start);
159
+ --cjs-success-rgb: var(--cjs-brand-green-start-rgb);
160
+ --cjs-error: #EF4444;
161
+ --cjs-error-rgb: 239, 68, 68;
162
+ --cjs-info: var(--cjs-brand-cyan-start);
163
+ --cjs-info-rgb: var(--cjs-brand-cyan-start-rgb);
164
+
165
+ /* Surface colors with opacity support */
166
+ --cjs-background: rgba(var(--cjs-white-rgb), var(--cjs-bg-opacity));
167
+ --cjs-surface: rgba(var(--cjs-gray-50-rgb), var(--cjs-bg-opacity));
168
+ --cjs-border: rgba(var(--cjs-gray-700-rgb), var(--cjs-border-opacity));
169
+ --cjs-highlight: rgba(var(--cjs-black-rgb), var(--cjs-highlight-opacity));
170
+
171
+ /* Use the new contrasting foreground colors */
172
+ --cjs-text: rgba(var(--cjs-foreground-on-light-rgb), var(--cjs-text-opacity));
173
+ --cjs-text-secondary: rgba(var(--cjs-foreground-on-light-muted-rgb), var(--cjs-text-opacity));
174
+ --cjs-text-muted: rgba(var(--cjs-gray-500-rgb), var(--cjs-text-opacity));
175
+
176
+ /* Semantic text colors with guaranteed contrast */
177
+ --cjs-text-on-primary: var(--cjs-foreground-on-dark); /* Light text for primary buttons */
178
+ --cjs-text-on-secondary: var(--cjs-foreground-on-dark); /* Light text for secondary buttons */
179
+ --cjs-text-on-light: var(--cjs-foreground-on-light); /* Dark text for light backgrounds */
180
+ --cjs-text-on-dark: var(--cjs-foreground-on-dark); /* Light text for dark backgrounds */
181
+ }