@3sln/deck 0.0.11 → 0.0.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/bin/build.js CHANGED
@@ -6,6 +6,7 @@ import path from 'path';
6
6
  import {createRequire} from 'module';
7
7
  import { sha256, loadDeckConfig, getProjectFiles, getCardFiles, getHtmlTemplate } from '../src/config.js';
8
8
 
9
+ import {marked} from 'marked';
9
10
  const require = createRequire(import.meta.url);
10
11
 
11
12
  // --- Path Resolution ---
@@ -78,10 +79,37 @@ async function build() {
78
79
  const initialCardsData = await Promise.all(cardFiles.map(async (file) => {
79
80
  const content = await fs.readFile(path.resolve(outDir, file), 'utf-8');
80
81
  const hash = await sha256(content);
81
- return { path: `/${file}`, hash };
82
+
83
+ // Extract title for agents.md
84
+ const tokens = marked.lexer(content);
85
+ const heading = tokens.find(t => t.type === 'heading' && t.depth === 1);
86
+ const title = heading ? heading.text : path.basename(file, path.extname(file));
87
+
88
+ return { path: `/${file}`, hash, title };
82
89
  }));
83
90
  console.log(`Found and processed ${initialCardsData.length} cards.`);
84
91
 
92
+ // Generate agents.html
93
+ console.log('Generating agents.html...');
94
+ let agentsHtml = `<!doctype html>
95
+ <html>
96
+ <head>
97
+ <title>Agents Index</title>
98
+ </head>
99
+ <body>
100
+ <h1>Agents Index</h1>
101
+ <p>This file is meant to help LLMs find documentation. Below is a list of available cards.</p>
102
+ <ul>
103
+ `;
104
+ for (const card of initialCardsData) {
105
+ agentsHtml += ` <li><a href="${card.path}">${card.title}</a></li>\n`;
106
+ }
107
+ agentsHtml += ` </ul>
108
+ </body>
109
+ </html>`;
110
+ await fs.writeFile(path.resolve(outDir, 'agents.html'), agentsHtml);
111
+ console.log('agents.html generated.');
112
+
85
113
  // Generate asset manifest for service worker
86
114
  console.log('Generating asset manifest...');
87
115
  const manifest = await fs.readJson(path.resolve(assetsDir, '.vite/manifest.json'));
@@ -111,6 +139,9 @@ async function build() {
111
139
  pinnedCardPaths: buildConfig.pinned,
112
140
  entryFile: `/assets/${entryFile}`,
113
141
  cssFiles,
142
+ favicon: buildConfig.favicon,
143
+ scripts: buildConfig.scripts,
144
+ stylesheets: buildConfig.stylesheets,
114
145
  });
115
146
 
116
147
  await fs.writeFile(path.resolve(outDir, 'index.html'), html);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3sln/deck",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "A Vite plugin for building scalable, zero-config, Markdown-based component playgrounds and documentation sites.",
5
5
  "type": "module",
6
6
  "author": "Ray Stubbs",
package/src/config.js CHANGED
@@ -17,6 +17,9 @@ export async function loadDeckConfig(root) {
17
17
 
18
18
  const defaultConfig = {
19
19
  title: 'Deck',
20
+ favicon: null,
21
+ scripts: [],
22
+ stylesheets: [],
20
23
  pinned: [],
21
24
  pick: {},
22
25
  include: ['**/*'],
@@ -58,7 +61,25 @@ export function getCardFiles(root, config) {
58
61
  }).filter(s => s.endsWith('.md') || s.endsWith('.html'));
59
62
  }
60
63
 
61
- export function getHtmlTemplate({ title, importMap, initialCardsData, pinnedCardPaths, entryFile, cssFiles = [] }) {
64
+ export function getHtmlTemplate({ title, importMap, initialCardsData, pinnedCardPaths, entryFile, cssFiles = [], favicon, scripts = [], stylesheets = [] }) {
65
+ const scriptTags = scripts.map(s => {
66
+ if (typeof s === 'string') return `<script src="${s}"></script>`;
67
+ const attrs = Object.entries(s).map(([k, v]) => {
68
+ if (v === true) return k;
69
+ return `${k}="${v}"`;
70
+ }).join(' ');
71
+ return `<script ${attrs}></script>`;
72
+ }).join('\n');
73
+
74
+ const styleTags = stylesheets.map(s => {
75
+ if (typeof s === 'string') return `<link rel="stylesheet" href="${s}">`;
76
+ const attrs = Object.entries(s).map(([k, v]) => {
77
+ if (v === true) return k;
78
+ return `${k}="${v}"`;
79
+ }).join(' ');
80
+ return `<link rel="stylesheet" ${attrs}>`;
81
+ }).join('\n');
82
+
62
83
  return `
63
84
  <!doctype html>
64
85
  <html lang="en">
@@ -66,6 +87,8 @@ export function getHtmlTemplate({ title, importMap, initialCardsData, pinnedCard
66
87
  <meta charset="utf-8">
67
88
  <meta name="viewport" content="width=device-width, initial-scale=1">
68
89
  <title>${title}</title>
90
+ ${favicon ? `<link rel="icon" href="${favicon}">` : ''}
91
+ ${styleTags}
69
92
  ${importMap ? `<script type="importmap">${JSON.stringify(importMap)}</script>` : ''}
70
93
  <script>
71
94
  window.__INITIAL_CARDS_DATA__ = ${JSON.stringify(initialCardsData)};
@@ -88,9 +111,13 @@ export function getHtmlTemplate({ title, importMap, initialCardsData, pinnedCard
88
111
  }
89
112
  </style>
90
113
  ${cssFiles.map(file => `<link rel="stylesheet" href="/assets/${file}">`).join('\n')}
114
+ ${scriptTags}
91
115
  </head>
92
116
  <body>
93
117
  <div id="root"></div>
118
+ <div style="display: none;" aria-hidden="true">
119
+ This is a Single Page Application. Agents should look at the <a href="/agents.html">agents.html</a> file for documentation they can read easily.
120
+ </div>
94
121
  <script type="module">
95
122
  import { renderDeck } from '${entryFile}';
96
123
  renderDeck({
package/vite-plugin.js CHANGED
@@ -151,7 +151,10 @@ export default function deckPlugin() {
151
151
  importMap: devConfig.importMap,
152
152
  initialCardsData,
153
153
  pinnedCardPaths: devConfig.pinned,
154
- entryFile: '@3sln/deck'
154
+ entryFile: '@3sln/deck',
155
+ favicon: devConfig.favicon,
156
+ scripts: devConfig.scripts,
157
+ stylesheets: devConfig.stylesheets,
155
158
  });
156
159
  const html = await server.transformIndexHtml(req.url, template);
157
160
  res.end(html);