Changes
27 changed files (+701/-79)
-
-
-
@@ -27,7 +27,9 @@ "toml": {"useTabs": true }, "markup": { "useTabs": true "useTabs": true, "scriptIndent": true, "styleIndent": true }, "malva": { "useTabs": true
-
-
-
@@ -14,3 +14,7 @@# What: ビルドされた *.d.ts ファイルを格納するディレクトリ。 # Why: 自動生成されたディレクトリのため。 /types # What: Astro の中間ファイルとか。 # Why: 自動生成されたディレクトリのため。 .astro
-
-
-
@@ -0,0 +1,15 @@// [Astro](https://astro.build/) のビルド設定。 // // SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only import { defineConfig } from "astro/config"; export default defineConfig({ trailingSlash: "always", srcDir: "./src/docs", outDir: "./docs-dist", devToolbar: { enabled: false, }, });
-
-
-
@@ -3,9 +3,9 @@ "name": "@yamori/gui","private": true, "type": "module", "scripts": { "dev": "vite", "build:lib": "TARGET=lib vite build && tsc -p tsconfig.build.jsonc", "build:docs": "vite build", "dev": "ASTRO_TELEMETRY_DISABLED=1 astro dev", "build:lib": "vite build && tsc -p tsconfig.build.jsonc", "build:docs": "ASTRO_TELEMETRY_DISABLED=1 astro build", "build:all": "bun build:lib && bun build:docs", "build": "bun build:lib", "clean": "rm -rf dist docs-dist types",
-
@@ -20,7 +20,13 @@ "./*.css": {"default": "./dist/*.css" } }, "dependencies": { "@fontsource-variable/inter": "^5.1.0", "@fontsource/ibm-plex-sans-jp": "^5.1.0", "@fontsource/monaspace-neon": "^5.1.0" }, "devDependencies": { "astro": "^5.0.3", "typescript": "^5.7.2", "vite": "^6.0.2" }
-
-
-
packages/gui/src/_docs/styles.css (deleted)
-
@@ -1,13 +0,0 @@/* ドキュメントページの共通 CSS 。 * * SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> * SPDX-License-Identifier: AGPL-3.0-only */ body { display: flex; flex-direction: column; align-items: start; gap: var(--space-px-2); padding: var(--space-px-4); }
-
-
-
@@ -5,6 +5,8 @@ * SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com>* SPDX-License-Identifier: AGPL-3.0-only */ @import "./reset.css"; @import "./vars/base.css"; @import "./vars/dark.css" (prefers-color-scheme: dark); @import "./vars/contrast.css" (prefers-contrast: more);
-
-
-
@@ -0,0 +1,33 @@--- // SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only --- <style> .doc > :global(:where(*)) { display: block; margin: 1em 0; } .doc :global(h2) { font-weight: bold; font-size: var(--font-lg); margin-top: 2em; } .doc :global(ul) { display: flex; flex-direction: column; align-items: start; padding-inline-start: 1.25em; } .doc :global(ul > li) { display: list-item; list-style: disc; } </style> <div class="doc"> <slot /> </div>
-
-
-
@@ -0,0 +1,23 @@--- // SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only const { class: className, ...rest } = Astro.props; --- <style> .nav { padding: var(--space-px-4) var(--space-px-5); } .list { display: flex; flex-direction: column; } </style> <nav {...rest} class:list={["nav", className]}> <ul class="list"> <slot /> </ul> </nav>
-
-
-
@@ -0,0 +1,68 @@--- // SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only const { defaultOpened = true, title } = Astro.props; --- <style> .wrapper { display: block; margin: var(--space-px-6) 0; } .collapsible { display: block; min-width: 0; width: 100%; } .toggle { display: flex; justify-content: space-between; align-items: center; min-width: 0; width: 100%; border: 1px solid transparent; padding: var(--space-px-4) var(--space-px-5); font-size: var(--font-sm); font-weight: bold; border-radius: 4px; cursor: pointer; } .toggle:hover { background-color: oklch(var(--color-fg) / 5%); } .toggle:focus-visible { border-color: oklch(var(--color-border) / var(--alpha-border-strong)); } .toggle-indicator::before { content: "+"; } .collapsible[open] .toggle-indicator::before { content: "-"; } .list { display: flex; flex-direction: column; padding-inline-start: var(--space-px-6); } </style> <li class="wrapper"> <details class="collapsible" open={defaultOpened}> <summary class="toggle"> <span>{title}</span> <span class="toggle-indicator" /> </summary> <ul class="list"> <slot /> </ul> </details> </li>
-
-
-
@@ -0,0 +1,38 @@--- // SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only const { href } = Astro.props; --- <style> .wrapper { display: block; margin: var(--space-px-3) 0; } .link { display: block; min-width: 0; width: 100%; padding: var(--space-px-4) var(--space-px-5); border: 1px solid transparent; border-radius: 4px; cursor: pointer; } .link:hover { background-color: oklch(var(--color-fg) / 5%); } .link:focus-visible { border-color: oklch(var(--color-border) / var(--alpha-border-strong)); } </style> <li class="wrapper"> <a class="link" href={href}> <slot /> </a> </li>
-
-
-
@@ -0,0 +1,84 @@--- // SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only import ThemeOverride from "./ThemeOverride.astro"; interface Props { title?: string; colorScheme?: "dark" | "light"; contrast?: "more" | "no-preference"; } const { colorScheme, contrast, title, ...rest } = Astro.props; --- <style> .preview { display: flex; flex-direction: column; border: 1px solid oklch(var(--color-border) / var(--alpha-border-medium)); border-radius: 4px; overflow: hidden; } .override { display: block; padding: var(--space-px-7); background-color: oklch(var(--color-bg)); color: oklch(var(--color-fg)); } .header { display: block; padding: var(--space-px-5); font-size: var(--font-sm); font-weight: bold; border-bottom: 1px solid oklch(var(--color-border) / var(--alpha-border-subtle)); background-color: oklch(var(--color-fg) / 2%); color: oklch(var(--color-fg) / var(--alpha-fg-medium)); } .footer { display: block; border-top: 1px solid oklch(var(--color-border) / var(--alpha-border-subtle)); font-family: var(--font-mono); font-size: var(--font-xs); padding: var(--space-px-4); background-color: oklch(var(--color-fg) / 2%); color: oklch(var(--color-fg) / var(--alpha-fg-subtle)); text-align: end; } </style> <div {...rest} class="preview"> { title && ( <div class="header"> {title} </div> ) } <ThemeOverride class="override" color-scheme={colorScheme} contrast={contrast} > <slot /> </ThemeOverride> { (colorScheme || contrast) && ( <code class="footer"> {colorScheme && <span>(prefers-color-scheme: {colorScheme})</span>} {colorScheme && contrast ? <span> and </span> : null} {contrast && <span>(prefers-contrast: {contrast})</span>} </code> ) } </div>
-
-
-
@@ -0,0 +1,42 @@--- // SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only import Preview from "./Preview.astro"; const colorSchemes = ["light", "dark"]; const contrasts = ["no-preference", "more"]; const matrix = colorSchemes .map((colorScheme) => { return contrasts.map((contrast) => { return { colorScheme, contrast, }; }); }) .flat(); --- <style> .matrix { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); gap: var(--space-px-8); } .preview { width: 100%; } </style> <div class="matrix"> { matrix.map((overrides) => ( <Preview {...overrides}> <slot /> </Preview> )) } </div>
-
-
-
@@ -0,0 +1,14 @@--- // SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only --- <script> import { DocsThemeOverride } from "./docs-theme-override.ts"; DocsThemeOverride.register(); </script> <docs-theme-override {...Astro.props}> <slot /> </docs-theme-override>
-
-
-
@@ -0,0 +1,128 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only import { component } from "../../components/_utils.ts"; import base from "../../vars/base.css?inline"; import dark from "../../vars/dark.css?inline"; import contrast from "../../vars/contrast.css?inline"; import darkContrast from "../../vars/dark-contrast.css?inline"; export const DocsThemeOverride = component( "docs-theme-override", class DocsThemeOverride extends HTMLElement { static get observedAttributes() { return ["color-scheme", "contrast"] as const; } #contrast: "more" | "no-preference" | null = null; #colorScheme: "dark" | "light" | null = null; #darkStyle: HTMLStyleElement; #contrastStyle: HTMLStyleElement; #darkContrastStyle: HTMLStyleElement; attributeChangedCallback( name: (typeof DocsThemeOverride)["observedAttributes"][number], oldValue: string | null, newValue: string | null, ) { if (oldValue === newValue) { return; } switch (name) { case "color-scheme": this.setColorScheme(newValue); return; case "contrast": this.setContrast(newValue); return; } } setContrast(value: string | null): void { switch (value) { case null: case "more": case "no-preference": this.#contrast = value; this.updateMediaQueries(); return; default: console.warn( `Invalid contrast override "${value}". Accepted values are: "more", "no-preference" and null`, ); return; } } setColorScheme(value: string | null): void { switch (value) { case null: case "dark": case "light": this.#colorScheme = value; this.updateMediaQueries(); return; default: console.warn( `Invalid color-scheme override "${value}". Accepted values are: "dark", "light" and null`, ); return; } } updateMediaQueries(): void { const dark = this.#colorScheme === null ? "(prefers-color-scheme: dark)" : this.#colorScheme === "dark" ? "all" : "not all"; const contrast = this.#contrast === null ? "(prefers-contrast: more)" : this.#contrast === "more" ? "all" : "not all"; this.#darkStyle.media = dark; this.#contrastStyle.media = contrast; this.#darkContrastStyle.media = dark === contrast ? dark : `${dark} and ${contrast}`; } constructor() { super(); const shadow = this.attachShadow({ mode: "open", }); const baseStyle = document.createElement("style"); baseStyle.textContent = base; shadow.appendChild(baseStyle); this.#darkStyle = document.createElement("style"); this.#darkStyle.textContent = dark; shadow.appendChild(this.#darkStyle); this.#contrastStyle = document.createElement("style"); this.#contrastStyle.textContent = contrast; shadow.appendChild(this.#contrastStyle); this.#darkContrastStyle = document.createElement("style"); this.#darkContrastStyle.textContent = darkContrast; shadow.appendChild(this.#darkContrastStyle); this.updateMediaQueries(); const slot = document.createElement("slot"); shadow.appendChild(slot); } }, );
-
-
-
@@ -0,0 +1,101 @@--- // SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only import "../../all.css"; import NavBar from "../components/NavBar.astro"; import NavBarGroup from "../components/NavBarGroup.astro"; import NavBarItem from "../components/NavBarItem.astro"; const { title } = Astro.props; --- <html lang="ja"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>{title} | Yamori GUI</title> <style> .body { position: absolute; inset: 0; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: max-content minmax(0, 1fr); gap: var(--space-px-12); } .nav { border-bottom: 1px solid oklch(var(--color-border) / var(--alpha-border-medium)); } @media (min-width: 1200px) { .body { grid-template-columns: minmax(0, 1fr) minmax(0, 60rem); grid-template-rows: 100%; } .nav { border-bottom: none; border-right: 1px solid oklch(var(--color-border) / var(--alpha-border-medium)); } } @media (min-width: 1700px) { .body { grid-template-columns: minmax(0, 1fr) minmax(0, 60rem) minmax(0, 1fr); } } .main { display: block; padding: var(--space-px-4); width: 100%; } .header { display: block; padding: var(--space-px-9) var(--space-px-8); border-bottom: 1px solid oklch(var(--color-border) / var(--alpha-border-subtle)); color: oklch(var(--color-fg) / var(--alpha-fg-strong)); } .title { font-size: var(--font-xl); font-weight: bold; } .contents { display: block; margin: var(--space-px-10) var(--space-px-8); } </style> <script src="../register.ts"></script> </head> <body class="body"> <NavBar class="nav"> <NavBarItem href="/"> About </NavBarItem> <NavBarGroup title="Components"> <NavBarItem href="/components/button/"> Button </NavBarItem> </NavBarGroup> </NavBar> <main class="main"> <header class="header"> <h1 class="title">{title}</h1> </header> <div class="contents"> <slot /> </div> </main> </body> </html>
-
-
-
@@ -0,0 +1,38 @@--- // SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only import DocsLayout from "../../layouts/DocsLayout.astro"; import Document from "../../components/Document.astro"; import Preview from "../../components/Preview.astro"; import ThemeMatrixPreview from "../../components/ThemeMatrixPreview.astro"; --- <DocsLayout title="Button"> <Document> <p> ユーザがクリックやタップをすることでアクションを実行する UI です。 以下の操作を「押す」という操作とみなします。 </p> <ul> <li>クリック (マウス)</li> <li>タップ (タッチインターフェイス)</li> <li>フォーカスが当たっている状態で <kbd>Space</kbd> キー (キーボード)</li> </ul> <ThemeMatrixPreview> <yamori-button>ボタン</yamori-button> </ThemeMatrixPreview> <h2>Inline / Block</h2> <p> ボタンはデフォルトでブロックレベル要素となっています。 <code>inline</code> 属性を指定することでインラインになります。 </p> <Preview title="inline"> <yamori-button inline="">ボタン</yamori-button> </Preview> <Preview title="block (デフォルト)"> <yamori-button>Button</yamori-button> </Preview> </Document> </DocsLayout>
-
-
-
@@ -0,0 +1,23 @@--- // SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only import DocsLayout from "../layouts/DocsLayout.astro"; import Document from "../components/Document.astro"; --- <DocsLayout title="Yamori GUI"> <Document> <p> Yamori のスタイルシートとコンポーネントのドキュメント兼デモサイトです。 </p> <h2>Components</h2> <p> CustomElement で実装されたセマンティクスを持つ UI 要素です。 </p> <p> ドメインデータには関与せず、インタラクションや表示といったユーザとのやりとりにのみ関心を持ちます。そのため Protobuf で定義されたデータを受け取る・出力することはありません。 </p> </Document> </DocsLayout>
-
-
-
@@ -4,12 +4,19 @@ * SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com>* SPDX-License-Identifier: AGPL-3.0-only */ @import "./reset.css"; @import "@fontsource/monaspace-neon/400.css"; @import "@fontsource-variable/inter"; @import "@fontsource/ibm-plex-sans-jp/400.css"; body { font-size: 1rem; line-height: 1.25; line-height: 1.5; font-family: var(--font-sans); background-color: oklch(var(--color-bg)); color: oklch(var(--color-fg)); color: oklch(var(--color-fg) / var(--alpha-fg-medium)); } :not(:defined) { display: none; }
-
-
packages/gui/src/index.html (deleted)
-
@@ -1,16 +0,0 @@<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>パッケージドキュメント | Yamori GUI</title> <link rel="stylesheet" href="./all.css" /> <script type="module" async src="./_docs/register.ts"></script> <link rel="stylesheet" href="./_docs/styles.css" /> </head> <body> <yamori-button inline>ボタン</yamori-button> <yamori-button>Button</yamori-button> <button>Normal Button</button> </body> </html>
-
-
-
@@ -6,7 +6,8 @@ */:root, :host { --font-sans: "Inter Variable", sans-serif; --font-sans: "Inter Variable", "IBM Plex Sans JP", sans-serif; --font-mono: "Monaspace Neon", monospace; /* Plastic Ratio の近似値 */ --scale: calc(53 / 40);
-
@@ -19,9 +20,41 @@ --color-bg: var(--color-bg-l) var(--chroma) var(--hue);--color-fg-l: 25%; --color-fg: var(--color-fg-l) var(--chroma) var(--hue); --alpha-fg-strong: 95%; --alpha-fg-medium: 85%; --alpha-fg-subtle: 60%; --color-border-l: 20%; --color-border: var(--color-border-l) var(--chroma) var(--hue); --alpha-border-strong: 50%; --alpha-border-medium: 25%; --alpha-border-subtle: 10%; /* pow() が広く実装されて1年程度しか経っていないため我慢 */ --space-px-1: 2px; --space-px-2: calc(var(--space-px-1) * var(--scale)); --space-px-3: calc(var(--space-px-2) * var(--scale)); --space-px-4: calc(var(--space-px-3) * var(--scale)); --space-px-5: calc(var(--space-px-4) * var(--scale)); --space-px-6: calc(var(--space-px-5) * var(--scale)); --space-px-7: calc(var(--space-px-6) * var(--scale)); --space-px-8: calc(var(--space-px-7) * var(--scale)); --space-px-9: calc(var(--space-px-8) * var(--scale)); --space-px-10: calc(var(--space-px-9) * var(--scale)); --space-px-11: calc(var(--space-px-10) * var(--scale)); --space-px-12: calc(var(--space-px-11) * var(--scale)); --space-px-13: calc(var(--space-px-12) * var(--scale)); --space-px-14: calc(var(--space-px-13) * var(--scale)); --space-px-15: calc(var(--space-px-14) * var(--scale)); --space-px-16: calc(var(--space-px-15) * var(--scale)); --space-px-17: calc(var(--space-px-16) * var(--scale)); --space-px-18: calc(var(--space-px-17) * var(--scale)); --space-px-19: calc(var(--space-px-18) * var(--scale)); --space-px-20: calc(var(--space-px-19) * var(--scale)); --font-md: 1rem; --font-lg: calc(var(--font-md) * var(--scale)); --font-xl: calc(var(--font-lg) * var(--scale)); --font-sm: calc(var(--font-md) / var(--scale)); --font-xs: calc(var(--font-sm) / var(--scale)); }
-
-
-
@@ -8,4 +8,12 @@:root, :host { --color-fg-l: 1%; --alpha-fg-strong: 100%; --alpha-fg-medium: 95%; --alpha-fg-subtle: 80%; --color-border-l: 3%; --alpha-border-strong: 90%; --alpha-border-medium: 50%; --alpha-border-subtle: 30%; }
-
-
-
@@ -9,4 +9,5 @@ :root,:host { --color-bg-l: 10%; --color-fg-l: 99%; --color-border-l: 95%; }
-
-
-
@@ -9,4 +9,5 @@ :root,:host { --color-bg-l: 15%; --color-fg-l: 95%; --color-border-l: 90%; }
-
-
-
@@ -11,5 +11,5 @@ "emitDeclarationOnly": true,"outDir": "./types" }, "include": ["src/**/*.ts"], "exclude": ["src/_docs/*.ts"] "exclude": ["src/docs/*.ts"] }
-
-
-
@@ -4,20 +4,11 @@ //// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only import { readdir } from "node:fs/promises"; import { extname, relative } from "node:path"; import { relative } from "node:path"; import { defineConfig, type UserConfig, type Rollup } from "vite"; const srcDir = new URL("./src/", import.meta.url); async function htmlFilesToRollupInput(): Promise<Rollup.InputOption> { const files = await readdir(srcDir, { recursive: true }); return files .filter((file) => extname(file) === ".html") .map((file) => new URL(file, srcDir).pathname); } function libraryCSSFiles( files: readonly URL[],
-
@@ -52,36 +43,25 @@export default defineConfig(async () => { return { root: srcDir.pathname, build: // Vite はライブラリと通常の HTML 出力を同時に行えない仕様バグがあるため、 // 環境変数でビルド対象を切り分けて複数回実行することで両方ビルドしている。 process.env.TARGET === "lib" ? { emptyOutDir: true, outDir: "../dist", cssCodeSplit: true, lib: { entry: { ...libraryCSSFiles([ new URL("./src/all.css", import.meta.url), new URL("./src/reset.css", import.meta.url), new URL("./src/global.css", import.meta.url), new URL("./src/vars/base.css", import.meta.url), new URL("./src/vars/dark.css", import.meta.url), new URL("./src/vars/contrast.css", import.meta.url), new URL("./src/vars/dark-contrast.css", import.meta.url), ]), lib: new URL("./lib.ts", srcDir).pathname, }, formats: ["es"], }, } : { emptyOutDir: true, outDir: "../docs-dist", rollupOptions: { input: await htmlFilesToRollupInput(), }, }, build: { emptyOutDir: true, outDir: "../dist", cssCodeSplit: true, lib: { entry: { ...libraryCSSFiles([ new URL("./src/all.css", import.meta.url), new URL("./src/reset.css", import.meta.url), new URL("./src/global.css", import.meta.url), new URL("./src/vars/base.css", import.meta.url), new URL("./src/vars/dark.css", import.meta.url), new URL("./src/vars/contrast.css", import.meta.url), new URL("./src/vars/dark-contrast.css", import.meta.url), ]), lib: new URL("./lib.ts", srcDir).pathname, }, formats: ["es"], }, }, } satisfies UserConfig; });
-