feat(player): a roomier YouTube player, its panel shut on demand
- The full-height previous/next strips beside the card are gone: the panel's transport row and Shift+arrows step on their own, and the video gains the 7rem the strips' gutters took. - Close is one icon in the card's top-right corner (the wide panel's head, the stacked card's title row). - The panel's description is cut to three lines with More / Less (ClampedText now takes the linked text as children). - Wide, the panel shuts to a 2.75rem strip (close, open, previous, next) for a bigger video; it stays shut while the queue steps on, and a video opened from a card starts it open. Focus moves to the counterpart toggle. - The wheel has one meaning per place: over a panel (or the stacked card) with something to scroll it only scrolls, never falling through to the volume at the end; over the video, or a panel that fits, it is the volume. - A long channel name is cut on the panel's line instead of running the 20rem panel into a sideways scroll.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useLayoutEffect, useRef, useState } from "react";
|
||||
import { useLayoutEffect, useRef, useState, type ReactNode } from "react";
|
||||
import { Button } from "./Button";
|
||||
|
||||
// Static class names, so Tailwind sees them.
|
||||
@@ -8,19 +8,25 @@ const CLAMP = { 3: "line-clamp-3", 5: "line-clamp-5", 8: "line-clamp-8" } as con
|
||||
* when the text is actually cut — measured, so a short text carries no dead button. Re-measured on a
|
||||
* resize: the window and the text-size slider both move where the cut falls. Another text starts
|
||||
* collapsed: a view reused for the next item (a show page opening another show) must not open its
|
||||
* text already expanded. */
|
||||
* text already expanded. `children` draws the text in a richer form (a description's links and
|
||||
* timestamps); `text` still names it, so another text is still another text. */
|
||||
export function ClampedText({
|
||||
text,
|
||||
lines,
|
||||
moreLabel,
|
||||
lessLabel,
|
||||
className,
|
||||
textClassName = "measure whitespace-pre-line text-sm leading-relaxed text-muted",
|
||||
children,
|
||||
}: {
|
||||
text: string;
|
||||
lines: keyof typeof CLAMP;
|
||||
moreLabel: string;
|
||||
lessLabel: string;
|
||||
className?: string;
|
||||
/** The text box's own dress (the default: a summary's muted paragraph). */
|
||||
textClassName?: string;
|
||||
children?: ReactNode;
|
||||
}) {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [clipped, setClipped] = useState(false);
|
||||
@@ -29,7 +35,7 @@ export function ClampedText({
|
||||
setShown(text);
|
||||
setExpanded(false);
|
||||
}
|
||||
const ref = useRef<HTMLParagraphElement>(null);
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
useLayoutEffect(() => {
|
||||
const el = ref.current;
|
||||
if (!el || expanded) return;
|
||||
@@ -41,12 +47,9 @@ export function ClampedText({
|
||||
}, [text, expanded]);
|
||||
return (
|
||||
<div className={className}>
|
||||
<p
|
||||
ref={ref}
|
||||
className={`measure whitespace-pre-line text-sm leading-relaxed text-muted ${expanded ? "" : CLAMP[lines]}`}
|
||||
>
|
||||
{text}
|
||||
</p>
|
||||
<div ref={ref} className={`${textClassName} ${expanded ? "" : CLAMP[lines]}`}>
|
||||
{children ?? text}
|
||||
</div>
|
||||
{(clipped || expanded) && (
|
||||
<Button
|
||||
variant="link"
|
||||
|
||||
@@ -24,7 +24,6 @@ const PLAIN: Record<string, [number, string]> = {
|
||||
"LanguageSwitcher.tsx": [1, "an option row"],
|
||||
"NavSidebar.tsx": [4, "the account trigger and its menu rows"],
|
||||
"PaletteLauncher.tsx": [2, "launcher controls"],
|
||||
"PlayerModal.tsx": [2, "previous / next arrows"],
|
||||
"PlaylistsRail.tsx": [1, "the load-error retry"],
|
||||
"PlexCollectionEditor.tsx": [1, "a checkbox row in a picker"],
|
||||
"PlexInfo.tsx": [1, "the rating filter (a number)"],
|
||||
|
||||
Reference in New Issue
Block a user