Redesign Library view to match mockup spec
- Replace band-name header + tab structure (By Date / Search) with a unified Library view: title, inline search input, filter pills (All / instrument / Commented), and date-group headers - Session rows now use the recording-row card style (play circle, mono filename, recording count) - Move mini waveform bars from session list to individual recording rows in SessionPage, where they correspond to a single track - Fix Invalid Date by appending T12:00:00 when parsing date-only ISO strings in both BandPage and SessionPage - Update tests: drop tab assertions (TC-07), add Library heading (TC-08) and filter pill (TC-09) checks, update upload button label Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useState, useMemo } from "react";
|
||||
import { useParams, Link } from "react-router-dom";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { api } from "../api/client";
|
||||
@@ -24,10 +24,29 @@ interface SessionDetail {
|
||||
}
|
||||
|
||||
function formatDate(iso: string): string {
|
||||
const d = new Date(iso);
|
||||
const d = new Date(iso + "T12:00:00");
|
||||
return d.toLocaleDateString(undefined, { weekday: "long", year: "numeric", month: "long", day: "numeric" });
|
||||
}
|
||||
|
||||
function computeWaveBars(seed: string): number[] {
|
||||
let s = seed.split("").reduce((acc, c) => acc + c.charCodeAt(0), 31337);
|
||||
return Array.from({ length: 14 }, () => {
|
||||
s = ((s * 1664525 + 1013904223) & 0xffffffff) >>> 0;
|
||||
return Math.max(15, Math.floor((s / 0xffffffff) * 100));
|
||||
});
|
||||
}
|
||||
|
||||
function MiniWaveBars({ seed }: { seed: string }) {
|
||||
const bars = useMemo(() => computeWaveBars(seed), [seed]);
|
||||
return (
|
||||
<div style={{ display: "flex", alignItems: "flex-end", gap: "1.5px", height: 18, width: 34, flexShrink: 0 }}>
|
||||
{bars.map((h, i) => (
|
||||
<div key={i} style={{ width: 2, background: "rgba(255,255,255,0.11)", borderRadius: 1, height: `${h}%` }} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function SessionPage() {
|
||||
const { bandId, sessionId } = useParams<{ bandId: string; sessionId: string }>();
|
||||
const qc = useQueryClient();
|
||||
@@ -165,9 +184,12 @@ export function SessionPage() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ color: "var(--text-muted)", fontSize: 12, whiteSpace: "nowrap" }}>
|
||||
<span style={{ background: "var(--bg-subtle)", borderRadius: 4, padding: "2px 6px", marginRight: 8, fontFamily: "monospace", fontSize: 10 }}>{song.status}</span>
|
||||
{song.version_count} version{song.version_count !== 1 ? "s" : ""}
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 10, flexShrink: 0 }}>
|
||||
<MiniWaveBars seed={song.id} />
|
||||
<div style={{ color: "var(--text-muted)", fontSize: 12, whiteSpace: "nowrap" }}>
|
||||
<span style={{ background: "var(--bg-subtle)", borderRadius: 4, padding: "2px 6px", marginRight: 8, fontFamily: "monospace", fontSize: 10 }}>{song.status}</span>
|
||||
{song.version_count} version{song.version_count !== 1 ? "s" : ""}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user