@doug-williamson/ng-rhombus 1.0.8 → 2.0.0-beta.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doug-williamson/ng-rhombus",
3
- "version": "1.0.8",
3
+ "version": "2.0.0-beta.1",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.0.0",
6
6
  "@angular/core": "^21.0.0",
@@ -0,0 +1,20 @@
1
+ @use '@angular/material' as mat;
2
+ @use './theme-colors' as colors;
3
+
4
+ @mixin theme($primary: colors.$primary-palette,
5
+ $tertiary: colors.$tertiary-palette,
6
+ $typography: Roboto,
7
+ $density: 0) {
8
+ html {
9
+ @include mat.theme((color: (primary: $primary,
10
+ tertiary: $tertiary,
11
+ ),
12
+ typography: $typography,
13
+ density: $density,
14
+ ));
15
+ }
16
+ }
17
+
18
+ @mixin high-contrast-overrides($theme-type) {
19
+ @include colors.high-contrast-overrides($theme-type);
20
+ }
@@ -0,0 +1,199 @@
1
+ // This file was generated by running 'ng generate @angular/material:theme-color'.
2
+ // Proceed with caution if making changes to this file.
3
+
4
+ @use 'sass:map';
5
+ @use '@angular/material' as mat;
6
+
7
+ // Note: Color palettes are generated from primary: #536CCF, secondary: #31CC7C
8
+ $_palettes: (
9
+ primary: (0: #000000,
10
+ 10: #001453,
11
+ 20: #002584,
12
+ 25: #103194,
13
+ 30: #213ea0,
14
+ 35: #2f4aac,
15
+ 40: #3d57b9,
16
+ 50: #5770d4,
17
+ 60: #728af0,
18
+ 70: #92a6ff,
19
+ 80: #b8c4ff,
20
+ 90: #dde1ff,
21
+ 95: #efefff,
22
+ 98: #fbf8ff,
23
+ 99: #fefbff,
24
+ 100: #ffffff,
25
+ ),
26
+ secondary: (0: #000000,
27
+ 10: #00210f,
28
+ 20: #00391d,
29
+ 25: #004525,
30
+ 30: #00522c,
31
+ 35: #005f35,
32
+ 40: #006d3d,
33
+ 50: #00894e,
34
+ 60: #00a660,
35
+ 70: #22c374,
36
+ 80: #4ce08d,
37
+ 90: #6cfda7,
38
+ 95: #c2ffd2,
39
+ 98: #e9ffeb,
40
+ 99: #f5fff4,
41
+ 100: #ffffff,
42
+ ),
43
+ tertiary: (0: #000000,
44
+ 10: #37003c,
45
+ 20: #57065e,
46
+ 25: #64186a,
47
+ 30: #722577,
48
+ 35: #7f3283,
49
+ 40: #8d3f90,
50
+ 50: #aa58ab,
51
+ 60: #c672c7,
52
+ 70: #e48ce3,
53
+ 80: #ffa9fd,
54
+ 90: #ffd6f9,
55
+ 95: #ffebf9,
56
+ 98: #fff7fa,
57
+ 99: #fffbff,
58
+ 100: #ffffff,
59
+ ),
60
+ neutral: (0: #000000,
61
+ 10: #1a1b21,
62
+ 20: #2f3037,
63
+ 25: #3a3b42,
64
+ 30: #46464d,
65
+ 35: #515259,
66
+ 40: #5d5e65,
67
+ 50: #76767e,
68
+ 60: #909098,
69
+ 70: #abaab3,
70
+ 80: #c7c5ce,
71
+ 90: #e3e1ea,
72
+ 95: #f1f0f9,
73
+ 98: #fbf8ff,
74
+ 99: #fefbff,
75
+ 100: #ffffff,
76
+ 4: #0d0e14,
77
+ 6: #121319,
78
+ 12: #1e1f26,
79
+ 17: #292a30,
80
+ 22: #34343b,
81
+ 24: #383940,
82
+ 87: #dad9e2,
83
+ 92: #e9e7f0,
84
+ 94: #eeedf6,
85
+ 96: #f4f2fc,
86
+ ),
87
+ neutral-variant: (0: #000000,
88
+ 10: #191b26,
89
+ 20: #2e303b,
90
+ 25: #393b47,
91
+ 30: #444652,
92
+ 35: #50525e,
93
+ 40: #5c5e6a,
94
+ 50: #757684,
95
+ 60: #8f909e,
96
+ 70: #a9aab9,
97
+ 80: #c5c5d4,
98
+ 90: #e1e1f1,
99
+ 95: #efefff,
100
+ 98: #fbf8ff,
101
+ 99: #fefbff,
102
+ 100: #ffffff,
103
+ ),
104
+ error: (0: #000000,
105
+ 10: #410002,
106
+ 20: #690005,
107
+ 25: #7e0007,
108
+ 30: #93000a,
109
+ 35: #a80710,
110
+ 40: #ba1a1a,
111
+ 50: #de3730,
112
+ 60: #ff5449,
113
+ 70: #ff897d,
114
+ 80: #ffb4ab,
115
+ 90: #ffdad6,
116
+ 95: #ffedea,
117
+ 98: #fff8f7,
118
+ 99: #fffbff,
119
+ 100: #ffffff,
120
+ ),
121
+ );
122
+
123
+ $_rest: (
124
+ secondary: map.get($_palettes, secondary),
125
+ neutral: map.get($_palettes, neutral),
126
+ neutral-variant: map.get($_palettes, neutral-variant),
127
+ error: map.get($_palettes, error),
128
+ );
129
+
130
+ $primary-palette: map.merge(map.get($_palettes, primary), $_rest);
131
+ $tertiary-palette: map.merge(map.get($_palettes, tertiary), $_rest);
132
+
133
+ @function _high-contrast-value($light, $dark, $theme-type) {
134
+ @if ($theme-type ==light) {
135
+ @return $light;
136
+ }
137
+
138
+ @if ($theme-type ==dark) {
139
+ @return $dark;
140
+ }
141
+
142
+ @if ($theme-type ==color-scheme) {
143
+ @return light-dark(#{$light}, #{$dark});
144
+ }
145
+
146
+ @error 'Unknown theme-type #{$theme-type}. Expected light, dark, or color-scheme';
147
+ }
148
+
149
+ @mixin high-contrast-overrides($theme-type) {
150
+ @include mat.theme-overrides((primary: _high-contrast-value(#00227a, #eeefff, $theme-type),
151
+ on-primary: _high-contrast-value(#ffffff, #000000, $theme-type),
152
+ primary-container: _high-contrast-value(#2440a2, #b2c0ff, $theme-type),
153
+ on-primary-container: _high-contrast-value(#ffffff, #00072d, $theme-type),
154
+ inverse-primary: _high-contrast-value(#b8c4ff, #223fa1, $theme-type),
155
+ primary-fixed: _high-contrast-value(#2440a2, #dde1ff, $theme-type),
156
+ primary-fixed-dim: _high-contrast-value(#002789, #b8c4ff, $theme-type),
157
+ on-primary-fixed: _high-contrast-value(#ffffff, #000000, $theme-type),
158
+ on-primary-fixed-variant: _high-contrast-value(#ffffff, #000b3b, $theme-type),
159
+ secondary: _high-contrast-value(#00341a, #beffcf, $theme-type),
160
+ on-secondary: _high-contrast-value(#ffffff, #000000, $theme-type),
161
+ secondary-container: _high-contrast-value(#00552e, #47dc8a, $theme-type),
162
+ on-secondary-container: _high-contrast-value(#ffffff, #000f05, $theme-type),
163
+ secondary-fixed: _high-contrast-value(#00552e, #6cfda7, $theme-type),
164
+ secondary-fixed-dim: _high-contrast-value(#003b1f, #4ce08d, $theme-type),
165
+ on-secondary-fixed: _high-contrast-value(#ffffff, #000000, $theme-type),
166
+ on-secondary-fixed-variant: _high-contrast-value(#ffffff, #001508, $theme-type),
167
+ tertiary: _high-contrast-value(#520059, #ffeaf9, $theme-type),
168
+ on-tertiary: _high-contrast-value(#ffffff, #000000, $theme-type),
169
+ tertiary-container: _high-contrast-value(#752879, #fea3fc, $theme-type),
170
+ on-tertiary-container: _high-contrast-value(#ffffff, #1c001f, $theme-type),
171
+ tertiary-fixed: _high-contrast-value(#752879, #ffd6f9, $theme-type),
172
+ tertiary-fixed-dim: _high-contrast-value(#5a0a61, #ffa9fd, $theme-type),
173
+ on-tertiary-fixed: _high-contrast-value(#ffffff, #000000, $theme-type),
174
+ on-tertiary-fixed-variant: _high-contrast-value(#ffffff, #250029, $theme-type),
175
+ background: _high-contrast-value(#fbf8ff, #121319, $theme-type),
176
+ on-background: _high-contrast-value(#1a1b21, #e3e1ea, $theme-type),
177
+ surface: _high-contrast-value(#fbf8ff, #121319, $theme-type),
178
+ surface-dim: _high-contrast-value(#b9b8c0, #121319, $theme-type),
179
+ surface-bright: _high-contrast-value(#fbf8ff, #4f4f57, $theme-type),
180
+ surface-container-lowest: _high-contrast-value(#ffffff, #000000, $theme-type),
181
+ surface-container: _high-contrast-value(#e3e1ea, #2f3037, $theme-type),
182
+ surface-container-high: _high-contrast-value(#d5d3dc, #3a3b42, $theme-type),
183
+ surface-container-highest: _high-contrast-value(#c7c5ce, #46464d, $theme-type),
184
+ on-surface: _high-contrast-value(#000000, #ffffff, $theme-type),
185
+ shadow: _high-contrast-value(#000000, #000000, $theme-type),
186
+ scrim: _high-contrast-value(#000000, #000000, $theme-type),
187
+ surface-tint: _high-contrast-value(#3d57b9, #b8c4ff, $theme-type),
188
+ inverse-surface: _high-contrast-value(#2f3037, #e3e1ea, $theme-type),
189
+ inverse-on-surface: _high-contrast-value(#ffffff, #000000, $theme-type),
190
+ outline: _high-contrast-value(#292c37, #efeffe, $theme-type),
191
+ outline-variant: _high-contrast-value(#474855, #c1c1d0, $theme-type),
192
+ error: _high-contrast-value(#600004, #ffece9, $theme-type),
193
+ on-error: _high-contrast-value(#ffffff, #000000, $theme-type),
194
+ error-container: _high-contrast-value(#98000a, #ffaea4, $theme-type),
195
+ on-error-container: _high-contrast-value(#ffffff, #220001, $theme-type),
196
+ surface-variant: _high-contrast-value(#e1e1f1, #444652, $theme-type),
197
+ on-surface-variant: _high-contrast-value(#000000, #ffffff, $theme-type),
198
+ ));
199
+ }
@@ -1,17 +1,13 @@
1
1
  import * as _doug_williamson_ng_rhombus from '@doug-williamson/ng-rhombus';
2
2
  import * as i0 from '@angular/core';
3
- import { OnInit, OnDestroy, EventEmitter, ElementRef } from '@angular/core';
3
+ import { OnInit, OnDestroy, EventEmitter, InjectionToken, ElementRef } from '@angular/core';
4
4
  import { BreakpointObserver } from '@angular/cdk/layout';
5
5
  import * as rxjs from 'rxjs';
6
6
  import { Subject, Observable } from 'rxjs';
7
7
  import { Router, ActivatedRoute } from '@angular/router';
8
8
  import { MatSnackBar } from '@angular/material/snack-bar';
9
9
  import { FormGroup, FormBuilder } from '@angular/forms';
10
- import * as _firebase_auth from '@firebase/auth';
11
- import { Auth } from '@angular/fire/auth';
12
- import { Timestamp } from '@angular/fire/firestore';
13
10
  import { MatDialog } from '@angular/material/dialog';
14
- import { Storage, UploadTask } from '@angular/fire/storage';
15
11
  import { CdkTextareaAutosize } from '@angular/cdk/text-field';
16
12
  import * as _fortawesome_fontawesome_common_types from '@fortawesome/fontawesome-common-types';
17
13
  import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
@@ -73,12 +69,12 @@ declare class NgRhombusWrapperComponent implements OnInit, OnDestroy {
73
69
  }
74
70
 
75
71
  declare class NgRhombusAuthenticationService {
76
- firebaseAuth: Auth;
77
- currentUser$: Observable<_firebase_auth.User | null>;
72
+ private authAdapter;
73
+ currentUser$: rxjs.Observable<_doug_williamson_ng_rhombus.NgRhombusAuthUser | null>;
78
74
  login(email: string, password: string): Promise<void>;
79
- logout(): Promise<any>;
75
+ logout(): Promise<void>;
80
76
  private currentUserProfile$;
81
- currentUserProfile: i0.Signal<_firebase_auth.User | null | undefined>;
77
+ currentUserProfile: i0.Signal<_doug_williamson_ng_rhombus.NgRhombusAuthUser | null>;
82
78
  static ɵfac: i0.ɵɵFactoryDeclaration<NgRhombusAuthenticationService, never>;
83
79
  static ɵprov: i0.ɵɵInjectableDeclaration<NgRhombusAuthenticationService>;
84
80
  }
@@ -117,21 +113,78 @@ declare class NgRhombusPageComponent {
117
113
  static ɵcmp: i0.ɵɵComponentDeclaration<NgRhombusPageComponent, "ng-rhombus-page", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "backLink": { "alias": "backLink"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
118
114
  }
119
115
 
116
+ interface NgRhombusAuthUser {
117
+ uid: string;
118
+ email?: string | null;
119
+ displayName?: string | null;
120
+ }
121
+ interface NgRhombusAuthAdapter {
122
+ currentUser$: Observable<NgRhombusAuthUser | null>;
123
+ login(email: string, password: string): Promise<void>;
124
+ logout(): Promise<void>;
125
+ }
126
+ declare const NG_RHOMBUS_AUTH_ADAPTER: InjectionToken<NgRhombusAuthAdapter>;
127
+
128
+ type NgRhombusSeoTag = {
129
+ name?: string;
130
+ property?: string;
131
+ content: string;
132
+ };
133
+ interface NgRhombusSeoAdapter {
134
+ setTitle(title: string): void;
135
+ updateTag(tag: NgRhombusSeoTag): void;
136
+ }
137
+ declare const NG_RHOMBUS_SEO_ADAPTER: InjectionToken<NgRhombusSeoAdapter>;
138
+
139
+ type NgRhombusTimestampLike = Date | number | string | {
140
+ toMillis: () => number;
141
+ } | {
142
+ seconds: number;
143
+ nanoseconds?: number;
144
+ };
145
+ declare function ngRhombusTimestampToMillis(value: NgRhombusTimestampLike | null | undefined): number | null;
146
+ declare enum ContentPillar {
147
+ DeveloperLife = "Developer Life",
148
+ AngularWebEngineering = "Angular & Web Engineering",
149
+ GamingAsAnAdult = "Gaming as an Adult",
150
+ FatherhoodFamily = "Fatherhood & Family",
151
+ CareerBalanceIdentity = "Career, Balance & Identity"
152
+ }
153
+ declare enum BlogSeries {
154
+ ThisWeekILearned = "This Week I Learned",
155
+ DevDiary = "Dev Diary",
156
+ AdultGamerNotes = "Adult Gamer Notes",
157
+ LessonsFromFatherhood = "Lessons from Fatherhood",
158
+ TradeoffsTruths = "Tradeoffs & Truths",
159
+ FromTheEditor = "From The Editor"
160
+ }
120
161
  declare class IBlog {
121
162
  id: string;
122
163
  title: string;
123
164
  description: string;
124
165
  thumbnail: string;
125
166
  content: string;
126
- timestamp: Timestamp;
167
+ /**
168
+ * Published timestamp used for ordering.
169
+ * Kept flexible so apps can provide Firestore Timestamp, Date, millis, etc.
170
+ */
171
+ timestamp: NgRhombusTimestampLike;
127
172
  /** Estimated read time in minutes at 200 wpm */
128
173
  readTimeMinutes: number;
174
+ /**
175
+ * Creator system fields.
176
+ * Keep optional for backward compatibility; enforce required in admin UI + writes.
177
+ */
178
+ pillar?: ContentPillar | null;
179
+ series?: BlogSeries | null;
180
+ tags?: string[] | null;
129
181
  }
130
182
 
131
183
  declare class NgRhombusBlogListComponent implements OnInit {
132
184
  #private;
133
185
  goToRoute: EventEmitter<string>;
134
186
  dataSource: i0.InputSignal<IBlog[]>;
187
+ timestampToMillis: typeof ngRhombusTimestampToMillis;
135
188
  ngOnInit(): void;
136
189
  goToBlogPost(id: string): void;
137
190
  static ɵfac: i0.ɵɵFactoryDeclaration<NgRhombusBlogListComponent, never>;
@@ -140,15 +193,15 @@ declare class NgRhombusBlogListComponent implements OnInit {
140
193
 
141
194
  declare class NgRhombusBlogPostLatestComponent {
142
195
  blogPost: i0.InputSignal<IBlog | undefined>;
196
+ timestampToMillis: typeof ngRhombusTimestampToMillis;
143
197
  static ɵfac: i0.ɵɵFactoryDeclaration<NgRhombusBlogPostLatestComponent, never>;
144
198
  static ɵcmp: i0.ɵɵComponentDeclaration<NgRhombusBlogPostLatestComponent, "ng-rhombus-blog-post-latest", never, { "blogPost": { "alias": "blogPost"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
145
199
  }
146
200
 
147
201
  declare class NgRhombusBlogService {
148
202
  private readonly WORDS_PER_MINUTE;
149
- private firestore;
150
- private injector;
151
- private blogCollectionRef;
203
+ private readonly blogAdapter;
204
+ private normalizeBlogPost;
152
205
  blogPosts: i0.WritableSignal<IBlog[]>;
153
206
  selectedBlogPost: i0.WritableSignal<IBlog | undefined>;
154
207
  fetchBlogPosts(): Promise<IBlog[]>;
@@ -157,33 +210,73 @@ declare class NgRhombusBlogService {
157
210
  createBlogPost(blogPost: IBlog): Promise<void>;
158
211
  updateBlogPost(blogPost: IBlog): Promise<void>;
159
212
  deleteBlogPost(id: string): Promise<void>;
213
+ /** Latest N posts */
214
+ fetchLatestBlogPosts(count?: number): Promise<IBlog[]>;
215
+ /** Latest N posts for a given series */
216
+ fetchLatestBlogPostsBySeries(series: BlogSeries, count?: number): Promise<IBlog[]>;
217
+ /**
218
+ * Adjacent posts within the same series as the current post.
219
+ * - nextNewer: newer than current within the series (if any)
220
+ * - nextOlder: older than current within the series (if any)
221
+ */
222
+ fetchAdjacentBlogPostsInSeries(id: string): Promise<{
223
+ series?: BlogSeries | null;
224
+ nextNewer?: IBlog;
225
+ nextOlder?: IBlog;
226
+ }>;
227
+ /**
228
+ * Adjacent posts in the global "latest first" ordering.
229
+ * - nextNewer: newer than current (if any)
230
+ * - nextOlder: older than current (if any)
231
+ */
232
+ fetchAdjacentBlogPosts(id: string): Promise<{
233
+ nextNewer?: IBlog;
234
+ nextOlder?: IBlog;
235
+ }>;
160
236
  calculateReadTimeMinutes(text: string | null | undefined): number;
161
237
  static ɵfac: i0.ɵɵFactoryDeclaration<NgRhombusBlogService, never>;
162
238
  static ɵprov: i0.ɵɵInjectableDeclaration<NgRhombusBlogService>;
163
239
  }
164
240
 
165
- declare class NgRhombusBlogPostThumbnailService {
166
- firebaseStorage: Storage;
167
- uploadImage(imageName: string, image: File): UploadTask;
168
- deleteImage(filePath?: string): Promise<void>;
169
- static ɵfac: i0.ɵɵFactoryDeclaration<NgRhombusBlogPostThumbnailService, never>;
170
- static ɵprov: i0.ɵɵInjectableDeclaration<NgRhombusBlogPostThumbnailService>;
171
- }
172
-
241
+ type BlogTableRow = {
242
+ kind: 'main';
243
+ post: IBlog;
244
+ } | {
245
+ kind: 'detail';
246
+ post: IBlog;
247
+ };
173
248
  declare class NgRhombusBlogTableComponent {
174
249
  editEvent: EventEmitter<string>;
175
250
  deleteEvent: EventEmitter<IBlog>;
176
- readonly thumbnailService: NgRhombusBlogPostThumbnailService;
177
251
  readonly blogService: NgRhombusBlogService;
178
252
  readonly dialog: MatDialog;
179
253
  dataSource: i0.InputSignal<IBlog[]>;
254
+ timestampToMillis: typeof ngRhombusTimestampToMillis;
180
255
  displayedColumns: string[];
256
+ detailColumns: string[];
257
+ tableData(): BlogTableRow[];
258
+ isMainRow: (_index: number, row: BlogTableRow) => row is {
259
+ kind: "main";
260
+ post: IBlog;
261
+ };
262
+ isDetailRow: (_index: number, row: BlogTableRow) => row is {
263
+ kind: "detail";
264
+ post: IBlog;
265
+ };
181
266
  goToBlogPost(id: string): void;
182
267
  onDeleteBlogPost(blogPost: IBlog): void;
183
268
  static ɵfac: i0.ɵɵFactoryDeclaration<NgRhombusBlogTableComponent, never>;
184
269
  static ɵcmp: i0.ɵɵComponentDeclaration<NgRhombusBlogTableComponent, "ng-rhombus-blog-table", never, { "dataSource": { "alias": "dataSource"; "required": false; "isSignal": true; }; }, { "editEvent": "editEvent"; "deleteEvent": "deleteEvent"; }, never, never, true, never>;
185
270
  }
186
271
 
272
+ declare class NgRhombusBlogPostThumbnailService {
273
+ private readonly adapter;
274
+ uploadImage(imageName: string, image: File): Promise<string>;
275
+ deleteImage(filePath?: string): Promise<void>;
276
+ static ɵfac: i0.ɵɵFactoryDeclaration<NgRhombusBlogPostThumbnailService, never>;
277
+ static ɵprov: i0.ɵɵInjectableDeclaration<NgRhombusBlogPostThumbnailService>;
278
+ }
279
+
187
280
  interface AppTheme {
188
281
  name: string;
189
282
  icon: string;
@@ -211,6 +304,8 @@ declare class NgRhombusBlogAddEditComponent {
211
304
  submitEvent: i0.OutputEmitterRef<IBlog>;
212
305
  contentData: i0.WritableSignal<string>;
213
306
  blogPostForm: FormGroup;
307
+ readonly pillars: ContentPillar[];
308
+ readonly seriesOptions: BlogSeries[];
214
309
  dialog: MatDialog;
215
310
  thumbnailService: NgRhombusBlogPostThumbnailService;
216
311
  formBuilder: FormBuilder;
@@ -220,12 +315,14 @@ declare class NgRhombusBlogAddEditComponent {
220
315
  markdown: string;
221
316
  constructor();
222
317
  ngOnInit(): void;
318
+ private applyCreatorSystemRules;
223
319
  onContentChange(): void;
224
320
  get thumbnailSource(): any;
225
321
  onFileUploaded(downloadUrl: string): void;
226
322
  onFileDeleted(): void;
227
323
  onCancelClick(): void;
228
324
  onSubmit(): void;
325
+ private parseTags;
229
326
  static ɵfac: i0.ɵɵFactoryDeclaration<NgRhombusBlogAddEditComponent, never>;
230
327
  static ɵcmp: i0.ɵɵComponentDeclaration<NgRhombusBlogAddEditComponent, "ng-rhombus-blog-form", never, { "blogPost": { "alias": "blogPost"; "required": false; "isSignal": true; }; }, { "cancelEvent": "cancelEvent"; "submitEvent": "submitEvent"; }, never, never, true, never>;
231
328
  }
@@ -234,6 +331,7 @@ declare class NgRhombusBlogPostComponent implements OnInit {
234
331
  #private;
235
332
  dataSource: i0.InputSignal<IBlog | undefined>;
236
333
  themeService: ThemeService;
334
+ timestampToMillis: typeof ngRhombusTimestampToMillis;
237
335
  ngOnInit(): void;
238
336
  getShareUrl(): string;
239
337
  get shareLinks(): {
@@ -247,6 +345,11 @@ declare class NgRhombusBlogPostComponent implements OnInit {
247
345
  faFacebook: _fortawesome_fontawesome_common_types.IconDefinition;
248
346
  faBluesky: _fortawesome_fontawesome_common_types.IconDefinition;
249
347
  faLinkedin: _fortawesome_fontawesome_common_types.IconDefinition;
348
+ private normalizeTags;
349
+ get contentPillar(): string | null;
350
+ get series(): string | null;
351
+ get tags(): string[];
352
+ get hasTaxonomy(): boolean;
250
353
  static ɵfac: i0.ɵɵFactoryDeclaration<NgRhombusBlogPostComponent, never>;
251
354
  static ɵcmp: i0.ɵɵComponentDeclaration<NgRhombusBlogPostComponent, "ng-rhombus-blog-post", never, { "dataSource": { "alias": "dataSource"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
252
355
  }
@@ -256,6 +359,33 @@ declare class NgRhombusBlogDeletePostComponent {
256
359
  static ɵcmp: i0.ɵɵComponentDeclaration<NgRhombusBlogDeletePostComponent, "ng-rhombus-Blog-delete-post", never, {}, {}, never, never, true, never>;
257
360
  }
258
361
 
362
+ interface NgRhombusBlogAdapter {
363
+ fetchBlogPosts(): Promise<IBlog[]>;
364
+ fetchBlogPost(id: string): Promise<IBlog | undefined>;
365
+ fetchLatestBlogPost(): Promise<IBlog | undefined>;
366
+ fetchLatestBlogPosts(count: number): Promise<IBlog[]>;
367
+ fetchLatestBlogPostsBySeries(series: BlogSeries, count: number): Promise<IBlog[]>;
368
+ fetchAdjacentBlogPostsInSeries(id: string): Promise<{
369
+ series?: BlogSeries | null;
370
+ nextNewer?: IBlog;
371
+ nextOlder?: IBlog;
372
+ }>;
373
+ fetchAdjacentBlogPosts(id: string): Promise<{
374
+ nextNewer?: IBlog;
375
+ nextOlder?: IBlog;
376
+ }>;
377
+ createBlogPost(blogPost: IBlog): Promise<void>;
378
+ updateBlogPost(blogPost: IBlog): Promise<void>;
379
+ deleteBlogPost(id: string): Promise<void>;
380
+ }
381
+ declare const NG_RHOMBUS_BLOG_ADAPTER: InjectionToken<NgRhombusBlogAdapter>;
382
+
383
+ interface NgRhombusBlogThumbnailAdapter {
384
+ uploadImageAndGetUrl(imageName: string, image: File): Promise<string>;
385
+ deleteImage(filePath?: string): Promise<void>;
386
+ }
387
+ declare const NG_RHOMBUS_BLOG_THUMBNAIL_ADAPTER: InjectionToken<NgRhombusBlogThumbnailAdapter>;
388
+
259
389
  declare class IHome {
260
390
  id: string;
261
391
  title: string;
@@ -275,6 +405,28 @@ declare class NgRhombusHomeAdminComponent implements OnInit {
275
405
  static ɵcmp: i0.ɵɵComponentDeclaration<NgRhombusHomeAdminComponent, "ng-rhombus-home-admin", never, { "formAdminData": { "alias": "formAdminData"; "required": false; "isSignal": true; }; }, { "cancelEvent": "cancelEvent"; "submitEvent": "submitEvent"; }, never, never, true, never>;
276
406
  }
277
407
 
408
+ type NgRhombusHomeSaveResult = {
409
+ created: true;
410
+ id: string;
411
+ } | {
412
+ updated: true;
413
+ id: string;
414
+ };
415
+ interface NgRhombusHomeAdapter {
416
+ fetchTopHomeDocument(): Promise<IHome | undefined>;
417
+ saveOrUpdateHomeDocument(homeData: IHome): Promise<NgRhombusHomeSaveResult>;
418
+ }
419
+ declare const NG_RHOMBUS_HOME_ADAPTER: InjectionToken<NgRhombusHomeAdapter>;
420
+
421
+ declare class NgRhombusHomeService {
422
+ private adapter;
423
+ homeAdminData: i0.WritableSignal<IHome | undefined>;
424
+ fetchTopHomeDocument(): Promise<IHome | undefined>;
425
+ saveOrUpdateHomeDocument(homeData: IHome): Promise<NgRhombusHomeSaveResult>;
426
+ static ɵfac: i0.ɵɵFactoryDeclaration<NgRhombusHomeService, never>;
427
+ static ɵprov: i0.ɵɵInjectableDeclaration<NgRhombusHomeService>;
428
+ }
429
+
278
430
  declare enum SocialsSource {
279
431
  Twitch = "Twitch",
280
432
  YouTube = "YouTube",
@@ -289,19 +441,6 @@ interface ISocial {
289
441
  source: SocialsSource;
290
442
  url: string;
291
443
  }
292
- declare class NgRhombusSocialsService {
293
- private firestore;
294
- private injector;
295
- private socialsRef;
296
- socials: i0.WritableSignal<ISocial[]>;
297
- fetchAll(): Promise<ISocial[]>;
298
- fetchById(id: string): Promise<ISocial | undefined>;
299
- create(social: Omit<ISocial, 'id'>): Promise<string>;
300
- update(id: string, patch: Partial<Omit<ISocial, 'id'>>): Promise<void>;
301
- remove(id: string): Promise<void>;
302
- static ɵfac: i0.ɵɵFactoryDeclaration<NgRhombusSocialsService, never>;
303
- static ɵprov: i0.ɵɵInjectableDeclaration<NgRhombusSocialsService>;
304
- }
305
444
 
306
445
  declare class NgRhombusSocialsListComponent {
307
446
  wrapperService: WrapperService;
@@ -328,5 +467,27 @@ declare class NgRhombusSocialsTableComponent {
328
467
  static ɵcmp: i0.ɵɵComponentDeclaration<NgRhombusSocialsTableComponent, "ng-rhombus-socials-table", never, { "socials": { "alias": "socials"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
329
468
  }
330
469
 
331
- export { IBlog, NgRhombusBlogAddEditComponent, NgRhombusBlogDeletePostComponent, NgRhombusBlogListComponent, NgRhombusBlogPostComponent, NgRhombusBlogPostLatestComponent, NgRhombusBlogPostThumbnailService, NgRhombusBlogService, NgRhombusBlogTableComponent, NgRhombusHomeAdminComponent, NgRhombusLoginComponent, NgRhombusPageComponent, NgRhombusSocialsListComponent, NgRhombusSocialsService, NgRhombusSocialsTableComponent, NgRhombusSpinnerComponent, NgRhombusWrapperComponent, SocialsSource, ThemeEnum, WrapperService };
332
- export type { Breadcrumb, ILoginCredentials, ISocial, NgRhombusNavItem, Theme };
470
+ declare class NgRhombusSocialsService {
471
+ private adapter;
472
+ socials: i0.WritableSignal<ISocial[]>;
473
+ private sort;
474
+ fetchAll(): Promise<ISocial[]>;
475
+ fetchById(id: string): Promise<ISocial | undefined>;
476
+ create(social: Omit<ISocial, 'id'>): Promise<string>;
477
+ update(id: string, patch: Partial<Omit<ISocial, 'id'>>): Promise<void>;
478
+ remove(id: string): Promise<void>;
479
+ static ɵfac: i0.ɵɵFactoryDeclaration<NgRhombusSocialsService, never>;
480
+ static ɵprov: i0.ɵɵInjectableDeclaration<NgRhombusSocialsService>;
481
+ }
482
+
483
+ interface NgRhombusSocialsAdapter {
484
+ fetchAll(): Promise<ISocial[]>;
485
+ fetchById(id: string): Promise<ISocial | undefined>;
486
+ create(social: Omit<ISocial, 'id'>): Promise<string>;
487
+ update(id: string, patch: Partial<Omit<ISocial, 'id'>>): Promise<void>;
488
+ remove(id: string): Promise<void>;
489
+ }
490
+ declare const NG_RHOMBUS_SOCIALS_ADAPTER: InjectionToken<NgRhombusSocialsAdapter>;
491
+
492
+ export { BlogSeries, ContentPillar, IBlog, IHome, NG_RHOMBUS_AUTH_ADAPTER, NG_RHOMBUS_BLOG_ADAPTER, NG_RHOMBUS_BLOG_THUMBNAIL_ADAPTER, NG_RHOMBUS_HOME_ADAPTER, NG_RHOMBUS_SEO_ADAPTER, NG_RHOMBUS_SOCIALS_ADAPTER, NgRhombusBlogAddEditComponent, NgRhombusBlogDeletePostComponent, NgRhombusBlogListComponent, NgRhombusBlogPostComponent, NgRhombusBlogPostLatestComponent, NgRhombusBlogPostThumbnailService, NgRhombusBlogService, NgRhombusBlogTableComponent, NgRhombusHomeAdminComponent, NgRhombusHomeService, NgRhombusLoginComponent, NgRhombusPageComponent, NgRhombusSocialsListComponent, NgRhombusSocialsService, NgRhombusSocialsTableComponent, NgRhombusSpinnerComponent, NgRhombusWrapperComponent, SocialsSource, ThemeEnum, WrapperService, ngRhombusTimestampToMillis };
493
+ export type { Breadcrumb, ILoginCredentials, ISocial, NgRhombusAuthAdapter, NgRhombusAuthUser, NgRhombusBlogAdapter, NgRhombusBlogThumbnailAdapter, NgRhombusHomeAdapter, NgRhombusHomeSaveResult, NgRhombusNavItem, NgRhombusSeoAdapter, NgRhombusSeoTag, NgRhombusSocialsAdapter, NgRhombusTimestampLike, Theme };