diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index a259598..4547d43 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -5,12 +5,12 @@ "url": "https://github.com/microsoft/win-dev-skills" }, "description": "Agents and skills for native Windows app development with WinUI 3 and the Windows App SDK.", - "version": "0.3.1", + "version": "0.4.0", "plugins": [ { "name": "winui", "description": "Agents and skills for WinUI 3 app development. Create new WinUI 3 desktop apps, convert from other frameworks to WinUI 3, or add features to existing WinUI 3 applications.", - "version": "0.3.1", + "version": "0.4.0", "source": "./plugins/winui", "category": "windows-development", "tags": [ diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7b38900 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,16 @@ +* text=auto eol=lf + +*.md text eol=lf +*.json text eol=lf +*.txt text eol=lf + +*.ps1 eol=lf +*.ts eol=lf +*.cs eol=lf +*.csproj eol=lf + + +*.png binary +*.jpg binary +*.ico binary +*.zip binary \ No newline at end of file diff --git a/.github/plugin/marketplace.json b/.github/plugin/marketplace.json index ffe956e..c40b8b5 100644 --- a/.github/plugin/marketplace.json +++ b/.github/plugin/marketplace.json @@ -6,13 +6,13 @@ }, "metadata": { "description": "Agents and skills for native Windows app development with WinUI 3 and the Windows App SDK.", - "version": "0.3.1" + "version": "0.4.0" }, "plugins": [ { "name": "winui", "description": "Agents and skills for WinUI 3 app development. Create new WinUI 3 desktop apps, convert from other frameworks to WinUI 3, or add features to existing WinUI 3 applications.", - "version": "0.3.1", + "version": "0.4.0", "source": "./plugins/winui" } ] diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1e90ecb..be0e1fa 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -33,7 +33,7 @@ jobs: build-mode: none steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Initialize CodeQL uses: github/codeql-action/init@v4 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 46b5d98..ae9a1fa 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Dependency Review uses: actions/dependency-review-action@v5 diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml index ce024b7..2cc3a2f 100644 --- a/.github/workflows/pr-validation.yml +++ b/.github/workflows/pr-validation.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Setup .NET uses: actions/setup-dotnet@v5 @@ -54,7 +54,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Download CI-built analyzer DLL uses: actions/download-artifact@v8 @@ -109,7 +109,7 @@ jobs: runs-on: windows-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Setup .NET uses: actions/setup-dotnet@v5 @@ -194,7 +194,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Validate plugin.json structure shell: bash @@ -231,7 +231,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Check every SKILL.md has valid YAML frontmatter shell: bash @@ -269,7 +269,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Compare duplicated analyzer .targets files shell: bash diff --git a/.github/workflows/release-policy.yml b/.github/workflows/release-policy.yml index 9e853b6..2dfd32b 100644 --- a/.github/workflows/release-policy.yml +++ b/.github/workflows/release-policy.yml @@ -4,11 +4,12 @@ name: Release policy # See CONTRIBUTING.md and RELEASING.md for the human-side flow. # # Job matrix: -# pr-target-policy PR → main | head_ref must be staging or hotfix/* -# version-sync PR → staging | NO version field changed +# pr-target-policy PR → main | head_ref must be staging, release/*, or hotfix/* +# version-sync PR → staging | NO version field changed (skipped for backmerge/*) # version-bump PR → main | all 5 version fields bumped, in sync, valid semver, strictly greater # changelog-entry PR → main | top-most CHANGELOG section matches new version, has bullets -# staging-up-to-date PR → staging | staging contains every commit on main +# staging-up-to-date PR → staging | PR head contains every commit on main +# (passes naturally for backmerge/* PRs) on: pull_request: @@ -51,11 +52,15 @@ jobs: version-sync: name: No version bump in feature PR - if: github.event.pull_request.base.ref == 'staging' + # Skip on backmerge/* PRs: those legitimately carry main's version-bump + # commit forward into staging. See CONTRIBUTING.md § Back-merge path. + if: > + github.event.pull_request.base.ref == 'staging' && + !startsWith(github.event.pull_request.head.ref, 'backmerge/') runs-on: ubuntu-latest steps: - name: Checkout (full depth) - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} @@ -95,25 +100,37 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout (full depth) - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 - - name: Verify staging contains every commit on main + - name: Verify PR head contains every commit on main + env: + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + HEAD_REF: ${{ github.event.pull_request.head.ref }} shell: bash run: | set -euo pipefail - git fetch origin main staging --quiet - # Find commits on main that are not on staging. - MISSING=$(git rev-list --count origin/main ^origin/staging) + git fetch origin main --quiet + # We check the PR head (not origin/staging) so back-merge PRs — which + # bring main into staging — pass naturally: after they merge, staging + # will contain main. Any other PR that doesn't already include main + # will fail here exactly as it would have under the old "staging vs + # main" check. + MISSING=$(git rev-list --count origin/main ^"$HEAD_SHA") if [[ "$MISSING" -gt 0 ]]; then - echo "::error::'staging' is behind 'main' by $MISSING commit(s)." - echo "::error::This usually means a hotfix landed on main and was not back-merged into staging." - echo "::error::A maintainer must run: git checkout staging && git merge origin/main && git push" - echo "::error::Then this PR can proceed. See CONTRIBUTING.md § Hotfix path." + echo "::error::PR head ('$HEAD_REF') is missing $MISSING commit(s) from 'main'." + echo "::error::This usually means a hotfix landed on main and was not back-merged into staging," + echo "::error::and this PR was branched from a stale staging." + echo "::error::Fix: open a back-merge PR first." + echo "::error:: git checkout -b backmerge/ origin/staging" + echo "::error:: git merge origin/main" + echo "::error:: git push -u origin backmerge/" + echo "::error:: gh pr create --base staging --head backmerge/" + echo "::error::Then rebase this PR on the updated staging. See CONTRIBUTING.md § Back-merge path." exit 1 fi - echo "::notice::'staging' contains every commit on 'main' — OK." + echo "::notice::PR head contains every commit on 'main' — OK." version-bump: name: Version bump (5 fields in sync) @@ -121,7 +138,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout (full depth) - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} @@ -202,7 +219,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/release-post-merge.yml b/.github/workflows/release-post-merge.yml index f717c7b..43863c0 100644 --- a/.github/workflows/release-post-merge.yml +++ b/.github/workflows/release-post-merge.yml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 @@ -114,7 +114,7 @@ jobs: BODY=$(cat < back into staging." + ``` + + The branch **must** be named `backmerge/*` — the `version-sync` CI check + skips that prefix so the version-bump diff doesn't trip the gate. The + `back-merge-reminder` workflow opens a tracking issue if you forget. + +## Back-merge path + +Whenever `main` advances (promotion PR merge, hotfix merge, revert) `staging` +must be caught up before any new feature PR can merge. Open a back-merge: + +```powershell +git fetch origin +git checkout -b backmerge/ origin/staging +git merge origin/main +git push -u origin backmerge/ +gh pr create --base staging --head backmerge/ +``` + +Naming: use `backmerge/X.Y.Z` after a release, `backmerge/hotfix-` after +a hotfix. The `backmerge/` prefix is required — without it the `version-sync` +check will (correctly) refuse to let the version-bump diff land on staging. ## CI checks you'll see | Check | When it runs | What it wants | |---|---|---| | `pr-target-policy` | PR targets `main` | Your branch is `staging`, `release/*`, or `hotfix/*`, AND comes from this repo (not a fork). | -| `version-sync` | PR targets `staging` | You did NOT change any version field. | +| `version-sync` | PR targets `staging` | You did NOT change any version field. (Skipped on `backmerge/*`.) | | `version-bump` | PR targets `main` | All 5 version fields bumped, valid semver, strictly greater, identical. | | `changelog-entry` | PR targets `main` | Top-most `## [X.Y.Z]` section matches the bumped version, has at least one bullet. | -| `staging-up-to-date-with-main` | PR targets `staging` | `staging` contains every commit on `main` (so hotfixes aren't lost). | +| `staging-up-to-date-with-main` | PR targets `staging` | PR head contains every commit on `main` (back-merge PRs satisfy this naturally). | | `build-tools` + provenance | Any PR | C# tools build, analyzer tests pass, committed payloads match source. | | `validate-plugin-manifest` + `validate-skill-frontmatter` | Any PR | Manifests are well-formed, every `SKILL.md` has valid frontmatter. | diff --git a/README.md b/README.md index 7417724..f9a9172 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,28 @@ Add the `microsoft/win-dev-skills` marketplace, then enable the `winui` plugin f > **Note:** Codex doesn't have an "agents" concept, so the orchestrator agent isn't exposed there. The skills still work - invoke them by name (e.g. `/winui-setup`, `/winui-design`) and Codex will load them on demand. +
+OpenClaw + +Install straight from this repo - no marketplace pre-registration needed. The explicit `--marketplace` source clones the repo on demand, reads its marketplace manifest, and installs the `winui` plugin natively (`Format: openclaw`): + +```powershell +openclaw plugins install winui --marketplace microsoft/win-dev-skills +openclaw gateway restart +``` + +Or from a local clone: + +```powershell +git clone https://github.com/microsoft/win-dev-skills +openclaw plugins install ./win-dev-skills/plugins/winui +``` + +Verify the eight skills loaded with `openclaw skills list` (each shows `✓ ready`). + +> **Note:** OpenClaw maps skills, not agents, so the `winui-dev` orchestrator agent isn't exposed there. The skills still work - ask the agent for a WinUI task and it loads the relevant skill on demand. +
+ Then start a new session and run the `winui-setup` skill with `/winui-setup`. Once setup is done, try a real task: diff --git a/RELEASING.md b/RELEASING.md index 709a652..0e4855d 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -109,6 +109,27 @@ Automatically: (consumers may need to run `copilot plugin marketplace update win-dev-skills` to see the new version listed). +## Post-release back-merge (REQUIRED) + +After the promotion PR merges and `auto-tag` succeeds, **immediately open a +back-merge PR `main → staging`**. Without it, `staging` is missing the version +bump + the freshly-emptied `[Unreleased]` CHANGELOG section, and +`open-release-pr.ps1` will refuse to cut the next release until staging catches +up. + +```powershell +git fetch origin +git checkout -b backmerge/X.Y.Z origin/staging +git merge origin/main +git push -u origin backmerge/X.Y.Z +gh pr create --base staging --head backmerge/X.Y.Z ` + --title "Back-merge main into staging after X.Y.Z" ` + --body "Brings the Release X.Y.Z commit from main back into staging." +``` + +The branch **must** start with `backmerge/` — the `version-sync` CI check +skips that prefix so the version-bump diff doesn't trip the gate. + > [!IMPORTANT] > **Don't announce the new tag externally until `auto-tag` succeeds.** > Marketplace consumers (`winui@win-dev-skills`) get the new code as soon as @@ -126,7 +147,8 @@ If a release on `main` is broken: 3. Add a CHANGELOG entry under the new version explaining what was reverted and why. 4. PR against `main` directly — this is treated like a hotfix. -5. Back-merge the revert into `staging` after merging. +5. Back-merge the revert into `staging` after merging via a `backmerge/*` PR + (see CONTRIBUTING.md § Back-merge path). The original tag stays in place (we don't delete tags); the rollback creates a new tag. Consumers updating past the broken version skip cleanly. diff --git a/plugins/winui/index.js b/plugins/winui/index.js new file mode 100644 index 0000000..aca1f06 --- /dev/null +++ b/plugins/winui/index.js @@ -0,0 +1,13 @@ +import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; + +// win-dev-skills is a content plugin: it ships WinUI 3 skills (and agents) only, +// with no runtime tools, providers, or channels. OpenClaw native plugins require +// a code entry point, so this registers nothing and lets the manifest's `skills` +// field drive skill discovery. +export default definePluginEntry({ + id: "winui", + name: "WinUI", + description: + "Agents and skills for WinUI 3 app development. Create new WinUI 3 desktop apps, convert from other frameworks to WinUI 3, or add features to existing WinUI 3 applications.", + register() {}, +}); diff --git a/plugins/winui/openclaw.plugin.json b/plugins/winui/openclaw.plugin.json new file mode 100644 index 0000000..3ba149c --- /dev/null +++ b/plugins/winui/openclaw.plugin.json @@ -0,0 +1,13 @@ +{ + "id": "winui", + "name": "WinUI", + "description": "Agents and skills for WinUI 3 app development. Create new WinUI 3 desktop apps, convert from other frameworks to WinUI 3, or add features to existing WinUI 3 applications.", + "skills": [ + "skills" + ], + "configSchema": { + "type": "object", + "additionalProperties": false, + "properties": {} + } +} diff --git a/plugins/winui/package.json b/plugins/winui/package.json new file mode 100644 index 0000000..c9dc6d8 --- /dev/null +++ b/plugins/winui/package.json @@ -0,0 +1,21 @@ +{ + "name": "winui", + "type": "module", + "private": true, + "description": "Agents and skills for WinUI 3 app development. Create new WinUI 3 desktop apps, convert from other frameworks to WinUI 3, or add features to existing WinUI 3 applications.", + "license": "MIT", + "files": [ + "index.js", + "openclaw.plugin.json", + "skills", + "agents" + ], + "peerDependencies": { + "openclaw": ">=2026.3.24-beta.2" + }, + "openclaw": { + "extensions": [ + "./index.js" + ] + } +} diff --git a/plugins/winui/plugin.json b/plugins/winui/plugin.json index e81be12..b7d61b3 100644 --- a/plugins/winui/plugin.json +++ b/plugins/winui/plugin.json @@ -1,7 +1,7 @@ { "name": "winui", "description": "Agents and skills for WinUI 3 app development. Create new WinUI 3 desktop apps, convert from other frameworks to WinUI 3, or add features to existing WinUI 3 applications.", - "version": "0.3.1", + "version": "0.4.0", "author": { "name": "Microsoft", "url": "https://github.com/microsoft/win-dev-skills" diff --git a/plugins/winui/skills/winui-design/SKILL.md b/plugins/winui/skills/winui-design/SKILL.md index ff4e081..9890d43 100644 --- a/plugins/winui/skills/winui-design/SKILL.md +++ b/plugins/winui/skills/winui-design/SKILL.md @@ -1,60 +1,59 @@ --- name: winui-design -description: "WinUI 3 UI design and XAML correctness — layout planning, control selection, Fluent Design, theming (Light/Dark/HighContrast), typography styles, spacing, brushes, accessibility, data binding review. Use when designing new pages, converting from WPF/Electron/web, reviewing XAML, fixing theme issues, or applying Fluent Design." +description: "Use when designing, reviewing, or fixing WinUI 3: layout planning, control choice, Fluent Design alignment, Light/Dark/High Contrast theming, typography, spacing, brushes, accessibility, and XAML data-binding design. Load before authoring new XAML, reviewing UI PRs, migrating desktop UI to WinUI, or choosing between WinUI controls/patterns." --- -### UI Planning -> **Before picking controls, search the catalogue.** This skill ships `winui-search.exe` alongside this `SKILL.md`. It indexes 100+ WinUI Gallery controls, every Windows Community Toolkit scenario, and a curated set of platform integration patterns (JumpList, Share, file pickers, drag-drop). Use it to ground every control choice in a real shipping sample **before writing any XAML** — this is the difference between guessing property names and copying canonical code. -> -> ```powershell -> .\winui-search.exe search "" "" ... # batch one focused query per feature -> .\winui-search.exe get ... # batch up to 3 IDs — full XAML + C# + pitfall notes -> .\winui-search.exe list # browse all patterns (heavy — prefer search) -> .\winui-search.exe update # force refresh now -> ``` -> -> **Workflow:** in **one** `search` call, list every feature you need for the current page (one focused query per feature, not a bag of keywords) → from each shortlist pick the best ID → grab full code with `get` (batch up to 3 IDs per call) → then write XAML using those samples as reference. **Do NOT interleave searching with coding** — front-load all lookups, then code. BM25 rewards focused per-query phrasing, so keep each query about one control or pattern. -#### Step 1: Identify App Type and Anchor Control -| App Type | Anchor Control | Reference App | -|----------|---------------|---------------| -| Settings / config tool | `NavigationView` Left + `SettingsCard` | Windows Settings | -| Document / session editor | `TabView` + full-width content | Windows Terminal, Notepad | -| Hierarchical browser | `TreeView` + `ListView` + `BreadcrumbBar` | File Explorer | -| Developer tool / dashboard | `NavigationView` + card layout | Dev Home | -| Single-purpose utility | Mode switcher + compact grid | Calculator | +## Search samples before writing XAML -#### Step 2: Map Requirements to Controls -**Navigation:** 2-7 sections → `NavigationView`; document tabs → `TabView`; breadcrumb trail → `BreadcrumbBar`; 2-3 modes → `SelectorBar`. +This skill ships `winui-search.exe` alongside this `SKILL.md` (≈100 WinUI Gallery controls, every Windows Community Toolkit scenario, curated platform-integration patterns; each result returns full XAML + C# + pitfall notes). **Front-load lookups, then code** — don't interleave. -**Data display:** Vertical list → `ListView`; tiles/grid → `GridView` or `ItemsRepeater` + `UniformGridLayout`; hierarchy → `TreeView`; tabular → `ListView` with Grid column headers; master-detail → `ListView` + detail `Grid`. +```powershell +.\winui-search.exe search "" "" ... # batch one focused query per feature (BM25 likes focused phrasing) +.\winui-search.exe get ... # batch up to 3 IDs — full XAML + C# + pitfall notes +.\winui-search.exe list # browse all patterns (heavy — prefer search) +.\winui-search.exe update # force cache refresh +``` + +Search covers controls **and** platform integration (file pickers, Share, JumpList, drag-drop, app lifecycle, dialogs) — front-load all lookups before writing XAML; **don't interleave** search with coding. + +## App-shape anchors + +Pick the closest shipping app silhouette before laying out a page: + +| App type | Anchor controls | Reference apps | +|----------|-----------------|----------------| +| Settings / config tool | `NavigationView` Left + `SettingsCard` / `SettingsExpander` | Windows Settings, Slack | +| Document / session editor | `TabView` + full-bleed content, light chrome | Windows Terminal, VS Code, Notepad | +| Hierarchical browser | `TreeView` + `ListView` + `BreadcrumbBar` | File Explorer, Outlook | +| Developer tool / dashboard | `NavigationView` + card layout | Dev Home, GitHub Desktop | +| Single-purpose utility | Mode switcher + compact grid | Calculator, Snipping Tool | +| Media / canvas / hero | `Grid` with hero surface, floating commands, **no** `NavigationView` | Photos, Spotify, Clipchamp | + +## Reach-for-this control map -**Input:** Text → `TextBox`; number → `NumberBox`; search → `AutoSuggestBox`; date → `CalendarDatePicker`; boolean → `ToggleSwitch`; pick one from 2-3 → `RadioButtons`; pick one from 4+ → `ComboBox`. +Before writing XAML, map the requirement to a platform control. These mappings exist to short-circuit cross-framework instincts (WPF `DataGrid`, web ``): -**Feedback:** Blocking decision → `ContentDialog`; contextual action → `Flyout`/`MenuFlyout`; onboarding → `TeachingTip`; inline status → `InfoBar`; system notification → `AppNotification`. +- **Navigation:** 2–7 sections → `NavigationView`; document/session tabs → `TabView`; breadcrumb trail → `BreadcrumbBar`; 2–3 modes → `SelectorBar`. +- **Data display:** Vertical list → `ListView`; tiles/grid → `GridView` or `ItemsRepeater` + `UniformGridLayout`; hierarchy → `TreeView`; **tabular → `ListView` with a `Grid`-based `ItemTemplate` and a header `Grid` above** (WinUI has no `DataGrid`; don't default to `CommunityToolkit.WinUI.Controls.DataGrid` — its columns can't use `x:Bind`); master-detail → `ListView` + detail `Grid`. +- **Input:** Text → `TextBox`; number → `NumberBox`; search → `AutoSuggestBox`; date → `CalendarDatePicker`; boolean → `ToggleSwitch`; pick one from 2–3 → `RadioButtons`; pick one from 4+ → `ComboBox`. +- **Feedback:** Blocking decision → `ContentDialog`; contextual action → `Flyout` / `MenuFlyout`; onboarding / hint → `TeachingTip`; inline status / async progress → `InfoBar`; system notification → `AppNotification`. -#### Step 3: Plan Layout -- **Content fills the window** — no floating cards on empty backgrounds -- `Grid` for structure, `StackPanel` only for simple stacking of few items -- Sidebar: fixed 300-360px width; main content: `Width="*"` with 24px padding -- Status bar: `Grid` row at bottom; toolbar: `CommandBar` or title bar buttons +If the mapping above doesn't fit, search `winui-search.exe` before improvising. -#### Step 4: Size the Window to the App +## Window sizing (WinUI 3 specifics) -> **WinUI 3 has no `SizeToContent`.** Without an explicit size, Windows defaults the main window to ~1024×768 — oversized for most utilities. **Size the window in `MainWindow`'s constructor; derive from the layout, not a generic.** +> **WinUI 3 has no `SizeToContent`.** Without an explicit size, Windows defaults the main window to ~1024×768 — oversized for most utilities. Size it in `MainWindow`'s constructor. -**Rubric.** Width = widest row + 48 padding (24 each side), rounded **up** to nearest 20. Height = 32 (titlebar) + Σ(row heights) + Σ(spacing) + 48 padding, rounded up to 20. Round up — clipped content is a worse failure than a slightly-wide window. +**Rubric.** Width = widest row + 48 padding, rounded up to nearest 20. Height = 32 (titlebar) + Σ(row heights) + Σ(spacing) + 48 padding, rounded up to 20. Round up — clipped content is a worse failure than a slightly-wide window. Sanity ranges (derive yours from the rubric): -**Sanity check** (ranges, not targets — derive yours from the rubric): - Single-purpose utility → ~440–560 wide - Form / single-page tool → ~600–800 wide, ~640–800 tall - Multi-pane (nav + content) → ~1100–1300 wide, ~720–840 tall - Document / canvas / media editor → 1280+ wide -If your derived number is well below its range, you missed a row — re-check. - -`AppWindow.Resize` takes **physical pixels**, not DIPs — multiply by the monitor's DPI scale: +`AppWindow.Resize` takes **physical pixels**, not DIPs — multiply by the monitor's DPI scale. `XamlRoot.RasterizationScale` is null in the constructor and stale after `AppWindow.Move`, so `[DllImport] GetDpiForWindow` is the cleanest path: ```csharp using Microsoft.UI; @@ -72,150 +71,104 @@ public sealed partial class MainWindow : Window InitializeComponent(); var hwnd = Win32Interop.GetWindowFromWindowId(AppWindow.Id); var scale = GetDpiForWindow(hwnd) / 96.0; - AppWindow.Resize(new SizeInt32((int)(460 * scale), (int)(860 * scale))); + // widthDip / heightDip come from the rubric above — derive, don't copy. + AppWindow.Resize(new SizeInt32((int)(widthDip * scale), (int)(heightDip * scale))); } } ``` -`XamlRoot.RasterizationScale` is null in the ctor and stale after `AppWindow.Move`, so `[DllImport]` is the cleanest path. Don't try to size the window by setting `Width`/`Height` on the root `Grid` — that clips content, not the window. - -If the user asks for UI validation, see `winui-ui-testing` Step 3.5 to verify the rubric against the visual checklist. - -#### Step 5: Design Anti-Patterns -| ❌ Don't | ✅ Do Instead | -|----------|--------------| -| Centered floating card on background | Content fills window with padding | -| Custom pill/segment tab switcher | `NavigationView` Top or `SelectorBar` | -| Equal-width 50/50 column split | Fixed sidebar (300-360px) + flexible main | -| Hardcoded colors (`#FF0000`) | `{ThemeResource}` brushes | -| `ScrollViewer` around `ListView` | ListView has built-in scrolling | -| Custom ControlTemplate for standard controls | Built-in controls with style overrides | +Don't size the window by setting `Width`/`Height` on the root `Grid` — that clips content, not the window. -### XAML Correctness +## XAML landmines (the things you'll otherwise ship broken) -#### Theming Rules -- **`{ThemeResource BrushName}`** at usage sites — updates on theme change -- **`{StaticResource}`** with `ResourceKey` redirects inside theme dictionaries — zero allocation -- **`ResourceKey` must end in `Brush`** (target the `SolidColorBrush`, not the `Color`) -- Always define all three variants: `x:Key="Light"`, `x:Key="Dark"`, `x:Key="HighContrast"` — never use `x:Key="Default"` -- Verify runtime theme switching: `{ThemeResource}` updates; `{StaticResource}` does not +### `x:Bind` defaults to `OneTime` ```xml - - - - - + + + + ``` -#### High Contrast -Only 8 system color brushes allowed in HC dictionaries: - -| Background | Foreground | Use Case | -|------------|------------|----------| -| `SystemColorWindowColorBrush` | `SystemColorWindowTextColorBrush` | General content | -| `SystemColorHighlightColorBrush` | `SystemColorHighlightTextColorBrush` | Selected/hover | -| `SystemColorButtonFaceColorBrush` | `SystemColorButtonTextColorBrush` | Buttons | -| `SystemColorWindowColorBrush` | `SystemColorHotlightColorBrush` | Hyperlinks | -| `SystemColorWindowColorBrush` | `SystemColorGrayTextColorBrush` | Disabled content | - -**HC prohibitions:** No hardcoded colors, no opacity, no accent colors, no regular WinUI brushes, no `SystemColor*` in Light/Dark dicts. Use empty HC dict when WinUI defaults suffice. Set `HighContrastAdjustment = None` at app level. - -#### Typography — Use Styles, Not Raw FontSize -| Style | Size | Weight | Use For | -|-------|------|--------|---------| -| `CaptionTextBlockStyle` | 12px | Regular | Small labels, timestamps | -| `BodyTextBlockStyle` | 14px | Regular | Body text (default — don't set explicitly) | -| `BodyStrongTextBlockStyle` | 14px | Semibold | Emphasized body text | -| `SubtitleTextBlockStyle` | 20px | Semibold | Section headers, card titles | -| `TitleTextBlockStyle` | 28px | Semibold | Page titles | -| `TitleLargeTextBlockStyle` | 40px | Semibold | Large feature titles | -| `DisplayTextBlockStyle` | 68px | Semibold | Hero text | - -Use `SemiBold`, never `Bold`. Minimum 12px. `BasedOn` styles must not re-declare inherited properties. - -#### Spacing and Layout -- **4px grid:** margins, padding, sizes must be multiples of 4 (4, 8, 12, 16, 24, 32, 48) -- `ControlCornerRadius` (4px) for controls, `OverlayCornerRadius` (8px) for overlays — never hardcode -- `RowSpacing`/`ColumnSpacing` instead of spacer elements -- `MinHeight`/`MinWidth` instead of fixed sizing -- No negative margins - -#### Remove Defaults -Don't set WinUI default values — blocks future updates: -- `BodyTextBlockStyle` on TextBlock, `TextFillColorPrimaryBrush` foreground, `TextWrapping="NoWrap"`, `Padding="0"`, `Margin="0"` - -#### Acrylic Pairings -| Surface | Background | Border | -|---------|-----------|--------| -| Flyouts, tooltips | `AcrylicBackgroundFillColorDefaultBrush` | `SurfaceStrokeColorFlyoutBrush` | -| UI surfaces | `AcrylicBackgroundFillColorBaseBrush` | `SurfaceStrokeColorDefaultBrush` | - -Use `BackgroundSizing="InnerBorderEdge"` on bordered acrylic. `ThemeShadow` requires `Translation="0,0,32"` and 12px parent padding. - -#### Data Binding -- `{x:Bind}` over `{Binding}`, explicit `Mode=OneWay`/`TwoWay`, `x:DataType` on `DataTemplate` -- **TextBox `x:Bind TwoWay` — always add `UpdateSourceTrigger=PropertyChanged`** so the ViewModel updates on each keystroke instead of waiting for `LostFocus`. Without it, UIA automation (`set-value`) and programmatic changes won't commit to the ViewModel. - ```xml - - ``` -- Commands over Click/Tapped handlers (MVVM) -- `VisualStateManager` for visual property changes, not code-behind -- No `IValueConverter` — prefer `x:Bind` with functions - -**Bool negation and Visibility functions** — define static methods in code-behind: -```csharp -// In code-behind (e.g., MainPage.xaml.cs) -public static Visibility BoolToVisibility(bool value) => - value ? Visibility.Visible : Visibility.Collapsed; -public static Visibility InvertBoolToVisibility(bool value) => - value ? Visibility.Collapsed : Visibility.Visible; -public static bool IsNotBusy(bool isLoading) => !isLoading; -``` +### `TextBox` two-way needs `UpdateSourceTrigger=PropertyChanged` + ```xml - -Visibility="{x:Bind local:MainPage.BoolToVisibility(ViewModel.IsLoading), Mode=OneWay}" -IsEnabled="{x:Bind local:MainPage.IsNotBusy(ViewModel.IsLoading), Mode=OneWay}" + ``` -❌ NEVER use `Converter={x:Null}` — it crashes at runtime. -#### Accessibility -- `AutomationProperties.Name` on icon-only controls -- `AutomationProperties.AutomationId` on all interactive controls -- Semantic controls (`Button`, `HyperlinkButton`) — not clickable `Border`/`TextBlock` -- `DividerStrokeColorDefaultBrush` for dividers +Default trigger resolves to `LostFocus` specifically for `TextBox.Text` (most other properties default to `PropertyChanged`). The VM is not updated per keystroke, and UIA keyboard-simulation tests (WinAppDriver `SendKeys`, etc.) that assert immediately after typing will see stale VM state until focus moves. + +### Attached properties from C# use static setters, not initializers -**Setting attached properties in code-behind** — WinUI attached properties use static methods, NOT object initializer syntax: ```csharp -using Microsoft.UI.Xaml.Automation; // required for AutomationProperties +using Microsoft.UI.Xaml.Automation; -// ❌ WRONG — object initializer doesn't work for attached properties +// ❌ WRONG — does not compile. CS0117: 'Button' does not contain a definition for 'AutomationProperties'. +// AutomationProperties is a static class of attached-property accessors, not an instance member. var btn = new Button { AutomationProperties = { AutomationId = "BtnSave" } }; -// ✅ CORRECT — static setter method +// ✅ CORRECT var btn = new Button { Content = "Save" }; AutomationProperties.SetAutomationId(btn, "BtnSave"); AutomationProperties.SetName(btn, "Save button"); Grid.SetRow(btn, 1); -Grid.SetColumn(btn, 0); ToolTipService.SetToolTip(btn, "Save the current document"); ``` -#### Formatting -- Self-closing tags for childless elements -- Styles referenced with `{StaticResource}` not `{ThemeResource}` -- No `px` suffix on numeric values, no commented-out XAML -- Consistent attribute order: x:Name, AutomationProperties, layout, content, style - -### References - -| File | Read when... | -|------|-------------| -| `references/approved-brushes.md` | Looking up correct WinUI brush names and usage rules | -| `references/theme-aware-resources.md` | Implementing ThemeResource/StaticResource, High Contrast, acrylic pairings | -| `references/code-review-checklist.md` | Reviewing XAML changes for correctness | -| `references/pr-review-patterns.md` | Applying concrete review fixes and patterns | -| `references/control-styles.md` | Customizing built-in control styles | -| `references/typography-and-spacing.md` | Detailed type ramp, spacing grid, and sizing examples | -| `references/colors-and-materials.md` | Theme brush catalog, Mica/Acrylic surface pairings, material usage | -| `references/iconography-and-motion.md` | Icon guidelines, animation patterns, connected animations | +### `Converter={x:Null}` crashes `x:Bind` at runtime + +`{x:Bind}` requires `Converter` to be a `{StaticResource}` lookup. `Converter={x:Null}` compiles but the generated code calls `LookupConverter("")`, which returns null, then dereferences it — you get `Resource Dictionary Key can only be String-typed` / `NullReferenceException` on first activation of the binding. If you don't want a converter, omit the property entirely. + +### Prefer `x:Bind` static functions over `IValueConverter` + +```csharp +// MainPage.xaml.cs +public static Visibility BoolToVisibility(bool v) => v ? Visibility.Visible : Visibility.Collapsed; +public static Visibility InvertBoolToVisibility(bool v) => v ? Visibility.Collapsed : Visibility.Visible; +public static bool Not(bool v) => !v; +``` +```xml + + +``` + +Don't rely on the glyph alone — screen readers won't announce "save icon" without `AutomationProperties.Name`. + +### Reusing an icon definition + +Define once in `App.xaml`, consume anywhere via `IconSourceElement`: + +```xml + + +``` +```xml + + + +``` + +### IconElement-bearing controls (cheat-sheet) + +Controls whose `Icon` property takes an `IconElement`: +- `AppBarButton`, `AppBarToggleButton` +- `MenuFlyoutItem`, `MenuFlyoutSubItem` +- `AutoSuggestBox.QueryIcon` +- `NavigationViewItem` +- `SelectorBarItem` + +Controls whose `IconSource` property takes an `IconSource`: +- `TabViewItem`, `SwipeItem` +- `InfoBar`, `InfoBadge` +- `TeachingTip` +- `XamlUICommand` +- `AnimatedIcon.FallbackIconSource`, `AnimatedIconSource.FallbackIconSource` + +If you find yourself wrapping a `FontIcon` in `IconSourceElement` repeatedly, you've picked the wrong slot — switch the parent's property to its `IconSource`-typed sibling if it exists. diff --git a/plugins/winui/skills/winui-design/references/code-review-checklist.md b/plugins/winui/skills/winui-design/references/code-review-checklist.md deleted file mode 100644 index 10c5a71..0000000 --- a/plugins/winui/skills/winui-design/references/code-review-checklist.md +++ /dev/null @@ -1,114 +0,0 @@ -# Code Review Checklist - -## Theme Support - -- [ ] Uses `{ThemeResource}` for colors/brushes at usage sites -- [ ] Uses `{StaticResource}` with `ResourceKey` redirects inside theme dictionaries -- [ ] Custom theme resources define `Light`, `Dark`, and `HighContrast` variants -- [ ] No `x:Key="Default"` — uses explicit `Light`/`Dark`/`HighContrast` -- [ ] `ResourceKey` values end in `Brush` (not the Color name) -- [ ] HC dictionary uses only the 8 system color brushes (no accent, no hardcoded, no WinUI brushes) -- [ ] No opacity on elements or brushes in HC dictionaries -- [ ] No HC resources (`SystemColor*`) used in Light/Dark dictionaries -- [ ] `StaticResource` redirects preferred over inline `SolidColorBrush` in theme dicts -- [ ] Theme dictionary `x:Key` order consistent across Light/Dark/HighContrast -- [ ] No partial theme updates — Light/Dark changes include matching HighContrast in same PR -- [ ] No ad-hoc themed literals (`White`/`Transparent` for themed surfaces) -- [ ] Acrylic surfaces use correct border/background pairings -- [ ] Light and Dark dicts reference the same semantic WinUI keys; differences are intentional -- [ ] Empty HC dict used when WinUI defaults suffice (``) -- [ ] `HighContrastAdjustment="None"` set at app level -- [ ] Accent colors use `SystemAccentColor*` resources (no hardcoded accent values) -- [ ] Verify runtime theme switching (ThemeResource updates; StaticResource does not) - -## Data Binding - -- [ ] Uses `{x:Bind}` over `{Binding}` where possible -- [ ] `Mode` explicitly set on `x:Bind` when values change (`OneWay`/`TwoWay`) -- [ ] `DataTemplate` has `x:DataType` specified -- [ ] No `IValueConverter` — uses `x:Bind` with functions -- [ ] Button text uses `Content` directly, not a nested `TextBlock` -- [ ] `IsEnabled` bound from ViewModel readiness state -- [ ] Commands used instead of Click/Tapped event handlers (MVVM) -- [ ] `VisualStateManager` used for visual property changes (not code-behind) -- [ ] ViewModel state mapped to named properties (bool/enum) instead of complex converter stacks -- [ ] Converters are only simple type conversions; business logic stays in ViewModel -- [ ] No code-behind for styles/colors/layout (exception: `HighContrastAdjustment` at app level) - -## Typography - -- [ ] Uses system text styles, not hardcoded font properties -- [ ] `FontWeight` is `SemiBold`, never `Bold` -- [ ] `BasedOn` styles do not re-declare inherited properties -- [ ] Default `TextFillColorPrimaryBrush` foreground not explicitly set -- [ ] No font sizes below 12px -- [ ] Icon TextBlocks set `IsTextScaleFactorEnabled="False"` -- [ ] Icon font uses `{ThemeResource SymbolThemeFontFamily}`, not hardcoded - -## Layout - -- [ ] Uses `ControlCornerRadius`/`OverlayCornerRadius` (not hardcoded) -- [ ] Selective corner rounding uses standard radii (e.g., `8,8,0,0`) -- [ ] Margins/padding use multiples of 4 -- [ ] Uses `MinHeight`/`MinWidth` instead of fixed sizing -- [ ] No fixed heights on text containers -- [ ] No fixed button widths (content-driven or `MinWidth`) -- [ ] `Border` for single-child containers (not nested Grids) -- [ ] `StackPanel` does not contain TextBlocks needing `TextTrimming` -- [ ] `RowSpacing`/`ColumnSpacing` used instead of spacer elements -- [ ] No negative margins -- [ ] `ThemeShadow` has `Translation="0,0,32"` and 12px parent padding -- [ ] Shadow receiver is behind the elevated element (z-order) -- [ ] `BackgroundSizing="InnerBorderEdge"` on bordered acrylic elements -- [ ] Mixed-control rows vertically centered - -## Styles - -- [ ] Styles referenced with `{StaticResource}` (not `{ThemeResource}`) -- [ ] Default WinUI property values not explicitly set (Padding, CornerRadius, etc.) -- [ ] Single-use styles inlined, named style deleted -- [ ] Existing WinUI styles checked before creating custom ones -- [ ] No no-op style churn -- [ ] App-specific resources stay in app or feature dictionaries -- [ ] `ThemeResource` used inside style setters for themed values -- [ ] VisualStateManager uses AdaptiveTrigger for responsive layout when needed -- [ ] Unused VisualState definitions removed - -## Resource Organization & Naming - -- [ ] Semantic resource keys used (avoid location-based names) -- [ ] Shared resources promoted only when reused across features -- [ ] One-off values remain local (no global resources for single-use) - -## Accessibility - -- [ ] `AutomationProperties.Name` on icon-only controls -- [ ] Light-dismiss targets are hit-test visible (`Background="Transparent"`) -- [ ] `DividerStrokeColorDefaultBrush` for dividers (not custom opacity brushes) - -## Performance - -- [ ] `x:Load` for conditional content -- [ ] `x:Phase` for list item incremental loading -- [ ] `OneTime` binding for static content -- [ ] Minimal container nesting - -## Formatting - -- [ ] Uniform indentation (spaces, no tabs) -- [ ] Self-closing tags for childless elements -- [ ] No `px` suffix on numeric values -- [ ] No commented-out XAML -- [ ] Unused VisualState definitions removed -- [ ] ThemeDictionaries before non-themed resources -- [ ] Namespace declarations ordered consistently (default, `x:`, platform, WinUI, local) -- [ ] Attribute order consistent across related files -- [ ] No checkpoint files checked in (use `_CP` locally and remove before commit) - -## Testing Reminders - -**If changing brushes:** Test in NightSky HC theme, hover on all interactive elements. Include Light/Dark/HC screenshot evidence. - -**If changing text/containers:** Test with text scaling at max and with long/localized strings. - -**If changing layout:** Test at 100%, 150%, 200%, 250% display scaling. Validate Figma at 100% scale. diff --git a/plugins/winui/skills/winui-design/references/colors-and-materials.md b/plugins/winui/skills/winui-design/references/colors-and-materials.md deleted file mode 100644 index caf424e..0000000 --- a/plugins/winui/skills/winui-design/references/colors-and-materials.md +++ /dev/null @@ -1,106 +0,0 @@ -# Colors and Materials Reference - -## Colors — Theme Resources - -**Never hardcode colors.** Always use `{ThemeResource}` brushes so your app works in Light, Dark, and High Contrast modes. - -### Text brushes - -| Resource | Use for | -|----------|---------| -| `TextFillColorPrimaryBrush` | Primary text (headings, body) | -| `TextFillColorSecondaryBrush` | Secondary / supporting text | -| `TextFillColorTertiaryBrush` | Pressed state text | -| `TextFillColorDisabledBrush` | Disabled text only | -| `TextOnAccentFillColorPrimaryBrush` | Text on accent-colored backgrounds | -| `AccentTextFillColorPrimaryBrush` | Hyperlinks and accent text | - -### Control fill brushes - -| Resource | Use for | -|----------|---------| -| `ControlFillColorDefaultBrush` | Control rest state | -| `ControlFillColorSecondaryBrush` | Control hover state | -| `ControlFillColorTertiaryBrush` | Control pressed state | -| `ControlFillColorDisabledBrush` | Disabled controls | -| `ControlFillColorInputActiveBrush` | Focused text input fields | - -### Background brushes - -| Resource | Use for | -|----------|---------| -| `CardBackgroundFillColorDefaultBrush` | Card backgrounds | -| `CardBackgroundFillColorSecondaryBrush` | Alternate card rows | -| `LayerFillColorDefaultBrush` | Layered surface backgrounds | -| `SolidBackgroundFillColorBaseBrush` | Opaque page backgrounds | -| `SmokeFillColorDefaultBrush` | Overlay dimming (behind dialogs) | -| `AcrylicBackgroundFillColorBaseBrush` | Acrylic material surfaces | - -### Accent fill (for primary action buttons) - -| Resource | Use for | -|----------|---------| -| `AccentFillColorDefaultBrush` | Primary button rest | -| `AccentFillColorSecondaryBrush` | Primary button hover | -| `AccentFillColorTertiaryBrush` | Primary button pressed | -| `AccentFillColorDisabledBrush` | Disabled primary button | - -### Stroke / border brushes - -| Resource | Use for | -|----------|---------| -| `CardStrokeColorDefaultBrush` | Card borders | -| `ControlStrokeColorDefaultBrush` | Control borders | -| `DividerStrokeColorDefaultBrush` | Separators and dividers | - -### Color code examples - -```xml - - - - - - - - - -``` - ---- - -## Materials — Mica & Acrylic - -**Mica** — use for the app's main window background. It samples the desktop wallpaper for a subtle tinted translucency. - -**Acrylic** — use for transient surfaces (flyouts, menus, sidebars) layered on top of the main window. - -```xml - - - - - - - - - - - - - - -``` - -| Material | Surface lifetime | Example | -|----------|-----------------|---------| -| **Mica** | Long-lived (app window) | Main window background | -| **Mica Base Alt** | Long-lived (alternate tint) | Secondary window background | -| **Acrylic** | Transient (overlays) | Flyouts, sidebars, command bars | - -Materials fall back to solid color on unsupported systems — no code needed. diff --git a/plugins/winui/skills/winui-design/references/control-styles.md b/plugins/winui/skills/winui-design/references/control-styles.md deleted file mode 100644 index cd3d6bf..0000000 --- a/plugins/winui/skills/winui-design/references/control-styles.md +++ /dev/null @@ -1,91 +0,0 @@ -# Control Styles - -Built-in WinUI 3 styles and patterns. Use `{StaticResource}` to reference, `BasedOn` to extend. - -## Button Styles - -| Style | Description | -|-------|-------------| -| `DefaultButtonStyle` | Standard button | -| `AccentButtonStyle` | Accent-colored primary action button | -| `NavigationBackButtonNormalStyle` | Back navigation (40x40) | -| `NavigationBackButtonSmallStyle` | Small back navigation (30x30) | - -```xml - -``` - -Empty HC dictionary lets WinUI defaults apply. Light and Dark usually have identical redirects. Border brush states should match background states. - -## Typography Styles - -| Style | Size | Weight | Use Case | -|-------|------|--------|----------| -| `CaptionTextBlockStyle` | 12px | Regular | Small labels, timestamps | -| `BodyTextBlockStyle` | 14px | Regular | Default body text (applied by default) | -| `BaseTextBlockStyle` | 14px | Semibold | Base body style (less common) | -| `BodyStrongTextBlockStyle` | 14px | Semibold | Emphasized body text | -| `BodyLargeTextBlockStyle` | 18px | Regular | Prominent body text | -| `SubtitleTextBlockStyle` | 20px | Semibold | Section headers, card titles | -| `TitleTextBlockStyle` | 28px | Semibold | Page titles | -| `TitleLargeTextBlockStyle` | 40px | Semibold | Large feature titles | -| `DisplayTextBlockStyle` | 68px | Semibold | Hero text | - -**Rules:** -- `BodyTextBlockStyle` is the default — do not explicitly apply it. -- `TextWrapping="NoWrap"` is the default — do not set it. -- Use `SemiBold`, never `Bold`. -- Minimum 12px for CJK legibility. -- `BasedOn` styles must not re-declare inherited properties (FontSize, FontFamily, FontWeight, LineHeight). - -## Style Hygiene - -- Reference styles with `{StaticResource}` (not `{ThemeResource}` — unnecessary overhead). -- Check for existing WinUI styles before creating custom ones. -- Single-use styles: inline the properties, delete the named style. -- Keep one-off values inline; promote to shared dictionary only when reused. -- Prefer setters/resource overrides for minor visual tweaks; avoid replacing `ControlTemplate` unless structurally required. -- Use `ThemeResource` inside style setters for theme-dependent values. -- Avoid no-op style churn. - -## Naming Conventions - -| Type | Convention | Example | -|------|------------|---------| -| Style | `{Purpose}Style` | `PrimaryButtonStyle` | -| Brush | `{Usage}{Property}Brush` | `HeaderBackgroundBrush` | -| DataTemplate | `{DataType}Template` | `UserItemTemplate` | -| Element `x:Name` | PascalCase + suffix | `SearchTextBox`, `SaveButton` | diff --git a/plugins/winui/skills/winui-design/references/iconography-and-motion.md b/plugins/winui/skills/winui-design/references/iconography-and-motion.md deleted file mode 100644 index 51d9e86..0000000 --- a/plugins/winui/skills/winui-design/references/iconography-and-motion.md +++ /dev/null @@ -1,103 +0,0 @@ -# Iconography and Motion Reference - -## Iconography - -Use **Segoe Fluent Icons** (Windows 11) via the `SymbolThemeFontFamily` resource, which falls back to **Segoe MDL2 Assets** on Windows 10 automatically. - -### Icon types in order of preference - -| Type | When to use | Example | -|------|-------------|---------| -| `SymbolIcon` | Standard named icons (simplest) | `` | -| `FontIcon` | Specific glyph codes from Segoe Fluent Icons | `` | -| `AnimatedIcon` | Interactive states (checkbox, nav, toggle) | Built-in with some controls | -| `ImageIcon` | Custom brand icons or images | `` | -| `PathIcon` | Custom vector shapes | `` | -| `BitmapIcon` | Legacy bitmap icons | Avoid — prefer `ImageIcon` | - -**Standard icon sizes:** 16px (inline/compact), 20px (default control size), 24px (emphasis), 32px (large), 48px (hero/feature). - -### Icon code examples - -```xml - - - - - - - - - - - - -``` - -Browse available icons in the **WinUI Gallery** app → Design guidance → Iconography, or search [Segoe Fluent Icons](https://learn.microsoft.com/windows/apps/design/style/segoe-fluent-icons-font). - ---- - -## Corner Radius - -Use the **built-in theme resources** — never hardcode `CornerRadius` values: - -| Resource | Value | Use for | -|----------|-------|---------| -| `ControlCornerRadius` | 4px | In-page controls (buttons, inputs, list items) | -| `OverlayCornerRadius` | 8px | Top-level containers (cards, dialogs, flyouts, app window) | -| 0px | — | Edges that intersect with other straight edges (no resource needed) | - -```xml - - - - - - - - - - - -``` - -### Connected animations - -Animate elements between pages (e.g., list item → detail page): - -```csharp -// Source page — prepare animation -var service = ConnectedAnimationService.GetForCurrentView(); -service.PrepareToAnimate("itemAnimation", sourceElement); -Frame.Navigate(typeof(DetailPage), item); - -// Destination page — play animation -var animation = ConnectedAnimationService.GetForCurrentView() - .GetAnimation("itemAnimation"); -animation?.TryStart(destinationElement); -``` diff --git a/plugins/winui/skills/winui-design/references/layout-review.md b/plugins/winui/skills/winui-design/references/layout-review.md new file mode 100644 index 0000000..2aad8be --- /dev/null +++ b/plugins/winui/skills/winui-design/references/layout-review.md @@ -0,0 +1,41 @@ +# WinUI layout and responsive review reference + +Load this when reviewing responsive behaviour, breakpoints, or state coverage on a data-driven page. SKILL.md already covers theming, control choice, and XAML landmines — don't duplicate. + +## Page planning template + +Fill these in before writing XAML or reviewing a page: + +- Primary user task: +- Secondary tasks: +- Content type / density: +- Navigation structure: flat / hierarchical / hybrid: +- App silhouette: shell (left/top nav) / document / canvas-hero / dense-grid / list-detail / single-task: +- Breakpoint behaviour at small (`<640`), medium (`641–1007`), large (`≥1008`) epx: +- Input modes covered: keyboard, mouse, touch, pen: + +## Responsive techniques (least to most disruptive) + +Pick the lightest change that preserves the task: + +| Technique | Use when | Example | +|---|---|---| +| **Reposition** | Same content fits better elsewhere | Side details move below main on narrow widths | +| **Resize** | Same content needs different space | Wider reading column at large widths | +| **Reflow** | Sequence can wrap or change columns | One column becomes two at `≥1008` epx | +| **Show/hide** | Secondary metadata is optional at small widths | Hide avatar/details, keep a route to full info | +| **Re-architect** | Width changes the task model | Single-pane list-detail becomes side-by-side | + +Breakpoints are **app-window effective pixels**, not physical screen pixels. The window can be `<640` epx on a 4K monitor. + +## State coverage for any data-driven page + +Every collection, fetch, or async-bound surface should explicitly handle: + +- **Loading** — progress text or skeleton; not just a spinner with no context +- **Empty** — what happened and what the user can do (call-to-action, not just "no items") +- **Error** — cause if known + a retry/repair affordance; never colour-only +- **Offline / permission denied** — separate from generic error if the recovery path differs +- **Selection** — including keyboard arrow-key behaviour and multi-select where relevant + +If any of these aren't represented in the view model, the page isn't done. diff --git a/plugins/winui/skills/winui-design/references/pr-review-patterns.md b/plugins/winui/skills/winui-design/references/pr-review-patterns.md deleted file mode 100644 index d1a9737..0000000 --- a/plugins/winui/skills/winui-design/references/pr-review-patterns.md +++ /dev/null @@ -1,186 +0,0 @@ -# Review Guidance Patterns - -Concrete guidance patterns for WinUI 3 XAML reviews. Use these as a checklist for common pitfalls and fixes. - -## 1. Brush References Must Target Brush Resources - -`ResourceKey` must reference the `SolidColorBrush` resource (suffix `Brush`), not the `Color` resource. - -```xml - - - - - -``` - -Applies to High Contrast as well: - -```xml - - - - - -``` - -## 2. Prefer StaticResource Redirects Over Inline SolidColorBrush - -Inline brushes allocate new objects. Redirect to existing WinUI brushes instead: - -```xml - - - - - -``` - -## 3. High Contrast Rules (Strict) - -- Only use the 8 system color brushes in HighContrast dictionaries. -- No hardcoded colors, no opacity, no accent colors, no regular WinUI brushes in HC. -- No gradient animations in HC. Use a single SystemColor brush. -- Use `{ThemeResource}` only for `SystemColor*` in HC; use `{StaticResource}` elsewhere. -- Use empty HC dictionary when WinUI defaults suffice: - `` -- Set `HighContrastAdjustment = ApplicationHighContrastAdjustment.None` once at app level. - -## 4. Remove Defaults and Redundant Properties - -Avoid setting WinUI default values; it blocks future updates. - -```xml - -