@berlysia/vertical-writing-slide-system 0.0.10 → 0.0.11

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/cli.js CHANGED
@@ -30,9 +30,10 @@ async function runBuildAll() {
30
30
  async function runBuild() {
31
31
  try {
32
32
  await build({
33
- root: resolve(import.meta.dirname),
33
+ root: process.cwd(),
34
+ configFile: resolve(import.meta.dirname, "vite.config.ts"),
34
35
  build: {
35
- outDir: resolve("pages"),
36
+ outDir: resolve(process.cwd(), "pages"),
36
37
  },
37
38
  });
38
39
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@berlysia/vertical-writing-slide-system",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "vertical-slides": "./cli.js"
@@ -1,11 +1,11 @@
1
1
  import { existsSync } from "fs";
2
- import { mkdir, readdir, stat, cp, writeFile, mkdtemp, rmdir, } from "fs/promises";
2
+ import { mkdir, readdir, stat, cp, writeFile, mkdtemp, rm } from "fs/promises";
3
3
  import { join, resolve } from "path";
4
4
  import { build } from "vite";
5
5
  const defaultSlidesDir = resolve(import.meta.dirname, "..", "slides");
6
6
  const pagesDir = "pages";
7
7
  // Ensure pages directory exists
8
- await rmdir(pagesDir, { recursive: true });
8
+ await rm(pagesDir, { recursive: true });
9
9
  await mkdir(pagesDir, { recursive: true });
10
10
  async function buildSlide(slideName) {
11
11
  console.log(`Building ${slideName}...`);
@@ -20,7 +20,7 @@ async function buildSlide(slideName) {
20
20
  const slideOutputDir = join(pagesDir, slideName);
21
21
  await mkdir(slideOutputDir, { recursive: true });
22
22
  await cp(tmpDir, slideOutputDir, { recursive: true });
23
- await rmdir(tmpDir, { recursive: true });
23
+ await rm(tmpDir, { recursive: true });
24
24
  }
25
25
  async function createIndexPage(slideNames) {
26
26
  const slides = slideNames
@@ -1,6 +1,6 @@
1
1
  import type { Plugin } from "unified";
2
2
  import { visit } from "unist-util-visit";
3
- import type { Root } from "mdast";
3
+ import type { Root, Image } from "mdast";
4
4
 
5
5
  interface RemarkSlideImagesOptions {
6
6
  base: string;
@@ -12,17 +12,22 @@ const remarkSlideImages: Plugin<[RemarkSlideImagesOptions], Root> = (
12
12
  const { base } = options;
13
13
 
14
14
  return (tree) => {
15
- visit(tree, (node: any) => {
15
+ visit(tree, (node) => {
16
16
  // Handle Markdown image syntax
17
- if (node.type === "image" && typeof node.url === "string") {
18
- if (node.url.startsWith("@slide/")) {
19
- node.url = `${base}slide-assets/images/${node.url.slice(7)}`;
17
+ if (node.type === "image") {
18
+ const imageNode = node as Image;
19
+ if (imageNode.url.startsWith("@slide/")) {
20
+ imageNode.url = `${base}slide-assets/images/${imageNode.url.slice(7)}`;
20
21
  }
21
22
  }
22
23
 
23
24
  // Handle MDX JSX img elements
24
- if (node.type === "mdxJsxFlowElement" && node.name === "img") {
25
- const src = node.attributes?.find(
25
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
+ if (node.type === "mdxJsxFlowElement" && (node as any).name === "img") {
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ const mdxNode = node as any;
29
+ const src = mdxNode.attributes?.find(
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
31
  (attr: any) => attr.type === "mdxJsxAttribute" && attr.name === "src",
27
32
  );
28
33
  if (
@@ -36,9 +41,11 @@ const remarkSlideImages: Plugin<[RemarkSlideImagesOptions], Root> = (
36
41
 
37
42
  // Handle HTML img tags in Markdown
38
43
  if (node.type === "html") {
39
- const value = node.value as string;
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ const htmlNode = node as any;
46
+ const value = htmlNode.value as string;
40
47
  if (value.startsWith("<img")) {
41
- node.value = value.replace(
48
+ htmlNode.value = value.replace(
42
49
  /<img\s+([^>]*src="(@slide\/[^"]+)"[^>]*)>/g,
43
50
  (_, attributes, src) => {
44
51
  return `<img ${attributes.replace(
@@ -50,7 +50,7 @@ function validateSlidesDir(dir: string): void {
50
50
  }
51
51
  try {
52
52
  fs.accessSync(dir, fs.constants.R_OK);
53
- } catch (err) {
53
+ } catch {
54
54
  throw new Error(`No read permission for external slides directory: ${dir}`);
55
55
  }
56
56
  }
@@ -149,10 +149,12 @@ export default async function slidesPlugin(
149
149
 
150
150
  let base: string;
151
151
  let compiledSlides: string[] = [];
152
+ let resolvedConfig: ResolvedConfig;
152
153
  return {
153
154
  name: "vite-plugin-slides",
154
155
  configResolved(config: ResolvedConfig) {
155
156
  base = config.base;
157
+ resolvedConfig = config;
156
158
  },
157
159
  enforce: "pre",
158
160
  resolveId(id: string) {
@@ -282,37 +284,134 @@ export default async function slidesPlugin(
282
284
  }
283
285
  },
284
286
  async buildStart() {
285
- const targetImagesDir = path.resolve(
286
- process.cwd(),
287
- "public/slide-assets/images",
288
- );
289
- const sourceImagesDir = path.resolve(
290
- config.slidesDir,
291
- config.collection,
292
- "images",
293
- );
294
-
295
- // Copy images from slides directory
296
- if (fs.existsSync(sourceImagesDir)) {
287
+ // Ensure index.html exists in consumer project
288
+ const consumerIndexHtml = path.resolve(resolvedConfig.root, "index.html");
289
+
290
+ if (!fs.existsSync(consumerIndexHtml)) {
297
291
  try {
298
- // Create target directory if it doesn't exist
299
- mkdirSync(targetImagesDir, { recursive: true });
300
-
301
- // Copy all files from source to target
302
- const imageFiles = readdirSync(sourceImagesDir);
303
- for (const file of imageFiles) {
304
- const sourcePath = path.join(sourceImagesDir, file);
305
- const targetPath = path.join(targetImagesDir, file);
306
- copyFileSync(sourcePath, targetPath);
307
- }
308
- logger.info("Copied slide images successfully");
292
+ // Create a consumer-specific index.html that points to library sources
293
+ const libraryRoot = path.resolve(import.meta.dirname, "..");
294
+ const relativePath = path.relative(resolvedConfig.root, libraryRoot);
295
+
296
+ const indexHtmlContent = `<!doctype html>
297
+ <html lang="ja">
298
+ <head>
299
+ <meta charset="UTF-8" />
300
+ <link rel="icon" type="image/svg+xml" href="/${relativePath}/vite.svg" />
301
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
302
+ <title>Vertical Writing Slides</title>
303
+ <link rel="preconnect" href="https://fonts.googleapis.com">
304
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
305
+ <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP&family=Noto+Sans+Mono:wght@100..900&display=swap" rel="stylesheet">
306
+ <link rel="stylesheet" href="/${relativePath}/src/index.css" />
307
+ <link rel="stylesheet" media="screen" href="/${relativePath}/src/screen.css" />
308
+ <link rel="stylesheet" media="print" href="/${relativePath}/src/print.css" />
309
+ </head>
310
+ <body>
311
+ <div id="root"></div>
312
+ <script type="module" src="/${relativePath}/src/main.tsx"></script>
313
+ </body>
314
+ </html>`;
315
+
316
+ fs.writeFileSync(consumerIndexHtml, indexHtmlContent);
317
+ logger.info("Generated index.html for consumer project");
309
318
  } catch (error) {
310
319
  if (error instanceof Error) {
311
- logger.error("Failed to copy slide images", error);
320
+ logger.error("Failed to create index.html", error);
312
321
  }
313
322
  throw error;
314
323
  }
315
324
  }
325
+
326
+ // Handle images during dev mode
327
+ if (resolvedConfig.command === "serve") {
328
+ const targetImagesDir = path.resolve(
329
+ resolvedConfig.root,
330
+ "public/slide-assets/images",
331
+ );
332
+ const sourceImagesDir = path.resolve(
333
+ config.slidesDir,
334
+ config.collection,
335
+ "images",
336
+ );
337
+
338
+ // Copy images from slides directory
339
+ if (fs.existsSync(sourceImagesDir)) {
340
+ try {
341
+ // Create target directory if it doesn't exist
342
+ mkdirSync(targetImagesDir, { recursive: true });
343
+
344
+ // Copy all files from source to target
345
+ const imageFiles = readdirSync(sourceImagesDir);
346
+ for (const file of imageFiles) {
347
+ const sourcePath = path.join(sourceImagesDir, file);
348
+ const targetPath = path.join(targetImagesDir, file);
349
+ copyFileSync(sourcePath, targetPath);
350
+ }
351
+ logger.info("Copied slide images successfully");
352
+ } catch (error) {
353
+ if (error instanceof Error) {
354
+ logger.error("Failed to copy slide images", error);
355
+ }
356
+ throw error;
357
+ }
358
+ }
359
+ }
360
+ },
361
+
362
+ generateBundle() {
363
+ // Handle images during build mode
364
+ if (resolvedConfig.command === "build") {
365
+ const sourceImagesDir = path.resolve(
366
+ config.slidesDir,
367
+ config.collection,
368
+ "images",
369
+ );
370
+
371
+ if (fs.existsSync(sourceImagesDir)) {
372
+ try {
373
+ const imageFiles = readdirSync(sourceImagesDir);
374
+ logger.info(
375
+ `Processing ${imageFiles.length} image files from ${sourceImagesDir}`,
376
+ );
377
+
378
+ let processedCount = 0;
379
+ for (const file of imageFiles) {
380
+ const sourcePath = path.join(sourceImagesDir, file);
381
+ try {
382
+ const imageContent = fs.readFileSync(sourcePath);
383
+
384
+ // Add image files to the bundle
385
+ this.emitFile({
386
+ type: "asset",
387
+ fileName: `slide-assets/images/${file}`,
388
+ source: imageContent,
389
+ });
390
+ processedCount++;
391
+ logger.info(`Added image to bundle: ${file}`);
392
+ } catch (fileError) {
393
+ logger.error(
394
+ `Failed to process image file: ${file}`,
395
+ fileError instanceof Error
396
+ ? fileError
397
+ : new Error(String(fileError)),
398
+ );
399
+ // Continue processing other files instead of failing completely
400
+ }
401
+ }
402
+ logger.info(
403
+ `Successfully added ${processedCount}/${imageFiles.length} slide images to bundle`,
404
+ );
405
+ } catch (error) {
406
+ if (error instanceof Error) {
407
+ logger.error("Failed to read slide images directory", error);
408
+ }
409
+ throw error;
410
+ }
411
+ } else {
412
+ logger.warn(`No images directory found at: ${sourceImagesDir}`);
413
+ }
414
+ }
316
415
  },
317
416
 
318
417
  configureServer(server: ViteDevServer) {
package/vite.config.ts CHANGED
@@ -9,7 +9,10 @@ export default defineConfig(async () => {
9
9
  base: "./",
10
10
  resolve: {
11
11
  alias: {
12
- "@components": "/src/slide-components",
12
+ "@components": path.resolve(
13
+ import.meta.dirname,
14
+ "src/slide-components",
15
+ ),
13
16
  },
14
17
  },
15
18
  plugins: [