shortcut-next 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +223 -13
  2. package/package.json +1 -1
  3. package/templates/base/.eslintrc.json +75 -2
  4. package/templates/base/.prettierignore +8 -0
  5. package/templates/base/app/(dashboard)/layout.tsx +15 -89
  6. package/templates/base/app/home/page.tsx +2 -2
  7. package/templates/base/app/icon.svg +4 -0
  8. package/templates/base/app/layout.tsx +16 -6
  9. package/templates/base/app/login/page.tsx +31 -31
  10. package/templates/base/app/page.tsx +2 -2
  11. package/templates/base/{@core/components → components/ability}/Can.tsx +1 -1
  12. package/templates/base/components/auth/LoginForm.tsx +2 -2
  13. package/templates/base/components/auth/SignupForm.tsx +1 -1
  14. package/templates/base/{@core/components → components/common}/LanguageDropdown.tsx +2 -2
  15. package/templates/base/components/icon/Icon.tsx +8 -0
  16. package/templates/base/components/ui/GradientText.tsx +0 -1
  17. package/templates/base/core/configs/themeConfig.ts +40 -0
  18. package/templates/base/{@core → core}/context/AuthContext.tsx +2 -2
  19. package/templates/base/{@core → core}/context/SettingsContext.tsx +1 -0
  20. package/templates/base/{@core → core}/hooks/useAbility.ts +2 -6
  21. package/templates/base/{@core → core}/hooks/useLanguage.ts +1 -3
  22. package/templates/base/core/icons/customIcons.ts +12 -0
  23. package/templates/base/core/layouts/SidebarLayout/ActiveRouteContext.tsx +25 -0
  24. package/templates/base/core/layouts/SidebarLayout/FavoritesContext.tsx +63 -0
  25. package/templates/base/core/layouts/SidebarLayout/Sidebar.tsx +142 -0
  26. package/templates/base/core/layouts/SidebarLayout/SidebarContext.tsx +66 -0
  27. package/templates/base/core/layouts/SidebarLayout/components/CommandPalette.tsx +143 -0
  28. package/templates/base/core/layouts/SidebarLayout/components/FavoritesSection.tsx +113 -0
  29. package/templates/base/core/layouts/SidebarLayout/components/NavItemContextMenu.tsx +64 -0
  30. package/templates/base/core/layouts/SidebarLayout/components/NavItems.tsx +66 -0
  31. package/templates/base/core/layouts/SidebarLayout/components/SidebarAnimatedLabel.tsx +40 -0
  32. package/templates/base/core/layouts/SidebarLayout/components/SidebarFooter.tsx +76 -0
  33. package/templates/base/core/layouts/SidebarLayout/components/SidebarLogo.tsx +91 -0
  34. package/templates/base/core/layouts/SidebarLayout/components/SidebarNavGroup.tsx +115 -0
  35. package/templates/base/core/layouts/SidebarLayout/components/SidebarNavLink.tsx +116 -0
  36. package/templates/base/core/layouts/SidebarLayout/components/SidebarNavMore.tsx +74 -0
  37. package/templates/base/core/layouts/SidebarLayout/components/SidebarSection.tsx +115 -0
  38. package/templates/base/core/layouts/SidebarLayout/index.tsx +115 -0
  39. package/templates/base/core/layouts/SidebarLayout/ui/SidebarStyledComponents.tsx +82 -0
  40. package/templates/base/core/layouts/SidebarLayout/utils/SidebarUtils.ts +67 -0
  41. package/templates/base/core/layouts/types.ts +58 -0
  42. package/templates/base/{@core → core}/theme/ThemeComponent.tsx +1 -1
  43. package/templates/base/{@core → core}/theme/overrides/accordion.ts +2 -3
  44. package/templates/base/{@core → core}/theme/overrides/alerts.ts +14 -9
  45. package/templates/base/{@core → core}/theme/overrides/autocomplete.ts +0 -1
  46. package/templates/base/{@core → core}/theme/overrides/avatars.ts +7 -4
  47. package/templates/base/{@core → core}/theme/overrides/backdrop.ts +3 -6
  48. package/templates/base/{@core → core}/theme/overrides/breadcrumbs.ts +1 -2
  49. package/templates/base/{@core → core}/theme/overrides/button.ts +44 -59
  50. package/templates/base/core/theme/overrides/buttonGroup.ts +11 -0
  51. package/templates/base/{@core → core}/theme/overrides/card.ts +5 -4
  52. package/templates/base/{@core → core}/theme/overrides/chip.ts +11 -12
  53. package/templates/base/{@core → core}/theme/overrides/dataGrid.ts +18 -2
  54. package/templates/base/{@core → core}/theme/overrides/dialog.ts +25 -20
  55. package/templates/base/{@core → core}/theme/overrides/divider.ts +1 -2
  56. package/templates/base/{@core → core}/theme/overrides/fab.ts +1 -2
  57. package/templates/base/core/theme/overrides/iconButton.ts +36 -0
  58. package/templates/base/{@core → core}/theme/overrides/index.ts +8 -6
  59. package/templates/base/{@core → core}/theme/overrides/input.ts +3 -3
  60. package/templates/base/core/theme/overrides/link.ts +44 -0
  61. package/templates/base/{@core → core}/theme/overrides/list.ts +1 -2
  62. package/templates/base/core/theme/overrides/menu.ts +43 -0
  63. package/templates/base/core/theme/overrides/pagination.ts +36 -0
  64. package/templates/base/core/theme/overrides/paper.ts +12 -0
  65. package/templates/base/{@core → core}/theme/overrides/popover.ts +3 -3
  66. package/templates/base/{@core → core}/theme/overrides/progress.ts +2 -5
  67. package/templates/base/{@core → core}/theme/overrides/rating.ts +1 -2
  68. package/templates/base/{@core → core}/theme/overrides/select.ts +6 -3
  69. package/templates/base/{@core → core}/theme/overrides/snackbar.ts +3 -3
  70. package/templates/base/core/theme/overrides/switches.ts +62 -0
  71. package/templates/base/{@core → core}/theme/overrides/table.ts +3 -21
  72. package/templates/base/core/theme/overrides/tabs.ts +67 -0
  73. package/templates/base/core/theme/overrides/textFields.ts +96 -0
  74. package/templates/base/{@core → core}/theme/overrides/timeline.ts +2 -5
  75. package/templates/base/{@core → core}/theme/overrides/toggleButton.ts +4 -2
  76. package/templates/base/{@core → core}/theme/overrides/tooltip.ts +8 -7
  77. package/templates/base/{@core → core}/theme/overrides/typography.ts +1 -2
  78. package/templates/base/{@core → core}/theme/typography/index.ts +3 -2
  79. package/templates/base/docs/SidebarDocumentation.md +426 -0
  80. package/templates/base/navigation/dynamicRoutes.ts +32 -0
  81. package/templates/base/navigation/sidebarRoutes.ts +61 -0
  82. package/templates/base/next.config.ts +1 -1
  83. package/templates/base/package-lock.json +1314 -487
  84. package/templates/base/package.json +15 -11
  85. package/templates/base/providers/AppProviders.tsx +10 -8
  86. package/templates/base/providers/I18nProvider.tsx +1 -1
  87. package/templates/base/{middleware.ts → proxy.ts} +2 -2
  88. package/templates/base/public/fonts/Montserrat-Arabic-Black.ttf +0 -0
  89. package/templates/base/public/fonts/Montserrat-Arabic-Bold.ttf +0 -0
  90. package/templates/base/public/fonts/Montserrat-Arabic-ExtraBold.ttf +0 -0
  91. package/templates/base/public/fonts/Montserrat-Arabic-ExtraLight.ttf +0 -0
  92. package/templates/base/public/fonts/Montserrat-Arabic-Light.ttf +0 -0
  93. package/templates/base/public/fonts/Montserrat-Arabic-Medium.ttf +0 -0
  94. package/templates/base/public/fonts/Montserrat-Arabic-Regular.ttf +0 -0
  95. package/templates/base/public/fonts/Montserrat-Arabic-SemiBold.ttf +0 -0
  96. package/templates/base/public/fonts/Montserrat-Arabic-Thin.ttf +0 -0
  97. package/templates/base/public/images/shortcut-next.png +0 -0
  98. package/templates/base/tsconfig.json +21 -5
  99. package/templates/base/@core/configs/themeConfig.ts +0 -51
  100. package/templates/base/@core/layouts/types.ts +0 -41
  101. package/templates/base/@core/theme/overrides/buttonGroup.ts +0 -9
  102. package/templates/base/@core/theme/overrides/link.ts +0 -9
  103. package/templates/base/@core/theme/overrides/menu.ts +0 -25
  104. package/templates/base/@core/theme/overrides/pagination.ts +0 -59
  105. package/templates/base/@core/theme/overrides/paper.ts +0 -9
  106. package/templates/base/@core/theme/overrides/switches.ts +0 -29
  107. package/templates/base/@core/theme/overrides/tabs.ts +0 -33
  108. package/templates/base/components/loaders/spinner.css +0 -136
  109. /package/templates/base/{@core/components → components/common}/Direction.tsx +0 -0
  110. /package/templates/base/{@core/components → components/common}/Translations.tsx +0 -0
  111. /package/templates/base/components/{HydrationGate.tsx → wrappers/HydrationGate.tsx} +0 -0
  112. /package/templates/base/{@core → core}/clients/apiClient.ts +0 -0
  113. /package/templates/base/{@core → core}/configs/authConfig.ts +0 -0
  114. /package/templates/base/{@core → core}/configs/clientConfig.ts +0 -0
  115. /package/templates/base/{@core → core}/configs/i18n.ts +0 -0
  116. /package/templates/base/{@core → core}/hooks/useSettings.ts +0 -0
  117. /package/templates/base/{@core → core}/hooks/useToggleMode.ts +0 -0
  118. /package/templates/base/{@core → core}/theme/ThemeOptions.ts +0 -0
  119. /package/templates/base/{@core → core}/theme/breakpoints/index.ts +0 -0
  120. /package/templates/base/{@core → core}/theme/globalStyles.tsx +0 -0
  121. /package/templates/base/{@core → core}/theme/palette/index.ts +0 -0
  122. /package/templates/base/{@core → core}/theme/shadows/index.ts +0 -0
  123. /package/templates/base/{@core → core}/theme/spacing/index.ts +0 -0
  124. /package/templates/base/{@core → core}/theme/types.ts +0 -0
  125. /package/templates/base/{@core → core}/utils/hex-to-rgba.ts +0 -0
  126. /package/templates/base/{components → providers}/MSWProvider.tsx +0 -0
package/README.md CHANGED
@@ -1,26 +1,236 @@
1
- # Shortcut Next
1
+ # Shortcut Next
2
2
 
3
- > Scaffold modern **Next.js 15+ projects** in seconds — with **MUI**, **React Hook Form**, and **TanStack Query** built-in.
4
- > Optionally add **Tailwind CSS v4** with a single command.
3
+ Stop starting from scratch. Scaffold a production-ready **Next.js 15+** project with **MUI**, **React Hook Form**, **TanStack Query**, role-based authorization, i18n, and dark mode — all wired up and ready to go.
5
4
 
6
5
  ---
7
6
 
8
- ## 🚀 Features
7
+ ## What You Get
9
8
 
10
- - **Next.js 15 (App Router)** modern project structure, ready to go.
11
- - **MUI (Material UI)** — theming, components, dark mode ready.
12
- - **React Hook Form** forms made simple, integrated with MUI inputs.
13
- - **TanStack Query (React Query)** powerful data fetching and caching.
14
- - **Tailwind CSS v4** (optional) utility-first styling, zero config.
15
- - **TypeScript by default** — strict mode enabled.
16
- - **One CLI** — choose your preset: **Base** (MUI stack) or **Tailwind v4**.
9
+ - **Next.js 15** with App Router and TypeScript (strict mode)
10
+ - **MUI v7** — fully themed with 30+ customized components, dark mode, and RTL support
11
+ - **React Hook Form** + Yup validation
12
+ - **TanStack Query** for data fetching and caching
13
+ - **CASL authorization** — role-based access control out of the box
14
+ - **i18n** — English and Arabic with auto-detection
15
+ - **Tailwind CSS v4** (optional preset)
16
+ - **MSW** — mock API responses during development
17
17
 
18
18
  ---
19
19
 
20
- ## 📦 Installation
20
+ ## Installation
21
21
 
22
- You don’t need to install globally. Use `npx`:
22
+ Run this single command and follow the prompts:
23
23
 
24
24
  ```bash
25
25
  npx shortcut-next@latest
26
+ ```
26
27
 
28
+ You'll be asked three things:
29
+
30
+ 1. **Project name** — the folder that will be created
31
+ 2. **Preset** — `base` (MUI stack) or `tailwind` (MUI + Tailwind v4)
32
+ 3. **Package manager** — pnpm, npm, yarn, or bun
33
+
34
+ That's it. The CLI creates your project, initializes git, and installs dependencies.
35
+
36
+ ### Skip the Prompts (Optional)
37
+
38
+ ```bash
39
+ npx shortcut-next@latest my-app --preset tailwind --pm pnpm
40
+ ```
41
+
42
+ | Flag | Options |
43
+ | --------------- | ------------------------------ |
44
+ | `--preset` | `base` or `tailwind` |
45
+ | `--pm` | `npm`, `pnpm`, `yarn`, `bun` |
46
+ | `--no-git` | Skip git initialization |
47
+ | `--no-install` | Skip dependency installation |
48
+
49
+ ### Start Developing
50
+
51
+ ```bash
52
+ cd my-app
53
+ npm run dev
54
+ ```
55
+
56
+ Other available scripts:
57
+
58
+ ```bash
59
+ npm run build # Production build
60
+ npm run lint # ESLint
61
+ npm run typecheck # TypeScript validation
62
+ npm run format # Prettier
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Project Structure
68
+
69
+ ```text
70
+ app/
71
+ ├── layout.tsx # Root layout (fonts, providers)
72
+ ├── page.tsx # Landing page (public)
73
+ ├── login/page.tsx # Login / Signup page
74
+ ├── home/page.tsx # Authenticated home page
75
+ ├── unauthorized/page.tsx # Access denied page
76
+ └── (dashboard)/
77
+ └── dashboard/page.tsx # Dashboard with role-aware cards
78
+
79
+ core/
80
+ ├── clients/apiClient.ts # Axios instance (token refresh, auto-logout)
81
+ ├── context/AuthContext.tsx # Auth state (login, signup, logout)
82
+ ├── context/SettingsContext.tsx # Theme mode, direction, language
83
+ ├── theme/ # MUI theme system (see below)
84
+ ├── configs/ # Auth endpoints, i18n, theme defaults
85
+ └── hooks/ # useAbility, useCan, useLanguage
86
+
87
+ lib/abilities/ # CASL authorization (see below)
88
+ providers/AppProviders.tsx # Composes all context providers
89
+ proxy.ts # Middleware (auth + route protection)
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Authorization
95
+
96
+ The template includes a ready-to-use role-based access system powered by [CASL](https://casl.js.org/).
97
+
98
+ ### Roles
99
+
100
+ | Role | What they can do |
101
+ | --------- | -------------------------------------------------------- |
102
+ | `admin` | Full access to everything |
103
+ | `manager` | Read all, manage Users/Tickets/Reports, no Settings |
104
+ | `agent` | Read Dashboard/Tickets/Reports, manage Tickets |
105
+ | `viewer` | Read Dashboard and Reports only |
106
+
107
+ Your backend JWT must include a `role` claim. The token is read from an `accessToken` cookie.
108
+
109
+ ### Protect a New Route
110
+
111
+ Add one entry to `lib/abilities/routeMap.ts`:
112
+
113
+ ```ts
114
+ export const routePermissions: RoutePermission[] = [
115
+ // ... existing routes
116
+
117
+ // Exact route
118
+ { pattern: '/dashboard/reports', action: 'read', subject: 'Reports' },
119
+
120
+ // Dynamic param
121
+ { pattern: '/dashboard/users/[id]', action: 'manage', subject: 'Users' },
122
+
123
+ // Wildcard (all sub-routes)
124
+ { pattern: '/settings/*', action: 'manage', subject: 'Settings' },
125
+ ]
126
+ ```
127
+
128
+ That's it — the middleware handles enforcement automatically.
129
+
130
+ ### Check Permissions in Components
131
+
132
+ ```tsx
133
+ import { useAbility, useCan } from '@/core/hooks/useAbility'
134
+
135
+ // Option 1: Full ability object
136
+ const ability = useAbility()
137
+ if (ability.can('read', 'Users')) {
138
+ // show users link
139
+ }
140
+
141
+ // Option 2: Simple boolean
142
+ const canManageSettings = useCan('manage', 'Settings')
143
+ ```
144
+
145
+ ### Add a New Role
146
+
147
+ Edit `lib/abilities/roles.ts`:
148
+
149
+ ```ts
150
+ export const roleAbilities: Record<UserRole, (can: Can, cannot: Cannot) => void> = {
151
+ // ... existing roles
152
+
153
+ support: (can) => {
154
+ can('read', ['Dashboard', 'Tickets'])
155
+ can('manage', 'Tickets')
156
+ },
157
+ }
158
+ ```
159
+
160
+ Then add `'support'` to the `UserRole` type in `lib/abilities/types.ts`.
161
+
162
+ ---
163
+
164
+ ## MUI Theme Customization
165
+
166
+ The theme lives in `core/theme/` and is fully modular.
167
+
168
+ ### Change the Default Theme
169
+
170
+ Edit `core/configs/themeConfig.ts`:
171
+
172
+ ```ts
173
+ const themeConfig = {
174
+ mode: 'dark', // 'light' or 'dark'
175
+ direction: 'ltr', // 'ltr' or 'rtl'
176
+ responsiveFontSizes: true,
177
+ disableRipple: true,
178
+ borderRadius: 10,
179
+ }
180
+ ```
181
+
182
+ ### Customize a Component
183
+
184
+ Each MUI component has its own override file in `core/theme/overrides/`. For example, to change button styles, edit `core/theme/overrides/button.ts`:
185
+
186
+ ```ts
187
+ const Button = (settings: Settings) => ({
188
+ MuiButton: {
189
+ styleOverrides: {
190
+ root: ({ theme }) => ({
191
+ borderRadius: 8,
192
+ textTransform: 'none',
193
+ fontWeight: 600,
194
+ }),
195
+ contained: ({ theme }) => ({
196
+ boxShadow: theme.shadows[3],
197
+ }),
198
+ },
199
+ },
200
+ })
201
+ ```
202
+
203
+ ### Components with Overrides
204
+
205
+ Accordion, Alerts, Autocomplete, Avatars, Backdrop, Breadcrumbs, Button, ButtonGroup, Card, Chip, DataGrid, Dialog, Divider, FAB, IconButton, Input, Link, List, Menu, Pagination, Paper, Popover, Progress, Rating, Select, Snackbar, Switches, Table, Tabs, TextField, Timeline, ToggleButton, Tooltip, Typography.
206
+
207
+ ### Change the Color Palette
208
+
209
+ Edit `core/theme/palette/index.ts`:
210
+
211
+ ```ts
212
+ primary: {
213
+ light: '#8B9BFF',
214
+ main: '#5B74FF', // your brand color
215
+ dark: '#3B54DF',
216
+ },
217
+ secondary: {
218
+ main: '#00D0FF',
219
+ },
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Environment Variables
225
+
226
+ Create a `.env` file in your project root:
227
+
228
+ ```env
229
+ NEXT_PUBLIC_URL=https://your-backend-url.com
230
+ ```
231
+
232
+ ---
233
+
234
+ ## License
235
+
236
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shortcut-next",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Scaffold Next.js apps with MUI base or Tailwind v4 preset.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -1,3 +1,76 @@
1
1
  {
2
- "extends": ["next", "prettier"]
3
- }
2
+ "extends": [
3
+ "next/core-web-vitals",
4
+ "plugin:@typescript-eslint/recommended",
5
+ "prettier"
6
+ ],
7
+ "rules": {
8
+ "react/display-name": "off",
9
+ "@next/next/no-img-element": "off",
10
+ "react/no-unescaped-entities": "off",
11
+ "import/no-anonymous-default-export": "off",
12
+ "@typescript-eslint/no-unused-vars": "error",
13
+ "@typescript-eslint/ban-ts-comment": "off",
14
+ "@typescript-eslint/no-explicit-any": "off",
15
+ "@typescript-eslint/no-non-null-assertion": "off",
16
+ // add new line above comment
17
+ "lines-around-comment": [
18
+ "error",
19
+ {
20
+ "beforeLineComment": true,
21
+ "beforeBlockComment": true,
22
+ "allowBlockStart": true,
23
+ "allowClassStart": true,
24
+ "allowObjectStart": true,
25
+ "allowArrayStart": true
26
+ }
27
+ ],
28
+ // add new line above return
29
+ "newline-before-return": "error",
30
+ // add new line below import
31
+ "import/newline-after-import": [
32
+ "error",
33
+ {
34
+ "count": 1
35
+ }
36
+ ],
37
+ "@typescript-eslint/ban-types": [
38
+ "error",
39
+ {
40
+ "extendDefaults": true,
41
+ "types": {
42
+ "{}": false
43
+ }
44
+ }
45
+ ]
46
+ },
47
+ "plugins": [
48
+ "import"
49
+ ],
50
+ "settings": {
51
+ "import/parsers": {
52
+ "@typescript-eslint/parser": [
53
+ ".ts",
54
+ ".tsx"
55
+ ]
56
+ },
57
+ "import/resolver": {
58
+ "typescript": {
59
+ "alwaysTryTypes": true,
60
+ "project": [
61
+ "./tsconfig.json"
62
+ ]
63
+ }
64
+ }
65
+ },
66
+ "overrides": [
67
+ {
68
+ "files": [
69
+ "src/iconify-bundle/*"
70
+ ],
71
+ "rules": {
72
+ "@typescript-eslint/no-var-requires": "off"
73
+ }
74
+ }
75
+ ]
76
+ }
@@ -0,0 +1,8 @@
1
+ node_modules
2
+ .next
3
+ out
4
+ build
5
+ dist
6
+ coverage
7
+ *.lock
8
+ package-lock.json
@@ -1,97 +1,23 @@
1
- import { cookies } from 'next/headers'
2
- import { redirect } from 'next/navigation'
3
- import { decodeJwt } from 'jose'
4
- import type { UserRole } from '@/lib/abilities'
5
-
6
- /**
7
- * JWT payload structure
8
- */
9
- interface JWTPayload {
10
- sub: string
11
- email?: string
12
- role?: string
13
- name?: string
14
- exp?: number
15
- }
16
-
17
- /**
18
- * Session data extracted from JWT
19
- */
20
- interface Session {
21
- userId: string
22
- role: UserRole
23
- name?: string
24
- email?: string
25
- }
26
-
27
- /**
28
- * Extract session from cookies (server-side)
29
- *
30
- * This is the defense-in-depth check that runs in addition to middleware.
31
- * It ensures no protected content is ever rendered without a valid session.
32
- */
33
- async function getServerSession(): Promise<Session | null> {
34
- const cookieStore = await cookies()
35
- const token = cookieStore.get('accessToken')?.value
36
-
37
- if (!token) {
38
- return null
39
- }
1
+ import SidebarLayout from '@/core/layouts/SidebarLayout'
2
+ import navigation from '@/navigation/sidebarRoutes'
3
+ import { fetchDynamicRoutes } from '@/navigation/dynamicRoutes'
4
+ import themeConfig from '@/core/configs/themeConfig'
40
5
 
6
+ export default async function DashboardLayout({ children }: { children: React.ReactNode }) {
7
+ let dynamicNavItems: Awaited<ReturnType<typeof fetchDynamicRoutes>> = []
41
8
  try {
42
- const payload = decodeJwt(token) as JWTPayload
43
-
44
- // Check expiration
45
- if (payload.exp && payload.exp * 1000 < Date.now()) {
46
- return null
47
- }
48
-
49
- const validRoles: UserRole[] = ['admin', 'manager', 'agent', 'viewer']
50
- const role = validRoles.includes(payload.role as UserRole)
51
- ? (payload.role as UserRole)
52
- : 'viewer'
53
-
54
- return {
55
- userId: payload.sub,
56
- role,
57
- name: payload.name,
58
- email: payload.email,
59
- }
60
- } catch {
61
- return null
62
- }
63
- }
64
-
65
- /**
66
- * Dashboard Layout
67
- *
68
- * This is a Server Component that provides defense-in-depth for all dashboard routes.
69
- * Even if middleware is bypassed, this layout ensures no protected content renders
70
- * without a valid session.
71
- *
72
- * The layout wraps all routes in the (dashboard) route group.
73
- */
74
- export default async function DashboardLayout({
75
- children,
76
- }: {
77
- children: React.ReactNode
78
- }) {
79
- const session = await getServerSession()
80
-
81
- // Defense-in-depth: redirect if no session
82
- // This should rarely trigger since middleware handles it first
83
- if (!session) {
84
- redirect('/login?returnUrl=/dashboard')
9
+ dynamicNavItems = await fetchDynamicRoutes()
10
+ } catch (error) {
11
+ console.error('Failed to fetch dynamic nav routes:', error)
85
12
  }
86
13
 
87
14
  return (
88
- <div className="dashboard-layout">
89
- {/*
90
- Add dashboard navigation/sidebar here
91
- Navigation items can be filtered based on session.role
92
- using the useAbility hook in client components
93
- */}
94
- <main className="dashboard-content">{children}</main>
15
+ <div className='dashboard-layout'>
16
+ <main className='dashboard-content'>
17
+ <SidebarLayout navItems={navigation()} dynamicNavItems={dynamicNavItems} appName={themeConfig.templateName}>
18
+ {children}
19
+ </SidebarLayout>
20
+ </main>
95
21
  </div>
96
22
  )
97
23
  }
@@ -2,8 +2,8 @@
2
2
 
3
3
  import { Container, Typography, Paper, Box, Chip, Button } from '@mui/material'
4
4
  import { LogOut } from 'lucide-react'
5
- import { useAuth } from '@/@core/context/AuthContext'
6
- import { useCan } from '@/@core/hooks/useAbility'
5
+ import { useAuth } from '@/core/context/AuthContext'
6
+ import { useCan } from '@/core/hooks/useAbility'
7
7
 
8
8
  // Role-specific home components
9
9
  function AdminHome() {
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" fill="#5B74FF" d="M 530.5,258.5 C 531.5,258.5 532.5,258.5 533.5,258.5C 553.598,259.825 573.598,259.825 593.5,258.5C 596.5,258.5 599.5,258.5 602.5,258.5C 605.273,259.657 608.273,260.324 611.5,260.5C 616.302,262.127 620.468,264.794 624,268.5C 630.942,279.405 638.109,290.071 645.5,300.5C 655.003,316.844 665.003,332.844 675.5,348.5C 675.427,350.027 676.094,351.027 677.5,351.5C 683.754,363.016 690.754,374.016 698.5,384.5C 703.155,392.472 707.822,400.472 712.5,408.5C 712.427,410.027 713.094,411.027 714.5,411.5C 719.474,419.087 717.807,424.921 709.5,429C 662.833,429.667 616.167,429.667 569.5,429C 567.975,427.991 566.308,427.491 564.5,427.5C 560.603,425.114 557.103,422.114 554,418.5C 549.364,410.056 544.198,402.056 538.5,394.5C 537,390.827 535,387.494 532.5,384.5C 530.281,379.291 527.281,374.624 523.5,370.5C 515.491,356.377 507.158,343.043 498.5,330.5C 496.316,326.119 493.65,322.119 490.5,318.5C 490.011,317.005 489.345,315.671 488.5,314.5C 487.649,312.118 486.316,310.118 484.5,308.5C 484.672,307.508 484.338,306.842 483.5,306.5C 483.5,305.833 483.167,305.5 482.5,305.5C 476.33,297.555 468.33,295.055 458.5,298C 456.273,298.941 454.273,300.108 452.5,301.5C 451.833,301.5 451.5,301.833 451.5,302.5C 445.554,308.427 444.054,315.427 447,323.5C 459.358,344.235 472.191,364.569 485.5,384.5C 498.336,406.178 511.669,427.511 525.5,448.5C 527.194,455.947 524.527,461.113 517.5,464C 468.167,464.667 418.833,464.667 369.5,464C 363.047,462.611 357.713,459.444 353.5,454.5C 343.82,439.797 334.153,425.13 324.5,410.5C 323.66,408.147 322.326,406.147 320.5,404.5C 315.997,396.156 310.997,388.156 305.5,380.5C 305.5,379.5 305.5,378.5 305.5,377.5C 305.5,374.167 305.5,370.833 305.5,367.5C 307.269,362.052 310.603,357.719 315.5,354.5C 319.566,351.437 322.899,347.771 325.5,343.5C 326.5,342.167 327.5,340.833 328.5,339.5C 331.5,337.167 334.167,334.5 336.5,331.5C 339.5,329.167 342.167,326.5 344.5,323.5C 356.112,311.553 367.778,299.553 379.5,287.5C 382.5,286.5 384.5,284.5 385.5,281.5C 389.167,277.5 392.833,273.5 396.5,269.5C 400.516,265.492 405.182,262.492 410.5,260.5C 450.805,259.802 490.805,259.135 530.5,258.5 Z"/>
3
+ <path fill-rule="evenodd" clip-rule="evenodd" fill="#5B74FF" d="M 657.5,475.5 C 664.789,477.595 670.956,481.595 676,487.5C 692,511.5 708,535.5 724,559.5C 725.874,563.52 725.874,567.52 724,571.5C 721.283,574.71 718.783,578.044 716.5,581.5C 691.195,608.474 665.861,635.474 640.5,662.5C 634.73,668.771 628.73,674.938 622.5,681C 618.547,683.81 614.213,685.81 609.5,687C 546.833,687.667 484.167,687.667 421.5,687C 419.277,686.434 417.277,685.6 415.5,684.5C 415.027,683.094 414.027,682.427 412.5,682.5C 411.833,682.5 411.167,682.5 410.5,682.5C 405.379,677.722 401.046,672.388 397.5,666.5C 396.331,663.489 394.664,660.822 392.5,658.5C 386.069,647.96 379.402,637.627 372.5,627.5C 371.241,623.975 369.241,620.975 366.5,618.5C 355.912,600.316 344.579,582.649 332.5,565.5C 332.068,564.29 331.401,563.29 330.5,562.5C 327.996,557.485 324.996,552.819 321.5,548.5C 321.672,547.508 321.338,546.842 320.5,546.5C 319.525,544.205 318.192,542.205 316.5,540.5C 313.555,534.896 310.221,529.562 306.5,524.5C 304.65,520.355 304.15,516.021 305,511.5C 306.728,508.047 309.562,506.214 313.5,506C 361.156,506.344 408.49,506.344 455.5,506C 465.15,507.51 472.483,512.343 477.5,520.5C 490.587,541.677 503.92,562.677 517.5,583.5C 522.42,593.014 528.086,602.014 534.5,610.5C 539.119,620.228 545.119,629.061 552.5,637C 559.208,640.671 566.208,641.338 573.5,639C 576.106,638.238 578.106,636.708 579.5,634.5C 580.167,634.5 580.5,634.167 580.5,633.5C 584.921,628.719 586.421,623.053 585,616.5C 582.908,611.303 580.074,606.636 576.5,602.5C 572.33,594.82 567.663,587.487 562.5,580.5C 562.573,578.973 561.906,577.973 560.5,577.5C 559.66,575.147 558.326,573.147 556.5,571.5C 553.664,565.822 550.331,560.489 546.5,555.5C 533.273,533.389 519.773,511.389 506,489.5C 504.566,482.794 507.066,478.294 513.5,476C 561.499,475.5 609.499,475.333 657.5,475.5 Z"/>
4
+ </svg>
@@ -1,5 +1,6 @@
1
1
  import type { Metadata } from 'next'
2
- import { Poppins, Cairo } from 'next/font/google'
2
+ import { Poppins } from 'next/font/google'
3
+ import localFont from 'next/font/local'
3
4
  import './globals.css'
4
5
  import AppProviders from '@/providers/AppProviders'
5
6
 
@@ -9,10 +10,19 @@ const poppins = Poppins({
9
10
  weight: ['300', '400', '500', '600', '700']
10
11
  })
11
12
 
12
- const cairo = Cairo({
13
- subsets: ['arabic'],
14
- variable: '--font-cairo',
15
- weight: ['300', '400', '500', '600', '700']
13
+ const montserratArabic = localFont({
14
+ src: [
15
+ { path: '../public/fonts/Montserrat-Arabic-Thin.ttf', weight: '100' },
16
+ { path: '../public/fonts/Montserrat-Arabic-ExtraLight.ttf', weight: '200' },
17
+ { path: '../public/fonts/Montserrat-Arabic-Light.ttf', weight: '300' },
18
+ { path: '../public/fonts/Montserrat-Arabic-Regular.ttf', weight: '400' },
19
+ { path: '../public/fonts/Montserrat-Arabic-Medium.ttf', weight: '500' },
20
+ { path: '../public/fonts/Montserrat-Arabic-SemiBold.ttf', weight: '600' },
21
+ { path: '../public/fonts/Montserrat-Arabic-Bold.ttf', weight: '700' },
22
+ { path: '../public/fonts/Montserrat-Arabic-ExtraBold.ttf', weight: '800' },
23
+ { path: '../public/fonts/Montserrat-Arabic-Black.ttf', weight: '900' }
24
+ ],
25
+ variable: '--font-montserrat-arabic'
16
26
  })
17
27
  export const metadata: Metadata = {
18
28
  title: 'Shortcut Nextjs Template',
@@ -26,7 +36,7 @@ export default async function RootLayout({
26
36
  }>) {
27
37
  return (
28
38
  <html lang='en' dir='ltr'>
29
- <body className={`${poppins.variable} ${cairo.variable} antialiased`}>
39
+ <body className={`${poppins.variable} ${montserratArabic.variable} antialiased`}>
30
40
  <AppProviders>{children}</AppProviders>
31
41
  </body>
32
42
  </html>