@canopy-iiif/app 0.6.28 → 0.7.1

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.
@@ -0,0 +1,141 @@
1
+ const {
2
+ fs,
3
+ fsp,
4
+ path,
5
+ OUT_DIR,
6
+ CONTENT_DIR,
7
+ ensureDirSync,
8
+ } = require("../common");
9
+
10
+ async function ensureStyles() {
11
+ const stylesDir = path.join(OUT_DIR, "styles");
12
+ const dest = path.join(stylesDir, "styles.css");
13
+ const customContentCss = path.join(CONTENT_DIR, "_styles.css");
14
+ const appStylesDir = path.join(process.cwd(), "app", "styles");
15
+ const customAppCss = path.join(appStylesDir, "index.css");
16
+ ensureDirSync(stylesDir);
17
+
18
+ const root = process.cwd();
19
+ const twConfigsRoot = [
20
+ path.join(root, "tailwind.config.js"),
21
+ path.join(root, "tailwind.config.cjs"),
22
+ path.join(root, "tailwind.config.mjs"),
23
+ path.join(root, "tailwind.config.ts"),
24
+ ];
25
+ const twConfigsApp = [
26
+ path.join(appStylesDir, "tailwind.config.js"),
27
+ path.join(appStylesDir, "tailwind.config.cjs"),
28
+ path.join(appStylesDir, "tailwind.config.mjs"),
29
+ path.join(appStylesDir, "tailwind.config.ts"),
30
+ ];
31
+ let configPath = [...twConfigsApp, ...twConfigsRoot].find((p) => {
32
+ try {
33
+ return fs.existsSync(p);
34
+ } catch (_) {
35
+ return false;
36
+ }
37
+ });
38
+ if (!configPath) {
39
+ try {
40
+ const { CACHE_DIR } = require("../common");
41
+ const genDir = path.join(CACHE_DIR, "tailwind");
42
+ ensureDirSync(genDir);
43
+ const genCfg = path.join(genDir, "tailwind.config.js");
44
+ const cfg = `module.exports = {\n presets: [require('@canopy-iiif/app/ui/canopy-iiif-preset')],\n content: [\n './content/**/*.{mdx,html}',\n './site/**/*.html',\n './site/**/*.js',\n './packages/app/ui/**/*.{js,jsx,ts,tsx}',\n './packages/app/lib/iiif/components/**/*.{js,jsx}',\n ],\n theme: { extend: {} },\n plugins: [require('@canopy-iiif/app/ui/canopy-iiif-plugin')],\n};\n`;
45
+ fs.writeFileSync(genCfg, cfg, "utf8");
46
+ configPath = genCfg;
47
+ } catch (_) {
48
+ configPath = null;
49
+ }
50
+ }
51
+
52
+ const inputCss = fs.existsSync(customAppCss)
53
+ ? customAppCss
54
+ : fs.existsSync(customContentCss)
55
+ ? customContentCss
56
+ : null;
57
+
58
+ let generatedInput = null;
59
+ if (!inputCss) {
60
+ try {
61
+ const { CACHE_DIR } = require("../common");
62
+ const genDir = path.join(CACHE_DIR, "tailwind");
63
+ ensureDirSync(genDir);
64
+ generatedInput = path.join(genDir, "index.css");
65
+ const css = `@tailwind base;\n@tailwind components;\n@tailwind utilities;\n`;
66
+ fs.writeFileSync(generatedInput, css, "utf8");
67
+ } catch (_) {
68
+ generatedInput = null;
69
+ }
70
+ }
71
+
72
+ function resolveTailwindCli() {
73
+ try {
74
+ const cliJs = require.resolve("tailwindcss/lib/cli.js");
75
+ return { cmd: process.execPath, args: [cliJs] };
76
+ } catch (_) {}
77
+ try {
78
+ const localBin = path.join(
79
+ process.cwd(),
80
+ "node_modules",
81
+ ".bin",
82
+ process.platform === "win32" ? "tailwindcss.cmd" : "tailwindcss"
83
+ );
84
+ if (fs.existsSync(localBin)) return { cmd: localBin, args: [] };
85
+ } catch (_) {}
86
+ return null;
87
+ }
88
+ function buildTailwindCli({ input, output, config, minify = true }) {
89
+ try {
90
+ const cli = resolveTailwindCli();
91
+ if (!cli) return false;
92
+ const { spawnSync } = require("child_process");
93
+ const args = ["-i", input, "-o", output];
94
+ if (config) args.push("-c", config);
95
+ if (minify) args.push("--minify");
96
+ const res = spawnSync(cli.cmd, [...cli.args, ...args], {
97
+ stdio: "inherit",
98
+ env: { ...process.env, BROWSERSLIST_IGNORE_OLD_DATA: "1" },
99
+ });
100
+ return !!res && res.status === 0;
101
+ } catch (_) {
102
+ return false;
103
+ }
104
+ }
105
+
106
+ if (configPath && (inputCss || generatedInput)) {
107
+ const ok = buildTailwindCli({
108
+ input: inputCss || generatedInput,
109
+ output: dest,
110
+ config: configPath,
111
+ minify: true,
112
+ });
113
+ if (ok) return; // Tailwind compiled CSS
114
+ }
115
+
116
+ function isTailwindSource(p) {
117
+ try {
118
+ const s = fs.readFileSync(p, "utf8");
119
+ return /@tailwind\s+(base|components|utilities)/.test(s);
120
+ } catch (_) {
121
+ return false;
122
+ }
123
+ }
124
+ if (fs.existsSync(customAppCss)) {
125
+ if (!isTailwindSource(customAppCss)) {
126
+ await fsp.copyFile(customAppCss, dest);
127
+ return;
128
+ }
129
+ }
130
+ if (fs.existsSync(customContentCss)) {
131
+ if (!isTailwindSource(customContentCss)) {
132
+ await fsp.copyFile(customContentCss, dest);
133
+ return;
134
+ }
135
+ }
136
+
137
+ 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))}}`;
138
+ await fsp.writeFile(dest, css, "utf8");
139
+ }
140
+
141
+ module.exports = { ensureStyles };
@@ -84,4 +84,3 @@ async function getThumbnailUrl(resource, preferredSize = 1200, unsafe = false) {
84
84
  }
85
85
 
86
86
  module.exports = { getRepresentativeImage, getThumbnail, getThumbnailUrl };
87
-
package/lib/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  module.exports = {
2
- build: require('./build').build,
3
- dev: require('./dev').dev
2
+ build: require('./build/build').build,
3
+ dev: require('./build/dev').dev
4
4
  };
5
-
@@ -1,8 +1,8 @@
1
1
  const React = require('react');
2
2
  const ReactDOMServer = require('react-dom/server');
3
3
  const crypto = require('crypto');
4
- const { path, withBase } = require('./common');
5
- const { ensureDirSync, OUT_DIR, htmlShell, fsp } = require('./common');
4
+ const { path, withBase } = require('../common');
5
+ const { ensureDirSync, OUT_DIR, htmlShell, fsp } = require('../common');
6
6
 
7
7
  const FALLBACK_SEARCH_APP = `import React, { useEffect, useMemo, useSyncExternalStore, useState } from 'react';
8
8
  import { createRoot } from 'react-dom/client';
@@ -200,10 +200,10 @@ if (typeof document !== 'undefined') {
200
200
  `;
201
201
 
202
202
  async function ensureSearchRuntime() {
203
- const { fs, path } = require('./common');
203
+ const { fs, path } = require('../common');
204
204
  ensureDirSync(OUT_DIR);
205
205
  let esbuild = null;
206
- try { esbuild = require('../ui/node_modules/esbuild'); } catch (_) { try { esbuild = require('esbuild'); } catch (_) {} }
206
+ try { esbuild = require('../../ui/node_modules/esbuild'); } catch (_) { try { esbuild = require('esbuild'); } catch (_) {} }
207
207
  if (!esbuild) { console.warn('Search: skipped bundling (no esbuild)'); return; }
208
208
  const entry = path.join(__dirname, 'search-app.jsx');
209
209
  const scriptsDir = path.join(OUT_DIR, 'scripts');
@@ -327,7 +327,7 @@ async function ensureSearchRuntime() {
327
327
  return;
328
328
  }
329
329
  try {
330
- const { logLine } = require('./log');
330
+ const { logLine } = require('../build/log');
331
331
  let size = 0; try { const st = fs.statSync(outFile); size = st.size || 0; } catch (_) {}
332
332
  const kb = size ? ` (${(size/1024).toFixed(1)} KB)` : '';
333
333
  const rel = path.relative(process.cwd(), outFile).split(path.sep).join('/');
@@ -343,9 +343,9 @@ async function buildSearchPage() {
343
343
  const searchLayoutPath = path.join(path.resolve('content'), 'search', '_layout.mdx');
344
344
  let body = '';
345
345
  let head = '';
346
- if (require('./common').fs.existsSync(searchLayoutPath)) {
346
+ if (require('../common').fs.existsSync(searchLayoutPath)) {
347
347
  try {
348
- const mdx = require('./mdx');
348
+ const mdx = require('../build/mdx');
349
349
  const rendered = await mdx.compileMdxFile(searchLayoutPath, outPath, {});
350
350
  body = rendered && rendered.body ? rendered.body : '';
351
351
  head = rendered && rendered.head ? rendered.head : '';
@@ -361,7 +361,7 @@ async function buildSearchPage() {
361
361
  React.createElement('h1', null, 'Search'),
362
362
  React.createElement('div', { id: 'search-root' })
363
363
  );
364
- const { loadAppWrapper } = require('./mdx');
364
+ const { loadAppWrapper } = require('../build/mdx');
365
365
  const app = await loadAppWrapper();
366
366
  const wrappedApp = app && app.App ? React.createElement(app.App, null, content) : content;
367
367
  body = ReactDOMServer.renderToStaticMarkup(wrappedApp);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canopy-iiif/app",
3
- "version": "0.6.28",
3
+ "version": "0.7.1",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "Mat Jordan <mat@northwestern.edu>",
@@ -29,6 +29,7 @@
29
29
  "@iiif/helpers": "^1.4.0",
30
30
  "@mdx-js/mdx": "^3.1.0",
31
31
  "@mdx-js/react": "^3.1.0",
32
+ "charm": "^1.0.2",
32
33
  "cmdk": "^1.1.1",
33
34
  "js-yaml": "^4.1.0",
34
35
  "react-masonry-css": "^1.0.16",