@lukfel/ng-scaffold 20.0.10

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 (130) hide show
  1. package/.eslintrc.json +37 -0
  2. package/README.md +382 -0
  3. package/ng-package.json +8 -0
  4. package/package.json +28 -0
  5. package/src/lib/components/bottom-bar/bottom-bar.component.html +29 -0
  6. package/src/lib/components/bottom-bar/bottom-bar.component.scss +33 -0
  7. package/src/lib/components/bottom-bar/bottom-bar.component.spec.ts +24 -0
  8. package/src/lib/components/bottom-bar/bottom-bar.component.ts +31 -0
  9. package/src/lib/components/content-title-card/content-title-card.component.html +25 -0
  10. package/src/lib/components/content-title-card/content-title-card.component.scss +17 -0
  11. package/src/lib/components/content-title-card/content-title-card.component.spec.ts +108 -0
  12. package/src/lib/components/content-title-card/content-title-card.component.ts +24 -0
  13. package/src/lib/components/drawer/drawer.component.html +33 -0
  14. package/src/lib/components/drawer/drawer.component.scss +10 -0
  15. package/src/lib/components/drawer/drawer.component.spec.ts +52 -0
  16. package/src/lib/components/drawer/drawer.component.ts +30 -0
  17. package/src/lib/components/floating-button/floating-button.component.html +32 -0
  18. package/src/lib/components/floating-button/floating-button.component.scss +20 -0
  19. package/src/lib/components/floating-button/floating-button.component.spec.ts +84 -0
  20. package/src/lib/components/floating-button/floating-button.component.ts +57 -0
  21. package/src/lib/components/footer/footer.component.html +38 -0
  22. package/src/lib/components/footer/footer.component.scss +39 -0
  23. package/src/lib/components/footer/footer.component.spec.ts +118 -0
  24. package/src/lib/components/footer/footer.component.ts +14 -0
  25. package/src/lib/components/header/header.component.html +170 -0
  26. package/src/lib/components/header/header.component.scss +102 -0
  27. package/src/lib/components/header/header.component.spec.ts +134 -0
  28. package/src/lib/components/header/header.component.ts +53 -0
  29. package/src/lib/components/loading-overlay/loading-overlay.component.html +3 -0
  30. package/src/lib/components/loading-overlay/loading-overlay.component.scss +16 -0
  31. package/src/lib/components/loading-overlay/loading-overlay.component.spec.ts +24 -0
  32. package/src/lib/components/loading-overlay/loading-overlay.component.ts +10 -0
  33. package/src/lib/components/navbar/navbar.component.html +43 -0
  34. package/src/lib/components/navbar/navbar.component.scss +71 -0
  35. package/src/lib/components/navbar/navbar.component.spec.ts +43 -0
  36. package/src/lib/components/navbar/navbar.component.ts +35 -0
  37. package/src/lib/components/scaffold/scaffold.component.html +74 -0
  38. package/src/lib/components/scaffold/scaffold.component.scss +48 -0
  39. package/src/lib/components/scaffold/scaffold.component.spec.ts +119 -0
  40. package/src/lib/components/scaffold/scaffold.component.ts +191 -0
  41. package/src/lib/interceptors/loading.interceptor.ts +51 -0
  42. package/src/lib/models/bottom-bar-config.model.ts +8 -0
  43. package/src/lib/models/confirm-dialog-config.model.ts +6 -0
  44. package/src/lib/models/content-title-card-config.model.ts +6 -0
  45. package/src/lib/models/drawer-config.model.ts +6 -0
  46. package/src/lib/models/floating-button-config.model.ts +13 -0
  47. package/src/lib/models/footer-config.model.ts +10 -0
  48. package/src/lib/models/header-config.model.ts +26 -0
  49. package/src/lib/models/index.ts +15 -0
  50. package/src/lib/models/library-config.model.ts +4 -0
  51. package/src/lib/models/menu-button.model.ts +10 -0
  52. package/src/lib/models/navbar-config.model.ts +8 -0
  53. package/src/lib/models/navigation-link.model.ts +6 -0
  54. package/src/lib/models/placeholder-config.model.ts +7 -0
  55. package/src/lib/models/scaffold-config.model.ts +21 -0
  56. package/src/lib/models/seo-config.model.ts +6 -0
  57. package/src/lib/scaffold.module.ts +54 -0
  58. package/src/lib/services/breakpoint.service.spec.ts +15 -0
  59. package/src/lib/services/breakpoint.service.ts +16 -0
  60. package/src/lib/services/dialog.service.spec.ts +18 -0
  61. package/src/lib/services/dialog.service.ts +58 -0
  62. package/src/lib/services/index.ts +9 -0
  63. package/src/lib/services/local-storage.service.spec.ts +15 -0
  64. package/src/lib/services/local-storage.service.ts +125 -0
  65. package/src/lib/services/logger.service.spec.ts +15 -0
  66. package/src/lib/services/logger.service.ts +46 -0
  67. package/src/lib/services/router.service.spec.ts +15 -0
  68. package/src/lib/services/router.service.ts +91 -0
  69. package/src/lib/services/scaffold.service.spec.ts +15 -0
  70. package/src/lib/services/scaffold.service.ts +77 -0
  71. package/src/lib/services/seo.service.spec.ts +15 -0
  72. package/src/lib/services/seo.service.ts +75 -0
  73. package/src/lib/services/snackbar.service.spec.ts +18 -0
  74. package/src/lib/services/snackbar.service.ts +38 -0
  75. package/src/lib/services/theme.service.spec.ts +20 -0
  76. package/src/lib/services/theme.service.ts +71 -0
  77. package/src/lib/shared/components/dialogs/confirm-dialog/confirm-dialog.component.html +24 -0
  78. package/src/lib/shared/components/dialogs/confirm-dialog/confirm-dialog.component.scss +0 -0
  79. package/src/lib/shared/components/dialogs/confirm-dialog/confirm-dialog.component.spec.ts +85 -0
  80. package/src/lib/shared/components/dialogs/confirm-dialog/confirm-dialog.component.ts +14 -0
  81. package/src/lib/shared/components/file-upload/file-upload.component.html +21 -0
  82. package/src/lib/shared/components/file-upload/file-upload.component.scss +5 -0
  83. package/src/lib/shared/components/file-upload/file-upload.component.spec.ts +25 -0
  84. package/src/lib/shared/components/file-upload/file-upload.component.ts +43 -0
  85. package/src/lib/shared/components/icon/icon.component.html +17 -0
  86. package/src/lib/shared/components/icon/icon.component.scss +9 -0
  87. package/src/lib/shared/components/icon/icon.component.spec.ts +22 -0
  88. package/src/lib/shared/components/icon/icon.component.ts +17 -0
  89. package/src/lib/shared/components/input/input.component.html +38 -0
  90. package/src/lib/shared/components/input/input.component.scss +31 -0
  91. package/src/lib/shared/components/input/input.component.spec.ts +62 -0
  92. package/src/lib/shared/components/input/input.component.ts +72 -0
  93. package/src/lib/shared/components/placeholder/placeholder.component.html +21 -0
  94. package/src/lib/shared/components/placeholder/placeholder.component.scss +30 -0
  95. package/src/lib/shared/components/placeholder/placeholder.component.spec.ts +24 -0
  96. package/src/lib/shared/components/placeholder/placeholder.component.ts +16 -0
  97. package/src/lib/shared/modules/material.module.ts +77 -0
  98. package/src/lib/shared/shared.module.ts +18 -0
  99. package/src/public-api.ts +16 -0
  100. package/styles/_classes.scss +34 -0
  101. package/styles/_theme.scss +97 -0
  102. package/styles/_variables.scss +50 -0
  103. package/styles/fonts/icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 +0 -0
  104. package/styles/fonts/icons/gok-H7zzDkdnRel8-DQ6KAXJ69wP1tGnf4ZGhUce.woff2 +0 -0
  105. package/styles/fonts/material-icons.scss +48 -0
  106. package/styles/fonts/roboto/roboto-v30-latin-100.woff +0 -0
  107. package/styles/fonts/roboto/roboto-v30-latin-100.woff2 +0 -0
  108. package/styles/fonts/roboto/roboto-v30-latin-100italic.woff +0 -0
  109. package/styles/fonts/roboto/roboto-v30-latin-100italic.woff2 +0 -0
  110. package/styles/fonts/roboto/roboto-v30-latin-300.woff +0 -0
  111. package/styles/fonts/roboto/roboto-v30-latin-300.woff2 +0 -0
  112. package/styles/fonts/roboto/roboto-v30-latin-300italic.woff +0 -0
  113. package/styles/fonts/roboto/roboto-v30-latin-300italic.woff2 +0 -0
  114. package/styles/fonts/roboto/roboto-v30-latin-500.woff +0 -0
  115. package/styles/fonts/roboto/roboto-v30-latin-500.woff2 +0 -0
  116. package/styles/fonts/roboto/roboto-v30-latin-500italic.woff +0 -0
  117. package/styles/fonts/roboto/roboto-v30-latin-500italic.woff2 +0 -0
  118. package/styles/fonts/roboto/roboto-v30-latin-700.woff +0 -0
  119. package/styles/fonts/roboto/roboto-v30-latin-700.woff2 +0 -0
  120. package/styles/fonts/roboto/roboto-v30-latin-700italic.woff +0 -0
  121. package/styles/fonts/roboto/roboto-v30-latin-700italic.woff2 +0 -0
  122. package/styles/fonts/roboto/roboto-v30-latin-italic.woff +0 -0
  123. package/styles/fonts/roboto/roboto-v30-latin-italic.woff2 +0 -0
  124. package/styles/fonts/roboto/roboto-v30-latin-regular.woff +0 -0
  125. package/styles/fonts/roboto/roboto-v30-latin-regular.woff2 +0 -0
  126. package/styles/fonts/roboto-font.scss +109 -0
  127. package/styles/style.scss +54 -0
  128. package/tsconfig.lib.json +14 -0
  129. package/tsconfig.lib.prod.json +10 -0
  130. package/tsconfig.spec.json +14 -0
package/.eslintrc.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "extends": "../../.eslintrc.json",
3
+ "ignorePatterns": [
4
+ "!**/*"
5
+ ],
6
+ "overrides": [
7
+ {
8
+ "files": [
9
+ "*.ts"
10
+ ],
11
+ "rules": {
12
+ "@angular-eslint/directive-selector": [
13
+ "error",
14
+ {
15
+ "type": "attribute",
16
+ "prefix": "lf",
17
+ "style": "camelCase"
18
+ }
19
+ ],
20
+ "@angular-eslint/component-selector": [
21
+ "error",
22
+ {
23
+ "type": "element",
24
+ "prefix": "lf",
25
+ "style": "kebab-case"
26
+ }
27
+ ]
28
+ }
29
+ },
30
+ {
31
+ "files": [
32
+ "*.html"
33
+ ],
34
+ "rules": {}
35
+ }
36
+ ]
37
+ }
package/README.md ADDED
@@ -0,0 +1,382 @@
1
+ # Documentation
2
+ ## Introduction
3
+
4
+ This Angular library provides a foundational scaffold for modern web and mobile applications. It includes essential UI elements such as a header, sidebar, drawer, footer, floating button, and built-in services for theme switching, snackbar notifications, dialog management, and breakpoint detection. Simply wrap your `router-outlet` with the `lf-scaffold` element and configure the `ScaffoldConfig` within the `ScaffoldService`.
5
+
6
+ - **NPM**: [@lukfel/ng-scaffold](https://www.npmjs.com/package/@lukfel/ng-scaffold)
7
+ - **Demo**: [lukfel.github.io/ng-scaffold](https://lukfel.github.io/ng-scaffold)
8
+ - **Examples**: [Create a Tournament](https://www.create-a-tournament.com), [What a Waste](https://www.what-a-waste.at), [Uglygotchi](https://www.uglygotchi.at)
9
+
10
+
11
+
12
+
13
+ ## Installation
14
+ Install the package using npm:
15
+
16
+ ```sh
17
+ npm install @lukfel/ng-scaffold
18
+ ```
19
+
20
+
21
+
22
+
23
+ ## Module
24
+ Import the `ScaffoldModule` into your `app.module.ts` file.
25
+
26
+ * **Note:** (Optional) The library includes a built-in logging service called `Logger`, which logs library deugging events when a `ScaffoldLibraryConfig` is provided and `debugging` is set to `true`. Logging is automatically disabled in production mode when `prodution` is set to `true`.
27
+
28
+ ```ts
29
+ import { ScaffoldModule } from '@lukfel/ng-scaffold';
30
+ import { isDevMode } from '@angular/core';
31
+
32
+ @NgModule({
33
+ ...
34
+ imports: [
35
+ ScaffoldModule.forRoot({ production: !isDevMode(), debugging: isDevMode() }), // Omit .forRoot(...) if logging is not required
36
+ ]
37
+ })
38
+ export class AppModule { }
39
+ ```
40
+
41
+
42
+
43
+
44
+ ## Styling
45
+ Import the styles in your `styles.scss` and apply a default theme.
46
+
47
+ * **Note:** The library’s styles include Material icons and Roboto font styles.
48
+
49
+ ```scss
50
+ @use "@lukfel/ng-scaffold/styles" as lf;
51
+ @include lf.scaffold-theme(); // include a default theme
52
+ ```
53
+
54
+ ### Custom Themes (Optional)
55
+ To customize the default theme, define a new theme map specifying `primary`, `accent`, and `warn` colors using Material palettes. Enabling the `dark` option applies a dark theme. Pass your custom theme to `lf.scaffold-theme($my-theme)`.
56
+
57
+ ```scss
58
+ @use "@lukfel/ng-scaffold/styles" as lf;
59
+ @use '@angular/material' as mat;
60
+
61
+ $my-theme: (
62
+ primary: mat.define-palette(mat.$pink-palette),
63
+ accent: mat.define-palette(mat.$blue-palette),
64
+ warn: mat.define-palette(mat.$red-palette),
65
+ dark: false
66
+ );
67
+
68
+ @include lf.scaffold-theme($my-theme);
69
+ ```
70
+
71
+ ### Multiple Themes (Optional)
72
+ To switch between multiple themes dynamically, define additional themes using `lf.scaffold-colors($theme, 'theme-class')`, then apply the class to the `<body class="theme-class">` tag.
73
+
74
+ * **Note:** The `ThemeService` allows dynamic theme switching.
75
+
76
+ ```scss
77
+ @use "@lukfel/ng-scaffold/styles" as lf;
78
+ @use '@angular/material' as mat;
79
+
80
+ $my-theme: (
81
+ primary: mat.define-palette(mat.$pink-palette),
82
+ accent: mat.define-palette(mat.$blue-palette),
83
+ warn: mat.define-palette(mat.$red-palette),
84
+ dark: false
85
+ );
86
+
87
+ $my-theme2: (
88
+ primary: mat.define-palette(mat.$purple-palette),
89
+ accent: mat.define-palette(mat.$amber-palette),
90
+ dark: false
91
+ );
92
+
93
+ @include lf.scaffold-theme($my-theme); // Set the primary theme with lf.scaffold-theme(...)
94
+ @include lf.scaffold-colors($my-theme2, 'my-theme2'); // Set additional themes with lf.scaffold-colors(...)
95
+ ```
96
+
97
+ ### Custom Typography (Optional)
98
+ To change the default typography from Roboto, pass an additional parameter ``font-family`` in the theme map.
99
+
100
+ * **Note:** Don't forget to also import and set the font-family in the styles.
101
+
102
+ ```scss
103
+ @use "@lukfel/ng-scaffold/styles" as lf;
104
+ @use '@angular/material' as mat;
105
+
106
+ $my-theme: (
107
+ primary: mat.define-palette(mat.$pink-palette),
108
+ accent: mat.define-palette(mat.$blue-palette),
109
+ warn: mat.define-palette(mat.$red-palette),
110
+ dark: false,
111
+ font-family: 'Comic Sans'
112
+ );
113
+
114
+ @include lf.scaffold-theme($my-theme);
115
+
116
+ body {
117
+ font-family: "Comic Sans MS" !important;
118
+ }
119
+ ```
120
+
121
+
122
+
123
+
124
+ ## Template
125
+ Wrap your application’s content inside the `lf-scaffold` component in `app.component.html`.
126
+
127
+ ```html
128
+ <lf-scaffold>
129
+ <!-- (Optional) drawer content shows inside the left drawer if enabled -->
130
+ <ng-container drawerContent></ng-container>
131
+ <router-outlet></router-outlet>
132
+ </lf-scaffold>
133
+ ```
134
+
135
+
136
+
137
+
138
+ ## Configuration
139
+ Import the `ScaffoldService` in `app.component.ts` to manage the `ScaffoldConfig` settings.
140
+
141
+ ```ts
142
+ import { ScaffoldService } from '@lukfel/ng-scaffold';
143
+
144
+ export class AppComponent {
145
+ constructor(private scaffoldService: ScaffoldService) {}
146
+ }
147
+ ```
148
+
149
+ ### Update Configuration
150
+ Define the `ScaffoldConfig` in `app.component.ts` and update the `scaffoldConfig` property in `ScaffoldService`.
151
+
152
+ * **Notes:**
153
+ * If a sub-configuration (e.g., `headerConfig`) is missing or does not have `enable: true`, the corresponding UI element will not be displayed.
154
+ * Refer to the demo project for full configuration details.
155
+
156
+ ```ts
157
+ import { ScaffoldService, ScaffoldConfig } from '@lukfel/ng-scaffold';
158
+
159
+ export class AppComponent {
160
+
161
+ public scaffoldConfig: ScaffoldConfig = {
162
+ scrollPositionRestoration: true,
163
+ headerConfig: { enable: true, title: 'Scaffold', subtitle: 'by Lukas Felbinger' },
164
+ navbarConfig: { enable: true },
165
+ footerConfig: { enable: true, copyright: '© Lukas Felbinger 2023' },
166
+ floatingButtonConfig: { enable: true }
167
+ };
168
+
169
+ constructor(private scaffoldService: ScaffoldService) {
170
+ this.scaffoldService.scaffoldConfig = this.scaffoldConfig;
171
+ }
172
+ }
173
+ ```
174
+
175
+
176
+
177
+
178
+ ## Events
179
+ There are two ways to listen to scaffold user events (button clicks, input changes, ...):
180
+
181
+ ### Option 1 (Recommended) – Subscribe to Observables
182
+ Subscribe to the event Observables and listen to changes
183
+ ```ts
184
+ constructor(private scaffoldService: ScaffoldService, private router: Router) {
185
+ // Listen to click events (header menu and navbar buttons - click)
186
+ this.scaffoldService.buttonClickEventValue$.subscribe((id: string) => {
187
+ this.router.navigate([id]);
188
+ });
189
+
190
+ // Listen to header input change events (header input field - change)
191
+ this.scaffoldService.headerInputChangeValue$.subscribe((value: string) => {
192
+ ...
193
+ });
194
+ }
195
+ ```
196
+
197
+ ### Option 2 – Use Output Events
198
+ Specify the needed output events and call custom methods
199
+ ```html
200
+ <lf-scaffold
201
+ (headerButtonClickEvent)="headerButtonClickEvent($event)"
202
+ (headerInputSubmitEvent)="headerInputSubmitEvent($event)"
203
+ (headerInputChangeEvent)="headerInputChangeEvent($event)"
204
+ (navbarButtonClickEvent)="navbarButtonClickEvent($event)">
205
+ <router-outlet></router-outlet>
206
+ </lf-scaffold>
207
+ ```
208
+
209
+ ```ts
210
+ // Listen to header click events (header menu buttons - click)
211
+ public headerButtonClickEvent(id: string): void {
212
+ this.router.navigate([id]);
213
+ }
214
+
215
+ // Listen to header input submit events (header input field - submit)
216
+ public headerInputSubmitEvent(value: string): void {
217
+ ...
218
+ }
219
+
220
+ // Listen to header input change events (header input field - change)
221
+ public headerInputChangeEvent(value: string): void {
222
+ ...
223
+ }
224
+
225
+ // Listen to navbar click events (navbar menu buttons - click)
226
+ public navbarButtonClickEvent(id: string): void {
227
+ this.router.navigate([id]);
228
+ }
229
+ ```
230
+
231
+
232
+
233
+
234
+ ## Additional Services
235
+ This library includes several utility services:
236
+
237
+ - **`Logger`** – Development-only logging
238
+ - **`SnackbarService`** – Display snackbar notifications
239
+ - **`DialogService`** – Display custom dialogs
240
+ - **`BreakpointService`** – Detect screen breakpoints
241
+ - **`ThemeService`** – Manage themes dynamically
242
+ - **`RouterService`** – Track route changes and retreive route history
243
+ - **`SeoService`** – Manage meta tags
244
+ - **`LocalStorageService`** – Handle local storage
245
+
246
+ ### Logger
247
+ Logs internal library information if `debugging` is `true` and hides application logs during production if `production` is `true`.
248
+ * **Note:** `ScaffoldLibraryConfig` must be set during initialization ``ScaffoldModule.forRoot( { production: !isDevMode(), debugging: isDevMode() } )``
249
+
250
+ ```ts
251
+ import { Logger } from '@lukfel/ng-scaffold';
252
+
253
+ export class AppComponent {
254
+
255
+ constructor(private logger: Logger) {}
256
+
257
+ // Generic api call with logging
258
+ public apiCallWithLogging(): void {
259
+ this.apiService.apiCall().then(result => {
260
+ this.logger.log(result);
261
+ }).catch(error => {
262
+ this.logger.error(error);
263
+ });
264
+ }
265
+ }
266
+ ```
267
+
268
+ ### SnackbarService
269
+ Provides basic methods to display simple snackbar notifications with or without actions.
270
+
271
+ ```ts
272
+ import { SnackbarService } from '@lukfel/ng-scaffold';
273
+
274
+ export class AppComponent {
275
+
276
+ constructor(private snackbarService: SnackbarService) {}
277
+
278
+ // Generic api call with snackbar response
279
+ public apiCallWithSnackbarResponse(): void {
280
+ this.apiService.apiCall().then(result => {
281
+ this.snackbarService.openSnackbar('Call was successful');
282
+ }).catch(error => {
283
+ this.snackbarService.openSnackbar('Call was not successful');
284
+ });
285
+ }
286
+ }
287
+ ```
288
+
289
+ ### DialogService
290
+ Includes a basic confirmation dialog thar returns a `Promise`. Use the method `openCustomDialog` to pass your own dialog template and config.
291
+
292
+ ```ts
293
+ import { DialogService } from '@lukfel/ng-scaffold';
294
+
295
+ export class AppComponent {
296
+
297
+ constructor(private dialogService: DialogService) {}
298
+
299
+ // Generic api call with a subsequent confirmation dialog
300
+ public apiCallWithDialogConfirmation(): void {
301
+ this.dialogService.openConfirmDialog('Do you really want to make this api call?').then(response => {
302
+ // If the user confirmed the dialog, go through with the api call
303
+ if(response === true) {
304
+ this.apiService.apiCall().then(result => {
305
+ ...
306
+ }).catch(error => {
307
+ ...
308
+ });
309
+ }
310
+ });
311
+ }
312
+ }
313
+ ```
314
+
315
+ ### BreakpointService
316
+ Allows you to subscribe to breakpoint changes.
317
+
318
+ ```ts
319
+ import { BreakpointService } from '@lukfel/ng-scaffold';
320
+
321
+ export class AppComponent {
322
+
323
+ constructor(private breakpointService: BreakpointService) {
324
+ this.breakpointService.breakpoint$.subscribe((result: BreakpointState) => {
325
+ // Check which breakpoint is active
326
+ if (result.breakpoints[Breakpoints.XSmall]) {
327
+ ...
328
+ } else if (result.breakpoints[Breakpoints.Small]) {
329
+ ...
330
+ } else if (result.breakpoints[Breakpoints.Medium]) {
331
+ ...
332
+ } else if (result.breakpoints[Breakpoints.Large]) {
333
+ ...
334
+ }
335
+ });
336
+ }
337
+ }
338
+ ```
339
+
340
+ ### ThemeService
341
+ Dynamically change between your defined themes.
342
+
343
+ * **Note:** The theme must be defined and included in your styles [see multiple themes](#multiple-themes-optional)
344
+
345
+ ```ts
346
+ import { ThemeService } from '@lukfel/ng-scaffold';
347
+
348
+ export class AppComponent {
349
+
350
+ constructor(private themeService: ThemeService) {
351
+ this.themeService.setTheme('my-theme2', true); // the second parameter allows to persists the theme in the LocalStorage (using the built in LocalStorageService)
352
+ }
353
+ }
354
+ ```
355
+
356
+
357
+
358
+
359
+ ## Interceptors
360
+ Intercept HTTP Calls and automatically show a loading spinner.
361
+
362
+ * **Note:** The loading spinner can also be manually shown by udpating the value for `scaffoldConfig.loading` in the `ScaffoldService`
363
+
364
+ ```ts
365
+ import { ScaffoldModule } from '@lukfel/ng-scaffold';
366
+ import { isDevMode } from '@angular/core';
367
+
368
+ @NgModule({
369
+ ...
370
+ imports: [
371
+ ScaffoldModule.forRoot({ production: !isDevMode(), debugging: isDevMode() }), // Omit .forRoot(...) if logging is not required
372
+ ],
373
+ providers: [
374
+ {
375
+ provide: HTTP_INTERCEPTORS,
376
+ useClass: LoadingInterceptor,
377
+ multi: true
378
+ }
379
+ ]
380
+ })
381
+ export class AppModule { }
382
+ ```
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3
+ "dest": "../../dist/ng-scaffold",
4
+ "lib": {
5
+ "entryFile": "src/public-api.ts"
6
+ },
7
+ "assets": ["./styles/*.scss","./styles/**/*"]
8
+ }
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@lukfel/ng-scaffold",
3
+ "version": "20.0.10",
4
+ "description": "This Angular library provides a basic UI scaffold and services for modern web and mobile apps",
5
+ "license": "MIT",
6
+ "author": {
7
+ "name": "Lukas Felbinger",
8
+ "url": "https://www.lukasfelbinger.at"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/lukfel/ng-scaffold"
13
+ },
14
+ "peerDependencies": {
15
+ "@angular/common": "^20.0.5",
16
+ "@angular/core": "^20.0.5",
17
+ "@angular/material": "^20.0.5"
18
+ },
19
+ "dependencies": {
20
+ "tslib": "^2.3.0"
21
+ },
22
+ "exports": {
23
+ "./styles": {
24
+ "sass": "./styles/style.scss"
25
+ }
26
+ },
27
+ "sideEffects": false
28
+ }
@@ -0,0 +1,29 @@
1
+ @if (bottomBarConfig && bottomBarConfig.enable) {
2
+ <div
3
+ class="lf-bottom-bar px-4"
4
+ [ngClass]="bottomBarConfig.class"
5
+ [class.lf-bottom-bar-show-navbar]="!isMobile && navbarEnabled"
6
+ [class.lf-bottom-bar-show-navbar-mobile]="isMobile && navbarEnabled">
7
+ <button mat-icon-button (click)="closeClicked()">
8
+ <mat-icon>close</mat-icon>
9
+ </button>
10
+ @if (bottomBarConfig.message) {
11
+ <span class="ml-2">{{ bottomBarConfig.message }}</span>
12
+ }
13
+ @if (bottomBarConfig.actions) {
14
+ <div class="lf-bottom-bar-actions ml-4">
15
+ @for (action of bottomBarConfig.actions; track action) {
16
+ <button
17
+ mat-button
18
+ color="accent"
19
+ class="lf-bottom-bar-action ml-2"
20
+ [ngClass]="action.class"
21
+ (click)="actionClicked(action.id)"
22
+ [matTooltip]="action.tooltip!">
23
+ {{ action.label }}
24
+ </button>
25
+ }
26
+ </div>
27
+ }
28
+ </div>
29
+ }
@@ -0,0 +1,33 @@
1
+ @use '../../../../styles/variables' as *;
2
+
3
+ .lf-bottom-bar {
4
+ transition: bottom $transition;
5
+ transition: left $transition;
6
+ z-index: 101;
7
+ position: fixed;
8
+ left: 0;
9
+ bottom: 0;
10
+ right: 0;
11
+ height: $bottom-bar-height;
12
+ display: flex;
13
+ align-items: center;
14
+ box-sizing: border-box;
15
+ background-color: var(--color-accent);
16
+ color: white;
17
+
18
+ &.lf-bottom-bar-show-navbar-mobile {
19
+ bottom: calc($navbar-height-mobile + (2 * $navbar-padding)) !important;
20
+ }
21
+
22
+ &.lf-bottom-bar-show-navbar {
23
+ left: calc($navbar-width + (2 * $navbar-padding)) !important;;
24
+ }
25
+
26
+ .lf-bottom-bar-actions {
27
+ .lf-bottom-bar-action {
28
+ color: var(--color-accent) !important;
29
+ background-color: white !important;
30
+ }
31
+ }
32
+ }
33
+
@@ -0,0 +1,24 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+ import { SharedModule } from '../../shared/shared.module';
3
+ import { BottomBarComponent } from './bottom-bar.component';
4
+
5
+ describe('BottomBarComponent', () => {
6
+ let component: BottomBarComponent;
7
+ let fixture: ComponentFixture<BottomBarComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ declarations: [BottomBarComponent],
12
+ imports: [SharedModule]
13
+ })
14
+ .compileComponents();
15
+
16
+ fixture = TestBed.createComponent(BottomBarComponent);
17
+ component = fixture.componentInstance;
18
+ fixture.detectChanges();
19
+ });
20
+
21
+ it('should create', () => {
22
+ expect(component).toBeTruthy();
23
+ });
24
+ });
@@ -0,0 +1,31 @@
1
+ import { Component, EventEmitter, Input, Output } from '@angular/core';
2
+ import { BottomBarConfig } from '../../models';
3
+
4
+ @Component({
5
+ selector: 'lf-bottom-bar',
6
+ templateUrl: './bottom-bar.component.html',
7
+ styleUrls: ['./bottom-bar.component.scss'],
8
+ standalone: false
9
+ })
10
+ export class BottomBarComponent {
11
+
12
+ @Input() public bottomBarConfig: BottomBarConfig | null = null;
13
+ @Input() public isMobile: boolean = false;
14
+ @Input() public navbarEnabled: boolean = false;
15
+
16
+ @Output() public bottomBarCloseClickEvent = new EventEmitter<string>();
17
+ @Output() public bottomBarButtonClickEvent = new EventEmitter<string>();
18
+
19
+ public actionClicked(id?: string): void {
20
+ if (!id) {
21
+ return;
22
+ }
23
+
24
+ this.bottomBarButtonClickEvent.emit(id);
25
+ }
26
+
27
+ public closeClicked(): void {
28
+ this.bottomBarCloseClickEvent.emit('bottom-bar_close');
29
+ }
30
+
31
+ }
@@ -0,0 +1,25 @@
1
+ @if (contentTitleCardConfig && contentTitleCardConfig.enable) {
2
+ <mat-card
3
+ class="lf-content-title-card mat-elevation-z2 px-4"
4
+ [ngClass]="contentTitleCardConfig.class">
5
+ <!-- back button -->
6
+ @if (contentTitleCardConfig.showBackButton && routeHistory.length > 1) {
7
+ <button mat-icon-button color="accent" (click)="backButtonClicked()">
8
+ <mat-icon>arrow_back_ios</mat-icon>
9
+ </button>
10
+ }
11
+ <!-- spacer -->
12
+ <div style="flex: 1 1 auto"></div>
13
+ <!-- label -->
14
+ <span class="lf-content-title-card-label">
15
+ {{ contentTitleCardConfig.label || "" }}
16
+ </span>
17
+ <!-- spacer -->
18
+ <div style="flex: 1 1 auto"></div>
19
+ <!-- empty button spacer -->
20
+ <div
21
+ [style.width]="
22
+ contentTitleCardConfig.showBackButton && routeHistory.length > 1 ? '48px' : '0px'
23
+ "></div>
24
+ </mat-card>
25
+ }
@@ -0,0 +1,17 @@
1
+ @use '../../../../styles/variables' as *;
2
+
3
+ .lf-content-title-card {
4
+ z-index: $content-title-card-z-index;
5
+ height: $content-title-card-height;
6
+ display: flex;
7
+ flex-flow: row nowrap;
8
+ align-items: center;
9
+ border-radius: 0;
10
+
11
+ .lf-content-title-card-label {
12
+ font-size: $content-title-card-labe-font-size;
13
+ white-space: nowrap;
14
+ overflow: hidden;
15
+ text-overflow: ellipsis;
16
+ }
17
+ }