diff --git a/frontend/package-lock.json b/frontend/package-lock.json index fc86715..7032838 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,6 +16,8 @@ "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.26.1", + "react-syntax-highlighter": "^15.5.0", "react-toastify": "^10.0.5", "tailwind-merge": "^2.5.2" }, @@ -290,6 +292,17 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.4.tgz", + "integrity": "sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", @@ -865,6 +878,22 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.1.tgz", + "integrity": "sha512-S45oynt/WH19bHbIXjtli6QmwNYvaz+vtnubvNpNDvUOoA/OWh6j1OikIP3G+v5GHdxyC6EXoChG3HgYGEUfcg==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "dependencies": { + "@types/unist": "^2" + } + }, "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", @@ -890,6 +919,11 @@ "@types/react": "*" } }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" + }, "node_modules/@vitejs/plugin-react": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-3.1.0.tgz", @@ -1105,6 +1139,33 @@ "node": ">=4" } }, + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -1183,6 +1244,15 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -1369,6 +1439,18 @@ "reusify": "^1.0.4" } }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -1416,6 +1498,14 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -1538,6 +1628,61 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "engines": { + "node": "*" + } + }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1565,6 +1710,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1595,6 +1749,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -1689,6 +1852,19 @@ "loose-envify": "cli.js" } }, + "node_modules/lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "dependencies": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -1831,6 +2007,23 @@ "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", "dev": true }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2076,6 +2269,14 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -2086,6 +2287,18 @@ "react-is": "^16.13.1" } }, + "node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -2143,6 +2356,51 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.1.tgz", + "integrity": "sha512-kIwJveZNwp7teQRI5QmwWo39A5bXRyqpH0COKKmPnyD2vBvDwgFXSqDUYtt1h+FEyfnE8eXr7oe0MxRzVwCcvQ==", + "dependencies": { + "@remix-run/router": "1.19.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.1.tgz", + "integrity": "sha512-veut7m41S1fLql4pLhxeSW3jlqs+4MtjRLj0xvuCEXsxusJCbs6I8yn9BxzzDX2XDgafrccY6hwjmd/bL54tFw==", + "dependencies": { + "@remix-run/router": "1.19.1", + "react-router": "6.26.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-syntax-highlighter": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz", + "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "highlight.js": "^10.4.1", + "lowlight": "^1.17.0", + "prismjs": "^1.27.0", + "refractor": "^3.6.0" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, "node_modules/react-toastify": { "version": "10.0.5", "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz", @@ -2176,6 +2434,33 @@ "node": ">=8.10.0" } }, + "node_modules/refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/prismjs": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -2284,6 +2569,15 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -2764,6 +3058,14 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 809124d..cad409a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,6 +17,8 @@ "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.26.1", + "react-syntax-highlighter": "^15.5.0", "react-toastify": "^10.0.5", "tailwind-merge": "^2.5.2" }, diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index e25987e..e1cdc89 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,41 +1,48 @@ -import { useState, useEffect } from 'react'; -import RegexManager from './components/regex/RegexManager'; -import CustomFormatManager from './components/format/FormatManager'; -import Settings from './components/settings/SettingsManager'; -import Navbar from './components/ui/Navbar'; -import { ToastContainer } from 'react-toastify'; -import 'react-toastify/dist/ReactToastify.css'; +import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; +import { useState, useEffect } from "react"; +import RegexPage from "./components/regex/RegexPage"; +import FormatPage from "./components/format/FormatPage"; +import SettingsPage from "./components/settings/SettingsPage"; +import Navbar from "./components/ui/Navbar"; +import { ToastContainer } from "react-toastify"; +import "react-toastify/dist/ReactToastify.css"; function App() { - const [activeTab, setActiveTab] = useState('settings'); const [darkMode, setDarkMode] = useState(true); useEffect(() => { if (darkMode) { - document.documentElement.classList.add('dark'); + document.documentElement.classList.add("dark"); } else { - document.documentElement.classList.remove('dark'); + document.documentElement.classList.remove("dark"); } }, [darkMode]); return ( - <> -
- -
- {activeTab === 'regex' && } - {activeTab === 'format' && } - {activeTab === 'settings' && } -
+ +
+ +
+ + } /> + } /> + } /> + } /> +
- - - +
+ +
); } diff --git a/frontend/src/components/format/FormatManager.jsx b/frontend/src/components/format/FormatPage.jsx similarity index 66% rename from frontend/src/components/format/FormatManager.jsx rename to frontend/src/components/format/FormatPage.jsx index f07ef4f..9a2b972 100644 --- a/frontend/src/components/format/FormatManager.jsx +++ b/frontend/src/components/format/FormatPage.jsx @@ -1,18 +1,18 @@ -import { useState, useEffect } from 'react'; -import FormatCard from './FormatCard'; -import FormatModal from './FormatModal'; -import AddNewCard from '../ui/AddNewCard'; -import { getFormats } from '../../api/api'; -import FilterMenu from '../ui/FilterMenu'; -import SortMenu from '../ui/SortMenu'; +import { useState, useEffect } from "react"; +import FormatCard from "./FormatCard"; +import FormatModal from "./FormatModal"; +import AddNewCard from "../ui/AddNewCard"; +import { getFormats } from "../../api/api"; +import FilterMenu from "../ui/FilterMenu"; +import SortMenu from "../ui/SortMenu"; -function FormatManager() { +function FormatPage() { const [formats, setFormats] = useState([]); const [isModalOpen, setIsModalOpen] = useState(false); const [selectedFormat, setSelectedFormat] = useState(null); - const [sortBy, setSortBy] = useState('title'); - const [filterType, setFilterType] = useState('none'); - const [filterValue, setFilterValue] = useState(''); + const [sortBy, setSortBy] = useState("title"); + const [filterType, setFilterType] = useState("none"); + const [filterValue, setFilterValue] = useState(""); const [allTags, setAllTags] = useState([]); useEffect(() => { @@ -23,10 +23,12 @@ function FormatManager() { try { const fetchedFormats = await getFormats(); setFormats(fetchedFormats); - const tags = [...new Set(fetchedFormats.flatMap(format => format.tags || []))]; + const tags = [ + ...new Set(fetchedFormats.flatMap((format) => format.tags || [])), + ]; setAllTags(tags); } catch (error) { - console.error('Error fetching formats:', error); + console.error("Error fetching formats:", error); } }; @@ -46,10 +48,10 @@ function FormatManager() { }; const handleCloneFormat = (format) => { - const clonedFormat = { - ...format, + const clonedFormat = { + ...format, id: 0, // Ensure the ID is 0 for a new entry - name: `${format.name} [COPY]` + name: `${format.name} [COPY]`, }; setSelectedFormat(clonedFormat); // Set cloned format setIsModalOpen(true); // Open modal in Add mode @@ -60,11 +62,11 @@ function FormatManager() { }; const sortedAndFilteredFormats = formats - .filter(format => { - if (filterType === 'tag') { + .filter((format) => { + if (filterType === "tag") { return format.tags && format.tags.includes(filterValue); } - if (filterType === 'date') { + if (filterType === "date") { const formatDate = new Date(format.date_modified); const filterDate = new Date(filterValue); return formatDate.toDateString() === filterDate.toDateString(); @@ -72,9 +74,11 @@ function FormatManager() { return true; }) .sort((a, b) => { - if (sortBy === 'title') return a.name.localeCompare(b.name); - if (sortBy === 'dateCreated') return new Date(b.date_created) - new Date(a.date_created); - if (sortBy === 'dateModified') return new Date(b.date_modified) - new Date(a.date_modified); + if (sortBy === "title") return a.name.localeCompare(b.name); + if (sortBy === "dateCreated") + return new Date(b.date_created) - new Date(a.date_created); + if (sortBy === "dateModified") + return new Date(b.date_modified) - new Date(a.date_modified); return 0; }); @@ -93,12 +97,12 @@ function FormatManager() {
{sortedAndFilteredFormats.map((format) => ( - handleOpenModal(format)} onClone={handleCloneFormat} // Pass the clone handler - showDate={sortBy !== 'title'} + showDate={sortBy !== "title"} formatDate={formatDate} /> ))} @@ -115,4 +119,4 @@ function FormatManager() { ); } -export default FormatManager; +export default FormatPage; diff --git a/frontend/src/components/regex/RegexManager.jsx b/frontend/src/components/regex/RegexPage.jsx similarity index 67% rename from frontend/src/components/regex/RegexManager.jsx rename to frontend/src/components/regex/RegexPage.jsx index d35de46..7e460db 100644 --- a/frontend/src/components/regex/RegexManager.jsx +++ b/frontend/src/components/regex/RegexPage.jsx @@ -1,18 +1,18 @@ -import { useState, useEffect } from 'react'; -import RegexCard from './RegexCard'; -import RegexModal from './RegexModal'; -import AddNewCard from '../ui/AddNewCard'; -import { getRegexes } from '../../api/api'; -import FilterMenu from '../ui/FilterMenu'; -import SortMenu from '../ui/SortMenu'; +import { useState, useEffect } from "react"; +import RegexCard from "./RegexCard"; +import RegexModal from "./RegexModal"; +import AddNewCard from "../ui/AddNewCard"; +import { getRegexes } from "../../api/api"; +import FilterMenu from "../ui/FilterMenu"; +import SortMenu from "../ui/SortMenu"; -function RegexManager() { +function RegexPage() { const [regexes, setRegexes] = useState([]); const [isModalOpen, setIsModalOpen] = useState(false); const [selectedRegex, setSelectedRegex] = useState(null); - const [sortBy, setSortBy] = useState('title'); - const [filterType, setFilterType] = useState('none'); - const [filterValue, setFilterValue] = useState(''); + const [sortBy, setSortBy] = useState("title"); + const [filterType, setFilterType] = useState("none"); + const [filterValue, setFilterValue] = useState(""); const [allTags, setAllTags] = useState([]); useEffect(() => { @@ -23,10 +23,12 @@ function RegexManager() { try { const fetchedRegexes = await getRegexes(); setRegexes(fetchedRegexes); - const tags = [...new Set(fetchedRegexes.flatMap(regex => regex.tags || []))]; + const tags = [ + ...new Set(fetchedRegexes.flatMap((regex) => regex.tags || [])), + ]; setAllTags(tags); } catch (error) { - console.error('Error fetching regexes:', error); + console.error("Error fetching regexes:", error); } }; @@ -46,11 +48,11 @@ function RegexManager() { }; const handleCloneRegex = (regex) => { - const clonedRegex = { - ...regex, + const clonedRegex = { + ...regex, id: 0, // Ensure the ID is 0 for a new entry - name: `${regex.name} [COPY]`, - regex101Link: '' // Remove the regex101 link + name: `${regex.name} [COPY]`, + regex101Link: "", // Remove the regex101 link }; setSelectedRegex(clonedRegex); // Set cloned regex setIsModalOpen(true); // Open modal in Add mode @@ -61,11 +63,11 @@ function RegexManager() { }; const sortedAndFilteredRegexes = regexes - .filter(regex => { - if (filterType === 'tag') { + .filter((regex) => { + if (filterType === "tag") { return regex.tags && regex.tags.includes(filterValue); } - if (filterType === 'date') { + if (filterType === "date") { const regexDate = new Date(regex.date_modified); const filterDate = new Date(filterValue); return regexDate.toDateString() === filterDate.toDateString(); @@ -73,9 +75,11 @@ function RegexManager() { return true; }) .sort((a, b) => { - if (sortBy === 'title') return a.name.localeCompare(b.name); - if (sortBy === 'dateCreated') return new Date(b.date_created) - new Date(a.date_created); - if (sortBy === 'dateModified') return new Date(b.date_modified) - new Date(a.date_modified); + if (sortBy === "title") return a.name.localeCompare(b.name); + if (sortBy === "dateCreated") + return new Date(b.date_created) - new Date(a.date_created); + if (sortBy === "dateModified") + return new Date(b.date_modified) - new Date(a.date_modified); return 0; }); @@ -99,7 +103,7 @@ function RegexManager() { regex={regex} onEdit={() => handleOpenModal(regex)} onClone={handleCloneRegex} // Pass the clone handler - showDate={sortBy !== 'title'} + showDate={sortBy !== "title"} formatDate={formatDate} /> ))} @@ -116,4 +120,4 @@ function RegexManager() { ); } -export default RegexManager; +export default RegexPage; diff --git a/frontend/src/components/settings/SettingsManager.jsx b/frontend/src/components/settings/SettingsPage.jsx similarity index 99% rename from frontend/src/components/settings/SettingsManager.jsx rename to frontend/src/components/settings/SettingsPage.jsx index bc51504..5570e66 100644 --- a/frontend/src/components/settings/SettingsManager.jsx +++ b/frontend/src/components/settings/SettingsPage.jsx @@ -33,7 +33,7 @@ import CommitSection from "./CommitSection"; import Tooltip from "../ui/Tooltip"; import DiffModal from "./DiffModal"; -const SettingsManager = () => { +const SettingsPage = () => { const [settings, setSettings] = useState(null); const [status, setStatus] = useState(null); const [showModal, setShowModal] = useState(false); @@ -637,4 +637,4 @@ const SettingsManager = () => { ); }; -export default SettingsManager; +export default SettingsPage; diff --git a/frontend/src/components/ui/Navbar.jsx b/frontend/src/components/ui/Navbar.jsx index b5d381e..aa7bbda 100644 --- a/frontend/src/components/ui/Navbar.jsx +++ b/frontend/src/components/ui/Navbar.jsx @@ -1,16 +1,30 @@ -import PropTypes from 'prop-types'; -import { useState, useEffect, useRef } from 'react'; +import PropTypes from "prop-types"; +import { useState, useEffect, useRef } from "react"; +import { Link, useLocation } from "react-router-dom"; function ToggleSwitch({ checked, onChange }) { return ( ); @@ -21,10 +35,20 @@ ToggleSwitch.propTypes = { onChange: PropTypes.func.isRequired, }; -function Navbar({ activeTab, setActiveTab, darkMode, setDarkMode }) { +function Navbar({ darkMode, setDarkMode }) { const [tabOffset, setTabOffset] = useState(0); const [tabWidth, setTabWidth] = useState(0); - const tabsRef = useRef([]); + const tabsRef = useRef({}); + const location = useLocation(); + + const getActiveTab = (pathname) => { + if (pathname.startsWith("/regex")) return "regex"; + if (pathname.startsWith("/format")) return "format"; + if (pathname.startsWith("/settings")) return "settings"; + return "settings"; // default to settings if no match + }; + + const activeTab = getActiveTab(location.pathname); useEffect(() => { if (tabsRef.current[activeTab]) { @@ -39,44 +63,51 @@ function Navbar({ activeTab, setActiveTab, darkMode, setDarkMode }) {
-

- Profilarr -

+

Profilarr

- - - +
- setDarkMode(!darkMode)} /> + setDarkMode(!darkMode)} + />
@@ -84,8 +115,6 @@ function Navbar({ activeTab, setActiveTab, darkMode, setDarkMode }) { } Navbar.propTypes = { - activeTab: PropTypes.string.isRequired, - setActiveTab: PropTypes.func.isRequired, darkMode: PropTypes.bool.isRequired, setDarkMode: PropTypes.func.isRequired, };