This commit is contained in:
Sean Edmunds
2024-08-20 16:28:46 -05:00
parent 8152d3fe73
commit 7990f164d6
39 changed files with 824 additions and 772 deletions

View File

@@ -1,37 +1,37 @@
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,
}}
>

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" });
const { data, isFetching } = useQueryAPI({ endpoint: 'api/apps' });
const [applications, setApplications] = useState([]);
useEffect(() => {
if (!isFetching) {
@@ -13,26 +13,26 @@ function Applications({ contentType }: any) {
}
}, [isFetching]);
return (
<Stack id="apps" style={{ gap: 0 }}>
<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 +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) {
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,32 +24,28 @@ function Links({ contentType }: any) {
return (
<>
{groupsIsFetched && linksIsFetched && categories?.length > 0 && (
<Stack id="links" style={{ gap: 0 }}>
<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"
) {
if (category.column_filter === contentType || 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,18 +22,18 @@ 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}>
@@ -42,27 +42,27 @@ function Header({ greet, date }: any) {
</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" }}
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',
}}
>
{`${
@@ -71,7 +71,7 @@ function Header({ greet, date }: any) {
: time.getHours() > 12
? time.getHours() - 12
: time.getHours()
}:${fixDigits(time.getMinutes())} ${time.getHours() >= 12 ? "PM" : "AM"}`}
}:${fixDigits(time.getMinutes())} ${time.getHours() >= 12 ? 'PM' : 'AM'}`}
</Text>
</Stack>
</Stack>

View File

@@ -1,14 +1,14 @@
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}>

View File

@@ -1,14 +1,9 @@
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

@@ -1,50 +1,47 @@
import { Stack, TextInput } from "@mantine/core";
import { textInputClasses } from "../../../styles";
import { useQueryAPI } from "../../../hooks";
import { useState } from "react";
import { Stack, TextInput } from '@mantine/core';
import { useState } from 'react';
import { useQueryAPI } from '../../../hooks';
import { textInputClasses } from '../../../styles';
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 [value, setValue] = useState("");
const [providerLabel, setProviderLabel] = useState('Google Search');
const [providerURL, setProviderURL] = useState('https://www.google.com/search?q=');
const [value, setValue] = useState('');
const handleKeyPress = (item: any) => {
let option = ''
let subtext = ''
if (item.target.value.startsWith("/")) {
let option = '';
let subtext = '';
if (item.target.value.startsWith('/')) {
option =
item.target.value.substr(1, item.target.value.indexOf(" ") - 1) ||
item.target.value.substr(1);
item.target.value.substr(1, item.target.value.indexOf(' ') - 1) ||
item.target.value.substr(1);
subtext = item.target.value.substr(2 + option.length);
} else {
subtext = item.target.value;
}
if (item.key === "Enter") {
if (item.target.value.startsWith("/")) {
open(`${providerURL}${subtext}`, "_self");
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");
if (containsProtocol(item.target.value)) window.location = item.target.value;
else open(`https://${item.target.value}`, '_self');
} else {
open(`${providerURL}${subtext}`, "_self");
open(`${providerURL}${subtext}`, '_self');
}
}
};
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",
'^(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);
}
@@ -56,37 +53,37 @@ export default function Search() {
return (
<Stack
style={{
height: "100px",
backgroundColor: "transparent",
textAlign: "center",
position: "relative",
padding: ".3em",
display: "inline-block",
height: '100px',
backgroundColor: 'transparent',
textAlign: 'center',
position: 'relative',
padding: '.3em',
display: 'inline-block',
gap: 0,
}}
>
<TextInput
className={textInputClasses.search}
classNames={textInputClasses}
spellCheck="true"
spellCheck='true'
leftSection={providerLabel}
value={value}
data-active={value !== ''}
onChange={(item: any) => {
setValue(item.currentTarget.value)
if (item.target.value.startsWith("/")) {
setValue(item.currentTarget.value);
if (item.target.value.startsWith('/')) {
const provider = providers?.find(
(p: any) => p.prefix === item.target.value.split(" ")[0],
)
setProviderLabel(provider?.name || "Invalid Search");
(p: any) => p.prefix === item.target.value.split(' ')[0],
);
setProviderLabel(provider?.name || 'Invalid Search');
setProviderURL(provider?.url);
} else {
setProviderLabel("Google Search");
setProviderURL("https://www.google.com/search?q=");
setProviderLabel('Google Search');
setProviderURL('https://www.google.com/search?q=');
}
}}
onKeyUp={(item: any) => {
if(providerLabel !== "Invalid Search"){
if (providerLabel !== 'Invalid Search') {
handleKeyPress(item);
}
}}

View File

@@ -1,17 +1,15 @@
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" },
]);
const { data, isFetched } = useQueryAPI({ endpoint: 'api/appCategories' });
const [categories, setCategories] = useState([{ value: 'All', label: 'All' }]);
useEffect(() => {
if (data) {
@@ -19,20 +17,20 @@ function SettingsButton({ contentType, setContentType, theme }: any) {
data.map((category: any) => {
return { value: category.category, label: category.category };
}) || [];
list.unshift({ value: "All", label: "All" });
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 />
@@ -40,19 +38,19 @@ function SettingsButton({ contentType, setContentType, theme }: any) {
</Menu.Target>
<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"
label='Quick Actions'
className={navLink.defaultNavLink}
classNames={navLink}
>
<NavLink
label="Wake Dakota"
label='Wake Dakota'
leftSection={<FiMonitor />}
onClick={() => runWakeCommand()}
className={navLink.defaultNavLink}
@@ -60,7 +58,7 @@ function SettingsButton({ contentType, setContentType, theme }: any) {
/>
</NavLink>
<Select
label="Homepage Filter"
label='Homepage Filter'
data={categories ?? []}
defaultValue={contentType}
withCheckIcon={false}