feat: fix song view layout - align waveform top, scrollable comments, compose section always visible
This commit is contained in:
@@ -116,7 +116,8 @@ function Avatar({
|
||||
}
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
width: size,
|
||||
height: size,
|
||||
borderRadius: "50%",
|
||||
@@ -129,7 +130,8 @@ function Avatar({
|
||||
fontSize: size * 0.38,
|
||||
fontWeight: 700,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
{getInitials(name)}
|
||||
</div>
|
||||
@@ -200,7 +202,8 @@ function WaveformPins({
|
||||
return (
|
||||
<div
|
||||
key={c.id}
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
position: "absolute",
|
||||
left,
|
||||
top: 0,
|
||||
@@ -212,7 +215,8 @@ function WaveformPins({
|
||||
zIndex: 10,
|
||||
transition: "transform 0.12s",
|
||||
...(isHovered ? { transform: "translateX(-50%) scale(1.15)" } : {}),
|
||||
}}
|
||||
}
|
||||
}
|
||||
onMouseEnter={() => setHoveredId(c.id)}
|
||||
onMouseLeave={() => setHoveredId(null)}
|
||||
onClick={() => {
|
||||
@@ -223,7 +227,8 @@ function WaveformPins({
|
||||
{/* Tooltip */}
|
||||
{isHovered && (
|
||||
<div
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
position: "absolute",
|
||||
bottom: "calc(100% + 6px)",
|
||||
left: "50%",
|
||||
@@ -235,11 +240,13 @@ function WaveformPins({
|
||||
width: 180,
|
||||
zIndex: 50,
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 4 }}>
|
||||
<div
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
width: 18,
|
||||
height: 18,
|
||||
borderRadius: "50%",
|
||||
@@ -250,7 +257,8 @@ function WaveformPins({
|
||||
justifyContent: "center",
|
||||
fontSize: 8,
|
||||
fontWeight: 700,
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
{getInitials(c.author_name)}
|
||||
</div>
|
||||
@@ -266,7 +274,8 @@ function WaveformPins({
|
||||
)}
|
||||
{/* Avatar circle */}
|
||||
<div
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: "50%",
|
||||
@@ -279,7 +288,8 @@ function WaveformPins({
|
||||
fontSize: 9,
|
||||
fontWeight: 700,
|
||||
boxShadow: "0 2px 8px rgba(0,0,0,0.45)",
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
{getInitials(c.author_name)}
|
||||
</div>
|
||||
@@ -307,7 +317,7 @@ export function SongPage() {
|
||||
const [composeFocused, setComposeFocused] = useState(false);
|
||||
const [waveformWidth, setWaveformWidth] = useState(0);
|
||||
|
||||
// ── Data fetching ────────────────────────────────────────────────────────
|
||||
// ── Data fetching ──────────────────────────────────────────────────────
|
||||
|
||||
const { data: me } = useQuery({
|
||||
queryKey: ["me"],
|
||||
@@ -338,7 +348,7 @@ export function SongPage() {
|
||||
enabled: !!songId,
|
||||
});
|
||||
|
||||
// ── Version selection ────────────────────────────────────────────────────
|
||||
// ── Version selection ──────────────────────────────────────────────────
|
||||
|
||||
const activeVersion = selectedVersionId ?? versions?.[0]?.id ?? null;
|
||||
|
||||
@@ -361,7 +371,7 @@ export function SongPage() {
|
||||
return () => ro.disconnect();
|
||||
}, []);
|
||||
|
||||
// ── Keyboard shortcut: Space ──────────────────────────────────────────────
|
||||
// ── Keyboard shortcut: Space ────────────────────────────────────────────
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
@@ -401,26 +411,27 @@ export function SongPage() {
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
// ── Styles ────────────────────────────────────────────────────────────────
|
||||
// ── Styles ──────────────────────────────────────────────────────────────
|
||||
|
||||
const border = "rgba(255,255,255,0.055)";
|
||||
|
||||
// ── Render ────────────────────────────────────────────────────────────────
|
||||
// ── Render ──────────────────────────────────────────────────────────────
|
||||
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column", height: "100%", overflow: "hidden", background: "#0f0f12" }}>
|
||||
|
||||
{/* ── Breadcrumb header ──────────────────────────────────────────── */}
|
||||
<div
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
padding: "11px 20px",
|
||||
borderBottom: `1px solid ${border}`,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 5, flex: 1, minWidth: 0 }}>
|
||||
<button
|
||||
@@ -446,14 +457,16 @@ export function SongPage() {
|
||||
)}
|
||||
<span style={{ color: "rgba(255,255,255,0.15)", fontSize: 11 }}>›</span>
|
||||
<span
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
fontSize: 12,
|
||||
color: "rgba(255,255,255,0.7)",
|
||||
fontFamily: "'SF Mono', 'Fira Code', monospace",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
{song?.title ?? "…"}
|
||||
</span>
|
||||
@@ -466,7 +479,8 @@ export function SongPage() {
|
||||
<button
|
||||
key={v.id}
|
||||
onClick={() => setSelectedVersionId(v.id)}
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
background: v.id === activeVersion ? "rgba(232,162,42,0.14)" : "transparent",
|
||||
border: `1px solid ${v.id === activeVersion ? "rgba(232,162,42,0.28)" : "rgba(255,255,255,0.09)"}`,
|
||||
borderRadius: 6,
|
||||
@@ -475,7 +489,8 @@ export function SongPage() {
|
||||
cursor: "pointer",
|
||||
fontSize: 11,
|
||||
fontFamily: "monospace",
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
v{v.version_number}{v.label ? ` · ${v.label}` : ""}
|
||||
</button>
|
||||
@@ -484,7 +499,8 @@ export function SongPage() {
|
||||
)}
|
||||
|
||||
<button
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
background: "transparent",
|
||||
border: "1px solid rgba(255,255,255,0.09)",
|
||||
borderRadius: 6,
|
||||
@@ -494,28 +510,31 @@ export function SongPage() {
|
||||
padding: "5px 12px",
|
||||
fontFamily: "inherit",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
Share
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* ── Body: waveform | comments ────────────────────────────────── */}
|
||||
<div className="song-page-body" style={{ display: "flex", flex: 1, overflow: "hidden" }}>
|
||||
<div className="song-page-body" style={{ display: "flex", flexDirection: "column", flex: 1, overflow: "hidden" }}>
|
||||
|
||||
{/* ── Left: waveform + transport ──────────────────────────────── */}
|
||||
<div className="waveform-section" style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "hidden", padding: "16px 20px" }}>
|
||||
{/* ── Waveform section (top) ──────────────────────────────── */}
|
||||
<div className="waveform-section" style={{ display: "flex", flexDirection: "column", overflow: "hidden", padding: "16px 20px" }}>
|
||||
|
||||
{/* Waveform card */}
|
||||
<div
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
background: "rgba(255,255,255,0.02)",
|
||||
border: `1px solid ${border}`,
|
||||
borderRadius: 10,
|
||||
padding: "14px 14px 10px",
|
||||
marginBottom: 12,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 6 }}>
|
||||
<span style={{ fontSize: 11, color: "rgba(255,255,255,0.45)", fontFamily: "monospace" }}>
|
||||
@@ -559,13 +578,15 @@ export function SongPage() {
|
||||
|
||||
{/* Transport */}
|
||||
<div
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
gap: 10,
|
||||
padding: "4px 0 12px",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
{/* Skip back */}
|
||||
<TransportButton onClick={() => seekTo(Math.max(0, currentTime - 30))} title="−30s">
|
||||
@@ -576,7 +597,8 @@ export function SongPage() {
|
||||
<button
|
||||
onClick={isPlaying ? pause : play}
|
||||
disabled={!activeVersion}
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
width: 46,
|
||||
height: 46,
|
||||
background: "#e8a22a",
|
||||
@@ -589,7 +611,8 @@ export function SongPage() {
|
||||
opacity: activeVersion ? 1 : 0.4,
|
||||
flexShrink: 0,
|
||||
transition: "background 0.15s, transform 0.15s",
|
||||
}}
|
||||
}
|
||||
}
|
||||
onMouseEnter={(e) => { if (activeVersion) e.currentTarget.style.background = "#f0b740"; }}
|
||||
onMouseLeave={(e) => { e.currentTarget.style.background = "#e8a22a"; }}
|
||||
>
|
||||
@@ -606,49 +629,207 @@ export function SongPage() {
|
||||
|
||||
</div>
|
||||
|
||||
{/* ── Right: comment panel ──────────────────────────────────────── */}
|
||||
{/* ── Comments section (bottom) ──────────────────────────────── */}
|
||||
<div
|
||||
className="comment-panel"
|
||||
style={{
|
||||
width: 280,
|
||||
minWidth: 280,
|
||||
borderLeft: `1px solid ${border}`,
|
||||
style={
|
||||
{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
overflow: "hidden",
|
||||
background: "rgba(0,0,0,0.12)",
|
||||
// Responsive: center on mobile
|
||||
margin: "0 auto",
|
||||
}}
|
||||
borderTop: `1px solid ${border}`,
|
||||
flex: 1,
|
||||
}
|
||||
}
|
||||
>
|
||||
{/* Header */}
|
||||
<div
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
padding: "12px 15px",
|
||||
borderBottom: `1px solid ${border}`,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
<span style={{ fontSize: 13, fontWeight: 500, color: "rgba(255,255,255,0.72)" }}>Comments</span>
|
||||
{comments && comments.length > 0 && (
|
||||
<span
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
fontSize: 11,
|
||||
background: "rgba(232,162,42,0.14)",
|
||||
color: "#e8a22a",
|
||||
padding: "1px 8px",
|
||||
borderRadius: 10,
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
{comments.length}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Comment list */}
|
||||
{/* Compose section (moved to top) */}
|
||||
<div
|
||||
style={
|
||||
{
|
||||
padding: "11px 14px",
|
||||
borderBottom: `1px solid ${border}`,
|
||||
flexShrink: 0,
|
||||
}
|
||||
}
|
||||
>
|
||||
<div style={{ display: "flex", gap: 9, alignItems: "flex-start" }}>
|
||||
{/* My avatar */}
|
||||
{me ? (
|
||||
<Avatar name={me.display_name} avatarUrl={me.avatar_url ?? null} authorId={me.id} size={26} />
|
||||
) : (
|
||||
<div style={{ width: 26, height: 26, borderRadius: "50%", background: "rgba(255,255,255,0.06)", flexShrink: 0 }} />
|
||||
)}
|
||||
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
{/* Timestamp pill */}
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 7, marginBottom: 6 }}>
|
||||
<div
|
||||
style={
|
||||
{
|
||||
fontSize: 11,
|
||||
fontFamily: "monospace",
|
||||
background: "rgba(232,162,42,0.1)",
|
||||
color: "#e8a22a",
|
||||
border: "1px solid rgba(232,162,42,0.22)",
|
||||
padding: "3px 9px",
|
||||
borderRadius: 20,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 6,
|
||||
}
|
||||
}
|
||||
>
|
||||
{isPlaying && (
|
||||
<div
|
||||
style={
|
||||
{
|
||||
width: 6,
|
||||
height: 6,
|
||||
borderRadius: "50%",
|
||||
background: "#e8a22a",
|
||||
animation: "rh-blink 1.1s infinite",
|
||||
}
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{formatTime(currentTime)}
|
||||
</div>
|
||||
<span style={{ fontSize: 11, color: "rgba(255,255,255,0.18)" }}>· pins to playhead</span>
|
||||
</div>
|
||||
|
||||
{/* Textarea */}
|
||||
<textarea
|
||||
value={commentBody}
|
||||
onChange={(e) => setCommentBody(e.target.value)}
|
||||
onFocus={() => setComposeFocused(true)}
|
||||
onBlur={() => {
|
||||
if (!commentBody.trim()) setComposeFocused(false);
|
||||
}}
|
||||
placeholder="What do you hear at this moment…"
|
||||
style={
|
||||
{
|
||||
width: "100%",
|
||||
background: "rgba(255,255,255,0.05)",
|
||||
border: composeFocused
|
||||
? "1px solid rgba(232,162,42,0.35)"
|
||||
: "1px solid rgba(255,255,255,0.07)",
|
||||
borderRadius: 7,
|
||||
padding: "8px 10px",
|
||||
color: "#e0e0e8",
|
||||
fontSize: 12,
|
||||
resize: "none",
|
||||
outline: "none",
|
||||
fontFamily: "inherit",
|
||||
height: composeFocused ? 68 : 42,
|
||||
transition: "height 0.18s, border-color 0.15s",
|
||||
boxSizing: "border-box",
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Tag buttons + Post (visible when focused) */}
|
||||
{composeFocused && (
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 7 }}>
|
||||
<div style={{ display: "flex", gap: 5 }}>
|
||||
{(["suggestion", "issue", "keeper"] as const).map((tag) => (
|
||||
<button
|
||||
key={tag}
|
||||
onClick={() => setSelectedTag((t) => (t === tag ? "" : tag))}
|
||||
style={
|
||||
{
|
||||
fontSize: 11,
|
||||
padding: "3px 8px",
|
||||
borderRadius: 4,
|
||||
cursor: "pointer",
|
||||
fontFamily: "inherit",
|
||||
background:
|
||||
selectedTag === tag
|
||||
? TAG_STYLES[tag].bg
|
||||
: "rgba(255,255,255,0.05)",
|
||||
border:
|
||||
selectedTag === tag
|
||||
? `1px solid ${TAG_STYLES[tag].color}44`
|
||||
: "1px solid rgba(255,255,255,0.07)",
|
||||
color:
|
||||
selectedTag === tag
|
||||
? TAG_STYLES[tag].color
|
||||
: "rgba(255,255,255,0.32)",
|
||||
transition: "all 0.12s",
|
||||
}
|
||||
}
|
||||
>
|
||||
{tag}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
if (commentBody.trim()) {
|
||||
addCommentMutation.mutate({
|
||||
body: commentBody.trim(),
|
||||
timestamp: currentTime,
|
||||
tag: selectedTag,
|
||||
});
|
||||
}
|
||||
}}
|
||||
disabled={!commentBody.trim() || addCommentMutation.isPending}
|
||||
style={
|
||||
{
|
||||
padding: "5px 14px",
|
||||
borderRadius: 6,
|
||||
background: "#e8a22a",
|
||||
border: "none",
|
||||
color: "#0f0f12",
|
||||
cursor: commentBody.trim() ? "pointer" : "default",
|
||||
fontSize: 12,
|
||||
fontWeight: 600,
|
||||
fontFamily: "inherit",
|
||||
opacity: commentBody.trim() ? 1 : 0.35,
|
||||
transition: "opacity 0.12s",
|
||||
}
|
||||
}
|
||||
>
|
||||
Post
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Scrollable comment list */}
|
||||
<div style={{ flex: 1, overflowY: "auto", padding: "12px 14px" }}>
|
||||
{comments?.map((c) => {
|
||||
const tagStyle = c.tag ? TAG_STYLES[c.tag] : null;
|
||||
@@ -658,7 +839,8 @@ export function SongPage() {
|
||||
<div
|
||||
key={c.id}
|
||||
id={`comment-${c.id}`}
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
marginBottom: 14,
|
||||
paddingBottom: 14,
|
||||
borderBottom: "1px solid rgba(255,255,255,0.04)",
|
||||
@@ -666,7 +848,8 @@ export function SongPage() {
|
||||
background: isNearPlayhead ? "rgba(232,162,42,0.04)" : undefined,
|
||||
border: isNearPlayhead ? "1px solid rgba(232,162,42,0.12)" : undefined,
|
||||
padding: isNearPlayhead ? 8 : undefined,
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
{/* Author row */}
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 7, marginBottom: 5 }}>
|
||||
@@ -679,7 +862,8 @@ export function SongPage() {
|
||||
onClick={() => {
|
||||
seekTo(c.timestamp!);
|
||||
}}
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
marginLeft: "auto",
|
||||
fontSize: 10,
|
||||
fontFamily: "monospace",
|
||||
@@ -689,7 +873,8 @@ export function SongPage() {
|
||||
borderRadius: 3,
|
||||
padding: "1px 5px",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
}
|
||||
}
|
||||
onMouseEnter={(e) => (e.currentTarget.style.background = "rgba(232,162,42,0.2)")}
|
||||
onMouseLeave={(e) => (e.currentTarget.style.background = "rgba(232,162,42,0.1)")}
|
||||
>
|
||||
@@ -698,13 +883,15 @@ export function SongPage() {
|
||||
)}
|
||||
{tagStyle && (
|
||||
<span
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
fontSize: 10,
|
||||
padding: "1px 5px",
|
||||
borderRadius: 3,
|
||||
background: tagStyle.bg,
|
||||
color: tagStyle.color,
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
{c.tag}
|
||||
</span>
|
||||
@@ -744,148 +931,6 @@ export function SongPage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Compose */}
|
||||
<div
|
||||
style={{
|
||||
padding: "11px 14px",
|
||||
borderTop: `1px solid ${border}`,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", gap: 9, alignItems: "flex-start" }}>
|
||||
{/* My avatar */}
|
||||
{me ? (
|
||||
<Avatar name={me.display_name} avatarUrl={me.avatar_url ?? null} authorId={me.id} size={26} />
|
||||
) : (
|
||||
<div style={{ width: 26, height: 26, borderRadius: "50%", background: "rgba(255,255,255,0.06)", flexShrink: 0 }} />
|
||||
)}
|
||||
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
{/* Timestamp pill */}
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 7, marginBottom: 6 }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 11,
|
||||
fontFamily: "monospace",
|
||||
background: "rgba(232,162,42,0.1)",
|
||||
color: "#e8a22a",
|
||||
border: "1px solid rgba(232,162,42,0.22)",
|
||||
padding: "3px 9px",
|
||||
borderRadius: 20,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 6,
|
||||
}}
|
||||
>
|
||||
{isPlaying && (
|
||||
<div
|
||||
style={{
|
||||
width: 6,
|
||||
height: 6,
|
||||
borderRadius: "50%",
|
||||
background: "#e8a22a",
|
||||
animation: "rh-blink 1.1s infinite",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{formatTime(currentTime)}
|
||||
</div>
|
||||
<span style={{ fontSize: 11, color: "rgba(255,255,255,0.18)" }}>· pins to playhead</span>
|
||||
</div>
|
||||
|
||||
{/* Textarea */}
|
||||
<textarea
|
||||
value={commentBody}
|
||||
onChange={(e) => setCommentBody(e.target.value)}
|
||||
onFocus={() => setComposeFocused(true)}
|
||||
onBlur={() => {
|
||||
if (!commentBody.trim()) setComposeFocused(false);
|
||||
}}
|
||||
placeholder="What do you hear at this moment…"
|
||||
style={{
|
||||
width: "100%",
|
||||
background: "rgba(255,255,255,0.05)",
|
||||
border: composeFocused
|
||||
? "1px solid rgba(232,162,42,0.35)"
|
||||
: "1px solid rgba(255,255,255,0.07)",
|
||||
borderRadius: 7,
|
||||
padding: "8px 10px",
|
||||
color: "#e0e0e8",
|
||||
fontSize: 12,
|
||||
resize: "none",
|
||||
outline: "none",
|
||||
fontFamily: "inherit",
|
||||
height: composeFocused ? 68 : 42,
|
||||
transition: "height 0.18s, border-color 0.15s",
|
||||
boxSizing: "border-box",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Tag buttons + Post (visible when focused) */}
|
||||
{composeFocused && (
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 7 }}>
|
||||
<div style={{ display: "flex", gap: 5 }}>
|
||||
{(["suggestion", "issue", "keeper"] as const).map((tag) => (
|
||||
<button
|
||||
key={tag}
|
||||
onClick={() => setSelectedTag((t) => (t === tag ? "" : tag))}
|
||||
style={{
|
||||
fontSize: 11,
|
||||
padding: "3px 8px",
|
||||
borderRadius: 4,
|
||||
cursor: "pointer",
|
||||
fontFamily: "inherit",
|
||||
background:
|
||||
selectedTag === tag
|
||||
? TAG_STYLES[tag].bg
|
||||
: "rgba(255,255,255,0.05)",
|
||||
border:
|
||||
selectedTag === tag
|
||||
? `1px solid ${TAG_STYLES[tag].color}44`
|
||||
: "1px solid rgba(255,255,255,0.07)",
|
||||
color:
|
||||
selectedTag === tag
|
||||
? TAG_STYLES[tag].color
|
||||
: "rgba(255,255,255,0.32)",
|
||||
transition: "all 0.12s",
|
||||
}}
|
||||
>
|
||||
{tag}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
if (commentBody.trim()) {
|
||||
addCommentMutation.mutate({
|
||||
body: commentBody.trim(),
|
||||
timestamp: currentTime,
|
||||
tag: selectedTag,
|
||||
});
|
||||
}
|
||||
}}
|
||||
disabled={!commentBody.trim() || addCommentMutation.isPending}
|
||||
style={{
|
||||
padding: "5px 14px",
|
||||
borderRadius: 6,
|
||||
background: "#e8a22a",
|
||||
border: "none",
|
||||
color: "#0f0f12",
|
||||
cursor: commentBody.trim() ? "pointer" : "default",
|
||||
fontSize: 12,
|
||||
fontWeight: 600,
|
||||
fontFamily: "inherit",
|
||||
opacity: commentBody.trim() ? 1 : 0.35,
|
||||
transition: "opacity 0.12s",
|
||||
}}
|
||||
>
|
||||
Post
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -928,7 +973,8 @@ function TransportButton({ onClick, title, children }: { onClick: () => void; ti
|
||||
title={title}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
style={{
|
||||
style={
|
||||
{
|
||||
width: 34,
|
||||
height: 34,
|
||||
borderRadius: "50%",
|
||||
@@ -941,11 +987,10 @@ function TransportButton({ onClick, title, children }: { onClick: () => void; ti
|
||||
color: hovered ? "rgba(255,255,255,0.7)" : "rgba(255,255,255,0.35)",
|
||||
flexShrink: 0,
|
||||
transition: "all 0.12s",
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user