Skip to content

Commit 3071aba

Browse files
committed
add tooltips, add custom styling for select, fix height scaling
1 parent dd0a809 commit 3071aba

File tree

12 files changed

+175
-97
lines changed

12 files changed

+175
-97
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"dependencies": {
1313
"@astrojs/react": "^4.4.0",
1414
"@headlessui/react": "^2.2.9",
15+
"@heroicons/react": "^2.2.0",
1516
"@tailwindcss/vite": "^4.1.14",
1617
"@types/react": "^19.2.2",
1718
"@types/react-dom": "^19.2.1",

pnpm-lock.yaml

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/settings/SettingsCategory.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ export function SettingsCategory({ category }) {
3030
</Tab>
3131
))}
3232
</TabList>
33-
<TabPanels className="h-full flex-4">
33+
<TabPanels className="flex-4 h-full">
3434
{category.groups.map((group) => (
35-
<TabPanel key={group.name}>
35+
<TabPanel key={group.name} className="h-full">
3636
<SettingsGroup key={group.name} group={group} />
3737
</TabPanel>
3838
))}
Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
1+
import { useState } from "react";
12
import { SettingsItem } from "./SettingsItem";
23

3-
44
export function SettingsGroup({ group }) {
5+
const [tooltip, setTooltip] = useState("");
6+
57
return (
6-
<div className="SettingsView-group">
7-
{group.settings.map((setting) => <SettingsItem key={setting.id} setting={setting} />)}
8+
<div className="SettingsView-group-container">
9+
<div className="SettingsView-group">
10+
{group.settings.map((setting) => (
11+
<SettingsItem
12+
key={setting.id}
13+
setting={setting}
14+
setTooltip={setTooltip}
15+
/>
16+
))}
17+
</div>
18+
<div className="Settingsview-group-sidebar px-4 py-3">
19+
<p className="text-white text-2xl tf2-light">{tooltip}</p>
20+
</div>
821
</div>
922
);
1023
}

src/components/settings/SettingsItem.tsx

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,23 @@ import { SettingsHeader } from "./controls/SettingsHeader";
44
import { SettingsSelect } from "./controls/SettingsSelect";
55
import { SettingsSlider } from "./controls/SettingsSlider";
66

7-
export function SettingsItem({ setting }) {
8-
return (
9-
<div key={setting.id} className="mb-4">
10-
{setting.type === "check" && (
11-
<SettingsCheck setting={setting} />
12-
)}
13-
{setting.type === "slider" && (
14-
<SettingsSlider setting={setting} />
15-
)}
16-
{setting.type === "select" && (
17-
<SettingsSelect setting={setting} />
18-
)}
19-
{setting.type === "header" && (
20-
<SettingsHeader setting={setting} />
21-
)}
22-
{setting.type === "button" && (
23-
<SettingsButton setting={setting} />
24-
)}
25-
</div>
26-
)
27-
}
7+
export function SettingsItem({ setting, setTooltip }) {
8+
return (
9+
<div
10+
key={setting.id}
11+
className="mb-4"
12+
onMouseOver={() => {
13+
setTooltip(setting.tooltip ?? "");
14+
}}
15+
onMouseOut={() => {
16+
setTooltip("");
17+
}}
18+
>
19+
{setting.type === "check" && <SettingsCheck setting={setting} />}
20+
{setting.type === "slider" && <SettingsSlider setting={setting} />}
21+
{setting.type === "select" && <SettingsSelect setting={setting} />}
22+
{setting.type === "header" && <SettingsHeader setting={setting} />}
23+
{setting.type === "button" && <SettingsButton setting={setting} />}
24+
</div>
25+
);
26+
}

src/components/settings/SettingsView.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,19 @@
1919
overflow-x: hidden;
2020
scrollbar-color: #b4b4b4 #292526;
2121
}
22+
.SettingsView-group-container {
23+
height: 100%;
24+
display: flex;
25+
flex-direction: row;
26+
}
2227
.SettingsView-group {
2328
padding-top: 1rem;
2429
overflow-y: auto;
2530
overflow-x: hidden;
2631
height: 100%;
2732
scrollbar-color: #b4b4b4 #292526;
33+
flex: 1;
34+
}
35+
.Settingsview-group-sidebar {
36+
width: 33%;
2837
}

src/components/settings/SettingsView.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ export function SettingsView() {
1818
const [selectedIndex, setSelectedIndex] = useState(0);
1919

2020
return (
21-
<div className="SettingsView-background p-8 rounded-lg shadow-lg mx-auto">
21+
<div className="SettingsView-background p-8 rounded-lg shadow-lg mx-auto dark">
2222
<h1 className="text-5xl text-center SettingsView-main-title mb-4">Options</h1>
23-
<TabGroup className="flex flex-col flex-1" onChange={(index) => setSelectedIndex(index)}>
23+
<TabGroup className="flex flex-col flex-1 h-0" onChange={(index) => setSelectedIndex(index)}>
2424
<TabList className="flex justify-center space-x-4 tf2-bold text-2xl">
2525
{tabs.map((tab, index) => (
2626
<Tab
@@ -36,7 +36,7 @@ export function SettingsView() {
3636
</Tab>
3737
))}
3838
</TabList>
39-
<TabPanels className="flex-1">
39+
<TabPanels className="flex-1 h-0">
4040
{settingsData.categories.map((category) => (
4141
<TabPanel key={category.name} className="mt-6 h-full">
4242
<SettingsCategory key={category.name} category={category} />
Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
import { runRpc } from "@/util/ws";
2-
import { useEffect, useState } from "react";
2+
import { useEffect, useMemo, useState } from "react";
3+
import {
4+
Label,
5+
Listbox,
6+
ListboxButton,
7+
ListboxOption,
8+
ListboxOptions,
9+
} from "@headlessui/react";
10+
import { ChevronDownIcon } from "@heroicons/react/20/solid";
311

412
export function SettingsSelect({ setting }) {
513
const [value, setValue] = useState(0);
614

15+
const selectedOption = useMemo(() => {
16+
return setting.options.find((o) => o.value === value.toString());
17+
}, [value, setting.options]);
18+
719
useEffect(() => {
820
runRpc("getcvar", setting.cvar).then((response) => {
921
if (response !== null && response.length > 0) {
@@ -19,16 +31,47 @@ export function SettingsSelect({ setting }) {
1931

2032
return (
2133
<div>
22-
<label className="block mb-2 text-white tf2-light text-xl">
23-
{setting.label}
24-
</label>
25-
<select className="px-4 py-2 mb-2 border text-white" value={value} onChange={(ev) => callback(ev.target.value)}>
26-
{setting.options.map((option) => (
27-
<option key={option.value} value={option.value} selected={option.value === value}>
28-
{option.label}
29-
</option>
30-
))}
31-
</select>
34+
<Listbox value={value.toString()} onChange={callback}>
35+
<Label className="block mb-2 text-white tf2-light text-xl">
36+
{setting.label}
37+
</Label>
38+
<div className="relative mt-2">
39+
<div className="inline-flex divide-x divide-stone-700 outline-hidden dark:divide-stone-600">
40+
<ListboxButton className="cursor-default inline-flex items-center gap-x-4 bg-stone-600 px-3 py-2 text-white dark:bg-stone-500 hover:bg-stone-700 focus-visible:outline-1 focus-visible:outline-stone-400 dark:bg-stone-500 dark:hover:bg-stone-400 dark:focus-visible:outline-stone-400">
41+
<p className="text-lg tf2-light font-semibold">
42+
{selectedOption?.label ?? "\u00A0"}
43+
</p>
44+
<ChevronDownIcon aria-hidden="true" className="size-5 text-white forced-colors:text-[Highlight]" />
45+
</ListboxButton>
46+
</div>
47+
48+
<ListboxOptions
49+
transition
50+
className="tf2-light absolute mt-1 max-h-76 z-10 mt-2 origin-top-right divide-y divide-gray-200 overflow-y-auto overflow-x-hidden bg-white shadow-lg outline-1 outline-black/5 data-leave:transition data-leave:duration-100 data-leave:ease-in data-closed:data-leave:opacity-0 dark:divide-white/10 dark:bg-stone-800 dark:shadow-none dark:-outline-offset-1 dark:outline-white/10"
51+
>
52+
{setting.options.map((option) => (
53+
<ListboxOption
54+
key={option.value}
55+
value={option.value}
56+
className="group cursor-default p-4 text-lg text-gray-900 select-none data-focus:bg-stone-600 data-focus:text-white dark:text-white dark:data-focus:bg-stone-500"
57+
>
58+
<div className="flex flex-col">
59+
<div className="flex justify-between">
60+
<p className="font-normal group-data-selected:font-semibold">
61+
{option.label}
62+
</p>
63+
</div>
64+
{option.tooltip && (
65+
<p className="mt-2 text-gray-500 group-data-focus:text-stone-200 dark:text-gray-400 dark:group-data-focus:text-stone-100">
66+
{option.tooltip}
67+
</p>
68+
)}
69+
</div>
70+
</ListboxOption>
71+
))}
72+
</ListboxOptions>
73+
</div>
74+
</Listbox>
3275
</div>
3376
);
3477
}

src/components/settings/controls/SettingsSlider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function SettingsSlider({ setting }) {
2222
<label className="mb-2 text-white tf2-light text-xl">
2323
{setting.label}
2424
</label>
25-
<div className="flex flex-row justify-between items-center w-2/5">
25+
<div className="flex flex-row justify-between items-center w-3/5">
2626
<input
2727
className="me-4 flex-1"
2828
type="range"

0 commit comments

Comments
 (0)