Skip to content

Commit 7efe63d

Browse files
Refine dashboard settings and demo surfaces
1 parent 06bb835 commit 7efe63d

File tree

14 files changed

+502
-175
lines changed

14 files changed

+502
-175
lines changed

src/app.css

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
:root {
66
color-scheme: dark;
77
--shell-gutter: 1.5rem;
8+
--font-body: "IBM Plex Sans", sans-serif;
9+
--font-accent: "Space Grotesk", var(--font-body);
810
--bg: #0c1219;
911
--bg-elevated: #121923;
1012
--panel: rgba(18, 20, 26, 0.86);
@@ -77,7 +79,7 @@ body {
7779
margin: 0;
7880
min-height: 100vh;
7981
color: var(--text);
80-
font-family: "IBM Plex Sans", sans-serif;
82+
font-family: var(--font-body);
8183
background: transparent;
8284
position: relative;
8385
isolation: isolate;
@@ -165,7 +167,7 @@ h3,
165167
h4,
166168
h5,
167169
h6 {
168-
font-family: "Space Grotesk", sans-serif;
170+
font-family: var(--font-accent);
169171
letter-spacing: -0.03em;
170172
}
171173

src/components/overlay-settings-panel.tsx

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -325,22 +325,19 @@ export function OverlaySettingsPanel() {
325325
<CardHeader>
326326
<CardTitle>Layout and behavior</CardTitle>
327327
</CardHeader>
328-
<CardContent className="grid gap-4">
328+
<CardContent className="overflow-hidden border border-(--border) p-0">
329329
<ToggleRow
330330
label="Show creator"
331-
description="Show creator"
332331
checked={form.overlayShowCreator}
333332
onChange={(value) => setBoolean("overlayShowCreator", value)}
334333
/>
335334
<ToggleRow
336335
label="Show album"
337-
description="Show album"
338336
checked={form.overlayShowAlbum}
339337
onChange={(value) => setBoolean("overlayShowAlbum", value)}
340338
/>
341339
<ToggleRow
342340
label="Animate now playing"
343-
description="Animate current song"
344341
checked={form.overlayAnimateNowPlaying}
345342
onChange={(value) =>
346343
setBoolean("overlayAnimateNowPlaying", value)
@@ -353,7 +350,7 @@ export function OverlaySettingsPanel() {
353350
<CardHeader>
354351
<CardTitle>Theme</CardTitle>
355352
</CardHeader>
356-
<CardContent className="grid gap-4">
353+
<CardContent className="overflow-hidden border border-(--border) p-0">
357354
<ColorField
358355
label="Accent"
359356
value={form.overlayAccentColor}
@@ -380,8 +377,8 @@ export function OverlaySettingsPanel() {
380377
onChange={(value) => setColor("overlayPanelColor", value)}
381378
/>
382379
<ColorField
383-
label="Overlay background / chroma key"
384-
description="Use a normal visible background, or pick a deliberate key color like bright pink or green for OBS chroma key."
380+
label="Background color"
381+
description="For a transparent background, set background opacity to 0."
385382
value={form.overlayBackgroundColor}
386383
onChange={(value) =>
387384
setColor("overlayBackgroundColor", value)
@@ -399,10 +396,10 @@ export function OverlaySettingsPanel() {
399396
<CardHeader>
400397
<CardTitle>Density and sizing</CardTitle>
401398
</CardHeader>
402-
<CardContent className="grid gap-4">
399+
<CardContent className="overflow-hidden border border-(--border) p-0">
403400
<RangeField
404401
label="Overlay background opacity"
405-
description="Set this to 0 for a fully transparent page behind the playlist items."
402+
description="Set this to 0 for a fully transparent background behind the playlist items."
406403
min={0}
407404
max={100}
408405
value={form.overlayBackgroundOpacity}
@@ -557,24 +554,24 @@ export function OverlaySettingsPanel() {
557554

558555
function ToggleRow(props: {
559556
label: string;
560-
description: string;
557+
description?: string;
561558
checked: boolean;
562559
onChange: (value: boolean) => void;
563560
}) {
564561
return (
565-
<label className="flex items-start justify-between gap-4 border border-(--border) bg-(--panel-soft) p-4">
566-
<div>
562+
<label className="grid gap-2 px-4 py-3 odd:bg-(--panel-soft) even:bg-(--panel-muted)">
563+
<div className="flex items-center justify-between gap-4">
567564
<p className="font-medium text-(--text)">{props.label}</p>
568-
<p className="mt-1 text-sm leading-7 text-(--muted)">
569-
{props.description}
570-
</p>
565+
<input
566+
type="checkbox"
567+
checked={props.checked}
568+
onChange={(event) => props.onChange(event.target.checked)}
569+
className="h-5 w-5 shrink-0"
570+
/>
571571
</div>
572-
<input
573-
type="checkbox"
574-
checked={props.checked}
575-
onChange={(event) => props.onChange(event.target.checked)}
576-
className="mt-1 h-5 w-5"
577-
/>
572+
{props.description ? (
573+
<p className="text-sm leading-6 text-(--muted)">{props.description}</p>
574+
) : null}
578575
</label>
579576
);
580577
}
@@ -586,23 +583,27 @@ function ColorField(props: {
586583
onChange: (value: string) => void;
587584
}) {
588585
return (
589-
<div className="grid gap-2 border border-(--border) bg-(--panel-soft) p-4">
590-
<p className="text-sm font-medium text-(--text)">{props.label}</p>
586+
<div className="grid gap-2 px-4 py-3 odd:bg-(--panel-soft) even:bg-(--panel-muted)">
587+
<div className="flex flex-wrap items-center justify-between gap-3">
588+
<p className="text-sm font-medium text-(--text)">{props.label}</p>
589+
<div className="flex min-w-0 items-center gap-3 sm:w-auto">
590+
<input
591+
type="color"
592+
value={props.value}
593+
onChange={(event) => props.onChange(event.target.value)}
594+
className="h-10 w-12 shrink-0 border border-(--border) bg-transparent"
595+
/>
596+
<div className="w-full sm:w-44">
597+
<Input
598+
value={props.value}
599+
onChange={(event) => props.onChange(event.target.value)}
600+
/>
601+
</div>
602+
</div>
603+
</div>
591604
{props.description ? (
592605
<p className="text-sm leading-6 text-(--muted)">{props.description}</p>
593606
) : null}
594-
<div className="flex items-center gap-3">
595-
<input
596-
type="color"
597-
value={props.value}
598-
onChange={(event) => props.onChange(event.target.value)}
599-
className="h-11 w-14 border border-(--border) bg-transparent"
600-
/>
601-
<Input
602-
value={props.value}
603-
onChange={(event) => props.onChange(event.target.value)}
604-
/>
605-
</div>
606607
</div>
607608
);
608609
}
@@ -616,21 +617,26 @@ function RangeField(props: {
616617
onChange: (value: number) => void;
617618
}) {
618619
return (
619-
<div className="grid gap-3 border border-(--border) bg-(--panel-soft) p-4">
620+
<div className="grid gap-2 px-4 py-3 odd:bg-(--panel-soft) even:bg-(--panel-muted)">
620621
<div className="flex items-center justify-between gap-3">
621622
<p className="text-sm font-medium text-(--text)">{props.label}</p>
622-
<span className="text-sm text-(--muted)">{props.value}</span>
623+
<div className="flex items-center justify-between gap-3">
624+
<span className="text-xs font-semibold uppercase tracking-[0.16em] text-(--muted)">
625+
Value
626+
</span>
627+
<span className="text-sm text-(--text)">{props.value}</span>
628+
</div>
623629
</div>
624-
{props.description ? (
625-
<p className="text-sm leading-6 text-(--muted)">{props.description}</p>
626-
) : null}
627630
<input
628631
type="range"
629632
min={props.min}
630633
max={props.max}
631634
value={props.value}
632635
onChange={(event) => props.onChange(Number(event.target.value))}
633636
/>
637+
{props.description ? (
638+
<p className="text-sm leading-6 text-(--muted)">{props.description}</p>
639+
) : null}
634640
</div>
635641
);
636642
}

src/components/song-search-panel.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ export function SongSearchPanel(props: {
957957
{song.title}
958958
</p>
959959
{isDisabled ? (
960-
<span className="inline-flex items-center border border-amber-400/35 bg-amber-500/12 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.16em] text-amber-100">
960+
<span className="inline-flex items-center border border-amber-700/50 bg-amber-950 px-2 py-[3px] text-xs font-semibold uppercase tracking-[0.16em] text-amber-100">
961961
{disabledReason}
962962
</span>
963963
) : null}
@@ -979,29 +979,29 @@ export function SongSearchPanel(props: {
979979
<PathBadge
980980
label="Lead"
981981
shortLabel="L"
982-
className="border-emerald-400/30 bg-emerald-500/10 text-emerald-300 hover:bg-emerald-500/10"
982+
className="border-emerald-700/50 bg-emerald-950 text-emerald-100 hover:bg-emerald-950"
983983
/>
984984
) : null}
985985
{song.parts?.includes("rhythm") ? (
986986
<PathBadge
987987
label="Rhythm"
988988
shortLabel="R"
989-
className="border-sky-400/30 bg-sky-500/10 text-sky-300 hover:bg-sky-500/10"
989+
className="border-sky-700/50 bg-sky-950 text-sky-100 hover:bg-sky-950"
990990
/>
991991
) : null}
992992
{song.parts?.includes("bass") ? (
993993
<PathBadge
994994
label="Bass"
995995
shortLabel="B"
996-
className="border-orange-400/30 bg-orange-500/10 text-orange-300 hover:bg-orange-500/10"
996+
className="border-orange-700/50 bg-orange-950 text-orange-100 hover:bg-orange-950"
997997
/>
998998
) : null}
999999
{song.parts?.includes("voice") ||
10001000
song.parts?.includes("vocals") ? (
10011001
<PathBadge
10021002
label="Lyrics"
10031003
shortLabel="V"
1004-
className="border-violet-400/30 bg-violet-500/10 text-violet-300 hover:bg-violet-500/10"
1004+
className="border-violet-700/50 bg-violet-950 text-violet-100 hover:bg-violet-950"
10051005
/>
10061006
) : null}
10071007
</div>
@@ -1029,7 +1029,7 @@ export function SongSearchPanel(props: {
10291029
{song.title}
10301030
</p>
10311031
{isDisabled ? (
1032-
<span className="inline-flex items-center border border-amber-400/35 bg-amber-500/12 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.16em] text-amber-100">
1032+
<span className="inline-flex items-center border border-amber-700/50 bg-amber-950 px-2 py-[3px] text-xs font-semibold uppercase tracking-[0.16em] text-amber-100">
10331033
{disabledReason}
10341034
</span>
10351035
) : null}
@@ -1051,29 +1051,29 @@ export function SongSearchPanel(props: {
10511051
<PathBadge
10521052
label="Lead"
10531053
shortLabel="L"
1054-
className="border-emerald-400/30 bg-emerald-500/10 text-emerald-300 hover:bg-emerald-500/10"
1054+
className="border-emerald-700/50 bg-emerald-950 text-emerald-100 hover:bg-emerald-950"
10551055
/>
10561056
) : null}
10571057
{song.parts?.includes("rhythm") ? (
10581058
<PathBadge
10591059
label="Rhythm"
10601060
shortLabel="R"
1061-
className="border-sky-400/30 bg-sky-500/10 text-sky-300 hover:bg-sky-500/10"
1061+
className="border-sky-700/50 bg-sky-950 text-sky-100 hover:bg-sky-950"
10621062
/>
10631063
) : null}
10641064
{song.parts?.includes("bass") ? (
10651065
<PathBadge
10661066
label="Bass"
10671067
shortLabel="B"
1068-
className="border-orange-400/30 bg-orange-500/10 text-orange-300 hover:bg-orange-500/10"
1068+
className="border-orange-700/50 bg-orange-950 text-orange-100 hover:bg-orange-950"
10691069
/>
10701070
) : null}
10711071
{song.parts?.includes("voice") ||
10721072
song.parts?.includes("vocals") ? (
10731073
<PathBadge
10741074
label="Lyrics"
10751075
shortLabel="V"
1076-
className="border-violet-400/30 bg-violet-500/10 text-violet-300 hover:bg-violet-500/10"
1076+
className="border-violet-700/50 bg-violet-950 text-violet-100 hover:bg-violet-950"
10771077
/>
10781078
) : null}
10791079
</div>
@@ -1152,14 +1152,14 @@ function PathBadge(props: {
11521152
function getPathToneByValue(value: string) {
11531153
switch (value.toLowerCase()) {
11541154
case "lead":
1155-
return "border-emerald-400/30 bg-emerald-500/10 text-emerald-300";
1155+
return "border-emerald-700/50 bg-emerald-950 text-emerald-100";
11561156
case "rhythm":
1157-
return "border-sky-400/30 bg-sky-500/10 text-sky-300";
1157+
return "border-sky-700/50 bg-sky-950 text-sky-100";
11581158
case "bass":
1159-
return "border-orange-400/30 bg-orange-500/10 text-orange-300";
1159+
return "border-orange-700/50 bg-orange-950 text-orange-100";
11601160
case "voice":
11611161
case "vocals":
1162-
return "border-violet-400/30 bg-violet-500/10 text-violet-300";
1162+
return "border-violet-700/50 bg-violet-950 text-violet-100";
11631163
default:
11641164
return "border-(--border-strong) bg-(--panel) text-(--text)";
11651165
}

src/components/ui/badge.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type * as React from "react";
33
import { cn } from "~/lib/utils";
44

55
const badgeVariants = cva(
6-
"inline-flex select-none items-center rounded-none px-2.5 py-1 text-[11px] font-semibold uppercase tracking-[0.18em]",
6+
"inline-flex select-none items-center rounded-none px-2 py-[3px] text-xs font-semibold [font-family:var(--font-accent)] uppercase tracking-[0.16em]",
77
{
88
variants: {
99
variant: {

src/components/ui/button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as React from "react";
44
import { cn } from "~/lib/utils";
55

66
const buttonVariants = cva(
7-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-none border text-sm font-medium transition-[background,color,border-color,box-shadow,transform] duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--brand) focus-visible:ring-offset-2 focus-visible:ring-offset-(--bg) disabled:cursor-not-allowed disabled:opacity-50 active:translate-y-px",
7+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-none border text-sm font-medium [font-family:var(--font-accent)] uppercase tracking-[0.08em] transition-[background,color,border-color,box-shadow,transform] duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--brand) focus-visible:ring-offset-2 focus-visible:ring-offset-(--bg) disabled:cursor-not-allowed disabled:opacity-50 active:translate-y-px",
88
{
99
variants: {
1010
variant: {

src/components/ui/label.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ const Label = React.forwardRef<
88
>(({ className, ...props }, ref) => (
99
<LabelPrimitive.Root
1010
ref={ref}
11-
className={cn("text-sm font-medium text-(--text)", className)}
11+
className={cn(
12+
"text-sm font-medium [font-family:var(--font-accent)] uppercase tracking-[0.08em] text-(--text)",
13+
className
14+
)}
1215
{...props}
1316
/>
1417
));

src/components/ui/tabs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function TabsTrigger({
6363
<TabsPrimitive.Trigger
6464
data-slot="tabs-trigger"
6565
className={cn(
66-
"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-none border border-oklch(0.923 0.003 48.717) border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap text-oklch(0.147 0.004 49.25)/60 transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start hover:text-oklch(0.147 0.004 49.25) focus-visible:border-oklch(0.709 0.01 56.259) focus-visible:ring-[3px] focus-visible:ring-oklch(0.709 0.01 56.259)/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none dark:text-oklch(0.553 0.013 58.071) dark:hover:text-oklch(0.147 0.004 49.25) [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:border-oklch(1 0 0 / 10%) dark:text-oklch(0.985 0.001 106.423)/60 dark:hover:text-oklch(0.985 0.001 106.423) dark:focus-visible:border-oklch(0.553 0.013 58.071) dark:focus-visible:ring-oklch(0.553 0.013 58.071)/50 dark:dark:text-oklch(0.709 0.01 56.259) dark:dark:hover:text-oklch(0.985 0.001 106.423)",
66+
"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-none border border-oklch(0.923 0.003 48.717) border-transparent px-2 py-1 text-sm font-medium [font-family:var(--font-accent)] uppercase tracking-[0.08em] whitespace-nowrap text-oklch(0.147 0.004 49.25)/60 transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start hover:text-oklch(0.147 0.004 49.25) focus-visible:border-oklch(0.709 0.01 56.259) focus-visible:ring-[3px] focus-visible:ring-oklch(0.709 0.01 56.259)/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none dark:text-oklch(0.553 0.013 58.071) dark:hover:text-oklch(0.147 0.004 49.25) [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:border-oklch(1 0 0 / 10%) dark:text-oklch(0.985 0.001 106.423)/60 dark:hover:text-oklch(0.985 0.001 106.423) dark:focus-visible:border-oklch(0.553 0.013 58.071) dark:focus-visible:ring-oklch(0.553 0.013 58.071)/50 dark:dark:text-oklch(0.709 0.01 56.259) dark:dark:hover:text-oklch(0.985 0.001 106.423)",
6767
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
6868
"data-[state=active]:bg-oklch(1 0 0) data-[state=active]:text-oklch(0.147 0.004 49.25) dark:data-[state=active]:border-oklch(0.923 0.003 48.717) dark:data-[state=active]:bg-oklch(0.923 0.003 48.717)/30 dark:data-[state=active]:text-oklch(0.147 0.004 49.25) dark:data-[state=active]:bg-oklch(0.147 0.004 49.25) dark:data-[state=active]:text-oklch(0.985 0.001 106.423) dark:dark:data-[state=active]:border-oklch(1 0 0 / 15%) dark:dark:data-[state=active]:bg-oklch(1 0 0 / 15%)/30 dark:dark:data-[state=active]:text-oklch(0.985 0.001 106.423)",
6969
"after:absolute after:bg-oklch(0.147 0.004 49.25) after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100 dark:after:bg-oklch(0.985 0.001 106.423)",

0 commit comments

Comments
 (0)