refactor(vibe): make profile aura ambient
This commit is contained in:
@@ -17,8 +17,8 @@ function describeProfile(energy: number, novelty: number) {
|
||||
return { energyLabel, discoveryLabel };
|
||||
}
|
||||
|
||||
/** A small, ambient representation of the live recommendation profile. */
|
||||
export function VibeAura({ profile }: { profile: VibeProfile }) {
|
||||
/** An ambient representation of the live recommendation profile. */
|
||||
export function VibeAura({ profile, ambient = false }: { profile: VibeProfile; ambient?: boolean }) {
|
||||
const energy = clamp(profile.energy, 0.5);
|
||||
const novelty = clamp(profile.noveltyHunger ?? profile.explorationCoefficient, 0.3);
|
||||
const { energyLabel, discoveryLabel } = describeProfile(energy, novelty);
|
||||
@@ -32,10 +32,12 @@ export function VibeAura({ profile }: { profile: VibeProfile }) {
|
||||
|
||||
return (
|
||||
<div
|
||||
className="group relative grid h-16 w-16 shrink-0 place-items-center rounded-full focus:outline-none"
|
||||
className={ambient
|
||||
? 'pointer-events-none absolute right-10 top-32 z-0 grid h-16 w-16 scale-[3.6] place-items-center rounded-full opacity-35'
|
||||
: 'group relative grid h-16 w-16 shrink-0 place-items-center rounded-full focus:outline-none'}
|
||||
style={style}
|
||||
role="img"
|
||||
tabIndex={0}
|
||||
tabIndex={ambient ? -1 : 0}
|
||||
aria-label={`Current Vibe: ${energyLabel} energy and ${discoveryLabel} discovery`}
|
||||
>
|
||||
<div className="vibe-aura-halo" />
|
||||
@@ -46,10 +48,12 @@ export function VibeAura({ profile }: { profile: VibeProfile }) {
|
||||
<span className="vibe-aura-spark vibe-aura-spark-two" />
|
||||
<span className="vibe-aura-heart" />
|
||||
</div>
|
||||
<div className="pointer-events-none absolute right-0 top-[calc(100%+0.4rem)] z-10 w-44 rounded-md border border-border bg-surface1 px-3 py-2 text-xs leading-relaxed text-muted opacity-0 shadow-xl transition-opacity group-hover:opacity-100 group-focus:opacity-100">
|
||||
<span className="block font-medium text-text">Your Vibe is {energyLabel}</span>
|
||||
<span>Leaning {discoveryLabel}; it shifts as you listen.</span>
|
||||
</div>
|
||||
{!ambient && (
|
||||
<div className="pointer-events-none absolute right-0 top-[calc(100%+0.4rem)] z-10 w-44 rounded-md border border-border bg-surface1 px-3 py-2 text-xs leading-relaxed text-muted opacity-0 shadow-xl transition-opacity group-hover:opacity-100 group-focus:opacity-100">
|
||||
<span className="block font-medium text-text">Your Vibe is {energyLabel}</span>
|
||||
<span>Leaning {discoveryLabel}; it shifts as you listen.</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+43
-43
@@ -186,15 +186,15 @@ export default function Vibe() {
|
||||
|
||||
// ---- Active session ----
|
||||
return (
|
||||
<PageContainer width="sm" className="py-6">
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Sparkles size={22} className="text-accent" />
|
||||
<h1 className="text-2xl font-bold text-text">Vibing</h1>
|
||||
{initialBatchStatus === 'loading' && <Loader2 size={16} className="animate-spin text-muted" />}
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<VibeAura profile={profile} />
|
||||
<PageContainer width="sm" className="relative isolate overflow-hidden py-6">
|
||||
<VibeAura profile={profile} ambient />
|
||||
<div className="relative z-10 space-y-6">
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Sparkles size={22} className="text-accent" />
|
||||
<h1 className="text-2xl font-bold text-text">Vibing</h1>
|
||||
{initialBatchStatus === 'loading' && <Loader2 size={16} className="animate-spin text-muted" />}
|
||||
</div>
|
||||
<button
|
||||
onClick={handleEnd}
|
||||
className="flex items-center gap-2 rounded-lg border border-border px-3 py-1.5 text-sm text-text transition-colors hover:border-red-500/60 hover:text-red-300"
|
||||
@@ -202,45 +202,45 @@ export default function Vibe() {
|
||||
<Square size={14} />
|
||||
End Vibe
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
</header>
|
||||
|
||||
{(empty || initialBatchStatus === 'exhausted' || initialBatchStatus === 'failed') && (
|
||||
<div className="rounded-lg border border-border bg-surface0 p-4 text-sm text-muted">
|
||||
{initialBatchStatus === 'failed'
|
||||
? 'Could not load recommendations for this Vibe. Try starting a different one.'
|
||||
: 'No recommendations came back for this seed yet. Try ending and starting a different vibe.'}
|
||||
</div>
|
||||
)}
|
||||
{(empty || initialBatchStatus === 'exhausted' || initialBatchStatus === 'failed') && (
|
||||
<div className="rounded-lg border border-border bg-surface0 p-4 text-sm text-muted">
|
||||
{initialBatchStatus === 'failed'
|
||||
? 'Could not load recommendations for this Vibe. Try starting a different one.'
|
||||
: 'No recommendations came back for this seed yet. Try ending and starting a different vibe.'}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<div className="rounded-lg border border-red-500/40 bg-red-500/10 p-3 text-sm text-red-300">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
{error && (
|
||||
<div className="rounded-lg border border-red-500/40 bg-red-500/10 p-3 text-sm text-red-300">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{planVersion && <p className="text-xs text-muted/70">Plan revision {planVersion}; upcoming tracks may change as you listen.</p>}
|
||||
{planVersion && <p className="text-xs text-muted/70">Plan revision {planVersion}; upcoming tracks may change as you listen.</p>}
|
||||
|
||||
{currentTrack && (
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={handleKeep}
|
||||
className="flex items-center gap-2 rounded-lg border border-border px-4 py-2 text-sm font-medium text-text transition-colors hover:border-pink-500/60 hover:text-pink-300"
|
||||
>
|
||||
<Heart size={16} />
|
||||
Keep
|
||||
</button>
|
||||
<button
|
||||
onClick={handleDislike}
|
||||
className="flex items-center gap-2 rounded-lg border border-border px-4 py-2 text-sm font-medium text-text transition-colors hover:border-red-500/60 hover:text-red-300"
|
||||
>
|
||||
<ThumbsDown size={16} />
|
||||
Dislike & skip
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{currentTrack && (
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={handleKeep}
|
||||
className="flex items-center gap-2 rounded-lg border border-border px-4 py-2 text-sm font-medium text-text transition-colors hover:border-pink-500/60 hover:text-pink-300"
|
||||
>
|
||||
<Heart size={16} />
|
||||
Keep
|
||||
</button>
|
||||
<button
|
||||
onClick={handleDislike}
|
||||
className="flex items-center gap-2 rounded-lg border border-border px-4 py-2 text-sm font-medium text-text transition-colors hover:border-red-500/60 hover:text-red-300"
|
||||
>
|
||||
<ThumbsDown size={16} />
|
||||
Dislike & skip
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<VibeTimeline currentTrack={currentTrack} upcoming={upcoming} />
|
||||
<VibeTimeline currentTrack={currentTrack} upcoming={upcoming} />
|
||||
</div>
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user