Skip to content

feat(booking): add a per-user booking accent color - #69

Merged
shockalotti merged 1 commit into
Calnode:mainfrom
marijnbent:feat/booking-accent-color
Sep 21, 2026
Merged

shockalotti merged 1 commit into
Calnode:mainfrom
marijnbent:feat/booking-accent-color

Conversation

@marijnbent

@marijnbent marijnbent commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

Booking pages currently use the same dark accent for every host. This adds a color setting to Profile so a host can match their booking page to their own site.

The saved color applies to selected dates, time slots and primary buttons on the public booking and manage pages, and the supported Web Component embed. The event owner's color is used. Existing users keep the current dark accent by default.

The API accepts a six-digit hex color, normalizes it, and rejects invalid values. The button text switches between black and white based on the background luminance. There are no brand-specific defaults or workspace-wide color changes.

Validation: make build, go test ./..., pnpm check and pnpm test:visual pass. Tests cover color validation, persistence and foreground selection. Screenshots below compare the default color with a blue accent on the same local demo event.

This adds migration 00060; it may need renumbering before merge.

Before

Before

After

After

@github-actions

github-actions Bot commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA. ✅
Posted by the CLA Assistant Lite bot.

@marijnbent

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request Sep 20, 2026
@marijnbent
marijnbent marked this pull request as ready for review September 20, 2026 18:57
@pullfrog

pullfrog Bot commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

This repo's model isn't fully set up yet.

OPENAI_COMPATIBLE_MODEL env var is required when the model is set to "openai-compatible/byok". set it to the model ID served by your OpenAI-compatible endpoint (e.g. a Cloudflare AI Gateway or DashScope model). see https://docs.pullfrog.com/openai-compatible for setup.

Configure model →

Pullfrog  | Rerun failed job ➔ | View workflow run | via Pullfrog | Using OpenAI-compatible | 𝕏

@shockalotti

Copy link
Copy Markdown
Contributor

@pullfrog please review this PR

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No critical issues — minor suggestions inline, plus a couple of nitpicks.

Reviewed changes

  • Per-user booking accent color — new users.booking_accent column (migration 00060), six-digit-hex validation and lowercasing on PATCH /v1/users/me, surfaced via GET /v1/users/me, the public event-type payload, the book/manage templates, the embed widget, and a Profile color picker. The 00060 slot is free (highest existing migration is 00059_caldav_home_url.sql), so it does not need renumbering.
  • Contrast-aware foreground — accentForeground selects black/white from WCAG relative luminance; the 0.179 cutoff is the correct crossover where black and white contrast against a color meet.
  • Tests — TestBookingAccentReadableForeground (luminance table incl. invalid input) and TestProfileBookingAccent (rejects red / CSS-injection shapes, lowercases #FFE500, checks persistence). Both fail against a naive implementation, and go test ./internal/handler/ -run Accent passes locally.

ℹ️ Nitpicks

  • docs/ARCHITECTURE.md — the new note is inserted as the first paragraph under “15. Frontend toolchain & conventions”, but it describes booking/theme behaviour rather than toolchain conventions; it reads better in the booking/slots section.
  • The default #111827 is now written in four places that must move together if it ever changes: the migration DEFAULT, profile/+page.svelte:26, the embed fallback (embed.js:224), and the CSS fallback (booking.css:470).

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using opencode-go/deepseek-v4.1-flash | 𝕏

.demo-banner strong { font-weight: 600; }
.demo-banner a { color: inherit; text-decoration: underline; font-weight: 600; }

.cd.sel, .slot-btn.sel, .btn-primary { background: var(--booking-accent, #111827) !important; border-color: var(--booking-accent, #111827); color: var(--booking-accent-text, #fff) !important; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.btn-primary now carries background: … !important, which beats the existing .btn-primary:hover:not(:disabled) background (line 261), so primary buttons no longer darken on hover. The same accent/foreground pairing also leaves .cd.sel.today::after white (line 140), so the “today” dot disappears on light accents.

Technical details
# `!important` on `.btn-primary` freezes hover, and the today-dot ignores the foreground

## Affected sites
- `internal/handler/templates/booking.css:470` — `.cd.sel, .slot-btn.sel, .btn-primary { background: var(--booking-accent) !important; … }` overrides the non-important `.btn-primary:hover:not(:disabled) { background:#1f2937 }` at line 261.
- `internal/handler/templates/booking.css:140` — `.cd.sel.today::after { background:#fff; }` stays white even when `--booking-accent-text` is black for a light accent.

## Required outcome
- Selected controls keep the accent, but `.btn-primary` keeps its hover feedback; the today dot stays legible on both light and dark accents.

## Suggested approach (optional)
- Split the selector: `!important` is only needed to out-specify `.cd.sel`'s pre-existing `!important` at line 130. Leave `.btn-primary` background non-`!important` (nothing competes with it) and add a hover rule that tints the accent.
- Set `.cd.sel.today::after` to `background: currentColor` (or `var(--booking-accent-text)`) so the dot follows the chosen foreground.

Comment thread internal/handler/setup.go
return
}
if req.BookingAccent != nil {
if !regexp.MustCompile(`^#[0-9a-fA-F]{6}$`).MatchString(*req.BookingAccent) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regexp.MustCompile runs inside PatchMe, recompiling the pattern on every profile save. The repo hoists these to package-level vars (validUserID at avatar.go:19, gtmIDRe/ga4IDRe at tracking_settings.go:14).

Technical details
# Hoist the accent-validation regexp

## Affected sites
- `internal/handler/setup.go:171` — `regexp.MustCompile(\`^#[0-9a-fA-F]{6}$\`)` compiled per request.

## Suggested approach
- Add a package-level `var bookingAccentRe = regexp.MustCompile(\`^#[0-9a-fA-F]{6}$\`)` alongside the existing regex vars and reference it here.

@shockalotti
shockalotti merged commit 27f03e3 into Calnode:main Sep 21, 2026
2 of 3 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants