diff --git a/site/decodal-site/package-lock.json b/site/decodal-site/package-lock.json index 9ff8bb2..6980613 100644 --- a/site/decodal-site/package-lock.json +++ b/site/decodal-site/package-lock.json @@ -11,6 +11,8 @@ "@astrojs/check": "^0.9.4", "@codemirror/language": "^6.12.4", "@codemirror/view": "^6.43.6", + "@fontsource/ibm-plex-mono": "^5.3.0", + "@fontsource/ibm-plex-sans-jp": "^5.3.0", "@lezer/highlight": "^1.2.3", "@lezer/lr": "^1.4.10", "astro": "^4.16.18", @@ -1178,6 +1180,24 @@ "node": ">=12" } }, + "node_modules/@fontsource/ibm-plex-mono": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource/ibm-plex-mono/-/ibm-plex-mono-5.3.0.tgz", + "integrity": "sha512-eTgnZjZEGk1QtD3ZstF+Vclo2HLAni8YMy34/DxllwZvyz1lR/1RF/xTiAquOBO7MvqBx8D2Ig2WCPMVfdZu7Q==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/ibm-plex-sans-jp": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource/ibm-plex-sans-jp/-/ibm-plex-sans-jp-5.3.0.tgz", + "integrity": "sha512-Eas8EEVkh0UbITQMskrCF5Ha1L24GagNsvjMfrKwhv3KNPFRjbZAt0fLO4lSgfx4U4rHWpX5JeMDJNXF+hcguQ==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, "node_modules/@img/colour": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", diff --git a/site/decodal-site/package.json b/site/decodal-site/package.json index 8bf78a5..4de28d2 100644 --- a/site/decodal-site/package.json +++ b/site/decodal-site/package.json @@ -19,6 +19,8 @@ "@astrojs/check": "^0.9.4", "@codemirror/language": "^6.12.4", "@codemirror/view": "^6.43.6", + "@fontsource/ibm-plex-mono": "^5.3.0", + "@fontsource/ibm-plex-sans-jp": "^5.3.0", "@lezer/highlight": "^1.2.3", "@lezer/lr": "^1.4.10", "astro": "^4.16.18", diff --git a/site/decodal-site/src/components/HomePage.astro b/site/decodal-site/src/components/HomePage.astro new file mode 100644 index 0000000..2b48aeb --- /dev/null +++ b/site/decodal-site/src/components/HomePage.astro @@ -0,0 +1,211 @@ +--- +import ManualLayout from '../layouts/ManualLayout.astro'; +import { highlightCode } from '../lib/highlight.js'; + +const { locale = 'en' } = Astro.props; + +const translations = { + en: { + title: 'Decodal — Deferred Constraint Data Language', + description: 'Decodal is a deterministic data language for describing, composing, validating, and materializing structured data.', + heroTitle: 'Configuration, constraints, and defaults are values.', + heroLead: 'Decodal is a small deterministic language for describing, composing, validating, and materializing structured data. The same expression can carry concrete data and the range that data must satisfy.', + playground: 'Open the playground', + introduction: 'Read the introduction', + facts: [ + ['Source', '.dcdl'], + ['Runtime', 'Rust · WebAssembly'], + ['Output', 'Validated structured data'], + ], + exampleLabel: 'Decodal example and materialized result', + materialize: 'materialize', + modelTitle: 'One expression system, from abstract range to concrete data.', + definitions: [ + ['&', 'Compose without discarding constraints', 'Symmetric composition keeps information from both sides and fails when their ranges cannot overlap.'], + ['as', 'Verify that a value is more specific', 'The left side must fit inside the wider range on the right. Wider abstract fields remain available for later materialization.'], + ['//', 'Apply an explicit structural patch', 'Right-biased composition replaces the selected structure while preserving unrelated fields.'], + ['default', 'Choose a fallback only when materializing', 'A default does not erase the range. It is selected only when no more concrete value has been supplied.'], + ], + hostTitle: 'The host owns I/O. Decodal owns evaluation.', + hostDescription: 'Filesystems, Markdown, JSON, network resources, and application globals stay under host control. Decodal receives source or structured values and evaluates them with the same rules in production and editor tooling.', + flowLabel: 'Evaluation flow', + flow: [ + ['Host environment', 'globals · source · structured imports'], + ['Evaluate', 'lazy references · constraints · composition'], + ['Materialize', 'defaults · validation · diagnostics'], + ['Application data', 'Data · Rust type · JavaScript value'], + ], + embedding: 'Read the embedding guide', + packagesTitle: 'Use only the layer your application needs.', + packages: [ + ['Runtime, host embedding, schema derivation, and typed decoding.'], + ['Browser runtime and host-configurable semantic language service.'], + ['Language Server Protocol with application-defined environments.'], + ['CodeMirror 6 syntax, indentation, folding, highlighting, and formatter integration.'], + ], + packagesLink: 'Compare packages and integrations', + }, + ja: { + title: 'Decodal — 制約とデフォルトを値として扱うデータ言語', + description: 'Decodalは、構造化データの記述、合成、検証、具体化のための決定的なデータ言語です。', + heroTitle: '設定、|制約、|デフォルトは、|すべて値です。', + heroLead: 'Decodalは、|構造化データを|記述・合成・検証・具体化するための、|小さく決定的な言語です。|同じ式の中に、|具体的なデータと、|そのデータが満たすべき範囲を|保持できます。', + playground: 'Playgroundを開く', + introduction: 'はじめに読む', + facts: [ + ['ソース', '.dcdl'], + ['ランタイム', 'Rust · WebAssembly'], + ['出力', '検証済みの構造化データ'], + ], + exampleLabel: 'Decodalのコード例と具体化結果', + materialize: '具体化', + modelTitle: '抽象的な範囲から|具体的なデータまで、|ひとつの式体系で。', + definitions: [ + ['&', '制約を失わずに|合成する', '対称な合成は|両辺の情報を残し、|範囲が重ならない場合は|失敗します。'], + ['as', '値がより具体的であることを|検証する', '左辺は、|右辺のより広い範囲に|収まる必要があります。|右辺に残る抽象的なフィールドは、|後の具体化に|利用できます。'], + ['//', '構造を明示的に|上書きする', '右辺優先の合成で、|指定した構造を置き換えながら、|関係のないフィールドを|保持します。'], + ['default', '具体化するときだけ|フォールバックを選ぶ', 'defaultは範囲を消しません。|より具体的な値が|与えられていない場合にだけ|選択されます。'], + ], + hostTitle: 'I/Oはホストが担い、|評価はDecodalが担う。', + hostDescription: 'ファイルシステム、|Markdown、JSON、ネットワーク資源、|アプリケーションのグローバル値は、|ホストの管理下に置かれます。|Decodalはソースまたは|構造化された値を受け取り、|本番環境とエディタツールで|同じ規則を使って評価します。', + flowLabel: '評価の流れ', + flow: [ + ['ホスト環境', 'globals · source ·|構造化import'], + ['評価', '遅延参照 · 制約 ·|合成'], + ['具体化', 'default · 検証 ·|診断'], + ['アプリケーション|データ', 'Data · Rust型 ·|JavaScript値'], + ], + embedding: '組み込みガイドを読む', + packagesTitle: 'アプリケーションに|必要な層だけを|使えます。', + packages: [ + ['ランタイム、|ホストへの組み込み、|スキーマ導出、|型付きデコード。'], + ['ブラウザランタイムと、|ホストから設定できる|セマンティック言語サービス。'], + ['アプリケーション定義の環境を|利用できる|Language Server Protocol実装。'], + ['CodeMirror 6向けの構文、|インデント、折りたたみ、|ハイライト、|フォーマッタ連携。'], + ], + packagesLink: 'パッケージと統合方法を比較する', + }, +}; + +const copy = translations[locale] ?? translations.en; +const escapeHtml = (text) => String(text) + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +const phrase = (text) => locale === 'ja' + ? String(text).split('|').map((part) => `${escapeHtml(part)}`).join('') + : escapeHtml(text); + +const example = `let + Port = Int & >= 1 & <= 65535; + Service = { + host = String; + port = Port default 8080; + }; +in +{ + host = "127.0.0.1"; +} as Service;`; + +const result = `{ + "host": "127.0.0.1", + "port": 8080 +}`; +--- + +
+
+

+

+

+
+ {copy.facts.map(([label, value], index) => ( +
+
{label}
+
{index === 0 ? {value} : value}
+
+ ))} +
+

+ +
+
+ service.dcdl + DCDL +
+
+
+ {copy.materialize} +
{result}
+
+
+
+ +
+
+

+

+
+ {copy.definitions.map(([operator, title, description]) => ( +
+ {operator} +
+

+

+

+
+ ))} +
+
+ +
+
+

+

+

+
    + {copy.flow.map(([title, description], index) => ( +
  1. + {index + 1} + + +
  2. + ))} +
+ +
+ +
+
+

+

+
+ +
+
decodal-wasmJavaScript
+

+ JSRnpm +

+ +
+
decodal-codemirrorJavaScript
+

+ JSRnpm +

+
+ +
+
diff --git a/site/decodal-site/src/layouts/ManualLayout.astro b/site/decodal-site/src/layouts/ManualLayout.astro index 1935a49..70f5522 100644 --- a/site/decodal-site/src/layouts/ManualLayout.astro +++ b/site/decodal-site/src/layouts/ManualLayout.astro @@ -1,5 +1,7 @@ --- import { nav } from '../lib/docs.js'; +import '@fontsource/ibm-plex-mono/latin-400.css'; +import '@fontsource/ibm-plex-mono/latin-600.css'; import '../style.css'; const { @@ -8,10 +10,15 @@ const { active = '', playground = false, frontpage = false, + locale, } = Astro.props; const pathname = Astro.url.pathname; -const language = active ? 'ja' : 'en'; +const language = locale ?? (pathname.startsWith('/docs/') ? 'ja' : 'en'); +const homeHref = language === 'ja' ? '/ja/' : '/'; +const alternateHref = language === 'ja' ? '/' : '/ja/'; +const alternateLabel = language === 'ja' ? 'English' : '日本語'; +const alternateAriaLabel = language === 'ja' ? 'Switch to English' : '日本語に切り替える'; function isCurrent(path) { return pathname === path || (path !== '/' && pathname.startsWith(path)); @@ -35,18 +42,22 @@ function renderNav(items, prefix = []) { + {frontpage && } + {frontpage && } + {frontpage && } {title}
- + Decodal Deferred Constraint Data Language
diff --git a/site/decodal-site/src/pages/docs/[...slug].astro b/site/decodal-site/src/pages/docs/[...slug].astro index b998df4..4467a0e 100644 --- a/site/decodal-site/src/pages/docs/[...slug].astro +++ b/site/decodal-site/src/pages/docs/[...slug].astro @@ -1,6 +1,8 @@ --- import ManualLayout from '../../layouts/ManualLayout.astro'; import { allDocSlugs, docTitle, renderMarkdown } from '../../lib/docs.js'; +import '@fontsource/ibm-plex-sans-jp/400.css'; +import '@fontsource/ibm-plex-sans-jp/600.css'; export function getStaticPaths() { return allDocSlugs().map((slug) => ({ diff --git a/site/decodal-site/src/pages/docs/index.astro b/site/decodal-site/src/pages/docs/index.astro index 9e6d54a..998b5e1 100644 --- a/site/decodal-site/src/pages/docs/index.astro +++ b/site/decodal-site/src/pages/docs/index.astro @@ -1,6 +1,8 @@ --- import ManualLayout from '../../layouts/ManualLayout.astro'; import { renderMarkdown } from '../../lib/docs.js'; +import '@fontsource/ibm-plex-sans-jp/400.css'; +import '@fontsource/ibm-plex-sans-jp/600.css'; const html = renderMarkdown('index'); --- diff --git a/site/decodal-site/src/pages/index.astro b/site/decodal-site/src/pages/index.astro index 3c351af..4405ce8 100644 --- a/site/decodal-site/src/pages/index.astro +++ b/site/decodal-site/src/pages/index.astro @@ -1,163 +1,6 @@ --- -import ManualLayout from '../layouts/ManualLayout.astro'; -import { highlightCode } from '../lib/highlight.js'; - -const example = `let - Port = Int & >= 1 & <= 65535; - Service = { - host = String; - port = Port default 8080; - }; -in -{ - host = "127.0.0.1"; -} as Service;`; - -const result = `{ - "host": "127.0.0.1", - "port": 8080 -}`; +import HomePage from '../components/HomePage.astro'; +import '@fontsource/ibm-plex-sans-jp/latin-400.css'; +import '@fontsource/ibm-plex-sans-jp/latin-600.css'; --- - -
-
-

Configuration, constraints, and defaults are values.

-

- Decodal is a small deterministic language for describing, composing, validating, and materializing - structured data. The same expression can carry concrete data and the range that data must satisfy. -

- -
-
-
Source
-
.dcdl
-
-
-
Runtime
-
Rust · WebAssembly
-
-
-
Output
-
Validated structured data
-
-
-
- -
-
- service.dcdl - DCDL -
-
-
- materialize -
{result}
-
-
-
- -
-
-

One expression system, from abstract range to concrete data.

-
-
-
- & -
-

Compose without discarding constraints

-

Symmetric composition keeps information from both sides and fails when their ranges cannot overlap.

-
-
-
- as -
-

Verify that a value is more specific

-

The left side must fit inside the wider range on the right. Wider abstract fields remain available for later materialization.

-
-
-
- // -
-

Apply an explicit structural patch

-

Right-biased composition replaces the selected structure while preserving unrelated fields.

-
-
-
- default -
-

Choose a fallback only when materializing

-

A default does not erase the range. It is selected only when no more concrete value has been supplied.

-
-
-
-
- -
-
-

The host owns I/O. Decodal owns evaluation.

-

- Filesystems, Markdown, JSON, network resources, and application globals stay under host control. Decodal - receives source or structured values and evaluates them with the same rules in production and editor tooling. -

-
-
    -
  1. - 1 - Host environment - globals · source · structured imports -
  2. -
  3. - 2 - Evaluate - lazy references · constraints · composition -
  4. -
  5. - 3 - Materialize - defaults · validation · diagnostics -
  6. -
  7. - 4 - Application data - Data · Rust type · JavaScript value -
  8. -
- -
- -
-
-

Use only the layer your application needs.

-
-
-
-
decodalRust
-

Runtime, host embedding, schema derivation, and typed decoding.

- crates.io -
-
-
decodal-wasmJavaScript
-

Browser runtime and host-configurable semantic language service.

- JSRnpm -
-
-
decodal-lspRust
-

Language Server Protocol with application-defined environments.

- crates.io -
-
-
decodal-codemirrorJavaScript
-

CodeMirror 6 syntax, indentation, folding, highlighting, and formatter integration.

- JSRnpm -
-
- -
-
+ diff --git a/site/decodal-site/src/pages/ja/index.astro b/site/decodal-site/src/pages/ja/index.astro new file mode 100644 index 0000000..464ca8d --- /dev/null +++ b/site/decodal-site/src/pages/ja/index.astro @@ -0,0 +1,6 @@ +--- +import HomePage from '../../components/HomePage.astro'; +import '@fontsource/ibm-plex-sans-jp/400.css'; +import '@fontsource/ibm-plex-sans-jp/600.css'; +--- + diff --git a/site/decodal-site/src/pages/playground.astro b/site/decodal-site/src/pages/playground.astro index 7ced138..76641b9 100644 --- a/site/decodal-site/src/pages/playground.astro +++ b/site/decodal-site/src/pages/playground.astro @@ -1,5 +1,7 @@ --- import ManualLayout from '../layouts/ManualLayout.astro'; +import '@fontsource/ibm-plex-sans-jp/latin-400.css'; +import '@fontsource/ibm-plex-sans-jp/latin-600.css'; ---
diff --git a/site/decodal-site/src/scripts/playground.js b/site/decodal-site/src/scripts/playground.js index 3f2c2dc..f21db51 100644 --- a/site/decodal-site/src/scripts/playground.js +++ b/site/decodal-site/src/scripts/playground.js @@ -36,7 +36,7 @@ const editorTheme = EditorView.theme({ height: '100%', }, '.cm-scroller': { - fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace', + fontFamily: '"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace', fontSize: '13px', lineHeight: '1.45', overflow: 'auto', diff --git a/site/decodal-site/src/style.css b/site/decodal-site/src/style.css index 9c948a1..6432ce0 100644 --- a/site/decodal-site/src/style.css +++ b/site/decodal-site/src/style.css @@ -1,10 +1,10 @@ :root { color-scheme: light; - font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + font-family: var(--font-ui); font-synthesis: none; - --font-ui: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; - --font-code: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; + --font-ui: "IBM Plex Sans JP", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + --font-code: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; --canvas: #f6f7f8; --surface: #ffffff; @@ -524,6 +524,11 @@ main.frontpage { max-width: 660px; } +[lang="ja"] .home-intro h1 { + letter-spacing: -0.035em; + line-height: 1.15; +} + .home-lead { color: var(--muted); font-size: 1.05rem; @@ -657,6 +662,21 @@ main.frontpage { margin: 0; } +[lang="ja"] .section-heading h2 { + letter-spacing: -0.025em; + line-height: 1.3; +} + +[lang="ja"] .frontpage .phrased { + line-break: strict; + overflow-wrap: normal; + word-break: keep-all; +} + +[lang="ja"] .frontpage .phrase-unit { + white-space: nowrap; +} + .section-heading > p:last-child { color: var(--muted); line-height: 1.75; @@ -1230,7 +1250,7 @@ main.playground { padding-right: 8px; } - .topnav a:last-child { + .topnav .source-link { display: none; }