@boopkit/cap-web 0.3.0 → 0.4.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/capability.json CHANGED
@@ -3,8 +3,14 @@
3
3
  "description": "Web UI with Handlebars + Tailwind",
4
4
  "type": "application",
5
5
  "package": "@boopkit/cap-web",
6
- "dependencies": ["express-handlebars", "tailwindcss"],
7
- "devDependencies": ["@tailwindcss/cli"],
6
+ "dependencies": [
7
+ "express-handlebars",
8
+ "heroicons",
9
+ "tailwindcss"
10
+ ],
11
+ "devDependencies": [
12
+ "@tailwindcss/cli"
13
+ ],
8
14
  "files": [
9
15
  "views/",
10
16
  "public/",
@@ -14,20 +20,61 @@
14
20
  "tailwind.config.ts",
15
21
  "reference/web-ui.ref.md"
16
22
  ],
17
- "skills": ["design.web-ui-design.skill.md"],
23
+ "skills": [
24
+ "boop-web-web-ui-design"
25
+ ],
18
26
  "scripts": {
19
- "tailwind:build": { "cmd": "npx @tailwindcss/cli -i styles/styles.css -o public/css/style.css --minify", "description": "Compile Tailwind CSS for production" },
20
- "tailwind:watch": { "cmd": "npx @tailwindcss/cli -i styles/styles.css -o public/css/style.css --watch", "description": "Watch for changes and rebuild Tailwind CSS" }
27
+ "tailwind:build": {
28
+ "cmd": "npx @tailwindcss/cli -i styles/styles.css -o public/css/style.css --minify",
29
+ "description": "Compile Tailwind CSS for production"
30
+ },
31
+ "tailwind:watch": {
32
+ "cmd": "npx @tailwindcss/cli -i styles/styles.css -o public/css/style.css --watch",
33
+ "description": "Watch for changes and rebuild Tailwind CSS"
34
+ }
21
35
  },
22
36
  "postInstall": {
23
- "steps": ["Build CSS for the first time: npm run tailwind:build"]
37
+ "steps": [
38
+ "Build CSS for the first time: npm run tailwind:build"
39
+ ]
24
40
  },
25
41
  "hooks": [
26
- { "phase": "imports", "code": "import { configureViewEngine, configureStatic, requestLogger } from '@boopkit/cap-web';", "description": "view engine, static file serving, and request logging" },
27
- { "phase": "imports", "code": "import pageRoutes from './routes/pages';", "description": "page route definitions" },
28
- { "phase": "preRoutes", "order": 12, "code": "app.use(requestLogger());", "description": "log every request with method, URL, status, and timing" },
29
- { "phase": "preRoutes", "order": 40, "code": "configureViewEngine(app);", "description": "configure Handlebars as view engine" },
30
- { "phase": "preRoutes", "order": 45, "code": "configureStatic(app);", "description": "serve static content such as CSS" },
31
- { "phase": "preRoutes", "order": 50, "code": "app.use(pageRoutes);", "description": "mount page routes" }
32
- ]
42
+ {
43
+ "phase": "imports",
44
+ "code": "import { configureViewEngine, configureStatic, requestLogger } from '@boopkit/cap-web';",
45
+ "description": "view engine, static file serving, and request logging"
46
+ },
47
+ {
48
+ "phase": "imports",
49
+ "code": "import pageRoutes from './routes/pages';",
50
+ "description": "page route definitions"
51
+ },
52
+ {
53
+ "phase": "preRoutes",
54
+ "order": 12,
55
+ "code": "app.use(requestLogger());",
56
+ "description": "log every request with method, URL, status, and timing"
57
+ },
58
+ {
59
+ "phase": "preRoutes",
60
+ "order": 40,
61
+ "code": "configureViewEngine(app);",
62
+ "description": "configure Handlebars as view engine"
63
+ },
64
+ {
65
+ "phase": "preRoutes",
66
+ "order": 45,
67
+ "code": "configureStatic(app);",
68
+ "description": "serve static content such as CSS"
69
+ },
70
+ {
71
+ "phase": "preRoutes",
72
+ "order": 50,
73
+ "code": "app.use(pageRoutes);",
74
+ "description": "mount page routes"
75
+ }
76
+ ],
77
+ "skill_migrations": {
78
+ "boop-web-web-ui-design": "design.web-ui-design.skill.md"
79
+ }
33
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAmE3D,CAAC"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAyBA;;GAEG;AACH,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAyE3D,CAAC"}
package/dist/helpers.js CHANGED
@@ -4,8 +4,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.helpers = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
7
9
  const handlebars_1 = __importDefault(require("handlebars"));
8
10
  const marked_1 = require("marked");
11
+ const iconCache = new Map();
12
+ function readIcon(name, style, cssClass) {
13
+ const key = `${style}/${name}`;
14
+ let svg = iconCache.get(key);
15
+ if (svg === undefined) {
16
+ const svgPath = path_1.default.join(require.resolve('heroicons/package.json'), '..', style, `${name}.svg`);
17
+ try {
18
+ svg = fs_1.default.readFileSync(svgPath, 'utf8');
19
+ }
20
+ catch {
21
+ return `<!-- icon not found: ${key} -->`;
22
+ }
23
+ iconCache.set(key, svg);
24
+ }
25
+ if (cssClass) {
26
+ svg = svg.replace(/^<svg /, `<svg class="${cssClass}" `);
27
+ }
28
+ return svg;
29
+ }
9
30
  /**
10
31
  * Common Handlebars helpers for use in templates.
11
32
  */
@@ -79,5 +100,10 @@ exports.helpers = {
79
100
  const content = options.fn ? options.fn(this) : options;
80
101
  return new handlebars_1.default.SafeString(marked_1.marked.parse(content || ''));
81
102
  },
103
+ /** Inline SVG icon: {{icon "user" "24/outline"}} or {{icon "user" "24/outline" class="w-6 h-6"}} */
104
+ icon: (name, style, options) => {
105
+ const cssClass = options?.hash?.class;
106
+ return new handlebars_1.default.SafeString(readIcon(name, style || '24/outline', cssClass));
107
+ },
82
108
  };
83
109
  //# sourceMappingURL=helpers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import type { Request, Response, NextFunction } from 'express';
2
2
  /**
3
3
  * Lightweight request logger middleware.
4
- * Logs method, URL, status code, and response time to stdout.
4
+ * Logs method, URL, status code, and response time via structured logger.
5
5
  * Mount early (after requestId if present) so it captures all requests.
6
6
  */
7
7
  export declare function requestLogger(): (req: Request, res: Response, next: NextFunction) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"request-logger.d.ts","sourceRoot":"","sources":["../src/request-logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE/D;;;;GAIG;AACH,wBAAgB,aAAa,KACnB,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAa/D"}
1
+ {"version":3,"file":"request-logger.d.ts","sourceRoot":"","sources":["../src/request-logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAK/D;;;;GAIG;AACH,wBAAgB,aAAa,KACnB,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAa/D"}
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.requestLogger = requestLogger;
4
+ const logger_1 = require("@boopkit/logger");
5
+ const logger = (0, logger_1.createLogger)('web', 'request');
4
6
  /**
5
7
  * Lightweight request logger middleware.
6
- * Logs method, URL, status code, and response time to stdout.
8
+ * Logs method, URL, status code, and response time via structured logger.
7
9
  * Mount early (after requestId if present) so it captures all requests.
8
10
  */
9
11
  function requestLogger() {
@@ -14,7 +16,7 @@ function requestLogger() {
14
16
  const ms = Date.now() - start;
15
17
  const status = res.statusCode;
16
18
  const level = status >= 500 ? 'error' : status >= 400 ? 'warn' : 'info';
17
- console.log(`${new Date().toISOString()} ${level} [http] ${req.method} ${req.originalUrl} ${status} ${ms}ms req=${id}`);
19
+ logger.log(level, `${req.method} ${req.originalUrl} ${status} ${ms}ms`, { requestId: id, status, ms });
18
20
  });
19
21
  next();
20
22
  };
@@ -1 +1 @@
1
- {"version":3,"file":"request-logger.js","sourceRoot":"","sources":["../src/request-logger.ts"],"names":[],"mappings":";;AAOA,sCAcC;AAnBD;;;;GAIG;AACH,SAAgB,aAAa;IAC3B,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,EAAE,GAAI,GAAW,CAAC,EAAE,IAAI,GAAG,CAAC;QAElC,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YACpB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC;YAC9B,MAAM,KAAK,GAAG,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;YACxE,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,KAAK,WAAW,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,WAAW,IAAI,MAAM,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;QAC1H,CAAC,CAAC,CAAC;QAEH,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"request-logger.js","sourceRoot":"","sources":["../src/request-logger.ts"],"names":[],"mappings":";;AAUA,sCAcC;AAvBD,4CAA+C;AAE/C,MAAM,MAAM,GAAG,IAAA,qBAAY,EAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAE9C;;;;GAIG;AACH,SAAgB,aAAa;IAC3B,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,EAAE,GAAI,GAAW,CAAC,EAAE,IAAI,GAAG,CAAC;QAElC,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YACpB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC;YAC9B,MAAM,KAAK,GAAG,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;YACxE,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,WAAW,IAAI,MAAM,IAAI,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QACzG,CAAC,CAAC,CAAC;QAEH,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boopkit/cap-web",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Express view engine configuration, Handlebars helpers, and static asset middleware",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -21,8 +21,11 @@
21
21
  "build": "tsc -p tsconfig.json"
22
22
  },
23
23
  "dependencies": {
24
+ "@boopkit/logger": "^0.4.0",
24
25
  "handlebars-helpers": "^0.10.0",
25
- "marked": "^15.0.0"
26
+ "heroicons": "^2.2.0",
27
+ "marked": "^15.0.0",
28
+ "winston": "^3.17.0"
26
29
  },
27
30
  "peerDependencies": {
28
31
  "express": ">=4.0.0",
@@ -39,6 +39,7 @@ Handlebars via `express-handlebars`. Templates in `views/`, layouts in `views/la
39
39
  | `fmt_percent` | Percentage formatting |
40
40
  | `fmt_date` | Human-readable date (e.g., "March 28, 2026") |
41
41
  | `markdown` | Render markdown to HTML |
42
+ | `icon` | Inline SVG from heroicons: `{{icon "user" "24/outline"}}` with optional `class=` |
42
43
 
43
44
  ---
44
45
 
@@ -1,5 +1,10 @@
1
+ ---
2
+ name: boop-web-web-ui-design
3
+ description: "When you need to design and implement user interfaces following established patterns and philosophy."
4
+ metadata:
5
+ category: design
6
+ ---
1
7
  # Web UI Design Principles
2
- This skill guides the design and implementation of user interfaces following our established patterns and philosophy.
3
8
 
4
9
  For controller design (the code that handles requests and renders views), apply the core principles in `design.controllers.skill.md` from the `services` capability: thin dispatch, no business logic in controllers, services handle the work. This skill adds web-specific guidance on top: view rendering, template structure, CSS patterns.
5
10
 
@@ -88,6 +93,7 @@ When considering whether to reuse existing components:
88
93
  - `fmt_percent` — format as percentage: `{{fmt_percent 45}}` → `45%`
89
94
  - `fmt_date` — human-readable date: `{{fmt_date createdAt}}` → `March 28, 2026`
90
95
  - `markdown` — render markdown to HTML: `{{markdown text}}` or `{{#markdown}}...{{/markdown}}`
96
+ - `icon` — inline SVG icon from heroicons: `{{icon "user" "24/outline"}}` or with CSS class: `{{icon "check" "24/solid" class="w-5 h-5 text-green-600"}}`. Styles: `24/outline`, `24/solid`, `20/solid`, `16/solid`. Icons are read from `node_modules/heroicons/` and cached.
91
97
  - `json` — JSON stringify: `{{json obj}}`
92
98
  - `truncate` — truncate string: `{{truncate text 100}}`
93
99
  - `upper` / `lower` — case conversion