@foblex/m-render 3.0.1 → 3.0.2

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.
@@ -1,15 +1,15 @@
1
- @import "./_variables";
2
- @import "./_badge";
3
- @import "./_alert";
4
- @import "./_button";
5
- @import "./_fonts";
6
- @import "./_icons";
7
- @import "./_preview-group";
8
- @import "./_code-group";
9
- @import "./_code-view";
10
- @import "./_code-highlight";
11
- @import './_doc-text';
12
- @import "./_table";
1
+ @use "./variables";
2
+ @use "./badge";
3
+ @use "./alert";
4
+ @use "./button";
5
+ @use "./fonts";
6
+ @use "./icons";
7
+ @use "./preview-group";
8
+ @use "./code-group";
9
+ @use "./code-view";
10
+ @use "./code-highlight";
11
+ @use "./doc-text";
12
+ @use "./table";
13
13
 
14
14
  html {
15
15
  height: 100%;
@@ -1351,8 +1351,10 @@ class MarkdownService {
1351
1351
  _provider = inject(F_PREVIEW_NAVIGATION_PROVIDER, { optional: true });
1352
1352
  _pageLayout = signal({ ...DEFAULT_MARKDOWN_PAGE_LAYOUT_OPTIONS }, ...(ngDevMode ? [{ debugName: "_pageLayout" }] : []));
1353
1353
  _pageSeo = signal(null, ...(ngDevMode ? [{ debugName: "_pageSeo" }] : []));
1354
+ _pageOrigin = signal(null, ...(ngDevMode ? [{ debugName: "_pageOrigin" }] : []));
1354
1355
  pageLayout = this._pageLayout.asReadonly();
1355
1356
  pageSeo = this._pageSeo.asReadonly();
1357
+ pageOrigin = this._pageOrigin.asReadonly();
1356
1358
  constructor() {
1357
1359
  this._markdown
1358
1360
  .use((x) => new ParseSingleCodeItem().render(x))
@@ -1425,15 +1427,17 @@ class MarkdownService {
1425
1427
  _parseFrontMatterData(rawFrontMatter) {
1426
1428
  const layout = { ...DEFAULT_MARKDOWN_PAGE_LAYOUT_OPTIONS };
1427
1429
  const seo = {};
1430
+ const origin = { url: null, label: null };
1428
1431
  rawFrontMatter
1429
1432
  .split(/\r?\n/)
1430
- .forEach((line) => this._parseFrontMatterLine(line, layout, seo));
1433
+ .forEach((line) => this._parseFrontMatterLine(line, layout, seo, origin));
1431
1434
  return {
1432
1435
  layout,
1433
1436
  seo: Object.keys(seo).length ? seo : null,
1437
+ origin: this._resolveOrigin(origin),
1434
1438
  };
1435
1439
  }
1436
- _parseFrontMatterLine(line, layout, seo) {
1440
+ _parseFrontMatterLine(line, layout, seo, origin) {
1437
1441
  const normalizedLine = line.trim();
1438
1442
  if (!normalizedLine || normalizedLine.startsWith('#')) {
1439
1443
  return;
@@ -1450,6 +1454,7 @@ class MarkdownService {
1450
1454
  const boolValue = this._parseBoolean(value);
1451
1455
  this._applyLayoutKey(key, boolValue, layout);
1452
1456
  this._applySeoKey(key, value, boolValue, seo);
1457
+ this._applyOriginKey(key, value, origin);
1453
1458
  }
1454
1459
  _normalizeFrontMatterValue(value) {
1455
1460
  const trimmed = value.trim();
@@ -1574,6 +1579,71 @@ class MarkdownService {
1574
1579
  return;
1575
1580
  }
1576
1581
  }
1582
+ _applyOriginKey(key, value, origin) {
1583
+ switch (key) {
1584
+ case 'origin':
1585
+ case 'originurl':
1586
+ case 'origin_url':
1587
+ case 'original':
1588
+ case 'originalurl':
1589
+ case 'original_url':
1590
+ case 'source':
1591
+ case 'sourceurl':
1592
+ case 'source_url': {
1593
+ const normalizedUrl = this._normalizeOriginUrl(value);
1594
+ if (normalizedUrl) {
1595
+ origin.url = normalizedUrl;
1596
+ }
1597
+ return;
1598
+ }
1599
+ case 'originlabel':
1600
+ case 'origin_label':
1601
+ case 'origintext':
1602
+ case 'origin_text':
1603
+ case 'sourcelabel':
1604
+ case 'source_label':
1605
+ origin.label = value;
1606
+ return;
1607
+ }
1608
+ }
1609
+ _normalizeOriginUrl(value) {
1610
+ const trimmed = value.trim();
1611
+ if (!trimmed) {
1612
+ return null;
1613
+ }
1614
+ const candidate = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
1615
+ try {
1616
+ const url = new URL(candidate);
1617
+ if (!['http:', 'https:'].includes(url.protocol)) {
1618
+ return null;
1619
+ }
1620
+ return url.toString();
1621
+ }
1622
+ catch {
1623
+ return null;
1624
+ }
1625
+ }
1626
+ _resolveOrigin(origin) {
1627
+ if (!origin.url) {
1628
+ return null;
1629
+ }
1630
+ return {
1631
+ url: origin.url,
1632
+ label: origin.label || this._getOriginLabel(origin.url),
1633
+ };
1634
+ }
1635
+ _getOriginLabel(originUrl) {
1636
+ try {
1637
+ const hostname = new URL(originUrl).hostname.toLowerCase().replace(/^www\./, '');
1638
+ if (hostname === 'medium.com' || hostname.endsWith('.medium.com')) {
1639
+ return 'Originally published on Medium';
1640
+ }
1641
+ return `Originally published on ${hostname}`;
1642
+ }
1643
+ catch {
1644
+ return 'Originally published externally';
1645
+ }
1646
+ }
1577
1647
  _parseNumberOrDefault(value, fallback) {
1578
1648
  const numericValue = Number(value);
1579
1649
  if (!Number.isFinite(numericValue) || numericValue <= 0) {
@@ -1584,6 +1654,7 @@ class MarkdownService {
1584
1654
  _applyPageContext(data) {
1585
1655
  this._pageLayout.set({ ...data.layout });
1586
1656
  this._pageSeo.set(data.seo ? { ...data.seo } : null);
1657
+ this._pageOrigin.set(data.origin ? { ...data.origin } : null);
1587
1658
  }
1588
1659
  _resetPageContext() {
1589
1660
  this._applyPageContext(this._getDefaultFrontMatterData());
@@ -1592,6 +1663,7 @@ class MarkdownService {
1592
1663
  return {
1593
1664
  layout: { ...DEFAULT_MARKDOWN_PAGE_LAYOUT_OPTIONS },
1594
1665
  seo: null,
1666
+ origin: null,
1595
1667
  };
1596
1668
  }
1597
1669
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: MarkdownService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
@@ -3461,6 +3533,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImpor
3461
3533
 
3462
3534
  class MarkdownRenderer {
3463
3535
  value = input.required(...(ngDevMode ? [{ debugName: "value" }] : []));
3536
+ origin = input(null, ...(ngDevMode ? [{ debugName: "origin" }] : []));
3464
3537
  _hostElement = inject(ElementRef).nativeElement;
3465
3538
  _router = inject(Router);
3466
3539
  _injector = inject(Injector);
@@ -3507,14 +3580,14 @@ class MarkdownRenderer {
3507
3580
  this._dynamicComponents.dispose();
3508
3581
  }
3509
3582
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: MarkdownRenderer, deps: [], target: i0.ɵɵFactoryTarget.Component });
3510
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: MarkdownRenderer, isStandalone: true, selector: "markdown-renderer", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "click": "_onDocumentClick($event)" }, classAttribute: "m-render" }, ngImport: i0, template: "<div [innerHTML]=\"value()\"></div>\n@if (value()) {\n <markdown-footer />\n}\n\n", styles: [":host{display:block;width:100%}@media(min-width:1280px){:host{width:calc(100% - var(--on-page-navigation-width) - var(--page-padding))}}@media(min-width:1280px){:host.expand-no-toc{width:100%}}:host.empty-navigation{margin:auto;max-width:900px}\n"], dependencies: [{ kind: "component", type: MarkdownFooter, selector: "markdown-footer" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3583
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: MarkdownRenderer, isStandalone: true, selector: "markdown-renderer", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, origin: { classPropertyName: "origin", publicName: "origin", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "_onDocumentClick($event)" }, classAttribute: "m-render" }, ngImport: i0, template: "@if (origin(); as pageOrigin) {\n <p class=\"origin-link\">\n <span class=\"origin-link-label\">{{ pageOrigin.label }}:</span>\n <a [href]=\"pageOrigin.url\"\n target=\"_blank\"\n rel=\"noopener noreferrer nofollow\">{{ pageOrigin.url }}</a>\n </p>\n}\n<div [innerHTML]=\"value()\"></div>\n@if (value()) {\n <markdown-footer />\n}\n", styles: [":host{display:block;width:100%}@media(min-width:1280px){:host{width:calc(100% - var(--on-page-navigation-width) - var(--page-padding))}}@media(min-width:1280px){:host.expand-no-toc{width:100%}}:host.empty-navigation{margin:auto;max-width:900px}.origin-link{margin:0 0 16px;border-left:2px solid var(--divider-color);padding:8px 12px;background-color:var(--soft-background);line-height:20px;font-size:14px}.origin-link-label{margin-right:4px;font-weight:600}.origin-link a{overflow-wrap:anywhere}\n"], dependencies: [{ kind: "component", type: MarkdownFooter, selector: "markdown-footer" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3511
3584
  }
3512
3585
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: MarkdownRenderer, decorators: [{
3513
3586
  type: Component,
3514
3587
  args: [{ selector: 'markdown-renderer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MarkdownFooter], host: {
3515
3588
  class: 'm-render',
3516
- }, template: "<div [innerHTML]=\"value()\"></div>\n@if (value()) {\n <markdown-footer />\n}\n\n", styles: [":host{display:block;width:100%}@media(min-width:1280px){:host{width:calc(100% - var(--on-page-navigation-width) - var(--page-padding))}}@media(min-width:1280px){:host.expand-no-toc{width:100%}}:host.empty-navigation{margin:auto;max-width:900px}\n"] }]
3517
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], _onDocumentClick: [{
3589
+ }, template: "@if (origin(); as pageOrigin) {\n <p class=\"origin-link\">\n <span class=\"origin-link-label\">{{ pageOrigin.label }}:</span>\n <a [href]=\"pageOrigin.url\"\n target=\"_blank\"\n rel=\"noopener noreferrer nofollow\">{{ pageOrigin.url }}</a>\n </p>\n}\n<div [innerHTML]=\"value()\"></div>\n@if (value()) {\n <markdown-footer />\n}\n", styles: [":host{display:block;width:100%}@media(min-width:1280px){:host{width:calc(100% - var(--on-page-navigation-width) - var(--page-padding))}}@media(min-width:1280px){:host.expand-no-toc{width:100%}}:host.empty-navigation{margin:auto;max-width:900px}.origin-link{margin:0 0 16px;border-left:2px solid var(--divider-color);padding:8px 12px;background-color:var(--soft-background);line-height:20px;font-size:14px}.origin-link-label{margin-right:4px;font-weight:600}.origin-link a{overflow-wrap:anywhere}\n"] }]
3590
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], origin: [{ type: i0.Input, args: [{ isSignal: true, alias: "origin", required: false }] }], _onDocumentClick: [{
3518
3591
  type: HostListener,
3519
3592
  args: ['click', ['$event']]
3520
3593
  }] } });
@@ -3526,6 +3599,7 @@ class MarkdownRouter {
3526
3599
  _dataProvider = inject(DocumentationStore);
3527
3600
  _metaService = inject(FMetaService, { optional: true });
3528
3601
  emptyNavigation = !this._dataProvider.getNavigation().length;
3602
+ pageOrigin = this._markdown.pageOrigin;
3529
3603
  shouldExpandContent = computed(() => {
3530
3604
  const layout = this._markdown.pageLayout();
3531
3605
  return layout.hideTableOfContent && layout.expandContentWithoutTableOfContent;
@@ -3539,7 +3613,7 @@ class MarkdownRouter {
3539
3613
  }), tap(() => this._metaService?.applyMarkdownSeo(this._markdown.pageSeo())));
3540
3614
  })), { initialValue: undefined });
3541
3615
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: MarkdownRouter, deps: [], target: i0.ɵɵFactoryTarget.Component });
3542
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.4", type: MarkdownRouter, isStandalone: true, selector: "markdown-router", host: { attributes: { "ngSkipHydration": "" }, properties: { "class.empty-navigation": "emptyNavigation" } }, ngImport: i0, template: "<markdown-renderer [value]=\"html()\"\n [class.empty-navigation]=\"emptyNavigation\"\n [class.expand-no-toc]=\"shouldExpandContent()\"/>\n", styles: [":host{display:block;width:100%;padding:48px var(--page-padding) 140px}@media(min-width:1280px){:host{padding-right:max(var(--page-padding),(100vw - var(--layout-max-width)) / 2);padding-left:max(var(--page-padding),(100vw - var(--layout-max-width)) / 4)}}@media(min-width:1280px){:host.empty-navigation{padding-right:max(var(--page-padding),(100vw - var(--layout-max-width)) / 2);padding-left:max(var(--page-padding),(100vw - var(--layout-max-width)) / 2)}}\n"], dependencies: [{ kind: "component", type: MarkdownRenderer, selector: "markdown-renderer", inputs: ["value"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3616
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.4", type: MarkdownRouter, isStandalone: true, selector: "markdown-router", host: { attributes: { "ngSkipHydration": "" }, properties: { "class.empty-navigation": "emptyNavigation" } }, ngImport: i0, template: "<markdown-renderer [value]=\"html()\"\n [origin]=\"pageOrigin()\"\n [class.empty-navigation]=\"emptyNavigation\"\n [class.expand-no-toc]=\"shouldExpandContent()\"/>\n", styles: [":host{display:block;width:100%;padding:48px var(--page-padding) 140px}@media(min-width:1280px){:host{padding-right:max(var(--page-padding),(100vw - var(--layout-max-width)) / 2);padding-left:max(var(--page-padding),(100vw - var(--layout-max-width)) / 4)}}@media(min-width:1280px){:host.empty-navigation{padding-right:max(var(--page-padding),(100vw - var(--layout-max-width)) / 2);padding-left:max(var(--page-padding),(100vw - var(--layout-max-width)) / 2)}}\n"], dependencies: [{ kind: "component", type: MarkdownRenderer, selector: "markdown-renderer", inputs: ["value", "origin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3543
3617
  }
3544
3618
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: MarkdownRouter, decorators: [{
3545
3619
  type: Component,
@@ -3548,7 +3622,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImpor
3548
3622
  '[class.empty-navigation]': 'emptyNavigation',
3549
3623
  }, imports: [
3550
3624
  MarkdownRenderer,
3551
- ], template: "<markdown-renderer [value]=\"html()\"\n [class.empty-navigation]=\"emptyNavigation\"\n [class.expand-no-toc]=\"shouldExpandContent()\"/>\n", styles: [":host{display:block;width:100%;padding:48px var(--page-padding) 140px}@media(min-width:1280px){:host{padding-right:max(var(--page-padding),(100vw - var(--layout-max-width)) / 2);padding-left:max(var(--page-padding),(100vw - var(--layout-max-width)) / 4)}}@media(min-width:1280px){:host.empty-navigation{padding-right:max(var(--page-padding),(100vw - var(--layout-max-width)) / 2);padding-left:max(var(--page-padding),(100vw - var(--layout-max-width)) / 2)}}\n"] }]
3625
+ ], template: "<markdown-renderer [value]=\"html()\"\n [origin]=\"pageOrigin()\"\n [class.empty-navigation]=\"emptyNavigation\"\n [class.expand-no-toc]=\"shouldExpandContent()\"/>\n", styles: [":host{display:block;width:100%;padding:48px var(--page-padding) 140px}@media(min-width:1280px){:host{padding-right:max(var(--page-padding),(100vw - var(--layout-max-width)) / 2);padding-left:max(var(--page-padding),(100vw - var(--layout-max-width)) / 4)}}@media(min-width:1280px){:host.empty-navigation{padding-right:max(var(--page-padding),(100vw - var(--layout-max-width)) / 2);padding-left:max(var(--page-padding),(100vw - var(--layout-max-width)) / 2)}}\n"] }]
3552
3626
  }] });
3553
3627
 
3554
3628
  var index$2 = /*#__PURE__*/Object.freeze({