@duyanhdev/mvp-ifs-ui-kit 21.0.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 (170) hide show
  1. package/.editorconfig +16 -0
  2. package/.gitmodules +3 -0
  3. package/.postcssrc.json +5 -0
  4. package/.prettierignore +14 -0
  5. package/.prettierrc.json +29 -0
  6. package/LICENSE.md +21 -0
  7. package/README.md +59 -0
  8. package/angular.json +98 -0
  9. package/eslint.config.js +89 -0
  10. package/package.json +59 -0
  11. package/public/demo/images/flag/flag_placeholder.png +0 -0
  12. package/public/demo/images/footer-image.gif +0 -0
  13. package/public/demo/images/galleria/galleria1.jpg +0 -0
  14. package/public/demo/images/galleria/galleria10.jpg +0 -0
  15. package/public/demo/images/galleria/galleria10s.jpg +0 -0
  16. package/public/demo/images/galleria/galleria11.jpg +0 -0
  17. package/public/demo/images/galleria/galleria11s.jpg +0 -0
  18. package/public/demo/images/galleria/galleria12.jpg +0 -0
  19. package/public/demo/images/galleria/galleria12s.jpg +0 -0
  20. package/public/demo/images/galleria/galleria13.jpg +0 -0
  21. package/public/demo/images/galleria/galleria13s.jpg +0 -0
  22. package/public/demo/images/galleria/galleria14.jpg +0 -0
  23. package/public/demo/images/galleria/galleria14s.jpg +0 -0
  24. package/public/demo/images/galleria/galleria15.jpg +0 -0
  25. package/public/demo/images/galleria/galleria15s.jpg +0 -0
  26. package/public/demo/images/galleria/galleria1s.jpg +0 -0
  27. package/public/demo/images/galleria/galleria2.jpg +0 -0
  28. package/public/demo/images/galleria/galleria2s.jpg +0 -0
  29. package/public/demo/images/galleria/galleria3.jpg +0 -0
  30. package/public/demo/images/galleria/galleria3s.jpg +0 -0
  31. package/public/demo/images/galleria/galleria4.jpg +0 -0
  32. package/public/demo/images/galleria/galleria4s.jpg +0 -0
  33. package/public/demo/images/galleria/galleria5.jpg +0 -0
  34. package/public/demo/images/galleria/galleria5s.jpg +0 -0
  35. package/public/demo/images/galleria/galleria6.jpg +0 -0
  36. package/public/demo/images/galleria/galleria6s.jpg +0 -0
  37. package/public/demo/images/galleria/galleria7.jpg +0 -0
  38. package/public/demo/images/galleria/galleria7s.jpg +0 -0
  39. package/public/demo/images/galleria/galleria8.jpg +0 -0
  40. package/public/demo/images/galleria/galleria8s.jpg +0 -0
  41. package/public/demo/images/galleria/galleria9.jpg +0 -0
  42. package/public/demo/images/galleria/galleria9s.jpg +0 -0
  43. package/public/demo/images/product/bamboo-watch.jpg +0 -0
  44. package/public/demo/images/product/black-watch.jpg +0 -0
  45. package/public/demo/images/product/blue-band.jpg +0 -0
  46. package/public/demo/images/product/blue-t-shirt.jpg +0 -0
  47. package/public/demo/images/product/bracelet.jpg +0 -0
  48. package/public/demo/images/product/brown-purse.jpg +0 -0
  49. package/public/demo/images/product/chakra-bracelet.jpg +0 -0
  50. package/public/demo/images/product/galaxy-earrings.jpg +0 -0
  51. package/public/demo/images/product/game-controller.jpg +0 -0
  52. package/public/demo/images/product/gaming-set.jpg +0 -0
  53. package/public/demo/images/product/gold-phone-case.jpg +0 -0
  54. package/public/demo/images/product/green-earbuds.jpg +0 -0
  55. package/public/demo/images/product/green-t-shirt.jpg +0 -0
  56. package/public/demo/images/product/grey-t-shirt.jpg +0 -0
  57. package/public/demo/images/product/headphones.jpg +0 -0
  58. package/public/demo/images/product/light-green-t-shirt.jpg +0 -0
  59. package/public/demo/images/product/lime-band.jpg +0 -0
  60. package/public/demo/images/product/mini-speakers.jpg +0 -0
  61. package/public/demo/images/product/painted-phone-case.jpg +0 -0
  62. package/public/demo/images/product/pink-band.jpg +0 -0
  63. package/public/demo/images/product/pink-purse.jpg +0 -0
  64. package/public/demo/images/product/product-placeholder.svg +10 -0
  65. package/public/demo/images/product/purple-band.jpg +0 -0
  66. package/public/demo/images/product/purple-gemstone-necklace.jpg +0 -0
  67. package/public/demo/images/product/purple-t-shirt.jpg +0 -0
  68. package/public/demo/images/product/shoes.jpg +0 -0
  69. package/public/demo/images/product/sneakers.jpg +0 -0
  70. package/public/demo/images/product/teal-t-shirt.jpg +0 -0
  71. package/public/demo/images/product/yellow-earbuds.jpg +0 -0
  72. package/public/demo/images/product/yoga-mat.jpg +0 -0
  73. package/public/demo/images/product/yoga-set.jpg +0 -0
  74. package/src/app/layout/component/configurator/app.configurator.html +48 -0
  75. package/src/app/layout/component/configurator/app.configurator.ts +396 -0
  76. package/src/app/layout/component/floatingconfigurator/app.floatingconfigurator.ts +31 -0
  77. package/src/app/layout/component/footer/app.footer.scss +52 -0
  78. package/src/app/layout/component/footer/app.footer.ts +26 -0
  79. package/src/app/layout/component/layout/app.layout.ts +50 -0
  80. package/src/app/layout/component/menu/app.menu.html +7 -0
  81. package/src/app/layout/component/menu/app.menu.scss +13 -0
  82. package/src/app/layout/component/menu/app.menu.ts +90 -0
  83. package/src/app/layout/component/menuitem/app.menuitem.html +56 -0
  84. package/src/app/layout/component/menuitem/app.menuitem.scss +218 -0
  85. package/src/app/layout/component/menuitem/app.menuitem.ts +126 -0
  86. package/src/app/layout/component/sidebar/app.sidebar.html +3 -0
  87. package/src/app/layout/component/sidebar/app.sidebar.scss +0 -0
  88. package/src/app/layout/component/sidebar/app.sidebar.ts +106 -0
  89. package/src/app/layout/component/topbar/app.topbar.html +190 -0
  90. package/src/app/layout/component/topbar/app.topbar.scss +8 -0
  91. package/src/app/layout/component/topbar/app.topbar.ts +68 -0
  92. package/src/app/layout/service/layout.service.ts +117 -0
  93. package/src/app/pages/auth/access.ts +32 -0
  94. package/src/app/pages/auth/auth.routes.ts +10 -0
  95. package/src/app/pages/auth/error.ts +32 -0
  96. package/src/app/pages/auth/login.ts +71 -0
  97. package/src/app/pages/crud/crud.ts +387 -0
  98. package/src/app/pages/dashboard/dashboard.css +778 -0
  99. package/src/app/pages/dashboard/dashboard.html +191 -0
  100. package/src/app/pages/dashboard/dashboard.ts +348 -0
  101. package/src/app/pages/documentation/documentation.ts +73 -0
  102. package/src/app/pages/empty/empty.ts +11 -0
  103. package/src/app/pages/landing/components/featureswidget.ts +139 -0
  104. package/src/app/pages/landing/components/footerwidget.ts +73 -0
  105. package/src/app/pages/landing/components/herowidget.ts +25 -0
  106. package/src/app/pages/landing/components/highlightswidget.ts +46 -0
  107. package/src/app/pages/landing/components/pricingwidget.ts +119 -0
  108. package/src/app/pages/landing/components/topbarwidget.component.ts +68 -0
  109. package/src/app/pages/landing/landing.ts +31 -0
  110. package/src/app/pages/notfound/notfound.ts +68 -0
  111. package/src/app/pages/pages.routes.ts +17 -0
  112. package/src/app/pages/profile/profile.html +57 -0
  113. package/src/app/pages/profile/profile.scss +145 -0
  114. package/src/app/pages/profile/profile.ts +19 -0
  115. package/src/app/pages/service/country.service.ts +255 -0
  116. package/src/app/pages/service/customer.service.ts +9057 -0
  117. package/src/app/pages/service/icon.service.ts +23 -0
  118. package/src/app/pages/service/node.service.ts +816 -0
  119. package/src/app/pages/service/photo.service.ts +103 -0
  120. package/src/app/pages/service/product.service.ts +1322 -0
  121. package/src/app/pages/tickets/tickets-create/tickets-create.html +140 -0
  122. package/src/app/pages/tickets/tickets-create/tickets-create.scss +617 -0
  123. package/src/app/pages/tickets/tickets-create/tickets-create.ts +104 -0
  124. package/src/app/pages/tickets/tickets-list/ticket-list.html +150 -0
  125. package/src/app/pages/tickets/tickets-list/ticket-list.scss +392 -0
  126. package/src/app/pages/tickets/tickets-list/ticket-list.ts +178 -0
  127. package/src/app/pages/uikit/buttondemo.ts +254 -0
  128. package/src/app/pages/uikit/chartdemo.ts +290 -0
  129. package/src/app/pages/uikit/filedemo.ts +52 -0
  130. package/src/app/pages/uikit/formlayoutdemo.ts +129 -0
  131. package/src/app/pages/uikit/inputdemo.ts +339 -0
  132. package/src/app/pages/uikit/listdemo.ts +217 -0
  133. package/src/app/pages/uikit/mediademo.ts +1021 -0
  134. package/src/app/pages/uikit/menudemo.ts +540 -0
  135. package/src/app/pages/uikit/messagesdemo.ts +101 -0
  136. package/src/app/pages/uikit/miscdemo.ts +192 -0
  137. package/src/app/pages/uikit/overlaydemo.ts +235 -0
  138. package/src/app/pages/uikit/panelsdemo.ts +235 -0
  139. package/src/app/pages/uikit/tabledemo.ts +568 -0
  140. package/src/app/pages/uikit/timelinedemo.ts +141 -0
  141. package/src/app/pages/uikit/treedemo.ts +75 -0
  142. package/src/app/pages/uikit/uikit.routes.ts +35 -0
  143. package/src/app.component.ts +22 -0
  144. package/src/app.config.ts +23 -0
  145. package/src/app.routes.ts +23 -0
  146. package/src/assets/demo/code.scss +17 -0
  147. package/src/assets/demo/demo.scss +2 -0
  148. package/src/assets/demo/flags/flags.css +984 -0
  149. package/src/assets/layout/_core.scss +24 -0
  150. package/src/assets/layout/_footer.scss +8 -0
  151. package/src/assets/layout/_main.scss +21 -0
  152. package/src/assets/layout/_menu.scss +159 -0
  153. package/src/assets/layout/_mixins.scss +15 -0
  154. package/src/assets/layout/_preloading.scss +47 -0
  155. package/src/assets/layout/_responsive.scss +111 -0
  156. package/src/assets/layout/_topbar.scss +201 -0
  157. package/src/assets/layout/_typography.scss +68 -0
  158. package/src/assets/layout/_utils.scss +25 -0
  159. package/src/assets/layout/layout.scss +13 -0
  160. package/src/assets/layout/variables/_common.scss +21 -0
  161. package/src/assets/layout/variables/_dark.scss +5 -0
  162. package/src/assets/layout/variables/_light.scss +5 -0
  163. package/src/assets/styles.scss +4 -0
  164. package/src/assets/tailwind.css +32 -0
  165. package/src/index.html +15 -0
  166. package/src/main.ts +5 -0
  167. package/tsconfig.app.json +15 -0
  168. package/tsconfig.json +33 -0
  169. package/tsconfig.spec.json +15 -0
  170. package/vercel.json +9 -0
@@ -0,0 +1,396 @@
1
+ import { CommonModule, isPlatformBrowser } from '@angular/common';
2
+ import { Component, computed, inject, PLATFORM_ID, signal } from '@angular/core';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { Router } from '@angular/router';
5
+ import { $t, updatePreset, updateSurfacePalette } from '@primeuix/themes';
6
+ import Aura from '@primeuix/themes/aura';
7
+ import Lara from '@primeuix/themes/lara';
8
+ import Nora from '@primeuix/themes/nora';
9
+ import { PrimeNG } from 'primeng/config';
10
+ import { SelectButtonModule } from 'primeng/selectbutton';
11
+ import { LayoutService } from '@/app/layout/service/layout.service';
12
+
13
+ const presets = {
14
+ Aura,
15
+ Lara,
16
+ Nora
17
+ } as const;
18
+
19
+ declare type KeyOfType<T> = keyof T extends infer U ? U : never;
20
+
21
+ declare type SurfacesType = {
22
+ name?: string;
23
+ palette?: {
24
+ 0?: string;
25
+ 50?: string;
26
+ 100?: string;
27
+ 200?: string;
28
+ 300?: string;
29
+ 400?: string;
30
+ 500?: string;
31
+ 600?: string;
32
+ 700?: string;
33
+ 800?: string;
34
+ 900?: string;
35
+ 950?: string;
36
+ };
37
+ };
38
+
39
+ @Component({
40
+ selector: 'app-configurator',
41
+ standalone: true,
42
+ imports: [CommonModule, FormsModule, SelectButtonModule],
43
+ templateUrl: 'app.configurator.html',
44
+ host: {
45
+ class: 'hidden absolute top-13 right-0 w-72 p-4 bg-surface-0 dark:bg-surface-900 border border-surface rounded-border origin-top shadow-[0px_3px_5px_rgba(0,0,0,0.02),0px_0px_2px_rgba(0,0,0,0.05),0px_1px_4px_rgba(0,0,0,0.08)]'
46
+ }
47
+ })
48
+ export class AppConfigurator {
49
+ router = inject(Router);
50
+
51
+ config: PrimeNG = inject(PrimeNG);
52
+
53
+ layoutService: LayoutService = inject(LayoutService);
54
+
55
+ platformId = inject(PLATFORM_ID);
56
+
57
+ primeng = inject(PrimeNG);
58
+
59
+ presets = Object.keys(presets);
60
+
61
+ showMenuModeButton = signal(!this.router.url.includes('auth'));
62
+
63
+ menuModeOptions = [
64
+ { label: 'Static', value: 'static' },
65
+ { label: 'Overlay', value: 'overlay' }
66
+ ];
67
+
68
+ ngOnInit() {
69
+ if (isPlatformBrowser(this.platformId)) {
70
+ this.onPresetChange(this.layoutService.layoutConfig().preset);
71
+ }
72
+ }
73
+
74
+ surfaces: SurfacesType[] = [
75
+ {
76
+ name: 'slate',
77
+ palette: {
78
+ 0: '#ffffff',
79
+ 50: '#f8fafc',
80
+ 100: '#f1f5f9',
81
+ 200: '#e2e8f0',
82
+ 300: '#cbd5e1',
83
+ 400: '#94a3b8',
84
+ 500: '#64748b',
85
+ 600: '#475569',
86
+ 700: '#334155',
87
+ 800: '#1e293b',
88
+ 900: '#0f172a',
89
+ 950: '#020617'
90
+ }
91
+ },
92
+ {
93
+ name: 'gray',
94
+ palette: {
95
+ 0: '#ffffff',
96
+ 50: '#f9fafb',
97
+ 100: '#f3f4f6',
98
+ 200: '#e5e7eb',
99
+ 300: '#d1d5db',
100
+ 400: '#9ca3af',
101
+ 500: '#6b7280',
102
+ 600: '#4b5563',
103
+ 700: '#374151',
104
+ 800: '#1f2937',
105
+ 900: '#111827',
106
+ 950: '#030712'
107
+ }
108
+ },
109
+ {
110
+ name: 'zinc',
111
+ palette: {
112
+ 0: '#ffffff',
113
+ 50: '#fafafa',
114
+ 100: '#f4f4f5',
115
+ 200: '#e4e4e7',
116
+ 300: '#d4d4d8',
117
+ 400: '#a1a1aa',
118
+ 500: '#71717a',
119
+ 600: '#52525b',
120
+ 700: '#3f3f46',
121
+ 800: '#27272a',
122
+ 900: '#18181b',
123
+ 950: '#09090b'
124
+ }
125
+ },
126
+ {
127
+ name: 'neutral',
128
+ palette: {
129
+ 0: '#ffffff',
130
+ 50: '#fafafa',
131
+ 100: '#f5f5f5',
132
+ 200: '#e5e5e5',
133
+ 300: '#d4d4d4',
134
+ 400: '#a3a3a3',
135
+ 500: '#737373',
136
+ 600: '#525252',
137
+ 700: '#404040',
138
+ 800: '#262626',
139
+ 900: '#171717',
140
+ 950: '#0a0a0a'
141
+ }
142
+ },
143
+ {
144
+ name: 'stone',
145
+ palette: {
146
+ 0: '#ffffff',
147
+ 50: '#fafaf9',
148
+ 100: '#f5f5f4',
149
+ 200: '#e7e5e4',
150
+ 300: '#d6d3d1',
151
+ 400: '#a8a29e',
152
+ 500: '#78716c',
153
+ 600: '#57534e',
154
+ 700: '#44403c',
155
+ 800: '#292524',
156
+ 900: '#1c1917',
157
+ 950: '#0c0a09'
158
+ }
159
+ },
160
+ {
161
+ name: 'soho',
162
+ palette: {
163
+ 0: '#ffffff',
164
+ 50: '#ececec',
165
+ 100: '#dedfdf',
166
+ 200: '#c4c4c6',
167
+ 300: '#adaeb0',
168
+ 400: '#97979b',
169
+ 500: '#7f8084',
170
+ 600: '#6a6b70',
171
+ 700: '#55565b',
172
+ 800: '#3f4046',
173
+ 900: '#2c2c34',
174
+ 950: '#16161d'
175
+ }
176
+ },
177
+ {
178
+ name: 'viva',
179
+ palette: {
180
+ 0: '#ffffff',
181
+ 50: '#f3f3f3',
182
+ 100: '#e7e7e8',
183
+ 200: '#cfd0d0',
184
+ 300: '#b7b8b9',
185
+ 400: '#9fa1a1',
186
+ 500: '#87898a',
187
+ 600: '#6e7173',
188
+ 700: '#565a5b',
189
+ 800: '#3e4244',
190
+ 900: '#262b2c',
191
+ 950: '#0e1315'
192
+ }
193
+ },
194
+ {
195
+ name: 'ocean',
196
+ palette: {
197
+ 0: '#ffffff',
198
+ 50: '#fbfcfc',
199
+ 100: '#F7F9F8',
200
+ 200: '#EFF3F2',
201
+ 300: '#DADEDD',
202
+ 400: '#B1B7B6',
203
+ 500: '#828787',
204
+ 600: '#5F7274',
205
+ 700: '#415B61',
206
+ 800: '#29444E',
207
+ 900: '#183240',
208
+ 950: '#0c1920'
209
+ }
210
+ }
211
+ ];
212
+
213
+ selectedPrimaryColor = computed(() => {
214
+ return this.layoutService.layoutConfig().primary;
215
+ });
216
+
217
+ selectedSurfaceColor = computed(() => this.layoutService.layoutConfig().surface);
218
+
219
+ selectedPreset = computed(() => this.layoutService.layoutConfig().preset);
220
+
221
+ menuMode = computed(() => this.layoutService.layoutConfig().menuMode);
222
+
223
+ primaryColors = computed<SurfacesType[]>(() => {
224
+ const presetPalette = presets[this.layoutService.layoutConfig().preset as KeyOfType<typeof presets>].primitive;
225
+ const colors = ['emerald', 'green', 'lime', 'orange', 'amber', 'yellow', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose'];
226
+ const palettes: SurfacesType[] = [{ name: 'noir', palette: {} }];
227
+
228
+ colors.forEach((color) => {
229
+ palettes.push({
230
+ name: color,
231
+ palette: presetPalette?.[color as KeyOfType<typeof presetPalette>] as SurfacesType['palette']
232
+ });
233
+ });
234
+
235
+ return palettes;
236
+ });
237
+
238
+ getPresetExt() {
239
+ const color: SurfacesType = this.primaryColors().find((c) => c.name === this.selectedPrimaryColor()) || {};
240
+ const preset = this.layoutService.layoutConfig().preset;
241
+
242
+ if (color.name === 'noir') {
243
+ return {
244
+ semantic: {
245
+ primary: {
246
+ 50: '{surface.50}',
247
+ 100: '{surface.100}',
248
+ 200: '{surface.200}',
249
+ 300: '{surface.300}',
250
+ 400: '{surface.400}',
251
+ 500: '{surface.500}',
252
+ 600: '{surface.600}',
253
+ 700: '{surface.700}',
254
+ 800: '{surface.800}',
255
+ 900: '{surface.900}',
256
+ 950: '{surface.950}'
257
+ },
258
+ colorScheme: {
259
+ light: {
260
+ primary: {
261
+ color: '{primary.950}',
262
+ contrastColor: '#ffffff',
263
+ hoverColor: '{primary.800}',
264
+ activeColor: '{primary.700}'
265
+ },
266
+ highlight: {
267
+ background: '{primary.950}',
268
+ focusBackground: '{primary.700}',
269
+ color: '#ffffff',
270
+ focusColor: '#ffffff'
271
+ }
272
+ },
273
+ dark: {
274
+ primary: {
275
+ color: '{primary.50}',
276
+ contrastColor: '{primary.950}',
277
+ hoverColor: '{primary.200}',
278
+ activeColor: '{primary.300}'
279
+ },
280
+ highlight: {
281
+ background: '{primary.50}',
282
+ focusBackground: '{primary.300}',
283
+ color: '{primary.950}',
284
+ focusColor: '{primary.950}'
285
+ }
286
+ }
287
+ }
288
+ }
289
+ };
290
+ } else {
291
+ if (preset === 'Nora') {
292
+ return {
293
+ semantic: {
294
+ primary: color.palette,
295
+ colorScheme: {
296
+ light: {
297
+ primary: {
298
+ color: '{primary.600}',
299
+ contrastColor: '#ffffff',
300
+ hoverColor: '{primary.700}',
301
+ activeColor: '{primary.800}'
302
+ },
303
+ highlight: {
304
+ background: '{primary.600}',
305
+ focusBackground: '{primary.700}',
306
+ color: '#ffffff',
307
+ focusColor: '#ffffff'
308
+ }
309
+ },
310
+ dark: {
311
+ primary: {
312
+ color: '{primary.500}',
313
+ contrastColor: '{surface.900}',
314
+ hoverColor: '{primary.400}',
315
+ activeColor: '{primary.300}'
316
+ },
317
+ highlight: {
318
+ background: '{primary.500}',
319
+ focusBackground: '{primary.400}',
320
+ color: '{surface.900}',
321
+ focusColor: '{surface.900}'
322
+ }
323
+ }
324
+ }
325
+ }
326
+ };
327
+ } else {
328
+ return {
329
+ semantic: {
330
+ primary: color.palette,
331
+ colorScheme: {
332
+ light: {
333
+ primary: {
334
+ color: '{primary.500}',
335
+ contrastColor: '#ffffff',
336
+ hoverColor: '{primary.600}',
337
+ activeColor: '{primary.700}'
338
+ },
339
+ highlight: {
340
+ background: '{primary.50}',
341
+ focusBackground: '{primary.100}',
342
+ color: '{primary.700}',
343
+ focusColor: '{primary.800}'
344
+ }
345
+ },
346
+ dark: {
347
+ primary: {
348
+ color: '{primary.400}',
349
+ contrastColor: '{surface.900}',
350
+ hoverColor: '{primary.300}',
351
+ activeColor: '{primary.200}'
352
+ },
353
+ highlight: {
354
+ background: 'color-mix(in srgb, {primary.400}, transparent 84%)',
355
+ focusBackground: 'color-mix(in srgb, {primary.400}, transparent 76%)',
356
+ color: 'rgba(255,255,255,.87)',
357
+ focusColor: 'rgba(255,255,255,.87)'
358
+ }
359
+ }
360
+ }
361
+ }
362
+ };
363
+ }
364
+ }
365
+ }
366
+
367
+ updateColors(event: any, type: string, color: any) {
368
+ if (type === 'primary') {
369
+ this.layoutService.layoutConfig.update((state) => ({ ...state, primary: color.name }));
370
+ } else if (type === 'surface') {
371
+ this.layoutService.layoutConfig.update((state) => ({ ...state, surface: color.name }));
372
+ }
373
+ this.applyTheme(type, color);
374
+
375
+ event.stopPropagation();
376
+ }
377
+
378
+ applyTheme(type: string, color: any) {
379
+ if (type === 'primary') {
380
+ updatePreset(this.getPresetExt());
381
+ } else if (type === 'surface') {
382
+ updateSurfacePalette(color.palette);
383
+ }
384
+ }
385
+
386
+ onPresetChange(event: any) {
387
+ this.layoutService.layoutConfig.update((state) => ({ ...state, preset: event }));
388
+ const preset = presets[event as KeyOfType<typeof presets>];
389
+ const surfacePalette = this.surfaces.find((s) => s.name === this.selectedSurfaceColor())?.palette;
390
+ $t().preset(preset).preset(this.getPresetExt()).surfacePalette(surfacePalette).use({ useDefaultOptions: true });
391
+ }
392
+
393
+ onMenuModeChange(event: string) {
394
+ this.layoutService.layoutConfig.update((prev) => ({ ...prev, menuMode: event }));
395
+ }
396
+ }
@@ -0,0 +1,31 @@
1
+ import { Component, computed, inject, input } from '@angular/core';
2
+ import { ButtonModule } from 'primeng/button';
3
+ import { StyleClassModule } from 'primeng/styleclass';
4
+ import { AppConfigurator } from './../configurator/app.configurator';
5
+ import { LayoutService } from '@/app/layout/service/layout.service';
6
+ import { CommonModule } from '@angular/common';
7
+
8
+ @Component({
9
+ selector: 'app-floating-configurator',
10
+ imports: [CommonModule, ButtonModule, StyleClassModule, AppConfigurator],
11
+ template: `
12
+ <div class="flex gap-4 top-8 right-8" [ngClass]="{ fixed: float() }">
13
+ <p-button type="button" (onClick)="toggleDarkMode()" [rounded]="true" [icon]="isDarkTheme() ? 'pi pi-moon' : 'pi pi-sun'" severity="secondary" />
14
+ <div class="relative">
15
+ <p-button icon="pi pi-palette" pStyleClass="@next" enterFromClass="hidden" enterActiveClass="animate-scalein" leaveToClass="hidden" leaveActiveClass="animate-fadeout" [hideOnOutsideClick]="true" type="button" rounded />
16
+ <app-configurator />
17
+ </div>
18
+ </div>
19
+ `
20
+ })
21
+ export class AppFloatingConfigurator {
22
+ LayoutService = inject(LayoutService);
23
+
24
+ float = input<boolean>(true);
25
+
26
+ isDarkTheme = computed(() => this.LayoutService.layoutConfig().darkTheme);
27
+
28
+ toggleDarkMode() {
29
+ this.LayoutService.layoutConfig.update((state) => ({ ...state, darkTheme: !state.darkTheme }));
30
+ }
31
+ }
@@ -0,0 +1,52 @@
1
+ .footer {
2
+ background: #404040;
3
+ padding: 0 0 5px;
4
+ color: #fff;
5
+ font-size: 14px;
6
+ background-image: url('./../../../../../public/demo//images/footer-image.gif');
7
+ height: 60px;
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ width: 100%;
12
+ margin: auto;
13
+ }
14
+
15
+ .overlay {
16
+ width: 100%;
17
+ height: 100%;
18
+
19
+ }
20
+
21
+ .content {
22
+ text-align: center;
23
+ color: #fff;
24
+ display: flex;
25
+ justify-content: center;
26
+ flex-direction: column;
27
+ gap: 10px;
28
+ width: 100%;
29
+ height: 100%;
30
+ }
31
+
32
+ .copyright {
33
+ font-size: 13px;
34
+ }
35
+
36
+ .credits {
37
+ font-size: 12px;
38
+ }
39
+
40
+ .text-colorful {
41
+ background-image: linear-gradient(to left, #dedede, #00ff04, #71b5f3, #ffa7e5, #ff0, #ffc253, #ff3939);
42
+ -webkit-background-clip: text;
43
+ -moz-background-clip: text;
44
+ background-clip: text;
45
+ color: transparent;
46
+ font-weight: 800;
47
+ box-sizing: border-box;
48
+ cursor: pointer;
49
+ border: 2px solid rgb(255, 137, 196);
50
+ border-radius: 20px;
51
+ padding: 3px 6px;
52
+ }
@@ -0,0 +1,26 @@
1
+ import { Component } from '@angular/core';
2
+
3
+ @Component({
4
+ standalone: true,
5
+ selector: 'app-footer',
6
+ styleUrl: './app.footer.scss',
7
+ template: `
8
+ <footer class="footer">
9
+ <div class="overlay">
10
+ <div class="content">
11
+ <div class="copyright">
12
+ Copyright © 2026
13
+ <strong><span>Maruei Vietnam Precision Co., Ltd</span></strong
14
+ >.
15
+ </div>
16
+
17
+ <div class="credits">
18
+ Designed by
19
+ <span class="text-colorful">IFS Team</span>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ </footer>
24
+ `
25
+ })
26
+ export class AppFooter {}
@@ -0,0 +1,50 @@
1
+ import { Component, computed, effect, inject } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { RouterModule } from '@angular/router';
4
+ import { AppTopbar } from '../topbar/app.topbar';
5
+ import { AppSidebar } from '../sidebar/app.sidebar';
6
+ import { AppFooter } from '../footer/app.footer';
7
+ import { LayoutService } from '@/app/layout/service/layout.service';
8
+
9
+ @Component({
10
+ selector: 'app-layout',
11
+ standalone: true,
12
+ imports: [CommonModule, AppTopbar, AppSidebar, RouterModule, AppFooter],
13
+ template: `<div class="layout-wrapper" [ngClass]="containerClass()">
14
+ <app-topbar></app-topbar>
15
+ <app-sidebar></app-sidebar>
16
+ <div class="layout-main-container">
17
+ <div class="layout-main">
18
+ <router-outlet></router-outlet>
19
+ </div>
20
+ <app-footer></app-footer>
21
+ </div>
22
+ <div class="layout-mask"></div>
23
+ </div> `
24
+ })
25
+ export class AppLayout {
26
+ layoutService = inject(LayoutService);
27
+
28
+ constructor() {
29
+ effect(() => {
30
+ const state = this.layoutService.layoutState();
31
+ if (state.mobileMenuActive) {
32
+ document.body.classList.add('blocked-scroll');
33
+ } else {
34
+ document.body.classList.remove('blocked-scroll');
35
+ }
36
+ });
37
+ }
38
+
39
+ containerClass = computed(() => {
40
+ const config = this.layoutService.layoutConfig();
41
+ const state = this.layoutService.layoutState();
42
+ return {
43
+ 'layout-overlay': config.menuMode === 'overlay',
44
+ 'layout-static': config.menuMode === 'static',
45
+ 'layout-static-inactive': state.staticMenuDesktopInactive && config.menuMode === 'static',
46
+ 'layout-overlay-active': state.overlayMenuActive,
47
+ 'layout-mobile-active': state.mobileMenuActive
48
+ };
49
+ });
50
+ }
@@ -0,0 +1,7 @@
1
+ <ul class="layout-menu">
2
+ @for (item of model; track item.label) { @if (!item.separator) {
3
+ <li app-menuitem [item]="item" [root]="true"></li>
4
+ } @else {
5
+ <li class="menu-separator"></li>
6
+ } }
7
+ </ul>
@@ -0,0 +1,13 @@
1
+ // ===== MENU WRAPPER =====
2
+ .layout-menu {
3
+ list-style: none;
4
+ margin: 0;
5
+ padding: 0.5rem 0;
6
+
7
+ .menu-separator {
8
+ height: 1px;
9
+ background: linear-gradient(90deg, transparent, var(--surface-border), transparent);
10
+ margin: 0.5rem 1rem;
11
+
12
+ }
13
+ }
@@ -0,0 +1,90 @@
1
+ import { Component } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { RouterModule } from '@angular/router';
4
+ import { MenuItem } from 'primeng/api';
5
+ import { AppMenuitem } from './../menuitem/app.menuitem';
6
+
7
+ @Component({
8
+ selector: 'app-menu',
9
+ standalone: true,
10
+ imports: [CommonModule, AppMenuitem, RouterModule],
11
+ templateUrl: './app.menu.html'
12
+ })
13
+ export class AppMenu {
14
+ model: MenuItem[] = [];
15
+
16
+ ngOnInit() {
17
+ this.model = [
18
+ {
19
+ label: 'MENU CHÍNH',
20
+ items: [{ label: 'Dashboard', icon: 'pi pi-fw pi-home', routerLink: ['/'] }]
21
+ },
22
+ {
23
+ label: 'MIAT KAKOTORA',
24
+ items: [
25
+ { label: 'Danh sách', icon: 'pi pi-fw pi-briefcase', class: 'rotated-icon', routerLink: ['/projects/ticket-list'] },
26
+ { label: 'Tạo phiếu', icon: 'pi pi-fw pi-briefcase', class: 'rotated-icon', routerLink: ['/projects/ticket-create'] }
27
+ ]
28
+ },
29
+ {
30
+ label: 'Tạo TICKET',
31
+ items: [
32
+ { label: 'Tạo Phiếu', icon: 'pi pi-fw pi-image', routerLink: ['projects/phieu-yeu-cau/tao-phieu-yeu-cau'] },
33
+ { label: 'Danh Sách Phiếu', icon: 'pi pi-fw pi-bars', routerLink: ['/uikit/menu'] },
34
+ { label: 'Message', icon: 'pi pi-fw pi-comment', routerLink: ['/uikit/message'] }
35
+ ]
36
+ },
37
+ {
38
+ label: 'Hệ THỐNG',
39
+ path: '/hierarchy',
40
+ items: [
41
+ {
42
+ label: 'Submenu 1',
43
+ icon: 'pi pi-fw pi-bookmark',
44
+ path: '/hierarchy/submenu_1',
45
+ items: [
46
+ {
47
+ label: 'Submenu 1.1',
48
+ icon: 'pi pi-fw pi-bookmark',
49
+ path: '/hierarchy/submenu_1/submenu_1_1',
50
+ items: [
51
+ { label: 'Submenu 1.1.1', icon: 'pi pi-fw pi-bookmark' },
52
+ { label: 'Submenu 1.1.2', icon: 'pi pi-fw pi-bookmark' },
53
+ { label: 'Submenu 1.1.3', icon: 'pi pi-fw pi-bookmark' }
54
+ ]
55
+ },
56
+ {
57
+ label: 'Submenu 1.2',
58
+ icon: 'pi pi-fw pi-bookmark',
59
+ path: '/hierarchy/submenu_1/submenu_1_2',
60
+ items: [{ label: 'Submenu 1.2.1', icon: 'pi pi-fw pi-bookmark' }]
61
+ }
62
+ ]
63
+ },
64
+ {
65
+ label: 'Submenu 2',
66
+ icon: 'pi pi-fw pi-bookmark',
67
+ path: '/hierarchy/submenu_2',
68
+ items: [
69
+ {
70
+ label: 'Submenu 2.1',
71
+ icon: 'pi pi-fw pi-bookmark',
72
+ path: '/hierarchy/submenu_2/submenu_2_1',
73
+ items: [
74
+ { label: 'Submenu 2.1.1', icon: 'pi pi-fw pi-bookmark' },
75
+ { label: 'Submenu 2.1.2', icon: 'pi pi-fw pi-bookmark' }
76
+ ]
77
+ },
78
+ {
79
+ label: 'Submenu 2.2',
80
+ icon: 'pi pi-fw pi-bookmark',
81
+ path: '/hierarchy/submenu_2/submenu_2_2',
82
+ items: [{ label: 'Submenu 2.2.1', icon: 'pi pi-fw pi-bookmark' }]
83
+ }
84
+ ]
85
+ }
86
+ ]
87
+ }
88
+ ];
89
+ }
90
+ }