@franzzemen/brokenstock-shell 0.0.28 → 0.0.30
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,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, makeEnvironmentProviders, signal, computed, Injectable, inject, input, Directive, isDevMode, effect, untracked, HostListener, ViewChild, ChangeDetectionStrategy, Component, NgZone, viewChild, afterNextRender } from '@angular/core';
|
|
3
3
|
import * as i2$1 from '@angular/router';
|
|
4
|
-
import { Router, RouterLink, RouterLinkActive, RouterOutlet
|
|
4
|
+
import { Router, RouterLink, ActivatedRoute, RouterLinkActive, RouterOutlet } from '@angular/router';
|
|
5
5
|
import { HttpHeader, BEARER_TOKEN_REGEX, USERNAME_REGEX, PASSWORD_REGEX } from '@franzzemen/utility';
|
|
6
6
|
import { validateCredentials } from '@franzzemen/identity';
|
|
7
7
|
import { HttpClient } from '@angular/common/http';
|
|
@@ -11,7 +11,8 @@ import { NG_VALIDATORS, FormsModule } from '@angular/forms';
|
|
|
11
11
|
import { Marked } from 'marked';
|
|
12
12
|
import { gfmHeadingId } from 'marked-gfm-heading-id';
|
|
13
13
|
import fm from 'front-matter';
|
|
14
|
-
import { NgClass, DOCUMENT, DatePipe } from '@angular/common';
|
|
14
|
+
import { NgClass, CommonModule, DOCUMENT, DatePipe } from '@angular/common';
|
|
15
|
+
import { Title, Meta } from '@angular/platform-browser';
|
|
15
16
|
import { z } from 'zod/v4';
|
|
16
17
|
import * as i1 from '@angular/material/icon';
|
|
17
18
|
import { MatIconModule } from '@angular/material/icon';
|
|
@@ -1236,6 +1237,375 @@ var faqAuthoringPanel = /*#__PURE__*/Object.freeze({
|
|
|
1236
1237
|
FaqAuthoringPanel: FaqAuthoringPanel
|
|
1237
1238
|
});
|
|
1238
1239
|
|
|
1240
|
+
/**
|
|
1241
|
+
* Canonical public base URL (no trailing slash) used for OpenGraph,
|
|
1242
|
+
* Twitter, JSON-LD canonical URLs, and sitemap entries on the
|
|
1243
|
+
* public FAQ pages. Default empty string — falls back to relative
|
|
1244
|
+
* `og:url` etc. when unset, which is fine for previewing but
|
|
1245
|
+
* suboptimal for production SEO. Consumer apps should override.
|
|
1246
|
+
*/
|
|
1247
|
+
const FAQ_PUBLIC_SITE_BASE_URL = new InjectionToken('FAQ_PUBLIC_SITE_BASE_URL', { providedIn: 'root', factory: () => '' });
|
|
1248
|
+
const FAQ_PUBLIC_PUBLISHER = new InjectionToken('FAQ_PUBLIC_PUBLISHER', { providedIn: 'root', factory: () => ({ name: '' }) });
|
|
1249
|
+
|
|
1250
|
+
/**
|
|
1251
|
+
* Public, SEO-targeted FAQ index. Prerendered at build time on the
|
|
1252
|
+
* consumer side (e.g. /help in broken-stock). Lists every manifest
|
|
1253
|
+
* entry where `audience === 'public' && seoReady === true`, grouped
|
|
1254
|
+
* by category and ordered by `order`.
|
|
1255
|
+
*
|
|
1256
|
+
* SEO (E17): sets <title>, meta description, OG, and Twitter tags.
|
|
1257
|
+
* JSON-LD (E18): emits a schema.org CollectionPage referencing
|
|
1258
|
+
* each child entry as an ItemList.
|
|
1259
|
+
*/
|
|
1260
|
+
class PublicFaqIndex {
|
|
1261
|
+
constructor() {
|
|
1262
|
+
this.loader = inject(FAQ_CONTENT_LOADER);
|
|
1263
|
+
this.title = inject(Title);
|
|
1264
|
+
this.meta = inject(Meta);
|
|
1265
|
+
this.siteBase = inject(FAQ_PUBLIC_SITE_BASE_URL);
|
|
1266
|
+
this.publisher = inject(FAQ_PUBLIC_PUBLISHER);
|
|
1267
|
+
this._entries = signal([], ...(ngDevMode ? [{ debugName: "_entries" }] : /* istanbul ignore next */ []));
|
|
1268
|
+
this.loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
1269
|
+
this.visibleEntries = computed(() => this._entries().filter((e) => e.audience === 'public' && e.seoReady), ...(ngDevMode ? [{ debugName: "visibleEntries" }] : /* istanbul ignore next */ []));
|
|
1270
|
+
this.groups = computed(() => {
|
|
1271
|
+
const visible = this.visibleEntries();
|
|
1272
|
+
const byCategory = new Map();
|
|
1273
|
+
for (const entry of visible) {
|
|
1274
|
+
const list = byCategory.get(entry.category) ?? [];
|
|
1275
|
+
list.push(entry);
|
|
1276
|
+
byCategory.set(entry.category, list);
|
|
1277
|
+
}
|
|
1278
|
+
const groups = [];
|
|
1279
|
+
for (const [category, entries] of byCategory) {
|
|
1280
|
+
entries.sort((a, b) => a.order - b.order || a.title.localeCompare(b.title));
|
|
1281
|
+
groups.push({ category, entries });
|
|
1282
|
+
}
|
|
1283
|
+
groups.sort((a, b) => a.category.localeCompare(b.category));
|
|
1284
|
+
return groups;
|
|
1285
|
+
}, ...(ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []));
|
|
1286
|
+
this.jsonLd = computed(() => {
|
|
1287
|
+
const entries = this.visibleEntries();
|
|
1288
|
+
if (entries.length === 0)
|
|
1289
|
+
return null;
|
|
1290
|
+
const base = this.siteBase.replace(/\/+$/, '');
|
|
1291
|
+
const indexUrl = `${base}/help`;
|
|
1292
|
+
const ld = {
|
|
1293
|
+
'@context': 'https://schema.org',
|
|
1294
|
+
'@type': 'CollectionPage',
|
|
1295
|
+
name: 'Brokenstock Help',
|
|
1296
|
+
url: indexUrl,
|
|
1297
|
+
mainEntity: {
|
|
1298
|
+
'@type': 'ItemList',
|
|
1299
|
+
itemListElement: entries.map((entry, idx) => ({
|
|
1300
|
+
'@type': 'ListItem',
|
|
1301
|
+
position: idx + 1,
|
|
1302
|
+
url: `${base}/help/${entry.file}`,
|
|
1303
|
+
name: entry.title,
|
|
1304
|
+
})),
|
|
1305
|
+
},
|
|
1306
|
+
};
|
|
1307
|
+
if (this.publisher.name) {
|
|
1308
|
+
const pub = {
|
|
1309
|
+
'@type': 'Organization',
|
|
1310
|
+
name: this.publisher.name,
|
|
1311
|
+
};
|
|
1312
|
+
if (this.publisher.url)
|
|
1313
|
+
pub['url'] = this.publisher.url;
|
|
1314
|
+
if (this.publisher.logo)
|
|
1315
|
+
pub['logo'] = this.publisher.logo;
|
|
1316
|
+
ld['publisher'] = pub;
|
|
1317
|
+
}
|
|
1318
|
+
return serializeJsonLd$1(ld);
|
|
1319
|
+
}, ...(ngDevMode ? [{ debugName: "jsonLd" }] : /* istanbul ignore next */ []));
|
|
1320
|
+
}
|
|
1321
|
+
async ngOnInit() {
|
|
1322
|
+
try {
|
|
1323
|
+
const manifest = await this.loader.loadManifest();
|
|
1324
|
+
this._entries.set(manifest.entries);
|
|
1325
|
+
this.applyMeta();
|
|
1326
|
+
}
|
|
1327
|
+
finally {
|
|
1328
|
+
this.loading.set(false);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
applyMeta() {
|
|
1332
|
+
const base = this.siteBase.replace(/\/+$/, '');
|
|
1333
|
+
const url = `${base}/help`;
|
|
1334
|
+
const description = 'Documentation and walkthroughs for the Brokenstock trade-journal platform.';
|
|
1335
|
+
this.title.setTitle('Help — Brokenstock');
|
|
1336
|
+
this.meta.updateTag({ name: 'description', content: description });
|
|
1337
|
+
this.meta.updateTag({ property: 'og:type', content: 'website' });
|
|
1338
|
+
this.meta.updateTag({ property: 'og:title', content: 'Help — Brokenstock' });
|
|
1339
|
+
this.meta.updateTag({ property: 'og:description', content: description });
|
|
1340
|
+
this.meta.updateTag({ property: 'og:url', content: url });
|
|
1341
|
+
if (this.publisher.name) {
|
|
1342
|
+
this.meta.updateTag({ property: 'og:site_name', content: this.publisher.name });
|
|
1343
|
+
}
|
|
1344
|
+
this.meta.updateTag({ name: 'twitter:card', content: 'summary' });
|
|
1345
|
+
this.meta.updateTag({ name: 'twitter:title', content: 'Help — Brokenstock' });
|
|
1346
|
+
this.meta.updateTag({ name: 'twitter:description', content: description });
|
|
1347
|
+
}
|
|
1348
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: PublicFaqIndex, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1349
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: PublicFaqIndex, isStandalone: true, selector: "public-faq-index", ngImport: i0, template: `
|
|
1350
|
+
<article class="public-faq-index">
|
|
1351
|
+
<header>
|
|
1352
|
+
<h1>Brokenstock Help</h1>
|
|
1353
|
+
<p class="lead">Documentation and walkthroughs for the Brokenstock trade-journal platform.</p>
|
|
1354
|
+
</header>
|
|
1355
|
+
@if (loading()) {
|
|
1356
|
+
<p>Loading…</p>
|
|
1357
|
+
} @else if (groups().length === 0) {
|
|
1358
|
+
<p>No help pages are published yet.</p>
|
|
1359
|
+
} @else {
|
|
1360
|
+
@for (group of groups(); track group.category) {
|
|
1361
|
+
<section>
|
|
1362
|
+
<h2>{{ group.category }}</h2>
|
|
1363
|
+
<ul>
|
|
1364
|
+
@for (entry of group.entries; track entry.key) {
|
|
1365
|
+
<li>
|
|
1366
|
+
<a [routerLink]="['/help', entry.file]">{{ entry.title }}</a>
|
|
1367
|
+
@if (entry.description) {
|
|
1368
|
+
<span class="desc"> — {{ entry.description }}</span>
|
|
1369
|
+
}
|
|
1370
|
+
</li>
|
|
1371
|
+
}
|
|
1372
|
+
</ul>
|
|
1373
|
+
</section>
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
@if (jsonLd(); as ld) {
|
|
1377
|
+
<script type="application/ld+json">{{ ld }}</script>
|
|
1378
|
+
}
|
|
1379
|
+
</article>
|
|
1380
|
+
`, isInline: true, styles: [":host{display:block}.public-faq-index{max-width:860px;margin:0 auto;padding:2rem 1.25rem 4rem;font-family:system-ui,-apple-system,Segoe UI,sans-serif;line-height:1.55}header h1{font-size:2.25rem;margin:0 0 .5rem}.lead{color:#555;margin:0 0 2rem;font-size:1.1rem}h2{font-size:1.35rem;margin:1.75rem 0 .5rem;border-bottom:1px solid #eee;padding-bottom:.25rem}ul{list-style:none;padding:0;margin:0}li{padding:.4rem 0}a{color:#1565c0;text-decoration:none;font-weight:500}a:hover{text-decoration:underline}.desc{color:#666;font-weight:400}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
|
|
1381
|
+
}
|
|
1382
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: PublicFaqIndex, decorators: [{
|
|
1383
|
+
type: Component,
|
|
1384
|
+
args: [{ selector: 'public-faq-index', standalone: true, imports: [CommonModule, RouterLink], template: `
|
|
1385
|
+
<article class="public-faq-index">
|
|
1386
|
+
<header>
|
|
1387
|
+
<h1>Brokenstock Help</h1>
|
|
1388
|
+
<p class="lead">Documentation and walkthroughs for the Brokenstock trade-journal platform.</p>
|
|
1389
|
+
</header>
|
|
1390
|
+
@if (loading()) {
|
|
1391
|
+
<p>Loading…</p>
|
|
1392
|
+
} @else if (groups().length === 0) {
|
|
1393
|
+
<p>No help pages are published yet.</p>
|
|
1394
|
+
} @else {
|
|
1395
|
+
@for (group of groups(); track group.category) {
|
|
1396
|
+
<section>
|
|
1397
|
+
<h2>{{ group.category }}</h2>
|
|
1398
|
+
<ul>
|
|
1399
|
+
@for (entry of group.entries; track entry.key) {
|
|
1400
|
+
<li>
|
|
1401
|
+
<a [routerLink]="['/help', entry.file]">{{ entry.title }}</a>
|
|
1402
|
+
@if (entry.description) {
|
|
1403
|
+
<span class="desc"> — {{ entry.description }}</span>
|
|
1404
|
+
}
|
|
1405
|
+
</li>
|
|
1406
|
+
}
|
|
1407
|
+
</ul>
|
|
1408
|
+
</section>
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
@if (jsonLd(); as ld) {
|
|
1412
|
+
<script type="application/ld+json">{{ ld }}</script>
|
|
1413
|
+
}
|
|
1414
|
+
</article>
|
|
1415
|
+
`, styles: [":host{display:block}.public-faq-index{max-width:860px;margin:0 auto;padding:2rem 1.25rem 4rem;font-family:system-ui,-apple-system,Segoe UI,sans-serif;line-height:1.55}header h1{font-size:2.25rem;margin:0 0 .5rem}.lead{color:#555;margin:0 0 2rem;font-size:1.1rem}h2{font-size:1.35rem;margin:1.75rem 0 .5rem;border-bottom:1px solid #eee;padding-bottom:.25rem}ul{list-style:none;padding:0;margin:0}li{padding:.4rem 0}a{color:#1565c0;text-decoration:none;font-weight:500}a:hover{text-decoration:underline}.desc{color:#666;font-weight:400}\n"] }]
|
|
1416
|
+
}] });
|
|
1417
|
+
function serializeJsonLd$1(obj) {
|
|
1418
|
+
return JSON.stringify(obj).replace(/</g, '\\u003c');
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
/**
|
|
1422
|
+
* Public, SEO-targeted FAQ page. Prerendered at build time per
|
|
1423
|
+
* qualifying manifest entry (e.g. /help/landing, /help/trade/segments).
|
|
1424
|
+
*
|
|
1425
|
+
* The route is `help/**` so multi-segment file paths work; this
|
|
1426
|
+
* component reads the wildcard path off `ActivatedRoute.url`.
|
|
1427
|
+
*
|
|
1428
|
+
* SEO (E17): sets <title>, meta description, OpenGraph and Twitter
|
|
1429
|
+
* Card tags using Angular's Title + Meta services (SSR-compatible).
|
|
1430
|
+
* JSON-LD (E18): emits a schema.org Article (or BlogPosting) object
|
|
1431
|
+
* via an inline <script type="application/ld+json"> element. The
|
|
1432
|
+
* raw JSON has `<` escaped to `<` so a stray `</script>` inside
|
|
1433
|
+
* data won't break the surrounding tag.
|
|
1434
|
+
*/
|
|
1435
|
+
class PublicFaqPage {
|
|
1436
|
+
constructor() {
|
|
1437
|
+
this.route = inject(ActivatedRoute);
|
|
1438
|
+
this.loader = inject(FAQ_CONTENT_LOADER);
|
|
1439
|
+
this.renderer = inject(FaqMarkdownRendererService);
|
|
1440
|
+
this.title = inject(Title);
|
|
1441
|
+
this.meta = inject(Meta);
|
|
1442
|
+
this.siteBase = inject(FAQ_PUBLIC_SITE_BASE_URL);
|
|
1443
|
+
this.publisher = inject(FAQ_PUBLIC_PUBLISHER);
|
|
1444
|
+
this.entry = signal(null, ...(ngDevMode ? [{ debugName: "entry" }] : /* istanbul ignore next */ []));
|
|
1445
|
+
this.body = signal('', ...(ngDevMode ? [{ debugName: "body" }] : /* istanbul ignore next */ []));
|
|
1446
|
+
this.loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
1447
|
+
this.renderedHtml = computed(() => {
|
|
1448
|
+
const entry = this.entry();
|
|
1449
|
+
const body = this.body();
|
|
1450
|
+
if (!entry || !body)
|
|
1451
|
+
return '';
|
|
1452
|
+
return this.renderer.render(body, {
|
|
1453
|
+
context: 'page',
|
|
1454
|
+
imagePrefix: entry.imagePrefix
|
|
1455
|
+
? `/assets/faq/${entry.imagePrefix}`
|
|
1456
|
+
: undefined,
|
|
1457
|
+
});
|
|
1458
|
+
}, ...(ngDevMode ? [{ debugName: "renderedHtml" }] : /* istanbul ignore next */ []));
|
|
1459
|
+
this.jsonLd = computed(() => {
|
|
1460
|
+
const entry = this.entry();
|
|
1461
|
+
if (!entry)
|
|
1462
|
+
return null;
|
|
1463
|
+
const url = this.canonicalUrl(entry);
|
|
1464
|
+
const ld = {
|
|
1465
|
+
'@context': 'https://schema.org',
|
|
1466
|
+
'@type': 'Article',
|
|
1467
|
+
headline: entry.title,
|
|
1468
|
+
url,
|
|
1469
|
+
mainEntityOfPage: url,
|
|
1470
|
+
};
|
|
1471
|
+
if (entry.description)
|
|
1472
|
+
ld['description'] = entry.description;
|
|
1473
|
+
if (this.publisher.name) {
|
|
1474
|
+
const pub = {
|
|
1475
|
+
'@type': 'Organization',
|
|
1476
|
+
name: this.publisher.name,
|
|
1477
|
+
};
|
|
1478
|
+
if (this.publisher.url)
|
|
1479
|
+
pub['url'] = this.publisher.url;
|
|
1480
|
+
if (this.publisher.logo)
|
|
1481
|
+
pub['logo'] = this.publisher.logo;
|
|
1482
|
+
ld['publisher'] = pub;
|
|
1483
|
+
ld['author'] = pub;
|
|
1484
|
+
}
|
|
1485
|
+
return serializeJsonLd(ld);
|
|
1486
|
+
}, ...(ngDevMode ? [{ debugName: "jsonLd" }] : /* istanbul ignore next */ []));
|
|
1487
|
+
}
|
|
1488
|
+
async ngOnInit() {
|
|
1489
|
+
try {
|
|
1490
|
+
const segments = this.route.snapshot.url.map((s) => s.path);
|
|
1491
|
+
const filePath = segments.join('/');
|
|
1492
|
+
if (!filePath) {
|
|
1493
|
+
this.applyNotFoundMeta();
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
const manifest = await this.loader.loadManifest();
|
|
1497
|
+
const match = manifest.entries.find((e) => e.file === filePath && e.audience === 'public' && e.seoReady);
|
|
1498
|
+
if (!match) {
|
|
1499
|
+
this.applyNotFoundMeta();
|
|
1500
|
+
return;
|
|
1501
|
+
}
|
|
1502
|
+
const content = await this.loader.loadContent(match.key);
|
|
1503
|
+
if (content === null) {
|
|
1504
|
+
this.applyNotFoundMeta();
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
const parsed = this.renderer.parse(content);
|
|
1508
|
+
this.entry.set(match);
|
|
1509
|
+
this.body.set(parsed.body);
|
|
1510
|
+
this.applyMeta(match);
|
|
1511
|
+
}
|
|
1512
|
+
finally {
|
|
1513
|
+
this.loading.set(false);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
applyMeta(entry) {
|
|
1517
|
+
const url = this.canonicalUrl(entry);
|
|
1518
|
+
const description = entry.description ?? '';
|
|
1519
|
+
const title = `${entry.title} — Help`;
|
|
1520
|
+
this.title.setTitle(title);
|
|
1521
|
+
this.meta.updateTag({ name: 'description', content: description });
|
|
1522
|
+
this.meta.updateTag({ property: 'og:type', content: 'article' });
|
|
1523
|
+
this.meta.updateTag({ property: 'og:title', content: entry.title });
|
|
1524
|
+
this.meta.updateTag({ property: 'og:description', content: description });
|
|
1525
|
+
this.meta.updateTag({ property: 'og:url', content: url });
|
|
1526
|
+
if (this.publisher.name) {
|
|
1527
|
+
this.meta.updateTag({ property: 'og:site_name', content: this.publisher.name });
|
|
1528
|
+
}
|
|
1529
|
+
this.meta.updateTag({ name: 'twitter:card', content: 'summary' });
|
|
1530
|
+
this.meta.updateTag({ name: 'twitter:title', content: entry.title });
|
|
1531
|
+
this.meta.updateTag({ name: 'twitter:description', content: description });
|
|
1532
|
+
}
|
|
1533
|
+
applyNotFoundMeta() {
|
|
1534
|
+
this.title.setTitle('Page not found — Help');
|
|
1535
|
+
this.meta.updateTag({ name: 'robots', content: 'noindex' });
|
|
1536
|
+
}
|
|
1537
|
+
canonicalUrl(entry) {
|
|
1538
|
+
const base = this.siteBase.replace(/\/+$/, '');
|
|
1539
|
+
return `${base}/help/${entry.file}`;
|
|
1540
|
+
}
|
|
1541
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: PublicFaqPage, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1542
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: PublicFaqPage, isStandalone: true, selector: "public-faq-page", ngImport: i0, template: `
|
|
1543
|
+
<article class="public-faq-page">
|
|
1544
|
+
<nav class="crumbs">
|
|
1545
|
+
<a routerLink="/help">← Help</a>
|
|
1546
|
+
</nav>
|
|
1547
|
+
@if (loading()) {
|
|
1548
|
+
<p>Loading…</p>
|
|
1549
|
+
} @else if (!entry()) {
|
|
1550
|
+
<header>
|
|
1551
|
+
<h1>Page not found</h1>
|
|
1552
|
+
<p>That help page doesn't exist or isn't published. Try the <a routerLink="/help">help index</a>.</p>
|
|
1553
|
+
</header>
|
|
1554
|
+
} @else {
|
|
1555
|
+
<header>
|
|
1556
|
+
<h1>{{ entry()!.title }}</h1>
|
|
1557
|
+
@if (entry()!.description) {
|
|
1558
|
+
<p class="lead">{{ entry()!.description }}</p>
|
|
1559
|
+
}
|
|
1560
|
+
</header>
|
|
1561
|
+
<div class="body" [innerHTML]="renderedHtml()"></div>
|
|
1562
|
+
@if (jsonLd(); as ld) {
|
|
1563
|
+
<script type="application/ld+json">{{ ld }}</script>
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
</article>
|
|
1567
|
+
`, isInline: true, styles: [":host{display:block}.public-faq-page{max-width:860px;margin:0 auto;padding:2rem 1.25rem 4rem;font-family:system-ui,-apple-system,Segoe UI,sans-serif;line-height:1.6}.crumbs{margin-bottom:1.5rem;font-size:.9rem}.crumbs a{color:#1565c0;text-decoration:none}.crumbs a:hover{text-decoration:underline}header h1{font-size:2.1rem;margin:0 0 .5rem}.lead{color:#555;font-size:1.1rem;margin:0 0 1.5rem}.body :is(h1,h2,h3,h4){margin-top:2rem}.body a{color:#1565c0}.body img{max-width:100%;height:auto}.body pre{background:#f6f8fa;padding:.75rem 1rem;border-radius:6px;overflow-x:auto}.body code{background:#f6f8fa;padding:.1rem .3rem;border-radius:3px;font-size:.9em}.body pre code{background:transparent;padding:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
|
|
1568
|
+
}
|
|
1569
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: PublicFaqPage, decorators: [{
|
|
1570
|
+
type: Component,
|
|
1571
|
+
args: [{ selector: 'public-faq-page', standalone: true, imports: [CommonModule, RouterLink], template: `
|
|
1572
|
+
<article class="public-faq-page">
|
|
1573
|
+
<nav class="crumbs">
|
|
1574
|
+
<a routerLink="/help">← Help</a>
|
|
1575
|
+
</nav>
|
|
1576
|
+
@if (loading()) {
|
|
1577
|
+
<p>Loading…</p>
|
|
1578
|
+
} @else if (!entry()) {
|
|
1579
|
+
<header>
|
|
1580
|
+
<h1>Page not found</h1>
|
|
1581
|
+
<p>That help page doesn't exist or isn't published. Try the <a routerLink="/help">help index</a>.</p>
|
|
1582
|
+
</header>
|
|
1583
|
+
} @else {
|
|
1584
|
+
<header>
|
|
1585
|
+
<h1>{{ entry()!.title }}</h1>
|
|
1586
|
+
@if (entry()!.description) {
|
|
1587
|
+
<p class="lead">{{ entry()!.description }}</p>
|
|
1588
|
+
}
|
|
1589
|
+
</header>
|
|
1590
|
+
<div class="body" [innerHTML]="renderedHtml()"></div>
|
|
1591
|
+
@if (jsonLd(); as ld) {
|
|
1592
|
+
<script type="application/ld+json">{{ ld }}</script>
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
</article>
|
|
1596
|
+
`, styles: [":host{display:block}.public-faq-page{max-width:860px;margin:0 auto;padding:2rem 1.25rem 4rem;font-family:system-ui,-apple-system,Segoe UI,sans-serif;line-height:1.6}.crumbs{margin-bottom:1.5rem;font-size:.9rem}.crumbs a{color:#1565c0;text-decoration:none}.crumbs a:hover{text-decoration:underline}header h1{font-size:2.1rem;margin:0 0 .5rem}.lead{color:#555;font-size:1.1rem;margin:0 0 1.5rem}.body :is(h1,h2,h3,h4){margin-top:2rem}.body a{color:#1565c0}.body img{max-width:100%;height:auto}.body pre{background:#f6f8fa;padding:.75rem 1rem;border-radius:6px;overflow-x:auto}.body code{background:#f6f8fa;padding:.1rem .3rem;border-radius:3px;font-size:.9em}.body pre code{background:transparent;padding:0}\n"] }]
|
|
1597
|
+
}] });
|
|
1598
|
+
/**
|
|
1599
|
+
* Serializes a JSON-LD object for safe inclusion in a
|
|
1600
|
+
* `<script type="application/ld+json">` element. Escapes `<` so a
|
|
1601
|
+
* stray `</script>` inside any string field cannot break out of the
|
|
1602
|
+
* script tag. (Browsers and crawlers parse the resulting `<`
|
|
1603
|
+
* back to `<` per JSON spec.)
|
|
1604
|
+
*/
|
|
1605
|
+
function serializeJsonLd(obj) {
|
|
1606
|
+
return JSON.stringify(obj).replace(/</g, '\\u003c');
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1239
1609
|
class ThemeService {
|
|
1240
1610
|
constructor() {
|
|
1241
1611
|
this.mode = signal('dark', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
@@ -2048,5 +2418,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
|
|
|
2048
2418
|
* Generated bundle index. Do not edit.
|
|
2049
2419
|
*/
|
|
2050
2420
|
|
|
2051
|
-
export { AuthenticationService, CLEAR_USAGE, CommandRegistryService, CommandService, CommandTerminal, ConfirmDialog, FAQ_CONTENT_LOADER, FAQ_DEV_EDITOR, FAQ_DEV_MODE, FAQ_DEV_WORKSPACE_ROOT, FaqAuthoringPanel, FaqHistoryService, FaqMarkdownRendererService, FaqModal, FaqService, HELP_USAGE, HttpFaqContentLoader, KeyboardShortcutService, Login, MainContent, RegexValidatorDirective, SHELL_APP_NAME, SHELL_AUTH_URLS, SHELL_COMMANDS, SHELL_MENU_ITEMS, SHELL_POST_LOGIN_ROUTE, Shell, SideMenu, StatusBar, TerminalFocusService, ThemeService, ThinkingService, audienceAllowed, authGuard, authInterceptor, buildFallbackChain, guestGuard, provideShellConfig, tokenize };
|
|
2421
|
+
export { AuthenticationService, CLEAR_USAGE, CommandRegistryService, CommandService, CommandTerminal, ConfirmDialog, FAQ_CONTENT_LOADER, FAQ_DEV_EDITOR, FAQ_DEV_MODE, FAQ_DEV_WORKSPACE_ROOT, FAQ_PUBLIC_PUBLISHER, FAQ_PUBLIC_SITE_BASE_URL, FaqAuthoringPanel, FaqHistoryService, FaqMarkdownRendererService, FaqModal, FaqService, HELP_USAGE, HttpFaqContentLoader, KeyboardShortcutService, Login, MainContent, PublicFaqIndex, PublicFaqPage, RegexValidatorDirective, SHELL_APP_NAME, SHELL_AUTH_URLS, SHELL_COMMANDS, SHELL_MENU_ITEMS, SHELL_POST_LOGIN_ROUTE, Shell, SideMenu, StatusBar, TerminalFocusService, ThemeService, ThinkingService, audienceAllowed, authGuard, authInterceptor, buildFallbackChain, guestGuard, provideShellConfig, tokenize };
|
|
2052
2422
|
//# sourceMappingURL=franzzemen-brokenstock-shell.mjs.map
|