@foblex/m-render 4.0.1 → 4.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,7 +1,6 @@
1
1
  .m-render .doc-content a,
2
2
  .f-text-link {
3
3
  border-radius: var(--f-link-radius);
4
- color: currentcolor;
5
4
  cursor: pointer;
6
5
  font-weight: var(--f-link-font-weight);
7
6
  overflow-wrap: anywhere;
@@ -1465,17 +1465,36 @@ class MarkdownService {
1465
1465
  _normalizeLinks(html) {
1466
1466
  const currentPath = this._router.url;
1467
1467
  const prefix = currentPath.substring(0, currentPath.lastIndexOf('/'));
1468
- return html.replace(/<a\s+href="([^"]*)"/g, (match, href) => {
1469
- if (!this._isExternalLink(href)) {
1470
- let newHref = href.substring(0);
1471
- if (!href.startsWith('./')) {
1472
- newHref = href.startsWith('/') ? `${prefix}${href}` : `${prefix}/${href}`;
1473
- }
1474
- return `<a href="${newHref}"`;
1468
+ return html.replace(/<a\b[^>]*>/g, (tag) => {
1469
+ const tagWithClasses = this._appendLinkClasses(tag);
1470
+ const hrefMatch = tagWithClasses.match(/\bhref=(["'])([^"']*)\1/);
1471
+ if (!hrefMatch) {
1472
+ return tagWithClasses;
1473
+ }
1474
+ const href = hrefMatch[2];
1475
+ if (this._isExternalLink(href)) {
1476
+ return tagWithClasses;
1475
1477
  }
1476
- return match;
1478
+ let newHref = href.substring(0);
1479
+ if (!href.startsWith('./')) {
1480
+ newHref = href.startsWith('/') ? `${prefix}${href}` : `${prefix}/${href}`;
1481
+ }
1482
+ return tagWithClasses.replace(hrefMatch[0], `href=${hrefMatch[1]}${newHref}${hrefMatch[1]}`);
1477
1483
  });
1478
1484
  }
1485
+ _appendLinkClasses(tag) {
1486
+ const classes = ['f-text-link', 'f-text-link-primary'];
1487
+ const classMatch = tag.match(/\bclass=(["'])([^"']*)\1/);
1488
+ if (!classMatch) {
1489
+ return tag.replace('<a', `<a class="${classes.join(' ')}"`);
1490
+ }
1491
+ const existingClasses = classMatch[2].split(/\s+/).filter(Boolean);
1492
+ const mergedClasses = [
1493
+ ...existingClasses,
1494
+ ...classes.filter((className) => !existingClasses.includes(className)),
1495
+ ];
1496
+ return tag.replace(classMatch[0], `class=${classMatch[1]}${mergedClasses.join(' ')}${classMatch[1]}`);
1497
+ }
1479
1498
  _isExternalLink(href) {
1480
1499
  return href.startsWith('www') || href.startsWith('http');
1481
1500
  }
@@ -3205,14 +3224,14 @@ class PreviewCard extends PreviewCardBase {
3205
3224
  this._fPreviewGroupService.remove(this);
3206
3225
  }
3207
3226
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: PreviewCard, deps: null, target: i0.ɵɵFactoryTarget.Component });
3208
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: PreviewCard, isStandalone: true, selector: "a[preview-card]", host: { properties: { "attr.href": "url", "attr.title": "viewModel?.text" } }, usesInheritance: true, ngImport: i0, template: "@if (viewModel) {\n @if (src()) {\n <div class=\"media\">\n <img\n [src]=\"src()\"\n [alt]=\"viewModel.description || viewModel.text\"\n [title]=\"viewModel.text\"\n [attr.width]=\"viewModel.image_width || null\"\n [attr.height]=\"viewModel.image_height || null\">\n </div>\n }\n\n <div class=\"content\">\n @if (viewModel.badge) {\n <div class=\"meta\">\n <span class=\"f-badge sm {{viewModel.badge.type}}\">{{ viewModel.badge.text }}</span>\n </div>\n }\n\n <div class=\"title\">{{ viewModel.text }}</div>\n <div class=\"description\">{{ viewModel.description }}</div>\n </div>\n}\n\n", styles: [":host{--f-preview-card-radius: calc(var(--border-radius) + 2px);--f-preview-card-media-radius: calc(var(--border-radius) - 2px);position:relative;display:block;box-sizing:border-box;width:100%;padding:14px;border-radius:var(--f-preview-card-radius);text-decoration:none!important;color:inherit!important;cursor:pointer;-webkit-user-select:none;user-select:none;isolation:isolate}:host:before{position:absolute;inset:0;border:1px solid var(--alpha-12);border-radius:inherit;background-color:var(--background-color);box-shadow:var(--shadow-1);content:\"\";transition:background-color .15s ease,border-color .15s ease,transform .15s ease}:host:hover:before{border-color:var(--divider-color);background-color:var(--alt-background)}:host:hover img{transform:scale(1.02)}:host:active:before{transform:scale(.985)}:host:focus-visible{outline:none}:host:focus-visible:before{border-color:var(--primary-1);box-shadow:0 0 0 3px var(--primary-soft),var(--shadow-1)}:host>*{position:relative;z-index:1}:host .media{overflow:hidden;border:1px solid var(--divider-color);border-radius:var(--f-preview-card-media-radius);background-color:var(--soft-background);aspect-ratio:16/9}:host img{display:block;width:100%;height:100%;object-fit:cover;transition:transform .2s ease}:host .content{display:flex;flex-direction:column;gap:8px;min-width:0}:host .media+.content{padding-top:14px}:host .meta{display:flex;align-items:center;min-height:var(--f-badge-compact-height);margin-bottom:2px}:host .title{margin:0;color:var(--primary-text);font-size:18px;font-weight:600;line-height:24px;letter-spacing:-.01em;text-transform:none;width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}:host .description{margin:0!important;font-size:15px;line-height:24px;color:var(--secondary-text);width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}@media(min-width:640px){:host{width:calc((100% - 24px)/2)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3227
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: PreviewCard, isStandalone: true, selector: "a[preview-card]", host: { properties: { "attr.href": "url", "attr.title": "viewModel?.text" } }, usesInheritance: true, ngImport: i0, template: "@if (viewModel) {\n @if (src()) {\n <div class=\"media\">\n <img\n [src]=\"src()\"\n [alt]=\"viewModel.description || viewModel.text\"\n [title]=\"viewModel.text\"\n [attr.width]=\"viewModel.image_width || null\"\n [attr.height]=\"viewModel.image_height || null\">\n </div>\n }\n\n <div class=\"content\">\n @if (viewModel.badge) {\n <div class=\"meta\">\n <span class=\"f-badge sm {{viewModel.badge.type}}\">{{ viewModel.badge.text }}</span>\n </div>\n }\n\n <div class=\"title\">{{ viewModel.text }}</div>\n <div class=\"description\">{{ viewModel.description }}</div>\n </div>\n}\n\n", styles: [":host{--f-preview-card-radius: calc(var(--border-radius) + 2px);--f-preview-card-media-radius: calc(var(--border-radius) - 2px);position:relative;display:block;box-sizing:border-box;width:100%;padding:14px;border-radius:var(--f-preview-card-radius);text-decoration:none!important;color:inherit!important;cursor:pointer;-webkit-user-select:none;user-select:none;isolation:isolate}:host:before{position:absolute;inset:0;border:1px solid var(--alpha-12);border-radius:inherit;background-color:var(--background-color);content:\"\";transition:background-color .15s ease,border-color .15s ease,transform .15s ease}:host:hover:before{border-color:var(--divider-color);background-color:var(--alt-background)}:host:hover img{transform:scale(1.02)}:host:active:before{transform:scale(.985)}:host:focus-visible{outline:none}:host:focus-visible:before{border-color:var(--primary-1);box-shadow:0 0 0 3px var(--primary-soft),var(--shadow-1)}:host>*{position:relative;z-index:1}:host .media{overflow:hidden;border:1px solid var(--divider-color);border-radius:var(--f-preview-card-media-radius);background-color:var(--soft-background);aspect-ratio:16/9}:host img{display:block;width:100%;height:100%;object-fit:cover;transition:transform .2s ease}:host .content{display:flex;flex-direction:column;gap:8px;min-width:0}:host .media+.content{padding-top:14px}:host .meta{display:flex;align-items:center;min-height:var(--f-badge-compact-height);margin-bottom:2px}:host .title{margin:0;color:var(--primary-text);font-size:18px;font-weight:600;line-height:24px;letter-spacing:-.01em;text-transform:none;width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}:host .description{margin:0!important;font-size:15px;line-height:24px;color:var(--secondary-text);width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}@media(min-width:640px){:host{width:calc((100% - 24px)/2)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3209
3228
  }
3210
3229
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: PreviewCard, decorators: [{
3211
3230
  type: Component,
3212
3231
  args: [{ selector: 'a[preview-card]', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
3213
3232
  '[attr.href]': 'url',
3214
3233
  '[attr.title]': 'viewModel?.text',
3215
- }, template: "@if (viewModel) {\n @if (src()) {\n <div class=\"media\">\n <img\n [src]=\"src()\"\n [alt]=\"viewModel.description || viewModel.text\"\n [title]=\"viewModel.text\"\n [attr.width]=\"viewModel.image_width || null\"\n [attr.height]=\"viewModel.image_height || null\">\n </div>\n }\n\n <div class=\"content\">\n @if (viewModel.badge) {\n <div class=\"meta\">\n <span class=\"f-badge sm {{viewModel.badge.type}}\">{{ viewModel.badge.text }}</span>\n </div>\n }\n\n <div class=\"title\">{{ viewModel.text }}</div>\n <div class=\"description\">{{ viewModel.description }}</div>\n </div>\n}\n\n", styles: [":host{--f-preview-card-radius: calc(var(--border-radius) + 2px);--f-preview-card-media-radius: calc(var(--border-radius) - 2px);position:relative;display:block;box-sizing:border-box;width:100%;padding:14px;border-radius:var(--f-preview-card-radius);text-decoration:none!important;color:inherit!important;cursor:pointer;-webkit-user-select:none;user-select:none;isolation:isolate}:host:before{position:absolute;inset:0;border:1px solid var(--alpha-12);border-radius:inherit;background-color:var(--background-color);box-shadow:var(--shadow-1);content:\"\";transition:background-color .15s ease,border-color .15s ease,transform .15s ease}:host:hover:before{border-color:var(--divider-color);background-color:var(--alt-background)}:host:hover img{transform:scale(1.02)}:host:active:before{transform:scale(.985)}:host:focus-visible{outline:none}:host:focus-visible:before{border-color:var(--primary-1);box-shadow:0 0 0 3px var(--primary-soft),var(--shadow-1)}:host>*{position:relative;z-index:1}:host .media{overflow:hidden;border:1px solid var(--divider-color);border-radius:var(--f-preview-card-media-radius);background-color:var(--soft-background);aspect-ratio:16/9}:host img{display:block;width:100%;height:100%;object-fit:cover;transition:transform .2s ease}:host .content{display:flex;flex-direction:column;gap:8px;min-width:0}:host .media+.content{padding-top:14px}:host .meta{display:flex;align-items:center;min-height:var(--f-badge-compact-height);margin-bottom:2px}:host .title{margin:0;color:var(--primary-text);font-size:18px;font-weight:600;line-height:24px;letter-spacing:-.01em;text-transform:none;width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}:host .description{margin:0!important;font-size:15px;line-height:24px;color:var(--secondary-text);width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}@media(min-width:640px){:host{width:calc((100% - 24px)/2)}}\n"] }]
3234
+ }, template: "@if (viewModel) {\n @if (src()) {\n <div class=\"media\">\n <img\n [src]=\"src()\"\n [alt]=\"viewModel.description || viewModel.text\"\n [title]=\"viewModel.text\"\n [attr.width]=\"viewModel.image_width || null\"\n [attr.height]=\"viewModel.image_height || null\">\n </div>\n }\n\n <div class=\"content\">\n @if (viewModel.badge) {\n <div class=\"meta\">\n <span class=\"f-badge sm {{viewModel.badge.type}}\">{{ viewModel.badge.text }}</span>\n </div>\n }\n\n <div class=\"title\">{{ viewModel.text }}</div>\n <div class=\"description\">{{ viewModel.description }}</div>\n </div>\n}\n\n", styles: [":host{--f-preview-card-radius: calc(var(--border-radius) + 2px);--f-preview-card-media-radius: calc(var(--border-radius) - 2px);position:relative;display:block;box-sizing:border-box;width:100%;padding:14px;border-radius:var(--f-preview-card-radius);text-decoration:none!important;color:inherit!important;cursor:pointer;-webkit-user-select:none;user-select:none;isolation:isolate}:host:before{position:absolute;inset:0;border:1px solid var(--alpha-12);border-radius:inherit;background-color:var(--background-color);content:\"\";transition:background-color .15s ease,border-color .15s ease,transform .15s ease}:host:hover:before{border-color:var(--divider-color);background-color:var(--alt-background)}:host:hover img{transform:scale(1.02)}:host:active:before{transform:scale(.985)}:host:focus-visible{outline:none}:host:focus-visible:before{border-color:var(--primary-1);box-shadow:0 0 0 3px var(--primary-soft),var(--shadow-1)}:host>*{position:relative;z-index:1}:host .media{overflow:hidden;border:1px solid var(--divider-color);border-radius:var(--f-preview-card-media-radius);background-color:var(--soft-background);aspect-ratio:16/9}:host img{display:block;width:100%;height:100%;object-fit:cover;transition:transform .2s ease}:host .content{display:flex;flex-direction:column;gap:8px;min-width:0}:host .media+.content{padding-top:14px}:host .meta{display:flex;align-items:center;min-height:var(--f-badge-compact-height);margin-bottom:2px}:host .title{margin:0;color:var(--primary-text);font-size:18px;font-weight:600;line-height:24px;letter-spacing:-.01em;text-transform:none;width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}:host .description{margin:0!important;font-size:15px;line-height:24px;color:var(--secondary-text);width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}@media(min-width:640px){:host{width:calc((100% - 24px)/2)}}\n"] }]
3216
3235
  }] });
3217
3236
 
3218
3237
  var previewCard = /*#__PURE__*/Object.freeze({
@@ -3286,11 +3305,11 @@ class ShowcaseItem {
3286
3305
  return theme === 'dark' ? (model.imageUrlDark || model.imageUrl) : model.imageUrl;
3287
3306
  }, ...(ngDevMode ? [{ debugName: "src" }] : []));
3288
3307
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: ShowcaseItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
3289
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: ShowcaseItem, isStandalone: true, selector: "showcase-item", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@let data = model();\n\n@if (data) {\n @if (src()) {\n <div class=\"media\">\n <img [src]=\"src()\" [alt]=\"data.description || data.name\" [title]=\"data.name\">\n </div>\n }\n\n <div class=\"content\">\n @if (data.tags?.length) {\n <div class=\"meta\">\n @for (tag of data.tags; track tag) {\n <span class=\"f-badge sm tip\">{{ tag }}</span>\n }\n </div>\n }\n\n <div class=\"title\">{{ data.name }}</div>\n <div class=\"description\">{{ data.description }}</div>\n\n @if (data.links?.length) {\n <div class=\"links\">\n @for (link of data.links; track link.text) {\n <a class=\"f-text-link f-text-link-primary\" href=\"{{ link.url }}\" target=\"_blank\" rel=\"noopener\">{{ link.text }}</a>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{--f-showcase-card-radius: calc(var(--border-radius) + 2px);--f-showcase-card-media-radius: calc(var(--border-radius) - 2px);position:relative;display:block;box-sizing:border-box;width:100%;padding:14px;border-radius:var(--f-showcase-card-radius);isolation:isolate}:host:before{position:absolute;inset:0;border:1px solid var(--alpha-12);border-radius:inherit;background-color:var(--background-color);box-shadow:var(--shadow-1);content:\"\";transition:background-color .15s ease,border-color .15s ease,transform .15s ease}:host:hover:before{border-color:var(--divider-color);background-color:var(--alt-background)}:host:hover img{transform:scale(1.02)}:host:focus-within:before{border-color:var(--primary-1);box-shadow:0 0 0 3px var(--primary-soft),var(--shadow-1)}:host>*{position:relative;z-index:1}:host .media{overflow:hidden;border:1px solid var(--divider-color);border-radius:var(--f-showcase-card-media-radius);background-color:var(--soft-background);aspect-ratio:16/9}:host img{display:block;width:100%;height:100%;object-fit:cover;transition:transform .2s ease}:host .content{display:flex;flex-direction:column;gap:8px;min-width:0}:host .media+.content{padding-top:14px}:host .meta{display:flex;align-items:center;flex-wrap:wrap;gap:8px;min-height:var(--f-badge-compact-height);margin-bottom:2px}:host .title{margin:0;color:var(--primary-text);font-size:18px;font-weight:600;line-height:24px;letter-spacing:-.01em;text-transform:none;width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}:host .description{margin:0!important;font-size:15px;line-height:24px;color:var(--secondary-text);width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}@media(min-width:640px){:host{width:calc((100% - 24px)/2)}}.links{display:flex;flex-wrap:wrap;gap:12px;margin-top:4px}.links a{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3308
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: ShowcaseItem, isStandalone: true, selector: "showcase-item", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@let data = model();\n\n@if (data) {\n @if (src()) {\n <div class=\"media\">\n <img [src]=\"src()\" [alt]=\"data.description || data.name\" [title]=\"data.name\">\n </div>\n }\n\n <div class=\"content\">\n @if (data.tags?.length) {\n <div class=\"meta\">\n @for (tag of data.tags; track tag) {\n <span class=\"f-badge sm tip\">{{ tag }}</span>\n }\n </div>\n }\n\n <div class=\"title\">{{ data.name }}</div>\n <div class=\"description\">{{ data.description }}</div>\n\n @if (data.links.length) {\n <div class=\"links\">\n @for (link of data.links; track link.text) {\n <a class=\"f-text-link f-text-link-primary\" href=\"{{ link.url }}\" target=\"_blank\" rel=\"noopener\">{{ link.text }}</a>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{--f-showcase-card-radius: calc(var(--border-radius) + 2px);--f-showcase-card-media-radius: calc(var(--border-radius) - 2px);position:relative;display:block;box-sizing:border-box;width:100%;padding:14px;border-radius:var(--f-showcase-card-radius);isolation:isolate}:host:before{position:absolute;inset:0;border:1px solid var(--alpha-12);border-radius:inherit;background-color:var(--background-color);content:\"\";transition:background-color .15s ease,border-color .15s ease,transform .15s ease}:host:hover:before{border-color:var(--divider-color);background-color:var(--alt-background)}:host:hover img{transform:scale(1.02)}:host:focus-within:before{border-color:var(--primary-1);box-shadow:0 0 0 3px var(--primary-soft),var(--shadow-1)}:host>*{position:relative;z-index:1}:host .media{overflow:hidden;border:1px solid var(--divider-color);border-radius:var(--f-showcase-card-media-radius);background-color:var(--soft-background);aspect-ratio:16/9}:host img{display:block;width:100%;height:100%;object-fit:cover;transition:transform .2s ease}:host .content{display:flex;flex-direction:column;gap:8px;min-width:0}:host .media+.content{padding-top:14px}:host .meta{display:flex;align-items:center;flex-wrap:wrap;gap:8px;min-height:var(--f-badge-compact-height);margin-bottom:2px}:host .title{margin:0;color:var(--primary-text);font-size:18px;font-weight:600;line-height:24px;letter-spacing:-.01em;text-transform:none;width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}:host .description{margin:0!important;font-size:15px;line-height:24px;color:var(--secondary-text);width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}@media(min-width:640px){:host{width:calc((100% - 24px)/2)}}.links{display:flex;flex-wrap:wrap;gap:12px;margin-top:4px}.links a{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3290
3309
  }
3291
3310
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: ShowcaseItem, decorators: [{
3292
3311
  type: Component,
3293
- args: [{ selector: 'showcase-item', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let data = model();\n\n@if (data) {\n @if (src()) {\n <div class=\"media\">\n <img [src]=\"src()\" [alt]=\"data.description || data.name\" [title]=\"data.name\">\n </div>\n }\n\n <div class=\"content\">\n @if (data.tags?.length) {\n <div class=\"meta\">\n @for (tag of data.tags; track tag) {\n <span class=\"f-badge sm tip\">{{ tag }}</span>\n }\n </div>\n }\n\n <div class=\"title\">{{ data.name }}</div>\n <div class=\"description\">{{ data.description }}</div>\n\n @if (data.links?.length) {\n <div class=\"links\">\n @for (link of data.links; track link.text) {\n <a class=\"f-text-link f-text-link-primary\" href=\"{{ link.url }}\" target=\"_blank\" rel=\"noopener\">{{ link.text }}</a>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{--f-showcase-card-radius: calc(var(--border-radius) + 2px);--f-showcase-card-media-radius: calc(var(--border-radius) - 2px);position:relative;display:block;box-sizing:border-box;width:100%;padding:14px;border-radius:var(--f-showcase-card-radius);isolation:isolate}:host:before{position:absolute;inset:0;border:1px solid var(--alpha-12);border-radius:inherit;background-color:var(--background-color);box-shadow:var(--shadow-1);content:\"\";transition:background-color .15s ease,border-color .15s ease,transform .15s ease}:host:hover:before{border-color:var(--divider-color);background-color:var(--alt-background)}:host:hover img{transform:scale(1.02)}:host:focus-within:before{border-color:var(--primary-1);box-shadow:0 0 0 3px var(--primary-soft),var(--shadow-1)}:host>*{position:relative;z-index:1}:host .media{overflow:hidden;border:1px solid var(--divider-color);border-radius:var(--f-showcase-card-media-radius);background-color:var(--soft-background);aspect-ratio:16/9}:host img{display:block;width:100%;height:100%;object-fit:cover;transition:transform .2s ease}:host .content{display:flex;flex-direction:column;gap:8px;min-width:0}:host .media+.content{padding-top:14px}:host .meta{display:flex;align-items:center;flex-wrap:wrap;gap:8px;min-height:var(--f-badge-compact-height);margin-bottom:2px}:host .title{margin:0;color:var(--primary-text);font-size:18px;font-weight:600;line-height:24px;letter-spacing:-.01em;text-transform:none;width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}:host .description{margin:0!important;font-size:15px;line-height:24px;color:var(--secondary-text);width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}@media(min-width:640px){:host{width:calc((100% - 24px)/2)}}.links{display:flex;flex-wrap:wrap;gap:12px;margin-top:4px}.links a{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
3312
+ args: [{ selector: 'showcase-item', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let data = model();\n\n@if (data) {\n @if (src()) {\n <div class=\"media\">\n <img [src]=\"src()\" [alt]=\"data.description || data.name\" [title]=\"data.name\">\n </div>\n }\n\n <div class=\"content\">\n @if (data.tags?.length) {\n <div class=\"meta\">\n @for (tag of data.tags; track tag) {\n <span class=\"f-badge sm tip\">{{ tag }}</span>\n }\n </div>\n }\n\n <div class=\"title\">{{ data.name }}</div>\n <div class=\"description\">{{ data.description }}</div>\n\n @if (data.links.length) {\n <div class=\"links\">\n @for (link of data.links; track link.text) {\n <a class=\"f-text-link f-text-link-primary\" href=\"{{ link.url }}\" target=\"_blank\" rel=\"noopener\">{{ link.text }}</a>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{--f-showcase-card-radius: calc(var(--border-radius) + 2px);--f-showcase-card-media-radius: calc(var(--border-radius) - 2px);position:relative;display:block;box-sizing:border-box;width:100%;padding:14px;border-radius:var(--f-showcase-card-radius);isolation:isolate}:host:before{position:absolute;inset:0;border:1px solid var(--alpha-12);border-radius:inherit;background-color:var(--background-color);content:\"\";transition:background-color .15s ease,border-color .15s ease,transform .15s ease}:host:hover:before{border-color:var(--divider-color);background-color:var(--alt-background)}:host:hover img{transform:scale(1.02)}:host:focus-within:before{border-color:var(--primary-1);box-shadow:0 0 0 3px var(--primary-soft),var(--shadow-1)}:host>*{position:relative;z-index:1}:host .media{overflow:hidden;border:1px solid var(--divider-color);border-radius:var(--f-showcase-card-media-radius);background-color:var(--soft-background);aspect-ratio:16/9}:host img{display:block;width:100%;height:100%;object-fit:cover;transition:transform .2s ease}:host .content{display:flex;flex-direction:column;gap:8px;min-width:0}:host .media+.content{padding-top:14px}:host .meta{display:flex;align-items:center;flex-wrap:wrap;gap:8px;min-height:var(--f-badge-compact-height);margin-bottom:2px}:host .title{margin:0;color:var(--primary-text);font-size:18px;font-weight:600;line-height:24px;letter-spacing:-.01em;text-transform:none;width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}:host .description{margin:0!important;font-size:15px;line-height:24px;color:var(--secondary-text);width:100%;word-wrap:break-word;white-space:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}@media(min-width:640px){:host{width:calc((100% - 24px)/2)}}.links{display:flex;flex-wrap:wrap;gap:12px;margin-top:4px}.links a{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
3294
3313
  }], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }] } });
3295
3314
 
3296
3315
  const SHOWCASE_DATA = new InjectionToken('SHOWCASE_DATA');
@@ -3322,14 +3341,14 @@ class Showcase {
3322
3341
  this.activeTag.set(tag);
3323
3342
  }
3324
3343
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: Showcase, deps: [], target: i0.ɵɵFactoryTarget.Component });
3325
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: Showcase, isStandalone: true, selector: "showcase", ngImport: i0, template: "<div class=\"filters-panel\">\n <div class=\"filters-group\" role=\"radiogroup\" aria-label=\"Filter showcase items\">\n @for (filter of filterOptions(); track filter.value ?? 'all') {\n <f-radio-button\n [name]=\"filterGroupName\"\n [checked]=\"activeTag() === filter.value\"\n (change)=\"onFilterChange(filter.value)\">{{ filter.label }}</f-radio-button>\n }\n </div>\n</div>\n<div class=\"showcase-list\">\n @for (item of items(); track item.imageUrl) {\n <showcase-item [model]=\"item\"/>\n }\n</div>\n", styles: [".filters-panel{width:100%;margin-bottom:24px}.filters-group{display:flex;flex-wrap:wrap;align-items:flex-start;column-gap:20px;row-gap:10px}.showcase-list{display:flex;justify-content:flex-start;align-items:stretch;flex-wrap:wrap;gap:24px;pointer-events:all;overflow:hidden}\n"], dependencies: [{ kind: "component", type: FRadioButtonComponent, selector: "f-radio-button", inputs: ["id", "name", "checked"], outputs: ["change"] }, { kind: "component", type: ShowcaseItem, selector: "showcase-item", inputs: ["model"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3344
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: Showcase, isStandalone: true, selector: "showcase", ngImport: i0, template: "<div class=\"filters-panel\">\n <div class=\"filters-group\" role=\"radiogroup\" aria-label=\"Filter showcase items\">\n @for (filter of filterOptions(); track filter.label) {\n <f-radio-button\n [name]=\"filterGroupName\"\n [checked]=\"activeTag() === filter.value\"\n (change)=\"onFilterChange(filter.value)\">{{ filter.label }}</f-radio-button>\n }\n </div>\n</div>\n<div class=\"showcase-list\">\n @for (item of items(); track item.imageUrl) {\n <showcase-item [model]=\"item\"/>\n }\n</div>\n", styles: [".filters-panel{width:100%;margin-bottom:24px}.filters-group{display:flex;flex-wrap:wrap;align-items:flex-start;column-gap:20px;row-gap:10px}.showcase-list{display:flex;justify-content:flex-start;align-items:stretch;flex-wrap:wrap;gap:24px;pointer-events:all;overflow:hidden}\n"], dependencies: [{ kind: "component", type: FRadioButtonComponent, selector: "f-radio-button", inputs: ["id", "name", "checked"], outputs: ["change"] }, { kind: "component", type: ShowcaseItem, selector: "showcase-item", inputs: ["model"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3326
3345
  }
3327
3346
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: Showcase, decorators: [{
3328
3347
  type: Component,
3329
3348
  args: [{ selector: 'showcase', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
3330
3349
  FRadioButtonComponent,
3331
3350
  ShowcaseItem,
3332
- ], template: "<div class=\"filters-panel\">\n <div class=\"filters-group\" role=\"radiogroup\" aria-label=\"Filter showcase items\">\n @for (filter of filterOptions(); track filter.value ?? 'all') {\n <f-radio-button\n [name]=\"filterGroupName\"\n [checked]=\"activeTag() === filter.value\"\n (change)=\"onFilterChange(filter.value)\">{{ filter.label }}</f-radio-button>\n }\n </div>\n</div>\n<div class=\"showcase-list\">\n @for (item of items(); track item.imageUrl) {\n <showcase-item [model]=\"item\"/>\n }\n</div>\n", styles: [".filters-panel{width:100%;margin-bottom:24px}.filters-group{display:flex;flex-wrap:wrap;align-items:flex-start;column-gap:20px;row-gap:10px}.showcase-list{display:flex;justify-content:flex-start;align-items:stretch;flex-wrap:wrap;gap:24px;pointer-events:all;overflow:hidden}\n"] }]
3351
+ ], template: "<div class=\"filters-panel\">\n <div class=\"filters-group\" role=\"radiogroup\" aria-label=\"Filter showcase items\">\n @for (filter of filterOptions(); track filter.label) {\n <f-radio-button\n [name]=\"filterGroupName\"\n [checked]=\"activeTag() === filter.value\"\n (change)=\"onFilterChange(filter.value)\">{{ filter.label }}</f-radio-button>\n }\n </div>\n</div>\n<div class=\"showcase-list\">\n @for (item of items(); track item.imageUrl) {\n <showcase-item [model]=\"item\"/>\n }\n</div>\n", styles: [".filters-panel{width:100%;margin-bottom:24px}.filters-group{display:flex;flex-wrap:wrap;align-items:flex-start;column-gap:20px;row-gap:10px}.showcase-list{display:flex;justify-content:flex-start;align-items:stretch;flex-wrap:wrap;gap:24px;pointer-events:all;overflow:hidden}\n"] }]
3333
3352
  }] });
3334
3353
 
3335
3354
  var showcase = /*#__PURE__*/Object.freeze({