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";
|
||||
|
||||
return (
|
||||
<div className="w-full min-w-0 max-w-full" style={{ overflowX: "clip" }}>
|
||||
<div className="w-full max-w-full overflow-x-hidden relative z-40">
|
||||
<div className="w-full min-w-0 max-w-full overflow-hidden">
|
||||
<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">
|
||||
<h1 className="text-2xl font-bold" style={{ color: "var(--text-heading)" }}>Melodies</h1>
|
||||
{canEdit && (
|
||||
@@ -973,187 +973,187 @@ export default function MelodyList() {
|
||||
)}
|
||||
</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
|
||||
onSearch={setSearch}
|
||||
placeholder="Search by name, description, or tags..."
|
||||
/>
|
||||
<div className="flex flex-wrap gap-3 items-center w-full min-w-0">
|
||||
<select
|
||||
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 && (
|
||||
<div className="w-full min-w-0 flex items-start justify-between gap-3 flex-wrap">
|
||||
<div className="min-w-0 flex-1 flex flex-wrap gap-3 items-center">
|
||||
<select
|
||||
value={displayLang}
|
||||
onChange={(e) => setDisplayLang(e.target.value)}
|
||||
value={typeFilter}
|
||||
onChange={(e) => setTypeFilter(e.target.value)}
|
||||
className={selectClass}
|
||||
>
|
||||
{languages.map((l) => (
|
||||
<option key={l} value={l}>
|
||||
{getLanguageName(l)}
|
||||
<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>
|
||||
)}
|
||||
|
||||
{/* Column visibility dropdown */}
|
||||
<div className="relative z-50" ref={columnPickerRef}>
|
||||
<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={{
|
||||
borderColor: "var(--border-primary)",
|
||||
color: "var(--text-secondary)",
|
||||
}}
|
||||
<select
|
||||
value={toneFilter}
|
||||
onChange={(e) => setToneFilter(e.target.value)}
|
||||
className={selectClass}
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<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" />
|
||||
</svg>
|
||||
Columns
|
||||
</button>
|
||||
{showColumnPicker && (
|
||||
<div
|
||||
className="absolute right-0 top-full mt-1 z-[80] rounded-lg shadow-lg py-2 w-56 border"
|
||||
<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" 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={{
|
||||
backgroundColor: "var(--bg-card)",
|
||||
borderColor: "var(--border-primary)",
|
||||
color: "var(--text-secondary)",
|
||||
}}
|
||||
>
|
||||
{orderedColumnPickerColumns.map((col) => {
|
||||
const orderIdx = visibleColumns.indexOf(col.key);
|
||||
const canMove = orderIdx >= 0;
|
||||
return (
|
||||
<label
|
||||
key={col.key}
|
||||
className="flex items-center gap-2 px-3 py-1.5 text-sm cursor-pointer"
|
||||
style={{ color: col.alwaysOn ? "var(--text-muted)" : "var(--text-primary)" }}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isVisible(col.key)}
|
||||
onChange={() => toggleColumn(col.key)}
|
||||
disabled={col.alwaysOn}
|
||||
className="h-3.5 w-3.5 rounded cursor-pointer"
|
||||
/>
|
||||
<span className="flex-1">{col.label}</span>
|
||||
{canMove && (
|
||||
<span className="inline-flex gap-1" onClick={(e) => e.stopPropagation()}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => moveColumn(col.key, "up")}
|
||||
className="text-[10px] px-1 rounded border"
|
||||
style={{ borderColor: "var(--border-primary)", color: "var(--text-muted)", background: "transparent" }}
|
||||
title="Move up"
|
||||
>
|
||||
↑
|
||||
</button>
|
||||
<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>
|
||||
)}
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<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" />
|
||||
</svg>
|
||||
Columns
|
||||
</button>
|
||||
{showColumnPicker && (
|
||||
<div
|
||||
className="absolute right-0 top-full mt-1 rounded-lg shadow-lg py-2 w-56 border"
|
||||
style={{
|
||||
backgroundColor: "var(--bg-card)",
|
||||
borderColor: "var(--border-primary)",
|
||||
zIndex: 9999,
|
||||
}}
|
||||
>
|
||||
{orderedColumnPickerColumns.map((col) => {
|
||||
const orderIdx = visibleColumns.indexOf(col.key);
|
||||
const canMove = orderIdx >= 0;
|
||||
return (
|
||||
<label
|
||||
key={col.key}
|
||||
className="flex items-center gap-2 px-3 py-1.5 text-sm cursor-pointer"
|
||||
style={{ color: col.alwaysOn ? "var(--text-muted)" : "var(--text-primary)" }}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isVisible(col.key)}
|
||||
onChange={() => toggleColumn(col.key)}
|
||||
disabled={col.alwaysOn}
|
||||
className="h-3.5 w-3.5 rounded cursor-pointer"
|
||||
/>
|
||||
<span className="flex-1">{col.label}</span>
|
||||
{canMove && (
|
||||
<span className="inline-flex gap-1" onClick={(e) => e.stopPropagation()}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => moveColumn(col.key, "up")}
|
||||
className="text-[10px] px-1 rounded border"
|
||||
style={{ borderColor: "var(--border-primary)", color: "var(--text-muted)", background: "transparent" }}
|
||||
title="Move up"
|
||||
>
|
||||
↑
|
||||
</button>
|
||||
<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 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="inline-block max-w-[48vw] overflow-hidden text-ellipsis align-bottom">
|
||||
{hasAnyFilter
|
||||
? `Filtered - Showing ${displayRows.length} / ${allMelodyCount || melodies.length} Melodies | ${offlineTaggedCount} Melodies tagged for Offline`
|
||||
: `Showing all (${allMelodyCount || melodies.length}) Melodies | ${offlineTaggedCount} Melodies tagged for Offline`}
|
||||
</span>
|
||||
{hasAnyFilter
|
||||
? `Filtered - Showing ${displayRows.length} / ${allMelodyCount || melodies.length} Melodies | ${offlineTaggedCount} Melodies tagged for Offline`
|
||||
: `Showing all (${allMelodyCount || melodies.length}) Melodies | ${offlineTaggedCount} Melodies tagged for Offline`}
|
||||
</span>
|
||||
{canEdit && (
|
||||
<button
|
||||
@@ -1209,7 +1209,7 @@ export default function MelodyList() {
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
<tr style={{ backgroundColor: "var(--bg-primary)", borderBottom: "1px solid var(--border-primary)" }}>
|
||||
{activeColumns.map((col) => (
|
||||
|
||||
Reference in New Issue
Block a user