diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock index 5ec14d2..c89e8b8 100644 --- a/.github/workflows/actions.lock +++ b/.github/workflows/actions.lock @@ -9,6 +9,11 @@ workflows: - 'actions/setup-dotnet@v6.1.0' - 'actions/upload-artifact@v7.0.2' - 'nuget/login@v1.2.0' + '.github/workflows/pages.yml': + - 'actions/checkout@v7.0.1' + - 'actions/deploy-pages@v5.0.1' + - 'actions/setup-dotnet@v6.1.0' + - 'actions/upload-pages-artifact@v5.0.0' '.github/workflows/verify-lockfile.yml': - 'actions/checkout@v7.0.1' dependencies: @@ -17,6 +22,11 @@ dependencies: commit: 'sha1-3d3c42e5aac5ba805825da76410c181273ba90b1' owner_id: 44036562 repo_id: 197814629 + 'actions/deploy-pages@v5.0.1': + ref: 'v5.0.1' + commit: 'sha1-368f82528645a54fb793d4d04e342629a3f51346' + owner_id: 44036562 + repo_id: 438112499 'actions/download-artifact@v8.0.2': ref: 'v8.0.2' commit: 'sha1-9000827ccba6bdab643e8b6fd33ac0654aef8333' @@ -27,11 +37,23 @@ dependencies: commit: 'sha1-0f4a354dd5547a28c70b7853dbd95d5b67886e73' owner_id: 44036562 repo_id: 192625306 + 'actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f': + ref: 'v7.0.0' + commit: 'sha1-bbbca2ddaa5d8feaa63e36b76fdaad77386f024f' + owner_id: 44036562 + repo_id: 192625955 'actions/upload-artifact@v7.0.2': ref: 'v7.0.2' commit: 'sha1-cf430e030ddbb5b0abf93d22962f4752f3646cd9' owner_id: 44036562 repo_id: 192625955 + 'actions/upload-pages-artifact@v5.0.0': + ref: 'v5.0.0' + commit: 'sha1-fc324d3547104276b827a68afc52ff2a11cc49c9' + owner_id: 44036562 + repo_id: 496012378 + uses: + - 'actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f' 'nuget/login@v1.2.0': ref: 'v1.2.0' commit: 'sha1-8d196754b4036150537f80ac539e15c2f1028841' diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..cecb615 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,60 @@ +# デモサイト(ZipConvertCustomerBarCode.Demo、Blazor WebAssembly)を GitHub Pages に配置する +# https://cssho.github.io/ZipConvertCustomerBarCode/ +# PR ではソリューションのビルド(build.yml の test)でデモもビルドされるので、ここでは master への push だけ動かす +name: pages + +on: + push: + branches: [master] + paths: + - 'ZipConvertCustomerBarCode/**' + - 'ZipConvertCustomerBarCode.Demo/**' + - 'Directory.Build.props' + - 'global.json' + - '.github/workflows/pages.yml' + workflow_dispatch: + +permissions: + contents: read + +# 配置は1つずつ行い、実行中の配置は取り消さない +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7.0.1 + with: + persist-credentials: false + - uses: actions/setup-dotnet@v6.1.0 + with: + dotnet-version: 10.0.x + - name: デモサイトの作成 + run: dotnet publish ZipConvertCustomerBarCode.Demo -c Release -o publish + - name: GitHub Pages 用に調整 + shell: bash + run: | + # リポジトリ名のパス(/ZipConvertCustomerBarCode/)で公開されるため、base を書き換える + sed -i "s###" publish/wwwroot/index.html + grep -q "" publish/wwwroot/index.html + # _framework など _ で始まるフォルダーを Jekyll に無視させない + touch publish/wwwroot/.nojekyll + - uses: actions/upload-pages-artifact@v5.0.0 + with: + path: publish/wwwroot + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + permissions: + pages: write + id-token: write + steps: + - id: deployment + uses: actions/deploy-pages@v5.0.1 diff --git a/CLAUDE.md b/CLAUDE.md index ce2e0aa..63ce8fc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,8 +19,10 @@ - `Span` を使うのは計測で効果があった箇所のみ(住所照合の正規化、CSV の読み込み)。`Span` を使わなくても両方で速くできる場合は、`#if` を使わず共通のコードにする。 - `ZipConvertCustomerBarCode.Drawing`: System.Drawing.Common による描画(Windows のみ)。 - `ZipConvertCustomerBarCode.SkiaSharp`: SkiaSharp による描画。名前空間は `SkiaSharp` との衝突を避けるため `ZipConvertCustomerBarCode.Skia`。 +- `ZipConvertCustomerBarCode.Demo`: デモサイト(Blazor WebAssembly、net10.0、パッケージにはしない)。コアの `BarCode.Create` と `ToSvg` / `ToPrintSvg` だけを使い、郵便番号データは使わない(12万件あり、ブラウザーで読み込むには重い)。`InvariantGlobalization` で ICU を省いている(コアはカルチャに依存しない)。ソリューションに含めているので、CI の test でビルドされる。 + - ローカルでは `dotnet run --project ZipConvertCustomerBarCode.Demo` で起動する。Razor では `@code` が予約語なので、変数名に `code` を使わない。 - `netstandard2.0` の既定 C# は 7.3。`#if NET8_0_OR_GREATER` の外では `record` や null 許容参照型など新しい構文は使わない。 -- バージョン・著作権表示・パッケージ情報は `Directory.Build.props` にまとめている。パッケージアイコン `icon.png`(128×128)は、このライブラリで作ったバーコードの先頭4シンボル(スタート + 郵便番号3桁)を縦に伸ばし、紺地に白で描いたもの。`dotnet run tools/GenerateIcon.cs -- icon.png` で生成する(色・拡大率・余白もこのスクリプトにある)。 +- バージョン・著作権表示・パッケージ情報は `Directory.Build.props` にまとめている。パッケージアイコン `icon.png`(128×128)は、このライブラリで作ったバーコードの先頭4シンボル(スタート + 郵便番号3桁)を縦に伸ばし、紺地に白で描いたもの。`dotnet run tools/GenerateIcon.cs -- icon.png` で生成する(色・拡大率・余白もこのスクリプトにある)。デモサイトのファビコン `ZipConvertCustomerBarCode.Demo/wwwroot/icon.png` も同じ画像なので、作り直したらコピーする。 - 公開メンバーには XML ドキュメントコメントを付ける(`GenerateDocumentationFile` 有効のため、ないと警告になる)。CI(`GITHUB_ACTIONS`)では `TreatWarningsAsErrors` で警告をエラーにしている(依存パッケージの脆弱性の警告 NU1900〜NU1904 は除く)。ローカルで CI と同じ確認をするときは `dotnet build -p:TreatWarningsAsErrors=true` のように付ける。 - `.cs` ファイルは UTF-8(BOM 付き、`.editorconfig` にも記載)。新規ファイルにも BOM を付ける(`.claude/settings.json` のフックが Write / Edit 後に自動で補う)。改行は `core.autocrlf=true` に従う(Windows の作業ツリーでは CRLF、リポジトリ内は LF)。 @@ -41,6 +43,7 @@ - リリースは `v2.0.0` のようなタグを push すると、タグのバージョンで3パッケージを nuget.org に公開する(Trusted Publishing。ワークフローのファイル名 `build.yml` と Environment 名 `release` を nuget.org に登録しているので、どちらも名前を変えない)。nuget.org 側のポリシーは「新しいバージョンの追加のみ」なので、公開済みのバージョンは出し直せない(修正は次のバージョンで出す)。公開後に `github-release` ジョブがタグの GitHub Release を作る(リリースノートはマージした PR から自動生成、`-` を含むタグはプレリリース)。 - 公開ジョブは GitHub の `release` Environment で動く(`v*` タグのみ、cssho の承認後に実行。Secret `NUGET_USER` もこの Environment にある)。`Directory.Build.props` の `VersionPrefix` はローカルと CI のプレリリース版(`2.0.0-ci.N`)用で、公開時はタグのバージョンが優先される。`VersionPrefix` は `PackageValidationBaselineVersion` 以上にしておく(低いとアセンブリのバージョンが基準より低くなり CP0003 エラー)。 - ワークフローのアクションは `.github/workflows/actions.lock`(`gh actions-lock`)でコミットに固定している。`uses:` を追加・変更したら `gh actions-lock` でロックし直し、`gh actions-lock --verify` で確認してから、ロックファイルとワークフローを一緒にコミットする(ワークフローを編集すると、フックが `--verify-local` で漏れを知らせる)。JSON 出力は `--json=valid,findings` のように `=` でつなぐ(空白区切りだとパスとして解釈される)。 +- `.github/workflows/pages.yml`: master への push(コア・デモ・ビルド設定の変更時)と手動実行で、デモサイトを GitHub Pages(https://cssho.github.io/ZipConvertCustomerBarCode/)に配置する。リポジトリ名のパスで公開されるため、配置時に `index.html` の `` を書き換え、`.nojekyll` を置いている。 - CI の `verify-lockfile.yml` が PR・push・週1回でロックファイルを検証する。アクションの更新は Dependabot(`.github/dependabot.yml`、既定の cooldown でリリースから3日待つ)が、ロックファイルの作り直しも含めて PR にする。 - パッケージ作成時の検証(`EnablePackageValidation`)で、net8.0 版から netstandard2.0 版の公開 API が欠けているとエラー(CP0002)になる(net8.0 版にだけ API を足すのは検出しない)。 - あわせて、公開済みのバージョン(`Directory.Build.props` の `PackageValidationBaselineVersion`)と比べて公開 API を削除・変更していないかも確認する。破壊的変更をするメジャーバージョンアップでは、この基準を外すか更新する。 diff --git a/README.md b/README.md index 8296299..2b57614 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ZipConvertCustomerBarCode 郵便番号、住所から郵便物用のカスタマバーコードを生成する -[ZipConvertCustomerBarCode](http://zipccbc.azurewebsites.net/) +**[デモ](https://cssho.github.io/ZipConvertCustomerBarCode/)**: ブラウザーで郵便番号と住所を入力して、バーコードを試せます(WebAssembly で動作し、入力内容はどこにも送信しません)。 ## カスタマバーコード > お客さまがあらかじめ郵便物に印字する場合のバーコードがカスタマバーコードです。カスタマバーコードは、原則として差し出しの必要条件ではなく、料金割引を受けようとする場合に印字するもので、あて名印字と同時に印字できるような仕様としています。 diff --git a/ZipConvertCustomerBarCode.Demo/App.razor b/ZipConvertCustomerBarCode.Demo/App.razor new file mode 100644 index 0000000..29e3b4b --- /dev/null +++ b/ZipConvertCustomerBarCode.Demo/App.razor @@ -0,0 +1,213 @@ +カスタマバーコード デモ | ZipConvertCustomerBarCode + + + +
+
+

入力

+ +
+ 例: + @foreach (var sample in Samples) + { + + } +
+ + + +
+ 住所の入力方法 + + +
+ + @if (split) + { + + + } + else + { + +

+ 住所全体を町域名以降として扱うため、町域名に「丁目」「番」「ノ」などの前の漢数字を含む住所(一番町、八丁堀、三ノ輪 など)では、町域名の数字も住所表示番号として抜き出されてしまいます。 + その場合は「分けて入力」を使ってください。 +

+ } +
+ +
+

結果

+ @{ + // 入力のたびに作り直す(BarCode.Create は軽いので、ボタンを押さなくても即時に反映する) + var (barcode, error) = Generate(); + } + @if (error != null) + { +

@error

+ } + else if (barcode == null) + { +

郵便番号(7けた)を入力すると、ここにバーコードが表示されます。

+ } + else + { + + + + + @if (barcode.IsRepresentativeZipCode) + { +

+ 下2けたが「00」のため、代表の郵便番号の可能性があります。代表の郵便番号の郵便物には、カスタマバーコードを付けません。 +

+ } + +
+
郵便番号
+
@barcode.ZipCode
+
住所表示番号
+
+ @if (string.IsNullOrEmpty(barcode.AddressNumber)) + { + (なし) + } + else + { + @barcode.AddressNumber + } + バーコードに入るのは先頭13けた分です +
+
シンボル列
+
+
    + @for (var i = 0; i < barcode.Symbols.Count; i++) + { +
  1. @barcode.Symbols[i]
  2. + } +
+
    +
  • スタート・ストップ
  • +
  • 郵便番号
  • +
  • 住所表示番号
  • +
  • チェックデジット
  • +
+
+
+ +

C# で同じバーコードを作る

+
@CodeSample
+ } +
+ +
+

このデモについて

+ +
+
+ + + +@code { + private const int Scale = 3; + + private record Sample(string Label, string ZipCode, bool Split, string Address, string TownAddress, string BlockAddress); + + private static readonly Sample[] Samples = + { + new("ビル名あり", "263-0023", false, "千葉市稲毛区緑町3丁目30-8 郵便ビル403号", "", ""), + new("英字を含む", "273-0102", false, "千葉県鎌ケ谷市右京塚 東3丁目-20-5 郵便・A&bコーポB604号", "", ""), + new("住所A・Bに分ける", "100-0013", true, "", "東京都千代田区霞が関", "1丁目3番2号 郵便プラザ503室"), + new("町域名に漢数字", "102-0082", true, "", "東京都千代田区一番町", "5-3"), + }; + + private string zipCode = "263-0023"; + private bool split; + private string address = "千葉市稲毛区緑町3丁目30-8 郵便ビル403号"; + private string townAddress = ""; + private string blockAddress = ""; + + private (CustomerBarCode? Code, string? Error) Generate() + { + if (string.IsNullOrWhiteSpace(zipCode)) return (null, null); + try + { + return (split + ? BarCode.Create(zipCode, townAddress ?? "", blockAddress ?? "") + : BarCode.Create(zipCode, address ?? ""), null); + } + catch (ArgumentException) + { + return (null, "郵便番号は7けたの数字で入力してください(ハイフン・全角数字は可)。"); + } + } + + private void Apply(Sample sample) + { + zipCode = sample.ZipCode; + split = sample.Split; + address = sample.Address; + townAddress = sample.TownAddress; + blockAddress = sample.BlockAddress; + } + + // シンボル列の位置ごとの種類: スタート(0)・郵便番号(1〜7)・住所表示番号(8〜20)・チェックデジット(21)・ストップ(22) + private static string SymbolKind(int index) => index switch + { + 0 or 22 => "start", + <= 7 => "zip", + <= 20 => "address", + _ => "check", + }; + + private static string DataUri(string svg) => "data:image/svg+xml;charset=utf-8," + Uri.EscapeDataString(svg); + + private static string Literal(string value) => "\"" + value.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""; + + private string CodeSample + { + get + { + var create = split + ? $"BarCode.Create({Literal(zipCode)}, {Literal(townAddress)}, {Literal(blockAddress)})" + : $"BarCode.Create({Literal(zipCode)}, {Literal(address)})"; + return "using ZipConvertCustomerBarCode;\n\n" + + $"var code = {create};\n" + + "string svg = code.ToSvg(scale: 3); // 画像用(依存ライブラリなし)\n" + + "string printSvg = code.ToPrintSvg(point: 10); // 印刷用(mm 単位の実寸)\n" + + "// SkiaSharp で PNG にする場合: code.SavePng(\"barcode.png\", scale: 3);"; + } + } +} diff --git a/ZipConvertCustomerBarCode.Demo/Program.cs b/ZipConvertCustomerBarCode.Demo/Program.cs new file mode 100644 index 0000000..c071b03 --- /dev/null +++ b/ZipConvertCustomerBarCode.Demo/Program.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +using ZipConvertCustomerBarCode.Demo; + +var builder = WebAssemblyHostBuilder.CreateDefault(args); +builder.RootComponents.Add("#app"); +builder.RootComponents.Add("head::after"); + +await builder.Build().RunAsync(); diff --git a/ZipConvertCustomerBarCode.Demo/Properties/launchSettings.json b/ZipConvertCustomerBarCode.Demo/Properties/launchSettings.json new file mode 100644 index 0000000..0cebb5f --- /dev/null +++ b/ZipConvertCustomerBarCode.Demo/Properties/launchSettings.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "http://localhost:5122", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "https://localhost:7244;http://localhost:5122", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/ZipConvertCustomerBarCode.Demo/ZipConvertCustomerBarCode.Demo.csproj b/ZipConvertCustomerBarCode.Demo/ZipConvertCustomerBarCode.Demo.csproj new file mode 100644 index 0000000..b257a05 --- /dev/null +++ b/ZipConvertCustomerBarCode.Demo/ZipConvertCustomerBarCode.Demo.csproj @@ -0,0 +1,26 @@ + + + + + net10.0 + enable + enable + true + false + + true + + + + + + + + + + + + diff --git a/ZipConvertCustomerBarCode.Demo/_Imports.razor b/ZipConvertCustomerBarCode.Demo/_Imports.razor new file mode 100644 index 0000000..bc9dcd3 --- /dev/null +++ b/ZipConvertCustomerBarCode.Demo/_Imports.razor @@ -0,0 +1,3 @@ +@using Microsoft.AspNetCore.Components.Web +@using ZipConvertCustomerBarCode +@using ZipConvertCustomerBarCode.Demo diff --git a/ZipConvertCustomerBarCode.Demo/wwwroot/css/app.css b/ZipConvertCustomerBarCode.Demo/wwwroot/css/app.css new file mode 100644 index 0000000..ffdc8cc --- /dev/null +++ b/ZipConvertCustomerBarCode.Demo/wwwroot/css/app.css @@ -0,0 +1,422 @@ +:root { + color-scheme: light dark; + --bg: #f5f7fa; + --surface: #ffffff; + --text: #1d2733; + --muted: #5b6b7c; + --border: #d5dde6; + --accent: #1f3a5f; + --accent-text: #ffffff; + --link: #1f5fa8; + --code-bg: #eef2f6; + --error: #b42318; + --warning-bg: #fff7e0; + --warning-border: #e6b84d; + --start: #d9dee5; + --zip: #d6e6fb; + --address: #dcf2e1; + --check: #f8e1c8; +} + +@media (prefers-color-scheme: dark) { + :root { + --bg: #11161c; + --surface: #1a2129; + --text: #e3e9ef; + --muted: #9aa8b6; + --border: #2e3843; + --accent: #8fb3e0; + --accent-text: #0f1a27; + --link: #8fb8ec; + --code-bg: #222b35; + --error: #ff8a80; + --warning-bg: #3a3018; + --warning-border: #8a6d1f; + --start: #39424d; + --zip: #233b5a; + --address: #234530; + --check: #4d3721; + } +} + +*, *::before, *::after { + box-sizing: border-box; +} + +html { + -webkit-text-size-adjust: 100%; +} + +body { + margin: 0; + background: var(--bg); + color: var(--text); + font-family: system-ui, -apple-system, "Segoe UI", "Hiragino Sans", "Noto Sans JP", Meiryo, sans-serif; + line-height: 1.7; +} + +a { + color: var(--link); +} + +code, pre { + font-family: ui-monospace, "Cascadia Mono", Consolas, "Noto Sans Mono", monospace; +} + +.wrap { + max-width: 880px; + margin: 0 auto; + padding: 0 16px; +} + +.site-header { + background: var(--surface); + border-bottom: 1px solid var(--border); + padding: 24px 0 16px; + margin-bottom: 24px; +} + +.site-header h1 { + display: flex; + align-items: center; + gap: 10px; + margin: 0 0 8px; + font-size: 1.5rem; + line-height: 1.3; +} + +.site-header h1 span { + min-width: 0; + overflow-wrap: anywhere; +} + +.site-header h1 img { + border-radius: 6px; + flex: none; +} + +.lead { + margin: 0 0 8px; + color: var(--muted); +} + +.links { + display: flex; + flex-wrap: wrap; + gap: 4px 16px; +} + +.card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 10px; + padding: 20px; + margin-bottom: 20px; +} + +.card h2 { + margin: 0 0 12px; + font-size: 1.15rem; +} + +.card h3 { + margin: 24px 0 8px; + font-size: 1rem; +} + +.samples { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + margin-bottom: 16px; +} + +.samples-label { + color: var(--muted); + font-size: 0.9rem; +} + +.sample { + font: inherit; + font-size: 0.875rem; + padding: 4px 12px; + border-radius: 999px; + border: 1px solid var(--border); + background: var(--code-bg); + color: var(--text); + cursor: pointer; +} + +.sample:hover { + border-color: var(--accent); +} + +.field { + display: block; + margin-bottom: 14px; +} + +.field > span { + display: block; + font-weight: 600; + font-size: 0.9rem; + margin-bottom: 4px; +} + +.field input { + width: 100%; + font: inherit; + padding: 8px 10px; + border: 1px solid var(--border); + border-radius: 6px; + background: var(--bg); + color: var(--text); +} + +.field input:focus, .sample:focus-visible, .button:focus-visible, .mode input:focus-visible { + outline: 2px solid var(--link); + outline-offset: 1px; +} + +.mode { + border: 0; + padding: 0; + margin: 0 0 14px; +} + +.mode legend { + font-weight: 600; + font-size: 0.9rem; + margin-bottom: 4px; +} + +.mode label { + display: block; + cursor: pointer; +} + +.note { + margin: 0; + font-size: 0.875rem; + color: var(--muted); +} + +.placeholder, .muted { + color: var(--muted); +} + +.muted { + font-size: 0.85rem; + margin-left: 8px; +} + +.error { + color: var(--error); + font-weight: 600; +} + +.warning { + background: var(--warning-bg); + border: 1px solid var(--warning-border); + border-radius: 6px; + padding: 8px 12px; +} + +/* バーコードは白地に黒(ライブラリの出力のまま)。ダークモードでも白地で表示する */ +.barcode { + background: #ffffff; + border: 1px solid var(--border); + border-radius: 6px; + padding: 16px; + overflow-x: auto; +} + +.barcode svg { + display: block; + width: 100%; + max-width: 828px; + height: auto; + margin: 0 auto; +} + +.downloads { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin: 12px 0; +} + +.button { + display: inline-block; + padding: 6px 14px; + border-radius: 6px; + background: var(--accent); + color: var(--accent-text); + text-decoration: none; + font-size: 0.9rem; + font-weight: 600; +} + +.button.secondary { + background: transparent; + color: var(--link); + border: 1px solid var(--border); +} + +.details { + display: grid; + grid-template-columns: max-content 1fr; + gap: 8px 16px; + margin: 16px 0 0; +} + +.details dt { + font-weight: 600; +} + +.details dd { + margin: 0; + min-width: 0; +} + +.details code { + background: var(--code-bg); + padding: 1px 6px; + border-radius: 4px; +} + +.symbols, .legend { + display: flex; + flex-wrap: wrap; + gap: 4px; + list-style: none; + padding: 0; + margin: 0; +} + +.legend { + margin-top: 8px; + font-size: 0.8rem; +} + +.symbol { + font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; + font-size: 0.85rem; + padding: 1px 6px; + border-radius: 4px; + min-width: 2em; + text-align: center; +} + +.legend .symbol { + font-family: inherit; +} + +.symbol.start { background: var(--start); } +.symbol.zip { background: var(--zip); } +.symbol.address { background: var(--address); } +.symbol.check { background: var(--check); } + +.code { + background: var(--code-bg); + border-radius: 6px; + padding: 12px 14px; + overflow-x: auto; + font-size: 0.85rem; + line-height: 1.6; + margin: 0; +} + +.card ul { + margin: 0; + padding-left: 1.25em; +} + +/* 長いパッケージ名などが狭い画面ではみ出さないよう折り返す */ +.card li code, .details code { + overflow-wrap: anywhere; +} + +.footer { + color: var(--muted); + font-size: 0.85rem; + padding-bottom: 32px; +} + +@media (max-width: 560px) { + .details { + grid-template-columns: 1fr; + gap: 2px; + } + + .details dd { + margin-bottom: 10px; + } + + .muted { + display: block; + margin-left: 0; + } +} + +/* 読み込み中の表示とエラー表示(Blazor のテンプレートより) */ +.loading { + position: relative; + min-height: 60vh; +} + +.loading-progress { + position: absolute; + display: block; + width: 8rem; + height: 8rem; + inset: 20vh 0 auto 0; + margin: 0 auto; +} + +.loading-progress circle { + fill: none; + stroke: var(--border); + stroke-width: 0.6rem; + transform-origin: 50% 50%; + transform: rotate(-90deg); +} + +.loading-progress circle:last-child { + stroke: var(--accent); + stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%; + transition: stroke-dasharray 0.05s ease-in-out; +} + +.loading-progress-text { + position: absolute; + text-align: center; + font-weight: bold; + inset: calc(20vh + 3.25rem) 0 auto 0.2rem; +} + +.loading-progress-text::after { + content: var(--blazor-load-percentage-text, "読み込み中"); +} + +#blazor-error-ui { + color-scheme: light only; + background: lightyellow; + color: #1d2733; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; +} + +#blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; +} diff --git a/ZipConvertCustomerBarCode.Demo/wwwroot/icon.png b/ZipConvertCustomerBarCode.Demo/wwwroot/icon.png new file mode 100644 index 0000000..e79e5d4 Binary files /dev/null and b/ZipConvertCustomerBarCode.Demo/wwwroot/icon.png differ diff --git a/ZipConvertCustomerBarCode.Demo/wwwroot/index.html b/ZipConvertCustomerBarCode.Demo/wwwroot/index.html new file mode 100644 index 0000000..e219ddf --- /dev/null +++ b/ZipConvertCustomerBarCode.Demo/wwwroot/index.html @@ -0,0 +1,37 @@ + + + + + + + カスタマバーコード デモ | ZipConvertCustomerBarCode + + + + + + + + + + +
+
+ + + + +
+ +
+
+ +
+ エラーが発生しました。 + 再読み込み + 🗙 +
+ + + + diff --git a/ZipConvertCustomerBarCode.sln b/ZipConvertCustomerBarCode.sln index ff7bca3..6234011 100644 --- a/ZipConvertCustomerBarCode.sln +++ b/ZipConvertCustomerBarCode.sln @@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZipConvertCustomerBarCode.S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZipConvertCustomerBarCode.Tests", "ZipConvertCustomerBarCode.Tests\ZipConvertCustomerBarCode.Tests.csproj", "{961F7ADE-F107-48C5-816D-865351AAAB92}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZipConvertCustomerBarCode.Demo", "ZipConvertCustomerBarCode.Demo\ZipConvertCustomerBarCode.Demo.csproj", "{E538521C-BCF6-43AC-9BD5-88508F7791BE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -69,6 +71,18 @@ Global {961F7ADE-F107-48C5-816D-865351AAAB92}.Release|x64.Build.0 = Release|Any CPU {961F7ADE-F107-48C5-816D-865351AAAB92}.Release|x86.ActiveCfg = Release|Any CPU {961F7ADE-F107-48C5-816D-865351AAAB92}.Release|x86.Build.0 = Release|Any CPU + {E538521C-BCF6-43AC-9BD5-88508F7791BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E538521C-BCF6-43AC-9BD5-88508F7791BE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E538521C-BCF6-43AC-9BD5-88508F7791BE}.Debug|x64.ActiveCfg = Debug|Any CPU + {E538521C-BCF6-43AC-9BD5-88508F7791BE}.Debug|x64.Build.0 = Debug|Any CPU + {E538521C-BCF6-43AC-9BD5-88508F7791BE}.Debug|x86.ActiveCfg = Debug|Any CPU + {E538521C-BCF6-43AC-9BD5-88508F7791BE}.Debug|x86.Build.0 = Debug|Any CPU + {E538521C-BCF6-43AC-9BD5-88508F7791BE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E538521C-BCF6-43AC-9BD5-88508F7791BE}.Release|Any CPU.Build.0 = Release|Any CPU + {E538521C-BCF6-43AC-9BD5-88508F7791BE}.Release|x64.ActiveCfg = Release|Any CPU + {E538521C-BCF6-43AC-9BD5-88508F7791BE}.Release|x64.Build.0 = Release|Any CPU + {E538521C-BCF6-43AC-9BD5-88508F7791BE}.Release|x86.ActiveCfg = Release|Any CPU + {E538521C-BCF6-43AC-9BD5-88508F7791BE}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE