Skip to content

refactor: use reusable CI workflows from genebean/.github#43

Closed
genebean wants to merge 47 commits into
malcolmrigg:masterfrom
genebean:feat/use-reusable-workflows
Closed

refactor: use reusable CI workflows from genebean/.github#43
genebean wants to merge 47 commits into
malcolmrigg:masterfrom
genebean:feat/use-reusable-workflows

Conversation

@genebean

@genebean genebean commented Jun 25, 2026

Copy link
Copy Markdown

Summary

  • update-flake-lock.yml → calls update-flake-lock reusable workflow from genebean/.github
  • ci.ymlpre-commit (with npm-install: true) and nix-build (with npmDepsHash-glob: flake.nix) jobs call reusable workflows; typecheck, npm-audit, dependency-review, hacs-validate remain local

Test plan

  • Verify CI passes on this PR

genebean and others added 30 commits June 5, 2026 14:43
- Cache computed theme colors in set hass so drawing functions do not
  call getComputedStyle on every animation frame
- Bind animation callback once (_boundDrawClock) instead of allocating a
  new closure on every requestAnimationFrame call
- Replace manual ctx.rotate undo math with ctx.save/ctx.restore in all
  drawing functions, eliminating floating-point drift risk
- Replace DOM div creation in drawNumbers with ctx.measureText for font
  height, eliminating forced reflow on every frame
- Fix clearRect: was only clearing top-left quadrant; now clears full
  canvas (canvas.width/2, canvas.height/2 → canvas.width, canvas.height)
- Fix CSS property name typo: '--primary-background-color:' → without ':'
- Store ResizeObserver as instance variable and add disconnectedCallback
  to disconnect it (and cancel pending rAF/timeout) when card is removed
- Move resize debounce timeout to per-instance (_resizeTimeout) so
  multiple clock cards on the same dashboard don't clobber each other's
  timers; remove module-level resizeTimeout/resizeDelay/debouncedOnResize

No behavior changes — VERSION remains 0.9.0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Make getWizardState() the single source of truth: it now accepts a full
  wizard config object so it can check proximity_sensor; set hass populates
  a _wizardStates cache and drawTime reads from it instead of reimplementing
  state logic independently (which caused divergence and broke permanent
  locations)
- Remove pre-adding of lost/travelling zones: they now only appear on the
  dial when a wizard is actually in that state
- Remove the && this.config.travelling gate on travelling detection: moving
  by velocity or proximity sensor triggers Travelling regardless of whether
  the custom text key is set
- Proximity sensor check moved into getWizardState so both zone-building
  (set hass) and hand-positioning (drawTime) use the same decision
- Accept both 'travelling' and 'traveling' (American spelling) in config
- Accept both 'fontName' and 'fontname' spellings in config
- Default lostState to "Lost", travellingState to "Travelling" (was "Away")
- Reduce wizardOffset spread factor from 0.6 to 0.3 so hands center more
  accurately on their zone label

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Default width changed from 500 to 0 (auto); when width is not set the
  card fills its column width as a square, so it works in any layout
  without requiring a pixel value in the config
- @font-face is now only injected when the user provides a fontface config
  value; the previous default loaded ITCBLKAD.TTF from /local/ which
  produces a 404 for anyone who hasn't placed that file manually
- Default font changed to "Palatino Linotype, Palatino, Book Antiqua,
  serif" — a widely available system serif with a classic feel that suits
  the wizard theme without requiring a custom font file
- Add getGridOptions() so the card behaves correctly in the HA sections
  (grid) layout, reserving the right number of rows for its square shape
- Update getCardSize() to handle the auto-size case (falls back to
  availableWidth when configuredWidth is 0)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a full build pipeline (Nix dev shell, esbuild, TypeScript) and
rewrites the card as a LitElement with typed interfaces.

Build: flake.nix provides a nodejs_24 dev shell and a buildNpmPackage
derivation so both `nix develop -c npm run build` and `nix build`
produce wizard-clock-card.js. npmDepsHash is pinned against
package-lock.json; update it with prefetch-npm-deps after any dep change.

Card: WizardClockCard now extends LitElement with shadow DOM. hass is a
@Property() so Lit drives the reactive update cycle. Updates only trigger
a redraw when one of the watched entities (wizard entities and proximity
sensors) actually changes state — not on every HA state update. Config is
normalised through migrateConfig() which maps legacy spellings (traveling,
fontname) to canonical British English forms before any other code sees them.

Layout: getGridOptions() returns a 6×6 default with min 2×2, replacing
the dynamic row calculation. Canvas sizing uses min(width, height) so the
clock stays round at any card aspect ratio. CSS custom properties are read
from the shadow host (getComputedStyle(this)) which correctly inherits
HA's theme values through shadow DOM boundaries.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
build:dev and watch:dev produce wizard-clock-card-dev.js registering as
custom:wizard-clock-card-dev so stable and dev cards can coexist in HA.
CARDNAME is now a build-time esbuild --define inject rather than a source
constant, which prevents esbuild from inlining it before substitution.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add @Property layout so HA's layout context (grid vs masonry) triggers
  redraws on context switches
- CSS: ha-card height 100% + overflow hidden; canvas starts at 0x0 so
  masonry offsetHeight is near 0 before JS runs, preventing false
  height-constraint detection
- Sizing: use host offsetHeight when > 50px and < width (sections grid
  allocation); otherwise size by width only (masonry, editor)
- Observe :host in ResizeObserver instead of canvas to avoid write→fire
  feedback loop; reduce debounce to 100ms

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move _targetstate computation from _drawTime() to _updateAndDraw() so
  no array/object allocation happens on animation frames; only recomputed
  when entity state or config actually changes
- Sync non-animated hand fields (length, width, colour) to _currentstate
  in _updateAndDraw() so canvas resizes immediately reflect new dimensions
- Cache measureText() results per update in _charWidthCache and _textHeight;
  _drawNumbers() now does zero measureText calls per animation frame
- Promote _fontScale to module-level FONT_SCALE constant
- Prevent duplicate @font-face injection via module-level Set; repeated
  setConfig() calls (e.g. while editing YAML) no longer append duplicate
  <style> elements to document.body
- Remove ha-card { height: 100% } so the gray card content-sizes to the
  canvas circle; any leftover section space is transparent, not gray
- Reduce default rows from 8 to 7 for a tighter fit at typical section
  widths including mobile (7 × 56px ≈ 390px column width)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add wizard-clock-card-editor.ts: full LitElement editor using ha-form
  for all fields, ha-selector for zone picker, ha-expansion-panel for
  the Advanced section (mushroom pattern)
- Editor features: per-wizard entity/name/colour/textcolour/proximity
  pickers, auto-fill display name from friendly_name on entity change,
  proximity sensor validation warning, location list from zone picker,
  advanced settings (header, lost/travelling labels, min slots, fonts,
  shaft colour)
- Main card: add getConfigElement() dynamic import, getStubConfig(hass),
  window.customCards registration, max_rows:8 in getGridOptions()
- Fix wizard name fallback to friendly_name then entity ID so hands
  always have a label
- Fix hand text: anchor at 75% from hinge, rotate(PI/2) without
  per-quadrant flip so name reads from flare toward hinge on all hands
- Export WizardConfig and WizardClockCardConfig for editor import

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s section

Wizards section is expanded by default; individual wizards are collapsed.
Stops inner panel expanded-changed events from propagating to the outer
Wizards panel listener (which was causing the outer panel to collapse on
first render, producing continuous dialog reflowing and card shrinking).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Uses the same bare ha-expansion-panel pattern as the Advanced section —
no expanded binding, no event handlers. Starts collapsed by default.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces free-text hex inputs with the button-card style colour picker
for hand colour, name colour, and shaft colour. Accepts both named theme
colours and custom hex strings; value stored as a canvas-compatible string.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Self-contained agent instructions covering project structure, tooling
contract (nix develop), build commands (dev-only during feature work,
both at release), ha-expansion-panel patterns, HA-native component
patterns, config schema, and commit/PR hygiene.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds face_colour (default #EDE0C4 cream), border_colour (default #1a1a1a),
and location_colour (default #1a1a1a) config fields with ui_color pickers
in the Advanced section. All four colour fields (including shaft_colour)
now resolve HA theme tokens at draw time so picking a named token like
"primary" stays in sync with theme changes.

Border lineWidth increased from 2% to 8% of radius to match the classic
clock look from the readme image.

shaft_colour default changed from theme primary to #1a1a1a. A one-time
info banner in the card editor prompts existing users to choose between
restoring the old theme-based colour or keeping the new dark default.
The banner disappears permanently once either button is clicked.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ThemeColours interface previously carried secondaryBackground and
primaryBackground but neither was consumed anywhere after the configurable
colour fields were added. Remove both fields and their corresponding
getComputedStyle reads in _updateAndDraw().

Remove stale _shaftColour assignment in setConfig(): shaft_colour is now
resolved via _resolveColour() in _updateAndDraw() on every update, so the
raw copy written in setConfig() was immediately superseded and never read.

Pass cs (CSSStyleDeclaration) into _buildTargetState() and resolve
wizard.colour / wizard.textcolour through _resolveColour() before storing
them in HandState. Previously, if a user selected a ui_color theme token
(e.g. "primary") the literal string reached canvas fillStyle unchanged,
which canvas ignores. Tokens are now converted to CSS values at state-build
time so _drawHand() always receives a canvas-ready colour string.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
WizardClockCardConfig.width was never read — canvas sizing uses
offsetWidth/offsetHeight, not a configured value.

_drawNumbers() carried a kerning constant hardcoded to 0. Substituting 0
into the two affected formulas removes the dead variable and makes the
arc-placement math read directly.

_getWizardState() accepted WizardConfig | string but the string path was
never called. Narrowing the signature to WizardConfig removes two
typeof branches and makes the proximity sensor lookup unconditional.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces _labelOffset, replacing the old _textHeight field, to drive
both the text y-position and the arc-radius used for character spacing
in _drawNumbers().

The offset is computed as: ascent + r × 0.06.
  ascent   — scales with font size, keeps the outer glyph edge a fixed
             distance inside the border regardless of how many zones are
             shown.
  r × 0.06 — fixed clearance: 0.04r covers the border stroke half-width,
             0.02r is a visual gap.

The previous approach (textHeight × 1.5) was a fixed multiplier that
over-pushed text inward when few zones were configured (large font),
while only being correct for the many-zone auto-shrunk case.

Auto-shrink uses the same nominalOffset for the arc-per-label calculation
so the scaling decision and the final ring placement are consistent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full rewrite: TypeScript/Lit, visual editor, configurable colours, auto-shrink labels
Card identity
- Rename prod element from wizard-clock-card → weasley-clock-card (CARDNAME baked in at build)
- Add build:upstream script to produce wizard-clock-card.js for upstream PR testing (gitignored)
- Rename prod build output to weasley-clock-card.js; add dev/upstream outputs to .gitignore
- Update flake.nix pname, description, installPhase, and add nixfmt-tree/deadnix to devShell

HACS integration
- hacs.json: name = "Weasley Clock Card" (no render_readme → HACS shows info.md)
- info.md: full user-facing docs — installation, migration from wizard-clock-card (drop-in replacement), complete config reference, features list
- README.md: dev/contributor focused — build commands, dev card setup, upstream-compat build, project structure

CI / automation
- .github/workflows/ci.yml: pre-commit, typecheck, nix-build, npm-audit, dependency-review, hacs-validate (hacs/action)
- .github/workflows/release.yml: on release published → build prod JS and attach to GitHub release
- .github/workflows/update-flake-lock.yml: weekly Nix flake input updates via DeterminateSystems
- .github/renovate.json: weekly npm + GHA dependency updates, GHA updates grouped into one PR
- .pre-commit-config.yaml: trailing-whitespace, EOF, JSON/YAML checks, nixfmt, deadnix, typecheck
- Delete stale .github/workflows/validate.yaml (referenced non-existent repo.json and wizard-clock-card.js)

AGENTS.md
- Retitle and add CARDNAME/element-name explanation
- Update project structure listing with all new files
- Expand build commands table: add build:upstream and typecheck rows
- Update architecture section with correct element name per build target
- Add CI and Pre-commit section documenting hooks, CI jobs, release workflow, Renovate
- Update Git Branch Workflow: master → main, add fork PR note (--repo flag required)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chore: rename to weasley-clock-card, add HACS + CI infrastructure
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rename
- Repository: weasley-clock-card → weasley-wizarding-clock-card
- Source files: src/wizard-clock-card{,-editor}.ts → src/weasley-wizarding-clock-card{,-editor}.ts
- Built JS: weasley-clock-card.js → weasley-wizarding-clock-card.js
- Element name (CARDNAME): weasley-clock-card → weasley-wizarding-clock-card
- Dev element: weasley-clock-card-dev → weasley-wizarding-clock-card-dev
- Upstream element (wizard-clock-card) unchanged

hacs.json: add "filename" field so HACS knows which JS asset to download
(learned from boilerplate-card reference; required for correct HACS install)

Version bump: 0.10.0 → 0.11.0 across package.json, package-lock.json (both
places), flake.nix, and VERSION constant; npmDepsHash recomputed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chore: rename to weasley-wizarding-clock-card, release v0.11.0
esbuild is an npm devDependency — node_modules must be present for
npm run build to work. Add npm ci step, same fix as was applied to ci.yml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix: install npm deps before build in release workflow
Without this explicit flag HACS defaults to rendering README.md. The README
is dev/contributor focused; info.md has the user-facing install and config docs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The name shown in the HA card picker and editor was still "Wizard Clock Card"
from the upstream. Changed to "Weasley Wizarding Clock" to match the repo.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix: correct card name in customCards registration
Release skill corrections from v0.10.0/v0.11.0 experience:
- gh release create (not tag push) is what triggers the release workflow
- Remove warning against git push --tags (old upstream tags are valid history)
- Add pre-commit run -a step before committing

.gitignore: change .claude/ to .claude/* so negation patterns for
.claude/skills/** work without requiring -f on git add

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
genebean and others added 17 commits June 7, 2026 23:18
fix: update release skill and gitignore for .claude/skills
chore(deps): update github actions (major)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chore: combine Renovate dep updates (esbuild, custom-card-helpers, typescript)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docs: add deps-update skill for combining Renovate PRs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docs: add release branch step to release skill
Previously only mentioned gh pr create. Extends the rule to cover all
gh commands (issue create, release create, etc.) so agents always
target genebean/weasley-wizarding-clock-card, not the upstream fork.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docs: extend gh fork guard to all gh operations
Replaces inline job steps with calls to genebean/.github reusable workflows:
- update-flake-lock.yml → update-flake-lock
- ci.yml pre-commit + nix-build jobs → pre-commit-nix (npm-install), nix-build
@genebean

Copy link
Copy Markdown
Author

Opened against wrong repo — this targets the upstream fork. PR is being opened against genebean/weasley-wizarding-clock-card instead.

@genebean genebean closed this Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant