mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-22 10:51:02 +01:00
refactor(nav): Implement React Router for navigation
- Replace button-based navigation with React Router Links in Navbar - Add BrowserRouter, Routes, and Route components in App.js - Update Navbar to determine active tab based on current route - Remove setActiveTab prop from Navbar component - Update RegexPage, FormatPage, and SettingsPage imports in App.js - Adjust Navbar propTypes to remove activeTab and setActiveTab
This commit is contained in:
committed by
Sam Chau
parent
fd9d23a828
commit
330c162b0e
302
frontend/package-lock.json
generated
302
frontend/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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 (
|
||||
<>
|
||||
<div className="min-h-screen bg-gray-900 text-gray-100">
|
||||
<Navbar
|
||||
activeTab={activeTab}
|
||||
setActiveTab={setActiveTab}
|
||||
darkMode={darkMode}
|
||||
setDarkMode={setDarkMode}
|
||||
/>
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 mt-6">
|
||||
{activeTab === 'regex' && <RegexManager />}
|
||||
{activeTab === 'format' && <CustomFormatManager />}
|
||||
{activeTab === 'settings' && <Settings />}
|
||||
</div>
|
||||
<Router>
|
||||
<div className="min-h-screen bg-gray-900 text-gray-100">
|
||||
<Navbar darkMode={darkMode} setDarkMode={setDarkMode} />
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 mt-6">
|
||||
<Routes>
|
||||
<Route path="/regex" element={<RegexPage />} />
|
||||
<Route path="/format" element={<FormatPage />} />
|
||||
<Route path="/settings" element={<SettingsPage />} />
|
||||
<Route path="/" element={<SettingsPage />} />
|
||||
</Routes>
|
||||
</div>
|
||||
<ToastContainer position="top-right" autoClose={5000} hideProgressBar={false} newestOnTop={false} closeOnClick rtl={false} pauseOnFocusLoss draggable pauseOnHover />
|
||||
</>
|
||||
|
||||
</div>
|
||||
<ToastContainer
|
||||
position="top-right"
|
||||
autoClose={5000}
|
||||
hideProgressBar={false}
|
||||
newestOnTop={false}
|
||||
closeOnClick
|
||||
rtl={false}
|
||||
pauseOnFocusLoss
|
||||
draggable
|
||||
pauseOnHover
|
||||
/>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 mb-4">
|
||||
{sortedAndFilteredFormats.map((format) => (
|
||||
<FormatCard
|
||||
key={format.id}
|
||||
format={format}
|
||||
<FormatCard
|
||||
key={format.id}
|
||||
format={format}
|
||||
onEdit={() => 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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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 (
|
||||
<label className="flex items-center cursor-pointer">
|
||||
<div className="relative">
|
||||
<input type="checkbox" className="sr-only" checked={checked} onChange={onChange} />
|
||||
<div className={`block w-14 h-8 rounded-full ${checked ? 'bg-blue-600' : 'bg-gray-600'} transition-colors duration-300`}></div>
|
||||
<div className={`dot absolute left-1 top-1 bg-white w-6 h-6 rounded-full transition-transform duration-300 ${checked ? 'transform translate-x-6' : ''}`}></div>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only"
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<div
|
||||
className={`block w-14 h-8 rounded-full ${
|
||||
checked ? "bg-blue-600" : "bg-gray-600"
|
||||
} transition-colors duration-300`}
|
||||
></div>
|
||||
<div
|
||||
className={`dot absolute left-1 top-1 bg-white w-6 h-6 rounded-full transition-transform duration-300 ${
|
||||
checked ? "transform translate-x-6" : ""
|
||||
}`}
|
||||
></div>
|
||||
</div>
|
||||
<div className="ml-3 text-gray-300 font-medium">
|
||||
{checked ? 'Dark' : 'Light'}
|
||||
{checked ? "Dark" : "Light"}
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
@@ -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 }) {
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative">
|
||||
<div className="flex items-center justify-between h-16">
|
||||
<div className="flex items-center space-x-8">
|
||||
<h1 className="text-2xl font-bold text-white">
|
||||
Profilarr
|
||||
</h1>
|
||||
<h1 className="text-2xl font-bold text-white">Profilarr</h1>
|
||||
<div className="relative flex space-x-2">
|
||||
<div
|
||||
className="absolute top-0 bottom-0 bg-gray-900 rounded-md transition-all duration-300"
|
||||
style={{ left: tabOffset, width: tabWidth }}
|
||||
></div>
|
||||
<button
|
||||
ref={(el) => (tabsRef.current['regex'] = el)}
|
||||
<Link
|
||||
to="/regex"
|
||||
ref={(el) => (tabsRef.current["regex"] = el)}
|
||||
className={`px-3 py-2 rounded-md text-sm font-medium relative z-10 ${
|
||||
activeTab === 'regex' ? 'text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'
|
||||
activeTab === "regex"
|
||||
? "text-white"
|
||||
: "text-gray-300 hover:bg-gray-700 hover:text-white"
|
||||
}`}
|
||||
onClick={() => setActiveTab('regex')}
|
||||
>
|
||||
Regex
|
||||
</button>
|
||||
<button
|
||||
ref={(el) => (tabsRef.current['format'] = el)}
|
||||
</Link>
|
||||
<Link
|
||||
to="/format"
|
||||
ref={(el) => (tabsRef.current["format"] = el)}
|
||||
className={`px-3 py-2 rounded-md text-sm font-medium relative z-10 ${
|
||||
activeTab === 'format' ? 'text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'
|
||||
activeTab === "format"
|
||||
? "text-white"
|
||||
: "text-gray-300 hover:bg-gray-700 hover:text-white"
|
||||
}`}
|
||||
onClick={() => setActiveTab('format')}
|
||||
>
|
||||
Custom Format
|
||||
</button>
|
||||
<button
|
||||
ref={(el) => (tabsRef.current['settings'] = el)}
|
||||
</Link>
|
||||
<Link
|
||||
to="/settings"
|
||||
ref={(el) => (tabsRef.current["settings"] = el)}
|
||||
className={`px-3 py-2 rounded-md text-sm font-medium relative z-10 ${
|
||||
activeTab === 'settings' ? 'text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'
|
||||
activeTab === "settings"
|
||||
? "text-white"
|
||||
: "text-gray-300 hover:bg-gray-700 hover:text-white"
|
||||
}`}
|
||||
onClick={() => setActiveTab('settings')}
|
||||
>
|
||||
Settings
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<ToggleSwitch checked={darkMode} onChange={() => setDarkMode(!darkMode)} />
|
||||
<ToggleSwitch
|
||||
checked={darkMode}
|
||||
onChange={() => setDarkMode(!darkMode)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user