fix(playlists): name the view state in one sentence
Sorting a playlist whose stored order already matches the sort produced a warning, no Save button and no visible change — which reads as a malfunction, not as "there is nothing to save". And when the order DID change, three separate texts piled up in the toolbar (a reset link, a save hint, a "reordering is off" notice), none of which answered the question actually being asked: did I just change my playlist? One line now names which of the three situations you are in — the view matches the saved order, the view differs and can be saved, or a filter is on and saving is impossible — and says in each case that the saved order is untouched. The disabled grip still explains itself on hover and focus, so that notice no longer needs to stand in the toolbar.
This commit is contained in:
@@ -492,6 +492,23 @@ export default function Playlists() {
|
||||
// every render re-subscribed those listeners and re-ran focusModal() under the open player.
|
||||
const closePlayer = useCallback(() => setPlayingId(null), []);
|
||||
|
||||
// Name the current view in the user's terms: "Title ↑", "grouped by channel", or both.
|
||||
const sortLabel = viewSort && !isStoredSort(viewSort)
|
||||
? `${columns.find((c) => c.key === viewSort.key)?.header ?? viewSort.key} ${
|
||||
viewSort.dir === "asc" ? "↑" : "↓"
|
||||
}`
|
||||
: null;
|
||||
const viewName = groupBy
|
||||
? sortLabel
|
||||
? t("playlists.viewGroupedAnd", { sort: sortLabel })
|
||||
: t("playlists.viewGrouped")
|
||||
: (sortLabel ?? "");
|
||||
const viewStatus = filterActive
|
||||
? t("playlists.viewFiltered", { shown: shown.length, total: items.length })
|
||||
: canSaveOrder
|
||||
? t("playlists.viewDiffers", { view: viewName })
|
||||
: t("playlists.viewMatches", { view: viewName });
|
||||
|
||||
// Order matters: a built-in list is never reorderable, whatever the view says.
|
||||
const dragHint = !canEdit
|
||||
? t("playlists.dragBlockedBuiltin")
|
||||
@@ -670,19 +687,19 @@ export default function Playlists() {
|
||||
{canSaveOrder && (
|
||||
<button
|
||||
onClick={saveOrder}
|
||||
aria-describedby="pl-save-hint"
|
||||
className="inline-flex items-center gap-1.5 text-xs font-semibold px-2.5 py-1 rounded-lg border border-accent text-accent hover:bg-accent/10 transition"
|
||||
>
|
||||
<Check className="w-3.5 h-3.5" /> {t("playlists.saveOrder")}
|
||||
</button>
|
||||
)}
|
||||
{canSaveOrder && (
|
||||
<span id="pl-save-hint" className="text-[11px] text-muted/80">
|
||||
{t("playlists.saveOrderHint")}
|
||||
</span>
|
||||
)}
|
||||
{/* ONE sentence that names the state. Three loose texts used to pile up here (reset
|
||||
link + save hint + "reordering is off"), and none of them answered the question a
|
||||
user actually has — "did I just change my playlist?". Worse, sorting a list whose
|
||||
stored order ALREADY matches the sort produced a warning, no Save button and no
|
||||
visible change, which reads as a malfunction. Now the line says which of the three
|
||||
situations you are in; the disabled grip still explains itself on hover/focus. */}
|
||||
{viewActive && (
|
||||
<span className="text-[11px] text-muted/80">{dragHint}</span>
|
||||
<span className="text-[11px] text-muted/80">{viewStatus}</span>
|
||||
)}
|
||||
{canEdit && (
|
||||
<div className="ml-auto">
|
||||
|
||||
@@ -65,7 +65,6 @@
|
||||
"dragBlockedFilter": "Reordering by hand is off while a filter is applied.",
|
||||
"clearView": "Reset view",
|
||||
"saveOrder": "Save this order",
|
||||
"saveOrderHint": "Store the order you see as the playlist's own order (undoable).",
|
||||
"filteredCount": "{{count}} shown",
|
||||
"noneMatchFilter": "No videos match the filter.",
|
||||
"loadFailed": "Couldn't load this playlist.",
|
||||
@@ -79,5 +78,10 @@
|
||||
"dndPickedUp": "Picked up “{{title}}”, position {{pos}} of {{total}}.",
|
||||
"dndMovedOver": "“{{title}}” moved to position {{pos}} of {{total}}.",
|
||||
"dndDropped": "“{{title}}” dropped at position {{pos}} of {{total}}.",
|
||||
"dndCancelled": "Move cancelled; “{{title}}” is back at position {{pos}}."
|
||||
"dndCancelled": "Move cancelled; “{{title}}” is back at position {{pos}}.",
|
||||
"viewGrouped": "grouped by channel",
|
||||
"viewGroupedAnd": "grouped by channel, {{sort}}",
|
||||
"viewDiffers": "Temporary view ({{view}}) — the playlist's saved order is unchanged. Save it to keep this order.",
|
||||
"viewMatches": "This view ({{view}}) already matches the playlist's saved order, so there is nothing to save.",
|
||||
"viewFiltered": "Filtered view — {{shown}} of {{total}} shown. The order can't be saved while a filter is on."
|
||||
}
|
||||
|
||||
@@ -65,7 +65,6 @@
|
||||
"dragBlockedFilter": "A kézi átrendezés ki van kapcsolva, amíg szűrő van érvényben.",
|
||||
"clearView": "Nézet visszaállítása",
|
||||
"saveOrder": "Sorrend mentése",
|
||||
"saveOrderHint": "A látott sorrend legyen a lista saját sorrendje (visszavonható).",
|
||||
"filteredCount": "{{count}} látszik",
|
||||
"noneMatchFilter": "Egy videó sem felel meg a szűrőnek.",
|
||||
"loadFailed": "Nem sikerült betölteni ezt a listát.",
|
||||
@@ -79,5 +78,10 @@
|
||||
"dndPickedUp": "„{{title}}” felvéve, {{pos}}. a(z) {{total}} közül.",
|
||||
"dndMovedOver": "„{{title}}” a(z) {{pos}}. helyre került a(z) {{total}} közül.",
|
||||
"dndDropped": "„{{title}}” letéve a(z) {{pos}}. helyre a(z) {{total}} közül.",
|
||||
"dndCancelled": "Mozgatás megszakítva; „{{title}}” visszakerült a(z) {{pos}}. helyre."
|
||||
"dndCancelled": "Mozgatás megszakítva; „{{title}}” visszakerült a(z) {{pos}}. helyre.",
|
||||
"viewGrouped": "csatorna szerint csoportosítva",
|
||||
"viewGroupedAnd": "csatorna szerint csoportosítva, {{sort}}",
|
||||
"viewDiffers": "Ideiglenes nézet ({{view}}) — a lista mentett sorrendje változatlan. Mentsd, ha ez maradjon.",
|
||||
"viewMatches": "Ez a nézet ({{view}}) megegyezik a lista mentett sorrendjével, így nincs mit menteni.",
|
||||
"viewFiltered": "Szűrt nézet — {{total}} elemből {{shown}} látszik. Szűrés közben a sorrend nem menthető."
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user