CODEX - Thrid Try for the fix
This commit is contained in:
@@ -958,8 +958,8 @@ export default function MelodyList() {
|
|||||||
const selectClass = "px-3 py-2 rounded-md text-sm cursor-pointer border";
|
const selectClass = "px-3 py-2 rounded-md text-sm cursor-pointer border";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full min-w-0 max-w-full" style={{ overflowX: "clip" }}>
|
<div className="w-full min-w-0 max-w-full overflow-hidden">
|
||||||
<div className="w-full max-w-full overflow-x-hidden relative z-40">
|
<div className="w-full min-w-0 relative" style={{ zIndex: 30 }}>
|
||||||
<div className="flex items-center justify-between mb-6 w-full min-w-0">
|
<div className="flex items-center justify-between mb-6 w-full min-w-0">
|
||||||
<h1 className="text-2xl font-bold" style={{ color: "var(--text-heading)" }}>Melodies</h1>
|
<h1 className="text-2xl font-bold" style={{ color: "var(--text-heading)" }}>Melodies</h1>
|
||||||
{canEdit && (
|
{canEdit && (
|
||||||
@@ -973,187 +973,187 @@ export default function MelodyList() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-4 space-y-3 w-full min-w-0">
|
<div className="mb-4 space-y-3 w-full min-w-0 relative" style={{ zIndex: 40 }}>
|
||||||
<SearchBar
|
<SearchBar
|
||||||
onSearch={setSearch}
|
onSearch={setSearch}
|
||||||
placeholder="Search by name, description, or tags..."
|
placeholder="Search by name, description, or tags..."
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-wrap gap-3 items-center w-full min-w-0">
|
<div className="w-full min-w-0 flex items-start justify-between gap-3 flex-wrap">
|
||||||
<select
|
<div className="min-w-0 flex-1 flex flex-wrap gap-3 items-center">
|
||||||
value={typeFilter}
|
|
||||||
onChange={(e) => setTypeFilter(e.target.value)}
|
|
||||||
className={selectClass}
|
|
||||||
>
|
|
||||||
<option value="">All Types</option>
|
|
||||||
{MELODY_TYPES.filter(Boolean).map((t) => (
|
|
||||||
<option key={t} value={t}>
|
|
||||||
{t.charAt(0).toUpperCase() + t.slice(1)}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<select
|
|
||||||
value={toneFilter}
|
|
||||||
onChange={(e) => setToneFilter(e.target.value)}
|
|
||||||
className={selectClass}
|
|
||||||
>
|
|
||||||
<option value="">All Tones</option>
|
|
||||||
{MELODY_TONES.filter(Boolean).map((t) => (
|
|
||||||
<option key={t} value={t}>
|
|
||||||
{t.charAt(0).toUpperCase() + t.slice(1)}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<select
|
|
||||||
value={statusFilter}
|
|
||||||
onChange={(e) => setStatusFilter(e.target.value)}
|
|
||||||
className={selectClass}
|
|
||||||
>
|
|
||||||
<option value="">All Statuses</option>
|
|
||||||
<option value="published">Published (Live)</option>
|
|
||||||
<option value="draft">Drafts</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<div className="relative z-50" ref={creatorPickerRef}>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setShowCreatorPicker((prev) => !prev)}
|
|
||||||
className="px-3 py-2 rounded-md text-sm transition-colors cursor-pointer flex items-center gap-1.5 border"
|
|
||||||
style={{ borderColor: "var(--border-primary)", color: "var(--text-secondary)" }}
|
|
||||||
>
|
|
||||||
Created By
|
|
||||||
{createdByFilter.length > 0 ? ` (${createdByFilter.length})` : ""}
|
|
||||||
</button>
|
|
||||||
{showCreatorPicker && (
|
|
||||||
<div
|
|
||||||
className="absolute left-0 top-full mt-1 z-[80] rounded-lg shadow-lg py-2 w-64 border max-h-64 overflow-auto"
|
|
||||||
style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
|
|
||||||
>
|
|
||||||
{allCreators.length === 0 ? (
|
|
||||||
<p className="px-3 py-1.5 text-sm" style={{ color: "var(--text-muted)" }}>No creators found</p>
|
|
||||||
) : (
|
|
||||||
allCreators.map((creator) => (
|
|
||||||
<label
|
|
||||||
key={creator}
|
|
||||||
className="flex items-center gap-2 px-3 py-1.5 text-sm cursor-pointer"
|
|
||||||
style={{ color: "var(--text-primary)" }}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={createdByFilter.includes(creator)}
|
|
||||||
onChange={() => toggleCreator(creator)}
|
|
||||||
className="h-3.5 w-3.5 rounded cursor-pointer"
|
|
||||||
/>
|
|
||||||
{creator}
|
|
||||||
</label>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
{createdByFilter.length > 0 && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setCreatedByFilter([])}
|
|
||||||
className="w-full text-left px-3 py-1.5 text-xs underline"
|
|
||||||
style={{ color: "var(--accent)", background: "none", border: "none" }}
|
|
||||||
>
|
|
||||||
Clear selection
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{languages.length > 1 && (
|
|
||||||
<select
|
<select
|
||||||
value={displayLang}
|
value={typeFilter}
|
||||||
onChange={(e) => setDisplayLang(e.target.value)}
|
onChange={(e) => setTypeFilter(e.target.value)}
|
||||||
className={selectClass}
|
className={selectClass}
|
||||||
>
|
>
|
||||||
{languages.map((l) => (
|
<option value="">All Types</option>
|
||||||
<option key={l} value={l}>
|
{MELODY_TYPES.filter(Boolean).map((t) => (
|
||||||
{getLanguageName(l)}
|
<option key={t} value={t}>
|
||||||
|
{t.charAt(0).toUpperCase() + t.slice(1)}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Column visibility dropdown */}
|
<select
|
||||||
<div className="relative z-50" ref={columnPickerRef}>
|
value={toneFilter}
|
||||||
<button
|
onChange={(e) => setToneFilter(e.target.value)}
|
||||||
type="button"
|
className={selectClass}
|
||||||
onClick={() => setShowColumnPicker((prev) => !prev)}
|
|
||||||
className="px-3 py-2 rounded-md text-sm transition-colors cursor-pointer flex items-center gap-1.5 border"
|
|
||||||
style={{
|
|
||||||
borderColor: "var(--border-primary)",
|
|
||||||
color: "var(--text-secondary)",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<option value="">All Tones</option>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" />
|
{MELODY_TONES.filter(Boolean).map((t) => (
|
||||||
</svg>
|
<option key={t} value={t}>
|
||||||
Columns
|
{t.charAt(0).toUpperCase() + t.slice(1)}
|
||||||
</button>
|
</option>
|
||||||
{showColumnPicker && (
|
))}
|
||||||
<div
|
</select>
|
||||||
className="absolute right-0 top-full mt-1 z-[80] rounded-lg shadow-lg py-2 w-56 border"
|
|
||||||
|
<select
|
||||||
|
value={statusFilter}
|
||||||
|
onChange={(e) => setStatusFilter(e.target.value)}
|
||||||
|
className={selectClass}
|
||||||
|
>
|
||||||
|
<option value="">All Statuses</option>
|
||||||
|
<option value="published">Published (Live)</option>
|
||||||
|
<option value="draft">Drafts</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<div className="relative" ref={creatorPickerRef} style={{ zIndex: 60 }}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowCreatorPicker((prev) => !prev)}
|
||||||
|
className="px-3 py-2 rounded-md text-sm transition-colors cursor-pointer flex items-center gap-1.5 border"
|
||||||
|
style={{ borderColor: "var(--border-primary)", color: "var(--text-secondary)" }}
|
||||||
|
>
|
||||||
|
Created By
|
||||||
|
{createdByFilter.length > 0 ? ` (${createdByFilter.length})` : ""}
|
||||||
|
</button>
|
||||||
|
{showCreatorPicker && (
|
||||||
|
<div
|
||||||
|
className="absolute left-0 top-full mt-1 rounded-lg shadow-lg py-2 w-64 border max-h-64 overflow-auto"
|
||||||
|
style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)", zIndex: 9999 }}
|
||||||
|
>
|
||||||
|
{allCreators.length === 0 ? (
|
||||||
|
<p className="px-3 py-1.5 text-sm" style={{ color: "var(--text-muted)" }}>No creators found</p>
|
||||||
|
) : (
|
||||||
|
allCreators.map((creator) => (
|
||||||
|
<label
|
||||||
|
key={creator}
|
||||||
|
className="flex items-center gap-2 px-3 py-1.5 text-sm cursor-pointer"
|
||||||
|
style={{ color: "var(--text-primary)" }}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={createdByFilter.includes(creator)}
|
||||||
|
onChange={() => toggleCreator(creator)}
|
||||||
|
className="h-3.5 w-3.5 rounded cursor-pointer"
|
||||||
|
/>
|
||||||
|
{creator}
|
||||||
|
</label>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
{createdByFilter.length > 0 && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setCreatedByFilter([])}
|
||||||
|
className="w-full text-left px-3 py-1.5 text-xs underline"
|
||||||
|
style={{ color: "var(--accent)", background: "none", border: "none" }}
|
||||||
|
>
|
||||||
|
Clear selection
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{languages.length > 1 && (
|
||||||
|
<select
|
||||||
|
value={displayLang}
|
||||||
|
onChange={(e) => setDisplayLang(e.target.value)}
|
||||||
|
className={selectClass}
|
||||||
|
>
|
||||||
|
{languages.map((l) => (
|
||||||
|
<option key={l} value={l}>
|
||||||
|
{getLanguageName(l)}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="relative" ref={columnPickerRef} style={{ zIndex: 60 }}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowColumnPicker((prev) => !prev)}
|
||||||
|
className="px-3 py-2 rounded-md text-sm transition-colors cursor-pointer flex items-center gap-1.5 border"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "var(--bg-card)",
|
|
||||||
borderColor: "var(--border-primary)",
|
borderColor: "var(--border-primary)",
|
||||||
|
color: "var(--text-secondary)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{orderedColumnPickerColumns.map((col) => {
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
const orderIdx = visibleColumns.indexOf(col.key);
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" />
|
||||||
const canMove = orderIdx >= 0;
|
</svg>
|
||||||
return (
|
Columns
|
||||||
<label
|
</button>
|
||||||
key={col.key}
|
{showColumnPicker && (
|
||||||
className="flex items-center gap-2 px-3 py-1.5 text-sm cursor-pointer"
|
<div
|
||||||
style={{ color: col.alwaysOn ? "var(--text-muted)" : "var(--text-primary)" }}
|
className="absolute right-0 top-full mt-1 rounded-lg shadow-lg py-2 w-56 border"
|
||||||
>
|
style={{
|
||||||
<input
|
backgroundColor: "var(--bg-card)",
|
||||||
type="checkbox"
|
borderColor: "var(--border-primary)",
|
||||||
checked={isVisible(col.key)}
|
zIndex: 9999,
|
||||||
onChange={() => toggleColumn(col.key)}
|
}}
|
||||||
disabled={col.alwaysOn}
|
>
|
||||||
className="h-3.5 w-3.5 rounded cursor-pointer"
|
{orderedColumnPickerColumns.map((col) => {
|
||||||
/>
|
const orderIdx = visibleColumns.indexOf(col.key);
|
||||||
<span className="flex-1">{col.label}</span>
|
const canMove = orderIdx >= 0;
|
||||||
{canMove && (
|
return (
|
||||||
<span className="inline-flex gap-1" onClick={(e) => e.stopPropagation()}>
|
<label
|
||||||
<button
|
key={col.key}
|
||||||
type="button"
|
className="flex items-center gap-2 px-3 py-1.5 text-sm cursor-pointer"
|
||||||
onClick={() => moveColumn(col.key, "up")}
|
style={{ color: col.alwaysOn ? "var(--text-muted)" : "var(--text-primary)" }}
|
||||||
className="text-[10px] px-1 rounded border"
|
>
|
||||||
style={{ borderColor: "var(--border-primary)", color: "var(--text-muted)", background: "transparent" }}
|
<input
|
||||||
title="Move up"
|
type="checkbox"
|
||||||
>
|
checked={isVisible(col.key)}
|
||||||
↑
|
onChange={() => toggleColumn(col.key)}
|
||||||
</button>
|
disabled={col.alwaysOn}
|
||||||
<button
|
className="h-3.5 w-3.5 rounded cursor-pointer"
|
||||||
type="button"
|
/>
|
||||||
onClick={() => moveColumn(col.key, "down")}
|
<span className="flex-1">{col.label}</span>
|
||||||
className="text-[10px] px-1 rounded border"
|
{canMove && (
|
||||||
style={{ borderColor: "var(--border-primary)", color: "var(--text-muted)", background: "transparent" }}
|
<span className="inline-flex gap-1" onClick={(e) => e.stopPropagation()}>
|
||||||
title="Move down"
|
<button
|
||||||
>
|
type="button"
|
||||||
↓
|
onClick={() => moveColumn(col.key, "up")}
|
||||||
</button>
|
className="text-[10px] px-1 rounded border"
|
||||||
</span>
|
style={{ borderColor: "var(--border-primary)", color: "var(--text-muted)", background: "transparent" }}
|
||||||
)}
|
title="Move up"
|
||||||
</label>
|
>
|
||||||
);
|
↑
|
||||||
})}
|
</button>
|
||||||
</div>
|
<button
|
||||||
)}
|
type="button"
|
||||||
|
onClick={() => moveColumn(col.key, "down")}
|
||||||
|
className="text-[10px] px-1 rounded border"
|
||||||
|
style={{ borderColor: "var(--border-primary)", color: "var(--text-muted)", background: "transparent" }}
|
||||||
|
title="Move down"
|
||||||
|
>
|
||||||
|
↓
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="ml-auto flex items-center gap-3 flex-nowrap min-w-0">
|
<div className="flex items-center justify-end gap-3 shrink-0 flex-wrap ml-auto">
|
||||||
<span className="text-sm whitespace-nowrap" style={{ color: "var(--text-muted)" }}>
|
<span className="text-sm whitespace-nowrap" style={{ color: "var(--text-muted)" }}>
|
||||||
<span className="inline-block max-w-[48vw] overflow-hidden text-ellipsis align-bottom">
|
{hasAnyFilter
|
||||||
{hasAnyFilter
|
? `Filtered - Showing ${displayRows.length} / ${allMelodyCount || melodies.length} Melodies | ${offlineTaggedCount} Melodies tagged for Offline`
|
||||||
? `Filtered - Showing ${displayRows.length} / ${allMelodyCount || melodies.length} Melodies | ${offlineTaggedCount} Melodies tagged for Offline`
|
: `Showing all (${allMelodyCount || melodies.length}) Melodies | ${offlineTaggedCount} Melodies tagged for Offline`}
|
||||||
: `Showing all (${allMelodyCount || melodies.length}) Melodies | ${offlineTaggedCount} Melodies tagged for Offline`}
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
{canEdit && (
|
{canEdit && (
|
||||||
<button
|
<button
|
||||||
@@ -1209,7 +1209,7 @@ export default function MelodyList() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="w-full max-w-full overflow-x-auto relative z-0">
|
<div className="w-full max-w-full overflow-x-auto relative z-0">
|
||||||
<table className="w-full text-sm min-w-max">
|
<table className="w-full min-w-full text-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr style={{ backgroundColor: "var(--bg-primary)", borderBottom: "1px solid var(--border-primary)" }}>
|
<tr style={{ backgroundColor: "var(--bg-primary)", borderBottom: "1px solid var(--border-primary)" }}>
|
||||||
{activeColumns.map((col) => (
|
{activeColumns.map((col) => (
|
||||||
|
|||||||
Reference in New Issue
Block a user