diff --git a/Dockerfile b/Dockerfile index cd3c778..fc651c2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,8 @@ WORKDIR /app/site ARG PUBLIC_ENABLE_SW=true ENV PUBLIC_ENABLE_SW=$PUBLIC_ENABLE_SW +ARG PUBLIC_ENABLE_NAV_HOVER_LINE=true +ENV PUBLIC_ENABLE_NAV_HOVER_LINE=$PUBLIC_ENABLE_NAV_HOVER_LINE ARG PUBLIC_ASSET_VERSION ENV PUBLIC_ASSET_VERSION=$PUBLIC_ASSET_VERSION diff --git a/docker-compose.yml b/docker-compose.yml index 134c9bf..9dece0e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,6 +7,7 @@ services: args: # Build-time toggle for service worker registration in the generated static HTML. PUBLIC_ENABLE_SW: ${PUBLIC_ENABLE_SW:-true} + PUBLIC_ENABLE_NAV_HOVER_LINE: ${PUBLIC_ENABLE_NAV_HOVER_LINE:-true} PUBLIC_ASSET_VERSION: ${PUBLIC_ASSET_VERSION:-} # Public, build-time config baked into the HTML. PUBLIC_SITE_URL: ${PUBLIC_SITE_URL:-} diff --git a/header-desktop-1366x768.png b/header-desktop-1366x768.png new file mode 100644 index 0000000..6f7f9a8 Binary files /dev/null and b/header-desktop-1366x768.png differ diff --git a/header-hover-effect-desktop.png b/header-hover-effect-desktop.png new file mode 100644 index 0000000..bbd26bd Binary files /dev/null and b/header-hover-effect-desktop.png differ diff --git a/header-hover-videos.png b/header-hover-videos.png new file mode 100644 index 0000000..bbd26bd Binary files /dev/null and b/header-hover-videos.png differ diff --git a/header-mobile-390x844.png b/header-mobile-390x844.png new file mode 100644 index 0000000..7597bde Binary files /dev/null and b/header-mobile-390x844.png differ diff --git a/openspec/changes/archive/2026-02-11-final-touches/.openspec.yaml b/openspec/changes/archive/2026-02-11-final-touches/.openspec.yaml new file mode 100644 index 0000000..4465244 --- /dev/null +++ b/openspec/changes/archive/2026-02-11-final-touches/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-02-11 diff --git a/openspec/changes/archive/2026-02-11-final-touches/design.md b/openspec/changes/archive/2026-02-11-final-touches/design.md new file mode 100644 index 0000000..03b28e8 --- /dev/null +++ b/openspec/changes/archive/2026-02-11-final-touches/design.md @@ -0,0 +1,82 @@ +## Context + +The primary header navigation is currently laid out as a simple left brand + right nav flex row. This makes the header feel left-heavy and de-emphasizes the brand. The site already uses a cohesive visual system (tokenized colors, glow accents, motion preferences) and has existing accessibility constraints (focus-visible, reduced motion). + +Relevant implementation notes: + +- Header markup is in `site/src/layouts/BaseLayout.astro`. +- Styling is in `site/src/styles/global.css`. +- Public feature flags are expressed via `PUBLIC_*` env vars and commonly use an opt-out string comparison (`!== "false"`) similar to `PUBLIC_ENABLE_SW`. + +This change is purely UI-level: layout and hover presentation. No routing, data, or backend behavior changes are required. + +## Goals / Non-Goals + +**Goals:** + +- Add a left-side logo in the header using the same asset as the favicon, sized appropriately and aligned with the header rhythm. +- Center the site brand label ("SanthoshJ") in the primary header layout without breaking the mobile hamburger behavior. +- Introduce a novel animated hover-line treatment that appears only on hover: + - primary header title links (brand + Videos, Podcast, Blog) + - section/module titles for Videos, Podcast, Blog (titles only) +- Gate the hover-line treatment behind a public env flag so it can be turned off to preserve the current behavior. +- Preserve accessibility: + - no layout shift due to hover effects + - keyboard focus remains visible and not confused with hover-only affordances + - reduced motion mode substantially reduces/disables the animation + +**Non-Goals:** + +- Redesigning the overall header/nav visual language beyond layout + hover line. +- Changing navigation destinations, labels, or analytics tracking attributes. +- Introducing new font families or major typography changes. +- Adding new build dependencies. + +## Decisions + +### 1) Header layout strategy: CSS Grid for centering + +Decision: implement the header container as a 3-column grid (`left / center / right`) and place: + +- left: logo link +- center: brand text link +- right: nav links (desktop) and hamburger toggle (mobile) + +Rationale: grid makes true center alignment robust even when left/right columns have different widths, and avoids brittle absolute positioning. + +Alternative: flex with spacer elements. Rejected due to center drift as content changes. + +### 2) Logo asset and sizing + +Decision: reuse `site/public/favicon.png` as the logo source initially, styled to a fixed square size with pixel-snapped rendering. + +Rationale: avoids introducing new assets. If needed later, replace with a dedicated logo asset (same path/size contract). + +### 3) Hover-line implementation: pseudo-element with no layout impact + +Decision: implement the hover line using `::after` (or `background-size`) so it does not affect layout metrics. + +- visible only on `:hover` +- reduced motion: animation disabled/reduced +- focus-visible: keep existing focus ring; optionally show a static line for focus (not animated) + +Rationale: avoids CLS and keeps the effect decorative. + +### 4) Feature flag: public opt-out env var + +Decision: add `PUBLIC_ENABLE_NAV_HOVER_LINE` (string) and treat `"false"` as disabled; all other values (including undefined) keep current behavior. + +Rationale: matches existing public env patterns and ensures default behavior remains unchanged. + +### 5) Scope of "titles" + +Decision: apply the hover-line to primary header title links (center brand + Videos/Podcast/Blog nav) and to explicit title elements for the three primary content surfaces (Videos, Podcast, Blog) where they are presented as headings; avoid applying to card titles and other headings. + +Rationale: keeps the effect intentional and avoids visual noise. + +## Risks / Trade-offs + +- [Mobile header regressions] Grid changes could break the hamburger layout → Mitigation: keep mobile nav toggle and panel behavior unchanged; add targeted CSS at the existing breakpoint. +- [Accessibility confusion] Hover-only affordance might be mistaken for focus indicator → Mitigation: do not remove focus-visible styles; keep hover line hover-only and optionally static on focus. +- [Theme contrast] Line color may be low-contrast in some themes → Mitigation: use existing accent tokens and test across dark/light/high-contrast. +- [Over-application] Accidentally applying effect to card titles → Mitigation: apply only to selectors scoped to nav links + specific page/module title classes. diff --git a/openspec/changes/archive/2026-02-11-final-touches/proposal.md b/openspec/changes/archive/2026-02-11-final-touches/proposal.md new file mode 100644 index 0000000..98962ef --- /dev/null +++ b/openspec/changes/archive/2026-02-11-final-touches/proposal.md @@ -0,0 +1,33 @@ +## Why + +The site header can feel visually left-weighted. A tighter, more intentional navbar layout and hover treatment will improve polish and brand presentation. + +## What Changes + +- Move the site branding text "SanthoshJ" to the center of the navbar (desktop and mobile-safe). +- Add a left-side logo using the existing favicon asset, sized appropriately for the header. +- Add a novel/creative animated hover line treatment that appears only on hover: + - primary header title links: brand + Videos, Podcast, Blog + - section/module titles for Videos, Podcast, Blog (titles only) +- Add a public env flag to enable/disable the hover line effect: + - default behavior remains unchanged unless explicitly enabled/disabled + - when disabled, revert to current hover behavior +- Ensure all the above changes are WCAG compliant. + +## Capabilities + +### New Capabilities + +- `navbar-branding`: Add a left logo and centered brand layout in the primary header. +- `nav-hover-line`: Provide an animated hover-line treatment for primary header title links and key section titles, gated by a public env flag. + +### Modified Capabilities + +- (none) + +## Impact + +- `site/src/layouts/BaseLayout.astro` (header markup: logo placement, centered brand, nav link structure) +- `site/src/styles/global.css` (navbar layout + hover line animation styles) +- `site/public/favicon.*` (reuse as navbar logo asset) +- `site/src/env.d.ts` + `site/src/lib/config.ts` (new `PUBLIC_*` env flag wiring) diff --git a/openspec/changes/archive/2026-02-11-final-touches/specs/nav-hover-line/spec.md b/openspec/changes/archive/2026-02-11-final-touches/specs/nav-hover-line/spec.md new file mode 100644 index 0000000..1b2009a --- /dev/null +++ b/openspec/changes/archive/2026-02-11-final-touches/specs/nav-hover-line/spec.md @@ -0,0 +1,47 @@ +## ADDED Requirements + +### Requirement: Hover line appears only on hover for primary header titles +The site MUST render a decorative animated line that appears only on hover for the primary header title links: + +- SanthoshJ (center brand link) + +- Videos +- Podcast +- Blog + +The hover line MUST NOT cause layout shift. + +#### Scenario: Hover line is hidden by default +- **WHEN** the header renders +- **THEN** the hover line is not visible on primary header title links until hover + +#### Scenario: Hover line appears on hover +- **WHEN** a pointer user hovers a primary header title link +- **THEN** an animated line appears as a hover affordance for that title + +### Requirement: Hover line applies to section/module titles for key surfaces +The site MUST apply the same hover-line treatment to the titles for the Videos, Podcast, and Blog surfaces, but only on titles (not on card titles). + +#### Scenario: Titles use hover line +- **WHEN** a pointer user hovers the Videos/Podcast/Blog surface title element +- **THEN** the hover line appears only for that title + +#### Scenario: Card titles are unaffected +- **WHEN** a pointer user hovers a content card title +- **THEN** no hover line effect is applied (existing behavior remains) + +### Requirement: Hover line is gated by a public env flag +The hover-line effect MUST be controllable via a public environment variable `PUBLIC_ENABLE_NAV_HOVER_LINE`. + +If `PUBLIC_ENABLE_NAV_HOVER_LINE` is set to the string `"false"`, the hover-line effect MUST be disabled and the current behavior MUST continue. + +#### Scenario: Flag disables hover line +- **WHEN** `PUBLIC_ENABLE_NAV_HOVER_LINE` is set to `"false"` +- **THEN** hovering primary header title links and surface titles does not render the hover line effect + +### Requirement: Reduced motion disables or substantially reduces animation +If `prefers-reduced-motion: reduce` is set, the hover-line animation MUST be disabled or substantially reduced. + +#### Scenario: Reduced motion disables noticeable hover animation +- **WHEN** `prefers-reduced-motion: reduce` is set and a user hovers a nav title +- **THEN** the hover line does not animate noticeably diff --git a/openspec/changes/archive/2026-02-11-final-touches/specs/navbar-branding/spec.md b/openspec/changes/archive/2026-02-11-final-touches/specs/navbar-branding/spec.md new file mode 100644 index 0000000..a5d69d5 --- /dev/null +++ b/openspec/changes/archive/2026-02-11-final-touches/specs/navbar-branding/spec.md @@ -0,0 +1,25 @@ +## ADDED Requirements + +### Requirement: Primary header shows logo and centered brand +The site MUST render a primary header that includes: + +- a left-side logo that links to `/` +- a centered brand label "SanthoshJ" that links to `/` +- the primary navigation links (Videos, Podcast, Blog) + +The logo MUST use the same visual asset as the site favicon. + +#### Scenario: Desktop header layout +- **WHEN** a user loads the home page on a desktop viewport +- **THEN** the header shows the logo on the left, the brand label centered, and the nav links on the right + +#### Scenario: Mobile header layout +- **WHEN** a user loads the home page on a mobile viewport +- **THEN** the header still shows the logo on the left and the brand label centered without overlapping the nav toggle + +### Requirement: Logo size is visually aligned +The header logo MUST be sized to match the header rhythm and MUST not cause layout shift. + +#### Scenario: Logo has fixed dimensions +- **WHEN** the header renders +- **THEN** the logo element has explicit width and height and does not change size on load diff --git a/openspec/changes/archive/2026-02-11-final-touches/tasks.md b/openspec/changes/archive/2026-02-11-final-touches/tasks.md new file mode 100644 index 0000000..dbd98e5 --- /dev/null +++ b/openspec/changes/archive/2026-02-11-final-touches/tasks.md @@ -0,0 +1,20 @@ +## 1. Header Branding Layout + +- [x] 1.1 Update `site/src/layouts/BaseLayout.astro` header markup to add a left logo link (favicon asset) and move "SanthoshJ" brand link to the center +- [x] 1.2 Update `site/src/styles/global.css` header layout to center brand text robustly (grid-based layout) while preserving mobile hamburger behavior +- [x] 1.3 Ensure logo has correct sizing and explicit dimensions (no layout shift) + +## 2. Hover Line Effect (Gated) + +- [x] 2.1 Add `PUBLIC_ENABLE_NAV_HOVER_LINE` to `site/src/env.d.ts` +- [x] 2.2 Add config wiring in `site/src/lib/config.ts` (or direct `import.meta.env` usage) with opt-out semantics (`"false"` disables) +- [x] 2.3 Implement hover-line CSS for primary header title links (brand + Videos/Podcast/Blog), hover-only, no layout shift +- [x] 2.4 Implement hover-line CSS for the Videos/Podcast/Blog surface title elements only (not card titles) +- [x] 2.5 Add reduced-motion handling so the effect is disabled/substantially reduced under `prefers-reduced-motion: reduce` +- [x] 2.6 Ensure focus-visible styles remain clear and are not replaced by hover-only affordances + +## 3. Verification + +- [x] 3.1 Verify layout on desktop + mobile widths (no overlap with nav toggle) +- [x] 3.2 Verify hover-line is enabled by default and fully disabled when `PUBLIC_ENABLE_NAV_HOVER_LINE="false"` +- [x] 3.3 Run `npm -C site run build` and ensure no new typecheck regressions diff --git a/openspec/specs/nav-hover-line/spec.md b/openspec/specs/nav-hover-line/spec.md new file mode 100644 index 0000000..78f4995 --- /dev/null +++ b/openspec/specs/nav-hover-line/spec.md @@ -0,0 +1,51 @@ +# nav-hover-line Specification + +## Purpose +TBD - created by archiving change final-touches. Update Purpose after archive. +## Requirements +### Requirement: Hover line appears only on hover for primary header titles +The site MUST render a decorative animated line that appears only on hover for the primary header title links: + +- SanthoshJ (center brand link) + +- Videos +- Podcast +- Blog + +The hover line MUST NOT cause layout shift. + +#### Scenario: Hover line is hidden by default +- **WHEN** the header renders +- **THEN** the hover line is not visible on primary header title links until hover + +#### Scenario: Hover line appears on hover +- **WHEN** a pointer user hovers a primary header title link +- **THEN** an animated line appears as a hover affordance for that title + +### Requirement: Hover line applies to section/module titles for key surfaces +The site MUST apply the same hover-line treatment to the titles for the Videos, Podcast, and Blog surfaces, but only on titles (not on card titles). + +#### Scenario: Titles use hover line +- **WHEN** a pointer user hovers the Videos/Podcast/Blog surface title element +- **THEN** the hover line appears only for that title + +#### Scenario: Card titles are unaffected +- **WHEN** a pointer user hovers a content card title +- **THEN** no hover line effect is applied (existing behavior remains) + +### Requirement: Hover line is gated by a public env flag +The hover-line effect MUST be controllable via a public environment variable `PUBLIC_ENABLE_NAV_HOVER_LINE`. + +If `PUBLIC_ENABLE_NAV_HOVER_LINE` is set to the string `"false"`, the hover-line effect MUST be disabled and the current behavior MUST continue. + +#### Scenario: Flag disables hover line +- **WHEN** `PUBLIC_ENABLE_NAV_HOVER_LINE` is set to `"false"` +- **THEN** hovering primary header title links and surface titles does not render the hover line effect + +### Requirement: Reduced motion disables or substantially reduces animation +If `prefers-reduced-motion: reduce` is set, the hover-line animation MUST be disabled or substantially reduced. + +#### Scenario: Reduced motion disables noticeable hover animation +- **WHEN** `prefers-reduced-motion: reduce` is set and a user hovers a nav title +- **THEN** the hover line does not animate noticeably + diff --git a/openspec/specs/navbar-branding/spec.md b/openspec/specs/navbar-branding/spec.md new file mode 100644 index 0000000..34111e9 --- /dev/null +++ b/openspec/specs/navbar-branding/spec.md @@ -0,0 +1,29 @@ +# navbar-branding Specification + +## Purpose +TBD - created by archiving change final-touches. Update Purpose after archive. +## Requirements +### Requirement: Primary header shows logo and centered brand +The site MUST render a primary header that includes: + +- a left-side logo that links to `/` +- a centered brand label "SanthoshJ" that links to `/` +- the primary navigation links (Videos, Podcast, Blog) + +The logo MUST use the same visual asset as the site favicon. + +#### Scenario: Desktop header layout +- **WHEN** a user loads the home page on a desktop viewport +- **THEN** the header shows the logo on the left, the brand label centered, and the nav links on the right + +#### Scenario: Mobile header layout +- **WHEN** a user loads the home page on a mobile viewport +- **THEN** the header still shows the logo on the left and the brand label centered without overlapping the nav toggle + +### Requirement: Logo size is visually aligned +The header logo MUST be sized to match the header rhythm and MUST not cause layout shift. + +#### Scenario: Logo has fixed dimensions +- **WHEN** the header renders +- **THEN** the logo element has explicit width and height and does not change size on load + diff --git a/site/.env.example b/site/.env.example index c926fb3..e89eb51 100644 --- a/site/.env.example +++ b/site/.env.example @@ -10,6 +10,10 @@ PUBLIC_UMAMI_WEBSITE_ID=00000000-0000-0000-0000-000000000000 # - In `npm run build`/`preview`, SW is registered only if this is "true". PUBLIC_ENABLE_SW=true +# Nav/title hover-line effect toggle (public, build-time). +# Set to "false" to disable the decorative hover-line treatment. +PUBLIC_ENABLE_NAV_HOVER_LINE=true + # Content ingestion configuration (used by scripts) YOUTUBE_CHANNEL_ID=UCxxxxxxxxxxxxxxxxxxxxxx YOUTUBE_API_KEY= diff --git a/site/src/env.d.ts b/site/src/env.d.ts index 08d9b7c..4533687 100644 --- a/site/src/env.d.ts +++ b/site/src/env.d.ts @@ -6,6 +6,7 @@ interface ImportMetaEnv { readonly PUBLIC_UMAMI_WEBSITE_ID?: string; readonly PUBLIC_ENABLE_SW?: string; readonly PUBLIC_ASSET_VERSION?: string; + readonly PUBLIC_ENABLE_NAV_HOVER_LINE?: string; } interface ImportMeta { diff --git a/site/src/layouts/BaseLayout.astro b/site/src/layouts/BaseLayout.astro index ee85185..3cd5c13 100644 --- a/site/src/layouts/BaseLayout.astro +++ b/site/src/layouts/BaseLayout.astro @@ -16,6 +16,7 @@ const siteUrl = (cfg.siteUrl || "http://localhost:4321").replace(/\/$/, ""); const canonicalUrl = `${siteUrl}${canonicalPath.startsWith("/") ? canonicalPath : `/${canonicalPath}`}`; const assetSuffix = cfg.assetVersion ? `?v=${encodeURIComponent(cfg.assetVersion)}` : ""; +const bodyClass = cfg.enableNavHoverLine ? "nav-hover-line-enabled" : ""; --- @@ -131,11 +132,22 @@ const assetSuffix = cfg.assetVersion ? `?v=${encodeURIComponent(cfg.assetVersion ) : null } - +