@foliokit/cms-core 0.4.2 → 1.0.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/README.md +62 -2
- package/eslint.config.mjs +48 -0
- package/ng-package.json +7 -0
- package/package.json +5 -18
- package/project.json +32 -0
- package/{esm2022/index.js → src/index.ts} +9 -2
- package/src/lib/cms-core/cms-core.html +1 -0
- package/src/lib/cms-core/cms-core.scss +0 -0
- package/src/lib/cms-core/cms-core.spec.ts +44 -0
- package/src/lib/cms-core/cms-core.ts +9 -0
- package/src/lib/firebase/firebase-admin.ts +32 -0
- package/src/lib/firebase/firebase.config.ts +26 -0
- package/src/lib/firebase/firebase.providers.ts +89 -0
- package/src/lib/firebase/foliokit.providers.ts +178 -0
- package/src/lib/models/author.model.ts +16 -0
- package/src/lib/models/page.model.ts +11 -0
- package/src/lib/models/post.model.ts +41 -0
- package/src/lib/models/site-config.model.ts +103 -0
- package/src/lib/models/tag.model.ts +5 -0
- package/src/lib/pipes/tag-label.pipe.ts +16 -0
- package/src/lib/resolvers/about-page.resolver.ts +76 -0
- package/src/lib/resolvers/links-page.resolver.ts +77 -0
- package/src/lib/resolvers/posts.resolver.ts +51 -0
- package/src/lib/services/auth.service.ts +49 -0
- package/src/lib/services/author.service.ts +88 -0
- package/src/lib/services/post.service.spec.ts +255 -0
- package/src/lib/services/post.service.ts +148 -0
- package/src/lib/services/site-config.service.ts +86 -0
- package/src/lib/services/tag.service.ts +24 -0
- package/src/lib/tokens/post-service.token.ts +14 -0
- package/src/lib/tokens/site-config-service.token.ts +12 -0
- package/src/lib/utils/normalize-author.ts +50 -0
- package/src/lib/utils/normalize-post.ts +66 -0
- package/src/lib/utils/normalize-site-config.ts +145 -0
- package/testing/firestore.stub.ts +65 -0
- package/tsconfig.json +31 -0
- package/tsconfig.lib.json +12 -0
- package/tsconfig.lib.prod.json +9 -0
- package/tsconfig.spec.json +8 -0
- package/esm2022/foliokit-cms-core.js +0 -5
- package/esm2022/foliokit-cms-core.js.map +0 -1
- package/esm2022/index.js.map +0 -1
- package/esm2022/lib/firebase/firebase.config.js +0 -8
- package/esm2022/lib/firebase/firebase.config.js.map +0 -1
- package/esm2022/lib/firebase/firebase.providers.js +0 -54
- package/esm2022/lib/firebase/firebase.providers.js.map +0 -1
- package/esm2022/lib/models/author.model.js +0 -1
- package/esm2022/lib/models/author.model.js.map +0 -1
- package/esm2022/lib/models/page.model.js +0 -1
- package/esm2022/lib/models/page.model.js.map +0 -1
- package/esm2022/lib/models/post.model.js +0 -1
- package/esm2022/lib/models/post.model.js.map +0 -1
- package/esm2022/lib/models/site-config.model.js +0 -1
- package/esm2022/lib/models/site-config.model.js.map +0 -1
- package/esm2022/lib/models/tag.model.js +0 -1
- package/esm2022/lib/models/tag.model.js.map +0 -1
- package/esm2022/lib/services/auth.service.js +0 -42
- package/esm2022/lib/services/auth.service.js.map +0 -1
- package/esm2022/lib/services/post.service.js +0 -83
- package/esm2022/lib/services/post.service.js.map +0 -1
- package/esm2022/lib/services/site-config.service.js +0 -30
- package/esm2022/lib/services/site-config.service.js.map +0 -1
- package/esm2022/lib/services/tag.service.js +0 -22
- package/esm2022/lib/services/tag.service.js.map +0 -1
- package/esm2022/lib/tokens/post-service.token.js +0 -5
- package/esm2022/lib/tokens/post-service.token.js.map +0 -1
- package/esm2022/lib/utils/normalize-post.js +0 -66
- package/esm2022/lib/utils/normalize-post.js.map +0 -1
- package/foliokit-cms-core.d.ts +0 -5
- package/index.d.ts +0 -13
- package/lib/firebase/firebase.config.d.ts +0 -11
- package/lib/firebase/firebase.providers.d.ts +0 -3
- package/lib/models/author.model.d.ts +0 -13
- package/lib/models/page.model.d.ts +0 -37
- package/lib/models/post.model.d.ts +0 -39
- package/lib/models/site-config.model.d.ts +0 -26
- package/lib/models/tag.model.d.ts +0 -5
- package/lib/services/auth.service.d.ts +0 -13
- package/lib/services/post.service.d.ts +0 -16
- package/lib/services/site-config.service.d.ts +0 -10
- package/lib/services/tag.service.d.ts +0 -9
- package/lib/tokens/post-service.token.d.ts +0 -10
- package/lib/utils/normalize-post.d.ts +0 -6
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tag.service.js","sourceRoot":"","sources":["../../../../../../libs/cms-core/src/lib/services/tag.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAc,EAAE,EAAE,MAAM,MAAM,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;;AAIxD,MAAM,OAAO,UAAU;IACJ,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAE/C,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAC3D,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CACf,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAQ,CAAC,CACnE,EACD,UAAU,CAAC,CAAC,GAAG,EAAE,EAAE;YACjB,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;YAC9C,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAChB,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;uGAbU,UAAU;2GAAV,UAAU,cADG,MAAM;;2FACnB,UAAU;kBADtB,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE","sourcesContent":["import { inject, Injectable } from '@angular/core';\nimport { collection, getDocs } from 'firebase/firestore';\nimport { from, Observable, of } from 'rxjs';\nimport { catchError, map } from 'rxjs/operators';\nimport { FIRESTORE } from '../firebase/firebase.config';\nimport type { Tag } from '../models/tag.model';\n\n@Injectable({ providedIn: 'root' })\nexport class TagService {\n private readonly firestore = inject(FIRESTORE);\n\n getAllTags(): Observable<Tag[]> {\n return from(getDocs(collection(this.firestore, 'tags'))).pipe(\n map((snapshot) =>\n snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }) as Tag),\n ),\n catchError((err) => {\n console.error('[TagService.getAllTags]', err);\n return of([]);\n }),\n );\n }\n}\n"]}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { InjectionToken, makeStateKey } from '@angular/core';
|
|
2
|
-
export const BLOG_POST_SERVICE = new InjectionToken('BLOG_POST_SERVICE');
|
|
3
|
-
export const POST_TRANSFER_KEY = makeStateKey('blog-post');
|
|
4
|
-
export const POSTS_TRANSFER_KEY = makeStateKey('blog-posts');
|
|
5
|
-
//# sourceMappingURL=post-service.token.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"post-service.token.js","sourceRoot":"","sources":["../../../../../../libs/cms-core/src/lib/tokens/post-service.token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAS7D,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,cAAc,CACjD,mBAAmB,CACpB,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAkB,WAAW,CAAC,CAAC;AAC5E,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAAa,YAAY,CAAC,CAAC","sourcesContent":["import { InjectionToken, makeStateKey } from '@angular/core';\nimport type { Observable } from 'rxjs';\nimport type { BlogPost } from '../models/post.model';\n\nexport interface IBlogPostService {\n getPublishedPosts(): Observable<BlogPost[]>;\n getPostBySlug(slug: string): Observable<BlogPost | null>;\n}\n\nexport const BLOG_POST_SERVICE = new InjectionToken<IBlogPostService>(\n 'BLOG_POST_SERVICE',\n);\n\nexport const POST_TRANSFER_KEY = makeStateKey<BlogPost | null>('blog-post');\nexport const POSTS_TRANSFER_KEY = makeStateKey<BlogPost[]>('blog-posts');\n"]}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Converts a Firestore timestamp in any of its runtime forms to milliseconds.
|
|
3
|
-
*
|
|
4
|
-
* Handles:
|
|
5
|
-
* - Native Timestamp objects from either SDK (have .toMillis())
|
|
6
|
-
* - Objects with .toDate() method (client SDK Timestamp without .toMillis())
|
|
7
|
-
* - Admin SDK serialized form { _seconds, _nanoseconds }
|
|
8
|
-
* - Plain { seconds, nanoseconds } objects
|
|
9
|
-
* - Already-numeric millisecond values
|
|
10
|
-
* - JavaScript Date objects
|
|
11
|
-
*/
|
|
12
|
-
function normalizeTimestamp(value) {
|
|
13
|
-
if (value == null)
|
|
14
|
-
return 0;
|
|
15
|
-
if (typeof value === 'number')
|
|
16
|
-
return value;
|
|
17
|
-
if (value instanceof Date)
|
|
18
|
-
return value.getTime();
|
|
19
|
-
if (typeof value === 'object') {
|
|
20
|
-
const v = value;
|
|
21
|
-
if (typeof v.toMillis === 'function') {
|
|
22
|
-
return v.toMillis();
|
|
23
|
-
}
|
|
24
|
-
if (typeof v.toDate === 'function') {
|
|
25
|
-
return v.toDate().getTime();
|
|
26
|
-
}
|
|
27
|
-
if (typeof v['_seconds'] === 'number') {
|
|
28
|
-
return v['_seconds'] * 1000 +
|
|
29
|
-
Math.floor((v['_nanoseconds'] ?? 0) / 1e6);
|
|
30
|
-
}
|
|
31
|
-
if (typeof v['seconds'] === 'number') {
|
|
32
|
-
return v['seconds'] * 1000 +
|
|
33
|
-
Math.floor((v['nanoseconds'] ?? 0) / 1e6);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return 0;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Maps raw Firestore DocumentData (merged with its doc id) into a fully typed,
|
|
40
|
-
* TransferState-serializable BlogPost. Callers must pass { id: doc.id, ...doc.data() }.
|
|
41
|
-
*/
|
|
42
|
-
export function normalizePost(raw) {
|
|
43
|
-
return {
|
|
44
|
-
id: raw['id'] ?? '',
|
|
45
|
-
slug: raw['slug'] ?? '',
|
|
46
|
-
title: raw['title'] ?? '',
|
|
47
|
-
subtitle: raw['subtitle'],
|
|
48
|
-
status: raw['status'],
|
|
49
|
-
content: raw['content'] ?? '',
|
|
50
|
-
excerpt: raw['excerpt'],
|
|
51
|
-
thumbnailUrl: raw['thumbnailUrl'],
|
|
52
|
-
thumbnailAlt: raw['thumbnailAlt'],
|
|
53
|
-
tags: raw['tags'] ?? [],
|
|
54
|
-
authorId: raw['authorId'],
|
|
55
|
-
readingTimeMinutes: raw['readingTimeMinutes'],
|
|
56
|
-
embeddedMedia: raw['embeddedMedia'] ?? {},
|
|
57
|
-
seo: raw['seo'] ?? {},
|
|
58
|
-
publishedAt: normalizeTimestamp(raw['publishedAt']),
|
|
59
|
-
scheduledPublishAt: raw['scheduledPublishAt'] != null
|
|
60
|
-
? normalizeTimestamp(raw['scheduledPublishAt'])
|
|
61
|
-
: undefined,
|
|
62
|
-
updatedAt: normalizeTimestamp(raw['updatedAt']),
|
|
63
|
-
createdAt: normalizeTimestamp(raw['createdAt']),
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
//# sourceMappingURL=normalize-post.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"normalize-post.js","sourceRoot":"","sources":["../../../../../../libs/cms-core/src/lib/utils/normalize-post.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,SAAS,kBAAkB,CAAC,KAAc;IACxC,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,CAAC,CAAC;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,KAAgC,CAAC;QAC3C,IAAI,OAAQ,CAA4B,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;YACjE,OAAQ,CAA4B,CAAC,QAAQ,EAAE,CAAC;QAClD,CAAC;QACD,IAAI,OAAQ,CAA0B,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC7D,OAAQ,CAAwB,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;QACtD,CAAC;QACD,IAAI,OAAO,CAAC,CAAC,UAAU,CAAC,KAAK,QAAQ,EAAE,CAAC;YACtC,OAAQ,CAAC,CAAC,UAAU,CAAY,GAAG,IAAI;gBACrC,IAAI,CAAC,KAAK,CAAC,CAAE,CAAC,CAAC,cAAc,CAAY,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,QAAQ,EAAE,CAAC;YACrC,OAAQ,CAAC,CAAC,SAAS,CAAY,GAAG,IAAI;gBACpC,IAAI,CAAC,KAAK,CAAC,CAAE,CAAC,CAAC,aAAa,CAAY,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAA4B;IACxD,OAAO;QACL,EAAE,EAAG,GAAG,CAAC,IAAI,CAAY,IAAI,EAAE;QAC/B,IAAI,EAAG,GAAG,CAAC,MAAM,CAAY,IAAI,EAAE;QACnC,KAAK,EAAG,GAAG,CAAC,OAAO,CAAY,IAAI,EAAE;QACrC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAuB;QAC/C,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAuB;QAC3C,OAAO,EAAG,GAAG,CAAC,SAAS,CAAY,IAAI,EAAE;QACzC,OAAO,EAAE,GAAG,CAAC,SAAS,CAAuB;QAC7C,YAAY,EAAE,GAAG,CAAC,cAAc,CAAuB;QACvD,YAAY,EAAE,GAAG,CAAC,cAAc,CAAuB;QACvD,IAAI,EAAG,GAAG,CAAC,MAAM,CAAc,IAAI,EAAE;QACrC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAuB;QAC/C,kBAAkB,EAAE,GAAG,CAAC,oBAAoB,CAAuB;QACnE,aAAa,EAAG,GAAG,CAAC,eAAe,CAA+B,IAAI,EAAE;QACxE,GAAG,EAAG,GAAG,CAAC,KAAK,CAAqB,IAAI,EAAE;QAC1C,WAAW,EAAE,kBAAkB,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACnD,kBAAkB,EAChB,GAAG,CAAC,oBAAoB,CAAC,IAAI,IAAI;YAC/B,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;YAC/C,CAAC,CAAC,SAAS;QACf,SAAS,EAAE,kBAAkB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/C,SAAS,EAAE,kBAAkB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;KAChD,CAAC;AACJ,CAAC","sourcesContent":["import type { BlogPost } from '../models/post.model';\n\n/**\n * Converts a Firestore timestamp in any of its runtime forms to milliseconds.\n *\n * Handles:\n * - Native Timestamp objects from either SDK (have .toMillis())\n * - Objects with .toDate() method (client SDK Timestamp without .toMillis())\n * - Admin SDK serialized form { _seconds, _nanoseconds }\n * - Plain { seconds, nanoseconds } objects\n * - Already-numeric millisecond values\n * - JavaScript Date objects\n */\nfunction normalizeTimestamp(value: unknown): number {\n if (value == null) return 0;\n if (typeof value === 'number') return value;\n if (value instanceof Date) return value.getTime();\n if (typeof value === 'object') {\n const v = value as Record<string, unknown>;\n if (typeof (v as { toMillis?: unknown }).toMillis === 'function') {\n return (v as { toMillis(): number }).toMillis();\n }\n if (typeof (v as { toDate?: unknown }).toDate === 'function') {\n return (v as { toDate(): Date }).toDate().getTime();\n }\n if (typeof v['_seconds'] === 'number') {\n return (v['_seconds'] as number) * 1000 +\n Math.floor(((v['_nanoseconds'] as number) ?? 0) / 1e6);\n }\n if (typeof v['seconds'] === 'number') {\n return (v['seconds'] as number) * 1000 +\n Math.floor(((v['nanoseconds'] as number) ?? 0) / 1e6);\n }\n }\n return 0;\n}\n\n/**\n * Maps raw Firestore DocumentData (merged with its doc id) into a fully typed,\n * TransferState-serializable BlogPost. Callers must pass { id: doc.id, ...doc.data() }.\n */\nexport function normalizePost(raw: Record<string, unknown>): BlogPost {\n return {\n id: (raw['id'] as string) ?? '',\n slug: (raw['slug'] as string) ?? '',\n title: (raw['title'] as string) ?? '',\n subtitle: raw['subtitle'] as string | undefined,\n status: raw['status'] as BlogPost['status'],\n content: (raw['content'] as string) ?? '',\n excerpt: raw['excerpt'] as string | undefined,\n thumbnailUrl: raw['thumbnailUrl'] as string | undefined,\n thumbnailAlt: raw['thumbnailAlt'] as string | undefined,\n tags: (raw['tags'] as string[]) ?? [],\n authorId: raw['authorId'] as string | undefined,\n readingTimeMinutes: raw['readingTimeMinutes'] as number | undefined,\n embeddedMedia: (raw['embeddedMedia'] as BlogPost['embeddedMedia']) ?? {},\n seo: (raw['seo'] as BlogPost['seo']) ?? {},\n publishedAt: normalizeTimestamp(raw['publishedAt']),\n scheduledPublishAt:\n raw['scheduledPublishAt'] != null\n ? normalizeTimestamp(raw['scheduledPublishAt'])\n : undefined,\n updatedAt: normalizeTimestamp(raw['updatedAt']),\n createdAt: normalizeTimestamp(raw['createdAt']),\n };\n}\n"]}
|
package/foliokit-cms-core.d.ts
DELETED
package/index.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export * from './lib/firebase/firebase.config';
|
|
2
|
-
export * from './lib/firebase/firebase.providers';
|
|
3
|
-
export * from './lib/models/post.model';
|
|
4
|
-
export * from './lib/models/site-config.model';
|
|
5
|
-
export * from './lib/models/page.model';
|
|
6
|
-
export * from './lib/models/tag.model';
|
|
7
|
-
export * from './lib/models/author.model';
|
|
8
|
-
export * from './lib/services/auth.service';
|
|
9
|
-
export * from './lib/services/post.service';
|
|
10
|
-
export * from './lib/services/site-config.service';
|
|
11
|
-
export * from './lib/services/tag.service';
|
|
12
|
-
export * from './lib/tokens/post-service.token';
|
|
13
|
-
export * from './lib/utils/normalize-post';
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { InjectionToken } from '@angular/core';
|
|
2
|
-
import type { FirebaseApp, FirebaseOptions } from 'firebase/app';
|
|
3
|
-
import type { Firestore } from 'firebase/firestore';
|
|
4
|
-
import type { FirebaseStorage } from 'firebase/storage';
|
|
5
|
-
import type { Auth } from 'firebase/auth';
|
|
6
|
-
export declare const FIREBASE_OPTIONS: InjectionToken<FirebaseOptions>;
|
|
7
|
-
export declare const FIREBASE_APP: InjectionToken<FirebaseApp>;
|
|
8
|
-
export declare const FIRESTORE: InjectionToken<Firestore>;
|
|
9
|
-
export declare const FIREBASE_STORAGE: InjectionToken<FirebaseStorage>;
|
|
10
|
-
export declare const FIREBASE_AUTH: InjectionToken<Auth | null>;
|
|
11
|
-
export declare const ADMIN_EMAIL: InjectionToken<string>;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Timestamp } from 'firebase/firestore';
|
|
2
|
-
import type { SocialLink } from './site-config.model';
|
|
3
|
-
export interface Author {
|
|
4
|
-
id: string;
|
|
5
|
-
name: string;
|
|
6
|
-
slug: string;
|
|
7
|
-
bio?: string;
|
|
8
|
-
avatarUrl?: string;
|
|
9
|
-
email?: string;
|
|
10
|
-
social?: SocialLink[];
|
|
11
|
-
createdAt: Timestamp;
|
|
12
|
-
updatedAt: Timestamp;
|
|
13
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { Timestamp } from 'firebase/firestore';
|
|
2
|
-
import type { SeoMeta } from './post.model';
|
|
3
|
-
export interface CmsPage {
|
|
4
|
-
id: string;
|
|
5
|
-
slug: string;
|
|
6
|
-
title: string;
|
|
7
|
-
status: 'published' | 'draft';
|
|
8
|
-
content?: string;
|
|
9
|
-
seo: SeoMeta;
|
|
10
|
-
createdAt: Timestamp;
|
|
11
|
-
updatedAt: Timestamp;
|
|
12
|
-
}
|
|
13
|
-
export interface LinktreeLink {
|
|
14
|
-
label: string;
|
|
15
|
-
url: string;
|
|
16
|
-
icon?: string;
|
|
17
|
-
order: number;
|
|
18
|
-
}
|
|
19
|
-
export interface HomePage extends CmsPage {
|
|
20
|
-
heroHeadline?: string;
|
|
21
|
-
heroSubheadline?: string;
|
|
22
|
-
heroCta?: {
|
|
23
|
-
label: string;
|
|
24
|
-
href: string;
|
|
25
|
-
};
|
|
26
|
-
featuredPostIds?: string[];
|
|
27
|
-
}
|
|
28
|
-
export interface AboutPage extends CmsPage {
|
|
29
|
-
bio?: string;
|
|
30
|
-
skills?: string[];
|
|
31
|
-
avatarUrl?: string;
|
|
32
|
-
}
|
|
33
|
-
export interface LinktreePage extends CmsPage {
|
|
34
|
-
links: LinktreeLink[];
|
|
35
|
-
avatarUrl?: string;
|
|
36
|
-
displayName?: string;
|
|
37
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
export interface SeoMeta {
|
|
2
|
-
title?: string;
|
|
3
|
-
description?: string;
|
|
4
|
-
keywords?: string[];
|
|
5
|
-
ogImage?: string;
|
|
6
|
-
canonicalUrl?: string;
|
|
7
|
-
noIndex?: boolean;
|
|
8
|
-
}
|
|
9
|
-
export interface EmbeddedMediaEntry {
|
|
10
|
-
token: string;
|
|
11
|
-
storagePath: string;
|
|
12
|
-
downloadUrl: string;
|
|
13
|
-
alt: string;
|
|
14
|
-
mimeType: string;
|
|
15
|
-
}
|
|
16
|
-
export interface BlogPost {
|
|
17
|
-
id: string;
|
|
18
|
-
slug: string;
|
|
19
|
-
title: string;
|
|
20
|
-
subtitle?: string;
|
|
21
|
-
status: 'published' | 'draft' | 'scheduled' | 'archived';
|
|
22
|
-
content: string;
|
|
23
|
-
excerpt?: string;
|
|
24
|
-
thumbnailUrl?: string;
|
|
25
|
-
thumbnailAlt?: string;
|
|
26
|
-
tags: string[];
|
|
27
|
-
authorId?: string;
|
|
28
|
-
readingTimeMinutes?: number;
|
|
29
|
-
embeddedMedia: Record<string, EmbeddedMediaEntry>;
|
|
30
|
-
seo: SeoMeta;
|
|
31
|
-
/** Unix milliseconds. Stored as Firestore Timestamp but always normalized on read. */
|
|
32
|
-
publishedAt: number;
|
|
33
|
-
/** Unix milliseconds, optional. */
|
|
34
|
-
scheduledPublishAt?: number;
|
|
35
|
-
/** Unix milliseconds. */
|
|
36
|
-
updatedAt: number;
|
|
37
|
-
/** Unix milliseconds. */
|
|
38
|
-
createdAt: number;
|
|
39
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { Timestamp } from 'firebase/firestore';
|
|
2
|
-
export interface NavItem {
|
|
3
|
-
label: string;
|
|
4
|
-
url: string;
|
|
5
|
-
order?: number;
|
|
6
|
-
external?: boolean;
|
|
7
|
-
icon?: string;
|
|
8
|
-
}
|
|
9
|
-
export interface SocialLink {
|
|
10
|
-
platform: string;
|
|
11
|
-
url: string;
|
|
12
|
-
label?: string;
|
|
13
|
-
icon?: string;
|
|
14
|
-
}
|
|
15
|
-
export interface SiteConfig {
|
|
16
|
-
id: string;
|
|
17
|
-
siteName: string;
|
|
18
|
-
siteUrl: string;
|
|
19
|
-
description?: string;
|
|
20
|
-
logo?: string;
|
|
21
|
-
favicon?: string;
|
|
22
|
-
nav: NavItem[];
|
|
23
|
-
social: SocialLink[];
|
|
24
|
-
defaultAuthorId?: string;
|
|
25
|
-
updatedAt: Timestamp;
|
|
26
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { User } from 'firebase/auth';
|
|
2
|
-
import * as i0 from "@angular/core";
|
|
3
|
-
export declare class AuthService {
|
|
4
|
-
private readonly auth;
|
|
5
|
-
private readonly adminEmail;
|
|
6
|
-
readonly user: import("@angular/core").Signal<User | null | undefined>;
|
|
7
|
-
readonly isAuthenticated: import("@angular/core").Signal<boolean>;
|
|
8
|
-
readonly isAdmin: import("@angular/core").Signal<boolean>;
|
|
9
|
-
signInWithGoogle(): Promise<void>;
|
|
10
|
-
signOut(): Promise<void>;
|
|
11
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<AuthService, never>;
|
|
12
|
-
static ɵprov: i0.ɵɵInjectableDeclaration<AuthService>;
|
|
13
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
import type { BlogPost } from '../models/post.model';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
export declare class PostService {
|
|
5
|
-
private readonly firestore;
|
|
6
|
-
private readonly storage;
|
|
7
|
-
getPublishedPosts(): Observable<BlogPost[]>;
|
|
8
|
-
getPostBySlug(slug: string): Observable<BlogPost | null>;
|
|
9
|
-
getPostsByTag(tag: string): Observable<BlogPost[]>;
|
|
10
|
-
getAllPosts(): Observable<BlogPost[]>;
|
|
11
|
-
getPostById(id: string): Observable<BlogPost>;
|
|
12
|
-
deleteStorageFile(storagePath: string): Observable<void>;
|
|
13
|
-
savePost(post: BlogPost): Observable<BlogPost>;
|
|
14
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<PostService, never>;
|
|
15
|
-
static ɵprov: i0.ɵɵInjectableDeclaration<PostService>;
|
|
16
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
import type { SiteConfig } from '../models/site-config.model';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
export declare class SiteConfigService {
|
|
5
|
-
private readonly firestore;
|
|
6
|
-
getSiteConfig(siteId: string): Observable<SiteConfig | null>;
|
|
7
|
-
getDefaultSiteConfig(): Observable<SiteConfig | null>;
|
|
8
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<SiteConfigService, never>;
|
|
9
|
-
static ɵprov: i0.ɵɵInjectableDeclaration<SiteConfigService>;
|
|
10
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
import type { Tag } from '../models/tag.model';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
export declare class TagService {
|
|
5
|
-
private readonly firestore;
|
|
6
|
-
getAllTags(): Observable<Tag[]>;
|
|
7
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<TagService, never>;
|
|
8
|
-
static ɵprov: i0.ɵɵInjectableDeclaration<TagService>;
|
|
9
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { InjectionToken } from '@angular/core';
|
|
2
|
-
import type { Observable } from 'rxjs';
|
|
3
|
-
import type { BlogPost } from '../models/post.model';
|
|
4
|
-
export interface IBlogPostService {
|
|
5
|
-
getPublishedPosts(): Observable<BlogPost[]>;
|
|
6
|
-
getPostBySlug(slug: string): Observable<BlogPost | null>;
|
|
7
|
-
}
|
|
8
|
-
export declare const BLOG_POST_SERVICE: InjectionToken<IBlogPostService>;
|
|
9
|
-
export declare const POST_TRANSFER_KEY: import("@angular/core").StateKey<BlogPost | null>;
|
|
10
|
-
export declare const POSTS_TRANSFER_KEY: import("@angular/core").StateKey<BlogPost[]>;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { BlogPost } from '../models/post.model';
|
|
2
|
-
/**
|
|
3
|
-
* Maps raw Firestore DocumentData (merged with its doc id) into a fully typed,
|
|
4
|
-
* TransferState-serializable BlogPost. Callers must pass { id: doc.id, ...doc.data() }.
|
|
5
|
-
*/
|
|
6
|
-
export declare function normalizePost(raw: Record<string, unknown>): BlogPost;
|