diff --git a/CHANGELOG.md b/CHANGELOG.md index 83187b91e..bebe3620c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +### 📌 **dev 25w21 (5/19/2025 - 5/26/2025)** +- **Account Settings**: Renamed the folder from `Account` to `Account Settings` for better clarity. +- **Code**: Module route configs are now stored in a separate file in each module directory and loaded dynamically in the routing mechanism. +- **Code**: Massive mechanism refactor to load module routes dynamically. +- **Code**: Renamed `layout` folder to `routes` for better clarity. + ### 📌 **dev 25w20 (5/12/2025 - 5/19/2025)** - **Wallet**: Fixed a bug where the order of the transactions doesn't update when the user update the date of a transaction. - **Wallet**: Fixed a critical bug where the page will crash when user tries to load the dashboard. diff --git a/src/apps/Achievements/config.tsx b/src/apps/Achievements/config.tsx new file mode 100644 index 000000000..db29a4c3d --- /dev/null +++ b/src/apps/Achievements/config.tsx @@ -0,0 +1,13 @@ +import { IconAward } from '@tabler/icons-react' +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Achievements', + icon: , + routes: { + achievements: lazy(() => import('.')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/apps/BooksLibrary/config.tsx b/src/apps/BooksLibrary/config.tsx new file mode 100644 index 000000000..645b0da99 --- /dev/null +++ b/src/apps/BooksLibrary/config.tsx @@ -0,0 +1,12 @@ +import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces' +import { lazy } from 'react' + +export default { + name: 'Books Library', + icon: 'tabler:books', + provider: lazy(() => import('./providers/BooksLibraryProvider')), + routes: { + '': lazy(() => import('.')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/apps/Calendar/config.tsx b/src/apps/Calendar/config.tsx new file mode 100644 index 000000000..71d061bbf --- /dev/null +++ b/src/apps/Calendar/config.tsx @@ -0,0 +1,13 @@ +import { IconCalendar } from '@tabler/icons-react' +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Calendar', + icon: , + routes: { + calendar: lazy(() => import('.')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/apps/CodeTime/config.tsx b/src/apps/CodeTime/config.tsx new file mode 100644 index 000000000..f45510986 --- /dev/null +++ b/src/apps/CodeTime/config.tsx @@ -0,0 +1,11 @@ +import { IconCode } from '@tabler/icons-react' +import { lazy } from 'react' + +export default { + name: 'Code Time', + icon: , + routes: { + 'code-time': lazy(() => import('.')) + }, + togglable: true +} diff --git a/src/apps/CurrencyConverter/config.tsx b/src/apps/CurrencyConverter/config.tsx new file mode 100644 index 000000000..eff999c5b --- /dev/null +++ b/src/apps/CurrencyConverter/config.tsx @@ -0,0 +1,12 @@ +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Currency Converter', + icon: 'tabler:currency-dollar', + routes: { + 'currency-converter': lazy(() => import('.')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/apps/GuitarTabs/config.tsx b/src/apps/GuitarTabs/config.tsx new file mode 100644 index 000000000..3891d17d4 --- /dev/null +++ b/src/apps/GuitarTabs/config.tsx @@ -0,0 +1,12 @@ +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Guitar Tabs', + icon: 'mingcute:guitar-line', + routes: { + 'guitar-tabs': lazy(() => import('.')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/apps/IdeaBox/config.tsx b/src/apps/IdeaBox/config.tsx new file mode 100644 index 000000000..7a88b861b --- /dev/null +++ b/src/apps/IdeaBox/config.tsx @@ -0,0 +1,15 @@ +import { IconBulb } from '@tabler/icons-react' +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Idea Box', + provider: lazy(() => import('./providers/IdeaBoxProvider')), + icon: , + routes: { + '': lazy(() => import('./pages/Containers')), + ':id/*': lazy(() => import('./pages/Ideas')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/apps/MomentVault/config.tsx b/src/apps/MomentVault/config.tsx new file mode 100644 index 000000000..6790d745d --- /dev/null +++ b/src/apps/MomentVault/config.tsx @@ -0,0 +1,14 @@ +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Moment Vault', + icon: 'tabler:history', + hasAI: true, + routes: { + 'moment-vault': lazy(() => import('.')) + }, + togglable: true, + requiredAPIKeys: ['openai'] +} satisfies ModuleConfig diff --git a/src/apps/Movies/config.tsx b/src/apps/Movies/config.tsx new file mode 100644 index 000000000..614c86eb1 --- /dev/null +++ b/src/apps/Movies/config.tsx @@ -0,0 +1,13 @@ +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Movies', + icon: 'tabler:movie', + routes: { + movies: lazy(() => import('.')) + }, + togglable: true, + requiredAPIKeys: ['tmdb'] +} satisfies ModuleConfig diff --git a/src/apps/Music/config.tsx b/src/apps/Music/config.tsx new file mode 100644 index 000000000..f0c06b167 --- /dev/null +++ b/src/apps/Music/config.tsx @@ -0,0 +1,12 @@ +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Music', + icon: 'tabler:music', + routes: { + music: lazy(() => import('.')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/apps/Passwords/config.tsx b/src/apps/Passwords/config.tsx new file mode 100644 index 000000000..a5788a72d --- /dev/null +++ b/src/apps/Passwords/config.tsx @@ -0,0 +1,13 @@ +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Passwords', + icon: 'tabler:key', + provider: lazy(() => import('./providers/PasswordsProvider')), + routes: { + '': lazy(() => import('.')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/apps/RailwayMap/config.tsx b/src/apps/RailwayMap/config.tsx new file mode 100644 index 000000000..5dc611278 --- /dev/null +++ b/src/apps/RailwayMap/config.tsx @@ -0,0 +1,13 @@ +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Railway Map', + icon: 'uil:subway', + provider: lazy(() => import('./providers/RailwayMapProvider')), + routes: { + '': lazy(() => import('.')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/apps/Sudoku/config.tsx b/src/apps/Sudoku/config.tsx new file mode 100644 index 000000000..f3073af63 --- /dev/null +++ b/src/apps/Sudoku/config.tsx @@ -0,0 +1,12 @@ +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Sudoku', + icon: 'uil:table', + routes: { + sudoku: lazy(() => import('.')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/apps/TodoList/config.tsx b/src/apps/TodoList/config.tsx new file mode 100644 index 000000000..1048c3c3e --- /dev/null +++ b/src/apps/TodoList/config.tsx @@ -0,0 +1,15 @@ +import { IconListCheck } from '@tabler/icons-react' +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Todo List', + icon: , + routes: { + 'todo-list': lazy(() => import('@apps/TodoList')) + }, + togglable: true, + hasAI: true, + requiredAPIKeys: ['groq'] +} satisfies ModuleConfig diff --git a/src/apps/VirtualWardrobe/config.tsx b/src/apps/VirtualWardrobe/config.tsx new file mode 100644 index 000000000..02db0442f --- /dev/null +++ b/src/apps/VirtualWardrobe/config.tsx @@ -0,0 +1,27 @@ +import { lazy } from 'react' +import { Navigate } from 'react-router' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Virtual Wardrobe', + icon: 'tabler:shirt', + subsection: [ + { + name: 'Virtual Wardrobe Clothes', + icon: 'tabler:shirt', + path: 'clothes' + }, + { + name: 'Virtual Wardrobe Outfits', + icon: 'tabler:layout', + path: 'outfits' + } + ], + routes: { + 'virtual-wardrobe': () => , + 'virtual-wardrobe/clothes': lazy(() => import('./pages/Clothes')), + 'virtual-wardrobe/outfits': lazy(() => import('./pages/Outfits')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/apps/Wallet/config.tsx b/src/apps/Wallet/config.tsx new file mode 100644 index 000000000..29c99ba87 --- /dev/null +++ b/src/apps/Wallet/config.tsx @@ -0,0 +1,40 @@ +import { + IconArrowsExchange, + IconBook, + IconCurrencyDollar, + IconDashboard, + IconFileText, + IconWallet +} from '@tabler/icons-react' +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Wallet', + icon: , + hasAI: true, + subsection: [ + { name: 'Dashboard', icon: , path: '' }, + { + name: 'Transactions', + icon: , + path: 'transactions' + }, + { name: 'Assets', icon: , path: 'assets' }, + { name: 'Ledgers', icon: , path: 'ledgers' }, + { + name: 'Financial Statements', + icon: , + path: 'statements' + } + ], + routes: { + wallet: lazy(() => import('./pages/Dashboard')), + 'wallet/transactions': lazy(() => import('./pages/Transactions')), + 'wallet/assets': lazy(() => import('./pages/Assets')), + 'wallet/ledgers': lazy(() => import('./pages/Ledgers')), + 'wallet/statements': lazy(() => import('./pages/Statements')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/apps/Wishlist/config.tsx b/src/apps/Wishlist/config.tsx new file mode 100644 index 000000000..eaa492f81 --- /dev/null +++ b/src/apps/Wishlist/config.tsx @@ -0,0 +1,14 @@ +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Wishlist', + icon: 'tabler:heart', + routes: { + wishlist: lazy(() => import('./pages/WishlistList')), + 'wishlist/:id': lazy(() => import('./pages/WishlistEntries')) + }, + togglable: true, + hasAI: true +} satisfies ModuleConfig diff --git a/src/apps/YoutubeSummarizer/config.tsx b/src/apps/YoutubeSummarizer/config.tsx new file mode 100644 index 000000000..8036d91d7 --- /dev/null +++ b/src/apps/YoutubeSummarizer/config.tsx @@ -0,0 +1,14 @@ +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Youtube Summarizer', + icon: 'tabler:brand-youtube', + routes: { + 'youtube-summarizer': lazy(() => import('.')) + }, + togglable: true, + requiredAPIKeys: ['groq'], + hasAI: true +} satisfies ModuleConfig diff --git a/src/apps/YoutubeVideos/config.tsx b/src/apps/YoutubeVideos/config.tsx new file mode 100644 index 000000000..9ec5d2014 --- /dev/null +++ b/src/apps/YoutubeVideos/config.tsx @@ -0,0 +1,12 @@ +import { lazy } from 'react' + +import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces' + +export default { + name: 'Youtube Videos', + icon: 'tabler:brand-youtube', + routes: { + 'youtube-videos': lazy(() => import('.')) + }, + togglable: true +} satisfies ModuleConfig diff --git a/src/core/App.tsx b/src/core/App.tsx index 41050ddef..588a721ba 100644 --- a/src/core/App.tsx +++ b/src/core/App.tsx @@ -22,7 +22,7 @@ import '@lifeforge/ui/dist/index.css' import './i18n' import './index.css' -import AppRouter from './layout/index.tsx' +import AppRouter from './routes/index.tsx' dayjs.extend(duration) dayjs.extend(isBetween) diff --git a/src/core/Routes.tsx b/src/core/Routes.tsx deleted file mode 100644 index 1360c2bf0..000000000 --- a/src/core/Routes.tsx +++ /dev/null @@ -1,382 +0,0 @@ -import { - IconArrowsExchange, - IconAward, - IconBook, - IconBooks, - IconBulb, - IconCalendar, - IconCode, - IconCurrencyDollar, - IconDashboard, - IconFileText, - IconHeart, - IconHistory, - IconInfoCircle, - IconKey, - IconLayout, - IconListCheck, - IconMovie, - IconMusic, - IconPalette, - IconPassword, - IconPlug, - IconServer, - IconShirt, - IconUserCog, - IconWallet -} from '@tabler/icons-react' -import { lazy } from 'react' -import { Navigate } from 'react-router' - -import { RouteCategory } from './layout/interfaces/routes_interfaces' - -export const ROUTES: RouteCategory[] = [ - { - title: '', - items: [ - { - name: 'Dashboard', - icon: , - routes: { - dashboard: lazy(() => import('./pages/Dashboard')) - }, - togglable: false - } - ] - }, - { - title: 'Productivity', - items: [ - { - name: 'Idea Box', - provider: lazy(() => import('@apps/IdeaBox/providers/IdeaBoxProvider')), - icon: , - routes: { - '': lazy(() => import('@apps/IdeaBox/pages/Containers')), - ':id/*': lazy(() => import('@apps/IdeaBox/pages/Ideas')) - }, - togglable: true - }, - { - name: 'Todo List', - icon: , - routes: { - 'todo-list': lazy(() => import('@apps/TodoList')) - }, - togglable: true, - hasAI: true, - requiredAPIKeys: ['groq'] - }, - { - name: 'Calendar', - icon: , - routes: { - calendar: lazy(() => import('@apps/Calendar')) - }, - togglable: true - }, - { - name: 'Code Time', - icon: , - routes: { - 'code-time': lazy(() => import('@apps/CodeTime')) - }, - togglable: true - } - ] - }, - { - title: 'Study', - items: [] - }, - { - title: 'Lifestyle', - items: [ - { - name: 'Moment Vault', - icon: , - hasAI: true, - routes: { - 'moment-vault': lazy(() => import('@apps/MomentVault')) - }, - togglable: true, - requiredAPIKeys: ['openai'] - }, - { - name: 'Achievements', - icon: , - routes: { - achievements: lazy(() => import('@apps/Achievements')) - }, - togglable: true - }, - { - name: 'Virtual Wardrobe', - icon: , - subsection: [ - { - name: 'Virtual Wardrobe Clothes', - icon: , - path: 'clothes' - }, - { - name: 'Virtual Wardrobe Outfits', - icon: , - path: 'outfits' - } - ], - routes: { - 'virtual-wardrobe': () => , - 'virtual-wardrobe/clothes': lazy( - () => import('@apps/VirtualWardrobe/pages/Clothes') - ), - 'virtual-wardrobe/outfits': lazy( - () => import('@apps/VirtualWardrobe/pages/Outfits') - ) - }, - togglable: true - }, - { - name: 'Movies', - icon: , - routes: { - movies: lazy(() => import('@apps/Movies')) - }, - togglable: true, - requiredAPIKeys: ['tmdb'] - } - ] - }, - { - title: 'Finance', - items: [ - { - name: 'Wallet', - icon: , - hasAI: true, - subsection: [ - { name: 'Dashboard', icon: , path: '' }, - { - name: 'Transactions', - icon: , - path: 'transactions' - }, - { name: 'Assets', icon: , path: 'assets' }, - { name: 'Ledgers', icon: , path: 'ledgers' }, - { - name: 'Financial Statements', - icon: , - path: 'statements' - } - ], - routes: { - wallet: lazy(() => import('@apps/Wallet/pages/Dashboard')), - 'wallet/transactions': lazy( - () => import('@apps/Wallet/pages/Transactions') - ), - 'wallet/assets': lazy(() => import('@apps/Wallet/pages/Assets')), - 'wallet/ledgers': lazy(() => import('@apps/Wallet/pages/Ledgers')), - 'wallet/statements': lazy( - () => import('@apps/Wallet/pages/Statements') - ) - }, - togglable: true - }, - { - name: 'Wishlist', - icon: , - routes: { - wishlist: lazy(() => import('@apps/Wishlist/pages/WishlistList')), - 'wishlist/:id': lazy( - () => import('@apps/Wishlist/pages/WishlistEntries') - ) - }, - togglable: true, - hasAI: true - } - ] - }, - { - title: 'Storage', - items: [ - { - name: 'Books Library', - icon: , - provider: lazy( - () => import('@apps/BooksLibrary/providers/BooksLibraryProvider') - ), - routes: { - '': lazy(() => import('@apps/BooksLibrary')) - }, - togglable: true - }, - { - name: 'Music', - icon: , - routes: { - music: lazy(() => import('@apps/Music')) - }, - togglable: true - }, - { - name: 'Guitar Tabs', - icon: 'mingcute:guitar-line', - routes: { - 'guitar-tabs': lazy(() => import('@apps/GuitarTabs')) - }, - togglable: true - }, - { - name: 'Youtube Videos', - icon: 'tabler:brand-youtube', - routes: { - 'youtube-videos': lazy(() => import('@apps/YoutubeVideos')) - }, - togglable: true - } - ] - }, - { - title: 'Confidential', - items: [ - { - name: 'Passwords', - icon: , - provider: lazy( - () => import('@apps/Passwords/providers/PasswordsProvider') - ), - routes: { - '': lazy(() => import('@apps/Passwords')) - }, - togglable: true - }, - { - name: 'API Keys', - icon: , - routes: { - 'api-keys': lazy(() => import('./pages/APIKeys')) - }, - togglable: false - } - ] - }, - { - title: 'Information', - items: [ - { - name: 'Railway Map', - icon: 'uil:subway', - provider: lazy( - () => import('@apps/RailwayMap/providers/RailwayMapProvider') - ), - routes: { - '': lazy(() => import('@apps/RailwayMap')) - }, - togglable: true - } - ] - }, - { - title: 'Utilities', - items: [ - { - name: 'Sudoku', - icon: 'uil:table', - routes: { - sudoku: lazy(() => import('@apps/Sudoku')) - }, - togglable: true - }, - { - name: 'Currency Converter', - icon: , - routes: { - 'currency-converter': lazy(() => import('@apps/CurrencyConverter')) - }, - togglable: true - }, - { - name: 'Youtube Summarizer', - icon: 'tabler:brand-youtube', - routes: { - 'youtube-summarizer': lazy(() => import('@apps/YoutubeSummarizer')) - }, - togglable: true, - requiredAPIKeys: ['groq'], - hasAI: true - } - ] - }, - { - title: 'Settings', - items: [ - { - name: 'Personalization', - icon: , - routes: { - personalization: lazy(() => import('./pages/Personalization')) - }, - togglable: false - }, - { - name: 'Modules', - icon: , - routes: { - modules: lazy(() => import('@apps/Modules')) - }, - togglable: false - }, - { - name: 'Server Status', - icon: , - routes: { - 'server-status': lazy(() => import('./pages/ServerStatus')) - }, - togglable: false - } - ] - }, - { - title: 'sso', - items: [ - { - name: 'Localization Manager', - icon: 'mingcute:translate-line', - routes: { - 'localization-manager': lazy( - () => import('./pages/LocalizationManager') - ) - }, - togglable: false - } - ] - }, - { - title: '', - items: [ - { - name: 'Documentation', - icon: , - routes: { - documentation: () => { - window.location.href = - 'https://docs.lifeforge.melvinchia.dev/getting-started/introduction' - return - } - }, - togglable: false - }, - { - name: 'Account Settings', - icon: , - routes: { - account: lazy(() => import('./pages/Account')) - }, - togglable: false, - hidden: true - } - ] - } -] - -export default ROUTES diff --git a/src/core/pages/Account/components/AvatarColumn.tsx b/src/core/pages/AccountSettings/components/AvatarColumn.tsx similarity index 100% rename from src/core/pages/Account/components/AvatarColumn.tsx rename to src/core/pages/AccountSettings/components/AvatarColumn.tsx diff --git a/src/core/pages/Account/components/OrdinaryColumn.tsx b/src/core/pages/AccountSettings/components/OrdinaryColumn.tsx similarity index 100% rename from src/core/pages/Account/components/OrdinaryColumn.tsx rename to src/core/pages/AccountSettings/components/OrdinaryColumn.tsx diff --git a/src/core/pages/Account/components/PasswordColumn.tsx b/src/core/pages/AccountSettings/components/PasswordColumn.tsx similarity index 100% rename from src/core/pages/Account/components/PasswordColumn.tsx rename to src/core/pages/AccountSettings/components/PasswordColumn.tsx diff --git a/src/core/pages/Account/components/TwoFAColumn.tsx b/src/core/pages/AccountSettings/components/TwoFAColumn.tsx similarity index 100% rename from src/core/pages/Account/components/TwoFAColumn.tsx rename to src/core/pages/AccountSettings/components/TwoFAColumn.tsx diff --git a/src/core/pages/AccountSettings/config.tsx b/src/core/pages/AccountSettings/config.tsx new file mode 100644 index 000000000..26f3f52cb --- /dev/null +++ b/src/core/pages/AccountSettings/config.tsx @@ -0,0 +1,13 @@ +import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces' +import { IconUserCog } from '@tabler/icons-react' +import { lazy } from 'react' + +export default { + name: 'Account Settings', + icon: , + routes: { + account: lazy(() => import('.')) + }, + togglable: false, + hidden: true +} satisfies ModuleConfig diff --git a/src/core/pages/Account/index.tsx b/src/core/pages/AccountSettings/index.tsx similarity index 94% rename from src/core/pages/Account/index.tsx rename to src/core/pages/AccountSettings/index.tsx index 2501deeb9..46e2b1f8c 100644 --- a/src/core/pages/Account/index.tsx +++ b/src/core/pages/AccountSettings/index.tsx @@ -7,7 +7,7 @@ import PasswordColumn from './components/PasswordColumn' import TwoFAColumn from './components/TwoFAColumn' import { AccountSettingsModals } from './modals' -function Account() { +function AccountSettings() { useModalsEffect(AccountSettingsModals) return ( @@ -35,4 +35,4 @@ function Account() { ) } -export default Account +export default AccountSettings diff --git a/src/core/pages/Account/modals/DisableTwoFAModal.tsx b/src/core/pages/AccountSettings/modals/DisableTwoFAModal.tsx similarity index 100% rename from src/core/pages/Account/modals/DisableTwoFAModal.tsx rename to src/core/pages/AccountSettings/modals/DisableTwoFAModal.tsx diff --git a/src/core/pages/Account/modals/EnableTwoFAModal/components/OTPConfirmScreen.tsx b/src/core/pages/AccountSettings/modals/EnableTwoFAModal/components/OTPConfirmScreen.tsx similarity index 100% rename from src/core/pages/Account/modals/EnableTwoFAModal/components/OTPConfirmScreen.tsx rename to src/core/pages/AccountSettings/modals/EnableTwoFAModal/components/OTPConfirmScreen.tsx diff --git a/src/core/pages/Account/modals/EnableTwoFAModal/components/QRCodeDisplay.tsx b/src/core/pages/AccountSettings/modals/EnableTwoFAModal/components/QRCodeDisplay.tsx similarity index 100% rename from src/core/pages/Account/modals/EnableTwoFAModal/components/QRCodeDisplay.tsx rename to src/core/pages/AccountSettings/modals/EnableTwoFAModal/components/QRCodeDisplay.tsx diff --git a/src/core/pages/Account/modals/EnableTwoFAModal/components/TwoFAEnableProcedure.tsx b/src/core/pages/AccountSettings/modals/EnableTwoFAModal/components/TwoFAEnableProcedure.tsx similarity index 100% rename from src/core/pages/Account/modals/EnableTwoFAModal/components/TwoFAEnableProcedure.tsx rename to src/core/pages/AccountSettings/modals/EnableTwoFAModal/components/TwoFAEnableProcedure.tsx diff --git a/src/core/pages/Account/modals/EnableTwoFAModal/index.tsx b/src/core/pages/AccountSettings/modals/EnableTwoFAModal/index.tsx similarity index 100% rename from src/core/pages/Account/modals/EnableTwoFAModal/index.tsx rename to src/core/pages/AccountSettings/modals/EnableTwoFAModal/index.tsx diff --git a/src/core/pages/Account/modals/ModifyModal.tsx b/src/core/pages/AccountSettings/modals/ModifyModal.tsx similarity index 100% rename from src/core/pages/Account/modals/ModifyModal.tsx rename to src/core/pages/AccountSettings/modals/ModifyModal.tsx diff --git a/src/core/pages/Account/modals/index.ts b/src/core/pages/AccountSettings/modals/index.ts similarity index 100% rename from src/core/pages/Account/modals/index.ts rename to src/core/pages/AccountSettings/modals/index.ts diff --git a/src/core/pages/Dashboard/config.tsx b/src/core/pages/Dashboard/config.tsx new file mode 100644 index 000000000..9000172be --- /dev/null +++ b/src/core/pages/Dashboard/config.tsx @@ -0,0 +1,12 @@ +import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces' +import { IconDashboard } from '@tabler/icons-react' +import { lazy } from 'react' + +export default { + name: 'Dashboard', + icon: , + routes: { + dashboard: lazy(() => import('.')) + }, + togglable: false +} satisfies ModuleConfig diff --git a/src/core/pages/Documentation/config.tsx b/src/core/pages/Documentation/config.tsx new file mode 100644 index 000000000..b3372a848 --- /dev/null +++ b/src/core/pages/Documentation/config.tsx @@ -0,0 +1,16 @@ +import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces' +import { IconInfoCircle } from '@tabler/icons-react' +import { Navigate } from 'react-router' + +export default { + name: 'Documentation', + icon: , + routes: { + documentation: () => { + window.location.href = + 'https://docs.lifeforge.melvinchia.dev/getting-started/introduction' + return + } + }, + togglable: false +} as ModuleConfig diff --git a/src/core/pages/LocalizationManager/config.tsx b/src/core/pages/LocalizationManager/config.tsx new file mode 100644 index 000000000..db786cf55 --- /dev/null +++ b/src/core/pages/LocalizationManager/config.tsx @@ -0,0 +1,12 @@ +import { lazy } from 'react' + +import { ModuleConfig } from '../../routes/interfaces/routes_interfaces' + +export default { + name: 'Localization Manager', + icon: 'mingcute:translate-line', + routes: { + 'localization-manager': lazy(() => import('.')) + }, + togglable: false +} satisfies ModuleConfig diff --git a/src/apps/Modules/ModuleItem.tsx b/src/core/pages/Modules/components/ModuleItem.tsx similarity index 95% rename from src/apps/Modules/ModuleItem.tsx rename to src/core/pages/Modules/components/ModuleItem.tsx index 0b782b6e9..f1040a919 100644 --- a/src/apps/Modules/ModuleItem.tsx +++ b/src/core/pages/Modules/components/ModuleItem.tsx @@ -1,3 +1,4 @@ +import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces' import { Icon } from '@iconify/react' import clsx from 'clsx' import _ from 'lodash' @@ -8,14 +9,12 @@ import { Switch } from '@lifeforge/ui' import useComponentBg from '@hooks/useComponentBg' -import { RouteItem } from '../../core/layout/interfaces/routes_interfaces' - function ModuleItem({ module, enabled, toggleModule }: { - module: RouteItem + module: ModuleConfig enabled: boolean toggleModule: (moduleName: string) => void }) { diff --git a/src/core/pages/Modules/config.tsx b/src/core/pages/Modules/config.tsx new file mode 100644 index 000000000..73fa9e2e6 --- /dev/null +++ b/src/core/pages/Modules/config.tsx @@ -0,0 +1,11 @@ +import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces' +import { lazy } from 'react' + +export default { + name: 'Modules', + icon: 'tabler:plug', + routes: { + modules: lazy(() => import('.')) + }, + togglable: false +} satisfies ModuleConfig diff --git a/src/apps/Modules/index.tsx b/src/core/pages/Modules/index.tsx similarity index 94% rename from src/apps/Modules/index.tsx rename to src/core/pages/Modules/index.tsx index 7cc4a36f2..689f9d71d 100644 --- a/src/apps/Modules/index.tsx +++ b/src/core/pages/Modules/index.tsx @@ -1,3 +1,4 @@ +import ROUTES from '@core/routes/Routes' import _ from 'lodash' import { useTranslation } from 'react-i18next' import { toast } from 'react-toastify' @@ -6,9 +7,8 @@ import { LoadingScreen, ModuleHeader, ModuleWrapper } from '@lifeforge/ui' import fetchAPI from '@utils/fetchAPI' -import ROUTES from '../../core/Routes' -import { useAuth } from '../../core/pages/Auth/providers/AuthProvider' -import ModuleItem from './ModuleItem' +import { useAuth } from '../Auth/providers/AuthProvider' +import ModuleItem from './components/ModuleItem' function Modules() { const { t } = useTranslation('common.sidebar') diff --git a/src/apps/Modules/interfaces/module_interfaces.ts b/src/core/pages/Modules/interfaces/module_interfaces.ts similarity index 100% rename from src/apps/Modules/interfaces/module_interfaces.ts rename to src/core/pages/Modules/interfaces/module_interfaces.ts diff --git a/src/core/pages/Personalization/config.tsx b/src/core/pages/Personalization/config.tsx new file mode 100644 index 000000000..fa0f29e01 --- /dev/null +++ b/src/core/pages/Personalization/config.tsx @@ -0,0 +1,12 @@ +import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces' +import { IconPalette } from '@tabler/icons-react' +import { lazy } from 'react' + +export default { + name: 'Personalization', + icon: , + routes: { + personalization: lazy(() => import('.')) + }, + togglable: false +} satisfies ModuleConfig diff --git a/src/core/pages/ServerStatus/config.tsx b/src/core/pages/ServerStatus/config.tsx new file mode 100644 index 000000000..d2ca9733e --- /dev/null +++ b/src/core/pages/ServerStatus/config.tsx @@ -0,0 +1,12 @@ +import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces' +import { IconServer } from '@tabler/icons-react' +import { lazy } from 'react' + +export default { + name: 'Server Status', + icon: , + routes: { + 'server-status': lazy(() => import('.')) + }, + togglable: false +} satisfies ModuleConfig diff --git a/src/core/routes/Routes.tsx b/src/core/routes/Routes.tsx new file mode 100644 index 000000000..593dcde8d --- /dev/null +++ b/src/core/routes/Routes.tsx @@ -0,0 +1,43 @@ +import { ModuleCategory } from './interfaces/routes_interfaces' +import RouteItems from './routes.json' + +export const ROUTES: ModuleCategory[] = [] + +const modules = import.meta.glob([ + '../../apps/**/config.tsx', + '../pages/**/config.tsx' +]) + +function resolveAlias(path: string): string { + if (path.startsWith('@apps')) { + return path.replace('@apps', '../../apps') + } + if (path.startsWith('@core')) { + return path.replace('@core', '../pages') + } + + return path +} + +for (const route of RouteItems) { + const { title, items } = route + + const importPromises = items.map(async item => { + const resolved = `${resolveAlias(item)}/config.tsx` + const importer = modules[resolved] + + if (!importer) throw new Error(`Module not found: ${resolved}`) + + const mod = (await importer()) as { default: any } + return mod.default + }) + + const awaitedRoutes = await Promise.all(importPromises) + + ROUTES.push({ + title, + items: awaitedRoutes + }) +} + +export default ROUTES diff --git a/src/core/layout/components/ChildRoutesRenderer.tsx b/src/core/routes/components/ChildRoutesRenderer.tsx similarity index 89% rename from src/core/layout/components/ChildRoutesRenderer.tsx rename to src/core/routes/components/ChildRoutesRenderer.tsx index 5da6fba1b..001aef424 100644 --- a/src/core/layout/components/ChildRoutesRenderer.tsx +++ b/src/core/routes/components/ChildRoutesRenderer.tsx @@ -3,7 +3,7 @@ import { Route } from 'react-router' import { LoadingScreen, ModalManager } from '@lifeforge/ui' -import { RouteItem } from '../interfaces/routes_interfaces' +import { ModuleConfig } from '../../routes/interfaces/routes_interfaces' import APIKeyStatusProvider from '../providers/APIKeyStatusProvider' function ChildRoutesRenderer({ @@ -12,7 +12,7 @@ function ChildRoutesRenderer({ APIKeys = [], t }: { - routes: RouteItem['routes'] + routes: ModuleConfig['routes'] t: any isNested?: boolean APIKeys?: string[] diff --git a/src/core/layout/components/Layout.tsx b/src/core/routes/components/Layout.tsx similarity index 100% rename from src/core/layout/components/Layout.tsx rename to src/core/routes/components/Layout.tsx diff --git a/src/core/layout/components/MainRoutesRenderer.tsx b/src/core/routes/components/MainRoutesRenderer.tsx similarity index 92% rename from src/core/layout/components/MainRoutesRenderer.tsx rename to src/core/routes/components/MainRoutesRenderer.tsx index 283ff636d..5f43d4bda 100644 --- a/src/core/layout/components/MainRoutesRenderer.tsx +++ b/src/core/routes/components/MainRoutesRenderer.tsx @@ -1,14 +1,14 @@ +import MainApplication from '@core/routes/components/Layout' import _ from 'lodash' import { useTranslation } from 'react-i18next' import { Route, Routes } from 'react-router' import { NotFoundScreen } from '@lifeforge/ui' -import ROUTES from '../../Routes' import Auth from '../../pages/Auth' import { useAuth } from '../../pages/Auth/providers/AuthProvider' +import ROUTES from '../Routes' import ChildRoutesRenderer from './ChildRoutesRenderer' -import MainApplication from './Layout' function MainRoutesRenderer() { const { t } = useTranslation('common.misc') @@ -29,6 +29,8 @@ function MainRoutesRenderer() { ? (() => { const Provider: React.FC = item.provider + console.log('Provider', Provider) + return ( { diff --git a/src/core/layout/index.tsx b/src/core/routes/index.tsx similarity index 94% rename from src/core/layout/index.tsx rename to src/core/routes/index.tsx index d3695b63a..effc3b18c 100644 --- a/src/core/layout/index.tsx +++ b/src/core/routes/index.tsx @@ -1,3 +1,4 @@ +import MainRoutesRenderer from '@core/routes/components/MainRoutesRenderer' import { useEffect } from 'react' import { useLocation, useNavigate } from 'react-router' @@ -12,7 +13,6 @@ import { useModalsEffect } from '@lifeforge/ui' import Auth from '../pages/Auth' import { useAuth } from '../pages/Auth/providers/AuthProvider' -import MainRoutesRenderer from './components/MainRoutesRenderer' import useAuthEffect from './hooks/useAuthEffect' import useTitleEffect from './hooks/useTitleEffect' diff --git a/src/core/layout/interfaces/routes_interfaces.ts b/src/core/routes/interfaces/routes_interfaces.ts similarity index 84% rename from src/core/layout/interfaces/routes_interfaces.ts rename to src/core/routes/interfaces/routes_interfaces.ts index 5a77c5cf6..74febeccf 100644 --- a/src/core/layout/interfaces/routes_interfaces.ts +++ b/src/core/routes/interfaces/routes_interfaces.ts @@ -1,4 +1,4 @@ -export interface RouteItem { +export interface ModuleConfig { name: string icon: React.ReactElement | string provider?: @@ -20,7 +20,7 @@ export interface RouteItem { hidden?: boolean } -export interface RouteCategory { +export interface ModuleCategory { title: string - items: RouteItem[] + items: ModuleConfig[] } diff --git a/src/core/layout/providers/APIKeyStatusProvider.tsx b/src/core/routes/providers/APIKeyStatusProvider.tsx similarity index 92% rename from src/core/layout/providers/APIKeyStatusProvider.tsx rename to src/core/routes/providers/APIKeyStatusProvider.tsx index 3def7e86b..15a3d2174 100644 --- a/src/core/layout/providers/APIKeyStatusProvider.tsx +++ b/src/core/routes/providers/APIKeyStatusProvider.tsx @@ -1,9 +1,9 @@ +import MissingAPIKeyScreen from '@core/routes/components/MissingAPIKeyScreen' + import { ModuleWrapper, QueryWrapper } from '@lifeforge/ui' import useAPIQuery from '@hooks/useAPIQuery' -import MissingAPIKeyScreen from '../components/MissingAPIKeyScreen' - function APIKeyStatusProvider({ APIKeys, children diff --git a/src/core/routes/routes.json b/src/core/routes/routes.json new file mode 100644 index 000000000..e4af0d938 --- /dev/null +++ b/src/core/routes/routes.json @@ -0,0 +1,83 @@ +[ + { + "title": "", + "items": [ + "@core/Dashboard" + ] + }, + { + "title": "Productivity", + "items": [ + "@apps/IdeaBox", + "@apps/TodoList", + "@apps/Calendar", + "@apps/CodeTime" + ] + }, + { + "title": "Lifestyle", + "items": [ + "@apps/MomentVault", + "@apps/VirtualWardrobe", + "@apps/Movies", + "@apps/Achievements" + ] + }, + { + "title": "Finance", + "items": [ + "@apps/Wallet", + "@apps/Wishlist" + ] + }, + { + "title": "Storage", + "items": [ + "@apps/BooksLibrary", + "@apps/Music", + "@apps/GuitarTabs", + "@apps/YoutubeVideos" + ] + }, + { + "title": "Confidential", + "items": [ + "@apps/Passwords" + ] + }, + { + "title": "Information", + "items": [ + "@apps/RailwayMap" + ] + }, + { + "title": "Utilities", + "items": [ + "@apps/Sudoku", + "@apps/CurrencyConverter", + "@apps/YoutubeSummarizer" + ] + }, + { + "title": "Settings", + "items": [ + "@core/Personalization", + "@core/Modules", + "@core/ServerStatus" + ] + }, + { + "title": "sso", + "items": [ + "@core/LocalizationManager" + ] + }, + { + "title": "", + "items": [ + "@core/Documentation", + "@core/AccountSettings" + ] + } +] \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 15e79e5d9..f52264a23 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,10 +2,16 @@ "compilerOptions": { "target": "ES2020", "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": [ + "ES2020", + "DOM", + "DOM.Iterable" + ], "module": "ESNext", "skipLibCheck": true, - "types": ["node"], + "types": [ + "node" + ], /* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, @@ -19,19 +25,38 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "paths": { - "@components/*": ["./src/components/*"], - "@providers/*": ["./src/core/providers/*"], - "@hooks/*": ["./src/core/hooks/*"], - "@interfaces/*": ["./src/core/interfaces/*"], - "@utils/*": ["./src/core/utils/*"], - "@apps/*": ["./src/apps/*"], - "@security/*": ["./src/core/security/*"] + "@components/*": [ + "./src/components/*" + ], + "@providers/*": [ + "./src/core/providers/*" + ], + "@hooks/*": [ + "./src/core/hooks/*" + ], + "@interfaces/*": [ + "./src/core/interfaces/*" + ], + "@utils/*": [ + "./src/core/utils/*" + ], + "@apps/*": [ + "./src/apps/*" + ], + "@security/*": [ + "./src/core/security/*" + ], + "@core/*": [ + "./src/core/*" + ], } }, - "include": ["./src/**/*"], + "include": [ + "./src/**/*" + ], "references": [ { "path": "./tsconfig.node.json" } ] -} +} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index f3e6db7c0..3e7beeb3b 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,6 +10,17 @@ const ReactCompilerConfig = { } } +export const alias = { + '@components': path.resolve(__dirname, './src/components'), + '@providers': path.resolve(__dirname, './src/core/providers'), + '@hooks': path.resolve(__dirname, './src/core/hooks'), + '@interfaces': path.resolve(__dirname, './src/core/interfaces'), + '@utils': path.resolve(__dirname, './src/core/utils'), + '@apps': path.resolve(__dirname, './src/apps'), + '@security': path.resolve(__dirname, './src/core/security'), + '@core': path.resolve(__dirname, './src/core') +} + export default defineConfig({ envDir: path.resolve(__dirname, './env'), plugins: [ @@ -30,15 +41,7 @@ export default defineConfig({ } }, resolve: { - alias: { - '@components': path.resolve(__dirname, './src/components'), - '@providers': path.resolve(__dirname, './src/core/providers'), - '@hooks': path.resolve(__dirname, './src/core/hooks'), - '@interfaces': path.resolve(__dirname, './src/core/interfaces'), - '@utils': path.resolve(__dirname, './src/core/utils'), - '@apps': path.resolve(__dirname, './src/apps'), - '@security': path.resolve(__dirname, './src/core/security') - } + alias }, build: { target: 'esnext',