@canopy-iiif/app 0.10.32 → 0.12.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/lib/build/dev.js CHANGED
@@ -3,6 +3,12 @@ const fsp = fs.promises;
3
3
  const path = require("path");
4
4
  const { spawn, spawnSync } = require("child_process");
5
5
  const http = require("http");
6
+ let sass = null;
7
+ try {
8
+ sass = require("sass");
9
+ } catch (_) {
10
+ sass = null;
11
+ }
6
12
  const {
7
13
  CONTENT_DIR,
8
14
  OUT_DIR,
@@ -29,6 +35,13 @@ const UI_DIST_DIR = path.resolve(path.join(__dirname, "../../ui/dist"));
29
35
  const APP_PACKAGE_ROOT = path.resolve(path.join(__dirname, "..", ".."));
30
36
  const APP_LIB_DIR = path.join(APP_PACKAGE_ROOT, "lib");
31
37
  const APP_UI_DIR = path.join(APP_PACKAGE_ROOT, "ui");
38
+ let loadUiTheme = null;
39
+ try {
40
+ const uiTheme = require(path.join(APP_UI_DIR, "theme.js"));
41
+ if (uiTheme && typeof uiTheme.loadCanopyTheme === "function") {
42
+ loadUiTheme = uiTheme.loadCanopyTheme;
43
+ }
44
+ } catch (_) {}
32
45
  const APP_WATCH_TARGETS = [
33
46
  { dir: APP_LIB_DIR, label: "@canopy-iiif/app/lib" },
34
47
  { dir: APP_UI_DIR, label: "@canopy-iiif/app/ui" },
@@ -1025,6 +1038,7 @@ async function dev() {
1025
1038
  );
1026
1039
  const uiStylesDir = path.join(APP_UI_DIR, "styles");
1027
1040
  const uiStylesCss = path.join(uiStylesDir, "index.css");
1041
+ const uiStylesEntry = path.join(uiStylesDir, "index.scss");
1028
1042
  const pluginFiles = [uiPlugin, uiPreset].filter((p) => {
1029
1043
  try {
1030
1044
  return fs.existsSync(p);
@@ -1056,6 +1070,36 @@ async function dev() {
1056
1070
  });
1057
1071
  } catch (_) {}
1058
1072
  }
1073
+ const rebuildUiStyles = () => {
1074
+ if (!sass || !fs.existsSync(uiStylesEntry)) return false;
1075
+ try {
1076
+ const theme = loadUiTheme ? loadUiTheme({ cwd: process.cwd() }) : null;
1077
+ const source = `${
1078
+ theme && theme.sassConfig ? theme.sassConfig : ""
1079
+ }@use 'index';`;
1080
+ const result = sass.compileString(source, {
1081
+ loadPaths: [uiStylesDir],
1082
+ style: "expanded",
1083
+ });
1084
+ let cssOutput = result && result.css ? result.css : "";
1085
+ const themeCss = theme && theme.css ? theme.css.trim() : "";
1086
+ if (themeCss) {
1087
+ cssOutput = `/* canopy-theme */\n${themeCss}\n/* canopy-theme:end */\n${cssOutput}`;
1088
+ }
1089
+ fs.writeFileSync(uiStylesCss, cssOutput, "utf8");
1090
+ console.log(
1091
+ "[tailwind] rebuilt @canopy-iiif/app/ui styles →",
1092
+ prettyPath(uiStylesCss)
1093
+ );
1094
+ return true;
1095
+ } catch (err) {
1096
+ console.warn(
1097
+ "[tailwind] failed to rebuild @canopy-iiif/app/ui styles:",
1098
+ err && err.message ? err.message : err
1099
+ );
1100
+ return false;
1101
+ }
1102
+ };
1059
1103
  const attachCssWatcher = () => {
1060
1104
  if (uiCssWatcherAttached) {
1061
1105
  if (fs.existsSync(uiStylesCss)) return;
@@ -1080,11 +1124,15 @@ async function dev() {
1080
1124
  } catch (_) {}
1081
1125
  }
1082
1126
  };
1127
+ if (fs.existsSync(uiStylesEntry)) rebuildUiStyles();
1083
1128
  attachCssWatcher();
1084
1129
  const handleUiSassChange = () => {
1130
+ const ok = rebuildUiStyles();
1085
1131
  attachCssWatcher();
1086
1132
  scheduleTailwindRestart(
1087
- "[tailwind] detected @canopy-iiif/app/ui Sass change — restarting Tailwind",
1133
+ ok
1134
+ ? "[tailwind] detected @canopy-iiif/app/ui Sass change — restarting Tailwind"
1135
+ : "[tailwind] Sass compile failed — attempting Tailwind restart",
1088
1136
  "[tailwind] compile after UI Sass change failed"
1089
1137
  );
1090
1138
  };
@@ -1148,16 +1196,66 @@ async function dev() {
1148
1196
  const stylesDir = path.dirname(inputCss);
1149
1197
  if (stylesDir && stylesDir.includes(path.join("app", "styles"))) {
1150
1198
  let cssDebounce = null;
1151
- try {
1152
- fs.watch(stylesDir, { persistent: false }, (evt, fn) => {
1153
- clearTimeout(cssDebounce);
1154
- cssDebounce = setTimeout(() => {
1155
- try { onBuildStart(); } catch (_) {}
1156
- safeCompile("[tailwind] compile after CSS change failed");
1157
- try { onCssChange(); } catch (_) {}
1158
- }, 50);
1159
- });
1160
- } catch (_) {}
1199
+ const triggerCssRebuild = () => {
1200
+ clearTimeout(cssDebounce);
1201
+ cssDebounce = setTimeout(() => {
1202
+ try { onBuildStart(); } catch (_) {}
1203
+ safeCompile("[tailwind] compile after CSS change failed");
1204
+ try { onCssChange(); } catch (_) {}
1205
+ }, 50);
1206
+ };
1207
+ const shouldHandle = (filename) => {
1208
+ if (!filename) return true;
1209
+ return /\.(css|s[ac]ss)$/i.test(String(filename));
1210
+ };
1211
+ const attachRecursiveWatch = () => {
1212
+ try {
1213
+ fs.watch(
1214
+ stylesDir,
1215
+ { persistent: false, recursive: true },
1216
+ (evt, fn) => {
1217
+ if (!shouldHandle(fn)) return;
1218
+ triggerCssRebuild();
1219
+ }
1220
+ );
1221
+ return true;
1222
+ } catch (_) {
1223
+ return false;
1224
+ }
1225
+ };
1226
+ if (!attachRecursiveWatch()) {
1227
+ const watchers = new Map();
1228
+ function watchDir(dir) {
1229
+ if (watchers.has(dir)) return;
1230
+ try {
1231
+ const watcher = fs.watch(
1232
+ dir,
1233
+ { persistent: false },
1234
+ (evt, fn) => {
1235
+ if (shouldHandle(fn)) triggerCssRebuild();
1236
+ scanDir(dir);
1237
+ }
1238
+ );
1239
+ watchers.set(dir, watcher);
1240
+ } catch (_) {}
1241
+ }
1242
+ function scanDir(dir) {
1243
+ let entries = [];
1244
+ try {
1245
+ entries = fs.readdirSync(dir, { withFileTypes: true });
1246
+ } catch (_) {
1247
+ return;
1248
+ }
1249
+ for (const entry of entries) {
1250
+ if (!entry || !entry.isDirectory()) continue;
1251
+ const next = path.join(dir, entry.name);
1252
+ watchDir(next);
1253
+ scanDir(next);
1254
+ }
1255
+ }
1256
+ watchDir(stylesDir);
1257
+ scanDir(stylesDir);
1258
+ }
1161
1259
  }
1162
1260
  } catch (err) {
1163
1261
  console.error("[tailwind] setup failed:", err && err.message ? err.message : err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canopy-iiif/app",
3
- "version": "0.10.32",
3
+ "version": "0.12.0",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "Mat Jordan <mat@northwestern.edu>",