@doug-williamson/ng-rhombus 2.0.0-beta.2 → 2.0.0-beta.4

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.
@@ -401,6 +401,11 @@ const NG_RHOMBUS_SEO_ADAPTER = new InjectionToken('NG_RHOMBUS_SEO_ADAPTER', {
401
401
  }),
402
402
  });
403
403
 
404
+ const NG_RHOMBUS_SITE_METADATA = new InjectionToken('NG_RHOMBUS_SITE_METADATA', {
405
+ providedIn: 'root',
406
+ factory: () => ({}),
407
+ });
408
+
404
409
  /*
405
410
  * Public API Surface of @doug-williamson/ng-rhombus/shell
406
411
  */
@@ -429,14 +434,14 @@ function ngRhombusTimestampToMillis(value) {
429
434
  }
430
435
  return null;
431
436
  }
432
- var ContentPillar;
433
- (function (ContentPillar) {
434
- ContentPillar["DeveloperLife"] = "Developer Life";
435
- ContentPillar["AngularWebEngineering"] = "Angular & Web Engineering";
436
- ContentPillar["GamingAsAnAdult"] = "Gaming as an Adult";
437
- ContentPillar["FatherhoodFamily"] = "Fatherhood & Family";
438
- ContentPillar["CareerBalanceIdentity"] = "Career, Balance & Identity";
439
- })(ContentPillar || (ContentPillar = {}));
437
+ var ContentDimension;
438
+ (function (ContentDimension) {
439
+ ContentDimension["DeveloperLife"] = "Developer Life";
440
+ ContentDimension["AngularWebEngineering"] = "Angular & Web Engineering";
441
+ ContentDimension["GamingAsAnAdult"] = "Gaming as an Adult";
442
+ ContentDimension["FatherhoodFamily"] = "Fatherhood & Family";
443
+ ContentDimension["CareerBalanceIdentity"] = "Career, Balance & Identity";
444
+ })(ContentDimension || (ContentDimension = {}));
440
445
  var BlogSeries;
441
446
  (function (BlogSeries) {
442
447
  BlogSeries["ThisWeekILearned"] = "This Week I Learned";
@@ -446,48 +451,68 @@ var BlogSeries;
446
451
  BlogSeries["TradeoffsTruths"] = "Tradeoffs & Truths";
447
452
  BlogSeries["FromTheEditor"] = "From The Editor";
448
453
  })(BlogSeries || (BlogSeries = {}));
449
- class IBlog {
450
- }
451
454
 
452
455
  class NgRhombusBlogListComponent {
453
456
  constructor() {
454
457
  this.goToRoute = new EventEmitter();
455
458
  this.#seo = inject(NG_RHOMBUS_SEO_ADAPTER);
456
- this.#platformId = inject(PLATFORM_ID);
457
459
  this.#document = inject(DOCUMENT);
460
+ this.#site = inject(NG_RHOMBUS_SITE_METADATA);
458
461
  this.dataSource = input([], ...(ngDevMode ? [{ debugName: "dataSource" }] : []));
459
462
  this.timestampToMillis = ngRhombusTimestampToMillis;
460
463
  }
461
464
  #seo;
462
- #platformId;
463
465
  #document;
466
+ #site;
467
+ hasDimensions(post) {
468
+ return Boolean(post.dimensions?.length);
469
+ }
470
+ firstDimension(post) {
471
+ const dims = post.dimensions;
472
+ return dims && dims.length ? dims[0] : undefined;
473
+ }
474
+ hasTaxonomy(post) {
475
+ return this.hasDimensions(post) || Boolean(post.series) || Boolean(post.tags?.length);
476
+ }
477
+ getDisplayDate(post) {
478
+ return post.publishedAt ?? post.publishAt ?? post.createdAt ?? post.updatedAt;
479
+ }
464
480
  ngOnInit() {
465
- const origin = isPlatformBrowser(this.#platformId) ? this.#document.location?.origin : undefined;
466
- const imageUrl = origin ? new URL('/fav.ico', origin).toString() : '/fav.ico';
481
+ const origin = this.#site.origin ?? this.#document.location?.origin;
482
+ const path = this.#document.location?.pathname ?? '/latest';
483
+ const pageUrl = origin ? new URL(path, origin).toString() : path;
484
+ const imagePath = '/favicon.ico';
485
+ const imageUrl = origin ? new URL(imagePath, origin).toString() : imagePath;
486
+ const siteName = this.#site.siteName ?? 'Rhombus Software';
467
487
  // Document title
468
488
  this.#seo.setTitle('Blog - Doug Williamson');
469
489
  // Basic meta
470
490
  this.#seo.updateTag({ name: 'description', content: 'This is my personal collection of blog posts.' });
471
491
  // Open Graph
472
- this.#seo.updateTag({ property: 'og:type', content: 'article' });
492
+ this.#seo.updateTag({ property: 'og:type', content: 'website' });
493
+ this.#seo.updateTag({ property: 'og:site_name', content: siteName });
473
494
  this.#seo.updateTag({ property: 'og:title', content: 'Blog - Doug Williamson' });
474
495
  this.#seo.updateTag({ property: 'og:description', content: 'This is my personal collection of blog posts.' });
496
+ this.#seo.updateTag({ property: 'og:url', content: pageUrl });
475
497
  this.#seo.updateTag({ property: 'og:image', content: imageUrl });
476
498
  // Twitter Card
477
499
  this.#seo.updateTag({ name: 'twitter:card', content: 'summary' });
500
+ if (this.#site.twitterSite)
501
+ this.#seo.updateTag({ name: 'twitter:site', content: this.#site.twitterSite });
478
502
  this.#seo.updateTag({ name: 'twitter:title', content: 'Blog - Doug Williamson' });
479
503
  this.#seo.updateTag({ name: 'twitter:description', content: 'This is my personal collection of blog posts.' });
504
+ this.#seo.updateTag({ name: 'twitter:url', content: pageUrl });
480
505
  this.#seo.updateTag({ name: 'twitter:image', content: imageUrl });
481
506
  }
482
507
  goToBlogPost(id) {
483
508
  this.goToRoute.emit(id);
484
509
  }
485
510
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgRhombusBlogListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
486
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.4", type: NgRhombusBlogListComponent, isStandalone: true, selector: "ng-rhombus-blog-list", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { goToRoute: "goToRoute" }, ngImport: i0, template: "@if ((dataSource()).length === 0) {\r\n<p class=\"m-6 justify-self-center\">No blog posts found.</p>\r\n} @else {\r\n<mat-nav-list>\r\n\t@for (blogPost of dataSource(); track blogPost.id; let last = $last) {\r\n\t<mat-list-item (click)=\"goToRoute.emit(blogPost.id)\" lines=\"2\">\r\n\t\t<h3 matListItemTitle>{{ blogPost.title }}</h3>\r\n\t\t<p matListItemMeta>{{ timestampToMillis(blogPost.timestamp) | date: 'MMMM d, y' }}</p>\r\n\r\n\t\t@if (blogPost.pillar || blogPost.series || (blogPost.tags?.length ?? 0) > 0) {\r\n\t\t<div matListItemLine class=\"taxonomy\">\r\n\t\t\t<mat-chip-set aria-label=\"Post taxonomy\">\r\n\t\t\t\t@if (blogPost.pillar) {\r\n\t\t\t\t<mat-chip [highlighted]=\"true\" class=\"primary-chips-theme\">Pillar: {{ blogPost.pillar }}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t\t@if (blogPost.series) {\r\n\t\t\t\t<mat-chip [highlighted]=\"true\" class=\"secondary-chips-theme\">Series: {{ blogPost.series }}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t\t<!-- @for (t of blogPost.tags ?? []; track t) {\r\n\t\t\t\t<mat-chip [highlighted]=\"true\" class=\"neutral-chips-theme\">#{{ t }}</mat-chip>\r\n\t\t\t\t} -->\r\n\t\t\t</mat-chip-set>\r\n\t\t</div>\r\n\t\t}\r\n\t</mat-list-item>\r\n\t@if (!last) {\r\n\t<mat-divider></mat-divider>\r\n\t}\r\n\t}\r\n</mat-nav-list>\r\n}", styles: [".neutral-chips-theme{--mat-chip-outline-color: var(--mat-sys-surface-variant);--mat-chip-elevated-selected-container-color: var(--mat-sys-surface-variant);--mat-chip-selected-label-text-color: var(--mat-sys-on-surface-variant);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.primary-chips-theme{--mat-chip-outline-color: var(--mat-sys-primary);--mat-chip-elevated-selected-container-color: var(--mat-sys-primary);--mat-chip-selected-label-text-color: var(--mat-sys-on-primary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.secondary-chips-theme{--mat-chip-outline-color: var(--mat-sys-secondary);--mat-chip-elevated-selected-container-color: var(--mat-sys-secondary);--mat-chip-selected-label-text-color: var(--mat-sys-on-secondary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.mdc-list{padding:0}.mdc-list-item{border-radius:0!important;height:auto;padding:12px 16px}.taxonomy mat-chip-set{max-width:100%}\n"], dependencies: [{ kind: "ngmodule", type: MatListModule }, { kind: "component", type: i1$2.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "component", type: i1$2.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "component", type: i1$2.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i1$2.MatListItemLine, selector: "[matListItemLine]" }, { kind: "directive", type: i1$2.MatListItemTitle, selector: "[matListItemTitle]" }, { kind: "directive", type: i1$2.MatListItemMeta, selector: "[matListItemMeta]" }, { kind: "ngmodule", type: MatDividerModule }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i2$3.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "component", type: i2$3.MatChipSet, selector: "mat-chip-set", inputs: ["disabled", "role", "tabIndex"] }, { kind: "pipe", type: DatePipe, name: "date" }] }); }
511
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.4", type: NgRhombusBlogListComponent, isStandalone: true, selector: "ng-rhombus-blog-list", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { goToRoute: "goToRoute" }, ngImport: i0, template: "@if ((dataSource()).length === 0) {\r\n<p class=\"m-6 justify-self-center\">No blog posts found.</p>\r\n} @else {\r\n<mat-nav-list>\r\n\t@for (blogPost of dataSource(); track blogPost.id; let last = $last) {\r\n\t<mat-list-item (click)=\"goToRoute.emit(blogPost.id)\" lines=\"2\">\r\n\t\t<h3 matListItemTitle>{{ blogPost.title }}</h3>\r\n\t\t<p matListItemMeta>{{ timestampToMillis(getDisplayDate(blogPost)) | date: 'MMMM d, y' }}</p>\r\n\r\n\t\t@if (hasTaxonomy(blogPost)) {\r\n\t\t<div matListItemLine class=\"taxonomy\">\r\n\t\t\t<mat-chip-set aria-label=\"Post taxonomy\">\r\n\t\t\t\t@if (hasDimensions(blogPost)) {\r\n\t\t\t\t<mat-chip [highlighted]=\"true\" class=\"primary-chips-theme\">Dimension: {{ firstDimension(blogPost)\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t\t@if (blogPost.series) {\r\n\t\t\t\t<mat-chip [highlighted]=\"true\" class=\"secondary-chips-theme\">Series: {{ blogPost.series }}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t\t<!-- @for (t of blogPost.tags ?? []; track t) {\r\n\t\t\t\t<mat-chip [highlighted]=\"true\" class=\"neutral-chips-theme\">#{{ t }}</mat-chip>\r\n\t\t\t\t} -->\r\n\t\t\t</mat-chip-set>\r\n\t\t</div>\r\n\t\t}\r\n\t</mat-list-item>\r\n\t@if (!last) {\r\n\t<mat-divider></mat-divider>\r\n\t}\r\n\t}\r\n</mat-nav-list>\r\n}", styles: [".neutral-chips-theme{--mat-chip-outline-color: var(--mat-sys-surface-variant);--mat-chip-elevated-selected-container-color: var(--mat-sys-surface-variant);--mat-chip-selected-label-text-color: var(--mat-sys-on-surface-variant);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.primary-chips-theme{--mat-chip-outline-color: var(--mat-sys-primary);--mat-chip-elevated-selected-container-color: var(--mat-sys-primary);--mat-chip-selected-label-text-color: var(--mat-sys-on-primary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.secondary-chips-theme{--mat-chip-outline-color: var(--mat-sys-secondary);--mat-chip-elevated-selected-container-color: var(--mat-sys-secondary);--mat-chip-selected-label-text-color: var(--mat-sys-on-secondary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.mdc-list{padding:0}.mdc-list-item{border-radius:0!important;height:auto;padding:12px 16px}.taxonomy mat-chip-set{max-width:100%}\n"], dependencies: [{ kind: "ngmodule", type: MatListModule }, { kind: "component", type: i1$2.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "component", type: i1$2.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "component", type: i1$2.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i1$2.MatListItemLine, selector: "[matListItemLine]" }, { kind: "directive", type: i1$2.MatListItemTitle, selector: "[matListItemTitle]" }, { kind: "directive", type: i1$2.MatListItemMeta, selector: "[matListItemMeta]" }, { kind: "ngmodule", type: MatDividerModule }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i2$3.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "component", type: i2$3.MatChipSet, selector: "mat-chip-set", inputs: ["disabled", "role", "tabIndex"] }, { kind: "pipe", type: DatePipe, name: "date" }] }); }
487
512
  }
488
513
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgRhombusBlogListComponent, decorators: [{
489
514
  type: Component,
490
- args: [{ selector: 'ng-rhombus-blog-list', imports: [DatePipe, MatListModule, MatDividerModule, MatChipsModule], template: "@if ((dataSource()).length === 0) {\r\n<p class=\"m-6 justify-self-center\">No blog posts found.</p>\r\n} @else {\r\n<mat-nav-list>\r\n\t@for (blogPost of dataSource(); track blogPost.id; let last = $last) {\r\n\t<mat-list-item (click)=\"goToRoute.emit(blogPost.id)\" lines=\"2\">\r\n\t\t<h3 matListItemTitle>{{ blogPost.title }}</h3>\r\n\t\t<p matListItemMeta>{{ timestampToMillis(blogPost.timestamp) | date: 'MMMM d, y' }}</p>\r\n\r\n\t\t@if (blogPost.pillar || blogPost.series || (blogPost.tags?.length ?? 0) > 0) {\r\n\t\t<div matListItemLine class=\"taxonomy\">\r\n\t\t\t<mat-chip-set aria-label=\"Post taxonomy\">\r\n\t\t\t\t@if (blogPost.pillar) {\r\n\t\t\t\t<mat-chip [highlighted]=\"true\" class=\"primary-chips-theme\">Pillar: {{ blogPost.pillar }}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t\t@if (blogPost.series) {\r\n\t\t\t\t<mat-chip [highlighted]=\"true\" class=\"secondary-chips-theme\">Series: {{ blogPost.series }}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t\t<!-- @for (t of blogPost.tags ?? []; track t) {\r\n\t\t\t\t<mat-chip [highlighted]=\"true\" class=\"neutral-chips-theme\">#{{ t }}</mat-chip>\r\n\t\t\t\t} -->\r\n\t\t\t</mat-chip-set>\r\n\t\t</div>\r\n\t\t}\r\n\t</mat-list-item>\r\n\t@if (!last) {\r\n\t<mat-divider></mat-divider>\r\n\t}\r\n\t}\r\n</mat-nav-list>\r\n}", styles: [".neutral-chips-theme{--mat-chip-outline-color: var(--mat-sys-surface-variant);--mat-chip-elevated-selected-container-color: var(--mat-sys-surface-variant);--mat-chip-selected-label-text-color: var(--mat-sys-on-surface-variant);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.primary-chips-theme{--mat-chip-outline-color: var(--mat-sys-primary);--mat-chip-elevated-selected-container-color: var(--mat-sys-primary);--mat-chip-selected-label-text-color: var(--mat-sys-on-primary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.secondary-chips-theme{--mat-chip-outline-color: var(--mat-sys-secondary);--mat-chip-elevated-selected-container-color: var(--mat-sys-secondary);--mat-chip-selected-label-text-color: var(--mat-sys-on-secondary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.mdc-list{padding:0}.mdc-list-item{border-radius:0!important;height:auto;padding:12px 16px}.taxonomy mat-chip-set{max-width:100%}\n"] }]
515
+ args: [{ selector: 'ng-rhombus-blog-list', imports: [DatePipe, MatListModule, MatDividerModule, MatChipsModule], template: "@if ((dataSource()).length === 0) {\r\n<p class=\"m-6 justify-self-center\">No blog posts found.</p>\r\n} @else {\r\n<mat-nav-list>\r\n\t@for (blogPost of dataSource(); track blogPost.id; let last = $last) {\r\n\t<mat-list-item (click)=\"goToRoute.emit(blogPost.id)\" lines=\"2\">\r\n\t\t<h3 matListItemTitle>{{ blogPost.title }}</h3>\r\n\t\t<p matListItemMeta>{{ timestampToMillis(getDisplayDate(blogPost)) | date: 'MMMM d, y' }}</p>\r\n\r\n\t\t@if (hasTaxonomy(blogPost)) {\r\n\t\t<div matListItemLine class=\"taxonomy\">\r\n\t\t\t<mat-chip-set aria-label=\"Post taxonomy\">\r\n\t\t\t\t@if (hasDimensions(blogPost)) {\r\n\t\t\t\t<mat-chip [highlighted]=\"true\" class=\"primary-chips-theme\">Dimension: {{ firstDimension(blogPost)\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t\t@if (blogPost.series) {\r\n\t\t\t\t<mat-chip [highlighted]=\"true\" class=\"secondary-chips-theme\">Series: {{ blogPost.series }}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t\t<!-- @for (t of blogPost.tags ?? []; track t) {\r\n\t\t\t\t<mat-chip [highlighted]=\"true\" class=\"neutral-chips-theme\">#{{ t }}</mat-chip>\r\n\t\t\t\t} -->\r\n\t\t\t</mat-chip-set>\r\n\t\t</div>\r\n\t\t}\r\n\t</mat-list-item>\r\n\t@if (!last) {\r\n\t<mat-divider></mat-divider>\r\n\t}\r\n\t}\r\n</mat-nav-list>\r\n}", styles: [".neutral-chips-theme{--mat-chip-outline-color: var(--mat-sys-surface-variant);--mat-chip-elevated-selected-container-color: var(--mat-sys-surface-variant);--mat-chip-selected-label-text-color: var(--mat-sys-on-surface-variant);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.primary-chips-theme{--mat-chip-outline-color: var(--mat-sys-primary);--mat-chip-elevated-selected-container-color: var(--mat-sys-primary);--mat-chip-selected-label-text-color: var(--mat-sys-on-primary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.secondary-chips-theme{--mat-chip-outline-color: var(--mat-sys-secondary);--mat-chip-elevated-selected-container-color: var(--mat-sys-secondary);--mat-chip-selected-label-text-color: var(--mat-sys-on-secondary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.mdc-list{padding:0}.mdc-list-item{border-radius:0!important;height:auto;padding:12px 16px}.taxonomy mat-chip-set{max-width:100%}\n"] }]
491
516
  }], propDecorators: { goToRoute: [{
492
517
  type: Output
493
518
  }], dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }] } });
@@ -497,12 +522,17 @@ class NgRhombusBlogPostLatestComponent {
497
522
  this.blogPost = input(...(ngDevMode ? [undefined, { debugName: "blogPost" }] : []));
498
523
  this.timestampToMillis = ngRhombusTimestampToMillis;
499
524
  }
525
+ getDisplayDate(post) {
526
+ if (!post)
527
+ return null;
528
+ return post.publishedAt ?? post.publishAt ?? post.createdAt ?? post.updatedAt;
529
+ }
500
530
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgRhombusBlogPostLatestComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
501
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.4", type: NgRhombusBlogPostLatestComponent, isStandalone: true, selector: "ng-rhombus-blog-post-latest", inputs: { blogPost: { classPropertyName: "blogPost", publicName: "blogPost", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<mat-nav-list>\r\n <mat-list-item [routerLink]=\"['/blog', blogPost()?.id]\">\r\n <span matListItemTitle>{{ blogPost()?.title }}</span>\r\n <span matListItemLine>{{ blogPost()?.description }}</span>\r\n <span matListItemLine>{{ timestampToMillis(blogPost()?.timestamp) | date: 'MMMM d, y' }}</span>\r\n </mat-list-item>\r\n</mat-nav-list>", styles: [".mdc-list-item{border-radius:0!important}\n"], dependencies: [{ kind: "ngmodule", type: MatListModule }, { kind: "component", type: i1$2.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "component", type: i1$2.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "directive", type: i1$2.MatListItemLine, selector: "[matListItemLine]" }, { kind: "directive", type: i1$2.MatListItemTitle, selector: "[matListItemTitle]" }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: DatePipe, name: "date" }] }); }
531
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.4", type: NgRhombusBlogPostLatestComponent, isStandalone: true, selector: "ng-rhombus-blog-post-latest", inputs: { blogPost: { classPropertyName: "blogPost", publicName: "blogPost", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<mat-nav-list>\r\n <mat-list-item [routerLink]=\"['/blog', blogPost()?.id]\">\r\n <span matListItemTitle>{{ blogPost()?.title }}</span>\r\n <span matListItemLine>{{ blogPost()?.excerpt ?? blogPost()?.description }}</span>\r\n <span matListItemLine>{{ timestampToMillis(getDisplayDate(blogPost())) | date: 'MMMM d, y' }}</span>\r\n </mat-list-item>\r\n</mat-nav-list>", styles: [".mdc-list-item{border-radius:0!important}\n"], dependencies: [{ kind: "ngmodule", type: MatListModule }, { kind: "component", type: i1$2.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "component", type: i1$2.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "directive", type: i1$2.MatListItemLine, selector: "[matListItemLine]" }, { kind: "directive", type: i1$2.MatListItemTitle, selector: "[matListItemTitle]" }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: DatePipe, name: "date" }] }); }
502
532
  }
503
533
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgRhombusBlogPostLatestComponent, decorators: [{
504
534
  type: Component,
505
- args: [{ selector: 'ng-rhombus-blog-post-latest', imports: [DatePipe, MatListModule, RouterLink], template: "<mat-nav-list>\r\n <mat-list-item [routerLink]=\"['/blog', blogPost()?.id]\">\r\n <span matListItemTitle>{{ blogPost()?.title }}</span>\r\n <span matListItemLine>{{ blogPost()?.description }}</span>\r\n <span matListItemLine>{{ timestampToMillis(blogPost()?.timestamp) | date: 'MMMM d, y' }}</span>\r\n </mat-list-item>\r\n</mat-nav-list>", styles: [".mdc-list-item{border-radius:0!important}\n"] }]
535
+ args: [{ selector: 'ng-rhombus-blog-post-latest', imports: [DatePipe, MatListModule, RouterLink], template: "<mat-nav-list>\r\n <mat-list-item [routerLink]=\"['/blog', blogPost()?.id]\">\r\n <span matListItemTitle>{{ blogPost()?.title }}</span>\r\n <span matListItemLine>{{ blogPost()?.excerpt ?? blogPost()?.description }}</span>\r\n <span matListItemLine>{{ timestampToMillis(getDisplayDate(blogPost())) | date: 'MMMM d, y' }}</span>\r\n </mat-list-item>\r\n</mat-nav-list>", styles: [".mdc-list-item{border-radius:0!important}\n"] }]
506
536
  }], propDecorators: { blogPost: [{ type: i0.Input, args: [{ isSignal: true, alias: "blogPost", required: false }] }] } });
507
537
 
508
538
  class NgRhombusBlogPostHelper {
@@ -518,6 +548,21 @@ class NgRhombusBlogPostHelper {
518
548
  const randomThreeDigitNumber = Math.floor(Math.random() * 1000);
519
549
  return `${slug}-${randomThreeDigitNumber}`;
520
550
  }
551
+ static buildSnippet(content, limit = 280) {
552
+ if (!content)
553
+ return '';
554
+ const firstParagraph = content.split(/\n\s*\n/)[0] ?? content;
555
+ const normalized = firstParagraph
556
+ .replace(/<[^>]+>/g, '')
557
+ .replace(/\s+/g, ' ')
558
+ .trim();
559
+ if (normalized.length <= limit)
560
+ return normalized;
561
+ const trimmed = normalized.slice(0, limit);
562
+ const lastSpace = trimmed.lastIndexOf(' ');
563
+ const safeCut = lastSpace > 0 ? trimmed.slice(0, lastSpace) : trimmed;
564
+ return `${safeCut.trim()}...`;
565
+ }
521
566
  }
522
567
 
523
568
  const NG_RHOMBUS_BLOG_ADAPTER = new InjectionToken('NG_RHOMBUS_BLOG_ADAPTER', {
@@ -550,6 +595,9 @@ const NG_RHOMBUS_BLOG_ADAPTER = new InjectionToken('NG_RHOMBUS_BLOG_ADAPTER', {
550
595
  updateBlogPost: async () => {
551
596
  throw new Error('NG_RHOMBUS_BLOG_ADAPTER is not provided.');
552
597
  },
598
+ updateQueueOrder: async () => {
599
+ throw new Error('NG_RHOMBUS_BLOG_ADAPTER is not provided.');
600
+ },
553
601
  deleteBlogPost: async () => {
554
602
  throw new Error('NG_RHOMBUS_BLOG_ADAPTER is not provided.');
555
603
  },
@@ -563,15 +611,71 @@ class NgRhombusBlogService {
563
611
  this.blogPosts = signal([], ...(ngDevMode ? [{ debugName: "blogPosts" }] : []));
564
612
  this.selectedBlogPost = signal(undefined, ...(ngDevMode ? [{ debugName: "selectedBlogPost" }] : []));
565
613
  }
614
+ normalizeDimensions(raw) {
615
+ const asArray = (value) => {
616
+ if (Array.isArray(value))
617
+ return value.map(v => `${v}`.trim()).filter(Boolean);
618
+ if (typeof value === 'string')
619
+ return [`${value}`.trim()].filter(Boolean);
620
+ return undefined;
621
+ };
622
+ const fromDimensions = asArray(raw?.dimensions);
623
+ const fromPillars = asArray(raw?.pillars);
624
+ const fromDimension = asArray(raw?.dimension ?? raw?.pillar);
625
+ const merged = [fromDimensions, fromPillars, fromDimension].filter(Boolean).flat();
626
+ return Array.from(new Set(merged));
627
+ }
566
628
  normalizeBlogPost(post) {
567
- const timestampMillis = ngRhombusTimestampToMillis(post.timestamp);
629
+ const coerceTimestamp = (value) => {
630
+ if (value == null)
631
+ return undefined;
632
+ const millis = ngRhombusTimestampToMillis(value);
633
+ if (millis != null)
634
+ return millis;
635
+ if (value instanceof Date)
636
+ return value;
637
+ if (typeof value === 'number' || typeof value === 'string')
638
+ return value;
639
+ const maybeSeconds = value;
640
+ if (typeof maybeSeconds.seconds === 'number')
641
+ return maybeSeconds;
642
+ const maybeToMillis = value;
643
+ if (typeof maybeToMillis.toMillis === 'function') {
644
+ const result = maybeToMillis.toMillis();
645
+ if (Number.isFinite(result))
646
+ return result;
647
+ }
648
+ return undefined;
649
+ };
650
+ const createdAt = coerceTimestamp(post.createdAt) ?? Date.now();
651
+ const updatedAt = coerceTimestamp(post.updatedAt) ?? createdAt;
652
+ const publishAt = coerceTimestamp(post.publishAt);
653
+ const publishedAt = post.publishedAt
654
+ ? coerceTimestamp(post.publishedAt)
655
+ : coerceTimestamp(post.timestamp);
656
+ const excerpt = post.excerpt ?? post.description ?? '';
657
+ const dimensions = this.normalizeDimensions(post);
658
+ const readingTime = post.readingTime ?? post.readTimeMinutes ?? this.calculateReadingTime(post.content);
659
+ const slug = post.slug ?? post.id;
660
+ const status = post.status ?? (publishedAt ? 'published' : 'draft');
568
661
  return {
569
662
  ...post,
570
- timestamp: timestampMillis ?? post.timestamp,
663
+ slug,
664
+ excerpt,
665
+ description: post.description ?? excerpt,
666
+ createdAt,
667
+ updatedAt,
668
+ publishAt,
669
+ publishedAt,
670
+ dimensions,
671
+ readingTime,
672
+ tags: post.tags ?? [],
673
+ status,
571
674
  };
572
675
  }
573
676
  async fetchBlogPosts() {
574
677
  const posts = (await this.blogAdapter.fetchBlogPosts()).map(p => this.normalizeBlogPost(p));
678
+ console.log('Fetched blog posts:', posts);
575
679
  this.blogPosts.set(posts);
576
680
  return posts;
577
681
  }
@@ -592,15 +696,46 @@ class NgRhombusBlogService {
592
696
  return normalized;
593
697
  }
594
698
  async createBlogPost(blogPost) {
595
- const id = NgRhombusBlogPostHelper.createSlug(blogPost.title);
699
+ const now = new Date();
700
+ const slug = blogPost.slug ?? NgRhombusBlogPostHelper.createSlug(blogPost.title);
701
+ const excerpt = blogPost.excerpt ?? blogPost.description ?? '';
702
+ const status = blogPost.status ?? 'draft';
703
+ const dimensions = this.normalizeDimensions(blogPost);
704
+ const readingTime = blogPost.readingTime ?? this.calculateReadingTime(blogPost.content);
705
+ const social = this.ensureSocialSnippet(blogPost.content, blogPost.social, status);
596
706
  await this.blogAdapter.createBlogPost({
597
707
  ...blogPost,
598
- id,
599
- timestamp: new Date(),
708
+ id: slug,
709
+ slug,
710
+ status,
711
+ excerpt,
712
+ description: blogPost.description ?? excerpt,
713
+ createdAt: blogPost.createdAt ?? now,
714
+ updatedAt: now,
715
+ publishAt: blogPost.publishAt,
716
+ publishedAt: blogPost.publishedAt,
717
+ queueOrder: blogPost.queueOrder,
718
+ dimensions,
719
+ readingTime,
720
+ social,
600
721
  });
601
722
  }
602
723
  async updateBlogPost(blogPost) {
603
- await this.blogAdapter.updateBlogPost(blogPost);
724
+ const now = new Date();
725
+ const status = blogPost.status ?? 'draft';
726
+ const excerpt = blogPost.excerpt ?? blogPost.description ?? '';
727
+ const dimensions = this.normalizeDimensions(blogPost);
728
+ const readingTime = blogPost.readingTime ?? this.calculateReadingTime(blogPost.content);
729
+ const social = this.ensureSocialSnippet(blogPost.content, blogPost.social, status);
730
+ await this.blogAdapter.updateBlogPost({
731
+ ...blogPost,
732
+ excerpt,
733
+ description: blogPost.description ?? excerpt,
734
+ updatedAt: now,
735
+ readingTime,
736
+ social,
737
+ dimensions,
738
+ });
604
739
  }
605
740
  deleteBlogPost(id) {
606
741
  return this.blogAdapter.deleteBlogPost(id);
@@ -640,12 +775,68 @@ class NgRhombusBlogService {
640
775
  nextOlder: result.nextOlder ? this.normalizeBlogPost(result.nextOlder) : undefined,
641
776
  };
642
777
  }
643
- calculateReadTimeMinutes(text) {
778
+ calculateReadingTime(text) {
644
779
  if (!text)
645
780
  return 1;
646
781
  const words = text.trim().split(/\s+/).length;
647
782
  return Math.max(1, Math.ceil(words / this.WORDS_PER_MINUTE));
648
783
  }
784
+ async saveQueueOrder(queue) {
785
+ const ordered = queue.map((post, idx) => ({
786
+ id: post.id,
787
+ queueOrder: idx + 1,
788
+ status: 'queued',
789
+ }));
790
+ if (this.blogAdapter.updateQueueOrder) {
791
+ await this.blogAdapter.updateQueueOrder(ordered);
792
+ return;
793
+ }
794
+ await Promise.all(ordered.map(update => this.blogAdapter.updateBlogPost(update)));
795
+ }
796
+ primaryDimension(post) {
797
+ if (!post)
798
+ return null;
799
+ const dims = this.normalizeDimensions(post);
800
+ return dims.length > 0 ? dims[0] : null;
801
+ }
802
+ dimensionsOf(post) {
803
+ if (!post)
804
+ return [];
805
+ return this.normalizeDimensions(post);
806
+ }
807
+ hasDimension(post, dimension) {
808
+ if (!dimension)
809
+ return false;
810
+ const dims = this.normalizeDimensions(post);
811
+ return dims.includes(dimension);
812
+ }
813
+ overlapDimensions(a, b) {
814
+ const dimsA = this.normalizeDimensions(a);
815
+ const dimsB = this.normalizeDimensions(b);
816
+ return dimsA.some(d => dimsB.includes(d));
817
+ }
818
+ async fetchRelatedPosts(current, opts = {}) {
819
+ const primaryLimit = opts.primaryLimit ?? 3;
820
+ const bridgeLimit = opts.bridgeLimit ?? 1;
821
+ const latest = await this.fetchLatestBlogPosts(Math.max(6, primaryLimit + bridgeLimit + 3));
822
+ const filtered = latest.filter(p => p.id !== current.id);
823
+ const primaryDimension = this.primaryDimension(current);
824
+ const primary = filtered.filter(p => this.overlapDimensions(p, current)).slice(0, primaryLimit);
825
+ let bridge = null;
826
+ if (bridgeLimit > 0) {
827
+ bridge = filtered.find(p => !this.hasDimension(p, primaryDimension)) ?? null;
828
+ }
829
+ return { primary, bridge };
830
+ }
831
+ ensureSocialSnippet(content, social, status) {
832
+ if (status !== 'draft')
833
+ return social;
834
+ const hasSnippet = social?.x && social.x.trim().length > 0;
835
+ if (hasSnippet)
836
+ return social;
837
+ const snippet = NgRhombusBlogPostHelper.buildSnippet(content, 280);
838
+ return { ...social, x: snippet };
839
+ }
649
840
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgRhombusBlogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
650
841
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgRhombusBlogService, providedIn: 'root' }); }
651
842
  }
@@ -662,11 +853,21 @@ class NgRhombusBlogTableComponent {
662
853
  this.dialog = inject(MatDialog);
663
854
  this.dataSource = input([], ...(ngDevMode ? [{ debugName: "dataSource" }] : []));
664
855
  this.timestampToMillis = ngRhombusTimestampToMillis;
665
- this.displayedColumns = ['title', 'pillar', 'series', 'timestamp'];
856
+ this.displayedColumns = ['title', 'status', 'dimension', 'series', 'publishedAt'];
666
857
  this.detailColumns = ['detail'];
667
858
  this.isMainRow = (_index, row) => row.kind === 'main';
668
859
  this.isDetailRow = (_index, row) => row.kind === 'detail';
669
860
  }
861
+ hasDimensions(post) {
862
+ return Boolean(post.dimensions?.length);
863
+ }
864
+ firstDimension(post) {
865
+ const dims = post.dimensions;
866
+ return dims && dims.length ? dims[0] : undefined;
867
+ }
868
+ getDisplayDate(post) {
869
+ return post.publishedAt ?? post.publishAt ?? post.createdAt ?? post.updatedAt;
870
+ }
670
871
  tableData() {
671
872
  const posts = this.dataSource();
672
873
  if (!posts?.length)
@@ -683,11 +884,11 @@ class NgRhombusBlogTableComponent {
683
884
  this.deleteEvent.emit(blogPost);
684
885
  }
685
886
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgRhombusBlogTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
686
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.4", type: NgRhombusBlogTableComponent, isStandalone: true, selector: "ng-rhombus-blog-table", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { editEvent: "editEvent", deleteEvent: "deleteEvent" }, ngImport: i0, template: "@if (dataSource().length > 0) {\r\n<table mat-table [dataSource]=\"tableData()\" class=\"mat-elevation-z1\" multiTemplateDataRows>\r\n\r\n\t<!-- Title Column -->\r\n\t<ng-container matColumnDef=\"title\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Title</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">{{ row.post.title }}</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Pillar Column -->\r\n\t<ng-container matColumnDef=\"pillar\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Pillar</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">\r\n\t\t\t@if (row.post.pillar) {\r\n\t\t\t<mat-chip-set aria-label=\"Pillar\" role=\"list\">\r\n\t\t\t\t<mat-chip role=\"listitem\" [highlighted]=\"true\" class=\"primary-chips-theme\">{{ row.post.pillar\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t</mat-chip-set>\r\n\t\t\t} @else {\r\n\t\t\t\u2014\r\n\t\t\t}\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Series Column -->\r\n\t<ng-container matColumnDef=\"series\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Series</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">\r\n\t\t\t@if (row.post.series) {\r\n\t\t\t<mat-chip-set aria-label=\"Series\" role=\"list\">\r\n\t\t\t\t<mat-chip role=\"listitem\" [highlighted]=\"true\" class=\"secondary-chips-theme\">{{ row.post.series\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t</mat-chip-set>\r\n\t\t\t} @else {\r\n\t\t\t\u2014\r\n\t\t\t}\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Timestamp Column -->\r\n\t<ng-container matColumnDef=\"timestamp\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Date</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">{{ timestampToMillis(row.post.timestamp) | date: 'MMMM d, y' }}</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Detail Row (full width) -->\r\n\t<ng-container matColumnDef=\"detail\">\r\n\t\t<td mat-cell *matCellDef=\"let row\" [attr.colspan]=\"displayedColumns.length\">\r\n\t\t\t<div class=\"detail-content\">\r\n\t\t\t\t@if (row.post.description) {\r\n\t\t\t\t<div class=\"detail-description\">{{ row.post.description }}</div>\r\n\t\t\t\t}\r\n\r\n\t\t\t\t<div class=\"detail-actions\">\r\n\t\t\t\t\t<button mat-icon-button (click)=\"goToBlogPost(row.post.id)\" aria-label=\"Edit blog post\">\r\n\t\t\t\t\t\t<mat-icon>edit</mat-icon>\r\n\t\t\t\t\t</button>\r\n\t\t\t\t\t<button mat-icon-button (click)=\"onDeleteBlogPost(row.post)\" aria-label=\"Delete blog post\">\r\n\t\t\t\t\t\t<mat-icon>delete</mat-icon>\r\n\t\t\t\t\t</button>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\r\n\t<tr mat-row *matRowDef=\"let row; columns: displayedColumns; when: isMainRow\"></tr>\r\n\t<tr mat-row *matRowDef=\"let row; columns: detailColumns; when: isDetailRow\" class=\"detail-row\"></tr>\r\n</table>\r\n} @else {\r\n<div class=\"empty-set\">\r\n\t<span>No blog posts created yet.</span>\r\n</div>\r\n\r\n}", styles: [".empty-set{margin:12px}.neutral-chips-theme{--mat-chip-outline-color: var(--mat-sys-surface-variant);--mat-chip-elevated-selected-container-color: var(--mat-sys-surface-variant);--mat-chip-selected-label-text-color: var(--mat-sys-on-surface-variant);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.primary-chips-theme{--mat-chip-outline-color: var(--mat-sys-primary);--mat-chip-elevated-selected-container-color: var(--mat-sys-primary);--mat-chip-selected-label-text-color: var(--mat-sys-on-primary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.secondary-chips-theme{--mat-chip-outline-color: var(--mat-sys-secondary);--mat-chip-elevated-selected-container-color: var(--mat-sys-secondary);--mat-chip-selected-label-text-color: var(--mat-sys-on-secondary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.rhombus{overflow-y:auto}.mat-column-source,.mat-column-actions{text-align:center}.mat-column-source fa-icon,.mat-column-actions fa-icon{display:inline-block}.detail-row td{padding-top:0;padding-bottom:0}.detail-content{display:flex;flex-wrap:nowrap;gap:8px 12px;align-items:center;padding:8px 0 12px;font:var(--mat-sys-body-small);color:var(--mat-sys-on-surface-variant)}.detail-actions{margin-left:auto;display:inline-flex;gap:4px;align-items:center}.detail-description{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i3$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i3$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i3$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i3$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i3$2.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i3$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i3$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i3$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i3$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i3$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i2$3.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "component", type: i2$3.MatChipSet, selector: "mat-chip-set", inputs: ["disabled", "role", "tabIndex"] }, { kind: "pipe", type: i5$1.DatePipe, name: "date" }] }); }
887
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.4", type: NgRhombusBlogTableComponent, isStandalone: true, selector: "ng-rhombus-blog-table", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { editEvent: "editEvent", deleteEvent: "deleteEvent" }, ngImport: i0, template: "@if (dataSource().length > 0) {\r\n<table mat-table [dataSource]=\"tableData()\" class=\"mat-elevation-z1\" multiTemplateDataRows>\r\n\r\n\t<!-- Title Column -->\r\n\t<ng-container matColumnDef=\"title\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Title</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">{{ row.post.title }}</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Status Column -->\r\n\t<ng-container matColumnDef=\"status\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Status</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">\r\n\t\t\t<mat-chip-set aria-label=\"Status\" role=\"list\">\r\n\t\t\t\t<mat-chip role=\"listitem\" [highlighted]=\"true\" class=\"neutral-chips-theme\">{{ row.post.status\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t\t@if (row.post.queueOrder && row.post.status === 'queued') {\r\n\t\t\t\t<mat-chip role=\"listitem\" class=\"secondary-chips-theme\" [highlighted]=\"true\">#{{ row.post.queueOrder\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t</mat-chip-set>\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Dimension Column -->\r\n\t<ng-container matColumnDef=\"dimension\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Dimension</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">\r\n\t\t\t@if (hasDimensions(row.post)) {\r\n\t\t\t<mat-chip-set aria-label=\"Dimension\" role=\"list\">\r\n\t\t\t\t<mat-chip role=\"listitem\" [highlighted]=\"true\" class=\"primary-chips-theme\">{{ firstDimension(row.post)\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t</mat-chip-set>\r\n\t\t\t} @else {\r\n\t\t\t\u2014\r\n\t\t\t}\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Series Column -->\r\n\t<ng-container matColumnDef=\"series\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Series</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">\r\n\t\t\t@if (row.post.series) {\r\n\t\t\t<mat-chip-set aria-label=\"Series\" role=\"list\">\r\n\t\t\t\t<mat-chip role=\"listitem\" [highlighted]=\"true\" class=\"secondary-chips-theme\">{{ row.post.series\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t</mat-chip-set>\r\n\t\t\t} @else {\r\n\t\t\t\u2014\r\n\t\t\t}\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<!-- PublishedAt Column -->\r\n\t<ng-container matColumnDef=\"publishedAt\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Date</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">{{ timestampToMillis(getDisplayDate(row.post)) | date: 'MMMM d, y' }}</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Detail Row (full width) -->\r\n\t<ng-container matColumnDef=\"detail\">\r\n\t\t<td mat-cell *matCellDef=\"let row\" [attr.colspan]=\"displayedColumns.length\">\r\n\t\t\t<div class=\"detail-content\">\r\n\t\t\t\t@if (row.post.description) {\r\n\t\t\t\t<div class=\"detail-description\">{{ row.post.description }}</div>\r\n\t\t\t\t}\r\n\r\n\t\t\t\t<div class=\"detail-actions\">\r\n\t\t\t\t\t<button mat-icon-button (click)=\"goToBlogPost(row.post.id)\" aria-label=\"Edit blog post\">\r\n\t\t\t\t\t\t<mat-icon>edit</mat-icon>\r\n\t\t\t\t\t</button>\r\n\t\t\t\t\t<button mat-icon-button (click)=\"onDeleteBlogPost(row.post)\" aria-label=\"Delete blog post\">\r\n\t\t\t\t\t\t<mat-icon>delete</mat-icon>\r\n\t\t\t\t\t</button>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\r\n\t<tr mat-row *matRowDef=\"let row; columns: displayedColumns; when: isMainRow\"></tr>\r\n\t<tr mat-row *matRowDef=\"let row; columns: detailColumns; when: isDetailRow\" class=\"detail-row\"></tr>\r\n</table>\r\n} @else {\r\n<div class=\"empty-set\">\r\n\t<span>No blog posts created yet.</span>\r\n</div>\r\n\r\n}", styles: [".empty-set{margin:12px}.neutral-chips-theme{--mat-chip-outline-color: var(--mat-sys-surface-variant);--mat-chip-elevated-selected-container-color: var(--mat-sys-surface-variant);--mat-chip-selected-label-text-color: var(--mat-sys-on-surface-variant);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.primary-chips-theme{--mat-chip-outline-color: var(--mat-sys-primary);--mat-chip-elevated-selected-container-color: var(--mat-sys-primary);--mat-chip-selected-label-text-color: var(--mat-sys-on-primary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.secondary-chips-theme{--mat-chip-outline-color: var(--mat-sys-secondary);--mat-chip-elevated-selected-container-color: var(--mat-sys-secondary);--mat-chip-selected-label-text-color: var(--mat-sys-on-secondary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.rhombus{overflow-y:auto}.mat-column-source,.mat-column-actions{text-align:center}.mat-column-source fa-icon,.mat-column-actions fa-icon{display:inline-block}.detail-row td{padding-top:0;padding-bottom:0}.detail-content{display:flex;flex-wrap:nowrap;gap:8px 12px;align-items:center;padding:8px 0 12px;font:var(--mat-sys-body-small);color:var(--mat-sys-on-surface-variant)}.detail-actions{margin-left:auto;display:inline-flex;gap:4px;align-items:center}.detail-description{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i3$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i3$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i3$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i3$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i3$2.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i3$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i3$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i3$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i3$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i3$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i2$3.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "component", type: i2$3.MatChipSet, selector: "mat-chip-set", inputs: ["disabled", "role", "tabIndex"] }, { kind: "pipe", type: i5$1.DatePipe, name: "date" }] }); }
687
888
  }
688
889
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgRhombusBlogTableComponent, decorators: [{
689
890
  type: Component,
690
- args: [{ selector: 'ng-rhombus-blog-table', imports: [CommonModule, MatButtonModule, MatIconModule, MatTableModule, MatChipsModule], template: "@if (dataSource().length > 0) {\r\n<table mat-table [dataSource]=\"tableData()\" class=\"mat-elevation-z1\" multiTemplateDataRows>\r\n\r\n\t<!-- Title Column -->\r\n\t<ng-container matColumnDef=\"title\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Title</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">{{ row.post.title }}</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Pillar Column -->\r\n\t<ng-container matColumnDef=\"pillar\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Pillar</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">\r\n\t\t\t@if (row.post.pillar) {\r\n\t\t\t<mat-chip-set aria-label=\"Pillar\" role=\"list\">\r\n\t\t\t\t<mat-chip role=\"listitem\" [highlighted]=\"true\" class=\"primary-chips-theme\">{{ row.post.pillar\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t</mat-chip-set>\r\n\t\t\t} @else {\r\n\t\t\t\u2014\r\n\t\t\t}\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Series Column -->\r\n\t<ng-container matColumnDef=\"series\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Series</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">\r\n\t\t\t@if (row.post.series) {\r\n\t\t\t<mat-chip-set aria-label=\"Series\" role=\"list\">\r\n\t\t\t\t<mat-chip role=\"listitem\" [highlighted]=\"true\" class=\"secondary-chips-theme\">{{ row.post.series\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t</mat-chip-set>\r\n\t\t\t} @else {\r\n\t\t\t\u2014\r\n\t\t\t}\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Timestamp Column -->\r\n\t<ng-container matColumnDef=\"timestamp\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Date</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">{{ timestampToMillis(row.post.timestamp) | date: 'MMMM d, y' }}</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Detail Row (full width) -->\r\n\t<ng-container matColumnDef=\"detail\">\r\n\t\t<td mat-cell *matCellDef=\"let row\" [attr.colspan]=\"displayedColumns.length\">\r\n\t\t\t<div class=\"detail-content\">\r\n\t\t\t\t@if (row.post.description) {\r\n\t\t\t\t<div class=\"detail-description\">{{ row.post.description }}</div>\r\n\t\t\t\t}\r\n\r\n\t\t\t\t<div class=\"detail-actions\">\r\n\t\t\t\t\t<button mat-icon-button (click)=\"goToBlogPost(row.post.id)\" aria-label=\"Edit blog post\">\r\n\t\t\t\t\t\t<mat-icon>edit</mat-icon>\r\n\t\t\t\t\t</button>\r\n\t\t\t\t\t<button mat-icon-button (click)=\"onDeleteBlogPost(row.post)\" aria-label=\"Delete blog post\">\r\n\t\t\t\t\t\t<mat-icon>delete</mat-icon>\r\n\t\t\t\t\t</button>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\r\n\t<tr mat-row *matRowDef=\"let row; columns: displayedColumns; when: isMainRow\"></tr>\r\n\t<tr mat-row *matRowDef=\"let row; columns: detailColumns; when: isDetailRow\" class=\"detail-row\"></tr>\r\n</table>\r\n} @else {\r\n<div class=\"empty-set\">\r\n\t<span>No blog posts created yet.</span>\r\n</div>\r\n\r\n}", styles: [".empty-set{margin:12px}.neutral-chips-theme{--mat-chip-outline-color: var(--mat-sys-surface-variant);--mat-chip-elevated-selected-container-color: var(--mat-sys-surface-variant);--mat-chip-selected-label-text-color: var(--mat-sys-on-surface-variant);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.primary-chips-theme{--mat-chip-outline-color: var(--mat-sys-primary);--mat-chip-elevated-selected-container-color: var(--mat-sys-primary);--mat-chip-selected-label-text-color: var(--mat-sys-on-primary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.secondary-chips-theme{--mat-chip-outline-color: var(--mat-sys-secondary);--mat-chip-elevated-selected-container-color: var(--mat-sys-secondary);--mat-chip-selected-label-text-color: var(--mat-sys-on-secondary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.rhombus{overflow-y:auto}.mat-column-source,.mat-column-actions{text-align:center}.mat-column-source fa-icon,.mat-column-actions fa-icon{display:inline-block}.detail-row td{padding-top:0;padding-bottom:0}.detail-content{display:flex;flex-wrap:nowrap;gap:8px 12px;align-items:center;padding:8px 0 12px;font:var(--mat-sys-body-small);color:var(--mat-sys-on-surface-variant)}.detail-actions{margin-left:auto;display:inline-flex;gap:4px;align-items:center}.detail-description{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
891
+ args: [{ selector: 'ng-rhombus-blog-table', imports: [CommonModule, MatButtonModule, MatIconModule, MatTableModule, MatChipsModule], template: "@if (dataSource().length > 0) {\r\n<table mat-table [dataSource]=\"tableData()\" class=\"mat-elevation-z1\" multiTemplateDataRows>\r\n\r\n\t<!-- Title Column -->\r\n\t<ng-container matColumnDef=\"title\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Title</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">{{ row.post.title }}</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Status Column -->\r\n\t<ng-container matColumnDef=\"status\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Status</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">\r\n\t\t\t<mat-chip-set aria-label=\"Status\" role=\"list\">\r\n\t\t\t\t<mat-chip role=\"listitem\" [highlighted]=\"true\" class=\"neutral-chips-theme\">{{ row.post.status\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t\t@if (row.post.queueOrder && row.post.status === 'queued') {\r\n\t\t\t\t<mat-chip role=\"listitem\" class=\"secondary-chips-theme\" [highlighted]=\"true\">#{{ row.post.queueOrder\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t</mat-chip-set>\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Dimension Column -->\r\n\t<ng-container matColumnDef=\"dimension\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Dimension</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">\r\n\t\t\t@if (hasDimensions(row.post)) {\r\n\t\t\t<mat-chip-set aria-label=\"Dimension\" role=\"list\">\r\n\t\t\t\t<mat-chip role=\"listitem\" [highlighted]=\"true\" class=\"primary-chips-theme\">{{ firstDimension(row.post)\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t</mat-chip-set>\r\n\t\t\t} @else {\r\n\t\t\t\u2014\r\n\t\t\t}\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Series Column -->\r\n\t<ng-container matColumnDef=\"series\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Series</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">\r\n\t\t\t@if (row.post.series) {\r\n\t\t\t<mat-chip-set aria-label=\"Series\" role=\"list\">\r\n\t\t\t\t<mat-chip role=\"listitem\" [highlighted]=\"true\" class=\"secondary-chips-theme\">{{ row.post.series\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t</mat-chip-set>\r\n\t\t\t} @else {\r\n\t\t\t\u2014\r\n\t\t\t}\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<!-- PublishedAt Column -->\r\n\t<ng-container matColumnDef=\"publishedAt\">\r\n\t\t<th mat-header-cell *matHeaderCellDef>Date</th>\r\n\t\t<td mat-cell *matCellDef=\"let row\">{{ timestampToMillis(getDisplayDate(row.post)) | date: 'MMMM d, y' }}</td>\r\n\t</ng-container>\r\n\r\n\t<!-- Detail Row (full width) -->\r\n\t<ng-container matColumnDef=\"detail\">\r\n\t\t<td mat-cell *matCellDef=\"let row\" [attr.colspan]=\"displayedColumns.length\">\r\n\t\t\t<div class=\"detail-content\">\r\n\t\t\t\t@if (row.post.description) {\r\n\t\t\t\t<div class=\"detail-description\">{{ row.post.description }}</div>\r\n\t\t\t\t}\r\n\r\n\t\t\t\t<div class=\"detail-actions\">\r\n\t\t\t\t\t<button mat-icon-button (click)=\"goToBlogPost(row.post.id)\" aria-label=\"Edit blog post\">\r\n\t\t\t\t\t\t<mat-icon>edit</mat-icon>\r\n\t\t\t\t\t</button>\r\n\t\t\t\t\t<button mat-icon-button (click)=\"onDeleteBlogPost(row.post)\" aria-label=\"Delete blog post\">\r\n\t\t\t\t\t\t<mat-icon>delete</mat-icon>\r\n\t\t\t\t\t</button>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</td>\r\n\t</ng-container>\r\n\r\n\t<tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\r\n\t<tr mat-row *matRowDef=\"let row; columns: displayedColumns; when: isMainRow\"></tr>\r\n\t<tr mat-row *matRowDef=\"let row; columns: detailColumns; when: isDetailRow\" class=\"detail-row\"></tr>\r\n</table>\r\n} @else {\r\n<div class=\"empty-set\">\r\n\t<span>No blog posts created yet.</span>\r\n</div>\r\n\r\n}", styles: [".empty-set{margin:12px}.neutral-chips-theme{--mat-chip-outline-color: var(--mat-sys-surface-variant);--mat-chip-elevated-selected-container-color: var(--mat-sys-surface-variant);--mat-chip-selected-label-text-color: var(--mat-sys-on-surface-variant);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.primary-chips-theme{--mat-chip-outline-color: var(--mat-sys-primary);--mat-chip-elevated-selected-container-color: var(--mat-sys-primary);--mat-chip-selected-label-text-color: var(--mat-sys-on-primary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.secondary-chips-theme{--mat-chip-outline-color: var(--mat-sys-secondary);--mat-chip-elevated-selected-container-color: var(--mat-sys-secondary);--mat-chip-selected-label-text-color: var(--mat-sys-on-secondary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.rhombus{overflow-y:auto}.mat-column-source,.mat-column-actions{text-align:center}.mat-column-source fa-icon,.mat-column-actions fa-icon{display:inline-block}.detail-row td{padding-top:0;padding-bottom:0}.detail-content{display:flex;flex-wrap:nowrap;gap:8px 12px;align-items:center;padding:8px 0 12px;font:var(--mat-sys-body-small);color:var(--mat-sys-on-surface-variant)}.detail-actions{margin-left:auto;display:inline-flex;gap:4px;align-items:center}.detail-description{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
691
892
  }], propDecorators: { editEvent: [{
692
893
  type: Output
693
894
  }], deleteEvent: [{
@@ -837,7 +1038,11 @@ class NgRhombusBlogAddEditComponent {
837
1038
  this.cancelEvent = output();
838
1039
  this.submitEvent = output();
839
1040
  this.contentData = signal('', ...(ngDevMode ? [{ debugName: "contentData" }] : []));
840
- this.pillars = Object.values(ContentPillar);
1041
+ this.dimensionRequiredValidator = (control) => {
1042
+ const value = control.value;
1043
+ return value && value.length > 0 ? null : { required: true };
1044
+ };
1045
+ this.dimensions = Object.values(ContentDimension);
841
1046
  this.seriesOptions = Object.values(BlogSeries);
842
1047
  this.dialog = inject(MatDialog);
843
1048
  this.thumbnailService = inject(NgRhombusBlogPostThumbnailService);
@@ -863,7 +1068,7 @@ class NgRhombusBlogAddEditComponent {
863
1068
  if (this.blogPost()) {
864
1069
  this.blogPostForm.patchValue({
865
1070
  title: this.blogPost()?.title,
866
- description: this.blogPost()?.description,
1071
+ excerpt: this.blogPost()?.excerpt ?? this.blogPost()?.description,
867
1072
  thumbnail: this.blogPost()?.thumbnail,
868
1073
  content: this.blogPost()?.content,
869
1074
  });
@@ -874,31 +1079,29 @@ class NgRhombusBlogAddEditComponent {
874
1079
  ngOnInit() {
875
1080
  this.blogPostForm = this.formBuilder.group({
876
1081
  title: [this.blogPost()?.title, Validators.required],
877
- description: [this.blogPost()?.description, Validators.required],
1082
+ excerpt: [this.blogPost()?.excerpt ?? this.blogPost()?.description, Validators.required],
878
1083
  thumbnail: [this.blogPost()?.thumbnail, Validators.required],
879
1084
  content: [this.blogPost()?.content, Validators.required],
880
1085
  // creator system
881
- pillar: [this.blogPost()?.pillar ?? null, Validators.required],
1086
+ dimensions: [this.blogService.dimensionsOf(this.blogPost()) ?? [], this.dimensionRequiredValidator],
882
1087
  series: [this.blogPost()?.series ?? null, Validators.required],
883
- tagsCsv: [(this.blogPost()?.tags ?? []).join(', '), Validators.required],
1088
+ tagsCsv: [(this.blogPost()?.tags ?? []).join(', ')],
884
1089
  });
885
1090
  this.applyCreatorSystemRules();
886
1091
  this.blogPostForm.get('series')?.valueChanges.subscribe(() => this.applyCreatorSystemRules());
887
1092
  }
888
1093
  applyCreatorSystemRules() {
889
- const pillarControl = this.blogPostForm.get('pillar');
1094
+ const dimensionControl = this.blogPostForm.get('dimensions');
890
1095
  const seriesValue = this.blogPostForm.get('series')?.value;
891
- if (!pillarControl)
1096
+ if (!dimensionControl)
892
1097
  return;
893
1098
  if (seriesValue === BlogSeries.FromTheEditor) {
894
- pillarControl.clearValidators();
895
- if (pillarControl.value !== null)
896
- pillarControl.setValue(null);
1099
+ dimensionControl.setValidators([this.dimensionRequiredValidator]);
897
1100
  }
898
1101
  else {
899
- pillarControl.setValidators([Validators.required]);
1102
+ dimensionControl.clearValidators();
900
1103
  }
901
- pillarControl.updateValueAndValidity({ emitEvent: false });
1104
+ dimensionControl.updateValueAndValidity({ emitEvent: false });
902
1105
  }
903
1106
  onContentChange() {
904
1107
  this.contentData.set(this.blogPostForm.getRawValue().content);
@@ -906,16 +1109,21 @@ class NgRhombusBlogAddEditComponent {
906
1109
  get thumbnailSource() {
907
1110
  return this.blogPostForm.getRawValue().thumbnail;
908
1111
  }
909
- onFileUploaded(downloadUrl) {
910
- this.blogPostForm.patchValue({
911
- thumbnail: downloadUrl
912
- });
1112
+ async onFileUploaded(downloadUrl) {
1113
+ const current = this.blogPostForm.getRawValue().thumbnail;
1114
+ if (current && current !== downloadUrl) {
1115
+ await this.thumbnailService.deleteImage(current);
1116
+ }
1117
+ this.blogPostForm.patchValue({ thumbnail: downloadUrl });
913
1118
  this.blogPostForm.markAsDirty();
914
1119
  }
915
- onFileDeleted() {
916
- this.blogPostForm.patchValue({
917
- thumbnail: ''
918
- });
1120
+ async onFileDeleted() {
1121
+ const current = this.blogPostForm.getRawValue().thumbnail;
1122
+ if (current) {
1123
+ await this.thumbnailService.deleteImage(current);
1124
+ }
1125
+ this.blogPostForm.patchValue({ thumbnail: '' });
1126
+ this.blogPostForm.markAsDirty();
919
1127
  }
920
1128
  onCancelClick() {
921
1129
  if (this.blogPost()) {
@@ -968,21 +1176,24 @@ class NgRhombusBlogAddEditComponent {
968
1176
  return;
969
1177
  const raw = this.blogPostForm.getRawValue();
970
1178
  const tags = this.parseTags(raw.tagsCsv);
971
- if (tags.length < 3 || tags.length > 6) {
972
- // keep it simple; if you prefer, set a form error and show mat-error
973
- return;
974
- }
975
- const submittedBlogPost = new IBlog();
976
- if (this.blogPost())
977
- submittedBlogPost.id = this.blogPost().id;
978
- submittedBlogPost.title = raw.title;
979
- submittedBlogPost.description = raw.description;
980
- submittedBlogPost.thumbnail = raw.thumbnail;
981
- submittedBlogPost.content = raw.content;
982
- submittedBlogPost.pillar = raw.pillar;
983
- submittedBlogPost.series = raw.series;
984
- submittedBlogPost.tags = tags;
985
- submittedBlogPost.readTimeMinutes = this.blogService.calculateReadTimeMinutes(raw.content);
1179
+ const slug = this.blogPost()?.slug ?? NgRhombusBlogPostHelper.createSlug(raw.title);
1180
+ const id = this.blogPost()?.id ?? slug;
1181
+ const submittedBlogPost = {
1182
+ id,
1183
+ slug,
1184
+ title: raw.title,
1185
+ excerpt: raw.excerpt,
1186
+ description: raw.excerpt,
1187
+ thumbnail: raw.thumbnail,
1188
+ content: raw.content,
1189
+ dimensions: raw.dimensions ?? [],
1190
+ series: raw.series,
1191
+ tags,
1192
+ readingTime: this.blogService.calculateReadingTime(raw.content),
1193
+ status: this.blogPost()?.status ?? 'draft',
1194
+ createdAt: this.blogPost()?.createdAt ?? new Date(),
1195
+ updatedAt: new Date(),
1196
+ };
986
1197
  this.submitEvent.emit(submittedBlogPost);
987
1198
  }
988
1199
  parseTags(csv) {
@@ -994,11 +1205,11 @@ class NgRhombusBlogAddEditComponent {
994
1205
  return Array.from(new Set(tags));
995
1206
  }
996
1207
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgRhombusBlogAddEditComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
997
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.4", type: NgRhombusBlogAddEditComponent, isStandalone: true, selector: "ng-rhombus-blog-form", inputs: { blogPost: { classPropertyName: "blogPost", publicName: "blogPost", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cancelEvent: "cancelEvent", submitEvent: "submitEvent" }, viewQueries: [{ propertyName: "blogPostPreview", first: true, predicate: ["blogPost"], descendants: true }], ngImport: i0, template: "<div class=\"h-full flex flex-row overflow-hidden min-h-0\">\r\n\t<div class=\"flex flex-col w-1/2 p-4 overflow-y-auto min-h-0\">\r\n\t\t<form novalidate class=\"flex flex-col gap-4 min-h-0\" [formGroup]=\"blogPostForm\">\r\n\t\t\t<mat-form-field>\r\n\t\t\t\t<mat-label>Title</mat-label>\r\n\t\t\t\t<input matInput placeholder=\"Placeholder\" formControlName=\"title\">\r\n\t\t\t</mat-form-field>\r\n\t\t\t<mat-form-field>\r\n\t\t\t\t<mat-label>Description</mat-label>\r\n\t\t\t\t<input matInput placeholder=\"Placeholder\" formControlName=\"description\">\r\n\t\t\t</mat-form-field>\r\n\t\t\t<ng-rhombus-thumbnail-control [thumbnailSrc]=\"thumbnailSource\" [width]=\"200\" [height]=\"112\"\r\n\t\t\t\t[displayMode]=\"'indicator'\" [disabled]=\"blogPost() !== undefined\"\r\n\t\t\t\t(onFileUploaded)=\"onFileUploaded($event)\"\r\n\t\t\t\t(onFileDeleted)=\"onFileDeleted()\"></ng-rhombus-thumbnail-control>\r\n\t\t\t<mat-form-field class=\"w-full\">\r\n\t\t\t\t<mat-label>Content</mat-label>\r\n\t\t\t\t<textarea matInput required class=\"content-textarea\" rows=\"12\" formControlName=\"content\"\r\n\t\t\t\t\t(input)=\"onContentChange()\"></textarea>\r\n\t\t\t</mat-form-field>\r\n\t\t\t<div class=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\r\n\t\t\t\t<mat-form-field class=\"w-full\">\r\n\t\t\t\t\t<mat-label>Content Pillar (optional for From The Editor)</mat-label>\r\n\t\t\t\t\t<mat-select formControlName=\"pillar\" required>\r\n\t\t\t\t\t\t@for (p of pillars; track p) {\r\n\t\t\t\t\t\t<mat-option [value]=\"p\">{{ p }}</mat-option>\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t</mat-select>\r\n\t\t\t\t</mat-form-field>\r\n\r\n\t\t\t\t<mat-form-field class=\"w-full\">\r\n\t\t\t\t\t<mat-label>Series</mat-label>\r\n\t\t\t\t\t<mat-select formControlName=\"series\" required>\r\n\t\t\t\t\t\t@for (s of seriesOptions; track s) {\r\n\t\t\t\t\t\t<mat-option [value]=\"s\">{{ s }}</mat-option>\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t</mat-select>\r\n\t\t\t\t</mat-form-field>\r\n\t\t\t</div>\r\n\t\t\t<mat-form-field>\r\n\t\t\t\t<mat-label>Tags</mat-label>\r\n\t\t\t\t<input matInput formControlName=\"tagsCsv\" placeholder=\"3\u20136 tags, comma-separated\">\r\n\t\t\t\t<mat-hint>Example: angular, firestore, testing</mat-hint>\r\n\t\t\t</mat-form-field>\r\n\t\t\t<div class=\"flex\">\r\n\t\t\t\t<button mat-raised-button class=\"\" (click)=\"onCancelClick()\" type=\"button\">Cancel</button>\r\n\t\t\t\t<div class=\"flex-1\"></div>\r\n\t\t\t\t<button mat-flat-button [disabled]=\"blogPostForm.invalid\" type=\"button\"\r\n\t\t\t\t\t(click)=\"onSubmit()\">Submit</button>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\r\n\t<div class=\"flex flex-col w-1/2 p-4 overflow-y-auto\">\r\n\t\t<mat-card>\r\n\t\t\t<mat-card-header>\r\n\t\t\t\t<mat-card-title>{{ blogPostForm.getRawValue().title }}</mat-card-title>\r\n\t\t\t\t<mat-card-subtitle>{{ blogPostForm.getRawValue().description }}</mat-card-subtitle>\r\n\t\t\t</mat-card-header>\r\n\t\t\t<img mat-card-image [src]=\"blogPostForm.getRawValue().thumbnail\" />\r\n\t\t\t<mat-card-content>\r\n\t\t\t\t<ng-rhombus-markdown [classes]=\"{ 'prose': true, 'dark:prose-invert': themeService.isDarkMode() }\"\r\n\t\t\t\t\t[data]=\"contentData()\" />\r\n\t\t\t</mat-card-content>\r\n\t\t\t<mat-card-footer>\r\n\t\t\t\t<span class=\"flex flex-row-reverse\">Doug Williamson</span>\r\n\t\t\t</mat-card-footer>\r\n\t\t</mat-card>\r\n\t</div>\r\n</div>", styles: [".mat-mdc-card-header,.mat-mdc-card-content,.mat-mdc-card-footer{padding:32px 16px}.content-textarea{resize:vertical}\n"], dependencies: [{ kind: "ngmodule", type: MatListModule }, { kind: "ngmodule", type: MatDividerModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i2$2.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i2$2.MatCardContent, selector: "mat-card-content" }, { kind: "directive", type: i2$2.MatCardFooter, selector: "mat-card-footer" }, { kind: "component", type: i2$2.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i2$2.MatCardImage, selector: "[mat-card-image], [matCardImage]" }, { kind: "directive", type: i2$2.MatCardSubtitle, selector: "mat-card-subtitle, [mat-card-subtitle], [matCardSubtitle]" }, { kind: "directive", type: i2$2.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "ngmodule", type: MatSidenavModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: ThumbnailControlComponent, selector: "ng-rhombus-thumbnail-control", inputs: ["width", "height", "thumbnailSrc", "disabled", "displayMode"], outputs: ["onFileUploaded", "onFileDeleted"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: NgRhombusMarkdownComponent, selector: "ng-rhombus-markdown", inputs: ["data", "classes"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }] }); }
1208
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.4", type: NgRhombusBlogAddEditComponent, isStandalone: true, selector: "ng-rhombus-blog-form", inputs: { blogPost: { classPropertyName: "blogPost", publicName: "blogPost", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cancelEvent: "cancelEvent", submitEvent: "submitEvent" }, viewQueries: [{ propertyName: "blogPostPreview", first: true, predicate: ["blogPost"], descendants: true }], ngImport: i0, template: "<div class=\"h-full flex flex-row overflow-hidden min-h-0\">\r\n\t<div class=\"flex flex-col w-1/2 p-4 overflow-y-auto min-h-0\">\r\n\t\t<form novalidate class=\"flex flex-col gap-4 min-h-0\" [formGroup]=\"blogPostForm\">\r\n\t\t\t<mat-form-field>\r\n\t\t\t\t<mat-label>Title</mat-label>\r\n\t\t\t\t<input matInput placeholder=\"Placeholder\" formControlName=\"title\">\r\n\t\t\t</mat-form-field>\r\n\t\t\t<mat-form-field>\r\n\t\t\t\t<mat-label>Excerpt</mat-label>\r\n\t\t\t\t<input matInput placeholder=\"Short summary\" formControlName=\"excerpt\">\r\n\t\t\t</mat-form-field>\r\n\t\t\t<ng-rhombus-thumbnail-control [thumbnailSrc]=\"thumbnailSource\" [width]=\"200\" [height]=\"112\"\r\n\t\t\t\t[displayMode]=\"'indicator'\" (onFileUploaded)=\"onFileUploaded($event)\"\r\n\t\t\t\t(onFileDeleted)=\"onFileDeleted()\"></ng-rhombus-thumbnail-control>\r\n\t\t\t<mat-form-field class=\"w-full\">\r\n\t\t\t\t<mat-label>Content</mat-label>\r\n\t\t\t\t<textarea matInput required class=\"content-textarea\" rows=\"12\" formControlName=\"content\"\r\n\t\t\t\t\t(input)=\"onContentChange()\"></textarea>\r\n\t\t\t</mat-form-field>\r\n\t\t\t<div class=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\r\n\t\t\t\t<mat-form-field class=\"w-full\">\r\n\t\t\t\t\t<mat-label>Series</mat-label>\r\n\t\t\t\t\t<mat-select formControlName=\"series\" required>\r\n\t\t\t\t\t\t@for (s of seriesOptions; track s) {\r\n\t\t\t\t\t\t<mat-option [value]=\"s\">{{ s }}</mat-option>\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t</mat-select>\r\n\t\t\t\t</mat-form-field>\r\n\r\n\t\t\t\t<mat-form-field class=\"w-full\">\r\n\t\t\t\t\t<mat-label>Dimensions (pick the modes)</mat-label>\r\n\t\t\t\t\t<mat-select formControlName=\"dimensions\" multiple>\r\n\t\t\t\t\t\t@for (p of dimensions; track p) {\r\n\t\t\t\t\t\t<mat-option [value]=\"p\">{{ p }}</mat-option>\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t</mat-select>\r\n\t\t\t\t\t<mat-hint>Choose one or more cognitive modes for this piece.</mat-hint>\r\n\t\t\t\t</mat-form-field>\r\n\t\t\t</div>\r\n\t\t\t<mat-form-field>\r\n\t\t\t\t<mat-label>Tags (optional)</mat-label>\r\n\t\t\t\t<input matInput formControlName=\"tagsCsv\" placeholder=\"Comma-separated tags\">\r\n\t\t\t\t<mat-hint>Example: angular, firestore, testing</mat-hint>\r\n\t\t\t</mat-form-field>\r\n\t\t\t<div class=\"flex\">\r\n\t\t\t\t<button mat-raised-button class=\"\" (click)=\"onCancelClick()\" type=\"button\">Cancel</button>\r\n\t\t\t\t<div class=\"flex-1\"></div>\r\n\t\t\t\t<button mat-flat-button [disabled]=\"blogPostForm.invalid\" type=\"button\"\r\n\t\t\t\t\t(click)=\"onSubmit()\">Submit</button>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\r\n\t<div class=\"flex flex-col w-1/2 p-4 overflow-y-auto\">\r\n\t\t<mat-card>\r\n\t\t\t<mat-card-header>\r\n\t\t\t\t<mat-card-title>{{ blogPostForm.getRawValue().title }}</mat-card-title>\r\n\t\t\t\t<mat-card-subtitle>{{ blogPostForm.getRawValue().excerpt }}</mat-card-subtitle>\r\n\t\t\t</mat-card-header>\r\n\t\t\t<img mat-card-image [src]=\"blogPostForm.getRawValue().thumbnail\" />\r\n\t\t\t<mat-card-content>\r\n\t\t\t\t<ng-rhombus-markdown [classes]=\"{ 'prose': true, 'dark:prose-invert': themeService.isDarkMode() }\"\r\n\t\t\t\t\t[data]=\"contentData()\" />\r\n\t\t\t</mat-card-content>\r\n\t\t\t<mat-card-footer>\r\n\t\t\t\t<span class=\"flex flex-row-reverse\">Doug Williamson</span>\r\n\t\t\t</mat-card-footer>\r\n\t\t</mat-card>\r\n\t</div>\r\n</div>", styles: [".mat-mdc-card-header,.mat-mdc-card-content,.mat-mdc-card-footer{padding:32px 16px}.content-textarea{resize:vertical}\n"], dependencies: [{ kind: "ngmodule", type: MatListModule }, { kind: "ngmodule", type: MatDividerModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i2$2.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i2$2.MatCardContent, selector: "mat-card-content" }, { kind: "directive", type: i2$2.MatCardFooter, selector: "mat-card-footer" }, { kind: "component", type: i2$2.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i2$2.MatCardImage, selector: "[mat-card-image], [matCardImage]" }, { kind: "directive", type: i2$2.MatCardSubtitle, selector: "mat-card-subtitle, [mat-card-subtitle], [matCardSubtitle]" }, { kind: "directive", type: i2$2.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "ngmodule", type: MatSidenavModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: ThumbnailControlComponent, selector: "ng-rhombus-thumbnail-control", inputs: ["width", "height", "thumbnailSrc", "disabled", "displayMode"], outputs: ["onFileUploaded", "onFileDeleted"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: NgRhombusMarkdownComponent, selector: "ng-rhombus-markdown", inputs: ["data", "classes"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }] }); }
998
1209
  }
999
1210
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgRhombusBlogAddEditComponent, decorators: [{
1000
1211
  type: Component,
1001
- args: [{ selector: 'ng-rhombus-blog-form', imports: [NgClass, MatListModule, MatDividerModule, MatButtonModule, MatCardModule, MatFormFieldModule, MatInputModule, MatProgressSpinnerModule, MatSidenavModule, ReactiveFormsModule, ThumbnailControlComponent, MatIconModule, NgRhombusMarkdownComponent, MatSelectModule], template: "<div class=\"h-full flex flex-row overflow-hidden min-h-0\">\r\n\t<div class=\"flex flex-col w-1/2 p-4 overflow-y-auto min-h-0\">\r\n\t\t<form novalidate class=\"flex flex-col gap-4 min-h-0\" [formGroup]=\"blogPostForm\">\r\n\t\t\t<mat-form-field>\r\n\t\t\t\t<mat-label>Title</mat-label>\r\n\t\t\t\t<input matInput placeholder=\"Placeholder\" formControlName=\"title\">\r\n\t\t\t</mat-form-field>\r\n\t\t\t<mat-form-field>\r\n\t\t\t\t<mat-label>Description</mat-label>\r\n\t\t\t\t<input matInput placeholder=\"Placeholder\" formControlName=\"description\">\r\n\t\t\t</mat-form-field>\r\n\t\t\t<ng-rhombus-thumbnail-control [thumbnailSrc]=\"thumbnailSource\" [width]=\"200\" [height]=\"112\"\r\n\t\t\t\t[displayMode]=\"'indicator'\" [disabled]=\"blogPost() !== undefined\"\r\n\t\t\t\t(onFileUploaded)=\"onFileUploaded($event)\"\r\n\t\t\t\t(onFileDeleted)=\"onFileDeleted()\"></ng-rhombus-thumbnail-control>\r\n\t\t\t<mat-form-field class=\"w-full\">\r\n\t\t\t\t<mat-label>Content</mat-label>\r\n\t\t\t\t<textarea matInput required class=\"content-textarea\" rows=\"12\" formControlName=\"content\"\r\n\t\t\t\t\t(input)=\"onContentChange()\"></textarea>\r\n\t\t\t</mat-form-field>\r\n\t\t\t<div class=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\r\n\t\t\t\t<mat-form-field class=\"w-full\">\r\n\t\t\t\t\t<mat-label>Content Pillar (optional for From The Editor)</mat-label>\r\n\t\t\t\t\t<mat-select formControlName=\"pillar\" required>\r\n\t\t\t\t\t\t@for (p of pillars; track p) {\r\n\t\t\t\t\t\t<mat-option [value]=\"p\">{{ p }}</mat-option>\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t</mat-select>\r\n\t\t\t\t</mat-form-field>\r\n\r\n\t\t\t\t<mat-form-field class=\"w-full\">\r\n\t\t\t\t\t<mat-label>Series</mat-label>\r\n\t\t\t\t\t<mat-select formControlName=\"series\" required>\r\n\t\t\t\t\t\t@for (s of seriesOptions; track s) {\r\n\t\t\t\t\t\t<mat-option [value]=\"s\">{{ s }}</mat-option>\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t</mat-select>\r\n\t\t\t\t</mat-form-field>\r\n\t\t\t</div>\r\n\t\t\t<mat-form-field>\r\n\t\t\t\t<mat-label>Tags</mat-label>\r\n\t\t\t\t<input matInput formControlName=\"tagsCsv\" placeholder=\"3\u20136 tags, comma-separated\">\r\n\t\t\t\t<mat-hint>Example: angular, firestore, testing</mat-hint>\r\n\t\t\t</mat-form-field>\r\n\t\t\t<div class=\"flex\">\r\n\t\t\t\t<button mat-raised-button class=\"\" (click)=\"onCancelClick()\" type=\"button\">Cancel</button>\r\n\t\t\t\t<div class=\"flex-1\"></div>\r\n\t\t\t\t<button mat-flat-button [disabled]=\"blogPostForm.invalid\" type=\"button\"\r\n\t\t\t\t\t(click)=\"onSubmit()\">Submit</button>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\r\n\t<div class=\"flex flex-col w-1/2 p-4 overflow-y-auto\">\r\n\t\t<mat-card>\r\n\t\t\t<mat-card-header>\r\n\t\t\t\t<mat-card-title>{{ blogPostForm.getRawValue().title }}</mat-card-title>\r\n\t\t\t\t<mat-card-subtitle>{{ blogPostForm.getRawValue().description }}</mat-card-subtitle>\r\n\t\t\t</mat-card-header>\r\n\t\t\t<img mat-card-image [src]=\"blogPostForm.getRawValue().thumbnail\" />\r\n\t\t\t<mat-card-content>\r\n\t\t\t\t<ng-rhombus-markdown [classes]=\"{ 'prose': true, 'dark:prose-invert': themeService.isDarkMode() }\"\r\n\t\t\t\t\t[data]=\"contentData()\" />\r\n\t\t\t</mat-card-content>\r\n\t\t\t<mat-card-footer>\r\n\t\t\t\t<span class=\"flex flex-row-reverse\">Doug Williamson</span>\r\n\t\t\t</mat-card-footer>\r\n\t\t</mat-card>\r\n\t</div>\r\n</div>", styles: [".mat-mdc-card-header,.mat-mdc-card-content,.mat-mdc-card-footer{padding:32px 16px}.content-textarea{resize:vertical}\n"] }]
1212
+ args: [{ selector: 'ng-rhombus-blog-form', imports: [MatListModule, MatDividerModule, MatButtonModule, MatCardModule, MatFormFieldModule, MatInputModule, MatProgressSpinnerModule, MatSidenavModule, ReactiveFormsModule, ThumbnailControlComponent, MatIconModule, NgRhombusMarkdownComponent, MatSelectModule], template: "<div class=\"h-full flex flex-row overflow-hidden min-h-0\">\r\n\t<div class=\"flex flex-col w-1/2 p-4 overflow-y-auto min-h-0\">\r\n\t\t<form novalidate class=\"flex flex-col gap-4 min-h-0\" [formGroup]=\"blogPostForm\">\r\n\t\t\t<mat-form-field>\r\n\t\t\t\t<mat-label>Title</mat-label>\r\n\t\t\t\t<input matInput placeholder=\"Placeholder\" formControlName=\"title\">\r\n\t\t\t</mat-form-field>\r\n\t\t\t<mat-form-field>\r\n\t\t\t\t<mat-label>Excerpt</mat-label>\r\n\t\t\t\t<input matInput placeholder=\"Short summary\" formControlName=\"excerpt\">\r\n\t\t\t</mat-form-field>\r\n\t\t\t<ng-rhombus-thumbnail-control [thumbnailSrc]=\"thumbnailSource\" [width]=\"200\" [height]=\"112\"\r\n\t\t\t\t[displayMode]=\"'indicator'\" (onFileUploaded)=\"onFileUploaded($event)\"\r\n\t\t\t\t(onFileDeleted)=\"onFileDeleted()\"></ng-rhombus-thumbnail-control>\r\n\t\t\t<mat-form-field class=\"w-full\">\r\n\t\t\t\t<mat-label>Content</mat-label>\r\n\t\t\t\t<textarea matInput required class=\"content-textarea\" rows=\"12\" formControlName=\"content\"\r\n\t\t\t\t\t(input)=\"onContentChange()\"></textarea>\r\n\t\t\t</mat-form-field>\r\n\t\t\t<div class=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\r\n\t\t\t\t<mat-form-field class=\"w-full\">\r\n\t\t\t\t\t<mat-label>Series</mat-label>\r\n\t\t\t\t\t<mat-select formControlName=\"series\" required>\r\n\t\t\t\t\t\t@for (s of seriesOptions; track s) {\r\n\t\t\t\t\t\t<mat-option [value]=\"s\">{{ s }}</mat-option>\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t</mat-select>\r\n\t\t\t\t</mat-form-field>\r\n\r\n\t\t\t\t<mat-form-field class=\"w-full\">\r\n\t\t\t\t\t<mat-label>Dimensions (pick the modes)</mat-label>\r\n\t\t\t\t\t<mat-select formControlName=\"dimensions\" multiple>\r\n\t\t\t\t\t\t@for (p of dimensions; track p) {\r\n\t\t\t\t\t\t<mat-option [value]=\"p\">{{ p }}</mat-option>\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t</mat-select>\r\n\t\t\t\t\t<mat-hint>Choose one or more cognitive modes for this piece.</mat-hint>\r\n\t\t\t\t</mat-form-field>\r\n\t\t\t</div>\r\n\t\t\t<mat-form-field>\r\n\t\t\t\t<mat-label>Tags (optional)</mat-label>\r\n\t\t\t\t<input matInput formControlName=\"tagsCsv\" placeholder=\"Comma-separated tags\">\r\n\t\t\t\t<mat-hint>Example: angular, firestore, testing</mat-hint>\r\n\t\t\t</mat-form-field>\r\n\t\t\t<div class=\"flex\">\r\n\t\t\t\t<button mat-raised-button class=\"\" (click)=\"onCancelClick()\" type=\"button\">Cancel</button>\r\n\t\t\t\t<div class=\"flex-1\"></div>\r\n\t\t\t\t<button mat-flat-button [disabled]=\"blogPostForm.invalid\" type=\"button\"\r\n\t\t\t\t\t(click)=\"onSubmit()\">Submit</button>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\r\n\t<div class=\"flex flex-col w-1/2 p-4 overflow-y-auto\">\r\n\t\t<mat-card>\r\n\t\t\t<mat-card-header>\r\n\t\t\t\t<mat-card-title>{{ blogPostForm.getRawValue().title }}</mat-card-title>\r\n\t\t\t\t<mat-card-subtitle>{{ blogPostForm.getRawValue().excerpt }}</mat-card-subtitle>\r\n\t\t\t</mat-card-header>\r\n\t\t\t<img mat-card-image [src]=\"blogPostForm.getRawValue().thumbnail\" />\r\n\t\t\t<mat-card-content>\r\n\t\t\t\t<ng-rhombus-markdown [classes]=\"{ 'prose': true, 'dark:prose-invert': themeService.isDarkMode() }\"\r\n\t\t\t\t\t[data]=\"contentData()\" />\r\n\t\t\t</mat-card-content>\r\n\t\t\t<mat-card-footer>\r\n\t\t\t\t<span class=\"flex flex-row-reverse\">Doug Williamson</span>\r\n\t\t\t</mat-card-footer>\r\n\t\t</mat-card>\r\n\t</div>\r\n</div>", styles: [".mat-mdc-card-header,.mat-mdc-card-content,.mat-mdc-card-footer{padding:32px 16px}.content-textarea{resize:vertical}\n"] }]
1002
1213
  }], ctorParameters: () => [], propDecorators: { blogPost: [{ type: i0.Input, args: [{ isSignal: true, alias: "blogPost", required: false }] }], cancelEvent: [{ type: i0.Output, args: ["cancelEvent"] }], submitEvent: [{ type: i0.Output, args: ["submitEvent"] }], blogPostPreview: [{
1003
1214
  type: ViewChild,
1004
1215
  args: ['blogPost']
@@ -1016,11 +1227,16 @@ class NgRhombusBlogPostComponent {
1016
1227
  this.faLinkedin = faLinkedin;
1017
1228
  }
1018
1229
  #doc;
1230
+ getDisplayDate(post) {
1231
+ if (!post)
1232
+ return null;
1233
+ return post.publishedAt ?? post.publishAt ?? post.createdAt ?? post.updatedAt;
1234
+ }
1019
1235
  ngOnInit() {
1020
1236
  }
1021
1237
  // Build absolute URL for sharing
1022
1238
  getShareUrl() {
1023
- const id = this.dataSource()?.id;
1239
+ const id = this.dataSource()?.slug ?? this.dataSource()?.id;
1024
1240
  const origin = this.#doc?.location?.origin ?? '';
1025
1241
  const path = id ? `/blog/${id}` : this.#doc?.location?.pathname ?? '/blog';
1026
1242
  return `${origin}${path}`;
@@ -1052,24 +1268,39 @@ class NgRhombusBlogPostComponent {
1052
1268
  .map(t => t.trim())
1053
1269
  .filter(Boolean);
1054
1270
  }
1055
- get contentPillar() {
1056
- return (this.dataSource()?.pillar ?? null) || null;
1271
+ get contentDimensions() {
1272
+ return this.normalizeDimensions(this.dataSource());
1057
1273
  }
1058
1274
  get series() {
1059
1275
  return (this.dataSource()?.series ?? null) || null;
1060
1276
  }
1061
1277
  get tags() {
1062
- return this.normalizeTags(this.dataSource()?.tags ?? null);
1278
+ return this.normalizeTags(this.dataSource()?.tags ?? undefined);
1063
1279
  }
1064
1280
  get hasTaxonomy() {
1065
- return !!this.contentPillar || !!this.series || this.tags.length > 0;
1281
+ return this.contentDimensions.length > 0 || !!this.series || this.tags.length > 0;
1282
+ }
1283
+ normalizeDimensions(post) {
1284
+ if (!post)
1285
+ return [];
1286
+ const asArray = (value) => {
1287
+ if (Array.isArray(value))
1288
+ return value.map(v => `${v}`.trim()).filter(Boolean);
1289
+ if (typeof value === 'string')
1290
+ return [`${value}`.trim()].filter(Boolean);
1291
+ return undefined;
1292
+ };
1293
+ const dims = [asArray(post.dimensions), asArray(post.pillars), asArray(post.dimension ?? post.pillar)]
1294
+ .filter(Boolean)
1295
+ .flat();
1296
+ return Array.from(new Set(dims));
1066
1297
  }
1067
1298
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgRhombusBlogPostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1068
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.4", type: NgRhombusBlogPostComponent, isStandalone: true, selector: "ng-rhombus-blog-post", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<mat-card>\r\n\t<mat-card-header>\r\n\t\t<mat-card-title>{{ dataSource()?.title }}</mat-card-title>\r\n\t\t<mat-card-subtitle>\r\n\t\t\t@if (contentPillar || series) {\r\n\t\t\t<mat-chip-set aria-label=\"Post taxonomy\" role=\"list\">\r\n\t\t\t\t@if (contentPillar) {\r\n\t\t\t\t<mat-chip role=\"listitem\" class=\"primary-chips-theme\" [highlighted]=\"true\">Pillar: {{ contentPillar\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t\t@if (series) {\r\n\t\t\t\t<mat-chip role=\"listitem\" class=\"secondary-chips-theme\" [highlighted]=\"true\">Series: {{ series\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t</mat-chip-set>\r\n\t\t\t}\r\n\t\t</mat-card-subtitle>\r\n\t</mat-card-header>\r\n\t<mat-card-content>\r\n\t\t<div class=\"flex items-center justify-between\">\r\n\t\t\t<p class=\"timestamp\">\r\n\t\t\t\t{{ dataSource()?.readTimeMinutes }} {{ dataSource()?.readTimeMinutes === 1 ? 'min' : 'mins' }}\r\n\t\t\t\t&middot;\r\n\t\t\t\t{{ timestampToMillis(dataSource()?.timestamp) | date: 'MMM d, y' }}\r\n\t\t\t</p>\r\n\t\t\t<div class=\"flex-1\"></div>\r\n\t\t\t<button matIconButton [matMenuTriggerFor]=\"shareMenu\" aria-label=\"Share post\">\r\n\t\t\t\t<mat-icon>share</mat-icon>\r\n\t\t\t</button>\r\n\t\t</div>\r\n\r\n\t\t<mat-menu #shareMenu=\"matMenu\">\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.twitter\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faXTwitter\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on X</span>\r\n\t\t\t</a>\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.facebook\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faFacebook\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on Facebook</span>\r\n\t\t\t</a>\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.bluesky\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faBluesky\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on Bluesky</span>\r\n\t\t\t</a>\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.linkedin\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faLinkedin\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on LinkedIn</span>\r\n\t\t\t</a>\r\n\t\t\t<button mat-menu-item (click)=\"copyLink()\">\r\n\t\t\t\t<mat-icon>content_copy</mat-icon>\r\n\t\t\t\t<span>Copy link</span>\r\n\t\t\t</button>\r\n\t\t</mat-menu>\r\n\t</mat-card-content>\r\n\t<img mat-card-image [src]=\"dataSource()?.thumbnail\" />\r\n\t<mat-card-content class=\"content\">\r\n\t\t<ng-rhombus-markdown\r\n\t\t\t[classes]=\"{ 'prose': true, 'dark:prose-invert': themeService.isDarkMode() }\"\r\n\t\t\t[data]=\"dataSource()?.content\"\r\n\t\t/>\r\n\t</mat-card-content>\r\n\t@if (tags.length) {\r\n\t<mat-card-content>\r\n\t\t<mat-chip-set aria-label=\"Post tags\" role=\"list\">\r\n\t\t\t@for (t of tags; track t) {\r\n\t\t\t<mat-chip role=\"listitem\" highlighted=\"true\" class=\"neutral-chips-theme\">#{{ t }}</mat-chip>\r\n\t\t\t}\r\n\t\t</mat-chip-set>\r\n\t</mat-card-content>\r\n\t}\r\n</mat-card>", styles: [".neutral-chips-theme{--mat-chip-outline-color: var(--mat-sys-surface-variant);--mat-chip-elevated-selected-container-color: var(--mat-sys-surface-variant);--mat-chip-selected-label-text-color: var(--mat-sys-on-surface-variant);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.primary-chips-theme{--mat-chip-outline-color: var(--mat-sys-primary);--mat-chip-elevated-selected-container-color: var(--mat-sys-primary);--mat-chip-selected-label-text-color: var(--mat-sys-on-primary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.secondary-chips-theme{--mat-chip-outline-color: var(--mat-sys-secondary);--mat-chip-elevated-selected-container-color: var(--mat-sys-secondary);--mat-chip-selected-label-text-color: var(--mat-sys-on-secondary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.card-image{--mat-card-elevated-container-shape: var(--mat-sys-shape-medium)}.mat-mdc-card-header{padding:32px 32px 16px}.mat-mdc-card-footer,.mat-mdc-card-content{padding:0 32px 32px}.content{padding:32px}.mat-mdc-card-title{margin-bottom:12px}.mat-mdc-card{border-radius:0}\n"], dependencies: [{ kind: "component", type: NgRhombusMarkdownComponent, selector: "ng-rhombus-markdown", inputs: ["data", "classes"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i2$2.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i2$2.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i2$2.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i2$2.MatCardImage, selector: "[mat-card-image], [matCardImage]" }, { kind: "directive", type: i2$2.MatCardSubtitle, selector: "mat-card-subtitle, [mat-card-subtitle], [matCardSubtitle]" }, { kind: "directive", type: i2$2.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i2$3.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "component", type: i2$3.MatChipSet, selector: "mat-chip-set", inputs: ["disabled", "role", "tabIndex"] }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$5.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }, { kind: "pipe", type: DatePipe, name: "date" }] }); }
1299
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.4", type: NgRhombusBlogPostComponent, isStandalone: true, selector: "ng-rhombus-blog-post", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<mat-card>\r\n\t<mat-card-header>\r\n\t\t<mat-card-title>{{ dataSource()?.title }}</mat-card-title>\r\n\t\t<mat-card-subtitle>\r\n\t\t\t@if (contentDimensions.length || series) {\r\n\t\t\t<mat-chip-set aria-label=\"Post taxonomy\" role=\"list\">\r\n\t\t\t\t@for (d of contentDimensions; track d) {\r\n\t\t\t\t<mat-chip role=\"listitem\" class=\"primary-chips-theme\" [highlighted]=\"true\">Dimension: {{ d }}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t\t@if (series) {\r\n\t\t\t\t<mat-chip role=\"listitem\" class=\"secondary-chips-theme\" [highlighted]=\"true\">Series: {{ series\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t</mat-chip-set>\r\n\t\t\t}\r\n\t\t</mat-card-subtitle>\r\n\t</mat-card-header>\r\n\t<mat-card-content>\r\n\t\t<div class=\"flex items-center justify-between\">\r\n\t\t\t<p class=\"timestamp\">\r\n\t\t\t\t{{ dataSource()?.readingTime }}\r\n\t\t\t\t{{ dataSource()?.readingTime === 1 ? 'min' : 'mins' }}\r\n\t\t\t\t&middot;\r\n\t\t\t\t{{ timestampToMillis(getDisplayDate(dataSource())) | date: 'MMM d, y' }}\r\n\t\t\t</p>\r\n\t\t\t<div class=\"flex-1\"></div>\r\n\t\t\t<button matIconButton [matMenuTriggerFor]=\"shareMenu\" aria-label=\"Share post\">\r\n\t\t\t\t<mat-icon>share</mat-icon>\r\n\t\t\t</button>\r\n\t\t</div>\r\n\r\n\t\t<mat-menu #shareMenu=\"matMenu\">\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.twitter\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faXTwitter\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on X</span>\r\n\t\t\t</a>\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.facebook\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faFacebook\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on Facebook</span>\r\n\t\t\t</a>\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.bluesky\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faBluesky\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on Bluesky</span>\r\n\t\t\t</a>\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.linkedin\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faLinkedin\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on LinkedIn</span>\r\n\t\t\t</a>\r\n\t\t\t<button mat-menu-item (click)=\"copyLink()\">\r\n\t\t\t\t<mat-icon>content_copy</mat-icon>\r\n\t\t\t\t<span>Copy link</span>\r\n\t\t\t</button>\r\n\t\t</mat-menu>\r\n\t</mat-card-content>\r\n\t<img mat-card-image [src]=\"dataSource()?.thumbnail\" />\r\n\t<mat-card-content class=\"content\">\r\n\t\t<ng-rhombus-markdown [classes]=\"{ 'prose': true, 'dark:prose-invert': themeService.isDarkMode() }\"\r\n\t\t\t[data]=\"dataSource()?.content\" />\r\n\t</mat-card-content>\r\n\t@if (tags.length) {\r\n\t<mat-card-content>\r\n\t\t<mat-chip-set aria-label=\"Post tags\" role=\"list\">\r\n\t\t\t@for (t of tags; track t) {\r\n\t\t\t<mat-chip role=\"listitem\" highlighted=\"true\" class=\"neutral-chips-theme\">#{{ t }}</mat-chip>\r\n\t\t\t}\r\n\t\t</mat-chip-set>\r\n\t</mat-card-content>\r\n\t}\r\n</mat-card>", styles: [".neutral-chips-theme{--mat-chip-outline-color: var(--mat-sys-surface-variant);--mat-chip-elevated-selected-container-color: var(--mat-sys-surface-variant);--mat-chip-selected-label-text-color: var(--mat-sys-on-surface-variant);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.primary-chips-theme{--mat-chip-outline-color: var(--mat-sys-primary);--mat-chip-elevated-selected-container-color: var(--mat-sys-primary);--mat-chip-selected-label-text-color: var(--mat-sys-on-primary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.secondary-chips-theme{--mat-chip-outline-color: var(--mat-sys-secondary);--mat-chip-elevated-selected-container-color: var(--mat-sys-secondary);--mat-chip-selected-label-text-color: var(--mat-sys-on-secondary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.card-image{--mat-card-elevated-container-shape: var(--mat-sys-shape-medium)}.mat-mdc-card-header{padding:32px 32px 16px}.mat-mdc-card-footer,.mat-mdc-card-content{padding:0 32px 32px}.content{padding:32px}.mat-mdc-card-title{margin-bottom:12px}.mat-mdc-card{border-radius:0}\n"], dependencies: [{ kind: "component", type: NgRhombusMarkdownComponent, selector: "ng-rhombus-markdown", inputs: ["data", "classes"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i2$2.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i2$2.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i2$2.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i2$2.MatCardImage, selector: "[mat-card-image], [matCardImage]" }, { kind: "directive", type: i2$2.MatCardSubtitle, selector: "mat-card-subtitle, [mat-card-subtitle], [matCardSubtitle]" }, { kind: "directive", type: i2$2.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i2$3.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "component", type: i2$3.MatChipSet, selector: "mat-chip-set", inputs: ["disabled", "role", "tabIndex"] }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$5.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }, { kind: "pipe", type: DatePipe, name: "date" }] }); }
1069
1300
  }
1070
1301
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgRhombusBlogPostComponent, decorators: [{
1071
1302
  type: Component,
1072
- args: [{ selector: 'ng-rhombus-blog-post', imports: [DatePipe, NgClass, NgRhombusMarkdownComponent, MatCardModule, MatMenuModule, MatIconModule, MatButtonModule, MatChipsModule, FontAwesomeModule], template: "<mat-card>\r\n\t<mat-card-header>\r\n\t\t<mat-card-title>{{ dataSource()?.title }}</mat-card-title>\r\n\t\t<mat-card-subtitle>\r\n\t\t\t@if (contentPillar || series) {\r\n\t\t\t<mat-chip-set aria-label=\"Post taxonomy\" role=\"list\">\r\n\t\t\t\t@if (contentPillar) {\r\n\t\t\t\t<mat-chip role=\"listitem\" class=\"primary-chips-theme\" [highlighted]=\"true\">Pillar: {{ contentPillar\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t\t@if (series) {\r\n\t\t\t\t<mat-chip role=\"listitem\" class=\"secondary-chips-theme\" [highlighted]=\"true\">Series: {{ series\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t</mat-chip-set>\r\n\t\t\t}\r\n\t\t</mat-card-subtitle>\r\n\t</mat-card-header>\r\n\t<mat-card-content>\r\n\t\t<div class=\"flex items-center justify-between\">\r\n\t\t\t<p class=\"timestamp\">\r\n\t\t\t\t{{ dataSource()?.readTimeMinutes }} {{ dataSource()?.readTimeMinutes === 1 ? 'min' : 'mins' }}\r\n\t\t\t\t&middot;\r\n\t\t\t\t{{ timestampToMillis(dataSource()?.timestamp) | date: 'MMM d, y' }}\r\n\t\t\t</p>\r\n\t\t\t<div class=\"flex-1\"></div>\r\n\t\t\t<button matIconButton [matMenuTriggerFor]=\"shareMenu\" aria-label=\"Share post\">\r\n\t\t\t\t<mat-icon>share</mat-icon>\r\n\t\t\t</button>\r\n\t\t</div>\r\n\r\n\t\t<mat-menu #shareMenu=\"matMenu\">\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.twitter\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faXTwitter\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on X</span>\r\n\t\t\t</a>\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.facebook\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faFacebook\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on Facebook</span>\r\n\t\t\t</a>\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.bluesky\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faBluesky\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on Bluesky</span>\r\n\t\t\t</a>\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.linkedin\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faLinkedin\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on LinkedIn</span>\r\n\t\t\t</a>\r\n\t\t\t<button mat-menu-item (click)=\"copyLink()\">\r\n\t\t\t\t<mat-icon>content_copy</mat-icon>\r\n\t\t\t\t<span>Copy link</span>\r\n\t\t\t</button>\r\n\t\t</mat-menu>\r\n\t</mat-card-content>\r\n\t<img mat-card-image [src]=\"dataSource()?.thumbnail\" />\r\n\t<mat-card-content class=\"content\">\r\n\t\t<ng-rhombus-markdown\r\n\t\t\t[classes]=\"{ 'prose': true, 'dark:prose-invert': themeService.isDarkMode() }\"\r\n\t\t\t[data]=\"dataSource()?.content\"\r\n\t\t/>\r\n\t</mat-card-content>\r\n\t@if (tags.length) {\r\n\t<mat-card-content>\r\n\t\t<mat-chip-set aria-label=\"Post tags\" role=\"list\">\r\n\t\t\t@for (t of tags; track t) {\r\n\t\t\t<mat-chip role=\"listitem\" highlighted=\"true\" class=\"neutral-chips-theme\">#{{ t }}</mat-chip>\r\n\t\t\t}\r\n\t\t</mat-chip-set>\r\n\t</mat-card-content>\r\n\t}\r\n</mat-card>", styles: [".neutral-chips-theme{--mat-chip-outline-color: var(--mat-sys-surface-variant);--mat-chip-elevated-selected-container-color: var(--mat-sys-surface-variant);--mat-chip-selected-label-text-color: var(--mat-sys-on-surface-variant);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.primary-chips-theme{--mat-chip-outline-color: var(--mat-sys-primary);--mat-chip-elevated-selected-container-color: var(--mat-sys-primary);--mat-chip-selected-label-text-color: var(--mat-sys-on-primary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.secondary-chips-theme{--mat-chip-outline-color: var(--mat-sys-secondary);--mat-chip-elevated-selected-container-color: var(--mat-sys-secondary);--mat-chip-selected-label-text-color: var(--mat-sys-on-secondary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.card-image{--mat-card-elevated-container-shape: var(--mat-sys-shape-medium)}.mat-mdc-card-header{padding:32px 32px 16px}.mat-mdc-card-footer,.mat-mdc-card-content{padding:0 32px 32px}.content{padding:32px}.mat-mdc-card-title{margin-bottom:12px}.mat-mdc-card{border-radius:0}\n"] }]
1303
+ args: [{ selector: 'ng-rhombus-blog-post', imports: [DatePipe, NgRhombusMarkdownComponent, MatCardModule, MatMenuModule, MatIconModule, MatButtonModule, MatChipsModule, FontAwesomeModule], template: "<mat-card>\r\n\t<mat-card-header>\r\n\t\t<mat-card-title>{{ dataSource()?.title }}</mat-card-title>\r\n\t\t<mat-card-subtitle>\r\n\t\t\t@if (contentDimensions.length || series) {\r\n\t\t\t<mat-chip-set aria-label=\"Post taxonomy\" role=\"list\">\r\n\t\t\t\t@for (d of contentDimensions; track d) {\r\n\t\t\t\t<mat-chip role=\"listitem\" class=\"primary-chips-theme\" [highlighted]=\"true\">Dimension: {{ d }}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t\t@if (series) {\r\n\t\t\t\t<mat-chip role=\"listitem\" class=\"secondary-chips-theme\" [highlighted]=\"true\">Series: {{ series\r\n\t\t\t\t\t}}</mat-chip>\r\n\t\t\t\t}\r\n\t\t\t</mat-chip-set>\r\n\t\t\t}\r\n\t\t</mat-card-subtitle>\r\n\t</mat-card-header>\r\n\t<mat-card-content>\r\n\t\t<div class=\"flex items-center justify-between\">\r\n\t\t\t<p class=\"timestamp\">\r\n\t\t\t\t{{ dataSource()?.readingTime }}\r\n\t\t\t\t{{ dataSource()?.readingTime === 1 ? 'min' : 'mins' }}\r\n\t\t\t\t&middot;\r\n\t\t\t\t{{ timestampToMillis(getDisplayDate(dataSource())) | date: 'MMM d, y' }}\r\n\t\t\t</p>\r\n\t\t\t<div class=\"flex-1\"></div>\r\n\t\t\t<button matIconButton [matMenuTriggerFor]=\"shareMenu\" aria-label=\"Share post\">\r\n\t\t\t\t<mat-icon>share</mat-icon>\r\n\t\t\t</button>\r\n\t\t</div>\r\n\r\n\t\t<mat-menu #shareMenu=\"matMenu\">\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.twitter\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faXTwitter\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on X</span>\r\n\t\t\t</a>\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.facebook\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faFacebook\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on Facebook</span>\r\n\t\t\t</a>\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.bluesky\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faBluesky\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on Bluesky</span>\r\n\t\t\t</a>\r\n\t\t\t<a mat-menu-item [href]=\"shareLinks.linkedin\" target=\"_blank\" rel=\"noopener\">\r\n\t\t\t\t<fa-icon [icon]=\"faLinkedin\" class=\"mr-2\"></fa-icon>\r\n\t\t\t\t<span>Share on LinkedIn</span>\r\n\t\t\t</a>\r\n\t\t\t<button mat-menu-item (click)=\"copyLink()\">\r\n\t\t\t\t<mat-icon>content_copy</mat-icon>\r\n\t\t\t\t<span>Copy link</span>\r\n\t\t\t</button>\r\n\t\t</mat-menu>\r\n\t</mat-card-content>\r\n\t<img mat-card-image [src]=\"dataSource()?.thumbnail\" />\r\n\t<mat-card-content class=\"content\">\r\n\t\t<ng-rhombus-markdown [classes]=\"{ 'prose': true, 'dark:prose-invert': themeService.isDarkMode() }\"\r\n\t\t\t[data]=\"dataSource()?.content\" />\r\n\t</mat-card-content>\r\n\t@if (tags.length) {\r\n\t<mat-card-content>\r\n\t\t<mat-chip-set aria-label=\"Post tags\" role=\"list\">\r\n\t\t\t@for (t of tags; track t) {\r\n\t\t\t<mat-chip role=\"listitem\" highlighted=\"true\" class=\"neutral-chips-theme\">#{{ t }}</mat-chip>\r\n\t\t\t}\r\n\t\t</mat-chip-set>\r\n\t</mat-card-content>\r\n\t}\r\n</mat-card>", styles: [".neutral-chips-theme{--mat-chip-outline-color: var(--mat-sys-surface-variant);--mat-chip-elevated-selected-container-color: var(--mat-sys-surface-variant);--mat-chip-selected-label-text-color: var(--mat-sys-on-surface-variant);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.primary-chips-theme{--mat-chip-outline-color: var(--mat-sys-primary);--mat-chip-elevated-selected-container-color: var(--mat-sys-primary);--mat-chip-selected-label-text-color: var(--mat-sys-on-primary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.secondary-chips-theme{--mat-chip-outline-color: var(--mat-sys-secondary);--mat-chip-elevated-selected-container-color: var(--mat-sys-secondary);--mat-chip-selected-label-text-color: var(--mat-sys-on-secondary);box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f}.card-image{--mat-card-elevated-container-shape: var(--mat-sys-shape-medium)}.mat-mdc-card-header{padding:32px 32px 16px}.mat-mdc-card-footer,.mat-mdc-card-content{padding:0 32px 32px}.content{padding:32px}.mat-mdc-card-title{margin-bottom:12px}.mat-mdc-card{border-radius:0}\n"] }]
1073
1304
  }], propDecorators: { dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }] } });
1074
1305
 
1075
1306
  class NgRhombusBlogDeletePostComponent {
@@ -1392,5 +1623,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.4", ngImpor
1392
1623
  * Generated bundle index. Do not edit.
1393
1624
  */
1394
1625
 
1395
- 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, NgRhombusMarkdownComponent, NgRhombusPageComponent, NgRhombusSocialsListComponent, NgRhombusSocialsService, NgRhombusSocialsTableComponent, NgRhombusSpinnerComponent, NgRhombusWrapperComponent, SocialsSource, ThemeEnum, WrapperService, ngRhombusTimestampToMillis };
1626
+ export { BlogSeries, ContentDimension, IHome, NG_RHOMBUS_AUTH_ADAPTER, NG_RHOMBUS_BLOG_ADAPTER, NG_RHOMBUS_BLOG_THUMBNAIL_ADAPTER, NG_RHOMBUS_HOME_ADAPTER, NG_RHOMBUS_SEO_ADAPTER, NG_RHOMBUS_SITE_METADATA, NG_RHOMBUS_SOCIALS_ADAPTER, NgRhombusBlogAddEditComponent, NgRhombusBlogDeletePostComponent, NgRhombusBlogListComponent, NgRhombusBlogPostComponent, NgRhombusBlogPostLatestComponent, NgRhombusBlogPostThumbnailService, NgRhombusBlogService, NgRhombusBlogTableComponent, NgRhombusHomeAdminComponent, NgRhombusHomeService, NgRhombusLoginComponent, NgRhombusMarkdownComponent, NgRhombusPageComponent, NgRhombusSocialsListComponent, NgRhombusSocialsService, NgRhombusSocialsTableComponent, NgRhombusSpinnerComponent, NgRhombusWrapperComponent, SocialsSource, ThemeEnum, WrapperService, ngRhombusTimestampToMillis };
1396
1627
  //# sourceMappingURL=doug-williamson-ng-rhombus.mjs.map