-
-
Notifications
You must be signed in to change notification settings - Fork 257
/
Copy pathcontent.ts
135 lines (126 loc) · 3.76 KB
/
content.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/// <reference types="vite/client" />
import { inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Observable, of } from 'rxjs';
import { map, switchMap, tap } from 'rxjs/operators';
import { ContentFile } from './content-file';
import { CONTENT_FILES_TOKEN } from './content-files-token';
import { parseRawContentFile } from './parse-raw-content-file';
import { waitFor } from './utils/zone-wait-for';
import { RenderTaskService } from './render-task.service';
function getContentFile<
Attributes extends Record<string, any> = Record<string, any>
>(
contentFiles: Record<string, () => Promise<string>>,
prefix: string,
slug: string,
fallback: string,
renderTaskService: RenderTaskService
): Observable<ContentFile<Attributes | Record<string, never>>> {
const filePath = `/src/content/${prefix}${slug}`;
const contentFile =
contentFiles[`${filePath}.md`] ?? contentFiles[`${filePath}.agx`];
if (!contentFile) {
return of({
filename: filePath,
attributes: {},
slug: '',
content: fallback,
});
}
const contentTask = renderTaskService.addRenderTask();
return new Observable<string | { default: any; metadata: any }>(
(observer) => {
const contentResolver = contentFile();
if (import.meta.env.SSR === true) {
waitFor(contentResolver).then((content) => {
observer.next(content);
observer.complete();
setTimeout(() => renderTaskService.clearRenderTask(contentTask), 10);
});
} else {
contentResolver.then((content) => {
observer.next(content);
observer.complete();
});
}
}
).pipe(
map((contentFile) => {
if (typeof contentFile === 'string') {
const { content, attributes } =
parseRawContentFile<Attributes>(contentFile);
return {
filename: filePath,
slug,
attributes,
content,
};
}
return {
filename: filePath,
slug,
attributes: contentFile.metadata,
content: contentFile.default,
};
})
);
}
/**
* Retrieves the static content using the provided param and/or prefix.
*
* @param param route parameter (default: 'slug')
* @param fallback fallback text if content file is not found (default: 'No Content Found')
*/
export function injectContent<
Attributes extends Record<string, any> = Record<string, any>
>(
param:
| string
| {
param: string;
subdirectory: string;
}
| {
customFilename: string;
} = 'slug',
fallback = 'No Content Found'
): Observable<ContentFile<Attributes | Record<string, never>>> {
const contentFiles = inject(CONTENT_FILES_TOKEN);
const renderTaskService = inject(RenderTaskService);
const task = renderTaskService.addRenderTask();
if (typeof param === 'string' || 'param' in param) {
const prefix = typeof param === 'string' ? '' : `${param.subdirectory}/`;
const route = inject(ActivatedRoute);
const paramKey = typeof param === 'string' ? param : param.param;
return route.paramMap.pipe(
map((params) => params.get(paramKey)),
switchMap((slug) => {
if (slug) {
return getContentFile<Attributes>(
contentFiles,
prefix,
slug,
fallback,
renderTaskService
);
}
return of({
filename: '',
slug: '',
attributes: {},
content: fallback,
});
}),
tap(() => renderTaskService.clearRenderTask(task))
);
} else {
return getContentFile<Attributes>(
contentFiles,
'',
param.customFilename,
fallback,
renderTaskService
).pipe(tap(() => renderTaskService.clearRenderTask(task)));
}
}