@aklinker1/viteshot 0.4.0 → 0.4.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.
package/README.md CHANGED
@@ -66,8 +66,7 @@ Your screenshot designs go in `store/designs/{name}@{width}x{height}.{ext}`.
66
66
  ### Vue
67
67
 
68
68
  1. Add `@vitejs/plugin-vue` to `store/viteshot.config.ts`
69
- 2. Add a `.vue` design file
70
- 3. Use the `t` prop to access translations for the current locale
69
+ 2. Use the `t` prop to access translations for the current locale
71
70
 
72
71
  ```vue
73
72
  <!-- store/designs/example@640x480.vue -->
@@ -87,8 +86,7 @@ defineProps<{
87
86
  ### Svelte
88
87
 
89
88
  1. Add `@sveltejs/vite-plugin-svelte` to `store/viteshot.config.ts`
90
- 2. Add a `.svelte` design file
91
- 3. Use the `t` prop to access translations for the current locale
89
+ 2. Use the `t` prop to access translations for the current locale
92
90
 
93
91
  ```svelte
94
92
  <!-- store/designs/example@640x480.svelte -->
@@ -102,9 +100,8 @@ defineProps<{
102
100
  ### React
103
101
 
104
102
  1. Add `@vitejs/plugin-react` to `store/viteshot.config.ts`
105
- 2. Export your component as the default module from your `.tsx` or `.jsx` file
106
- 3. Import any styles
107
- 4. Use the `t` prop to access translations for the current locale
103
+ 2. You're component must be the default export
104
+ 3. Use the `t` prop to access translations for the current locale
108
105
 
109
106
  ```tsx
110
107
  // store/designs/example@640x400.tsx
package/dist/index.d.mts CHANGED
@@ -53,12 +53,12 @@ type Screenshot = {
53
53
  id: string;
54
54
  path: string;
55
55
  ext: string;
56
- filenameNoExt: string;
57
56
  name: string;
58
- size: string | undefined;
59
- width: number | undefined;
60
- height: number | undefined;
57
+ size: string;
58
+ width: number;
59
+ height: number;
61
60
  };
62
61
  declare function getScreenshots(designsDir: string): Promise<Screenshot[]>;
62
+ declare function logInvalidDesignFiles(designsDir: string): Promise<void>;
63
63
  //#endregion
64
- export { InlineConfig, PuppeteerOptions, ResolvedConfig, Screenshot, UserConfig, createServer, defineConfig, exportScreenshots, getScreenshots, resolveConfig };
64
+ export { InlineConfig, PuppeteerOptions, ResolvedConfig, Screenshot, UserConfig, createServer, defineConfig, exportScreenshots, getScreenshots, logInvalidDesignFiles, resolveConfig };
package/dist/index.mjs CHANGED
@@ -2,6 +2,7 @@ import { dirname, extname, join, relative, resolve } from "node:path";
2
2
  import { pathToFileURL } from "node:url";
3
3
  import { mkdir, readFile, readdir, rm } from "node:fs/promises";
4
4
  import natsort from "natural-compare-lite";
5
+ import { styleText } from "node:util";
5
6
  import { createServer as createServer$1 } from "vite";
6
7
  import puppeteer from "puppeteer-core";
7
8
  import pMap from "p-map";
@@ -12,7 +13,7 @@ var favicon_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1
12
13
 
13
14
  //#endregion
14
15
  //#region src/templates/dashboard.html?raw
15
- var dashboard_default = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Viteshot</title>\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\" />\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n min-width: 0;\n min-height: 0;\n list-style: none;\n }\n\n :root {\n --color-base: #000000;\n --color-base-content: #ffffff;\n --color-accent: #2ce4f4;\n --spacing: 0.25rem;\n color-scheme: dark;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n [data-theme=\"light\"] {\n --color-base: #f8f8f0;\n --color-base-content: #000000;\n --color-accent: #008996;\n color-scheme: light;\n }\n body {\n background-color: var(--color-base);\n color: var(--color-base-content);\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n \"Segoe UI\",\n Roboto,\n \"Helvetica Neue\",\n Arial,\n sans-serif;\n }\n a {\n color: var(--color-accent);\n font-weight: 500;\n text-decoration: underline;\n }\n a:hover {\n color: color-mix(\n in srgb,\n var(--color-accent) 70%,\n var(--color-base-content)\n );\n }\n\n .app {\n display: flex;\n flex-direction: column;\n gap: calc(4 * var(--spacing));\n }\n .header {\n display: flex;\n align-items: center;\n gap: calc(2 * var(--spacing));\n padding: calc(4 * var(--spacing)) calc(4 * var(--spacing)) 0\n calc(4 * var(--spacing));\n }\n .header .left {\n flex: 1;\n display: flex;\n align-items: center;\n gap: calc(4 * var(--spacing));\n }\n .header .left h1 {\n font-size: calc(6 * var(--spacing));\n }\n .header .left a {\n font-size: calc(4 * var(--spacing));\n display: flex;\n align-items: center;\n }\n .header .left a svg {\n width: calc(4 * var(--spacing));\n height: calc(4 * var(--spacing));\n }\n .header .language-select {\n flex-shrink: 0;\n height: calc(8 * var(--spacing));\n padding: 0 calc(1 * var(--spacing)) 0 calc(2 * var(--spacing));\n }\n\n .theme-toggle {\n display: block;\n padding: var(--spacing);\n width: calc(8 * var(--spacing));\n height: calc(8 * var(--spacing));\n }\n .theme-toggle > .light {\n display: none;\n }\n *[data-theme=\"light\"] .theme-toggle > .dark {\n display: none;\n }\n *[data-theme=\"light\"] .theme-toggle > .light {\n display: block;\n }\n\n .list-item {\n display: flex;\n flex-direction: column;\n gap: calc(2 * var(--spacing));\n border-top: calc(0.5 * var(--spacing)) solid\n color-mix(in srgb, var(--color-base-content) 50%, transparent);\n }\n .list-item .title-row {\n padding: calc(4 * var(--spacing)) calc(4 * var(--spacing)) 0\n calc(4 * var(--spacing));\n font-size: calc(4 * var(--spacing));\n font-weight: normal;\n }\n .list-item .title-row .name {\n font-size: calc(5 * var(--spacing));\n }\n .list-item .title-row .size {\n color: color-mix(in srgb, var(--color-base-content) 50%, transparent);\n }\n .list-item .iframe-wrapper {\n overflow-x: auto;\n width: 100%;\n padding: 0 calc(4 * var(--spacing)) calc(4 * var(--spacing))\n calc(4 * var(--spacing));\n }\n .list-item iframe {\n border: calc(0.5 * var(--spacing)) solid\n color-mix(in srgb, var(--color-base-content) 50%, transparent);\n }\n </style>\n </head>\n <body>\n <div id=\"app\" class=\"app\"></div>\n <script type=\"module\" src=\"/viteshot-assets/dashboard.ts\"><\/script>\n </body>\n</html>\n";
16
+ var dashboard_default = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Viteshot</title>\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\" />\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n min-width: 0;\n min-height: 0;\n list-style: none;\n }\n\n :root {\n --color-base: #000000;\n --color-base-content: #ffffff;\n --color-accent: #2ce4f4;\n --spacing: 0.25rem;\n color-scheme: dark;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n [data-theme=\"light\"] {\n --color-base: #f8f8f0;\n --color-base-content: #000000;\n --color-accent: #008996;\n color-scheme: light;\n }\n body {\n background-color: var(--color-base);\n color: var(--color-base-content);\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n \"Segoe UI\",\n Roboto,\n \"Helvetica Neue\",\n Arial,\n sans-serif;\n }\n a {\n color: var(--color-accent);\n font-weight: 500;\n text-decoration: underline;\n }\n a:hover {\n color: color-mix(\n in srgb,\n var(--color-accent) 70%,\n var(--color-base-content)\n );\n }\n\n .app {\n display: flex;\n flex-direction: column;\n gap: calc(4 * var(--spacing));\n }\n .header {\n display: flex;\n align-items: center;\n gap: calc(2 * var(--spacing));\n padding: calc(4 * var(--spacing)) calc(4 * var(--spacing)) 0\n calc(4 * var(--spacing));\n }\n .header .left {\n flex: 1;\n display: flex;\n align-items: center;\n gap: calc(4 * var(--spacing));\n }\n .header .left h1 {\n font-size: calc(6 * var(--spacing));\n }\n .header .left a {\n font-size: calc(4 * var(--spacing));\n display: flex;\n align-items: center;\n }\n .header .left a svg {\n width: calc(4 * var(--spacing));\n height: calc(4 * var(--spacing));\n }\n .header .language-select {\n flex-shrink: 0;\n height: calc(8 * var(--spacing));\n padding: 0 calc(1 * var(--spacing)) 0 calc(2 * var(--spacing));\n }\n\n .theme-toggle {\n display: block;\n padding: var(--spacing);\n width: calc(8 * var(--spacing));\n height: calc(8 * var(--spacing));\n }\n .theme-toggle > .light {\n display: none;\n }\n *[data-theme=\"light\"] .theme-toggle > .dark {\n display: none;\n }\n *[data-theme=\"light\"] .theme-toggle > .light {\n display: block;\n }\n\n .list-item {\n display: flex;\n flex-direction: column;\n gap: calc(2 * var(--spacing));\n border-top: calc(0.5 * var(--spacing)) solid\n color-mix(in srgb, var(--color-base-content) 50%, transparent);\n }\n .list-item .title-row {\n padding: calc(4 * var(--spacing)) calc(4 * var(--spacing)) 0\n calc(4 * var(--spacing));\n font-size: calc(4 * var(--spacing));\n font-weight: normal;\n }\n .list-item .title-row .name {\n font-size: calc(5 * var(--spacing));\n position: relative;\n }\n .list-item .title-row .name:before {\n content: \"# \";\n position: absolute;\n left: calc(-4 * var(--spacing));\n opacity: 0%;\n transition: 0.1s;\n }\n .list-item .title-row .name:hover:before {\n opacity: 70%;\n }\n .list-item .title-row .size {\n color: color-mix(in srgb, var(--color-base-content) 50%, transparent);\n }\n .list-item .iframe-wrapper {\n overflow-x: auto;\n width: 100%;\n padding: 0 calc(4 * var(--spacing)) calc(4 * var(--spacing))\n calc(4 * var(--spacing));\n }\n .list-item iframe {\n border: calc(0.5 * var(--spacing)) solid\n color-mix(in srgb, var(--color-base-content) 50%, transparent);\n }\n </style>\n </head>\n <body>\n <div id=\"app\" class=\"app\"></div>\n <script type=\"module\" src=\"/viteshot-assets/dashboard.ts\"><\/script>\n </body>\n</html>\n";
16
17
 
17
18
  //#endregion
18
19
  //#region src/templates/screenshot.html?raw
@@ -58,27 +59,37 @@ async function getLocales(localesDir) {
58
59
 
59
60
  //#endregion
60
61
  //#region src/core/get-screenshots.ts
62
+ const FILENAME_REGEX = /^(?<name>.*?)@(?<size>(?<width>[0-9]+)x(?<height>[0-9]+)).(?<ext>.*)$/;
61
63
  async function getScreenshots(designsDir) {
62
64
  return (await readdir(designsDir, {
63
65
  recursive: true,
64
66
  withFileTypes: true
65
67
  })).filter((file) => file.isFile()).map((file) => {
68
+ const match = FILENAME_REGEX.exec(file.name);
69
+ if (!match) return;
66
70
  const path = join(file.parentPath, file.name);
67
- const ext = extname(file.name);
68
- const filenameNoExt = file.name.slice(0, -ext.length);
69
- const [name, size] = filenameNoExt.split("@", 2);
70
- const [width, height] = size ? size.split("x").map((value) => Number(value)) : [];
71
+ const name = match.groups.name;
72
+ const size = match.groups.size;
73
+ const width = Number(match.groups.width);
74
+ const height = Number(match.groups.height);
75
+ const ext = match.groups.ext;
71
76
  return {
72
77
  id: relative(designsDir, path),
73
78
  path,
74
79
  ext,
75
- filenameNoExt,
76
80
  name,
77
81
  size,
78
82
  width,
79
83
  height
80
84
  };
81
- }).toSorted((a, b) => natsort(a.id, b.id));
85
+ }).filter((file) => file != null).toSorted((a, b) => natsort(a.id, b.id));
86
+ }
87
+ async function logInvalidDesignFiles(designsDir) {
88
+ const invalid = (await readdir(designsDir, {
89
+ recursive: true,
90
+ withFileTypes: true
91
+ })).filter((file) => file.isFile()).map((file) => FILENAME_REGEX.exec(file.name) ? void 0 : file).filter((file) => file != null).map((file) => file.name);
92
+ if (invalid.length > 0) console.warn(`${styleText(["bold", "yellow"], "Invalid design file names:")}\n - ${invalid.join("\n - ")}`);
82
93
  }
83
94
 
84
95
  //#endregion
@@ -250,13 +261,16 @@ async function resolveConfig(dir = process.cwd()) {
250
261
  //#endregion
251
262
  //#region src/core/create-server.ts
252
263
  async function createServer(dir) {
253
- return createServer$1((await resolveConfig(dir)).vite);
264
+ const config = await resolveConfig(dir);
265
+ await logInvalidDesignFiles(config.designsDir);
266
+ return createServer$1(config.vite);
254
267
  }
255
268
 
256
269
  //#endregion
257
270
  //#region src/core/export-screenshots.ts
258
271
  async function exportScreenshots(dir) {
259
272
  const config = await resolveConfig(dir);
273
+ await logInvalidDesignFiles(config.designsDir);
260
274
  const cwd = process.cwd();
261
275
  const screenshots = await getScreenshots(config.designsDir);
262
276
  const locales = await getLocales(config.localesDir);
@@ -325,4 +339,4 @@ async function exportScreenshots(dir) {
325
339
  }
326
340
 
327
341
  //#endregion
328
- export { createServer, defineConfig, exportScreenshots, getScreenshots, resolveConfig };
342
+ export { createServer, defineConfig, exportScreenshots, getScreenshots, logInvalidDesignFiles, resolveConfig };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@aklinker1/viteshot",
3
3
  "description": "Generate store screenshots and promo images with code, powered by Vite",
4
- "version": "0.4.0",
4
+ "version": "0.4.1",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.3.9",
7
7
  "scripts": {