update atoms settings style

This commit is contained in:
Pas 2025-06-04 19:05:45 -06:00
parent 5eb15d8fb6
commit c0b97d848c
8 changed files with 94 additions and 43 deletions

View file

@ -498,8 +498,8 @@
"playbackItem": "Playback settings", "playbackItem": "Playback settings",
"audioItem": "Audio", "audioItem": "Audio",
"qualityItem": "Quality", "qualityItem": "Quality",
"sourceItem": "Video sources", "sourceItem": "Source",
"subtitleItem": "Subtitle settings", "subtitleItem": "Subtitles",
"videoSection": "Video settings" "videoSection": "Video settings"
}, },
"sources": { "sources": {
@ -544,6 +544,9 @@
"watchpartyItem": "Watch Party", "watchpartyItem": "Watch Party",
"notice": "Legacy Watch Party might not be available for some sources", "notice": "Legacy Watch Party might not be available for some sources",
"legacyWatchparty": "Use legacy Watch Party" "legacyWatchparty": "Use legacy Watch Party"
},
"audio": {
"default": "Default"
} }
}, },
"metadata": { "metadata": {

View file

@ -77,12 +77,14 @@ function RouterBase(props: { id: string; children: ReactNode }) {
style={dimensions} style={dimensions}
className="overflow-hidden relative z-10 max-h-full" className="overflow-hidden relative z-10 max-h-full"
> >
<Flare.Base className="group w-full bg-video-context-border h-full rounded-2xl transition-colors duration-100 text-video-context-type-main"> <Flare.Base className="group w-full bg-video-context-border bg-opacity-50 backdrop-blur-md h-full rounded-2xl transition-colors duration-100 text-video-context-type-main">
<Flare.Light <Flare.Light
flareSize={400} flareSize={400}
cssColorVar="--colors-video-context-light" cssColorVar="--colors-video-context-light"
backgroundClass="bg-video-context-background duration-100" backgroundClass="bg-video-context-background duration-100"
className="rounded-2xl opacity-100" className="rounded-2xl opacity-80"
gradientOpacity={0.3}
gradientSpread={60}
/> />
<Flare.Child className="pointer-events-auto relative transition-transform duration-100 h-full"> <Flare.Child className="pointer-events-auto relative transition-transform duration-100 h-full">
{props.children} {props.children}

View file

@ -12,7 +12,7 @@ function ButtonList(props: {
onClick: (v: any) => void; onClick: (v: any) => void;
}) { }) {
return ( return (
<div className="flex items-center bg-video-context-buttons-list p-1 rounded-lg"> <div className="flex items-center bg-video-context-light/10 p-1 rounded-lg">
{props.options.map((option) => { {props.options.map((option) => {
return ( return (
<button <button
@ -20,7 +20,7 @@ function ButtonList(props: {
className={classNames( className={classNames(
"w-full px-2 py-1 rounded-md tabbable", "w-full px-2 py-1 rounded-md tabbable",
props.selected === option props.selected === option
? "bg-video-context-buttons-active text-white" ? "bg-video-context-light/20 text-white"
: null, : null,
)} )}
onClick={() => props.onClick(option)} onClick={() => props.onClick(option)}

View file

@ -48,31 +48,57 @@ export function SettingsMenu({ id }: { id: string }) {
return ( return (
<Menu.Card> <Menu.Card>
<Menu.SectionTitle> <Menu.Section grid>
{t("player.menus.settings.videoSection")}
</Menu.SectionTitle>
<Menu.Section>
<Menu.ChevronLink <Menu.ChevronLink
box
onClick={() => router.navigate("/quality")} onClick={() => router.navigate("/quality")}
rightText={currentQuality ? qualityToString(currentQuality) : ""} rightText={currentQuality ? qualityToString(currentQuality) : ""}
> >
{t("player.menus.settings.qualityItem")} {t("player.menus.settings.qualityItem")}
<span className="text-type-secondary">
{currentQuality ? qualityToString(currentQuality) : ""}
</span>
</Menu.ChevronLink> </Menu.ChevronLink>
{currentAudioTrack && ( <Menu.ChevronLink
box
onClick={() => router.navigate("/source")}
rightText={sourceName}
>
{t("player.menus.settings.sourceItem")}
<span className="text-type-secondary">{sourceName}</span>
</Menu.ChevronLink>
<Menu.ChevronLink
box
onClick={() => router.navigate("/captions")}
rightText={sourceName}
>
{t("player.menus.settings.subtitleItem")}
<span className="text-type-secondary">
{selectedLanguagePretty ?? t("player.menus.subtitles.offChoice")}
</span>
</Menu.ChevronLink>
{currentAudioTrack ? (
<Menu.ChevronLink <Menu.ChevronLink
box
onClick={() => router.navigate("/audio")} onClick={() => router.navigate("/audio")}
rightText={selectedAudioLanguagePretty ?? undefined} rightText={selectedAudioLanguagePretty ?? undefined}
> >
{t("player.menus.settings.audioItem")} {t("player.menus.settings.audioItem")}
</Menu.ChevronLink> </Menu.ChevronLink>
) : (
<Menu.ChevronLink
box
onClick={() => router.navigate("/audio")}
disabled
>
{t("player.menus.settings.audioItem")}
<span className="text-type-secondary">
{t("player.menus.audio.default")}
</span>
</Menu.ChevronLink>
)} )}
</Menu.Section>
<Menu.ChevronLink <Menu.Section>
onClick={() => router.navigate("/source")}
rightText={sourceName}
>
{t("player.menus.settings.sourceItem")}
</Menu.ChevronLink>
<Menu.Link <Menu.Link
clickable clickable
onClick={() => onClick={() =>
@ -94,10 +120,7 @@ export function SettingsMenu({ id }: { id: string }) {
{t("player.menus.watchparty.watchpartyItem")} (Beta) {t("player.menus.watchparty.watchpartyItem")} (Beta)
</Menu.Link> </Menu.Link>
</Menu.Section> </Menu.Section>
<Menu.SectionTitle />
<Menu.SectionTitle>
{t("player.menus.settings.experienceSection")}
</Menu.SectionTitle>
<Menu.Section> <Menu.Section>
<Menu.Link <Menu.Link
rightSide={ rightSide={
@ -109,12 +132,6 @@ export function SettingsMenu({ id }: { id: string }) {
> >
{t("player.menus.settings.enableSubtitles")} {t("player.menus.settings.enableSubtitles")}
</Menu.Link> </Menu.Link>
<Menu.ChevronLink
onClick={() => router.navigate("/captions")}
rightText={selectedLanguagePretty ?? undefined}
>
{t("player.menus.settings.subtitleItem")}
</Menu.ChevronLink>
<Menu.ChevronLink onClick={() => router.navigate("/playback")}> <Menu.ChevronLink onClick={() => router.navigate("/playback")}>
{t("player.menus.settings.playbackItem")} {t("player.menus.settings.playbackItem")}
</Menu.ChevronLink> </Menu.ChevronLink>

View file

@ -1,7 +1,7 @@
export function Card(props: { children: React.ReactNode }) { export function Card(props: { children: React.ReactNode }) {
return ( return (
<div className="h-full grid grid-rows-[1fr]"> <div className="h-full grid grid-rows-[1fr]">
<div className="px-6 h-full flex flex-col justify-start overflow-y-auto overflow-x-hidden pb-4"> <div className="px-6 h-full flex flex-col justify-start overflow-y-auto overflow-x-hidden pb-4 scrollbar-none">
{props.children} {props.children}
</div> </div>
</div> </div>

View file

@ -17,11 +17,13 @@ export function Chevron(props: { children?: React.ReactNode }) {
export function LinkTitle(props: { export function LinkTitle(props: {
children: React.ReactNode; children: React.ReactNode;
textClass?: string; textClass?: string;
box?: boolean;
}) { }) {
return ( return (
<span <span
className={classNames([ className={classNames([
"font-medium text-left", "font-medium text-left",
props.box ? "flex flex-col items-center justify-center h-full" : "",
props.textClass || "text-video-context-type-main", props.textClass || "text-video-context-type-main",
])} ])}
> >
@ -78,13 +80,21 @@ export function Link(props: {
onClick?: () => void; onClick?: () => void;
children?: ReactNode; children?: ReactNode;
className?: string; className?: string;
box?: boolean;
disabled?: boolean;
}) { }) {
const classes = classNames("flex py-2 px-3 rounded-lg w-full -ml-3", { const classes = classNames(
"cursor-default": !props.clickable, "flex py-2 transition-colors duration-100 rounded-lg",
"hover:bg-video-context-hoverColor hover:bg-opacity-50 cursor-pointer tabbable": props.box ? "bg-video-context-light/10 h-20" : "",
props.clickable, {
"bg-video-context-hoverColor bg-opacity-50": props.active, "cursor-default": !props.clickable,
}); "hover:bg-video-context-light hover:bg-opacity-20 cursor-pointer tabbable":
props.clickable,
"bg-video-context-light bg-opacity-20": props.active,
"-ml-3 px-3 w-full": !props.box,
"opacity-50 pointer-events-none": props.disabled,
},
);
const styles = { width: "calc(100% + 1.5rem)" }; const styles = { width: "calc(100% + 1.5rem)" };
const content = ( const content = (
@ -110,9 +120,10 @@ export function Link(props: {
<button <button
type="button" type="button"
className={classes} className={classes}
style={styles} style={props.box ? {} : styles}
onClick={props.onClick} onClick={props.onClick}
data-active-link={props.active ? true : undefined} data-active-link={props.active ? true : undefined}
disabled={props.disabled}
> >
{content} {content}
</button> </button>
@ -124,6 +135,8 @@ export function ChevronLink(props: {
onClick?: () => void; onClick?: () => void;
children?: ReactNode; children?: ReactNode;
active?: boolean; active?: boolean;
box?: boolean;
disabled?: boolean;
}) { }) {
const rightContent = <Chevron>{props.rightText}</Chevron>; const rightContent = <Chevron>{props.rightText}</Chevron>;
return ( return (
@ -131,9 +144,12 @@ export function ChevronLink(props: {
onClick={props.onClick} onClick={props.onClick}
active={props.active} active={props.active}
clickable clickable
rightSide={rightContent} rightSide={props.box ? null : rightContent}
className={props.box ? "flex flex-col items-center justify-center" : ""}
box={props.box}
disabled={props.disabled}
> >
<LinkTitle>{props.children}</LinkTitle> <LinkTitle box={props.box}>{props.children}</LinkTitle>
</Link> </Link>
); );
} }
@ -145,6 +161,7 @@ export function SelectableLink(props: {
children?: ReactNode; children?: ReactNode;
disabled?: boolean; disabled?: boolean;
error?: ReactNode; error?: ReactNode;
box?: boolean;
}) { }) {
let rightContent; let rightContent;
if (props.selected) { if (props.selected) {
@ -168,6 +185,7 @@ export function SelectableLink(props: {
onClick={props.onClick} onClick={props.onClick}
clickable={!props.disabled} clickable={!props.disabled}
rightSide={rightContent} rightSide={rightContent}
box={props.box}
> >
<LinkTitle <LinkTitle
textClass={classNames({ textClass={classNames({

View file

@ -2,13 +2,14 @@ import classNames from "classnames";
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
export function SectionTitle(props: { export function SectionTitle(props: {
children: React.ReactNode; children?: React.ReactNode;
className?: string; className?: string;
}) { }) {
return ( return (
<h3 <h3
className={classNames( className={classNames(
"uppercase font-bold text-video-context-type-secondary text-xs pt-8 pl-1 pb-2.5 border-b border-video-context-border", "uppercase font-bold text-type-secondary text-xs pl-1 pb-2.5 border-b border-type-secondary/40",
props.children ? "pt-8" : "pt-4",
props.className, props.className,
)} )}
> >
@ -20,9 +21,15 @@ export function SectionTitle(props: {
export function Section(props: { export function Section(props: {
children: React.ReactNode; children: React.ReactNode;
className?: string; className?: string;
grid?: boolean;
}) { }) {
return ( return (
<div className={classNames("pt-4 space-y-1", props.className)}> <div
className={classNames(
props.grid ? "grid grid-cols-2 gap-3 pt-6" : "pt-4 space-y-1",
props.className,
)}
>
{props.children} {props.children}
</div> </div>
); );

View file

@ -8,6 +8,8 @@ export interface FlareProps {
flareSize?: number; flareSize?: number;
cssColorVar?: string; cssColorVar?: string;
enabled?: boolean; enabled?: boolean;
gradientOpacity?: number;
gradientSpread?: number;
} }
const SIZE_DEFAULT = 200; const SIZE_DEFAULT = 200;
@ -38,6 +40,8 @@ function Light(props: FlareProps) {
const outerRef = useRef<HTMLDivElement>(null); const outerRef = useRef<HTMLDivElement>(null);
const size = props.flareSize ?? SIZE_DEFAULT; const size = props.flareSize ?? SIZE_DEFAULT;
const cssVar = props.cssColorVar ?? CSS_VAR_DEFAULT; const cssVar = props.cssColorVar ?? CSS_VAR_DEFAULT;
const opacity = props.gradientOpacity ?? 1;
const spread = props.gradientSpread ?? 70;
useEffect(() => { useEffect(() => {
function mouseMove(e: MouseEvent) { function mouseMove(e: MouseEvent) {
@ -69,7 +73,7 @@ function Light(props: FlareProps) {
}, },
)} )}
style={{ style={{
backgroundImage: `radial-gradient(circle at center, rgba(var(${cssVar}) / 1), rgba(var(${cssVar}) / 0) 70%)`, backgroundImage: `radial-gradient(circle at center, rgba(var(${cssVar}) / ${opacity}), rgba(var(${cssVar}) / 0) ${spread}%)`,
backgroundPosition: `var(--bg-x) var(--bg-y)`, backgroundPosition: `var(--bg-x) var(--bg-y)`,
backgroundRepeat: "no-repeat", backgroundRepeat: "no-repeat",
backgroundSize: `${size.toFixed(0)}px ${size.toFixed(0)}px`, backgroundSize: `${size.toFixed(0)}px ${size.toFixed(0)}px`,
@ -85,7 +89,7 @@ function Light(props: FlareProps) {
<div <div
className="absolute inset-0 opacity-10" className="absolute inset-0 opacity-10"
style={{ style={{
background: `radial-gradient(circle at center, rgba(var(${cssVar}) / 1), rgba(var(${cssVar}) / 0) 70%)`, backgroundImage: `radial-gradient(circle at center, rgba(var(${cssVar}) / ${opacity}), rgba(var(${cssVar}) / 0) ${spread}%)`,
backgroundPosition: `var(--bg-x) var(--bg-y)`, backgroundPosition: `var(--bg-x) var(--bg-y)`,
backgroundRepeat: "no-repeat", backgroundRepeat: "no-repeat",
backgroundSize: `${size.toFixed(0)}px ${size.toFixed(0)}px`, backgroundSize: `${size.toFixed(0)}px ${size.toFixed(0)}px`,