diff --git a/package.json b/package.json
index d8a09f2..6512352 100644
--- a/package.json
+++ b/package.json
@@ -15,9 +15,11 @@
"@mui/icons-material": "^5.16.4",
"@mui/material": "^5.16.4",
"@mui/styled-engine-sc": "6.0.0-alpha.18",
+ "@types/uuid": "^10.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"styled-components": "^6.1.12",
+ "uuid": "^10.0.0",
"wouter": "^3.3.1"
},
"devDependencies": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3a6fcb4..a57a22f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -26,6 +26,9 @@ importers:
'@mui/styled-engine-sc':
specifier: 6.0.0-alpha.18
version: 6.0.0-alpha.18(styled-components@6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@types/uuid':
+ specifier: ^10.0.0
+ version: 10.0.0
react:
specifier: ^18.2.0
version: 18.3.1
@@ -35,6 +38,9 @@ importers:
styled-components:
specifier: ^6.1.12
version: 6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ uuid:
+ specifier: ^10.0.0
+ version: 10.0.0
wouter:
specifier: ^3.3.1
version: 3.3.1(react@18.3.1)
@@ -651,6 +657,9 @@ packages:
'@types/stylis@4.2.5':
resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==}
+ '@types/uuid@10.0.0':
+ resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==}
+
'@types/webextension-polyfill@0.10.7':
resolution: {integrity: sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==}
@@ -1682,6 +1691,10 @@ packages:
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ uuid@10.0.0:
+ resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
+ hasBin: true
+
uuid@8.3.2:
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
hasBin: true
@@ -2361,6 +2374,8 @@ snapshots:
'@types/stylis@4.2.5': {}
+ '@types/uuid@10.0.0': {}
+
'@types/webextension-polyfill@0.10.7': {}
'@vitejs/plugin-react@4.3.1(vite@5.3.4(@types/node@20.14.11))':
@@ -3385,6 +3400,8 @@ snapshots:
util-deprecate@1.0.2: {}
+ uuid@10.0.0: {}
+
uuid@8.3.2: {}
vite-plugin-web-extension@4.1.6(@types/node@20.14.11):
diff --git a/src/index.tsx b/src/index.tsx
index 02ed79b..eb08771 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -11,6 +11,7 @@ import theme from './theme';
import { DrawerOpenContextProvider } from './shared/contexts/DrawerOpenContext';
import { CurrentPageContextProvider } from './shared/contexts/CurrentPageContext';
import { ConfigurableLinksContextProvider } from './shared/contexts/ConfiguarableLinksContext';
+import { SnackBarValuesContextProvider } from './shared/contexts/SnackBarValuesConext';
ReactDOM.createRoot(document.getElementById('root')!).render(
@@ -19,7 +20,9 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
-
+
+
+
diff --git a/src/shared/classes/HomeplageLink.ts b/src/shared/classes/HomeplageLink.ts
new file mode 100644
index 0000000..5424551
--- /dev/null
+++ b/src/shared/classes/HomeplageLink.ts
@@ -0,0 +1,16 @@
+import { IHomepageLink } from "../interfaces/IHomepageLink";
+import * as uuid from 'uuid';
+
+export class HomepageLink implements IHomepageLink {
+ title: string;
+ subtitle: string;
+ hyperlink: string;
+ uuid: string
+
+ constructor() {
+ this.title = ""
+ this.subtitle = ""
+ this.hyperlink = ""
+ this.uuid = uuid.v4()
+ }
+}
\ No newline at end of file
diff --git a/src/shared/components/AppSnackBar.tsx b/src/shared/components/AppSnackBar.tsx
new file mode 100644
index 0000000..56dfeb7
--- /dev/null
+++ b/src/shared/components/AppSnackBar.tsx
@@ -0,0 +1,41 @@
+import { useContext } from "react";
+import { SnackBarValuesContext } from "../contexts/SnackBarValuesConext";
+import { IconButton, Snackbar, SnackbarCloseReason } from "@mui/material";
+import CloseIcon from '@mui/icons-material/Close';
+
+export default function() {
+ const {snackBarValues, setSnackBarValues} = useContext(SnackBarValuesContext)
+
+ const handleClose = (
+ event: React.SyntheticEvent | Event,
+ reason?: SnackbarCloseReason
+ ) => {
+ if (reason === 'clickaway') {
+ return
+ }
+ setSnackBarValues({open: false, message: ""})
+ }
+
+ const action = (
+ <>
+
+
+
+ >
+ )
+
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/src/shared/components/LinkList.tsx b/src/shared/components/LinkList.tsx
new file mode 100644
index 0000000..ce62937
--- /dev/null
+++ b/src/shared/components/LinkList.tsx
@@ -0,0 +1,32 @@
+import Sites from '@Data/sites.json'
+import { Grid } from "@mui/material";
+import LinkCard from "./linkcard";
+import { useContext } from 'react';
+import { ConfigurableLinksContext } from '../contexts/ConfiguarableLinksContext';
+
+export default function LinkList() {
+ const {configurableLinks, setConfigurableLinks} = useContext(ConfigurableLinksContext)
+
+ return (
+
+ {Sites.sites.map(site => (
+
+
+
+ ))}
+ {configurableLinks.map(link => (
+
+
+
+ ))}
+
+ )
+}
\ No newline at end of file
diff --git a/src/shared/components/settingsPage.tsx b/src/shared/components/settingsPage.tsx
index 5e26f71..7847eb3 100644
--- a/src/shared/components/settingsPage.tsx
+++ b/src/shared/components/settingsPage.tsx
@@ -1,69 +1,120 @@
import { Button, Grid, styled, TextField, Typography } from "@mui/material";
-import { useContext, useState } from "react";
-import { HomepageLink } from "../interfaces/HomepageLink.interface";
-import { ConfigurableLinksContext } from "../contexts/ConfiguarableLinksContext";
-
-const FormGrid = styled(Grid)(() => ({
- display: 'flex',
- flexDirection: 'column'
-}))
-
-interface FormRowProps {
- index: number
- link: HomepageLink
-}
+import { useContext, useEffect, useState } from "react";
+import { IHomepageLink } from "../interfaces/IHomepageLink";
+import { HomepageLink } from "../classes/HomeplageLink";
+import { SnackBarValuesContext } from "../contexts/SnackBarValuesConext";
export default function SettingsPage() {
- const {configurableLinks, setConfigurableLinks} = useContext(ConfigurableLinksContext)
+ const [configurableLinks, setConfigurableLinks] = useState>(
+ JSON.parse(localStorage.getItem("configurableLinks") as string) as Array ??
+ new Array
+ )
+ const {snackBarValues, setSnackBarValues} = useContext(SnackBarValuesContext)
+
const handleChange = (index: number, event: React.ChangeEvent) => {
let newconfigurableLinks = [...configurableLinks]
- newconfigurableLinks[index][event.target.name as keyof HomepageLink] = event.target.value
+ newconfigurableLinks[index][event.target.name as keyof IHomepageLink] = event.target.value
setConfigurableLinks(newconfigurableLinks)
}
- const addFields = () => {
- setConfigurableLinks([...configurableLinks, {} as HomepageLink])
+ const handleBlur = () => {
+ if (LinkNotEmpty(configurableLinks[configurableLinks.length -1])) {
+ addFields()
+ }
+ if (configurableLinks.length > 1) {
+ if (LinkEmpty(configurableLinks[configurableLinks.length -2])) {
+ deleteFieldsAt(configurableLinks.length -2)
+ }
+ }
}
+ function LinkNotEmpty(link: IHomepageLink): Boolean {
+ return link.title != "" &&
+ link.subtitle != "" &&
+ link.hyperlink != ""
+ }
+
+ function LinkEmpty(link: IHomepageLink): Boolean {
+ return link.title == "" &&
+ link.subtitle == "" &&
+ link.hyperlink == ""
+ }
+
+ const addFields = () => {
+ setConfigurableLinks([...configurableLinks, new HomepageLink()])
+ }
+
+ const deleteFieldsAt = (index: number) => {
+ setConfigurableLinks(configurableLinks.filter((link) => {return link != configurableLinks[index]}))
+ }
+
+ const saveToLocalStorage = () => {
+ localStorage.setItem("configurableLinks", JSON.stringify(configurableLinks.filter((link) => {return link != configurableLinks[configurableLinks.length -1]})))
+ setSnackBarValues({open: true, message: "Saved Links"})
+ }
+
+ useEffect(() => {
+ addFields()
+ return () => {
+ alert("Will close settings")
+ }
+ }, [])
+
return (
-
+
{configurableLinks.map((link, index) =>(
- <>
-
- handleChange(index, e)}
- />
+
+
+ handleChange(index, e)}
+ onBlur={handleBlur}
+ />
+
+
+ handleChange(index, e)}
+ onBlur={handleBlur}
+ />
+
+
+ handleChange(index, e)}
+ onBlur={handleBlur}
+ />
+
+ {(configurableLinks.length > 1 && index != configurableLinks.length -1)? (
+
+
+
+ ):null}
-
- handleChange(index, e)}
- />
-
-
- handleChange(index, e)}
- />
-
- >
))}
-
+
)
diff --git a/src/shared/contexts/ConfiguarableLinksContext.tsx b/src/shared/contexts/ConfiguarableLinksContext.tsx
index 7637921..45e3236 100644
--- a/src/shared/contexts/ConfiguarableLinksContext.tsx
+++ b/src/shared/contexts/ConfiguarableLinksContext.tsx
@@ -1,19 +1,19 @@
import { createContext, Dispatch, SetStateAction, useState } from "react"
-import { HomepageLink } from "../interfaces/HomepageLink.interface"
+import { IHomepageLink } from "../interfaces/IHomepageLink"
import { ContainerProps } from "@mui/material"
type ConfigurableLinksContextType = {
- configurableLinks: Array,
- setConfigurableLinks: Dispatch>>
+ configurableLinks: Array,
+ setConfigurableLinks: Dispatch>>
}
const ConfigurableLinksContext = createContext({
- configurableLinks: new Array,
+ configurableLinks: new Array,
setConfigurableLinks: () => {}
})
const ConfigurableLinksContextProvider = (props: ContainerProps) => {
- const [configurableLinks, setConfigurableLinks] = useState(new Array)
+ const [configurableLinks, setConfigurableLinks] = useState(new Array)
return (
diff --git a/src/shared/contexts/DrawerOpenContext.tsx b/src/shared/contexts/DrawerOpenContext.tsx
index 4cc02c6..11f3c2a 100644
--- a/src/shared/contexts/DrawerOpenContext.tsx
+++ b/src/shared/contexts/DrawerOpenContext.tsx
@@ -1,4 +1,3 @@
-
import { ContainerProps } from "@mui/material";
import { createContext, Dispatch, SetStateAction, useState } from "react";
diff --git a/src/shared/contexts/SnackBarValuesConext.tsx b/src/shared/contexts/SnackBarValuesConext.tsx
new file mode 100644
index 0000000..7d4c70d
--- /dev/null
+++ b/src/shared/contexts/SnackBarValuesConext.tsx
@@ -0,0 +1,25 @@
+import { createContext, Dispatch, SetStateAction, useState } from "react"
+import { ISnackBarValues } from "../interfaces/ISnackBarValues"
+import { ContainerProps } from "@mui/material"
+
+type SnackBarValuesContextType = {
+ snackBarValues: ISnackBarValues,
+ setSnackBarValues: Dispatch>
+}
+
+const SnackBarValuesContext = createContext({
+ snackBarValues: {open: false, message: ""} as ISnackBarValues,
+ setSnackBarValues: () => {}
+})
+
+const SnackBarValuesContextProvider = (props: ContainerProps) => {
+ const [snackBarValues, setSnackBarValues] = useState({open: false, message: ""})
+
+ return (
+
+ {props.children}
+
+ )
+}
+
+export {SnackBarValuesContext, SnackBarValuesContextProvider}
\ No newline at end of file
diff --git a/src/shared/interfaces/HomepageLink.interface.ts b/src/shared/interfaces/IHomepageLink.ts
similarity index 65%
rename from src/shared/interfaces/HomepageLink.interface.ts
rename to src/shared/interfaces/IHomepageLink.ts
index cc95389..ad899ae 100644
--- a/src/shared/interfaces/HomepageLink.interface.ts
+++ b/src/shared/interfaces/IHomepageLink.ts
@@ -1,4 +1,4 @@
-export interface HomepageLink {
+export interface IHomepageLink {
title: string
subtitle: string,
hyperlink: string
diff --git a/src/shared/interfaces/ISnackBarValues.ts b/src/shared/interfaces/ISnackBarValues.ts
new file mode 100644
index 0000000..51fdfdf
--- /dev/null
+++ b/src/shared/interfaces/ISnackBarValues.ts
@@ -0,0 +1,4 @@
+export interface ISnackBarValues {
+ open: boolean
+ message: string
+}
\ No newline at end of file
diff --git a/src/site/App.tsx b/src/site/App.tsx
index e1fb041..fa0f4f1 100644
--- a/src/site/App.tsx
+++ b/src/site/App.tsx
@@ -3,10 +3,11 @@ import { Box, Button, debounce, FormLabel, Grid, OutlinedInput, styled, TextFiel
import React, { useContext, useState } from 'react'
import MenuBar from '../shared/components/MenuBar'
import LinkCard from '../shared/components/linkcard'
-import { Link, Route } from 'wouter'
import MenuDrawer from '../shared/components/menudrawer'
import { CurrentPageContext } from '../shared/contexts/CurrentPageContext'
import SettingsPage from '../shared/components/settingsPage'
+import LinkList from '../shared/components/LinkList'
+import AppSnackBar from '../shared/components/AppSnackBar'
const useLocalStorage = (storageKey: string, fallbackState: any) => {
const [value, setValue] = React.useState(
@@ -21,7 +22,6 @@ const useLocalStorage = (storageKey: string, fallbackState: any) => {
function App() {
const {currentPage, setCurrentPage} = useContext(CurrentPageContext)
- const [drawerOpen, setDrawerOpen] = useState(false)
return (
<>
@@ -29,22 +29,13 @@ function App() {
{currentPage === 'home' ? (
-
- {Sites.sites.map(site => (
-
-
-
- ))}
-
+
): null}
{currentPage === 'edit' ? (
): null}
+
>
)
}