UNPKG

@analogjs/content

Version:

Content Rendering for Analog

236 lines (219 loc) 10.2 kB
import * as i0 from '@angular/core'; import { InjectionToken, Provider, AfterViewChecked, Signal, Type, AbstractType, ProviderToken } from '@angular/core'; import * as rxjs from 'rxjs'; import { Observable } from 'rxjs'; import * as mermaid from 'mermaid'; import { SafeHtml } from '@angular/platform-browser'; import * as marked from 'marked'; import { marked as marked$1 } from 'marked'; declare class AnchorNavigationDirective { private readonly document; private readonly location; private readonly router; handleNavigation(element: EventTarget | null): boolean; static ɵfac: i0.ɵɵFactoryDeclaration<AnchorNavigationDirective, never>; static ɵdir: i0.ɵɵDirectiveDeclaration<AnchorNavigationDirective, "[analogAnchorNavigation]", never, {}, {}, never, never, true, never>; } type TableOfContentItem = { id: string; level: number; text: string; }; type RenderedContent = { content: string; toc: TableOfContentItem[]; }; declare abstract class ContentRenderer { render(content: string): Promise<RenderedContent>; getContentHeadings(_content: string): TableOfContentItem[]; enhance(): void; static ɵfac: i0.ɵɵFactoryDeclaration<ContentRenderer, never>; static ɵprov: i0.ɵɵInjectableDeclaration<ContentRenderer>; } declare class NoopContentRenderer implements ContentRenderer { private readonly transferState; private contentId; /** * Generates a hash from the content string * to be used with the transfer state */ private generateHash; render(content: string): Promise<RenderedContent>; enhance(): void; getContentHeadings(content: string): TableOfContentItem[]; private extractHeadings; private extractHeadingsFromMarkdown; private extractHeadingsFromHtml; private makeSlug; } interface ContentFile<Attributes extends Record<string, any> = Record<string, any>> { filename: string; slug: string; content?: string | object; attributes: Attributes; toc?: TableOfContentItem[]; } /** * 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') */ declare function injectContent<Attributes extends Record<string, any> = Record<string, any>>(param?: string | { param: string; subdirectory: string; } | { customFilename: string; }, fallback?: string): Observable<ContentFile<Attributes | Record<string, never>>>; declare function injectContentFiles<Attributes extends Record<string, any>>(filterFn?: InjectContentFilesFilterFunction<Attributes>): ContentFile<Attributes>[]; type InjectContentFilesFilterFunction<T extends Record<string, any>> = (value: ContentFile<T>, index: number, array: ContentFile<T>[]) => boolean; declare function injectContentFilesMap(): Record<string, () => Promise<string>>; declare class MarkdownContentRendererService implements ContentRenderer { #private; render(content: string): Promise<RenderedContent>; getContentHeadings(content: string): TableOfContentItem[]; enhance(): void; static ɵfac: i0.ɵɵFactoryDeclaration<MarkdownContentRendererService, never>; static ɵprov: i0.ɵɵInjectableDeclaration<MarkdownContentRendererService>; } interface MarkdownRendererOptions { loadMermaid?: () => Promise<typeof mermaid>; } declare function withMarkdownRenderer(options?: MarkdownRendererOptions): Provider; declare function provideContent(...features: Provider[]): Provider[]; declare const MERMAID_IMPORT_TOKEN: InjectionToken<Promise<typeof mermaid>>; declare class AnalogMarkdownRouteComponent implements AfterViewChecked { private sanitizer; private route; contentRenderer: ContentRenderer; protected content: SafeHtml; classes: string; ngAfterViewChecked(): void; static ɵfac: i0.ɵɵFactoryDeclaration<AnalogMarkdownRouteComponent, never>; static ɵcmp: i0.ɵɵComponentDeclaration<AnalogMarkdownRouteComponent, "analog-markdown-route", never, { "classes": { "alias": "classes"; "required": false; }; }, {}, never, never, true, [{ directive: typeof AnchorNavigationDirective; inputs: {}; outputs: {}; }]>; } declare class AnalogMarkdownComponent implements AfterViewChecked { private sanitizer; private route; private zone; private readonly platformId; private readonly mermaidImport; private mermaid; private contentSource; readonly htmlContent: Signal<SafeHtml | undefined>; readonly content: i0.InputSignal<string | object | null | undefined>; readonly classes: i0.InputSignal<string>; contentRenderer: ContentRenderer; constructor(); getContentSource(): rxjs.Observable<string | SafeHtml>; renderContent(content: string): Promise<string>; ngAfterViewChecked(): void; private loadMermaid; static ɵfac: i0.ɵɵFactoryDeclaration<AnalogMarkdownComponent, never>; static ɵcmp: i0.ɵɵComponentDeclaration<AnalogMarkdownComponent, "analog-markdown", never, { "content": { "alias": "content"; "required": false; "isSignal": true; }; "classes": { "alias": "classes"; "required": false; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof AnchorNavigationDirective; inputs: {}; outputs: {}; }]>; } declare function parseRawContentFile<Attributes extends Record<string, any>>(rawContentFile: string): { content: string; attributes: Attributes; }; declare class MarkedSetupService { private readonly marked; private readonly highlighter; constructor(); getMarkedInstance(): typeof marked$1; static ɵfac: i0.ɵɵFactoryDeclaration<MarkedSetupService, never>; static ɵprov: i0.ɵɵInjectableDeclaration<MarkedSetupService>; } interface MarkedContentHighlighter { augmentCodeBlock?(code: string, lang: string): string; } declare abstract class MarkedContentHighlighter { abstract getHighlightExtension(): marked.MarkedExtension; static ɵfac: i0.ɵɵFactoryDeclaration<MarkedContentHighlighter, never>; static ɵprov: i0.ɵɵInjectableDeclaration<MarkedContentHighlighter>; } declare function withHighlighter(provider: ({ useValue: MarkedContentHighlighter; } | { useClass: Type<MarkedContentHighlighter> | AbstractType<MarkedContentHighlighter>; } | { useFactory: (...deps: any[]) => MarkedContentHighlighter; }) & { deps?: ProviderToken<any>[]; }): Provider; type ContentListLoaderFunction<Attributes extends Record<string, any>> = () => Promise<ContentFile<Attributes>[]>; declare const CONTENT_LIST_LOADER: InjectionToken<ContentListLoaderFunction<any>>; declare function injectContentListLoader<Attributes extends Record<string, any>>(): ContentListLoaderFunction<Attributes>; declare function withContentListLoader(): Provider; type ContentFileLoaderFunction = () => Promise<Record<string, () => Promise<string>>>; declare const CONTENT_FILE_LOADER: InjectionToken<ContentFileLoaderFunction>; declare function injectContentFileLoader(): ContentFileLoaderFunction; declare function withContentFileLoader(): Provider; /** * Token for the active content locale. * Provided via `withLocale()` in `provideContent()`. * * When set, `injectContentFiles()` filters to content matching this locale, * and `injectContent()` resolves locale-prefixed content paths first. */ declare const CONTENT_LOCALE: InjectionToken<string>; /** * Injects the content locale, returning null if not configured. */ declare function injectContentLocale(): string | null; interface ContentLocaleOptions { /** * Function that returns the active locale. * Runs in injection context so `inject()` can be used to read * from other tokens (e.g., a LOCALE token from a router package). * * ```typescript * withLocale({ loadLocale: injectLocale }) * withLocale({ loadLocale: () => navigator.language.split('-')[0] }) * ``` */ loadLocale: () => string | null; } /** * Content feature that sets the active locale for content resolution. * * When provided, content APIs become locale-aware: * - `injectContentFiles()` filters to files in the locale subdirectory * or with a matching `locale` frontmatter attribute. * - `injectContent()` tries locale-prefixed paths first * (e.g., `content/fr/blog/post.md` before `content/blog/post.md`). * * Usage: * ```typescript * // With loader — runs in injection context * provideContent( * withMarkdownRenderer(), * withLocale({ loadLocale: injectLocale }), * ) * * // Static locale * provideContent( * withMarkdownRenderer(), * withLocale('fr'), * ) * ``` */ declare function withLocale(locale: string | ContentLocaleOptions): Provider; /** * Filters content files by locale using map-based key lookup. * * Matching rules: * 1. Frontmatter `locale` attribute matches the active locale. * 2. File is in the active locale subdirectory (e.g., `/content/fr/blog/post`). * 3. File has no locale marker and no localized variant exists — included as universal content. * * Files in a different locale's subdirectory are always excluded. */ declare function filterByLocale<T extends Record<string, any>>(files: ContentFile<T>[], locale: string): ContentFile<T>[]; /** * Prepends locale-prefixed candidates before the standard candidates * for content file map key lookup. */ declare function withLocaleCandidates(candidates: string[], locale: string | null | undefined): string[]; export { AnchorNavigationDirective, CONTENT_FILE_LOADER, CONTENT_LIST_LOADER, CONTENT_LOCALE, ContentRenderer, MERMAID_IMPORT_TOKEN, AnalogMarkdownComponent as MarkdownComponent, MarkdownContentRendererService, AnalogMarkdownRouteComponent as MarkdownRouteComponent, MarkedContentHighlighter, MarkedSetupService, NoopContentRenderer, filterByLocale, injectContent, injectContentFileLoader, injectContentFiles, injectContentFilesMap, injectContentListLoader, injectContentLocale, parseRawContentFile, provideContent, withContentFileLoader, withContentListLoader, withHighlighter, withLocale, withLocaleCandidates, withMarkdownRenderer }; export type { ContentFile, InjectContentFilesFilterFunction };