Skip to content

Commit

Permalink
feat: Preset Menu Dropdown
Browse files Browse the repository at this point in the history
Next to Profiles/Presets, there is a dropdown
Currently the only option is delete preset, however "Rename Preset" will likely be added soon
  • Loading branch information
beebls committed Jul 2, 2023
1 parent 132a2a8 commit df29fa3
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 27 deletions.
15 changes: 15 additions & 0 deletions backend/backendHelpers/deletePreset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Theme } from "ThemeTypes";
import { changePreset } from "./changePreset";
import { deleteTheme } from "backend/pythonMethods";

export async function deletePreset(
presetName: string,
themes: Theme[],
refreshThemes: (e?: boolean) => void
) {
if (themes.find((e) => e.name === presetName)!.enabled) {
await changePreset("Default Profile", themes);
}
await deleteTheme(presetName);
refreshThemes();
}
1 change: 1 addition & 0 deletions backend/backendHelpers/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./changePreset";
export * from "./deletePreset";
7 changes: 5 additions & 2 deletions components/ManageThemes/YourProfilesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ManageThemeCard } from "./ManageThemeCard";
import { themeContext } from "@contexts/themeContext";
import { LocalThemeStatus } from "@pages/manage-themes";
import { Flags, MinimalCSSThemeInfo, Theme } from "ThemeTypes";
import { deletePreset } from "backend";

export function YourProfilesList({
updateStatuses,
Expand All @@ -15,7 +16,7 @@ export function YourProfilesList({
handleUninstall: (e: Theme) => void;
handleUpdate: (e: MinimalCSSThemeInfo) => void;
}) {
const { themes } = useContext(themeContext);
const { themes, refreshThemes } = useContext(themeContext);
const userChangeablePresets = themes.filter(
(e) => e.flags.includes(Flags.isPreset) && e.name !== "Default Profile"
);
Expand All @@ -32,7 +33,9 @@ export function YourProfilesList({
themeData={e}
updateStatuses={updateStatuses}
uninstalling={uninstalling}
handleUninstall={handleUninstall}
handleUninstall={(e: Theme) => {
deletePreset(e.name, themes, refreshThemes);
}}
handleUpdate={handleUpdate}
/>
))}
Expand Down
80 changes: 56 additions & 24 deletions components/Presets/PresetSelectionDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,71 @@
import { useContext, useMemo, useState } from "react";
import { CreatePresetModal, RadioDropdown } from "..";
import { CreatePresetModal, RadioDropdown, Tooltip } from "..";
import { themeContext } from "@contexts/themeContext";
import { Flags } from "ThemeTypes";
import { changePreset, setThemeState } from "backend";
import { changePreset, deletePreset, setThemeState } from "backend";
import { MenuDropdown } from "@components/Primitives/MenuDropdown";
import { BiTrash } from "react-icons/bi";
import { twMerge } from "tailwind-merge";

export function PresetSelectionDropdown() {
const { themes, refreshThemes } = useContext(themeContext);
const { themes, refreshThemes, selectedPreset } = useContext(themeContext);
const presets = useMemo(() => themes.filter((e) => e.flags.includes(Flags.isPreset)), [themes]);
const [showModal, setShowModal] = useState(false);

console.log(showModal);
console.log(selectedPreset?.name);

return (
<>
{showModal && <CreatePresetModal closeModal={() => setShowModal(false)} />}
<RadioDropdown
triggerClass="bg-base-5.5-dark"
headingText="Selected Profile"
ariaLabel="Profile Selection Dropdown"
value={presets.find((e) => e.enabled)?.name || "Default Profile"}
options={[
// This just ensures that default profile is the first result
"Default Profile",
...presets.map((e) => e.name).filter((e) => e !== "Default Profile"),
"New Profile",
]}
onValueChange={async (e) => {
if (e === "New Profile") {
setShowModal(true);
return;
<div className="flex w-full items-center justify-center gap-4">
{showModal && <CreatePresetModal closeModal={() => setShowModal(false)} />}
<RadioDropdown
triggerClass="bg-base-5.5-dark"
headingText="Selected Profile"
ariaLabel="Profile Selection Dropdown"
// value={presets.find((e) => e.enabled)?.name || "Default Profile"}
value={selectedPreset?.name || "Default Profile"}
options={[
// This just ensures that default profile is the first result
"Default Profile",
...presets.map((e) => e.name).filter((e) => e !== "Default Profile"),
"New Profile",
]}
onValueChange={async (e) => {
if (e === "New Profile") {
setShowModal(true);
return;
}
await changePreset(e, themes);
refreshThemes();
}}
/>
<Tooltip
content="You cannot edit the default profile."
delayDuration={500}
align="end"
disabled={selectedPreset?.name !== "Default Profile"}
triggerRootClass="self-end"
triggerContent={
<MenuDropdown
triggerDisabled={selectedPreset?.name === "Default Profile"}
align="end"
options={[
{
displayText: "Delete Theme",
icon: <BiTrash size={20} />,
onSelect: async () => {
deletePreset(selectedPreset!.name, themes, refreshThemes);
},
},
]}
triggerClass={twMerge(
"h-12 w-12 self-end rounded-xl border-2 border-borders-base1-dark bg-base-5.5-dark transition-all hover:border-borders-base2-dark",
selectedPreset?.name === "Default Profile" && "opacity-50"
)}
/>
}
await changePreset(e, themes);
refreshThemes();
}}
/>
/>
</div>
</>
);
}
70 changes: 70 additions & 0 deletions components/Primitives/MenuDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
import { ReactNode, useContext } from "react";
import { twMerge } from "tailwind-merge";
import { GiHamburgerMenu } from "react-icons/gi";
import { fontContext } from "@contexts/FontContext";

export function MenuDropdown({
options,
triggerClass = "",
align = "center",
triggerDisabled = false,
}: {
options: {
disabled?: boolean;
displayText: string;
icon: ReactNode;
onSelect: () => void;
}[];
triggerClass?: string;
triggerDisabled?: boolean;
align?: "center" | "start" | "end";
}) {
const { montserrat } = useContext(fontContext);
return (
<DropdownMenu.Root>
<DropdownMenu.Trigger
disabled={triggerDisabled}
className={twMerge(
"flex h-fit w-12 select-none items-center justify-center gap-2 rounded-full border border-borders-base3-dark px-4 py-2 text-xs font-bold text-white transition duration-150",
!triggerDisabled && "hover:scale-95 hover:bg-base-3-dark hover:active:scale-90",
triggerClass
)}
>
<GiHamburgerMenu size={16} />
</DropdownMenu.Trigger>

<DropdownMenu.Portal>
<div className={`dark text-white ${montserrat}`}>
<DropdownMenu.Content
align={align}
className="radio-dropdown font-fancy z-[9999] w-[250px] cursor-default select-none overflow-hidden rounded-xl border-2 border-borders-base2-light bg-base-3-light text-sm text-black transition-all dark:border-borders-base2-dark dark:bg-base-3-dark dark:text-white"
>
{options.map((e) => {
return (
<DropdownMenu.Item
disabled={e.disabled}
key={e.displayText}
onSelect={e.onSelect}
className="relative m-1 flex items-center justify-center rounded-lg px-4 py-2 outline-none hover:bg-brandBlue focus:bg-brandBlue dark:hover:bg-brandBlue dark:focus:bg-brandBlue"
>
<div className="flex w-full items-center justify-between gap-2">
<span
className={twMerge(
"flex w-fit items-center font-semibold",
e.disabled ? "text-textFadedLight dark:text-textFadedDark" : ""
)}
>
{e.displayText}
</span>
{e.icon}
</div>
</DropdownMenu.Item>
);
})}
</DropdownMenu.Content>
</div>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
}
7 changes: 6 additions & 1 deletion components/Primitives/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export function Tooltip({
arrow = false,
disabled = false,
content,
triggerRootClass = "",
align = "center",
}: {
triggerContent: ReactElement;
delayDuration?: number;
Expand All @@ -18,6 +20,8 @@ export function Tooltip({
disabled?: boolean;
arrow?: boolean;
content: ReactElement | string;
triggerRootClass?: string;
align?: "center" | "end" | "start";
}) {
const { montserrat } = useContext(fontContext);
const [open, setOpen] = useState(false);
Expand All @@ -28,10 +32,11 @@ export function Tooltip({
onOpenChange={(open) => !disabled && setOpen(open)}
delayDuration={delayDuration}
>
<RadixTooltip.Trigger>{triggerContent}</RadixTooltip.Trigger>
<RadixTooltip.Trigger className={triggerRootClass}>{triggerContent}</RadixTooltip.Trigger>
<RadixTooltip.Portal>
<div className={`dark ${montserrat} font-fancy`}>
<RadixTooltip.Content
align="end"
side={tooltipSide}
className={twMerge(
"font-fancy rounded-xl bg-fore-3-light p-2 px-4 text-black dark:bg-fore-3-dark dark:text-white",
Expand Down
1 change: 1 addition & 0 deletions components/Primitives/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from "./Modal";
export * from "./AlertDialog";
export * from "./Tooltip";
export * from "./ToggleSwitch";
export * from "./MenuDropdown";

0 comments on commit df29fa3

Please sign in to comment.