Sv443 10 місяців тому
батько
коміт
479acf2407

+ 1 - 0
.eslintrc.cjs

@@ -15,6 +15,7 @@ module.exports = {
     "eslint:recommended",
     "plugin:@typescript-eslint/recommended",
     "plugin:require-extensions/recommended",
+    "plugin:storybook/recommended"
   ],
   globals: {
     Atomics: "readonly",

+ 2 - 0
.gitignore

@@ -10,3 +10,5 @@ dist/out/
 dist/*.css.map
 .build.json
 *.ignore.*
+
+*storybook.log

+ 8 - 0
.storybook/global.css

@@ -0,0 +1,8 @@
+@import url(http://fonts.googleapis.com/css?family=Roboto:400,100,100italic,300,300ita‌​lic,400italic,500,500italic,700,700italic,900italic,900);
+
+body {
+  background-color: #030303;
+  color: #fff;
+  font-family: "Roboto", sans-serif;
+  font-size: 16px;
+}

+ 18 - 0
.storybook/main.ts

@@ -0,0 +1,18 @@
+import type { StorybookConfig } from "@storybook/html-vite";
+
+const config: StorybookConfig = {
+  stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
+  addons: [
+    "@storybook/addon-links",
+    "@storybook/addon-essentials",
+    "@chromatic-com/storybook",
+    "@storybook/addon-interactions",
+    "storybook-dark-mode",
+  ],
+  framework: {
+    name: "@storybook/html-vite",
+    options: {},
+  },
+};
+
+export default config;

+ 24 - 0
.storybook/preview.ts

@@ -0,0 +1,24 @@
+import type { Preview } from "@storybook/html";
+import { themes } from "@storybook/theming";
+import "./global.css";
+
+const preview: Preview = {
+  parameters: {
+    darkMode: {
+      // Override the default dark theme
+      dark: { ...themes.dark, appBg: "#222529" },
+      darkClass: "stb-dark",
+      // Override the default light theme
+      light: { ...themes.normal, appBg: "#fafafa" },
+      lightClass: "stb-light",
+    },
+    controls: {
+      matchers: {
+        color: /(background|color)$/i,
+        date: /Date$/i,
+      },
+    },
+  },
+};
+
+export default preview;

+ 1 - 0
changelog.md

@@ -26,6 +26,7 @@
     - Renamed all YT-specific instances to have the `yt` prefix
       - From `watchFlexy` to `ytWatchFlexy`
       - From `watchMetadata` to `ytWatchMetadata`
+  - Added Storybook for easier and faster development of components
 - **Plugin Interface Changes:**
   - Added new components:
     -  `createLongBtn()` to create a button with an icon and text (works either as normal or as a toggle button)  

Різницю між файлами не показано, бо вона завелика
+ 7553 - 838
package-lock.json


+ 16 - 2
package.json

@@ -27,7 +27,9 @@
     "node-ts": "node --no-warnings=ExperimentalWarning --enable-source-maps --loader ts-node/esm",
     "invisible": "node --enable-source-maps src/tools/run-invisible.mjs",
     "test": "npm run node-ts -- ./test.ts",
-    "knip": "knip"
+    "knip": "knip",
+    "storybook": "storybook dev -p 6006",
+    "build-storybook": "storybook build"
   },
   "engines": {
     "node": ">=18 <22",
@@ -67,10 +69,18 @@
     "nanoevents": "^9.0.0"
   },
   "devDependencies": {
+    "@chromatic-com/storybook": "^1.5.0",
     "@rollup/plugin-json": "^6.0.1",
     "@rollup/plugin-node-resolve": "^15.2.3",
     "@rollup/plugin-terser": "^0.4.4",
     "@rollup/plugin-typescript": "^11.1.5",
+    "@storybook/addon-essentials": "^8.1.5",
+    "@storybook/addon-interactions": "^8.1.5",
+    "@storybook/addon-links": "^8.1.5",
+    "@storybook/blocks": "^8.1.5",
+    "@storybook/html": "^8.1.5",
+    "@storybook/html-vite": "^8.1.5",
+    "@storybook/test": "^8.1.5",
     "@types/express": "^4.17.17",
     "@types/greasemonkey": "^4.0.4",
     "@types/node": "^20.12.12",
@@ -80,12 +90,15 @@
     "dotenv": "^16.4.1",
     "eslint": "^8.51.0",
     "eslint-plugin-require-extensions": "^0.1.3",
+    "eslint-plugin-storybook": "^0.8.0",
     "express": "^4.18.2",
     "knip": "^5.15.1",
     "nodemon": "^3.0.1",
     "rollup": "^4.6.0",
     "rollup-plugin-execute": "^1.1.1",
     "rollup-plugin-import-css": "^3.3.5",
+    "storybook": "^8.1.5",
+    "storybook-dark-mode": "^4.0.1",
     "ts-node": "^10.9.1",
     "tslib": "^2.5.2",
     "typescript": "^5.4.5"
@@ -107,7 +120,8 @@
     "ext": "ts,mts,js,jsx,mjs,json,html,css,svg,png",
     "ignore": [
       "dist/*",
-      "dev/*"
+      "dev/*",
+      "*/stories/*"
     ]
   }
 }

+ 57 - 0
src/stories/Button.stories.ts

@@ -0,0 +1,57 @@
+import type { StoryObj, Meta } from "@storybook/html";
+import { fn } from "@storybook/test";
+import { createButton, type ButtonProps } from "./Button.js";
+
+// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
+const meta = {
+  title: "Example/Example Button",
+  tags: ["autodocs"],
+  render: (args) => {
+    // You can either use a function to create DOM elements or use a plain html string!
+    // return `<div>${label}</div>`;
+    return createButton(args);
+  },
+  argTypes: {
+    backgroundColor: { control: "color" },
+    label: { control: "text" },
+    onClick: { action: "onClick" },
+    primary: { control: "boolean" },
+    size: {
+      control: { type: "select" },
+      options: ["small", "medium", "large"],
+    },
+  },
+  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+  args: { onClick: fn() },
+} satisfies Meta<ButtonProps>;
+
+export default meta;
+type Story = StoryObj<ButtonProps>;
+
+// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
+export const Primary: Story = {
+  args: {
+    primary: true,
+    label: "Button",
+  },
+};
+
+export const Secondary: Story = {
+  args: {
+    label: "Button",
+  },
+};
+
+export const Large: Story = {
+  args: {
+    size: "large",
+    label: "Button",
+  },
+};
+
+export const Small: Story = {
+  args: {
+    size: "small",
+    label: "Button",
+  },
+};

+ 38 - 0
src/stories/Button.ts

@@ -0,0 +1,38 @@
+import "./button.css";
+
+export interface ButtonProps {
+  /** Is this the principal call to action on the page? */
+  primary?: boolean;
+  /** What background color to use */
+  backgroundColor?: string;
+  /** How large should the button be? */
+  size?: "small" | "medium" | "large";
+  /** Button contents */
+  label: string;
+  /** Optional click handler */
+  onClick?: () => void;
+}
+
+export const createButton = ({
+  primary = false,
+  size = "medium",
+  backgroundColor,
+  label,
+  onClick,
+}: ButtonProps) => {
+  const btn = document.createElement("button");
+  btn.type = "button";
+  btn.innerText = label;
+  if (onClick) {
+    btn.addEventListener("click", onClick);
+  }
+
+  const mode = primary ? "storybook-button--primary" : "storybook-button--secondary";
+  btn.className = ["storybook-button", `storybook-button--${size}`, mode].join(" ");
+
+  if (backgroundColor) {
+    btn.style.backgroundColor = backgroundColor;
+  }
+
+  return btn;
+};

BIN
src/stories/assets/logo_128.png


+ 4 - 0
src/stories/assets/plus_circle_small.svg

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg height="24" viewBox="0 -960 960 960" width="24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
+  <path fill="#ffffff" d="m 456.54655,-331.45728 h 46.9069 v -125.08927 h 125.08927 v -46.9069 H 503.45345 v -125.08927 h -46.9069 v 125.08927 H 331.45728 v 46.9069 h 125.08927 z m 23.50583,148.54349 q -61.63461,0 -115.86705,-23.39169 -54.23324,-23.39169 -94.35014,-63.49062 -40.11769,-40.0997 -63.51955,-94.3087 -23.40185,-54.20821 -23.40185,-115.84282 0,-61.63461 23.39169,-115.86705 23.39169,-54.23324 63.49062,-94.35014 40.0997,-40.11769 94.3087,-63.51955 54.20821,-23.40185 115.84282,-23.40185 61.63461,0 115.86705,23.39169 54.23324,23.39169 94.35014,63.49062 40.11769,40.0997 63.51955,94.3087 23.40185,54.20821 23.40185,115.84282 0,61.63461 -23.39169,115.86705 -23.39169,54.23324 -63.49062,94.35014 -40.0997,40.11769 -94.3087,63.51955 -54.20821,23.40185 -115.84282,23.40185 z M 480,-229.82148 q 104.76226,0 177.47039,-72.70813 72.70813,-72.70813 72.70813,-177.47039 0,-104.76226 -72.70813,-177.47039 Q 584.76226,-730.17852 480,-730.17852 q -104.76226,0 -177.47039,72.70813 -72.70813,72.70813 -72.70813,177.47039 0,104.76226 72.70813,177.47039 72.70813,72.70813 177.47039,72.70813 z M 480,-480 Z" style="stroke-width:0.781808" />
+</svg>

+ 35 - 0
src/stories/button.css

@@ -0,0 +1,35 @@
+.storybook-button {
+  font-family: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-weight: 700;
+  border: 0;
+  border-radius: 3em;
+  cursor: pointer;
+  display: inline-block;
+  line-height: 1;
+}
+
+.storybook-button--primary {
+  color: white;
+  background-color: #1ea7fd;
+}
+
+.storybook-button--secondary {
+  color: #fff;
+  background-color: transparent;
+  box-shadow: rgba(255, 255, 255, 0.3) 0px 0px 0px 1px inset;
+}
+
+.storybook-button--small {
+  font-size: 12px;
+  padding: 10px 16px;
+}
+
+.storybook-button--medium {
+  font-size: 14px;
+  padding: 11px 20px;
+}
+
+.storybook-button--large {
+  font-size: 16px;
+  padding: 12px 24px;
+}

Деякі файли не було показано, через те що забагато файлів було змінено