Themes modal udpated

This commit is contained in:
Sean Edmunds
2024-08-15 17:07:48 -05:00
parent a47f201fff
commit a37ab84f65
45 changed files with 1480 additions and 1177 deletions

View File

@@ -1,28 +1,31 @@
import { Stack } from '@mantine/core';
import stackClasses from '../../styles/Stack.module.css';
import {useQueryAPI} from '../../hooks/useAPI';
import Search from './components/Search';
import Header from './components/Header';
import Applications from './components/Applications';
import Bookmarks from './components/Bookmarks';
import SettingsButton from './components/SettingsButton';
import { useEffect, useState } from 'react';
import '../../index.css';
import { useLocalStorage } from '@mantine/hooks';
import { Stack } from "@mantine/core";
import stackClasses from "../../styles/Stack.module.css";
import { useQueryAPI } from "../../hooks/useAPI";
import Search from "./components/Search";
import Header from "./components/Header";
import Applications from "./components/Applications";
import Bookmarks from "./components/Bookmarks";
import SettingsButton from "./components/SettingsButton";
import { useEffect, useState } from "react";
import "../../index.css";
import { useLocalStorage } from "@mantine/hooks";
export default function Homepage({theme}:any) {
const { data, isFetching } = useQueryAPI({ endpoint: 'api/messages' });
const [displayedGreeting, setDisplayedGreeting] = useState('');
const [contentType, setContentType] = useLocalStorage<any>({ key: 'contenttype', defaultValue: 'All' });
export default function Homepage({ theme }: any) {
const { data, isFetching } = useQueryAPI({ endpoint: "api/messages" });
const [displayedGreeting, setDisplayedGreeting] = useState("");
const [contentType, setContentType] = useLocalStorage<any>({
key: "contenttype",
defaultValue: "All",
});
function date() {
const currentDate = new Date();
const dateOptions: Intl.DateTimeFormatOptions = {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
};
const date = currentDate.toLocaleDateString('en-GB', dateOptions);
const date = currentDate.toLocaleDateString("en-GB", dateOptions);
return date;
}
function greet(list: any) {
@@ -32,7 +35,7 @@ export default function Homepage({theme}:any) {
let timeBased: any = [];
let easterEggs: any = [];
for (const l of list) {
if (l.easteregg === 'N') {
if (l.easteregg === "N") {
timeBased = timeBased.concat(l);
} else {
easterEggs = easterEggs.concat(l);
@@ -51,12 +54,16 @@ export default function Homepage({theme}:any) {
}, [isFetching]);
return (
<Stack gap={0} className={stackClasses.containerStack} justify='center'>
<Stack gap={0} className={stackClasses.containerStack} justify="center">
<Search />
<Header date={date()} greet={displayedGreeting} />
<Applications contentType={contentType}/>
<Bookmarks contentType={contentType}/>
<SettingsButton theme={theme} contentType={contentType} setContentType={setContentType}/>
<Applications contentType={contentType} />
<Bookmarks contentType={contentType} />
<SettingsButton
theme={theme}
contentType={contentType}
setContentType={setContentType}
/>
</Stack>
);
}

View File

@@ -1,41 +1,43 @@
import { Icon } from '@iconify/react';
import { Box, Stack, Text } from '@mantine/core';
import { useState } from 'react';
import stacks from '../../../styles/Stack.module.css';
import texts from '../../../styles/Text.module.css';
import { Icon } from "@iconify/react";
import { Box, Stack, Text } from "@mantine/core";
import { useState } from "react";
import stacks from "../../../styles/Stack.module.css";
import texts from "../../../styles/Text.module.css";
function AppItem({ url, icon, name }: any) {
const [textDecoration, setTextDecoration] = useState<string>('none');
const [textDecoration, setTextDecoration] = useState<string>("none");
return (
<Box
component='a'
component="a"
href={`https://${url}`}
onMouseOver={() => setTextDecoration('underline')}
onMouseOut={() => setTextDecoration('none')}
onMouseOver={() => setTextDecoration("underline")}
onMouseOut={() => setTextDecoration("none")}
className={stacks.appItemBox}
>
<Stack
style={{
height: '64px',
marginRight: '1em',
marginLeft: '1em',
paddingTop: '15px',
height: "64px",
marginRight: "1em",
marginLeft: "1em",
paddingTop: "15px",
}}
>
<Icon icon={`mdi:${icon}`} height={32} width={32} />
</Stack>
<Stack
style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
display: "flex",
flexDirection: "column",
justifyContent: "center",
flex: 1,
overflow: 'hidden',
overflow: "hidden",
gap: 0,
}}
>
<Text className={texts.appName} classNames={texts}>{name}</Text>
<Text className={texts.appName} classNames={texts}>
{name}
</Text>
<Text
className={texts.appUrl}
classNames={texts}

View File

@@ -1,11 +1,11 @@
import { Stack, Text } from '@mantine/core';
import { useEffect, useState } from 'react';
import {useQueryAPI} from '../../../hooks/useAPI';
import texts from '../../../styles/Text.module.css';
import AppItem from './AppItem';
import { Stack, Text } from "@mantine/core";
import { useEffect, useState } from "react";
import { useQueryAPI } from "../../../hooks/useAPI";
import texts from "../../../styles/Text.module.css";
import AppItem from "./AppItem";
function Applications({contentType}: any) {
const { data, isFetching } = useQueryAPI({ endpoint: 'api/apps' });
function Applications({ contentType }: any) {
const { data, isFetching } = useQueryAPI({ endpoint: "api/apps" });
const [applications, setApplications] = useState([]);
useEffect(() => {
if (!isFetching) {
@@ -13,24 +13,26 @@ function Applications({contentType}: any) {
}
}, [isFetching]);
return (
<Stack id='apps' style={{ gap: 0 }}>
<Text className={texts.sectionTitle} classNames={texts}>Applications</Text>
<Stack id="apps" style={{ gap: 0 }}>
<Text className={texts.sectionTitle} classNames={texts}>
Applications
</Text>
<Stack
style={{
background: 'var(--color-background)',
gap: '.25rem',
backgroundSize: 'cover',
borderBottom: '0px solid',
display: 'grid',
gridColumnGap: '5px',
gridRowGap: '5px',
gridTemplateColumns: '1fr 1fr 1fr 1fr 1fr 1fr',
gridTemplateRows: '64px',
paddingBottom: 'var(--module-spacing)',
background: "var(--color-background)",
gap: ".25rem",
backgroundSize: "cover",
borderBottom: "0px solid",
display: "grid",
gridColumnGap: "5px",
gridRowGap: "5px",
gridTemplateColumns: "1fr 1fr 1fr 1fr 1fr 1fr",
gridTemplateRows: "64px",
paddingBottom: "var(--module-spacing)",
}}
>
{applications?.map((item: any) => {
if (item.category === contentType || contentType === 'All')
if (item.category === contentType || contentType === "All")
return (
<AppItem
key={item.name}

View File

@@ -1,15 +0,0 @@
import BookmarkDetails from './BookmarkDetails';
function BookmarkGroups(props) {
const links = props.links;
return (
<div id='bookmarkForm'>
<h3>{links?.category}</h3>
{links?.map((links) => (
<BookmarkDetails key={links.name} name={links.name} url={links.url} />
))}
</div>
);
}
export default BookmarkGroups;

View File

@@ -1,15 +1,15 @@
import { Stack, Text } from '@mantine/core';
import { useEffect, useState } from 'react';
import {useQueryAPI} from '../../../hooks/useAPI';
import texts from '../../../styles/Text.module.css';
import LinkGroups from './LinkGroups';
import { Stack, Text } from "@mantine/core";
import { useEffect, useState } from "react";
import { useQueryAPI } from "../../../hooks/useAPI";
import texts from "../../../styles/Text.module.css";
import LinkGroups from "./LinkGroups";
function Links({contentType}: any) {
function Links({ contentType }: any) {
const { data: linkData, isFetched: linksIsFetched } = useQueryAPI({
endpoint: 'api/links',
endpoint: "api/links",
});
const { data: groupData, isFetched: groupsIsFetched } = useQueryAPI({
endpoint: 'api/categories',
endpoint: "api/categories",
});
const [bookmarks, setBookmarks] = useState([]);
const [categories, setCategories] = useState([]);
@@ -24,29 +24,32 @@ function Links({contentType}: any) {
return (
<>
{groupsIsFetched && linksIsFetched && categories?.length > 0 && (
<Stack id='links' style={{ gap: 0 }}>
<Text className={texts.sectionTitle} classNames={texts}>Bookmarks</Text>
<Stack id="links" style={{ gap: 0 }}>
<Text className={texts.sectionTitle} classNames={texts}>
Bookmarks
</Text>
<Stack
style={{
display: 'grid',
flexWrap: 'nowrap',
gridColumnGap: '20px',
gridRowGap: '0px',
gridTemplateColumns: '1fr 1fr 1fr 1fr 1fr',
gridTemplateRows: 'auto',
display: "grid",
flexWrap: "nowrap",
gridColumnGap: "20px",
gridRowGap: "0px",
gridTemplateColumns: "1fr 1fr 1fr 1fr 1fr",
gridTemplateRows: "auto",
}}
>
{categories.map((category: any) => {
if (
category.column_filter === contentType ||
contentType === 'All'
contentType === "All"
) {
return (
<LinkGroups
key={category.id}
category={category.category_name}
links={bookmarks.filter(
(bookmark: any) => bookmark.category === category.category_index,
(bookmark: any) =>
bookmark.category === category.category_index,
)}
/>
);

View File

@@ -1,6 +1,6 @@
import { Stack, Text } from '@mantine/core';
import { useEffect, useState } from 'react';
import {textClasses} from '../../../styles';
import { Stack, Text } from "@mantine/core";
import { useEffect, useState } from "react";
import { textClasses } from "../../../styles";
function Header({ greet, date }: any) {
const [time, setTime] = useState(new Date());
@@ -22,50 +22,56 @@ function Header({ greet, date }: any) {
return (
<Stack
style={{
borderBottom: '0px solid',
zIndex: '1',
clear: 'both',
display: 'flex',
flexDirection: 'row',
borderBottom: "0px solid",
zIndex: "1",
clear: "both",
display: "flex",
flexDirection: "row",
gap: 0,
}}
>
<Stack
style={{
display: 'grid',
width: '100%',
display: "grid",
width: "100%",
}}
>
<Text className={textClasses.greeting} classNames={textClasses}>{greet}</Text>
<Text className={textClasses.greeting} classNames={textClasses}>
{greet}
</Text>
</Stack>
<Stack
style={{
display: 'flex',
float: 'right',
justifyContent: 'right',
width: 'auto',
display: "flex",
float: "right",
justifyContent: "right",
width: "auto",
gap: 0,
}}
>
<Text className={textClasses.dateTime} classNames={textClasses} style={{ width: 'max-content' }}>
<Text
className={textClasses.dateTime}
classNames={textClasses}
style={{ width: "max-content" }}
>
{date}
</Text>
<Text
component='h2'
component="h2"
className={textClasses.dateTime}
classNames={textClasses}
style={{
justifyContent: 'right',
display: 'grid',
justifyContent: "right",
display: "grid",
}}
>
{`${
time.getHours() === 0
? 12
: time.getHours() > 12
? time.getHours() - 12
: time.getHours()
}:${fixDigits(time.getMinutes())} ${time.getHours() >= 12 ? 'PM' : 'AM'}`}
? time.getHours() - 12
: time.getHours()
}:${fixDigits(time.getMinutes())} ${time.getHours() >= 12 ? "PM" : "AM"}`}
</Text>
</Stack>
</Stack>

View File

@@ -1,17 +1,19 @@
import { Stack, Text } from '@mantine/core';
import texts from '../../../styles/Text.module.css';
import LinkItem from './LinkItem';
import { Stack, Text } from "@mantine/core";
import texts from "../../../styles/Text.module.css";
import LinkItem from "./LinkItem";
function LinkGroups({ links, category }: any) {
return (
<Stack
style={{
marginBottom: '0em',
display: 'block',
lineHeight: '1.5rem',
marginBottom: "0em",
display: "block",
lineHeight: "1.5rem",
}}
>
<Text className={texts.linkCategory} classNames={texts}>{category}</Text>
<Text className={texts.linkCategory} classNames={texts}>
{category}
</Text>
{links?.map((link: any) => (
<LinkItem key={link.name} link={link} />
))}

View File

@@ -1,9 +1,14 @@
import { Text } from '@mantine/core';
import texts from '../../../styles/Text.module.css';
import { Text } from "@mantine/core";
import texts from "../../../styles/Text.module.css";
function LinkItem({ link }: any) {
return (
<Text className={texts.linkItem} classNames={texts} component='a' href={link.url}>
<Text
className={texts.linkItem}
classNames={texts}
component="a"
href={link.url}
>
{link.name}
</Text>
);

View File

@@ -1,9 +1,9 @@
import { useEffect, useState } from 'react';
import Messages from '../../../components/Messages';
import useQueryAPI from '../../../hooks/useAPI';
import { useEffect, useState } from "react";
import Messages from "../../../components/Messages";
import useQueryAPI from "../../../hooks/useAPI";
function MessageInfo() {
const messageData = useQueryAPI({ endpoint: 'api/messages' });
const messageData = useQueryAPI({ endpoint: "api/messages" });
const [greetings, setGreetings] = useState([]);
useEffect(() => {
@@ -15,7 +15,7 @@ function MessageInfo() {
return (
<>
{greetings && (
<div id='messageForm'>
<div id="messageForm">
{greetings.map((greeting, index) => (
<Messages
key={greeting.id}

View File

@@ -4,72 +4,85 @@ import { useQueryAPI } from "../../../hooks";
import { useState } from "react";
export default function Search() {
const { data: providers } = useQueryAPI({ endpoint: 'api/providers' });
const { data: providers } = useQueryAPI({ endpoint: "api/providers" });
const [providerLabel, setProviderLabel] = useState('Google Search');
const [providerURL, setProviderURL] = useState('https://www.google.com/search?q=');
const handleKeyPress = (item: any) => {
const option = item.target.value.substr(1, item.target.value.indexOf(' ') - 1) || item.target.value.substr(1);
const subtext = item.target.value.substr(2 + option.length);
if (item.key === 'Enter') {
if (item.target.value.startsWith('/')) {
open(`${providerURL}${subtext}`, '_self');
} else if (validURL(item.target.value)) {
if (containsProtocol(item.target.value)) window.location = item.target.value;
else open(`https://${item.target.value}`, '_self');
} else {
open(`${providerURL}${subtext}`, '_self');
}
}
}
const [providerLabel, setProviderLabel] = useState("Google Search");
const [providerURL, setProviderURL] = useState(
"https://www.google.com/search?q=",
);
function validURL(str: any) {
const pattern = new RegExp(
'^(https?:\\/\\/)?' + // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
'(\\#[-a-z\\d_]*)?$',
'i',
); // fragment locator
return !!pattern.test(str);
}
function containsProtocol(str: any) {
const pattern = /^(https?:\/\/){1}.*/i;
return !!pattern.test(str);
}
const handleKeyPress = (item: any) => {
const option =
item.target.value.substr(1, item.target.value.indexOf(" ") - 1) ||
item.target.value.substr(1);
const subtext = item.target.value.substr(2 + option.length);
if (item.key === "Enter") {
if (item.target.value.startsWith("/")) {
open(`${providerURL}${subtext}`, "_self");
} else if (validURL(item.target.value)) {
if (containsProtocol(item.target.value))
window.location = item.target.value;
else open(`https://${item.target.value}`, "_self");
} else {
open(`${providerURL}${subtext}`, "_self");
}
}
};
return (
function validURL(str: any) {
const pattern = new RegExp(
"^(https?:\\/\\/)?" + // protocol
"((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name
"((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address
"(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path
"(\\?[;&a-z\\d%_.~+=-]*)?" + // query string
"(\\#[-a-z\\d_]*)?$",
"i",
); // fragment locator
return !!pattern.test(str);
}
function containsProtocol(str: any) {
const pattern = /^(https?:\/\/){1}.*/i;
return !!pattern.test(str);
}
return (
<Stack
style={{
backgroundColor: 'transparent',
textAlign: 'center',
position: 'relative',
padding: '.3em',
display: 'inline-block',
backgroundColor: "transparent",
textAlign: "center",
position: "relative",
padding: ".3em",
display: "inline-block",
gap: 0,
}}
>
<TextInput
className={textInputClasses.search}
classNames={textInputClasses}
spellCheck='true'
leftSection={providerLabel}
classNames={textInputClasses}
spellCheck="true"
leftSection={providerLabel}
onChange={(item: any) => {
if(item.target.value.startsWith('/')) {
setProviderLabel(providers?.find((p: any) => p.prefix === item.target.value.split(' ')[0]).name);
setProviderURL(providers?.find((p: any) => p.prefix === item.target.value.split(' ')[0]).url);
} else {
setProviderLabel('Google Search');
setProviderURL('https://www.google.com/search?q=');
}
}}
onKeyUp={(item: any) => {
handleKeyPress(item);
}}
if (item.target.value.startsWith("/")) {
setProviderLabel(
providers?.find(
(p: any) => p.prefix === item.target.value.split(" ")[0],
).name,
);
setProviderURL(
providers?.find(
(p: any) => p.prefix === item.target.value.split(" ")[0],
).url,
);
} else {
setProviderLabel("Google Search");
setProviderURL("https://www.google.com/search?q=");
}
}}
onKeyUp={(item: any) => {
handleKeyPress(item);
}}
/>
</Stack>
);
}
}

View File

@@ -1,58 +1,58 @@
import { Button, Menu, NavLink, Select } from '@mantine/core';
import { useEffect, useState } from 'react';
import { FiMenu, FiMonitor } from 'react-icons/fi';
import {useQueryAPI} from '../../../hooks/useAPI';
import button from '../../../styles/Button.module.css';
import menu from '../../../styles/Menu.module.css';
import navLink from '../../../styles/NavLink.module.css';
import selectClasses from '../../../styles/Select.module.css';
import { Button, Menu, NavLink, Select } from "@mantine/core";
import { useEffect, useState } from "react";
import { FiMenu, FiMonitor } from "react-icons/fi";
import { useQueryAPI } from "../../../hooks/useAPI";
import button from "../../../styles/Button.module.css";
import menu from "../../../styles/Menu.module.css";
import navLink from "../../../styles/NavLink.module.css";
import selectClasses from "../../../styles/Select.module.css";
function SettingsButton({ contentType, setContentType, theme }: any) {
const { data, isFetched } = useQueryAPI({ endpoint: "api/appCategories" });
const [categories, setCategories] = useState([
{ value: "All", label: "All" },
]);
function SettingsButton({contentType, setContentType, theme}: any) {
const { data, isFetched } = useQueryAPI({ endpoint: 'api/appCategories' });
const [categories, setCategories] = useState([{value: 'All', label: 'All'}]);
useEffect(() => {
if(data) {
const list: [any] = data.map((category: any) => {return {value: category.category, label: category.category}}) || [];
list.unshift({value: 'All', label: 'All'});
if (data) {
const list: [any] =
data.map((category: any) => {
return { value: category.category, label: category.category };
}) || [];
list.unshift({ value: "All", label: "All" });
setCategories(list);
}
}, [data, isFetched]);
function runWakeCommand() {
const requestOptions = {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
method: "GET",
headers: { "Content-Type": "application/json" },
};
fetch('/trigger/api/wakeDakota', requestOptions);
fetch("/trigger/api/wakeDakota", requestOptions);
}
return (
<Menu
withinPortal={false}
withArrow
shadow='md'
position='top'
>
<Menu withinPortal={false} withArrow shadow="md" position="top">
<Menu.Target>
<Button className={button.settingsButton} classNames={button}>
<FiMenu />
</Button>
</Menu.Target>
<Menu.Dropdown
className={menu.dropdown}
>
<Menu.Dropdown className={menu.dropdown}>
<NavLink
label='Settings'
component='a'
href='/trigger/settings'
label="Settings"
component="a"
href="/trigger/settings"
className={navLink.defaultNavLink}
classNames={navLink}
/>
<NavLink label='Quick Actions'
<NavLink
label="Quick Actions"
className={navLink.defaultNavLink}
classNames={navLink}>
classNames={navLink}
>
<NavLink
label='Wake Dakota'
label="Wake Dakota"
leftSection={<FiMonitor />}
onClick={() => runWakeCommand()}
className={navLink.defaultNavLink}
@@ -60,12 +60,12 @@ function SettingsButton({contentType, setContentType, theme}: any) {
/>
</NavLink>
<Select
label='Homepage Filter'
label="Homepage Filter"
data={categories ?? []}
defaultValue={contentType}
withCheckIcon={false}
onChange={(data: any) => {
setContentType(data)
setContentType(data);
}}
classNames={selectClasses}
comboboxProps={{ withinPortal: false }}

View File

@@ -1,8 +1,8 @@
import { ActionIcon, Group, Stack, Tabs } from "@mantine/core";
import tabClasses from '../../styles/Tabs.module.css';
import { ActionIcon, Group, Stack, Tabs, Text } from "@mantine/core";
import tabClasses from "../../styles/Tabs.module.css";
import Personalization from "./components/Personalization";
import { FiArrowLeftCircle } from "react-icons/fi";
import { actionIconClasses } from "../../styles";
import { actionIconClasses, textClasses } from "../../styles";
import Messages from "./components/Messages";
import Applications from "./components/Applications";
import Bookmarks from "./components/Bookmarks";
@@ -10,32 +10,60 @@ import Categories from "./components/Categories";
import SearchProviders from "./components/SearchProviders";
import Themes from "./components/Themes";
function Settings({theme}:any) {
function Settings({ theme }: any) {
return (
<Stack h={'100vh'} px={'2rem'} bg={'var(--color-background)'}>
<Group gap={0} >
<ActionIcon className={actionIconClasses.backButton} classNames={actionIconClasses} component="a" href="/trigger"><FiArrowLeftCircle/></ActionIcon>
<h1>Settings</h1>
</Group>
<Tabs orientation="vertical" defaultValue={'personalization'} className={tabClasses.settingsTabs} classNames={tabClasses}>
<Tabs.List>
<Tabs.Tab value="personalization">Personal Info</Tabs.Tab>
<Tabs.Tab value="messages">Messages</Tabs.Tab>
<Tabs.Tab value="applications">Applications</Tabs.Tab>
<Tabs.Tab value="bookmarks">Bookmarks</Tabs.Tab>
<Tabs.Tab value="bookmarksCategories">Categories</Tabs.Tab>
<Tabs.Tab value="themes">Themes</Tabs.Tab>
<Tabs.Tab value="providers">Search Providers</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="personalization"><Personalization/></Tabs.Panel>
<Tabs.Panel value="messages"><Messages/></Tabs.Panel>
<Tabs.Panel value="applications"><Applications/></Tabs.Panel>
<Tabs.Panel value="bookmarks"><Bookmarks/></Tabs.Panel>
<Tabs.Panel value="bookmarksCategories"><Categories/></Tabs.Panel>
<Tabs.Panel value="themes"><Themes/></Tabs.Panel>
<Tabs.Panel value="providers"><SearchProviders/></Tabs.Panel>
</Tabs>
</Stack>
<Stack h={"100vh"} px={"2rem"} bg={"var(--color-background)"}>
<Group gap={0}>
<ActionIcon
className={actionIconClasses.backButton}
classNames={actionIconClasses}
component="a"
href="/trigger"
>
<FiArrowLeftCircle />
</ActionIcon>
<Text className={textClasses.settingsTitle} classNames={textClasses}>
Settings
</Text>
</Group>
<Tabs
orientation="vertical"
defaultValue={"personalization"}
className={tabClasses.settingsTabs}
classNames={tabClasses}
>
<Tabs.List>
<Tabs.Tab value="personalization">Personal Info</Tabs.Tab>
<Tabs.Tab value="messages">Messages</Tabs.Tab>
<Tabs.Tab value="applications">Applications</Tabs.Tab>
<Tabs.Tab value="bookmarks">Bookmarks</Tabs.Tab>
<Tabs.Tab value="bookmarksCategories">Categories</Tabs.Tab>
<Tabs.Tab value="themes">Themes</Tabs.Tab>
<Tabs.Tab value="providers">Search Providers</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="personalization">
<Personalization />
</Tabs.Panel>
<Tabs.Panel value="messages">
<Messages />
</Tabs.Panel>
<Tabs.Panel value="applications">
<Applications />
</Tabs.Panel>
<Tabs.Panel value="bookmarks">
<Bookmarks />
</Tabs.Panel>
<Tabs.Panel value="bookmarksCategories">
<Categories />
</Tabs.Panel>
<Tabs.Panel value="themes">
<Themes theme={theme} />
</Tabs.Panel>
<Tabs.Panel value="providers">
<SearchProviders />
</Tabs.Panel>
</Tabs>
</Stack>
);
}
export default Settings;

View File

@@ -1,59 +1,61 @@
import { useEffect, useState } from "react";
import {useMutationAPI, useQueryAPI} from "../../../hooks/useAPI";
import { useMutationAPI, 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 } from "@mantine/core";
import { Stack, Text } from "@mantine/core";
import { textClasses } from "../../../styles";
const ApplicationSettings = () => {
const endpoint = "api/apps";
const endpoint = "api/apps";
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
endpoint: endpoint,
});
const [applicationData, setApplicationData] = useState<any>([]);
const {mutateAsync: createRow, isPending: isCreatingRow} = useMutationAPI();
const {mutateAsync: editRow, isPending: isEditingRow} = useMutationAPI();
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
useEffect(() => {
if(isFetched) {
setApplicationData(data);
}
})
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);
};
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>
<h2>Applications</h2>
<DataTable
tableName="Applications"
columns={ApplicationColumns()}
tableData={applicationData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
/>
</Stack>
)
<Stack>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
Applications
</Text>
<DataTable
tableName="Applications"
columns={ApplicationColumns()}
tableData={applicationData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
/>
</Stack>
);
};
export default ApplicationSettings;

View File

@@ -1,13 +1,14 @@
import { useEffect, useState } from "react";
import {useMutationAPI, useQueryAPI} from "../../../hooks/useAPI";
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
import { DataTable } from "../../../DataTable/DataTable";
import { toast } from "react-toastify";
import type { MRT_TableOptions } from "mantine-react-table";
import { Stack } from "@mantine/core";
import { Stack, Text } from "@mantine/core";
import BookmarkColumns from "../../../DataTable/columns/BookmarkColumns";
import { textClasses } from "../../../styles";
const BookmarkSettings = () => {
const endpoint = "api/links";
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
const endpoint = "api/links";
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
endpoint: endpoint,
});
const {
@@ -17,16 +18,16 @@ const BookmarkSettings = () => {
isFetched: groupDataisFetched,
} = useQueryAPI({ endpoint: "api/categories" });
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();
const [groups, setGroups] = useState([]);
const [fullyFetched, setFullyFetched] = useState(false);
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
useEffect(() => {
if(isFetched) {
setBookmarkData(data);
}
})
useEffect(() => {
if (isFetched) {
setBookmarkData(data);
}
});
useEffect(() => {
if (groupDataisFetched) {
@@ -38,39 +39,40 @@ 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);
};
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>
<h2>Bookmarks</h2>
<DataTable
tableName="Applications"
columns={BookmarkColumns(groups, groupData)}
tableData={bookmarkData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
/>
</Stack>
)
<Stack>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
Bookmarks
</Text>
<DataTable
tableName="Applications"
columns={BookmarkColumns(groups, groupData)}
tableData={bookmarkData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
/>
</Stack>
);
};
export default BookmarkSettings;

View File

@@ -1,59 +1,61 @@
import { useEffect, useState } from "react";
import {useMutationAPI, useQueryAPI} from "../../../hooks/useAPI";
import { useMutationAPI, 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 } from "@mantine/core";
import { Stack, Text } from "@mantine/core";
import { textClasses } from "../../../styles";
const CategorySettings = () => {
const endpoint = "api/categories";
const endpoint = "api/categories";
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
endpoint: endpoint,
});
const [categoryData, setCategoryData] = useState<any>([]);
const {mutateAsync: createRow, isPending: isCreatingRow} = useMutationAPI();
const {mutateAsync: editRow, isPending: isEditingRow} = useMutationAPI();
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
useEffect(() => {
if(isFetched) {
setCategoryData(data);
}
})
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);
};
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>
<h2>Categories</h2>
<DataTable
tableName="Categories"
columns={CategoryColumns()}
tableData={categoryData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
/>
</Stack>
)
<Stack>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
Categories
</Text>
<DataTable
tableName="Categories"
columns={CategoryColumns()}
tableData={categoryData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
/>
</Stack>
);
};
export default CategorySettings;

View File

@@ -1,59 +1,61 @@
import { useEffect, useState } from "react";
import {useMutationAPI, useQueryAPI} from "../../../hooks/useAPI";
import { useMutationAPI, 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 } from "@mantine/core";
import { Stack, Text } from "@mantine/core";
import { textClasses } from "../../../styles";
const MessageSettings = () => {
const endpoint = "api/messages";
const endpoint = "api/messages";
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
endpoint: endpoint,
});
const [messageData, setMessageData] = useState<any>([]);
const {mutateAsync: createRow, isPending: isCreatingRow} = useMutationAPI();
const {mutateAsync: editRow, isPending: isEditingRow} = useMutationAPI();
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
useEffect(() => {
if(isFetched) {
setMessageData(data);
}
})
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);
};
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>
<h2>Messages</h2>
<DataTable
tableName="Messages"
columns={MessagesColumns()}
tableData={messageData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
/>
</Stack>
)
<Stack>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
Messages
</Text>
<DataTable
tableName="Messages"
columns={MessagesColumns()}
tableData={messageData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
/>
</Stack>
);
};
export default MessageSettings;

View File

@@ -1,58 +1,61 @@
import { useEffect, useState } from "react";
import {useMutationAPI, useQueryAPI} from "../../../hooks/useAPI";
import { useMutationAPI, 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 = () => {
const endpoint = "api/personaldata";
const endpoint = "api/personaldata";
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
endpoint: endpoint,
});
const [personalData, setPersonalData] = useState<any>([]);
const {mutateAsync: createRow, isPending: isCreatingRow} = useMutationAPI();
const {mutateAsync: editRow, isPending: isEditingRow} = useMutationAPI();
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
useEffect(() => {
if(isFetched) {
setPersonalData(data);
}
})
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);
};
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 (
<>
<h2>Personalization</h2>
<DataTable
tableName="Personalization"
columns={PersonalizationColumns()}
tableData={personalData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
/>
</>
)
<>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
Personalization
</Text>
<DataTable
tableName="Personalization"
columns={PersonalizationColumns()}
tableData={personalData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
/>
</>
);
};
export default PersonalizationSettings;

View File

@@ -1,59 +1,61 @@
import { useEffect, useState } from "react";
import {useMutationAPI, useQueryAPI} from "../../../hooks/useAPI";
import { useMutationAPI, 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 } from "@mantine/core";
import { Stack, Text } from "@mantine/core";
import { textClasses } from "../../../styles";
const SearchProviderSettings = () => {
const endpoint = "api/providers";
const endpoint = "api/providers";
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
endpoint: endpoint,
});
const [providerData, setProviderData] = useState<any>([]);
const {mutateAsync: createRow, isPending: isCreatingRow} = useMutationAPI();
const {mutateAsync: editRow, isPending: isEditingRow} = useMutationAPI();
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
useEffect(() => {
if(isFetched) {
setProviderData(data);
}
})
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);
};
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>
<h2>Search Providers</h2>
<DataTable
tableName="Categories"
columns={SearchProviderColumns()}
tableData={providerData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
/>
</Stack>
)
<Stack>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
Search Providers
</Text>
<DataTable
tableName="Categories"
columns={SearchProviderColumns()}
tableData={providerData}
isFetching={isFetching}
isLoading={isLoading}
onCreatingRowSave={handleCreateRow}
onEditingRowSave={handleEditRow}
/>
</Stack>
);
};
export default SearchProviderSettings;

View File

@@ -0,0 +1,250 @@
import { Icon } from "@iconify/react/dist/iconify.js";
import { Stack, Group, Text, Box } from "@mantine/core";
import { useState } from "react";
import { stackClasses } from "../../../styles";
export default function ThemeModalContent({ selectedTheme }: any) {
const ExampleApp = (previewTheme: any) => {
const [textDecoration, setTextDecoration] = useState<string>("none");
return (
<Box
component="a"
onMouseOver={() => setTextDecoration("underline")}
onMouseOut={() => setTextDecoration("none")}
className={stackClasses.appItemBox}
>
<Stack
style={{
height: "64px",
marginRight: "1em",
marginLeft: "1em",
paddingTop: "15px",
}}
>
<Icon
style={{ color: previewTheme.theme.colortextpri }}
icon={`mdi:check`}
height={32}
width={32}
/>
</Stack>
<Stack
style={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
flex: 1,
overflow: "hidden",
gap: 0,
}}
>
<Text
style={{
fontWeight: 400,
fontSize: 11,
fontStyle: "normal",
color: previewTheme.theme.colortextpri,
fontFamily:
"-apple-system, Jost, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif !important",
margin: 0,
}}
>
{"Example App"}
</Text>
<Text
style={{
fontWeight: 400,
fontSize: 11,
fontStyle: "italic",
color: previewTheme.theme.colortextacc,
fontFamily:
"-apple-system, Jost, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif !important",
margin: 0,
textDecoration: textDecoration,
}}
>
{"https://www.example.com"}
</Text>
</Stack>
</Box>
);
};
return (
<Stack
style={{
width: "100%",
backgroundColor: selectedTheme.colorbackground,
borderRadius: "10px",
}}
>
<Group
justify="center"
style={{
color: selectedTheme.colortextpri,
paddingTop: "1rem",
}}
>
{selectedTheme.name}
</Group>
<Text
pl={"1.5rem"}
style={{
textDecoration: "underline",
fontSize: "20px",
fontWeight: 200,
fontStyle: "italic",
height: "10px",
textTransform: "uppercase",
marginTop: "20px",
marginBottom: "20px",
color: selectedTheme.colortextpri,
}}
>
Applications
</Text>
<Stack
style={{
background: selectedTheme.colorbackground,
gap: ".25rem",
backgroundSize: "cover",
borderBottom: "0px solid",
display: "grid",
gridColumnGap: "5px",
gridRowGap: "5px",
gridTemplateColumns: "1fr 1fr 1fr",
gridTemplateRows: "64px",
padding: "1rem",
paddingTop: "0rem",
justifyContent: "center",
alignContent: "center",
}}
>
<ExampleApp theme={selectedTheme} />
<ExampleApp theme={selectedTheme} />
<ExampleApp theme={selectedTheme} />
</Stack>
<Text
pl={"1.5rem"}
style={{
textDecoration: "underline",
fontSize: "20px",
fontWeight: 200,
fontStyle: "italic",
height: "10px",
textTransform: "uppercase",
marginTop: "20px",
marginBottom: "20px",
color: selectedTheme.colortextpri,
}}
>
Bookmarks
</Text>
<Stack
style={{
display: "flex",
flexDirection: "row",
flexWrap: "nowrap",
gridColumnGap: "20px",
gridRowGap: "0px",
gridTemplateColumns: "1fr 1fr 1fr 1fr 1fr",
gridTemplateRows: "auto",
}}
>
<Stack
style={{
width: "100%",
marginBottom: "0em",
display: "block",
lineHeight: "1.5rem",
padding: "1rem",
paddingTop: "0rem",
}}
>
<Text
style={{
fontSize: "14px",
fontWeight: 400,
height: "10px",
width: "auto",
color: selectedTheme.colortextacc,
textTransform: "uppercase",
marginTop: "20px",
marginBottom: "20px",
}}
>
Example Category
</Text>
<Text
style={{
display: "block",
fontSize: "14px",
lineHeight: 2,
color: selectedTheme.colortextpri,
}}
component="a"
>
{"Link 1"}
</Text>
<Text
style={{
display: "block",
fontSize: "14px",
lineHeight: 2,
color: selectedTheme.colortextpri,
}}
component="a"
>
{"Link 2"}
</Text>
</Stack>
<Stack
style={{
width: "100%",
marginBottom: "0em",
display: "block",
lineHeight: "1.5rem",
padding: "1rem",
paddingTop: "0rem",
}}
>
<Text
style={{
fontSize: "14px",
fontWeight: 400,
height: "10px",
width: "auto",
color: selectedTheme.colortextacc,
textTransform: "uppercase",
marginTop: "20px",
marginBottom: "20px",
}}
>
Example Category
</Text>
<Text
style={{
display: "block",
fontSize: "14px",
lineHeight: 2,
color: selectedTheme.colortextpri,
}}
component="a"
>
{"Link 1"}
</Text>
<Text
style={{
display: "block",
fontSize: "14px",
lineHeight: 2,
color: selectedTheme.colortextpri,
}}
component="a"
>
{"Link 2"}
</Text>
</Stack>
</Stack>
</Stack>
);
}

View File

@@ -1,87 +1,160 @@
import { useEffect, useState } from "react";
import { useQueryAPI } from "../../../hooks/useAPI";
import { ActionIcon, Button, ColorPicker, ColorSwatch, Group, Modal, SimpleGrid, Stack } from "@mantine/core";
import AppItem from "../../homepage/components/AppItem";
import {
ActionIcon,
Button,
Card,
ColorPicker,
ColorSwatch,
Divider,
Group,
Modal,
SimpleGrid,
Stack,
Text,
} from "@mantine/core";
import { FiEdit } from "react-icons/fi";
import { useDisclosure, useLocalStorage } from "@mantine/hooks";
import '@mantine/core/styles/ModalBase.css';
import '@mantine/core/styles/Modal.css';
function ThemesSettings() {
const [opened, { open, close }] = useDisclosure(false);
const [value, setValue] = useLocalStorage<any>({ key: 'theme', defaultValue: {} });
import "@mantine/core/styles/ModalBase.css";
import "@mantine/core/styles/Modal.css";
import { actionIconClasses, modalClasses, textClasses } from "../../../styles";
import ThemeModalContent from "./ThemeModalContent";
function ThemesSettings({ theme }: any) {
const [opened, { open, close }] = useDisclosure(false);
const [pickerOpen, { open: openPicker, close: closePicker }] = useDisclosure(false);
const [colorValue, onChange] = useState('#000000');
const [value, setValue] = useLocalStorage<any>({
key: "theme",
defaultValue: {},
});
const { data, isFetched } = useQueryAPI({
endpoint: "api/themes",
});
const [themesList, setThemesList] = useState([]);
const [selectedTheme, setSelectedTheme] = useState<any>({});
const [selectedTheme, setSelectedTheme] = useState<any>({});
useEffect(() => {
if (isFetched) {
setThemesList(data);
}
}, [isFetched]);
const handleOpen = (theme: any) => {
setSelectedTheme(theme);
open();
}
const handleOpen = (theme: any) => {
setSelectedTheme(theme);
open();
};
const handleClose = () => {
close();
closePicker();
};
return (
<>
<Modal.Root opened={opened} onClose={close}>
<Modal.Overlay />
<Modal.Content>
<Modal.Header>
<Modal.Title>Edit Theme</Modal.Title>
<Modal.CloseButton />
</Modal.Header>
<Modal.Body>
<Stack style={{ backgroundColor: selectedTheme.colorbackground, borderRadius: '10px' }}>
<Group justify="center" style={{ color: selectedTheme.colortextpri }}>{selectedTheme.name}</Group>
<AppItem
name={'Example App'}
url={'https://example.com'}
icon={'mdi:apps'}
category={'Default'}
/>
</Stack>
</Modal.Body>
</Modal.Content>
</Modal.Root>
<Stack h={'100%'} w={'100%'}>
<h2>Themes</h2>
<SimpleGrid cols={5}>
{themesList.map((theme: any) => (
<Stack key={theme.name}>
<Button
style={{
backgroundColor: theme.colorbackground,
border: `solid ${theme.colorborder}`,
color: theme.colortextpri,
}}
data-theme={theme.name}
onClick={() => {
setValue(theme.name)
}}
>
{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} />
<>
<Modal.Root
size={"50%"}
style={{
"--color-text-pri": theme.colortextpri,
"--color-text-acc": theme.colortextacc,
"--color-background": theme.colorbackground,
"--color-border": theme.colorborder,
"--color-search-background": theme.colorsearchbackground,
}}
className={modalClasses.editThemeModal}
classNames={modalClasses}
opened={opened}
onClose={handleClose}
>
<Modal.Overlay />
<Modal.Content>
<Modal.Header>
<Modal.Title>Edit Theme</Modal.Title>
<Modal.CloseButton />
</Modal.Header>
<Modal.Body p={"2rem"}>
<ThemeModalContent selectedTheme={selectedTheme} />
<Divider color="black" my="sm" />
<Group w={"100%"} h={"100%"} gap={0}>
<Stack w={"50%"}>
<Group c={'black'} justify="space-between">
<Text>Primary Color</Text>
<ColorSwatch onClick={openPicker} radius={"sm"} w={"100px"} color={selectedTheme.colortextpri} />
</Group>
<ActionIcon
onClick={() => handleOpen(theme)}
><FiEdit/></ActionIcon>
</Group>
</Stack>
))}
</SimpleGrid>
</Stack>
</>
<Group c={'black'} justify="space-between">
<Text>Accent Color</Text>
<ColorSwatch radius={"sm"} w={"100px"} color={selectedTheme.colortextacc} />
</Group>
<Group c={'black'} justify="space-between">
<Text>Background Color</Text>
<ColorSwatch radius={"sm"} w={"100px"} color={selectedTheme.colorbackground} />
</Group>
<Group c={'black'} justify="space-between">
<Text>Border Color</Text>
<ColorSwatch radius={"sm"} w={"100px"} color={selectedTheme.colorborder} />
</Group>
<Group c={'black'} justify="space-between">
<Text>Search Background Color</Text>
<ColorSwatch radius={"sm"} w={"100px"} color={selectedTheme.colorsearchbackground} />
</Group>
</Stack>
<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>
</>
) : (
<Card bg={'#0002'} h={"100%"} w={"90%"}>
<Text c="black">
Pick a swatch to edit the color.
</Text>
</Card>
)}
</Stack>
</Group>
</Modal.Body>
</Modal.Content>
</Modal.Root>
<Stack h={"100%"} w={"100%"}>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
Themes
</Text>
<SimpleGrid cols={5}>
{themesList.map((theme: any) => (
<Stack key={theme.name}>
<Button
style={{
backgroundColor: theme.colorbackground,
border: `solid ${theme.colorborder}`,
color: theme.colortextpri,
}}
data-theme={theme.name}
onClick={() => {
setValue(theme.name);
}}
>
{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>
<ActionIcon
className={actionIconClasses.editButton}
classNames={actionIconClasses}
onClick={() => handleOpen(theme)}
>
<FiEdit />
</ActionIcon>
</Group>
</Stack>
))}
</SimpleGrid>
</Stack>
</>
);
}
export default ThemesSettings;