Theming working

This commit is contained in:
Sean Edmunds
2024-08-16 15:38:30 -05:00
parent a37ab84f65
commit 44d2405a1d
13 changed files with 4712 additions and 4496 deletions

99
package-lock.json generated
View File

@@ -17,8 +17,11 @@
"@mantine/modals": "^7.12.1",
"@tabler/icons-react": "^3.12.0",
"@tanstack/react-query": "^5.51.23",
"@tanstack/react-query-devtools": "^4.36.1",
"@tanstack/react-query-persist-client": "^5.51.23",
"clsx": "^2.1.1",
"dayjs": "^1.11.12",
"idb-keyval": "^6.2.1",
"jotai": "^2.9.3",
"mantine-react-table": "^2.0.0-beta.6",
"react": "^18.3.1",
@@ -1531,6 +1534,18 @@
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@tanstack/query-persist-client-core": {
"version": "5.51.21",
"resolved": "https://registry.npmjs.org/@tanstack/query-persist-client-core/-/query-persist-client-core-5.51.21.tgz",
"integrity": "sha512-W/H3SFIMPjxgiwkrl511pG2JhvKnFWtLCgO+AlNqk9keyClMbm9tb3oLUHveLuzviCaROpmFShW+eSP5zYwk4g==",
"dependencies": {
"@tanstack/query-core": "5.51.21"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@tanstack/react-query": {
"version": "5.51.23",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.51.23.tgz",
@@ -1546,6 +1561,41 @@
"react": "^18.0.0"
}
},
"node_modules/@tanstack/react-query-devtools": {
"version": "4.36.1",
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.36.1.tgz",
"integrity": "sha512-WYku83CKP3OevnYSG8Y/QO9g0rT75v1om5IvcWUwiUZJ4LanYGLVCZ8TdFG5jfsq4Ej/lu2wwDAULEUnRIMBSw==",
"dependencies": {
"@tanstack/match-sorter-utils": "^8.7.0",
"superjson": "^1.10.0",
"use-sync-external-store": "^1.2.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"@tanstack/react-query": "^4.36.1",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@tanstack/react-query-persist-client": {
"version": "5.51.23",
"resolved": "https://registry.npmjs.org/@tanstack/react-query-persist-client/-/react-query-persist-client-5.51.23.tgz",
"integrity": "sha512-SwTNwxhG4zgpji3B8oLZqZuaOXYtOjbuqVerMQkOX/vGroIU6dGh1SzOwy4glW3IVr+G3kUKMcS3JYibWPQZiQ==",
"dependencies": {
"@tanstack/query-persist-client-core": "5.51.21"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"@tanstack/react-query": "^5.51.23",
"react": "^18 || ^19"
}
},
"node_modules/@tanstack/react-table": {
"version": "8.19.3",
"resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.19.3.tgz",
@@ -2120,6 +2170,20 @@
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true
},
"node_modules/copy-anything": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
"integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
"dependencies": {
"is-what": "^4.1.8"
},
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@@ -2843,6 +2907,11 @@
"react-is": "^16.7.0"
}
},
"node_modules/idb-keyval": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
"integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
},
"node_modules/ignore": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
@@ -2956,6 +3025,17 @@
"node": ">=8"
}
},
"node_modules/is-what": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
"integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -3896,6 +3976,17 @@
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
},
"node_modules/superjson": {
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/superjson/-/superjson-1.13.3.tgz",
"integrity": "sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg==",
"dependencies": {
"copy-anything": "^3.0.2"
},
"engines": {
"node": ">=10"
}
},
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -4128,6 +4219,14 @@
}
}
},
"node_modules/use-sync-external-store": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
"integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/vite": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz",

View File

@@ -19,8 +19,11 @@
"@mantine/modals": "^7.12.1",
"@tabler/icons-react": "^3.12.0",
"@tanstack/react-query": "^5.51.23",
"@tanstack/react-query-devtools": "^4.36.1",
"@tanstack/react-query-persist-client": "^5.51.23",
"clsx": "^2.1.1",
"dayjs": "^1.11.12",
"idb-keyval": "^6.2.1",
"jotai": "^2.9.3",
"mantine-react-table": "^2.0.0-beta.6",
"react": "^18.3.1",

View File

@@ -31,15 +31,7 @@ function App() {
defaultValue: "blackboard",
});
const [currentTheme, setCurrentTheme] = useState<any>({});
const overrides = createTheme({
white: currentTheme.colorbackground,
fontFamily:
"-apple-system,Jost,BlinkMacSystemFont,Helvetica Neue,Roboto,sans-serif",
});
const mantineTheme = mergeMantineTheme(DEFAULT_THEME, overrides);
const [currentTheme, setCurrentTheme] = useState<any>(undefined);
useEffect(() => {
if (data && themeName) {
@@ -60,6 +52,14 @@ function App() {
),
);
const overrides = createTheme({
white: currentTheme?.colorbackground,
fontFamily:
"-apple-system,Jost,BlinkMacSystemFont,Helvetica Neue,Roboto,sans-serif",
});
const mantineTheme = mergeMantineTheme(DEFAULT_THEME, overrides);
return (
<MantineProvider theme={mantineTheme}>
{currentTheme && (

View File

@@ -1,15 +1,61 @@
import { MantineReactTable, useMantineReactTable } from "mantine-react-table";
import {
MantineReactTable,
MRT_Row,
MRT_TableOptions,
useMantineReactTable,
} from "mantine-react-table";
import { memo } from "react";
import "../dataTableStyles.css";
import { ActionIcon, Button, Flex, Text, Tooltip } from "@mantine/core";
import { FiPlus } from "react-icons/fi";
import { IconEdit, IconTrash } from "@tabler/icons-react";
import { useMutationAPI } from "../hooks/useAPI";
import { modals } from "@mantine/modals";
export function DataTableComponent({
tableName,
columns,
tableData,
isFetching,
isLoading,
onCreatingRowSave,
onEditingRowSave,
}: any) {
endpoint,
}: {
tableName: string;
columns: any;
tableData: any;
isFetching: boolean;
isLoading: boolean;
endpoint: string;
}) {
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
const { mutateAsync: deleteRow, isPending: isDeletingRow } = useMutationAPI();
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
exitCreatingMode,
}) => {
createRow({ method: "POST", endpoint: endpoint, body: values });
exitCreatingMode();
};
const handleEditRow: MRT_TableOptions<any>["onEditingRowSave"] = async ({
values,
table,
}) => {
editRow({ method: "PATCH", endpoint: endpoint, body: values });
table.setEditingRow(null);
};
const openDeleteConfirmModal = (row: MRT_Row<any>) =>
modals.openConfirmModal({
title: "Are you sure you want to delete this user?",
children: <Text>Are you sure?</Text>,
labels: { confirm: "Delete", cancel: "Cancel" },
confirmProps: { color: "red" },
onConfirm: () =>
deleteRow({ method: "DELETE", endpoint: endpoint, body: row.original }),
});
const table = useMantineReactTable({
columns: columns,
data: tableData,
@@ -21,8 +67,8 @@ export function DataTableComponent({
editDisplayMode: "row",
enableBottomToolbar: false,
enableToolbarInternalActions: false,
onCreatingRowSave: onCreatingRowSave,
onEditingRowSave: onEditingRowSave,
onCreatingRowSave: handleCreateRow,
onEditingRowSave: handleEditRow,
getRowId: (row: any) => row.id,
initialState: {
showProgressBars: isFetching,
@@ -47,6 +93,27 @@ export function DataTableComponent({
borderLeft: "none",
},
},
renderRowActions: ({ row, table }) => (
<Flex gap="md">
<Tooltip label="Edit">
<ActionIcon onClick={() => table.setEditingRow(row)}>
<IconEdit />
</ActionIcon>
</Tooltip>
<Tooltip label="Delete">
<ActionIcon color="red" onClick={() => openDeleteConfirmModal(row)}>
<IconTrash />
</ActionIcon>
</Tooltip>
</Flex>
),
renderTopToolbarCustomActions: ({ table }) => {
return (
<Button onClick={() => table.setCreatingRow(true)}>
<FiPlus />
</Button>
);
},
});
return <MantineReactTable table={table} />;
}

View File

@@ -49,6 +49,7 @@ export default function Search() {
return (
<Stack
style={{
height: "100px",
backgroundColor: "transparent",
textAlign: "center",
position: "relative",

View File

@@ -1,11 +1,10 @@
import { useEffect, useState } from "react";
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
import { useQueryAPI } from "../../../hooks/useAPI";
import { DataTable } from "../../../DataTable/DataTable";
import { toast } from "react-toastify";
import type { MRT_TableOptions } from "mantine-react-table";
import ApplicationColumns from "../../../DataTable/columns/ApplicationColumns";
import { Stack, Text } from "@mantine/core";
import { textClasses } from "../../../styles";
const ApplicationSettings = () => {
const endpoint = "api/apps";
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
@@ -13,34 +12,12 @@ const ApplicationSettings = () => {
});
const [applicationData, setApplicationData] = useState<any>([]);
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
useEffect(() => {
if (isFetched) {
setApplicationData(data);
}
});
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
exitCreatingMode,
}) => {
createRow({ method: "POST", endpoint: endpoint, body: values }).then(() => {
toast.success("Application created successfully");
});
exitCreatingMode();
};
const handleEditRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
table,
}) => {
editRow({ method: "PATCH", endpoint: endpoint, body: values }).then(() => {
toast.success("Application updated successfully");
});
table.setEditingRow(null);
};
return (
<Stack>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
@@ -52,8 +29,7 @@ const ApplicationSettings = () => {
tableData={applicationData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
endpoint={endpoint}
/>
</Stack>
);

View File

@@ -1,8 +1,6 @@
import { useEffect, useState } from "react";
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
import { useQueryAPI } from "../../../hooks/useAPI";
import { DataTable } from "../../../DataTable/DataTable";
import { toast } from "react-toastify";
import type { MRT_TableOptions } from "mantine-react-table";
import { Stack, Text } from "@mantine/core";
import BookmarkColumns from "../../../DataTable/columns/BookmarkColumns";
import { textClasses } from "../../../styles";
@@ -20,8 +18,6 @@ const BookmarkSettings = () => {
const [bookmarkData, setBookmarkData] = useState<any>([]);
const [groups, setGroups] = useState([]);
const [fullyFetched, setFullyFetched] = useState(false);
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
useEffect(() => {
if (isFetched) {
@@ -39,25 +35,6 @@ const BookmarkSettings = () => {
}
}, [groupDataisFetched]);
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
exitCreatingMode,
}) => {
createRow({ method: "POST", endpoint: endpoint, body: values }).then(() => {
toast.success("Application created successfully");
});
exitCreatingMode();
};
const handleEditRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
table,
}) => {
editRow({ method: "PATCH", endpoint: endpoint, body: values }).then(() => {
toast.success("Application updated successfully");
});
table.setEditingRow(null);
};
return (
<Stack>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
@@ -69,8 +46,7 @@ const BookmarkSettings = () => {
tableData={bookmarkData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
endpoint={endpoint}
/>
</Stack>
);

View File

@@ -1,8 +1,6 @@
import { useEffect, useState } from "react";
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
import { useQueryAPI } from "../../../hooks/useAPI";
import { DataTable } from "../../../DataTable/DataTable";
import { toast } from "react-toastify";
import type { MRT_TableOptions } from "mantine-react-table";
import CategoryColumns from "../../../DataTable/columns/CategoryColumns";
import { Stack, Text } from "@mantine/core";
import { textClasses } from "../../../styles";
@@ -13,34 +11,12 @@ const CategorySettings = () => {
});
const [categoryData, setCategoryData] = useState<any>([]);
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
useEffect(() => {
if (isFetched) {
setCategoryData(data);
}
});
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
exitCreatingMode,
}) => {
createRow({ method: "POST", endpoint: endpoint, body: values }).then(() => {
toast.success("Category created successfully");
});
exitCreatingMode();
};
const handleEditRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
table,
}) => {
editRow({ method: "PATCH", endpoint: endpoint, body: values }).then(() => {
toast.success("Category updated successfully");
});
table.setEditingRow(null);
};
return (
<Stack>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
@@ -52,8 +28,7 @@ const CategorySettings = () => {
tableData={categoryData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
endpoint={endpoint}
/>
</Stack>
);

View File

@@ -1,8 +1,6 @@
import { useEffect, useState } from "react";
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
import { useQueryAPI } from "../../../hooks/useAPI";
import { DataTable } from "../../../DataTable/DataTable";
import { toast } from "react-toastify";
import type { MRT_TableOptions } from "mantine-react-table";
import MessagesColumns from "../../../DataTable/columns/MessagesColumns";
import { Stack, Text } from "@mantine/core";
import { textClasses } from "../../../styles";
@@ -13,34 +11,12 @@ const MessageSettings = () => {
});
const [messageData, setMessageData] = useState<any>([]);
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
useEffect(() => {
if (isFetched) {
setMessageData(data);
}
});
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
exitCreatingMode,
}) => {
createRow({ method: "POST", endpoint: endpoint, body: values }).then(() => {
toast.success("Message created successfully");
});
exitCreatingMode();
};
const handleEditRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
table,
}) => {
editRow({ method: "PATCH", endpoint: endpoint, body: values }).then(() => {
toast.success("Message updated successfully");
});
table.setEditingRow(null);
};
return (
<Stack>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
@@ -52,8 +28,7 @@ const MessageSettings = () => {
tableData={messageData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
endpoint={endpoint}
/>
</Stack>
);

View File

@@ -1,9 +1,7 @@
import { useEffect, useState } from "react";
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
import { useQueryAPI } from "../../../hooks/useAPI";
import { DataTable } from "../../../DataTable/DataTable";
import PersonalizationColumns from "../../../DataTable/columns/PersonalizationColumns";
import { toast } from "react-toastify";
import type { MRT_TableOptions } from "mantine-react-table";
import { textClasses } from "../../../styles";
import { Text } from "@mantine/core";
const PersonalizationSettings = () => {
@@ -13,34 +11,12 @@ const PersonalizationSettings = () => {
});
const [personalData, setPersonalData] = useState<any>([]);
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
useEffect(() => {
if (isFetched) {
setPersonalData(data);
}
});
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
exitCreatingMode,
}) => {
createRow({ method: "POST", endpoint: endpoint, body: values }).then(() => {
toast.success("Personalization created successfully");
});
exitCreatingMode();
};
const handleEditRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
table,
}) => {
editRow({ method: "PATCH", endpoint: endpoint, body: values }).then(() => {
toast.success("Personalization updated successfully");
});
table.setEditingRow(null);
};
return (
<>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
@@ -52,8 +28,7 @@ const PersonalizationSettings = () => {
tableData={personalData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
endpoint={endpoint}
/>
</>
);

View File

@@ -1,8 +1,6 @@
import { useEffect, useState } from "react";
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
import { useQueryAPI } from "../../../hooks/useAPI";
import { DataTable } from "../../../DataTable/DataTable";
import { toast } from "react-toastify";
import type { MRT_TableOptions } from "mantine-react-table";
import SearchProviderColumns from "../../../DataTable/columns/SearchProviderColumns";
import { Stack, Text } from "@mantine/core";
import { textClasses } from "../../../styles";
@@ -13,34 +11,12 @@ const SearchProviderSettings = () => {
});
const [providerData, setProviderData] = useState<any>([]);
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
useEffect(() => {
if (isFetched) {
setProviderData(data);
}
});
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
exitCreatingMode,
}) => {
createRow({ method: "POST", endpoint: endpoint, body: values }).then(() => {
toast.success("Search provider created successfully");
});
exitCreatingMode();
};
const handleEditRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
values,
table,
}) => {
editRow({ method: "PATCH", endpoint: endpoint, body: values }).then(() => {
toast.success("Search provider updated successfully");
});
table.setEditingRow(null);
};
return (
<Stack>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
@@ -52,8 +28,7 @@ const SearchProviderSettings = () => {
tableData={providerData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
endpoint={endpoint}
/>
</Stack>
);

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import { useQueryAPI } from "../../../hooks/useAPI";
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
import {
ActionIcon,
Button,
@@ -7,22 +7,27 @@ import {
ColorPicker,
ColorSwatch,
Divider,
Grid,
Group,
Modal,
SimpleGrid,
Stack,
Text,
TextInput,
} from "@mantine/core";
import { FiEdit } from "react-icons/fi";
import { FiEdit, FiPlus, FiSave, FiTrash, FiX } from "react-icons/fi";
import { useDisclosure, useLocalStorage } from "@mantine/hooks";
import "@mantine/core/styles/ModalBase.css";
import "@mantine/core/styles/Modal.css";
import { actionIconClasses, modalClasses, textClasses } from "../../../styles";
import ThemeModalContent from "./ThemeModalContent";
import { modals } from "@mantine/modals";
function ThemesSettings({ theme }: any) {
const [opened, { open, close }] = useDisclosure(false);
const [pickerOpen, { open: openPicker, close: closePicker }] = useDisclosure(false);
const [colorValue, onChange] = useState('#000000');
const [pickerOpen, { open: openPicker, close: closePicker }] =
useDisclosure(false);
const [colorId, setColorId] = useState<string>("");
const [colorValue, setColorValue] = useState("#000000");
const [value, setValue] = useLocalStorage<any>({
key: "theme",
defaultValue: {},
@@ -32,6 +37,10 @@ function ThemesSettings({ theme }: any) {
});
const [themesList, setThemesList] = useState([]);
const [selectedTheme, setSelectedTheme] = useState<any>({});
const { mutateAsync: createTheme, isPending: isCreatingTheme } =
useMutationAPI();
const { mutateAsync: deleteTheme, isPending: isDeletingTheme } =
useMutationAPI();
useEffect(() => {
if (isFetched) {
setThemesList(data);
@@ -48,6 +57,29 @@ function ThemesSettings({ theme }: any) {
closePicker();
};
const handleSaveTheme = () => {
createTheme({
method: selectedTheme.id === undefined ? "POST" : "PATCH",
endpoint: "api/themes",
body: selectedTheme,
});
close();
};
const openDeleteConfirmModal = (theme: any) =>
modals.openConfirmModal({
title: "Are you sure you want to delete this theme?",
labels: { confirm: "Delete", cancel: "Cancel" },
confirmProps: { color: "red" },
onConfirm: () =>
deleteTheme({ method: "DELETE", endpoint: "api/themes", body: theme }),
});
const handleDeleteTheme = (theme: any) => {
openDeleteConfirmModal(theme);
close();
};
return (
<>
<Modal.Root
@@ -73,55 +105,206 @@ function ThemesSettings({ theme }: any) {
<Modal.Body p={"2rem"}>
<ThemeModalContent selectedTheme={selectedTheme} />
<Divider color="black" my="sm" />
<TextInput
label="Theme Name"
value={selectedTheme.name}
onChange={(e) =>
setSelectedTheme({ ...selectedTheme, name: e.target.value })
}
styles={{
label: {
color: "black",
},
input: {
color: "black",
backgroundColor: "white",
},
}}
/>
<Divider color="black" my="sm" />
<Group w={"100%"} h={"100%"} gap={0}>
<Stack w={"50%"}>
<Group c={'black'} justify="space-between">
<Group c={"black"} justify="space-between">
<Text>Primary Color</Text>
<ColorSwatch onClick={openPicker} radius={"sm"} w={"100px"} color={selectedTheme.colortextpri} />
<ColorSwatch
onClick={() => {
setColorId("primary");
openPicker();
setColorValue(selectedTheme.colortextpri);
}}
radius={"sm"}
w={"100px"}
color={selectedTheme.colortextpri}
style={{ cursor: "pointer" }}
/>
</Group>
<Group c={'black'} justify="space-between">
<Group c={"black"} justify="space-between">
<Text>Accent Color</Text>
<ColorSwatch radius={"sm"} w={"100px"} color={selectedTheme.colortextacc} />
<ColorSwatch
onClick={() => {
setColorId("accent");
openPicker();
setColorValue(selectedTheme.colortextacc);
}}
radius={"sm"}
w={"100px"}
color={selectedTheme.colortextacc}
style={{ cursor: "pointer" }}
/>
</Group>
<Group c={'black'} justify="space-between">
<Group c={"black"} justify="space-between">
<Text>Background Color</Text>
<ColorSwatch radius={"sm"} w={"100px"} color={selectedTheme.colorbackground} />
<ColorSwatch
onClick={() => {
setColorId("background");
openPicker();
setColorValue(selectedTheme.colorbackground);
}}
radius={"sm"}
w={"100px"}
color={selectedTheme.colorbackground}
style={{ cursor: "pointer" }}
/>
</Group>
<Group c={'black'} justify="space-between">
<Group c={"black"} justify="space-between">
<Text>Border Color</Text>
<ColorSwatch radius={"sm"} w={"100px"} color={selectedTheme.colorborder} />
<ColorSwatch
onClick={() => {
setColorId("border");
openPicker();
setColorValue(selectedTheme.colorborder);
}}
radius={"sm"}
w={"100px"}
color={selectedTheme.colorborder}
style={{ cursor: "pointer" }}
/>
</Group>
<Group c={'black'} justify="space-between">
<Group c={"black"} justify="space-between">
<Text>Search Background Color</Text>
<ColorSwatch radius={"sm"} w={"100px"} color={selectedTheme.colorsearchbackground} />
<ColorSwatch
onClick={() => {
setColorId("searchbackground");
openPicker();
setColorValue(selectedTheme.colorsearchbackground);
}}
radius={"sm"}
w={"100px"}
color={selectedTheme.colorsearchbackground}
style={{ cursor: "pointer" }}
/>
</Group>
</Stack>
<Stack h={"100%"} w={'50%'} align="center" justify="center">
<Stack h={"100%"} w={"50%"} align="center" justify="center">
{pickerOpen ? (
<>
<ColorPicker value={colorValue} onChange={onChange}/>
<Group><Text c={'black'}>{colorValue}</Text><Button onClick={() => {setSelectedTheme({ ...selectedTheme, colorbackground: colorValue }); closePicker();}} c={'white'} bg={'forestgreen'}>Save</Button></Group>
<ColorPicker value={colorValue} onChange={setColorValue} />
<Group w={"75%"} justify="space-between">
<Text c={"black"}>{colorValue}</Text>
<Group>
<Button
color={"green"}
onClick={() => {
switch (colorId) {
case "primary":
setSelectedTheme({
...selectedTheme,
colortextpri: colorValue,
});
break;
case "accent":
setSelectedTheme({
...selectedTheme,
colortextacc: colorValue,
});
break;
case "background":
setSelectedTheme({
...selectedTheme,
colorbackground: colorValue,
});
break;
case "border":
setSelectedTheme({
...selectedTheme,
colorborder: colorValue,
});
break;
case "searchbackground":
setSelectedTheme({
...selectedTheme,
colorsearchbackground: colorValue,
});
break;
}
closePicker();
}}
>
<FiSave />
</Button>
<Button color={"red"} onClick={closePicker}>
<FiX />
</Button>
</Group>
</Group>
</>
) : (
<Card bg={'#0002'} h={"100%"} w={"90%"}>
<Text c="black">
Pick a swatch to edit the color.
</Text>
<Card
bg={"#0002"}
h={"100%"}
w={"90%"}
style={{ alignItems: "center" }}
>
<Text c="black">Pick a swatch to edit the color.</Text>
</Card>
)}
</Stack>
</Group>
<Divider color="black" my="sm" />
<Group>
<Button color={"green"} onClick={handleSaveTheme}>
Save
</Button>
<Button color={"red"} onClick={close}>
Cancel
</Button>
</Group>
</Modal.Body>
</Modal.Content>
</Modal.Root>
<Stack h={"100%"} w={"100%"}>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
<Group>
<Text
className={textClasses.settingsSubTitle}
classNames={textClasses}
>
Themes
</Text>
<SimpleGrid cols={5}>
{themesList.map((theme: any) => (
<Stack key={theme.name}>
<Button
onClick={() => {
setSelectedTheme({
id: undefined,
name: "default",
imagebackground: "none",
colorbackground: "#EEEEEE",
colorsearchbackground: "#00000033",
colortextpri: "#222222",
colortextacc: "#5c5c5c",
colorborder: "#5c5c5c",
});
open();
}}
>
<FiPlus />
</Button>
</Group>
<Group justify="center">
{themesList.map((theme: any) => (
<Stack key={theme.name} w={"300px"}>
<Group gap={0} justify="space-between">
<Button
w={"100%"}
h={"75px"}
style={{
backgroundColor: theme.colorbackground,
border: `solid ${theme.colorborder}`,
@@ -134,14 +317,9 @@ function ThemesSettings({ theme }: any) {
>
{theme.name}
</Button>
<Group justify="space-between">
<Group className="theme-palette">
<ColorSwatch color={theme.colorbackground} />
<ColorSwatch color={theme.colorsearchbackground} />
<ColorSwatch color={theme.colortextpri} />
<ColorSwatch color={theme.colortextacc} />
<ColorSwatch color={theme.colorborder} />
</Group>
<Group justify="space-between" gap={0}>
<Group className="theme-palette">
<ActionIcon
className={actionIconClasses.editButton}
classNames={actionIconClasses}
@@ -149,10 +327,24 @@ function ThemesSettings({ theme }: any) {
>
<FiEdit />
</ActionIcon>
<ColorSwatch color={theme.colorbackground} />
<ColorSwatch color={theme.colorsearchbackground} />
<ColorSwatch color={theme.colortextpri} />
<ColorSwatch color={theme.colortextacc} />
<ColorSwatch color={theme.colorborder} />
<ActionIcon
className={actionIconClasses.editButton}
classNames={actionIconClasses}
onClick={() => handleDeleteTheme(theme)}
>
<FiTrash color="red" />
</ActionIcon>
</Group>
</Group>
</Stack>
))}
</SimpleGrid>
</Group>
</Stack>
</>
);

View File

@@ -18,10 +18,11 @@
text-align: center;
}
.section{
transition: opacity 0.1s 0s ease;
color: var(--color-border);
width: auto;
padding-left: .5rem;
display: none;
opacity: 0;
}
}
.wrapper:focus-within {
@@ -41,10 +42,11 @@
border-bottom-right-radius: .25em;
}
.section{
transition: opacity 0.4s 0.4s ease;
color: var(--color-border);
width: auto;
padding-left: .5rem;
display: flex;
opacity: 1;
}
}
}