v7.15.2 — footer Facebook page link + theme switch moved to Settings
The project's Facebook page (facebook.com/openvisengine) is now linked from the footer's right-hand group beside the version stamp — icon-only (lucide Facebook glyph), opens in a new tab, same hover/focus treatment as the portfolio link. The light/dark tick switch moved out of the header into the Settings tab's Appearance section as a 'Light / dark mode' row above the base-theme cards — identical mechanics (checked = white theme, unchecked = the visitor's stored dark base, both persist, mount-guarded SSR). Header is one control lighter; every appearance control now lives in one place. Verified in-browser: link attrs + icon, toggle absent from header, flip round trips (outline -> light -> outline, and purple -> light -> purple proving the stored-base tracking), What's New shows 7.15.2, sticky footer + no overflow at 1280/375, console clean.
This commit is contained in:
parent
b08490e80e
commit
4d5fba3977
6 changed files with 138 additions and 46 deletions
|
|
@ -2,6 +2,10 @@
|
|||
// stamp. (v7.10: the engine-health dot is gone -- compile errors already
|
||||
// toast, so the always-green "engine ok" badge was pure noise.)
|
||||
//
|
||||
// v7.15.2: the right-hand group carries the project's Facebook page link
|
||||
// (facebook.com/openvisengine) beside the version stamp -- icon-only, opens
|
||||
// in a new tab; the project identity corner.
|
||||
//
|
||||
// v7.9 credit block: "© {year} · Site Created & Deployed by Sum'ting White" +
|
||||
// a "View my portfolio at zcreations.dev" link, centered in the footer's
|
||||
// blank area. Flex choreography: from xl the credit sits INLINE between the
|
||||
|
|
@ -14,6 +18,7 @@
|
|||
|
||||
'use client'
|
||||
|
||||
import { Facebook } from 'lucide-react'
|
||||
import { useAvaStore } from '@/lib/store'
|
||||
import { APP_NAME, APP_VERSION } from '@/lib/version'
|
||||
|
||||
|
|
@ -76,8 +81,19 @@ export function FooterBar() {
|
|||
</a>
|
||||
</div>
|
||||
|
||||
{/* version stamp (v7.10: the engine-health dot beside it is gone) */}
|
||||
{/* version stamp (v7.10: the engine-health dot beside it is gone) +
|
||||
the project's Facebook page (v7.15.2) */}
|
||||
<div className="ml-auto flex shrink-0 items-center gap-3 sm:gap-4 xl:ml-0">
|
||||
<a
|
||||
href="https://www.facebook.com/openvisengine/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="OVE on Facebook (opens in a new tab)"
|
||||
title="OVE on Facebook -- facebook.com/openvisengine"
|
||||
className="inline-flex size-6 items-center justify-center rounded-xs text-zinc-500 transition-colors hover:bg-zinc-800 hover:text-emerald-300 focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
>
|
||||
<Facebook className="size-3.5" aria-hidden />
|
||||
</a>
|
||||
<span
|
||||
className="text-zinc-600"
|
||||
title={`${APP_NAME} -- version ${APP_VERSION}`}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,18 @@
|
|||
// OVE — sticky app header: logo, audio source controls (segmented), the
|
||||
// demo-track chip, What's New!, theme tick switch, BPM readout and the beat
|
||||
// indicator. (v7.6.1: the Set Beat button moved out — tap-tempo lives in the
|
||||
// Beat tab, and Space works anywhere.)
|
||||
// demo-track chip, What's New!, BPM readout and the beat indicator.
|
||||
// (v7.6.1: the Set Beat button moved out — tap-tempo lives in the Beat tab,
|
||||
// and Space works anywhere. v7.15.2: the light/dark tick switch moved out
|
||||
// too — it lives in the Settings tab's Appearance section now.)
|
||||
|
||||
'use client'
|
||||
|
||||
import { useRef, useSyncExternalStore } from 'react'
|
||||
import { AudioWaveform, Disc3, FileAudio, Link2, Mic, Moon, Music2, Square, Sun } from 'lucide-react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { useRef } from 'react'
|
||||
import { AudioWaveform, Disc3, FileAudio, Link2, Mic, Music2, Square } from 'lucide-react'
|
||||
import { BeatDot } from '@/components/ava/beat-dot'
|
||||
import { LinkDialog } from '@/components/ava/link-dialog'
|
||||
import { WhatsNew } from '@/components/ava/whats-new-dialog'
|
||||
import { useAudioSource } from '@/components/ava/audio-source'
|
||||
import { useAvaStore } from '@/lib/store'
|
||||
import { getStoredDarkBase } from '@/lib/theme'
|
||||
import { APP_NAME, APP_SHORT } from '@/lib/version'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
|
|
@ -142,35 +140,10 @@ function BpmReadout() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Light-switch tick: left position (unchecked) keeps the dark theme, flipping
|
||||
* right (checked) switches the page to the white theme. The dark side is
|
||||
* whichever dark base the visitor picked on the Settings tab (royal purple
|
||||
* by default); both choices persist per visitor. The useSyncExternalStore
|
||||
* mount guard returns false on the server / first client render and true
|
||||
* after hydration, so the checkbox never causes a hydration mismatch.
|
||||
* v7.15.2: the ThemeToggle (Moon/Sun tick switch) moved to the Settings
|
||||
* tab's Appearance section — see settings-tab.tsx. Same mechanics exactly
|
||||
* (flipping to dark returns to the visitor's stored dark base).
|
||||
*/
|
||||
const emptySubscribe = () => () => {}
|
||||
function ThemeToggle() {
|
||||
const { resolvedTheme, setTheme } = useTheme()
|
||||
const mounted = useSyncExternalStore(emptySubscribe, () => true, () => false)
|
||||
const isLight = mounted && resolvedTheme === 'light'
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex h-11 items-center gap-1.5 rounded-lg border border-zinc-800 bg-zinc-900/60 px-2.5"
|
||||
title={isLight ? 'Theme: light -- flip left for dark' : 'Theme: dark -- flip right for light'}
|
||||
>
|
||||
<Moon className="size-3.5 shrink-0 text-zinc-500" aria-hidden />
|
||||
<Switch
|
||||
checked={isLight}
|
||||
onCheckedChange={(v) => setTheme(v ? 'light' : getStoredDarkBase())}
|
||||
aria-label={isLight ? 'Switch to dark theme' : 'Switch to light theme'}
|
||||
className="data-[state=checked]:bg-emerald-400 data-[state=unchecked]:bg-zinc-600"
|
||||
/>
|
||||
<Sun className="size-3.5 shrink-0 text-zinc-500" aria-hidden />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function AppHeader() {
|
||||
return (
|
||||
|
|
@ -194,10 +167,10 @@ export function AppHeader() {
|
|||
<SourceControls />
|
||||
</div>
|
||||
|
||||
{/* what's new + theme switch + BPM readout + beat indicator -- always visible */}
|
||||
{/* what's new + BPM readout + beat indicator -- always visible
|
||||
(v7.15.2: the theme tick switch moved to the Settings tab) */}
|
||||
<div className="order-2 ml-auto flex items-center gap-2.5 md:order-3 sm:gap-3">
|
||||
<WhatsNew />
|
||||
<ThemeToggle />
|
||||
<BpmReadout />
|
||||
<BeatDot size={44} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
// OVE — Settings tab (v6.5): appearance controls — base theme + highlight
|
||||
// color pickers. Everything is per-visitor (localStorage only, nothing on
|
||||
// the server) and applies instantly. The Native tab that previously lived
|
||||
// in this slot is parked (see control-panel.tsx) and returns unchanged
|
||||
// when the project nears completion.
|
||||
// OVE — Settings tab (v6.5): appearance controls — light/dark flip (v7.15.2,
|
||||
// moved here from the header), base theme + highlight color pickers.
|
||||
// Everything is per-visitor (localStorage only, nothing on the server) and
|
||||
// applies instantly. The Native tab that previously lived in this slot is
|
||||
// parked (see control-panel.tsx) and returns unchanged when the project
|
||||
// nears completion.
|
||||
//
|
||||
// v7.7: the Music Services log in / "log out of all" section is PARKED
|
||||
// (MUSIC_SERVICES_UI below). Stream-a-Link already plays for everyone
|
||||
|
|
@ -14,10 +15,11 @@
|
|||
'use client'
|
||||
|
||||
import { useSyncExternalStore, useState, useEffect } from 'react'
|
||||
import { Check, LogIn, LogOut, Music4, Palette, RotateCcw } from 'lucide-react'
|
||||
import { Check, LogIn, LogOut, Moon, Music4, Palette, RotateCcw, Sun } from 'lucide-react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { ServiceLoginDialog } from '@/components/ava/service-login-dialog'
|
||||
import { SERVICES, type ServiceId } from '@/lib/music-services'
|
||||
import {
|
||||
|
|
@ -31,6 +33,7 @@ import {
|
|||
DEFAULT_BASE,
|
||||
THEME_BASES,
|
||||
applyAccent,
|
||||
getStoredDarkBase,
|
||||
isAccentId,
|
||||
storeDarkBase,
|
||||
type AccentId,
|
||||
|
|
@ -89,6 +92,14 @@ export function SettingsTab() {
|
|||
if (id === 'outline' && accent !== 'blue') applyAccent('blue')
|
||||
}
|
||||
|
||||
/** v7.15.2 — the header tick switch's flip, verbatim: checking = the white
|
||||
* theme; unchecking returns to the visitor's stored dark base (kept fresh
|
||||
* by pickBase below). The mount guard lives in `isLight`, so the SSR
|
||||
* render shows the unchecked position without a hydration mismatch. */
|
||||
function flipLight(v: boolean) {
|
||||
setTheme(v ? 'light' : getStoredDarkBase())
|
||||
}
|
||||
|
||||
function pickAccent(id: AccentId) {
|
||||
applyAccent(id)
|
||||
}
|
||||
|
|
@ -157,6 +168,38 @@ export function SettingsTab() {
|
|||
|
||||
<Separator />
|
||||
|
||||
{/* v7.15.2 — the light/dark tick switch, moved from the header. First
|
||||
control in Appearance: the quick flip. The base cards below remain
|
||||
the full palette choice; this row only toggles between the white
|
||||
theme and whichever dark base the visitor picked (default outline). */}
|
||||
<section aria-label="Light and dark mode">
|
||||
<h4 className="text-xs font-semibold uppercase tracking-[0.14em] text-zinc-500">Light / dark mode</h4>
|
||||
<div className="mt-3 flex items-center justify-between gap-4 rounded-xl border border-zinc-800 bg-zinc-900/40 px-4 py-3">
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-semibold">
|
||||
{mounted ? (isLight ? 'Light theme' : 'Dark theme') : 'Theme'}
|
||||
</p>
|
||||
<p className="mt-0.5 text-[11px] leading-snug text-zinc-500">
|
||||
Quick flip between the white theme and the dark side — flipping back to dark returns
|
||||
to the base picked below (or the last one used).
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className="flex shrink-0 items-center gap-2"
|
||||
title={isLight ? 'Theme: light -- flip left for dark' : 'Theme: dark -- flip right for light'}
|
||||
>
|
||||
<Moon className="size-4 shrink-0 text-zinc-500" aria-hidden />
|
||||
<Switch
|
||||
checked={isLight}
|
||||
onCheckedChange={flipLight}
|
||||
aria-label={isLight ? 'Switch to dark theme' : 'Switch to light theme'}
|
||||
className="data-[state=checked]:bg-emerald-400 data-[state=unchecked]:bg-zinc-600"
|
||||
/>
|
||||
<Sun className="size-4 shrink-0 text-zinc-500" aria-hidden />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section aria-label="Base theme">
|
||||
<h4 className="text-xs font-semibold uppercase tracking-[0.14em] text-zinc-500">Base theme</h4>
|
||||
<div className="mt-3 grid grid-cols-1 gap-3 sm:grid-cols-2">
|
||||
|
|
|
|||
|
|
@ -39,6 +39,20 @@ export interface ReleaseNote {
|
|||
}
|
||||
|
||||
export const RELEASE_NOTES: ReleaseNote[] = [
|
||||
{
|
||||
version: '7.15.2',
|
||||
name: 'Facebook page + theme switch in Settings',
|
||||
changes: [
|
||||
{
|
||||
kind: 'added',
|
||||
text: "OVE has a Facebook page now -- the footer carries the link (the Facebook icon beside the version stamp), so that is where news and showcase clips will land.",
|
||||
},
|
||||
{
|
||||
kind: 'improved',
|
||||
text: 'The light/dark tick switch moved from the header to the Settings tab, as the first row of the Appearance section -- every look-and-feel control now lives in one place. It flips exactly as before: back to dark it returns to the base picked below it, and both choices persist.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
version: '7.15.1',
|
||||
name: 'Silence holds the beat grid',
|
||||
|
|
|
|||
|
|
@ -12,6 +12,22 @@
|
|||
// warns in the console when the two drift apart.
|
||||
//
|
||||
// History:
|
||||
// 7.15.2 — Facebook page + theme switch relocation (user request): the
|
||||
// project now has its own Facebook page, and the footer's
|
||||
// right-hand group carries the link (facebook.com/openvisengine)
|
||||
// beside the version stamp -- an icon-only button (lucide
|
||||
// Facebook glyph) that opens in a new tab, same hover/focus
|
||||
// treatment as the portfolio link. The light/dark tick switch
|
||||
// (v6.3) moved out of the header into the Settings tab's
|
||||
// Appearance section, as a "Light / dark mode" row ABOVE the
|
||||
// base-theme cards -- the header is one control lighter and all
|
||||
// appearance controls now live in one place. Mechanics are
|
||||
// identical: checking = the white theme, unchecking returns to
|
||||
// the visitor's stored dark base (kept fresh by the base cards),
|
||||
// both choices persist per visitor, and the mount guard keeps
|
||||
// the SSR render mismatch-free. The row states the current side
|
||||
// ("Light theme" / "Dark theme") and explains the return-to-base
|
||||
// behavior in its caption.
|
||||
// 7.15.1 — the silence hold (user request): "if silence is detected,
|
||||
// it needs to place an immediate override and hold on the beat
|
||||
// detection / prediction ... if silence is no longer detected,
|
||||
|
|
@ -532,4 +548,4 @@
|
|||
|
||||
export const APP_NAME = 'Open Visualization Engine'
|
||||
export const APP_SHORT = 'OVE'
|
||||
export const APP_VERSION = '7.15.1'
|
||||
export const APP_VERSION = '7.15.2'
|
||||
|
|
|
|||
30
worklog.md
30
worklog.md
|
|
@ -2500,3 +2500,33 @@ BROWSER E2E (agent-browser, ALL PASS; probe track = generated 13 s WAV, 8 s of 1
|
|||
|
||||
Stage Summary:
|
||||
- v7.15.1 shipped: silence places an immediate HOLD on beat detection + prediction (level < 0.006 for 300 ms; sticky until 0.015) -- nothing fires, learning/confidence/beatphase freeze; decisive audio releases instantly and the grid resumes from the phase the audio went quiet (pause/resume keeps perfect time); taps override; waveform/band data never gated; scripts get silent; the indicator shows HOLD. Headless 26/26 + browser E2E green; pushed to zai-dev.
|
||||
|
||||
---
|
||||
Task ID: 45
|
||||
Agent: main (Z.ai Code)
|
||||
Task: v7.15.2 (user request): "So I created a facebook page just for this project that I would like to add to the footer, it is 'https://www.facebook.com/openvisengine/'. Also the light/dark theme switch needs to be moved to the 'Settings' tab." Delivered on the zai-dev staging branch (remote: gitzcreations/openvisengine).
|
||||
|
||||
Approach:
|
||||
- The Facebook link belongs with the PROJECT identity, not the maker credit block (that corner is the site creator's) -- so it went into the footer's right-hand group beside the version stamp: icon-only (lucide Facebook glyph, size-3.5 in a size-6 hit area), target=_blank + rel=noopener noreferrer, aria-label + title for a11y, same hover/focus treatment as the portfolio link (zinc-500 -> emerald-300, focus-visible ring).
|
||||
- The theme tick switch (v6.3 header resident) is a stateless control whose logic (flip to light / flip back to the STORED dark base) lives entirely in setTheme + getStoredDarkBase() -- so moving it is pure relocation. New home: the Settings tab's Appearance section, as a "Light / dark mode" row ABOVE the base-theme cards (the quick flip first, the full palette choice below), in a bordered card that states the current side ("Light theme" / "Dark theme") and explains the return-to-base behavior in its caption. Mechanics are byte-identical: checked = 'light', unchecked = getStoredDarkBase(); the existing mounted/isLight guard keeps the SSR render mismatch-free.
|
||||
- pickBase() already refreshes the stored dark base on every dark card pick, so the switch's return target always tracks the visitor's latest dark choice -- verified with a purple -> light -> dark round trip.
|
||||
|
||||
Work Log:
|
||||
- footer-bar.tsx: Facebook icon link in the right group (v7.15.2 comment block; Facebook import from lucide-react).
|
||||
- header.tsx: ThemeToggle component + its now-unused imports removed (useSyncExternalStore, Moon/Sun, useTheme, Switch, getStoredDarkBase); file header + right-group comments updated (v7.15.2 note pointing at settings-tab.tsx); the header right group is now What's New! + BPM readout + beat indicator.
|
||||
- settings-tab.tsx: "Light / dark mode" section (first in Appearance) with the Moon/Sun tick switch; flipLight() = the header toggle's onCheckedChange verbatim; Moon, Sun, Switch, getStoredDarkBase imports; file header comment updated.
|
||||
- version.ts: APP_VERSION 7.15.2 + history entry. release-notes.ts: 7.15.2 "Facebook page + theme switch in Settings" (1 added + 1 improved, first-person voice, no em dashes).
|
||||
|
||||
BROWSER E2E (agent-browser, ALL PASS):
|
||||
- Fresh load: title "OVE -- Open Visualization Engine (v7.15.2)"; footer shows "version 7.15.2".
|
||||
- Footer link: present in <footer>, href https://www.facebook.com/openvisengine/, target=_blank, rel=noopener noreferrer, aria-label "OVE on Facebook (opens in a new tab)", title set, lucide-facebook icon rendered, in the same group as the version stamp; visible at 1280 and 375 widths.
|
||||
- Header: no [role=switch], zero lucide-moon/lucide-sun icons (the toggle is gone); header right group = What's New! + BPM + beat dot.
|
||||
- Settings tab: section[aria-label="Light and dark mode"] first in Appearance, heading "Light / dark mode", status "Dark theme", caption present, switch unchecked with aria-label "Switch to light theme", Moon+Sun icons, Base theme section follows.
|
||||
- Flip test: click -> html.light + "Light theme" + aria "Switch to dark theme"; click again -> html.outline (the stored dark base restored, not just any dark) + "Dark theme".
|
||||
- Stored-base tracking: pick Royal Purple card -> html.purple; flip light -> light; flip back -> html.purple (the round trip returns to the NEWLY stored base, proving pickBase/storeDarkBase feeds the switch). Default look (outline + blue accent) restored afterwards.
|
||||
- What's New: dialog opens with 7.15.2 first ("Facebook page + theme switch in Settings", both items present).
|
||||
- Responsive: 1280x800 footer sticks to the viewport bottom (docH 800 = innerH 800); 375x812 no horizontal overflow (scrollW 375 = clientW), footer flush at the document bottom (footerBottomDoc 1301.26 ~= docH 1301 -- pushed naturally, header sticky).
|
||||
- Console: 0 errors / 0 warnings. Test browser closed.
|
||||
|
||||
Stage Summary:
|
||||
- v7.15.2 shipped: the footer's right-hand group carries the project's Facebook page link (facebook.com/openvisengine, icon-only, new tab) beside the version stamp; the light/dark tick switch moved from the header to the Settings tab's Appearance section (first row, above the base-theme cards) with identical mechanics -- checked = white theme, unchecked = the visitor's stored dark base, both persist. Browser E2E green across link, relocation, flip behavior, stored-base tracking, What's New, responsiveness and the sticky footer.
|
||||
|
|
|
|||
Loading…
Reference in a new issue