Skip to content

Commit 92436f8

Browse files
authored
feat: add dynamic select for effects (#24)
Instead having a circle for each effect, would be easier to just have a Select field. Since this select is dynamic, it won't fit on the current Select made by @moovmooov, so we implemented a `DynamicSelect` for this exceptional case (which can happen in the future). ![image](https://github.com/user-attachments/assets/f2c02086-8f01-4658-8e30-585e12121e15)
1 parent 64cdcc6 commit 92436f8

16 files changed

+185
-88
lines changed

lefthook.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ pre-commit:
99
parallel: false
1010
commands:
1111
lint:
12-
run: pnpx @biomejs/biome check --no-errors-on-unmatched --files-ignore-unknown=true -- {staged_files}
12+
run: pnpx @biomejs/biome@1.8.3 check --no-errors-on-unmatched --files-ignore-unknown=true -- {staged_files}
1313
pre-push:
1414
parallel: false
1515
commands:
1616
lint:
17-
run: pnpx @biomejs/biome check --no-errors-on-unmatched --files-ignore-unknown=true -- {push_files}
17+
run: pnpx @biomejs/biome@1.8.3 check --no-errors-on-unmatched --files-ignore-unknown=true -- {push_files}

locales/en/messages.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,8 @@
139139
},
140140
"pronounsItIts": {
141141
"message": "It/Its"
142+
},
143+
"effectsLabel": {
144+
"message": "Select your effect"
142145
}
143146
}

locales/pt_BR/messages.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,5 +154,8 @@
154154
},
155155
"themes": {
156156
"message": "Temas"
157+
},
158+
"effectsLabel": {
159+
"message": "Selecione um Efeito"
157160
}
158161
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"identity",
7777
"*://*.twitch.tv/*",
7878
"https://*.danielheart.dev/*",
79+
"https://*.basementdevs.com.br/*",
7980
"*://localhost/*",
8081
"storage"
8182
]

pnpm-lock.yaml

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

src/components/effect-customize.tsx

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import DynamicSelect from "@/components/ui/dynamic-select";
2+
import SelectField from "@/components/ui/select-field";
13
import { useUserSettings } from "@/hooks/use-user-settings";
24
import { useAccessToken } from "@/providers/access-token-provider";
35
import { usePatchUserSettingsMutation } from "@/services/settings-service";
46
import type { Effect } from "@/types/types";
7+
import { PRONOUNS_ITEMS } from "@/utils/pronouns";
58
import { useStorage } from "@plasmohq/storage/hook";
69
import { Check } from "lucide-react";
710

@@ -21,7 +24,12 @@ const EffectCustomize = ({
2124
const { activeSettings } = useUserSettings(liveProfile, channelName);
2225

2326
const effectList = effects || [];
24-
27+
console.log(effectList);
28+
const mappedEffects = effectList.map((effect) => ({
29+
name: effect.name,
30+
apiValue: effect.id.toString(),
31+
}));
32+
console.log(mappedEffects);
2533
const handleChange = (key: string, value: number | undefined) => {
2634
mutate({
2735
authorization: accessToken,
@@ -34,22 +42,16 @@ const EffectCustomize = ({
3442

3543
return (
3644
<div className="flex space-x-4">
37-
{effectList.map((effect) => (
38-
<div key={effect.id} className="relative">
39-
<button
40-
type="button"
41-
className={`w-8 h-8 rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-white
42-
${activeSettings?.effect_id === effect.id ? "ring-2 ring-white" : ""}`}
43-
style={{ backgroundColor: effect.hex ?? "#000" }}
44-
onClick={() => handleChange("effect_id", effect.id)}
45-
/>
46-
{activeSettings?.effect_id === effect.id && (
47-
<div className="absolute -top-1 -right-1 bg-icon-high border-helper-outline rounded-full p-0.5">
48-
<Check size={12} className="text-elevation-surface font-bold" />
49-
</div>
50-
)}
51-
</div>
52-
))}
45+
<DynamicSelect
46+
id="effects"
47+
label="effectsLabel"
48+
items={mappedEffects}
49+
value={activeSettings?.effect_id.toString()}
50+
onChange={(effect) =>
51+
handleChange("effect_id", Number.parseInt(effect))
52+
}
53+
disabled={!activeSettings?.enabled}
54+
/>
5355
</div>
5456
);
5557
};

src/components/ui/chat-appearance.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { env } from "@/config/env";
22
import { useUserSettings } from "@/hooks/use-user-settings";
33
import type UserStorageService from "@/services/user/user-storage-service";
4+
import { cn } from "@/utils/cn";
45
import { t } from "@/utils/i18n";
56

67
type ChatAppearanceProps = {
@@ -34,7 +35,12 @@ export default function ChatAppearance({
3435
alt="Occupation icon"
3536
className="rounded"
3637
/>
37-
<span className="font-bold text-gray text-xs">
38+
<span
39+
className={cn(
40+
"font-bold text-gray text-xs",
41+
activeSettings?.effect.class_name,
42+
)}
43+
>
3844
{userService.user.name}
3945
</span>
4046
<span className="font-medium text-text-low text-xs">
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { t } from "@/utils/i18n";
2+
import { ChevronDown } from "lucide-react";
3+
import React, { useState, type MutableRefObject } from "react";
4+
5+
type DynamicSelectProps = {
6+
id: string;
7+
label: string;
8+
items: { name: string; apiValue: string }[];
9+
value?: string;
10+
disabled?: boolean;
11+
onChange: (value: string) => void;
12+
children?: React.ReactNode;
13+
};
14+
15+
const DynamicSelect = React.forwardRef<HTMLSelectElement, DynamicSelectProps>(
16+
({ id, label, items, value, onChange, disabled, children }, ref) => {
17+
return (
18+
<div className="flex flex-col gap-3 w-full">
19+
<div className="flex flex-row gap-x-5 items-center">
20+
<label className="font-medium text-text-high" htmlFor={id}>
21+
{t(label)}
22+
</label>
23+
</div>
24+
<div className="relative">
25+
<select
26+
ref={ref as MutableRefObject<HTMLSelectElement>}
27+
id={id}
28+
onChange={(e) => onChange(e.target.value)}
29+
value={value}
30+
className="flex w-full items-center justify-between px-4 py-2 border border-helper-outline hover:border-icon-medium focus:border-primary-600 focus:outline-none font-medium bg-elevation-surface rounded-md appearance-none pr-10 disabled:cursor-not-allowed disabled:opacity-50"
31+
disabled={disabled}
32+
>
33+
{items.map(({ name, apiValue }) => (
34+
<option
35+
key={name}
36+
value={apiValue}
37+
className="bg-helper-outline font-primary text-text-medium focus:border-primary-600"
38+
>
39+
{name}
40+
</option>
41+
))}
42+
</select>
43+
<ChevronDown
44+
size="16"
45+
className="absolute right-3 top-1/2 transform -translate-y-1/2 pointer-events-none text-icon-medium"
46+
/>
47+
</div>
48+
</div>
49+
);
50+
},
51+
);
52+
53+
DynamicSelect.displayName = "DynamicSelect";
54+
55+
export default DynamicSelect;

src/components/ui/select-field.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ type SelectFieldProps = {
99
value?: string;
1010
disabled?: boolean;
1111
onChange: (value: string) => void;
12+
children?: React.ReactNode;
1213
};
1314

1415
const SelectField = React.forwardRef<HTMLSelectElement, SelectFieldProps>(
15-
({ id, label, items, value, onChange, disabled }, ref) => {
16+
({ id, label, items, value, onChange, disabled, children }, ref) => {
1617
return (
1718
<div className="flex flex-col gap-3 w-full">
1819
<div className="flex flex-row gap-x-5 items-center">

0 commit comments

Comments
 (0)