@canopy-iiif/app 0.10.11 → 0.10.13

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/lib/build/dev.js CHANGED
@@ -9,7 +9,7 @@ const {
9
9
  ASSETS_DIR,
10
10
  ensureDirSync,
11
11
  } = require("../common");
12
- function resolveTailwindCli() {
12
+ function resolveTailwindCli() {
13
13
  const bin = path.join(
14
14
  process.cwd(),
15
15
  "node_modules",
@@ -40,6 +40,14 @@ const HAS_APP_WORKSPACE = (() => {
40
40
  return false;
41
41
  }
42
42
  })();
43
+
44
+ function stripTailwindThemeLayer(targetPath) {
45
+ try {
46
+ const raw = fs.readFileSync(targetPath, "utf8");
47
+ const cleaned = raw.replace(/@layer theme\{[\s\S]*?\}(?=@layer|$)/g, "");
48
+ if (cleaned !== raw) fs.writeFileSync(targetPath, cleaned, "utf8");
49
+ } catch (_) {}
50
+ }
43
51
  let pendingModuleReload = false;
44
52
  let building = false;
45
53
  let buildAgain = false;
@@ -896,6 +904,7 @@ async function dev() {
896
904
  }
897
905
  throw new Error("[tailwind] Initial Tailwind build failed.");
898
906
  }
907
+ stripTailwindThemeLayer(outputCss);
899
908
  console.log(
900
909
  `[tailwind] initial build ok (${fileSizeKb(outputCss)} KB) →`,
901
910
  prettyPath(outputCss)
@@ -920,6 +929,7 @@ async function dev() {
920
929
  cssWatcherAttached = true;
921
930
  try {
922
931
  fs.watch(outputCss, { persistent: false }, () => {
932
+ stripTailwindThemeLayer(outputCss);
923
933
  if (!unmuted) {
924
934
  unmuted = true;
925
935
  console.log(
@@ -946,6 +956,7 @@ async function dev() {
946
956
  }
947
957
  throw new Error("[tailwind] On-demand Tailwind compile failed.");
948
958
  }
959
+ stripTailwindThemeLayer(outputCss);
949
960
  console.log(
950
961
  `[tailwind] compiled (${fileSizeKb(outputCss)} KB) →`,
951
962
  prettyPath(outputCss)
package/lib/build/iiif.js CHANGED
@@ -50,6 +50,7 @@ const HERO_IMAGE_SIZES_ATTR = "(min-width: 1024px) 1280px, 100vw";
50
50
  const OG_IMAGE_WIDTH = 1200;
51
51
  const OG_IMAGE_HEIGHT = 630;
52
52
  const HERO_REPRESENTATIVE_SIZE = Math.max(HERO_THUMBNAIL_SIZE, OG_IMAGE_WIDTH);
53
+ const MAX_ENTRY_SLUG_LENGTH = 50;
53
54
 
54
55
  function resolvePositiveInteger(value, fallback) {
55
56
  const num = Number(value);
@@ -65,6 +66,64 @@ function resolveBoolean(value) {
65
66
  return normalized === "1" || normalized === "true" || normalized === "yes";
66
67
  }
67
68
 
69
+ function normalizeCollectionUris(value) {
70
+ if (value === undefined || value === null) return [];
71
+ const rawValues = Array.isArray(value) ? value : [value];
72
+ const seen = new Set();
73
+ const uris = [];
74
+ for (const entry of rawValues) {
75
+ if (typeof entry !== "string") continue;
76
+ const trimmed = entry.trim();
77
+ if (!trimmed || seen.has(trimmed)) continue;
78
+ seen.add(trimmed);
79
+ uris.push(trimmed);
80
+ }
81
+ return uris;
82
+ }
83
+
84
+ function clampSlugLength(slug, limit = MAX_ENTRY_SLUG_LENGTH) {
85
+ if (!slug) return "";
86
+ const max = Math.max(1, limit);
87
+ if (slug.length <= max) return slug;
88
+ const slice = slug.slice(0, max);
89
+ const trimmed = slice.replace(/-+$/g, "");
90
+ return trimmed || slice || slug.slice(0, 1);
91
+ }
92
+
93
+ function isSlugTooLong(value) {
94
+ return typeof value === "string" && value.length > MAX_ENTRY_SLUG_LENGTH;
95
+ }
96
+
97
+ function normalizeSlugBase(value, fallback) {
98
+ const safeFallback = fallback || "entry";
99
+ const base = typeof value === "string" ? value : String(value || "");
100
+ const clamped = clampSlugLength(base, MAX_ENTRY_SLUG_LENGTH);
101
+ if (clamped) return clamped;
102
+ return clampSlugLength(safeFallback, MAX_ENTRY_SLUG_LENGTH) || safeFallback;
103
+ }
104
+
105
+ function buildSlugWithSuffix(base, fallback, counter) {
106
+ const suffix = `-${counter}`;
107
+ const baseLimit = Math.max(1, MAX_ENTRY_SLUG_LENGTH - suffix.length);
108
+ const trimmedBase =
109
+ clampSlugLength(base, baseLimit) ||
110
+ clampSlugLength(fallback, baseLimit) ||
111
+ fallback.slice(0, baseLimit);
112
+ return `${trimmedBase}${suffix}`;
113
+ }
114
+
115
+ function normalizeStringList(value) {
116
+ if (value === undefined || value === null) return [];
117
+ const rawValues = Array.isArray(value) ? value : [value];
118
+ return rawValues
119
+ .map((entry) => {
120
+ if (typeof entry === "string") return entry.trim();
121
+ if (entry === undefined || entry === null) return "";
122
+ return String(entry).trim();
123
+ })
124
+ .filter(Boolean);
125
+ }
126
+
68
127
  function resolveThumbnailPreferences() {
69
128
  return {
70
129
  size: resolvePositiveInteger(
@@ -537,13 +596,15 @@ const RESERVED_SLUGS = {Manifest: new Set(), Collection: new Set()};
537
596
  function computeUniqueSlug(index, baseSlug, id, type) {
538
597
  const byId = Array.isArray(index && index.byId) ? index.byId : [];
539
598
  const normId = normalizeIiifId(String(id || ""));
599
+ const fallbackBase = type === "Manifest" ? "untitled" : "collection";
600
+ const normalizedBase = normalizeSlugBase(baseSlug || fallbackBase, fallbackBase);
540
601
  const used = new Set(
541
602
  byId
542
603
  .filter((e) => e && e.slug && e.type === type)
543
604
  .map((e) => String(e.slug))
544
605
  );
545
606
  const reserved = RESERVED_SLUGS[type] || new Set();
546
- let slug = baseSlug || (type === "Manifest" ? "untitled" : "collection");
607
+ let slug = normalizedBase;
547
608
  let i = 1;
548
609
  for (;;) {
549
610
  const existing = byId.find(
@@ -560,7 +621,7 @@ function computeUniqueSlug(index, baseSlug, id, type) {
560
621
  reserved.add(slug);
561
622
  return slug;
562
623
  }
563
- slug = `${baseSlug}-${i++}`;
624
+ slug = buildSlugWithSuffix(normalizedBase, fallbackBase, i++);
564
625
  }
565
626
  }
566
627
 
@@ -568,18 +629,20 @@ function ensureBaseSlugFor(index, baseSlug, id, type) {
568
629
  try {
569
630
  const byId = Array.isArray(index && index.byId) ? index.byId : [];
570
631
  const normId = normalizeIiifId(String(id || ""));
632
+ const fallbackBase = type === "Manifest" ? "untitled" : "collection";
633
+ const normalizedBase = normalizeSlugBase(baseSlug || fallbackBase, fallbackBase);
571
634
  const existingWithBase = byId.find(
572
- (e) => e && e.type === type && String(e.slug) === String(baseSlug)
635
+ (e) => e && e.type === type && String(e.slug) === String(normalizedBase)
573
636
  );
574
637
  if (existingWithBase && normalizeIiifId(existingWithBase.id) !== normId) {
575
638
  // Reassign the existing entry to the next available suffix to free the base
576
639
  const newSlug = computeUniqueSlug(
577
640
  index,
578
- baseSlug,
641
+ normalizedBase,
579
642
  existingWithBase.id,
580
643
  type
581
644
  );
582
- if (newSlug && newSlug !== baseSlug) existingWithBase.slug = newSlug;
645
+ if (newSlug && newSlug !== normalizedBase) existingWithBase.slug = newSlug;
583
646
  }
584
647
  } catch (_) {}
585
648
  return baseSlug;
@@ -620,13 +683,15 @@ async function loadCachedManifestById(id) {
620
683
  );
621
684
  slug = entry && entry.slug;
622
685
  }
686
+ if (isSlugTooLong(slug)) slug = null;
623
687
  if (!slug) {
624
688
  // Try an on-disk scan to recover mapping if index is missing/out-of-sync
625
689
  const memo = MEMO_ID_TO_SLUG.get(String(id));
626
690
  if (memo) slug = memo;
691
+ if (isSlugTooLong(slug)) slug = null;
627
692
  if (!slug) {
628
693
  const found = await findSlugByIdFromDisk(id);
629
- if (found) {
694
+ if (found && !isSlugTooLong(found)) {
630
695
  slug = found;
631
696
  MEMO_ID_TO_SLUG.set(String(id), slug);
632
697
  try {
@@ -830,6 +895,7 @@ async function loadCachedCollectionById(id) {
830
895
  );
831
896
  slug = entry && entry.slug;
832
897
  }
898
+ if (isSlugTooLong(slug)) slug = null;
833
899
  if (!slug) {
834
900
  // Scan collections dir if mapping missing
835
901
  try {
@@ -845,7 +911,12 @@ async function loadCachedCollectionById(id) {
845
911
  String((obj && (obj.id || obj["@id"])) || "")
846
912
  );
847
913
  if (cid && cid === normalizeIiifId(String(id))) {
848
- slug = name.replace(/\.json$/i, "");
914
+ const candidate = name.replace(/\.json$/i, "");
915
+ if (isSlugTooLong(candidate)) {
916
+ slug = null;
917
+ break;
918
+ }
919
+ slug = candidate;
849
920
  // heal mapping
850
921
  try {
851
922
  index.byId = Array.isArray(index.byId) ? index.byId : [];
@@ -1052,9 +1123,13 @@ async function loadConfig() {
1052
1123
  async function buildIiifCollectionPages(CONFIG) {
1053
1124
  const cfg = CONFIG || (await loadConfig());
1054
1125
 
1055
- const collectionUri =
1056
- (cfg && cfg.collection) || process.env.CANOPY_COLLECTION_URI || "";
1057
- if (!collectionUri) return {searchRecords: []};
1126
+ let collectionUris = normalizeCollectionUris(cfg && cfg.collection);
1127
+ if (!collectionUris.length) {
1128
+ collectionUris = normalizeCollectionUris(
1129
+ process.env.CANOPY_COLLECTION_URI || ""
1130
+ );
1131
+ }
1132
+ if (!collectionUris.length) return {searchRecords: []};
1058
1133
 
1059
1134
  const searchIndexCfg = (cfg && cfg.search && cfg.search.index) || {};
1060
1135
  const metadataCfg = (searchIndexCfg && searchIndexCfg.metadata) || {};
@@ -1093,38 +1168,15 @@ async function buildIiifCollectionPages(CONFIG) {
1093
1168
  enabled: summaryEnabled,
1094
1169
  };
1095
1170
  const annotationMotivations = new Set(
1096
- Array.isArray(annotationsCfg && annotationsCfg.motivation)
1097
- ? annotationsCfg.motivation
1098
- .map((m) =>
1099
- String(m || "")
1100
- .trim()
1101
- .toLowerCase()
1102
- )
1103
- .filter(Boolean)
1104
- : []
1171
+ normalizeStringList(annotationsCfg && annotationsCfg.motivation).map((m) =>
1172
+ m.toLowerCase()
1173
+ )
1105
1174
  );
1106
1175
  const annotationsOptions = {
1107
1176
  enabled: annotationsEnabled,
1108
1177
  motivations: annotationMotivations,
1109
1178
  };
1110
1179
 
1111
- // Fetch top-level collection
1112
- logLine("• Traversing IIIF Collection(s)", "blue", {dim: true});
1113
- const root = await readJsonFromUri(collectionUri, {log: true});
1114
- if (!root) {
1115
- logLine("IIIF: Failed to fetch collection", "red");
1116
- return {searchRecords: []};
1117
- }
1118
- const normalizedRoot = await normalizeToV3(root);
1119
- // Save collection cache
1120
- try {
1121
- await saveCachedCollection(
1122
- normalizedRoot,
1123
- normalizedRoot.id || collectionUri,
1124
- ""
1125
- );
1126
- } catch (_) {}
1127
-
1128
1180
  // Recursively traverse Collections and gather all Manifest tasks
1129
1181
  const tasks = [];
1130
1182
  const visitedCollections = new Set(); // normalized ids
@@ -1179,7 +1231,27 @@ async function buildIiifCollectionPages(CONFIG) {
1179
1231
  // Traverse strictly by parent/child hierarchy (Presentation 3): items → Manifest or Collection
1180
1232
  } catch (_) {}
1181
1233
  }
1182
- await gatherFromCollection(normalizedRoot, "");
1234
+ // Fetch each configured collection and queue manifests from all of them
1235
+ logLine("• Traversing IIIF Collection(s)", "blue", {dim: true});
1236
+ for (const uri of collectionUris) {
1237
+ let root = null;
1238
+ try {
1239
+ root = await readJsonFromUri(uri, {log: true});
1240
+ } catch (_) {
1241
+ root = null;
1242
+ }
1243
+ if (!root) {
1244
+ try {
1245
+ logLine(`IIIF: Failed to fetch collection → ${uri}`, "red");
1246
+ } catch (_) {}
1247
+ continue;
1248
+ }
1249
+ const normalizedRoot = await normalizeToV3(root);
1250
+ try {
1251
+ await saveCachedCollection(normalizedRoot, normalizedRoot.id || uri, "");
1252
+ } catch (_) {}
1253
+ await gatherFromCollection(normalizedRoot, "");
1254
+ }
1183
1255
  if (!tasks.length) return {searchRecords: []};
1184
1256
 
1185
1257
  // Split into chunks and process with limited concurrency
@@ -1322,6 +1394,7 @@ async function buildIiifCollectionPages(CONFIG) {
1322
1394
  (e) => e && e.type === "Manifest" && normalizeIiifId(e.id) === nid
1323
1395
  );
1324
1396
  let slug = mEntry && mEntry.slug;
1397
+ if (isSlugTooLong(slug)) slug = null;
1325
1398
  if (!slug) {
1326
1399
  slug = computeUniqueSlug(idxMap, baseSlug, nid, "Manifest");
1327
1400
  const parentNorm = normalizeIiifId(String(it.parent || ""));
@@ -1,6 +1,14 @@
1
1
  const { fs, fsp, path, OUT_DIR, ensureDirSync, absoluteUrl } = require('../common');
2
2
  const slugify = require('slugify');
3
3
 
4
+ function normalizeMetadataLabel(label) {
5
+ if (typeof label !== 'string') return '';
6
+ return label
7
+ .trim()
8
+ .replace(/[:\s]+$/g, '')
9
+ .toLowerCase();
10
+ }
11
+
4
12
  function firstI18nString(x) {
5
13
  if (!x) return '';
6
14
  if (typeof x === 'string') return x;
@@ -17,7 +25,11 @@ async function buildFacetsForWorks(combined, labelWhitelist) {
17
25
  const facetsDir = path.resolve('.cache/iiif');
18
26
  ensureDirSync(facetsDir);
19
27
  const map = new Map(); // label -> Map(value -> Set(docIdx))
20
- const labels = Array.isArray(labelWhitelist) ? labelWhitelist.map(String) : [];
28
+ const normalizedLabels = new Set(
29
+ (Array.isArray(labelWhitelist) ? labelWhitelist : [])
30
+ .map((label) => normalizeMetadataLabel(String(label || '')))
31
+ .filter(Boolean)
32
+ );
21
33
  if (!Array.isArray(combined)) combined = [];
22
34
  for (let i = 0; i < combined.length; i++) {
23
35
  const rec = combined[i];
@@ -37,7 +49,12 @@ async function buildFacetsForWorks(combined, labelWhitelist) {
37
49
  const label = firstI18nString(entry.label);
38
50
  const valueRaw = entry.value && (typeof entry.value === 'string' ? entry.value : firstI18nString(entry.value));
39
51
  if (!label || !valueRaw) continue;
40
- if (labels.length && !labels.includes(label)) continue; // only configured labels
52
+ if (
53
+ normalizedLabels.size &&
54
+ !normalizedLabels.has(normalizeMetadataLabel(label))
55
+ ) {
56
+ continue; // only configured labels
57
+ }
41
58
  const values = [];
42
59
  try {
43
60
  if (typeof entry.value === 'string') values.push(entry.value);
@@ -79,11 +96,19 @@ async function writeFacetCollections(labelWhitelist, combined) {
79
96
  if (!fs.existsSync(facetsPath)) return;
80
97
  let facets = [];
81
98
  try { facets = JSON.parse(fs.readFileSync(facetsPath, 'utf8')) || []; } catch (_) { facets = []; }
82
- const labels = new Set((Array.isArray(labelWhitelist) ? labelWhitelist : []).map(String));
99
+ const normalizedLabels = new Set(
100
+ (Array.isArray(labelWhitelist) ? labelWhitelist : [])
101
+ .map((label) => normalizeMetadataLabel(String(label || '')))
102
+ .filter(Boolean)
103
+ );
83
104
  const apiRoot = path.join(OUT_DIR, 'api');
84
105
  const facetRoot = path.join(apiRoot, 'facet');
85
106
  ensureDirSync(facetRoot);
86
- const list = (Array.isArray(facets) ? facets : []).filter((f) => !labels.size || labels.has(String(f && f.label)));
107
+ const list = (Array.isArray(facets) ? facets : []).filter((f) => {
108
+ if (!normalizedLabels.size) return true;
109
+ const normalized = normalizeMetadataLabel(String((f && f.label) || ''));
110
+ return normalized ? normalizedLabels.has(normalized) : false;
111
+ });
87
112
  const labelIndexItems = [];
88
113
  for (const f of list) {
89
114
  if (!f || !f.label || !Array.isArray(f.values)) continue;
@@ -143,6 +143,14 @@ async function ensureStyles() {
143
143
  } catch (_) {}
144
144
  }
145
145
 
146
+ function stripTailwindThemeLayer(targetPath) {
147
+ try {
148
+ const raw = fs.readFileSync(targetPath, "utf8");
149
+ const cleaned = raw.replace(/@layer theme\{[\s\S]*?\}(?=@layer|$)/g, "");
150
+ if (cleaned !== raw) fs.writeFileSync(targetPath, cleaned, "utf8");
151
+ } catch (_) {}
152
+ }
153
+
146
154
  const shouldInjectTheme = !(hasAppCss && configPath);
147
155
 
148
156
  if (configPath && (inputCss || generatedInput)) {
@@ -154,6 +162,7 @@ async function ensureStyles() {
154
162
  });
155
163
  if (ok) {
156
164
  if (shouldInjectTheme) injectThemeTokens(dest);
165
+ stripTailwindThemeLayer(dest);
157
166
  return; // Tailwind compiled CSS
158
167
  }
159
168
  }
@@ -170,6 +179,7 @@ async function ensureStyles() {
170
179
  if (!isTailwindSource(customAppCss)) {
171
180
  await fsp.copyFile(customAppCss, dest);
172
181
  if (shouldInjectTheme) injectThemeTokens(dest);
182
+ stripTailwindThemeLayer(dest);
173
183
  return;
174
184
  }
175
185
  }
@@ -177,6 +187,7 @@ async function ensureStyles() {
177
187
  if (!isTailwindSource(customContentCss)) {
178
188
  await fsp.copyFile(customContentCss, dest);
179
189
  if (shouldInjectTheme) injectThemeTokens(dest);
190
+ stripTailwindThemeLayer(dest);
180
191
  return;
181
192
  }
182
193
  }
@@ -184,6 +195,7 @@ async function ensureStyles() {
184
195
  const css = `:root{--max-w:760px;--muted:#6b7280}*{box-sizing:border-box}body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Helvetica,Arial,sans-serif;max-width:var(--max-w);margin:2rem auto;padding:0 1rem;line-height:1.6}a{color:#2563eb;text-decoration:none}a:hover{text-decoration:underline}.site-header,.site-footer{display:flex;align-items:center;justify-content:space-between;gap:.5rem;padding:1rem 0;border-bottom:1px solid #e5e7eb}.site-footer{border-bottom:0;border-top:1px solid #e5e7eb;color:var(--muted)}.brand{font-weight:600}.content pre{background:#f6f8fa;padding:1rem;overflow:auto}.content code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;background:#f6f8fa;padding:.1rem .3rem;border-radius:4px}.tabs{display:flex;gap:.5rem;align-items:center;border-bottom:1px solid #e5e7eb;margin:.5rem 0}.tab{background:none;border:0;color:#374151;padding:.25rem .5rem;border-radius:.375rem;cursor:pointer}.tab:hover{color:#111827}.tab-active{color:#2563eb;border:1px solid #e5e7eb;border-bottom:0;background:#fff}.masonry{column-gap:1rem;column-count:1}@media(min-width:768px){.masonry{column-count:2}}@media(min-width:1024px){.masonry{column-count:3}}.masonry>*{break-inside:avoid;margin-bottom:1rem;display:block}[data-grid-variant=masonry]{column-gap:var(--grid-gap,1rem);column-count:var(--cols-base,1)}@media(min-width:768px){[data-grid-variant=masonry]{column-count:var(--cols-md,2)}}@media(min-width:1024px){[data-grid-variant=masonry]{column-count:var(--cols-lg,3)}}[data-grid-variant=masonry]>*{break-inside:avoid;margin-bottom:var(--grid-gap,1rem);display:block}[data-grid-variant=grid]{display:grid;grid-template-columns:repeat(var(--cols-base,1),minmax(0,1fr));gap:var(--grid-gap,1rem)}@media(min-width:768px){[data-grid-variant=grid]{grid-template-columns:repeat(var(--cols-md,2),minmax(0,1fr))}}@media(min-width:1024px){[data-grid-variant=grid]{grid-template-columns:repeat(var(--cols-lg,3),minmax(0,1fr))}}`;
185
196
  await fsp.writeFile(dest, css, "utf8");
186
197
  injectThemeTokens(dest);
198
+ stripTailwindThemeLayer(dest);
187
199
  }
188
200
 
189
201
  module.exports = { ensureStyles };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canopy-iiif/app",
3
- "version": "0.10.11",
3
+ "version": "0.10.13",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "Mat Jordan <mat@northwestern.edu>",
@@ -12,6 +12,7 @@
12
12
  "./ui": "./ui/dist/index.mjs",
13
13
  "./ui/server": "./ui/dist/server.mjs",
14
14
  "./ui/styles/index.css": "./ui/styles/index.css",
15
+ "./ui/styles/runtime.css": "./ui/styles/runtime.css",
15
16
  "./ui/canopy-iiif-plugin": "./ui/tailwind-canopy-iiif-plugin.js",
16
17
  "./ui/canopy-iiif-preset": "./ui/tailwind-canopy-iiif-preset.js",
17
18
  "./ui/tailwind-config": {
@@ -1,74 +1,74 @@
1
1
  /* canopy-theme */
2
2
  @layer properties {
3
3
  :root {
4
- --color-brand-50: #fdfdfe;
5
- --color-brand-100: #edf2fe;
6
- --color-brand-200: #e1e9ff;
7
- --color-brand-300: #c1d0ff;
8
- --color-brand-400: #abbdf9;
9
- --color-brand-500: #8da4ef;
10
- --color-brand-600: #3e63dd;
11
- --color-brand-700: #3358d4;
12
- --color-brand-800: #3a5bc7;
13
- --color-brand-900: #172245;
14
- --color-brand-default: #3358d4;
15
- --color-gray-50: #fcfcfd;
16
- --color-gray-100: #f0f0f3;
17
- --color-gray-200: #e8e8ec;
18
- --color-gray-300: #d9d9e0;
19
- --color-gray-400: #cdced6;
20
- --color-gray-500: #b9bbc6;
21
- --color-gray-600: #8b8d98;
22
- --color-gray-700: #80838d;
23
- --color-gray-800: #60646c;
24
- --color-gray-900: #111316;
25
- --color-gray-default: #111316;
26
- --color-gray-muted: #8b8d98;
27
- --colors-accent: #3358d4 !important;
28
- --colors-accentAlt: #3a5bc7 !important;
29
- --colors-accentMuted: #abbdf9 !important;
30
- --colors-primary: #111316 !important;
31
- --colors-primaryAlt: #111316 !important;
32
- --colors-primaryMuted: #111316 !important;
33
- --colors-secondary: #fcfcfd !important;
34
- --colors-secondaryAlt: #fcfcfd !important;
35
- --colors-secondaryMuted: #fcfcfd !important;
36
- color-scheme: light;
4
+ --color-brand-50: #191111;
5
+ --color-brand-100: #3b1219;
6
+ --color-brand-200: #500f1c;
7
+ --color-brand-300: #72232d;
8
+ --color-brand-400: #8c333a;
9
+ --color-brand-500: #b54548;
10
+ --color-brand-600: #e5484d;
11
+ --color-brand-700: #ec5d5e;
12
+ --color-brand-800: #ff9592;
13
+ --color-brand-900: #ffdde3;
14
+ --color-brand-default: #ec5d5e;
15
+ --color-gray-50: #111111;
16
+ --color-gray-100: #222222;
17
+ --color-gray-200: #2a2a2a;
18
+ --color-gray-300: #3a3a3a;
19
+ --color-gray-400: #484848;
20
+ --color-gray-500: #606060;
21
+ --color-gray-600: #6e6e6e;
22
+ --color-gray-700: #7b7b7b;
23
+ --color-gray-800: #b4b4b4;
24
+ --color-gray-900: #f5f5f5;
25
+ --color-gray-default: #f5f5f5;
26
+ --color-gray-muted: #6e6e6e;
27
+ --colors-accent: #ec5d5e !important;
28
+ --colors-accentAlt: #ff9592 !important;
29
+ --colors-accentMuted: #8c333a !important;
30
+ --colors-primary: #f5f5f5 !important;
31
+ --colors-primaryAlt: #f5f5f5 !important;
32
+ --colors-primaryMuted: #f5f5f5 !important;
33
+ --colors-secondary: #111111 !important;
34
+ --colors-secondaryAlt: #111111 !important;
35
+ --colors-secondaryMuted: #111111 !important;
36
+ color-scheme: dark;
37
37
  }
38
38
  :host {
39
- --color-brand-50: #fdfdfe;
40
- --color-brand-100: #edf2fe;
41
- --color-brand-200: #e1e9ff;
42
- --color-brand-300: #c1d0ff;
43
- --color-brand-400: #abbdf9;
44
- --color-brand-500: #8da4ef;
45
- --color-brand-600: #3e63dd;
46
- --color-brand-700: #3358d4;
47
- --color-brand-800: #3a5bc7;
48
- --color-brand-900: #172245;
49
- --color-brand-default: #3358d4;
50
- --color-gray-50: #fcfcfd;
51
- --color-gray-100: #f0f0f3;
52
- --color-gray-200: #e8e8ec;
53
- --color-gray-300: #d9d9e0;
54
- --color-gray-400: #cdced6;
55
- --color-gray-500: #b9bbc6;
56
- --color-gray-600: #8b8d98;
57
- --color-gray-700: #80838d;
58
- --color-gray-800: #60646c;
59
- --color-gray-900: #111316;
60
- --color-gray-default: #111316;
61
- --color-gray-muted: #8b8d98;
62
- --colors-accent: #3358d4 !important;
63
- --colors-accentAlt: #3a5bc7 !important;
64
- --colors-accentMuted: #abbdf9 !important;
65
- --colors-primary: #111316 !important;
66
- --colors-primaryAlt: #111316 !important;
67
- --colors-primaryMuted: #111316 !important;
68
- --colors-secondary: #fcfcfd !important;
69
- --colors-secondaryAlt: #fcfcfd !important;
70
- --colors-secondaryMuted: #fcfcfd !important;
71
- color-scheme: light;
39
+ --color-brand-50: #191111;
40
+ --color-brand-100: #3b1219;
41
+ --color-brand-200: #500f1c;
42
+ --color-brand-300: #72232d;
43
+ --color-brand-400: #8c333a;
44
+ --color-brand-500: #b54548;
45
+ --color-brand-600: #e5484d;
46
+ --color-brand-700: #ec5d5e;
47
+ --color-brand-800: #ff9592;
48
+ --color-brand-900: #ffdde3;
49
+ --color-brand-default: #ec5d5e;
50
+ --color-gray-50: #111111;
51
+ --color-gray-100: #222222;
52
+ --color-gray-200: #2a2a2a;
53
+ --color-gray-300: #3a3a3a;
54
+ --color-gray-400: #484848;
55
+ --color-gray-500: #606060;
56
+ --color-gray-600: #6e6e6e;
57
+ --color-gray-700: #7b7b7b;
58
+ --color-gray-800: #b4b4b4;
59
+ --color-gray-900: #f5f5f5;
60
+ --color-gray-default: #f5f5f5;
61
+ --color-gray-muted: #6e6e6e;
62
+ --colors-accent: #ec5d5e !important;
63
+ --colors-accentAlt: #ff9592 !important;
64
+ --colors-accentMuted: #8c333a !important;
65
+ --colors-primary: #f5f5f5 !important;
66
+ --colors-primaryAlt: #f5f5f5 !important;
67
+ --colors-primaryMuted: #f5f5f5 !important;
68
+ --colors-secondary: #111111 !important;
69
+ --colors-secondaryAlt: #111111 !important;
70
+ --colors-secondaryMuted: #111111 !important;
71
+ color-scheme: dark;
72
72
  }
73
73
  }
74
74
  /* canopy-theme:end */
@@ -1712,5 +1712,4 @@
1712
1712
 
1713
1713
  /**
1714
1714
  * Define source files for utility classes
1715
- */
1716
- @source "../dist";
1715
+ */
@@ -7,4 +7,4 @@
7
7
  /**
8
8
  * Define source files for utility classes
9
9
  */
10
- @source "../dist";
10
+ // @source "../dist";
@@ -130,6 +130,8 @@ function defineCanopyTailwindConfig(metaUrlOrOptions, maybeOptions) {
130
130
  config.theme = mergeTheme(config.theme, theme);
131
131
  }
132
132
 
133
+ config.theme = mergeTheme(config.theme, {colors: {}});
134
+
133
135
  return config;
134
136
  }
135
137
 
package/ui/theme.js CHANGED
@@ -130,14 +130,15 @@ function toTailwindScale(name, options = {}) {
130
130
  const prefix = name;
131
131
  const scale = {};
132
132
  const darken900Amount = normalizeDarkenAmount(options.darken900Amount);
133
+ const steps = STEP_MAP;
133
134
  for (const lvl of LEVELS) {
134
- const radixStep = STEP_MAP[lvl];
135
+ const radixStep = steps[lvl];
135
136
  const key = `${prefix}${radixStep}`;
136
137
  const value = palette[key];
137
138
  if (!value) return null;
138
139
  scale[lvl] = value;
139
140
  }
140
- const darkestKey = `${prefix}${STEP_MAP["900"]}`;
141
+ const darkestKey = `${prefix}${steps["900"]}`;
141
142
  if (scale["800"] && palette[darkestKey]) {
142
143
  const amount = darken900Amount != null ? darken900Amount : 0.25;
143
144
  scale["900"] =