diff --git a/README.md b/README.md index bd63128..fc4e7a6 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ The initial playground includes: - Distinct, accessible syntax palettes for light and dark color modes - Compiler-style diagnostics with source selection, code frames, expected values, help, and related locations - Safe SVG image preview, expanded dialog, and download +- User-selected provider icon stores with searchable AWS, Google Cloud, Azure, and tool artwork Authentication, persistence, collaboration, and paid themes remain outside this delivery. Cloudflare configuration targets the `stack-web` Worker and publishes the combined Vite and VitePress output as static assets. diff --git a/docs/.vitepress/theme/components/ProviderCatalog.vue b/docs/.vitepress/theme/components/ProviderCatalog.vue index e82229e..79d6a5d 100644 --- a/docs/.vitepress/theme/components/ProviderCatalog.vue +++ b/docs/.vitepress/theme/components/ProviderCatalog.vue @@ -5,7 +5,6 @@ import catalogData from "../data/provider-catalogs.json" type Locale = "en" | "ja" | "zh" | "ko" type CatalogIcon = (typeof catalogData.providers)[number]["icons"][number] -type CatalogSource = (typeof catalogData.providers)[number]["source"] & { id: string } const props = defineProps<{ locale: Locale }>() const pageSize = 100 @@ -20,17 +19,14 @@ const labels = { en: { allCategories: "All categories", allProviders: "All providers", - commandIntro: "Download, import, and render", + commandIntro: "Import this provider", category: "Category", copy: "Copy", copied: "Copied", - download: "Download ZIP", guidelines: "Guidelines", - hash: "Expected SHA-256", kind: "Kind", noResults: "No icon IDs match these filters.", officialPage: "Official download page", - primaryArchive: "Primary archive", product: "Product", results: "results", search: "Search ID, product, or category", @@ -41,17 +37,14 @@ const labels = { ja: { allCategories: "すべてのcategory", allProviders: "すべてのprovider", - commandIntro: "Download・import・render", + commandIntro: "このproviderをimport", category: "Category", copy: "コピー", copied: "コピー済み", - download: "ZIPをdownload", guidelines: "Guideline", - hash: "期待するSHA-256", kind: "Kind", noResults: "条件に一致するicon IDはありません。", officialPage: "公式download page", - primaryArchive: "Primary archive", product: "Product", results: "件", search: "ID、product、categoryを検索", @@ -62,17 +55,14 @@ const labels = { zh: { allCategories: "所有分类", allProviders: "所有提供商", - commandIntro: "下载、导入并渲染", + commandIntro: "导入此服务商", category: "分类", copy: "复制", copied: "已复制", - download: "下载 ZIP", guidelines: "使用指南", - hash: "预期 SHA-256", kind: "类型", noResults: "没有符合筛选条件的图标 ID。", officialPage: "官方下载页面", - primaryArchive: "主压缩包", product: "产品", results: "项结果", search: "搜索 ID、产品或分类", @@ -83,17 +73,14 @@ const labels = { ko: { allCategories: "모든 카테고리", allProviders: "모든 제공자", - commandIntro: "다운로드, import, render", + commandIntro: "이 제공자 가져오기", category: "카테고리", copy: "복사", copied: "복사됨", - download: "ZIP 다운로드", guidelines: "사용 지침", - hash: "예상 SHA-256", kind: "종류", noResults: "필터와 일치하는 아이콘 ID가 없습니다.", officialPage: "공식 다운로드 페이지", - primaryArchive: "Primary archive", product: "제품", results: "개 결과", search: "ID, 제품 또는 카테고리 검색", @@ -103,46 +90,14 @@ const labels = { }, } as const -const archiveFilenames: Record> = { - aws: { primary: "aws-icons.zip" }, - gcp: { - primary: "gcp-core-products-icons.zip", - categories: "gcp-category-icons.zip", - }, - azure: { primary: "azure-icons.zip" }, - "simple-icons": { primary: "simple-icons-16.29.0.zip" }, -} - const text = computed(() => labels[props.locale]) const selectedProvider = computed(() => catalogData.providers.find((item) => item.id === provider.value), ) -const selectedProviderSources = computed(() => { - const item = selectedProvider.value - if (!item) return [] - return [ - { ...item.source, id: "primary" }, - ...item.additionalSources.map((source) => ({ ...source, id: source.id })), - ] -}) const selectedProviderCommands = computed(() => { const item = selectedProvider.value if (!item) return "" - - const filenames = archiveFilenames[item.id] - const lines = selectedProviderSources.value.map( - (source) => `$ curl -fL "${source.archiveUrl}" -o ${filenames[source.id]}`, - ) - const importLines = [`$ stack icons import ${item.id} ./${filenames.primary} \\`] - for (const source of item.additionalSources) { - importLines.push(` --source ${source.id}=./${filenames[source.id]} \\`) - } - importLines.push(` --accept-terms -o .stack-icons/${item.id}`) - lines.push( - importLines.join("\n"), - `$ stack render architecture.stack --provider-pack .stack-icons/${item.id} -o architecture.svg`, - ) - return lines.join("\n") + return `$ stack icons import ${item.id} --accept-terms` }) const allIcons = computed(() => catalogData.providers.flatMap((item) => @@ -225,21 +180,6 @@ onBeforeUnmount(() => window.clearTimeout(copyTimer)) {{ text.terms }} -
-
- - {{ sourceItem.id === "primary" ? text.primaryArchive : sourceItem.id }} - - {{ sourceItem.release }} - - {{ text.download }} - - - {{ text.hash }} - {{ sourceItem.archiveSha256.replace("sha256:", "") }} - -
-

{{ text.commandIntro }}

{{ selectedProviderCommands }}
diff --git a/docs/guide/provider-icons.md b/docs/guide/provider-icons.md index 35913b8..272c3b6 100644 --- a/docs/guide/provider-icons.md +++ b/docs/guide/provider-icons.md @@ -1,56 +1,32 @@ # Provider icons -Stack supports a provider-neutral core icon catalog without setup. AWS, Google Cloud, Azure, and common developer or collaboration artwork is available through user-imported provider packs. The searchable catalog below is public metadata, but Stack does not host or redistribute the vendor SVG files. +Stack includes a provider-neutral core icon catalog. AWS, Google Cloud, Azure, and common developer and collaboration artwork are available through provider packs stored in your user-managed icon store. ## Available provider catalog -The audited catalog contains 1,051 IDs: 305 AWS Architecture Icons, all 19 Google Cloud core-product and 26 category icons, 639 Azure service icons after exact-byte deduplication, and 62 curated tool icons. Search or filter the complete list without loading any SVG bytes. Results are shown 100 at a time so the page remains usable on smaller devices. +The audited catalog contains 1,051 IDs: 305 AWS Architecture Icons, 45 Google Cloud product and category icons, 639 Azure service icons, and 62 curated tool icons. The tool catalog includes GitHub, GitHub Actions, Notion, Linear, Atlassian, Jira, Confluence, Docker, Kubernetes, Terraform, Datadog, Grafana, Sentry, and more. - - -Every imported manifest records the official product name, every contributing source release and archive hash, terms URL, review date, permitted output categories, and non-endorsement notice. Curated tool records also retain the rights owner's brand source and guideline links. A provider pack adds only artwork; the authored node `kind` still controls its semantic styling and layout. - -## Why artwork is not hosted +Select a provider card to see its import command, then search or filter the complete catalog. Results are shown 100 at a time for comfortable use on smaller devices. -The reviewed vendor guidance permits particular diagram and documentation uses, but does not clearly grant Stack permission to repackage every SVG byte in its website, npm package, WebAssembly module, or native binary. Static Documentation therefore shows searchable catalog metadata, provenance, and exact IDs without copying vendor artwork. - -The curated tool archive comes from [Simple Icons](https://simpleicons.org/). Its CC0 distribution does not imply that every underlying brand mark is CC0, so inclusion is not permission or endorsement. Follow the per-icon source and guideline links shown above before use. + -After you load a pack, the Playground shows its actual icons from your selected local files. It creates browser-local image URLs only after Engine validation and does not inject the SVG as page HTML. Review the linked provider terms before using or distributing a generated diagram. +A provider pack supplies artwork. The node `kind` in Stack source continues to control semantic styling and layout. -## Create a local pack +## Quick start -Select an AWS, Google Cloud, Azure, or Simple Icons card above to see its exact audited download URL, expected SHA-256, and complete `curl` → `stack icons import` → `stack render` commands. The CLI rejects an archive if its bytes no longer match the reviewed hash. +Import each provider used by a diagram once. `--accept-terms` records your confirmation that you reviewed the linked provider and brand terms. ```sh -$ stack icons list aws s3 -$ stack icons list simple-icons github +$ stack icons import gcp --accept-terms +$ stack icons import simple-icons --accept-terms +$ stack render architecture.stack -o architecture.svg ``` -Use `aws`, `gcp`, `azure`, or `simple-icons`. Google Cloud requires both official archives shown when its card is selected. The importer reads the files downloaded by `curl`; it does not fetch or upload them itself. It verifies every complete archive, reads only reviewed paths, removes active content, preserves colors and geometry, and creates `manifest.json`, `NOTICE.md`, and `assets/*.svg`. +The CLI downloads the audited official archives, verifies their complete SHA-256 hashes, sanitizes the selected SVGs, and writes each processed provider pack to the shared icon store. Google Cloud product and category artwork is imported together by the single `gcp` command. -## Use a pack in Playground +## Use provider icons in CLI -Open **Icons**, choose one pack's `manifest.json` and every declared file in `assets/`, then search the loaded local catalog and copy an ID into source: - -```stack -stack 1.0 - -diagram "Storage" { - node files "Amazon S3" { - kind storage - icon "aws:s3" - } -} -``` - -The selected files stay in the current browser tab. The Playground does not upload, fetch, or persist the pack, so reloads require another selection. Use **Notice** beside the SVG download when a rendered diagram embeds provider artwork. - -The Playground accepts an already processed pack, not a raw provider ZIP. Raw-archive verification and safe SVG processing remain in the CLI so browser code does not duplicate that security boundary. - -## Use a pack in CLI - -A single Stack file can use multiple providers. For example, this diagram uses Cloud Run from the Google Cloud pack and GitHub from the Simple Icons pack: +A Stack file can use multiple providers. This example combines Cloud Run from Google Cloud with GitHub from Simple Icons: ```stack stack 1.0 @@ -72,20 +48,71 @@ diagram "Deploy from GitHub to Cloud Run" { } ``` -After importing both packs with the commands shown in their catalog cards, repeat `--provider-pack` when rendering: +After both imports, the standard render command discovers both packs: + +```sh +$ stack render architecture.stack -o architecture.svg --notice architecture.NOTICE.md +``` + +## Shared icon store + +The default icon store is `$XDG_CONFIG_HOME/stack/icons`. When `XDG_CONFIG_HOME` is unset, Stack uses `$HOME/.config/stack/icons`. + +```text +icons/ + aws/ + gcp/ + azure/ + simple-icons/ +``` + +Set a different shared location in `$XDG_CONFIG_HOME/stack/config.yaml` with an absolute path: + +```yaml +default_icons_path: /absolute/path/to/stack-icons +``` + +The configured location is used by both `stack icons import` and `stack render`. + +## Use provider icons in Playground + +Open **Icons**, choose the `stack/icons` folder, and the Playground loads every recognized provider directory in that store. Search the loaded artwork and select an item to copy its ID into Stack source. + +The selected packs are processed in the current browser tab. When a rendered diagram contains provider artwork, **Notice** beside the SVG download provides the source, terms, and used-icon record. + +## Keep icons with a project + +Use `-o` to place imported packs in a project directory that can be committed with the repository: + +```sh +$ stack icons import gcp --accept-terms -o .stack-icons +$ stack icons import simple-icons --accept-terms -o .stack-icons +``` + +Pass that icon-store root with `--provider-pack` when rendering: ```sh $ stack render architecture.stack \ - --provider-pack .stack-icons/gcp \ - --provider-pack .stack-icons/simple-icons \ + --provider-pack .stack-icons \ -o architecture.svg \ --notice architecture.NOTICE.md ``` -The CLI validates each bounded pack before rendering and records the exact used icons and source archives in the notice sidecar. +## Find icon IDs + +Search the catalog from the CLI or on this page: + +```sh +$ stack icons list +$ stack icons list aws s3 +$ stack icons list azure database +$ stack icons list simple-icons github +``` + +The CLI output contains `ID`, `PRODUCT`, `CATEGORY`, and recommended `KIND` columns. Namespaced IDs such as `gcp:cloud-run` and `simple-icons:github` select artwork from the corresponding pack. -## Offline behavior +## Verification, terms, and notices -CLI authoring and SVG generation work fully offline after the CLI and any desired provider archives are on the device. Installing the CLI or obtaining a new official archive may require a connection. +The CLI catalog pins each official HTTPS archive URL, release, complete archive SHA-256, allowlisted entry path, terms URL, and review date. Import applies bounded archive and SVG sizes, sanitizes active and external SVG content, and writes each pack atomically. -The Web Playground also formats, checks, and renders locally after its JavaScript and WebAssembly have loaded. It has no server rendering dependency and provider files never leave the browser. The current website is not an installed offline app, however, so a cold start without a network connection is not guaranteed. +Each pack includes `NOTICE.md`. `stack render --notice ` writes the exact pack revisions, source releases, terms URLs, attribution, non-endorsement text, and used icon IDs for a rendered artifact. The catalog links each provider's official source and terms, plus brand sources and guidelines for curated Simple Icons marks. diff --git a/docs/ja/guide/provider-icons.md b/docs/ja/guide/provider-icons.md index 1384549..5659717 100644 --- a/docs/ja/guide/provider-icons.md +++ b/docs/ja/guide/provider-icons.md @@ -1,56 +1,32 @@ # Provider icon -Stackは設定不要でprovider-neutralなcore icon catalogを利用できます。AWS、Google Cloud、Azure、主要な開発・collaboration toolのartworkはuser-imported provider packとして利用します。検索可能なcatalogはpublic metadataですが、Stackがvendor SVG fileをhost・再配布することはありません。 +Stackにはprovider-neutralなcore icon catalogが含まれます。AWS、Google Cloud、Azure、主要な開発・collaboration toolのartworkは、user-managed icon storeに保存するprovider packとして利用できます。 ## 利用可能なprovider catalog -監査済みcatalogは合計1,051 IDです。AWS Architecture Icons 305件、Google Cloudのcore product 19件とcategory 26件、完全に同じbyteをdeduplicateしたAzure service icon 639件、主要tool 62件を収録します。SVG byteをloadせず全件を検索・filterでき、小さいdeviceでも崩れないよう100件ずつ表示します。 +監査済みcatalogには合計1,051 IDがあります。AWS Architecture Icons 305件、Google Cloudのproduct・category icon 45件、Azure service icon 639件、主要tool icon 62件です。Tool catalogにはGitHub、GitHub Actions、Notion、Linear、Atlassian、Jira、Confluence、Docker、Kubernetes、Terraform、Datadog、Grafana、Sentryなどが含まれます。 - - -Import済みmanifestには、公式product name、利用した全source releaseとarchive hash、terms URL、review date、許可されたoutput category、non-endorsement noticeが記録されます。Tool iconはrights ownerのbrand sourceとguideline linkも保持します。Provider packが追加するのはartworkだけで、semantic stylingとlayoutはsourceに書いたnode `kind`が引き続き決めます。 - -## Artworkをhostしない理由 +Provider cardを選ぶとimport commandを確認できます。全catalogを検索・filterでき、小さいdeviceでも見やすいよう100件ずつ表示します。 -確認したvendor guidanceは特定のdiagramやdocumentationでの利用を認めていますが、Stackのwebsite、npm package、WebAssembly module、native binaryへすべてのSVG byteを再packageする明確な許諾は確認できません。そのため静的Documentationではvendor artworkを複製せず、検索可能なcatalog metadata、provenance、正確なIDを表示します。 - -Tool archiveには[Simple Icons](https://simpleicons.org/)を使います。そのCC0 distributionは、個々のbrand markまでCC0であることを意味しません。Catalogへの掲載は利用許諾やendorsementではないため、使用前に上表のicon別sourceとguidelineを確認してください。 + -Packをloadした後のPlaygroundでは、選択したlocal fileから実際のiconを表示できます。Engine validation後にbrowser-localなimage URLを作り、SVGをpage HTMLとしてinjectしません。生成diagramの利用・配布前に、link先のprovider termsを確認してください。 +Provider packが追加するのはartworkです。Semantic stylingとlayoutはStack sourceに書いたnode `kind`が引き続き決めます。 -## Local packを作る +## Quick start -上のAWS、Google Cloud、Azure、Simple Iconsのcardを選ぶと、監査済みarchiveの正確なdownload URL、期待するSHA-256、`curl` → `stack icons import` → `stack render`の一連のcommandを確認できます。Archiveのbyteがreview済みhashと一致しなくなった場合、CLIはimportを拒否します。 +Diagramで使うproviderを一度ずつimportします。`--accept-terms`は、link先のprovider・brand termsを確認して同意したことを記録します。 ```sh -$ stack icons list aws s3 -$ stack icons list simple-icons github +$ stack icons import gcp --accept-terms +$ stack icons import simple-icons --accept-terms +$ stack render architecture.stack -o architecture.svg ``` -`aws`、`gcp`、`azure`、`simple-icons`を利用できます。Google Cloudはcard選択時に表示される2つの公式archiveが必要です。Importerは`curl`でdownloadしたfileを読み、downloadやupload自体は行いません。すべてのarchive全体を検証し、review済みpathだけを読み、active contentを除去してcolorとgeometryを保持し、`manifest.json`、`NOTICE.md`、`assets/*.svg`を生成します。 +CLIは監査済みの公式archiveをdownloadし、archive全体のSHA-256を検証し、選択したSVGをsanitizeして、処理済みprovider packをshared icon storeへ保存します。Google Cloudのproduct・category artworkは1つの`gcp` commandで一緒にimportされます。 -## Playgroundでpackを使う +## CLIでprovider iconを使う -**Icons**を開き、1つのpackにある`manifest.json`と`assets/`内の宣言済みfileをすべて選びます。Load済みlocal catalogを検索してIDをcopyし、sourceで使います。 - -```stack -stack 1.0 - -diagram "Storage" { - node files "Amazon S3" { - kind storage - icon "aws:s3" - } -} -``` - -選択fileは現在のbrowser tab内だけに留まります。Playgroundはpackをupload、fetch、永続化しないため、reload後は再選択が必要です。Provider artworkを埋め込んだSVGでは、SVG download横の**Notice**も保存してください。 - -Playgroundが受け取るのは処理済みpackで、providerのraw ZIPではありません。Raw archiveの検証と安全なSVG処理はCLIに集約し、browser codeにsecurity boundaryを重複実装しません。 - -## CLIでpackを使う - -1つのStack fileで複数providerを利用できます。例えば次のdiagramはGoogle Cloud packのCloud Runと、Simple Icons packのGitHubを使います。 +1つのStack fileで複数providerを利用できます。次の例はGoogle CloudのCloud RunとSimple IconsのGitHubを組み合わせます。 ```stack stack 1.0 @@ -72,20 +48,71 @@ diagram "Deploy from GitHub to Cloud Run" { } ``` -Catalog cardのcommandで両方のpackをimportした後、render時に`--provider-pack`を繰り返します。 +2つをimportした後は、通常のrender commandが両方のpackを見つけます。 + +```sh +$ stack render architecture.stack -o architecture.svg --notice architecture.NOTICE.md +``` + +## Shared icon store + +Default icon storeは`$XDG_CONFIG_HOME/stack/icons`です。`XDG_CONFIG_HOME`が未設定の場合は`$HOME/.config/stack/icons`を使います。 + +```text +icons/ + aws/ + gcp/ + azure/ + simple-icons/ +``` + +`$XDG_CONFIG_HOME/stack/config.yaml`にabsolute pathを書くと、shared locationを変更できます。 + +```yaml +default_icons_path: /absolute/path/to/stack-icons +``` + +このlocationは`stack icons import`と`stack render`の両方で使われます。 + +## Playgroundでprovider iconを使う + +**Icons**を開いて`stack/icons` folderを選ぶと、Playgroundがstore内の認識可能なprovider directoryをすべてloadします。Loadしたartworkを検索し、選択するとIDをStack sourceへcopyできます。 + +選択したpackは現在のbrowser tabで処理されます。生成diagramにprovider artworkが含まれる場合は、SVG download横の**Notice**からsource、terms、使用iconの記録を取得できます。 + +## Iconをprojectと一緒に管理する + +Import済みpackをrepositoryへ含める場合は、`-o`でproject directoryを指定します。 + +```sh +$ stack icons import gcp --accept-terms -o .stack-icons +$ stack icons import simple-icons --accept-terms -o .stack-icons +``` + +Render時は`--provider-pack`へ同じicon-store rootを渡します。 ```sh $ stack render architecture.stack \ - --provider-pack .stack-icons/gcp \ - --provider-pack .stack-icons/simple-icons \ + --provider-pack .stack-icons \ -o architecture.svg \ --notice architecture.NOTICE.md ``` -CLIはそれぞれのbounded packをrender前に検証し、実際に使ったiconとsource archiveをnotice sidecarへ記録します。 +## Icon IDを探す + +CLIまたはこのpageでcatalogを検索できます。 + +```sh +$ stack icons list +$ stack icons list aws s3 +$ stack icons list azure database +$ stack icons list simple-icons github +``` + +CLI outputには`ID`、`PRODUCT`、`CATEGORY`、推奨`KIND`が含まれます。`gcp:cloud-run`や`simple-icons:github`のようなnamespaced IDが対応するpackのartworkを選択します。 -## Offline behavior +## 検証・terms・notice -CLIと必要なprovider archiveがdeviceにあれば、source作成からSVG生成まで完全にofflineで動作します。CLIのinstallや新しい公式archiveの取得にはnetwork接続が必要な場合があります。 +CLI catalogは公式HTTPS archive URL、release、archive全体のSHA-256、allowlist済みentry path、terms URL、review dateをpinしています。Importではarchive・SVGのsizeを制限し、active・external SVG contentをsanitizeして、packをatomicに保存します。 -Web PlaygroundもJavaScriptとWebAssemblyをloadした後は、format、check、renderをbrowser内で実行します。Server-side renderへの依存はなく、provider fileはbrowser外へ出ません。ただし現在のwebsiteはinstall済みoffline appではないため、networkなしのcold startは保証しません。 +各packには`NOTICE.md`が含まれます。`stack render --notice `は、実際のpack revision、source release、terms URL、attribution、non-endorsement text、使用icon IDを出力します。Catalogから各providerの公式sourceとterms、Simple Iconsのbrand sourceとguidelineを確認できます。 diff --git a/docs/ja/reference/versioning-and-safety.md b/docs/ja/reference/versioning-and-safety.md index 65e9fc5..1a0b3b3 100644 --- a/docs/ja/reference/versioning-and-safety.md +++ b/docs/ja/reference/versioning-and-safety.md @@ -35,7 +35,6 @@ Rendered SVGにはscript、event handler、任意external reference、host font - Browser Playgroundがsupport対象のpublic experienceです。 - Public `@stack-sh/engine`がPlaygroundで使うtyped WebAssembly `format`、`check`、`render`を提供します。 - Public `@stack-sh/language`がeditor highlight用のshared TextMate grammarと言語metadataを提供します。 -- Native `stack` commandはprivate pre-release repositoryにありますが、support対象のexternal binaryとして未配布です。このdocsではinstall手順を案内しません。 -- Authentication、persistence、collaboration、billing、entitlement、paid theme、remote theme registry、hosted rendering API、PNG/PDF export、multi-file project、LSPは現在のpublic productに含みません。 +- Public [`stack-sh/cli`](https://github.com/stack-sh/cli)がnative `format`、`check`、`render`、provider-icon store操作を提供します。 Normative language contractは[`stack-sh/specification`](https://github.com/stack-sh/specification)、public theme catalogは[`stack-sh/theme`](https://github.com/stack-sh/theme)、engine behaviorは[`stack-sh/engine`](https://github.com/stack-sh/engine)が正本です。 diff --git a/docs/ko/guide/provider-icons.md b/docs/ko/guide/provider-icons.md index e69cd14..66defcc 100644 --- a/docs/ko/guide/provider-icons.md +++ b/docs/ko/guide/provider-icons.md @@ -1,56 +1,32 @@ # 클라우드 제공자 아이콘 -Stack은 설정 없이 제공자 중립적인 core icon catalog를 사용할 수 있습니다. AWS, Google Cloud, Azure 및 주요 개발·협업 도구 그림은 사용자가 가져온 provider pack으로 사용합니다. 아래 검색 가능한 catalog는 공개 metadata이지만 Stack은 vendor SVG 파일을 호스팅하거나 재배포하지 않습니다. +Stack에는 제공자 중립적인 core icon catalog가 포함됩니다. AWS, Google Cloud, Azure 및 주요 개발·협업 도구 그림은 사용자가 관리하는 icon store에 저장된 provider pack으로 사용할 수 있습니다. ## 사용 가능한 제공자 catalog -감사 완료 catalog에는 총 1,051개 ID가 있습니다. AWS Architecture Icons 305개, Google Cloud core product 19개와 category 26개 전체, byte가 완전히 같은 항목을 deduplicate한 Azure service icon 639개, 주요 tool icon 62개입니다. SVG byte를 불러오지 않고 전체 목록을 검색·filter할 수 있으며 작은 화면에서도 안정적으로 보이도록 100개씩 표시합니다. +감사 완료 catalog에는 총 1,051개 ID가 있습니다. AWS Architecture Icons 305개, Google Cloud 제품·category icon 45개, Azure service icon 639개, 주요 tool icon 62개입니다. Tool catalog에는 GitHub, GitHub Actions, Notion, Linear, Atlassian, Jira, Confluence, Docker, Kubernetes, Terraform, Datadog, Grafana, Sentry 등이 포함됩니다. - - -가져온 manifest는 공식 제품명, 사용한 모든 source release와 archive hash, terms URL, 검토 날짜, 허용된 output category, 비보증 안내를 기록합니다. Tool icon은 권리 보유자의 brand source 및 guideline link도 보존합니다. Provider pack은 그림만 추가하며 source의 node `kind`가 계속 의미적 스타일과 레이아웃을 결정합니다. - -## 그림을 호스팅하지 않는 이유 +Provider 카드를 선택하면 import 명령을 확인할 수 있습니다. 전체 catalog를 검색·filter할 수 있으며 작은 화면에서도 안정적으로 보이도록 100개씩 표시합니다. -검토한 vendor 지침은 특정 다이어그램과 문서 용도를 허용하지만 Stack website, npm package, WebAssembly module 또는 native binary에 모든 SVG byte를 다시 패키징할 명확한 허가는 제공하지 않습니다. 따라서 정적 문서는 vendor 그림을 복사하지 않고 검색 가능한 catalog metadata, provenance 및 정확한 ID를 표시합니다. - -Tool archive는 [Simple Icons](https://simpleicons.org/)에서 가져옵니다. CC0 distribution은 각 brand mark까지 CC0이라는 뜻이 아니며 catalog 등재도 사용 허가나 endorsement가 아닙니다. 사용 전에 위의 icon별 source 및 guideline link를 확인하세요. + -Pack을 불러온 뒤에는 Playground가 사용자가 선택한 로컬 파일에서 실제 아이콘을 표시합니다. Engine 검증 후에만 브라우저 로컬 이미지 URL을 만들며 SVG를 페이지 HTML로 주입하지 않습니다. 생성한 다이어그램을 사용하거나 배포하기 전에 연결된 제공자 terms를 확인하세요. +Provider pack은 그림을 제공합니다. Stack source의 node `kind`가 계속 의미적 스타일과 레이아웃을 결정합니다. -## 로컬 pack 만들기 +## 빠른 시작 -위의 AWS, Google Cloud, Azure 또는 Simple Icons 카드를 선택하면 감사 완료 archive의 정확한 다운로드 URL, 예상 SHA-256 및 전체 `curl` → `stack icons import` → `stack render` 명령을 확인할 수 있습니다. Archive byte가 검토된 hash와 더 이상 일치하지 않으면 CLI가 import를 거부합니다. +다이어그램에서 사용하는 각 provider를 한 번씩 import합니다. `--accept-terms`는 연결된 provider 및 brand terms를 검토하고 동의했음을 기록합니다. ```sh -$ stack icons list aws s3 -$ stack icons list simple-icons github +$ stack icons import gcp --accept-terms +$ stack icons import simple-icons --accept-terms +$ stack render architecture.stack -o architecture.svg ``` -`aws`, `gcp`, `azure`, `simple-icons`를 사용할 수 있습니다. Google Cloud에는 카드를 선택하면 표시되는 공식 archive 두 개가 필요합니다. Importer는 `curl`로 다운로드한 파일을 읽으며 자체적으로 다운로드하거나 업로드하지 않습니다. 모든 archive 전체를 검증하고 검토된 경로만 읽으며 active content를 제거하고 색상과 기하를 보존한 뒤 `manifest.json`, `NOTICE.md`, `assets/*.svg`를 생성합니다. +CLI는 감사 완료 공식 archive를 다운로드하고 전체 SHA-256을 검증하며 선택한 SVG를 sanitize한 뒤 처리된 provider pack을 shared icon store에 기록합니다. Google Cloud 제품과 category 그림은 하나의 `gcp` 명령으로 함께 import됩니다. -## Playground에서 pack 사용하기 +## CLI에서 provider icon 사용하기 -**Icons**를 열고 하나의 pack에 있는 `manifest.json`과 `assets/`의 선언된 파일을 모두 선택한 뒤 불러온 local catalog를 검색해 ID를 source로 복사합니다. - -```stack -stack 1.0 - -diagram "Storage" { - node files "Amazon S3" { - kind storage - icon "aws:s3" - } -} -``` - -선택한 파일은 현재 브라우저 탭에만 남습니다. Playground는 pack을 업로드, fetch 또는 영구 저장하지 않으므로 새로고침하면 다시 선택해야 합니다. 생성된 SVG에 provider 그림이 포함되면 SVG 다운로드 옆의 **Notice**도 저장하세요. - -Playground는 이미 처리된 pack을 받으며 provider의 raw ZIP을 직접 받지 않습니다. Raw archive 검증과 안전한 SVG 처리는 CLI에 유지하여 브라우저 코드가 보안 경계를 중복 구현하지 않습니다. - -## CLI에서 pack 사용하기 - -하나의 Stack 파일에서 여러 provider를 사용할 수 있습니다. 예를 들어 다음 다이어그램은 Google Cloud pack의 Cloud Run과 Simple Icons pack의 GitHub를 함께 사용합니다. +하나의 Stack 파일에서 여러 provider를 사용할 수 있습니다. 다음 예제는 Google Cloud의 Cloud Run과 Simple Icons의 GitHub를 함께 사용합니다. ```stack stack 1.0 @@ -72,20 +48,71 @@ diagram "Deploy from GitHub to Cloud Run" { } ``` -Catalog 카드의 명령으로 두 pack을 모두 import한 뒤 render할 때 `--provider-pack`을 반복해서 지정합니다. +두 pack을 import한 뒤 표준 render 명령이 모두 찾습니다. + +```sh +$ stack render architecture.stack -o architecture.svg --notice architecture.NOTICE.md +``` + +## Shared icon store + +기본 icon store는 `$XDG_CONFIG_HOME/stack/icons`입니다. `XDG_CONFIG_HOME`이 설정되지 않았으면 `$HOME/.config/stack/icons`를 사용합니다. + +```text +icons/ + aws/ + gcp/ + azure/ + simple-icons/ +``` + +`$XDG_CONFIG_HOME/stack/config.yaml`에서 절대 경로를 설정해 shared 위치를 변경할 수 있습니다. + +```yaml +default_icons_path: /absolute/path/to/stack-icons +``` + +이 위치는 `stack icons import`와 `stack render`에서 함께 사용됩니다. + +## Playground에서 provider icon 사용하기 + +**Icons**를 열고 `stack/icons` 폴더를 선택하면 Playground가 store 안의 인식 가능한 provider directory를 모두 불러옵니다. 불러온 그림을 검색하고 항목을 선택해 ID를 Stack source로 복사할 수 있습니다. + +선택한 pack은 현재 브라우저 탭에서 처리됩니다. 생성한 다이어그램에 provider 그림이 있으면 SVG 다운로드 옆의 **Notice**에서 source, terms 및 사용 icon 기록을 확인할 수 있습니다. + +## Icon을 프로젝트와 함께 관리하기 + +`-o`를 사용해 import한 pack을 repository와 함께 commit할 project directory에 둡니다. + +```sh +$ stack icons import gcp --accept-terms -o .stack-icons +$ stack icons import simple-icons --accept-terms -o .stack-icons +``` + +Render할 때 같은 icon-store root를 `--provider-pack`으로 전달합니다. ```sh $ stack render architecture.stack \ - --provider-pack .stack-icons/gcp \ - --provider-pack .stack-icons/simple-icons \ + --provider-pack .stack-icons \ -o architecture.svg \ --notice architecture.NOTICE.md ``` -CLI는 크기가 제한된 각 pack을 render 전에 검증하고 실제 사용 icon과 source archive를 notice sidecar에 기록합니다. +## Icon ID 찾기 + +CLI 또는 이 페이지에서 catalog를 검색할 수 있습니다. + +```sh +$ stack icons list +$ stack icons list aws s3 +$ stack icons list azure database +$ stack icons list simple-icons github +``` + +CLI 출력에는 `ID`, `PRODUCT`, `CATEGORY`, 권장 `KIND`가 포함됩니다. `gcp:cloud-run`, `simple-icons:github` 같은 namespaced ID가 해당 pack의 그림을 선택합니다. -## 오프라인 동작 +## 검증, terms 및 notice -CLI와 필요한 provider archive가 기기에 있으면 source 작성부터 SVG 생성까지 완전히 오프라인으로 동작합니다. CLI 설치나 새 공식 archive 다운로드에는 네트워크가 필요할 수 있습니다. +CLI catalog는 각 공식 HTTPS archive URL, release, 전체 SHA-256, 허용된 entry path, terms URL, review date를 pin합니다. Import는 archive와 SVG 크기를 제한하고 active 및 external SVG content를 sanitize하며 pack을 atomic하게 기록합니다. -Web Playground도 JavaScript와 WebAssembly가 로드된 뒤에는 format, check, render를 브라우저 안에서 실행합니다. 서버 렌더링 의존성이 없고 provider 파일은 브라우저 밖으로 나가지 않습니다. 다만 현재 website는 설치된 offline app이 아니므로 네트워크 없는 cold start를 보장하지 않습니다. +각 pack에는 `NOTICE.md`가 포함됩니다. `stack render --notice `는 실제 pack revision, source release, terms URL, attribution, non-endorsement text 및 사용 icon ID를 기록합니다. Catalog는 각 provider의 공식 source와 terms, Simple Icons mark의 brand source와 guideline도 연결합니다. diff --git a/docs/ko/reference/versioning-and-safety.md b/docs/ko/reference/versioning-and-safety.md index 89b801c..66e1fdb 100644 --- a/docs/ko/reference/versioning-and-safety.md +++ b/docs/ko/reference/versioning-and-safety.md @@ -35,7 +35,6 @@ Stack 문자열은 일반 텍스트입니다. 소스에는 실행 코드, 임의 - 브라우저 Playground가 지원되는 공개 경험입니다. - 공개 `@stack-sh/engine`은 Playground가 사용하는 typed WebAssembly `format`, `check`, `render`를 제공합니다. - 공개 `@stack-sh/language`는 에디터 하이라이트용 공유 TextMate grammar와 언어 metadata를 제공합니다. -- Native `stack` 명령은 private pre-release repository에 있지만 지원되는 external binary로 배포되지 않았습니다. 이 문서는 설치를 안내하지 않습니다. -- Authentication, persistence, collaboration, billing, entitlement, paid theme, remote theme registry, hosted rendering API, PNG/PDF export, multi-file project, LSP는 현재 공개 제품에 포함되지 않습니다. +- 공개 [`stack-sh/cli`](https://github.com/stack-sh/cli)는 native `format`, `check`, `render` 및 provider-icon store 작업을 제공합니다. 표준 언어 계약은 [`stack-sh/specification`](https://github.com/stack-sh/specification), 공개 테마 catalog는 [`stack-sh/theme`](https://github.com/stack-sh/theme), 엔진 동작은 [`stack-sh/engine`](https://github.com/stack-sh/engine)이 소유합니다. diff --git a/docs/public/llms.txt b/docs/public/llms.txt index 69e55ab..d445829 100644 --- a/docs/public/llms.txt +++ b/docs/public/llms.txt @@ -9,7 +9,7 @@ These Markdown pages are the public user-facing reference. Examples marked as `s - [What is Stack?](https://stack-diagram.com/docs/guide/what-is-stack.md): Goals, conceptual model, processing pipeline, and deliberate non-goals. - [Getting started](https://stack-diagram.com/docs/guide/getting-started.md): Package installation, first diagram, engine operations, and browser Playground workflow. - [Using the Playground](https://stack-diagram.com/docs/guide/playground.md): Editor, formatter, diagnostics, preview, color mode, and SVG download behavior. -- [Provider icons](https://stack-diagram.com/docs/guide/provider-icons.md): Searchable AWS, Google Cloud, Azure, and tool catalogs; local pack import, terms, and offline boundaries. +- [Provider icons](https://stack-diagram.com/docs/guide/provider-icons.md): Searchable AWS, Google Cloud, Azure, and tool catalogs; shared icon-store import, Playground loading, configuration, and terms. ## Language diff --git a/docs/reference/versioning-and-safety.md b/docs/reference/versioning-and-safety.md index 4f18a44..61f835a 100644 --- a/docs/reference/versioning-and-safety.md +++ b/docs/reference/versioning-and-safety.md @@ -35,7 +35,6 @@ Rendered SVG contains no script, event handler, arbitrary external reference, ho - The browser Playground is the supported public experience. - Public `@stack-sh/engine` provides the typed WebAssembly `format`, `check`, and `render` operations used by the Playground. - Public `@stack-sh/language` provides the shared TextMate grammar and language metadata used for editor highlighting. -- The native `stack` command exists in a private pre-release repository but is not distributed as a supported external binary. These docs do not instruct users to install it. -- Authentication, persistence, collaboration, billing, entitlement, paid themes, remote theme registries, hosted rendering APIs, PNG/PDF export, multi-file projects, and LSP features are not part of the current public product. +- Public [`stack-sh/cli`](https://github.com/stack-sh/cli) provides native `format`, `check`, `render`, and provider-icon store operations. The normative language contract remains in [`stack-sh/specification`](https://github.com/stack-sh/specification). The public theme catalog is in [`stack-sh/theme`](https://github.com/stack-sh/theme), and engine behavior is in [`stack-sh/engine`](https://github.com/stack-sh/engine). diff --git a/docs/zh/guide/provider-icons.md b/docs/zh/guide/provider-icons.md index 4ef62d5..1d80962 100644 --- a/docs/zh/guide/provider-icons.md +++ b/docs/zh/guide/provider-icons.md @@ -1,56 +1,32 @@ # 云服务商图标 -Stack 无需配置即可使用与服务商无关的核心图标目录。AWS、Google Cloud、Azure 以及常用开发和协作工具图标通过用户导入的 provider pack 使用。下方可搜索目录属于公开元数据,但 Stack 不托管或重新分发服务商 SVG 文件。 +Stack 内置与服务商无关的核心图标目录。AWS、Google Cloud、Azure 以及常用开发和协作工具图形通过 provider pack 使用,并保存在用户管理的 icon store 中。 ## 可用的服务商目录 -已审核目录共有 1,051 个 ID:305 个 AWS Architecture Icons、Google Cloud 的全部 19 个核心产品与 26 个分类图标、对完全相同字节去重后的 639 个 Azure 服务图标,以及 62 个常用工具图标。无需加载 SVG 字节即可搜索和筛选完整列表,并以每次 100 项的方式在小屏设备上稳定显示。 +已审核目录共有 1,051 个 ID:305 个 AWS Architecture Icons、45 个 Google Cloud 产品与分类图标、639 个 Azure 服务图标,以及 62 个常用工具图标。工具目录包括 GitHub、GitHub Actions、Notion、Linear、Atlassian、Jira、Confluence、Docker、Kubernetes、Terraform、Datadog、Grafana 和 Sentry 等。 - - -每个导入的 manifest 都记录官方产品名称、使用的每个来源版本与压缩包 hash、条款 URL、审核日期、允许的输出类别和非背书声明。工具图标还保留权利方的品牌来源和使用指南链接。Provider pack 只增加图形;源代码中的节点 `kind` 仍决定语义样式和布局。 - -## 为什么不托管图形 +选择服务商卡片即可查看导入命令。完整目录支持搜索与筛选,并以每次 100 项的方式在小屏设备上稳定显示。 -已审核的服务商指南允许特定的架构图与文档用途,但没有明确授权 Stack 将所有 SVG 字节重新打包到网站、npm 包、WebAssembly 模块或原生二进制中。因此静态文档只展示可搜索的目录元数据、来源和准确 ID,不复制服务商图形。 - -工具归档来自 [Simple Icons](https://simpleicons.org/)。其 CC0 分发不代表每个底层品牌标志都是 CC0;被列入目录也不构成使用许可或背书。使用前请查看上方每个图标的来源和指南链接。 + -加载 pack 后,Playground 会从用户选择的本地文件显示真实图标。Engine 验证完成后才创建浏览器本地图片 URL,也不会把 SVG 注入页面 HTML。使用或分发生成图之前,请检查对应的服务商条款。 +Provider pack 提供图形;Stack 源码中的节点 `kind` 继续决定语义样式和布局。 -## 创建本地 pack +## 快速开始 -选择上方的 AWS、Google Cloud、Azure 或 Simple Icons 卡片,即可查看已审核压缩包的准确下载 URL、预期 SHA-256,以及完整的 `curl` → `stack icons import` → `stack render` 命令。如果压缩包字节不再匹配已审核 hash,CLI 会拒绝导入。 +为图中使用的每个服务商执行一次导入。`--accept-terms` 表示你已查看并接受链接中的服务商和品牌条款。 ```sh -$ stack icons list aws s3 -$ stack icons list simple-icons github +$ stack icons import gcp --accept-terms +$ stack icons import simple-icons --accept-terms +$ stack render architecture.stack -o architecture.svg ``` -可使用 `aws`、`gcp`、`azure` 或 `simple-icons`。Google Cloud 需要选择卡片时显示的两个官方压缩包。Importer 读取由 `curl` 下载的文件,本身不发起下载或上传;它验证每个完整压缩包,只读取审核过的路径,移除活动内容,保留颜色与几何,并生成 `manifest.json`、`NOTICE.md` 和 `assets/*.svg`。 +CLI 会下载已审核的官方压缩包,验证完整 SHA-256,清理选定 SVG,并将处理后的 provider pack 写入共享 icon store。一个 `gcp` 命令会同时导入 Google Cloud 产品和分类图形。 -## 在 Playground 使用 pack +## 在 CLI 中使用服务商图标 -打开 **Icons**,选择一个 pack 的 `manifest.json` 和 `assets/` 中所有已声明文件,再搜索已加载的本地目录并复制 ID 到源代码: - -```stack -stack 1.0 - -diagram "Storage" { - node files "Amazon S3" { - kind storage - icon "aws:s3" - } -} -``` - -所选文件只保留在当前浏览器标签页。Playground 不上传、获取或持久化 pack,因此刷新后需要重新选择。生成的 SVG 使用服务商图形时,也请下载 SVG 旁边的 **Notice**。 - -Playground 接受已经处理的 pack,而不是服务商原始 ZIP。原始压缩包验证和安全 SVG 处理仍由 CLI 负责,避免浏览器代码重复安全边界。 - -## 在 CLI 中使用 pack - -一个 Stack 文件可以使用多个服务商。例如,下面的图同时使用 Google Cloud pack 中的 Cloud Run 与 Simple Icons pack 中的 GitHub: +一个 Stack 文件可以使用多个服务商。下面的例子组合了 Google Cloud 的 Cloud Run 与 Simple Icons 的 GitHub: ```stack stack 1.0 @@ -72,20 +48,71 @@ diagram "Deploy from GitHub to Cloud Run" { } ``` -使用目录卡片中的命令导入两个 pack 后,在渲染时重复指定 `--provider-pack`: +完成两次导入后,标准渲染命令会发现两个 pack: + +```sh +$ stack render architecture.stack -o architecture.svg --notice architecture.NOTICE.md +``` + +## 共享 icon store + +默认 icon store 为 `$XDG_CONFIG_HOME/stack/icons`。未设置 `XDG_CONFIG_HOME` 时使用 `$HOME/.config/stack/icons`。 + +```text +icons/ + aws/ + gcp/ + azure/ + simple-icons/ +``` + +可在 `$XDG_CONFIG_HOME/stack/config.yaml` 中设置绝对路径来更改共享位置: + +```yaml +default_icons_path: /absolute/path/to/stack-icons +``` + +`stack icons import` 与 `stack render` 都会使用该位置。 + +## 在 Playground 中使用服务商图标 + +打开 **Icons**,选择 `stack/icons` 文件夹,Playground 会加载其中所有可识别的服务商目录。搜索已加载图形并选择一项,即可把 ID 复制到 Stack 源码中。 + +所选 pack 在当前浏览器标签页中处理。当生成图使用服务商图形时,SVG 下载旁的 **Notice** 会提供来源、条款和已使用图标记录。 + +## 将图标与项目一起管理 + +使用 `-o` 将导入的 pack 放进可随仓库提交的项目目录: + +```sh +$ stack icons import gcp --accept-terms -o .stack-icons +$ stack icons import simple-icons --accept-terms -o .stack-icons +``` + +渲染时通过 `--provider-pack` 传入同一个 icon-store 根目录: ```sh $ stack render architecture.stack \ - --provider-pack .stack-icons/gcp \ - --provider-pack .stack-icons/simple-icons \ + --provider-pack .stack-icons \ -o architecture.svg \ --notice architecture.NOTICE.md ``` -CLI 会在渲染前验证每个有大小限制的 pack,并把实际使用的图标和来源压缩包写入 notice sidecar。 +## 查找图标 ID + +可通过 CLI 或本页搜索目录: + +```sh +$ stack icons list +$ stack icons list aws s3 +$ stack icons list azure database +$ stack icons list simple-icons github +``` + +CLI 输出包含 `ID`、`PRODUCT`、`CATEGORY` 和推荐的 `KIND`。`gcp:cloud-run`、`simple-icons:github` 等带命名空间的 ID 会选择对应 pack 中的图形。 -## 离线行为 +## 验证、条款与 notice -设备上已有 CLI 和所需服务商压缩包后,从编写源码到生成 SVG 都可完全离线。安装 CLI 或获取新的官方压缩包可能需要网络。 +CLI 目录固定了每个官方 HTTPS 压缩包 URL、版本、完整 SHA-256、允许的条目路径、条款 URL 与审核日期。导入时会限制压缩包与 SVG 大小,清理活动及外部 SVG 内容,并以原子方式写入 pack。 -Web Playground 的 JavaScript 与 WebAssembly 加载完成后,format、check 和 render 也都在浏览器本地运行,不依赖服务端渲染,服务商文件不会离开浏览器。但当前网站并不是已安装的离线应用,因此无法保证断网冷启动。 +每个 pack 都包含 `NOTICE.md`。`stack render --notice ` 会写入实际 pack 版本、来源版本、条款 URL、署名、非背书文本和已使用的图标 ID。目录还链接每个服务商的官方来源与条款,以及 Simple Icons 标志对应的品牌来源和指南。 diff --git a/docs/zh/reference/versioning-and-safety.md b/docs/zh/reference/versioning-and-safety.md index a7d43ff..1d46fd1 100644 --- a/docs/zh/reference/versioning-and-safety.md +++ b/docs/zh/reference/versioning-and-safety.md @@ -35,7 +35,6 @@ Stack 字符串是纯文本。源文件不能包含可执行代码、任意 HTML - 浏览器 Playground 是受支持的公共体验。 - 公共 `@stack-sh/engine` 提供 Playground 使用的 typed WebAssembly `format`、`check` 和 `render`。 - 公共 `@stack-sh/language` 提供编辑器高亮使用的共享 TextMate grammar 和语言 metadata。 -- Native `stack` 命令存在于 private pre-release repository,但尚未作为受支持外部 binary 分发;本网站不会提供安装说明。 -- Authentication、persistence、collaboration、billing、entitlement、paid theme、remote theme registry、hosted rendering API、PNG/PDF export、multi-file project 和 LSP 不属于当前公共产品。 +- 公共 [`stack-sh/cli`](https://github.com/stack-sh/cli) 提供原生 `format`、`check`、`render` 和 provider-icon store 操作。 规范语言合同位于 [`stack-sh/specification`](https://github.com/stack-sh/specification),公共主题 catalog 位于 [`stack-sh/theme`](https://github.com/stack-sh/theme),引擎行为位于 [`stack-sh/engine`](https://github.com/stack-sh/engine)。 diff --git a/scripts/validate-docs.mjs b/scripts/validate-docs.mjs index db7800b..64b5acc 100644 --- a/scripts/validate-docs.mjs +++ b/scripts/validate-docs.mjs @@ -291,10 +291,19 @@ for (const locale of ["", ...locales]) { throw new Error(`${componentLocale}/guide/provider-icons.md is missing its provider catalog`) } for (const providerPack of ["gcp", "simple-icons"]) { - if (!source.includes(`--provider-pack .stack-icons/${providerPack}`)) { + if (!source.includes(`stack icons import ${providerPack} --accept-terms`)) { throw new Error(`${componentLocale}/guide/provider-icons.md is missing ${providerPack}`) } } + for (const command of [ + "stack render architecture.stack -o architecture.svg", + "--provider-pack .stack-icons", + "default_icons_path: /absolute/path/to/stack-icons", + ]) { + if (!source.includes(command)) { + throw new Error(`${componentLocale}/guide/provider-icons.md is missing ${command}`) + } + } for (const iconId of ["gcp:cloud-run", "simple-icons:github"]) { if (!source.includes(`icon "${iconId}"`)) { throw new Error(`${componentLocale}/guide/provider-icons.md is missing ${iconId}`) @@ -302,4 +311,17 @@ for (const locale of ["", ...locales]) { } } +const providerCatalogComponent = await readFile( + path.join(docsRoot, ".vitepress/theme/components/ProviderCatalog.vue"), + "utf8", +) +if (!providerCatalogComponent.includes("stack icons import ${item.id} --accept-terms")) { + throw new Error("Provider catalog cards must show the provider import command") +} +for (const legacyCommand of ["curl -fL", "--source"]) { + if (providerCatalogComponent.includes(legacyCommand)) { + throw new Error(`Provider catalog still contains legacy command ${legacyCommand}`) + } +} + console.log(`Validated ${pages.length * (locales.length + 1)} documentation pages.`) diff --git a/src/App.test.tsx b/src/App.test.tsx index f443845..083004d 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -22,6 +22,12 @@ vi.mock("@stack-sh/engine", () => ({ import App from "./App" +function fileAt(path: string, contents: string, type?: string): File { + const file = new File([contents], path.split("/").at(-1) ?? path, { type }) + Object.defineProperty(file, "webkitRelativePath", { value: path }) + return file +} + const metadata = { engineVersion: "0.6.0", languageVersion: { major: 1, minor: 0 }, @@ -211,64 +217,96 @@ describe("Stack Playground", () => { expect(screen.getByRole("button", { name: "Expand rendered diagram" })).toHaveFocus() }) - it("loads a provider pack locally and renders with it", async () => { + it("loads a provider icon store and renders with every known pack", async () => { const user = userEvent.setup() render() await screen.findByAltText("Rendered Stack architecture diagram") await user.click(await screen.findByRole("button", { name: "Provider icons" })) - const manifest = new File( - [ - JSON.stringify({ - packVersion: "0.1.0", - provider: { id: "aws", name: "Amazon Web Services" }, - source: { - pageUrl: "https://example.com/icons", - release: "fixture-1", - reviewAfter: "2026-12-03", - termsUrl: "https://example.com/terms", + const awsManifest = fileAt( + "icons/aws/manifest.json", + JSON.stringify({ + packVersion: "0.1.0", + provider: { id: "aws", name: "Amazon Web Services" }, + source: { + pageUrl: "https://example.com/icons", + release: "fixture-1", + reviewAfter: "2026-12-03", + termsUrl: "https://example.com/terms", + }, + icons: [ + { + asset: { path: "assets/s3.svg" }, + id: "aws:s3", + productName: "Amazon Simple Storage Service (Amazon S3)", }, - icons: [ - { - asset: { path: "assets/s3.svg" }, - id: "aws:s3", - productName: "Amazon Simple Storage Service (Amazon S3)", - }, - ], - }), - ], - "manifest.json", - { type: "application/json" }, + ], + }), + "application/json", + ) + const awsAsset = fileAt( + "icons/aws/assets/s3.svg", + '', + "image/svg+xml", + ) + const simpleIconsManifest = fileAt( + "icons/simple-icons/manifest.json", + JSON.stringify({ + packVersion: "0.1.0", + provider: { id: "simple-icons", name: "Simple Icons" }, + source: { + pageUrl: "https://example.com/simple-icons", + release: "fixture-1", + reviewAfter: "2026-12-03", + termsUrl: "https://example.com/simple-icons/terms", + }, + icons: [ + { + asset: { path: "assets/github.svg" }, + id: "simple-icons:github", + productName: "GitHub", + }, + ], + }), + "application/json", ) - const asset = new File( - [''], - "s3.svg", - { type: "image/svg+xml" }, + const simpleIconsAsset = fileAt( + "icons/simple-icons/assets/github.svg", + '', + "image/svg+xml", ) - await user.upload(screen.getByLabelText("Provider pack files"), [manifest, asset]) + await user.upload(screen.getByLabelText("Provider icon store folder"), [ + awsManifest, + awsAsset, + simpleIconsManifest, + simpleIconsAsset, + ]) expect(await screen.findByText("Amazon Web Services")).toBeInTheDocument() + expect(screen.getByText("Simple Icons")).toBeInTheDocument() expect(screen.getByText("aws:s3")).toBeInTheDocument() + expect(screen.getByText("simple-icons:github")).toBeInTheDocument() expect( screen.getByAltText("Amazon Simple Storage Service (Amazon S3) icon"), ).toBeInTheDocument() - expect(engine.checkWithProviderPacks).toHaveBeenCalledOnce() + expect(engine.checkWithProviderPacks).toHaveBeenCalledTimes(2) expect(engine.renderWithProviderPacks).toHaveBeenCalledOnce() + expect(engine.renderWithProviderPacks.mock.calls[0][1]).toHaveLength(2) await user.click(screen.getByRole("button", { name: "Close" })) expect(screen.getByRole("button", { name: "Notice" })).toBeInTheDocument() }) - it("shows an import error without sending provider files anywhere", async () => { + it("shows an icon store error before sending provider files to the engine", async () => { const user = userEvent.setup() render() await screen.findByAltText("Rendered Stack architecture diagram") await user.click(await screen.findByRole("button", { name: "Provider icons" })) await user.upload( - screen.getByLabelText("Provider pack files"), - new File(["not json"], "manifest.json", { type: "application/json" }), + screen.getByLabelText("Provider icon store folder"), + fileAt("icons/aws/manifest.json", "not json", "application/json"), ) expect(await screen.findByRole("alert")).toHaveTextContent( diff --git a/src/App.tsx b/src/App.tsx index 740a521..43b41f2 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -139,17 +139,10 @@ export default function App() { saveColorMode(nextColorMode) } - function handleProviderPackImport(pack: LoadedProviderPack) { - validateProviderPack(pack.input) - if ( - !providerPacks.some((item) => item.providerId === pack.providerId) && - providerPacks.length >= 32 - ) { - throw new Error("At most 32 provider packs may be loaded in one tab.") - } - const nextPacks = [...providerPacks.filter((item) => item.providerId !== pack.providerId), pack] - setProviderPacks(nextPacks) - runRender(source, nextPacks) + function handleProviderIconStoreLoad(packs: readonly LoadedProviderPack[]) { + for (const pack of packs) validateProviderPack(pack.input) + setProviderPacks(packs) + runRender(source, packs) } function handleProviderPackRemove(providerId: string) { @@ -199,7 +192,7 @@ export default function App() { diff --git a/src/components/provider-icons.test.tsx b/src/components/provider-icons.test.tsx index 7e66b8a..ba3fe52 100644 --- a/src/components/provider-icons.test.tsx +++ b/src/components/provider-icons.test.tsx @@ -41,7 +41,7 @@ describe("ProviderIcons", () => { render( , diff --git a/src/components/provider-icons.tsx b/src/components/provider-icons.tsx index 776cc3b..e34ab28 100644 --- a/src/components/provider-icons.tsx +++ b/src/components/provider-icons.tsx @@ -11,18 +11,18 @@ import { DialogTrigger, } from "@/components/ui/dialog" import { SvgAssetImage } from "@/components/svg-asset-image" -import { loadProviderPackFiles, type LoadedProviderPack } from "@/lib/provider-pack" +import { loadProviderIconStoreFiles, type LoadedProviderPack } from "@/lib/provider-pack" interface ProviderIconsProps { disabled: boolean packs: readonly LoadedProviderPack[] - onImport: (pack: LoadedProviderPack) => void + onLoad: (packs: readonly LoadedProviderPack[]) => void onRemove: (providerId: string) => void } const ICON_BATCH_SIZE = 48 -export function ProviderIcons({ disabled, packs, onImport, onRemove }: ProviderIconsProps) { +export function ProviderIcons({ disabled, packs, onLoad, onRemove }: ProviderIconsProps) { const inputRef = useRef(null) const [error, setError] = useState(null) const [isImporting, setIsImporting] = useState(false) @@ -50,9 +50,9 @@ export function ProviderIcons({ disabled, packs, onImport, onRemove }: ProviderI setError(null) setIsImporting(true) try { - onImport(await loadProviderPackFiles(files)) + onLoad(await loadProviderIconStoreFiles(files)) } catch (loadError) { - setError(loadError instanceof Error ? loadError.message : "The provider pack could not load.") + setError(loadError instanceof Error ? loadError.message : "The icon store could not load.") } finally { setIsImporting(false) if (inputRef.current) inputRef.current.value = "" @@ -75,7 +75,7 @@ export function ProviderIcons({ disabled, packs, onImport, onRemove }: ProviderI @@ -91,27 +93,27 @@ export function ProviderIcons({ disabled, packs, onImport, onRemove }: ProviderI Provider icons - Load a CLI-created pack into this tab. Files stay in your browser and are never - uploaded. + Load the stack/icons folder created by Stack CLI. Processing stays in this + browser.
void handleFiles(event.currentTarget.files)} ref={inputRef} type="file" + {...{ webkitdirectory: "" }} />
-

Import one local pack

+

Load one icon store

- Select its manifest.json and every declared SVG in assets/ - . + Select the folder that contains aws, gcp,{" "} + azure, or simple-icons.

{error ? ( @@ -134,10 +136,9 @@ export function ProviderIcons({ disabled, packs, onImport, onRemove }: ProviderI {packs.length === 0 ? (