@ciderpress/ui 1.0.0-rc.10 → 1.0.0-rc.12

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.
Files changed (92) hide show
  1. package/dist/head/css/loader-apple.css +1 -1
  2. package/dist/head/css/loader-dots.css +1 -1
  3. package/dist/head/css/themes/amber.css +1 -1
  4. package/dist/head/css/themes/arcade.css +1 -1
  5. package/dist/head/css/themes/grannysmith.css +1 -1
  6. package/dist/head/css/themes/honeycrisp.css +1 -1
  7. package/dist/head/css/themes/midnight.css +1 -1
  8. package/dist/head/css/themes/mulled.css +1 -1
  9. package/dist/node.mjs +1110 -28
  10. package/dist/theme/components/home/cta.css +15 -0
  11. package/dist/theme/components/home/cta.tsx +10 -2
  12. package/dist/theme/components/home/feature-card.css +1 -1
  13. package/dist/theme/components/home/feature-card.tsx +3 -2
  14. package/dist/theme/components/home/feature.tsx +34 -31
  15. package/dist/theme/components/home/hero-demo.css +11 -0
  16. package/dist/theme/components/home/home-visual.tsx +226 -0
  17. package/dist/theme/components/home/layout.tsx +350 -171
  18. package/dist/theme/components/home/split.css +46 -19
  19. package/dist/theme/components/home/split.tsx +28 -8
  20. package/dist/theme/components/home/tabs.css +299 -0
  21. package/dist/theme/components/home/tabs.tsx +351 -0
  22. package/dist/theme/components/home/trust-strip.css +41 -0
  23. package/dist/theme/components/home/trust-strip.tsx +168 -11
  24. package/dist/theme/components/home/workspaces.tsx +171 -69
  25. package/dist/theme/components/seo-head-data.test.ts +196 -0
  26. package/dist/theme/components/seo-head-data.ts +490 -0
  27. package/dist/theme/components/seo-head.tsx +102 -0
  28. package/dist/theme/components/shared/IssueLinkIcon.tsx +42 -0
  29. package/dist/theme/components/shared/issue-link.css +74 -0
  30. package/dist/theme/components/workspaces/card.css +4 -0
  31. package/dist/theme/components/workspaces/card.tsx +3 -3
  32. package/dist/theme/components/workspaces/grid.tsx +18 -6
  33. package/dist/theme/index.tsx +6 -0
  34. package/dist/theme/lib/rich-text-parse.ts +740 -0
  35. package/dist/theme/lib/rich-text.test.tsx +342 -0
  36. package/dist/theme/lib/rich-text.tsx +86 -0
  37. package/dist/theme/lib/seo-url.ts +28 -0
  38. package/dist/theme/styles/overrides/fonts.css +7 -4
  39. package/dist/theme/styles/overrides/home.css +11 -2
  40. package/dist/theme/styles/overrides/rspress.css +10 -5
  41. package/dist/theme/styles/overrides/tokens.css +41 -23
  42. package/dist/theme/styles/rich-text.css +106 -0
  43. package/dist/theme/styles/themes/amber.css +32 -2
  44. package/dist/theme/styles/themes/arcade.css +16 -1
  45. package/dist/theme/styles/themes/grannysmith.css +32 -2
  46. package/dist/theme/styles/themes/honeycrisp.css +37 -7
  47. package/dist/theme/styles/themes/midnight.css +16 -1
  48. package/dist/theme/styles/themes/mulled.css +54 -9
  49. package/package.json +6 -5
  50. package/src/theme/components/home/cta.css +15 -0
  51. package/src/theme/components/home/cta.tsx +10 -2
  52. package/src/theme/components/home/feature-card.css +1 -1
  53. package/src/theme/components/home/feature-card.tsx +3 -2
  54. package/src/theme/components/home/feature.tsx +34 -31
  55. package/src/theme/components/home/hero-demo.css +11 -0
  56. package/src/theme/components/home/home-visual.tsx +226 -0
  57. package/src/theme/components/home/layout.tsx +350 -171
  58. package/src/theme/components/home/split.css +46 -19
  59. package/src/theme/components/home/split.tsx +28 -8
  60. package/src/theme/components/home/tabs.css +299 -0
  61. package/src/theme/components/home/tabs.tsx +351 -0
  62. package/src/theme/components/home/trust-strip.css +41 -0
  63. package/src/theme/components/home/trust-strip.tsx +168 -11
  64. package/src/theme/components/home/workspaces.tsx +171 -69
  65. package/src/theme/components/seo-head-data.test.ts +196 -0
  66. package/src/theme/components/seo-head-data.ts +490 -0
  67. package/src/theme/components/seo-head.tsx +102 -0
  68. package/src/theme/components/shared/IssueLinkIcon.tsx +42 -0
  69. package/src/theme/components/shared/issue-link.css +74 -0
  70. package/src/theme/components/workspaces/card.css +4 -0
  71. package/src/theme/components/workspaces/card.tsx +3 -3
  72. package/src/theme/components/workspaces/grid.tsx +18 -6
  73. package/src/theme/index.tsx +6 -0
  74. package/src/theme/lib/rich-text-parse.ts +740 -0
  75. package/src/theme/lib/rich-text.test.tsx +342 -0
  76. package/src/theme/lib/rich-text.tsx +86 -0
  77. package/src/theme/lib/seo-url.ts +28 -0
  78. package/src/theme/styles/overrides/fonts.css +7 -4
  79. package/src/theme/styles/overrides/home.css +11 -2
  80. package/src/theme/styles/overrides/rspress.css +10 -5
  81. package/src/theme/styles/overrides/tokens.css +41 -23
  82. package/src/theme/styles/rich-text.css +106 -0
  83. package/src/theme/styles/themes/amber.css +32 -2
  84. package/src/theme/styles/themes/arcade.css +16 -1
  85. package/src/theme/styles/themes/grannysmith.css +32 -2
  86. package/src/theme/styles/themes/honeycrisp.css +37 -7
  87. package/src/theme/styles/themes/midnight.css +16 -1
  88. package/src/theme/styles/themes/mulled.css +54 -9
  89. package/dist/theme/components/home/hero-demo-custom.tsx +0 -116
  90. package/dist/theme/components/home/split-visual-custom.tsx +0 -26
  91. package/src/theme/components/home/hero-demo-custom.tsx +0 -116
  92. package/src/theme/components/home/split-visual-custom.tsx +0 -26
package/dist/node.mjs CHANGED
@@ -6,12 +6,14 @@ import node_path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { resolveOptionalIcon, serializeIcon } from "@ciderpress/config";
8
8
  import { BRAND_COLORS, BUILT_IN_THEMES, DEFAULT_THEME_NAME, defineTheme, isBuiltInTheme, resolveDefaultVariant, resolveThemeAlias, resolveThemeVariants, themeToCss } from "@ciderpress/theme";
9
+ import { pluginSitemap } from "@rspress/plugin-sitemap";
9
10
  import { P, match as match_match } from "massaman/match";
10
11
  import { visit as external_unist_util_visit_visit } from "unist-util-visit";
11
12
  import path_0 from "path";
12
13
  import { Project, SyntaxKind as external_ts_morph_SyntaxKind } from "ts-morph";
13
14
  import node_process from "node:process";
14
15
  import katex from "katex";
16
+ import { unfold } from "massaman/array";
15
17
  import react from "react";
16
18
  import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
17
19
  import { dirname as __rspack_dirname } from "node:path";
@@ -17358,7 +17360,7 @@ function buildLabelCss(label) {
17358
17360
  margin-top: -14px;
17359
17361
  text-align: left;
17360
17362
  color: var(--cp-c-text-2, #888);
17361
- font-family: 'Geist Pixel Square', ui-sans-serif, system-ui, sans-serif;
17363
+ font-family: var(--cp-ff-display, 'Geist Pixel Square', ui-sans-serif, system-ui, sans-serif);
17362
17364
  font-size: 28px;
17363
17365
  font-weight: 400;
17364
17366
  line-height: 1;
@@ -17375,10 +17377,658 @@ function ciderpressPlugin() {
17375
17377
  name: 'ciderpress',
17376
17378
  globalUIComponents: [
17377
17379
  node_path.resolve(componentsDir, 'theme-provider.tsx'),
17378
- node_path.resolve(componentsDir, 'edit-source-button.tsx')
17380
+ node_path.resolve(componentsDir, 'edit-source-button.tsx'),
17381
+ node_path.resolve(componentsDir, 'seo-head.tsx')
17379
17382
  ]
17380
17383
  };
17381
17384
  }
17385
+ const VERCEL_RESERVED_ROUTES = new Set([
17386
+ 'account',
17387
+ 'ai',
17388
+ 'blog',
17389
+ 'changelog',
17390
+ 'contact',
17391
+ 'customers',
17392
+ 'dashboard',
17393
+ 'design',
17394
+ 'docs',
17395
+ 'enterprise',
17396
+ 'guides',
17397
+ 'integrations',
17398
+ 'login',
17399
+ 'marketplace',
17400
+ 'new',
17401
+ 'oss',
17402
+ 'partners',
17403
+ 'pricing',
17404
+ 'resources',
17405
+ 'security',
17406
+ 'signup',
17407
+ 'solutions',
17408
+ 'templates'
17409
+ ]);
17410
+ function parseIssueLink(value) {
17411
+ if (!URL.canParse(value)) return null;
17412
+ const url = new URL(value);
17413
+ if ('https:' !== url.protocol) return null;
17414
+ const segments = url.pathname.split('/').filter(Boolean);
17415
+ const known = match_match(url.hostname).with('github.com', ()=>parseGitHubLink(segments)).with('www.github.com', ()=>parseGitHubLink(segments)).with('gitlab.com', ()=>parseGitLabLink(segments)).with('www.gitlab.com', ()=>parseGitLabLink(segments)).with('bitbucket.org', ()=>parseBitbucketLink(segments)).with('www.npmjs.com', ()=>parseNpmLink(segments)).with('npmjs.com', ()=>parseNpmLink(segments)).with('linear.app', ()=>parseLinearLink(segments)).with('app.clickup.com', ()=>parseClickUpLink(segments)).with('app.dash0.com', ()=>parseDash0Link({
17416
+ segments,
17417
+ url
17418
+ })).with('app.launchdarkly.com', ()=>parseLaunchDarklyLink(segments)).with('app.posthog.com', ()=>parsePostHogLink(segments)).with('eu.posthog.com', ()=>parsePostHogLink(segments)).with('app.pulumi.com', ()=>parsePulumiLink(segments)).with('vercel.com', ()=>parseVercelLink(segments)).with('www.figma.com', ()=>parseFigmaLink(segments)).with('figma.com', ()=>parseFigmaLink(segments)).with('docs.google.com', ()=>parseGoogleDocsLink(segments)).with('drive.google.com', ()=>parseGoogleDriveLink(segments)).with('trello.com', ()=>parseTrelloLink(segments)).with('www.trello.com', ()=>parseTrelloLink(segments)).with('app.asana.com', ()=>parseAsanaLink(segments)).with('www.loom.com', ()=>parseLoomLink(segments)).with('loom.com', ()=>parseLoomLink(segments)).with('www.postman.com', ()=>parsePostmanLink(segments)).with('postman.com', ()=>parsePostmanLink(segments)).when((hostname)=>hostname.endsWith('.atlassian.net'), ()=>parseAtlassianLink(segments)).when(isNotionHostname, ()=>parseNotionLink(segments)).when(isDatadogHostname, ()=>parseDatadogLink(segments)).when(isPagerDutyHostname, ()=>parsePagerDutyLink(segments)).when(isSlackHostname, ()=>parseSlackLink(segments)).when(isSentryHostname, ()=>parseSentryLink(segments)).otherwise(()=>null);
17419
+ return known;
17420
+ }
17421
+ function parseClickUpLink(segments) {
17422
+ const [resource, identifier] = segments;
17423
+ if ('t' !== resource || void 0 === identifier) return null;
17424
+ return {
17425
+ provider: 'clickup',
17426
+ kind: 'task',
17427
+ label: `Task ${identifier}`,
17428
+ reference: identifier,
17429
+ title: `Task ${identifier} on ClickUp`
17430
+ };
17431
+ }
17432
+ function parseDash0Link({ segments, url }) {
17433
+ const [marker, resource, view] = segments;
17434
+ if ('goto' !== marker || void 0 === resource) return null;
17435
+ return match_match({
17436
+ resource,
17437
+ view
17438
+ }).with({
17439
+ resource: 'dashboards'
17440
+ }, ()=>opaqueLink({
17441
+ provider: 'dash0',
17442
+ kind: 'dashboard',
17443
+ label: 'Dash0 dashboard'
17444
+ })).with({
17445
+ resource: 'logs'
17446
+ }, ()=>opaqueLink({
17447
+ provider: 'dash0',
17448
+ kind: 'logs',
17449
+ label: 'Dash0 logs'
17450
+ })).with({
17451
+ resource: 'services'
17452
+ }, ()=>opaqueLink({
17453
+ provider: 'dash0',
17454
+ kind: 'service',
17455
+ label: 'Dash0 service'
17456
+ })).when(({ resource: area })=>'traces' === area && url.searchParams.has('traceid'), ()=>opaqueLink({
17457
+ provider: 'dash0',
17458
+ kind: 'trace',
17459
+ label: 'Dash0 trace'
17460
+ })).otherwise(()=>null);
17461
+ }
17462
+ function parseDatadogLink(segments) {
17463
+ const [resource, identifier] = segments;
17464
+ if (void 0 === identifier) return null;
17465
+ return match_match(resource).with('dashboard', ()=>opaqueLink({
17466
+ provider: 'datadog',
17467
+ kind: 'dashboard',
17468
+ label: 'Datadog dashboard'
17469
+ })).with('monitors', ()=>opaqueLink({
17470
+ provider: 'datadog',
17471
+ kind: 'monitor',
17472
+ label: 'Datadog monitor'
17473
+ })).otherwise(()=>null);
17474
+ }
17475
+ function parseLaunchDarklyLink(segments) {
17476
+ const [projects, project, flags, identifier] = segments;
17477
+ if ('projects' !== projects || void 0 === project || 'flags' !== flags || void 0 === identifier) return null;
17478
+ return {
17479
+ provider: 'launchdarkly',
17480
+ kind: 'flag',
17481
+ label: `Flag ${identifier}`,
17482
+ reference: identifier,
17483
+ title: `Flag ${identifier} in ${project} on LaunchDarkly`
17484
+ };
17485
+ }
17486
+ function parsePostHogLink(segments) {
17487
+ const [projectMarker, project, resource, identifier] = segments;
17488
+ if ('project' !== projectMarker || void 0 === project || void 0 === resource) return null;
17489
+ return match_match(resource).when((value)=>'insights' === value && void 0 !== identifier, ()=>opaqueLink({
17490
+ provider: 'posthog',
17491
+ kind: 'insight',
17492
+ label: 'PostHog insight'
17493
+ })).when((value)=>'replay' === value && void 0 !== identifier, ()=>opaqueLink({
17494
+ provider: 'posthog',
17495
+ kind: 'recording',
17496
+ label: 'PostHog recording'
17497
+ })).when((value)=>'feature_flags' === value && void 0 !== identifier, ()=>opaqueLink({
17498
+ provider: 'posthog',
17499
+ kind: 'feature-flag',
17500
+ label: 'PostHog flag'
17501
+ })).otherwise(()=>null);
17502
+ }
17503
+ function parsePulumiLink(segments) {
17504
+ const [organization, project, stack] = segments;
17505
+ if (void 0 === organization || void 0 === project || void 0 === stack) return null;
17506
+ return {
17507
+ provider: 'pulumi',
17508
+ kind: 'stack',
17509
+ label: `Stack ${stack}`,
17510
+ reference: stack,
17511
+ title: `Stack ${organization}/${project}/${stack} on Pulumi`
17512
+ };
17513
+ }
17514
+ function parsePagerDutyLink(segments) {
17515
+ const [resource, identifier] = segments;
17516
+ if ('incidents' !== resource || void 0 === identifier) return null;
17517
+ return {
17518
+ provider: 'pagerduty',
17519
+ kind: 'incident',
17520
+ label: `Incident ${identifier}`,
17521
+ reference: identifier,
17522
+ title: `Incident ${identifier} on PagerDuty`
17523
+ };
17524
+ }
17525
+ function parseVercelLink(segments) {
17526
+ const [team, project] = segments;
17527
+ if (void 0 === team || void 0 === project || VERCEL_RESERVED_ROUTES.has(team)) return null;
17528
+ return opaqueLink({
17529
+ provider: 'vercel',
17530
+ kind: 'project',
17531
+ label: 'Vercel project'
17532
+ });
17533
+ }
17534
+ function remarkIssueLinks() {
17535
+ return (tree)=>{
17536
+ external_unist_util_visit_visit(tree, 'link', (node)=>{
17537
+ const issue = parseIssueLink(node.url);
17538
+ if (null === issue) return;
17539
+ const label = resolveLabel({
17540
+ issue,
17541
+ node
17542
+ });
17543
+ const data = node.data ?? {};
17544
+ const properties = readHProperties(data);
17545
+ node.children = buildBadgeChildren({
17546
+ provider: issue.provider,
17547
+ label
17548
+ });
17549
+ node.data = {
17550
+ ...data,
17551
+ hProperties: {
17552
+ ...properties,
17553
+ className: [
17554
+ ...readClassNames(properties.className),
17555
+ 'cp-issue-link',
17556
+ `cp-issue-link--${issue.provider}`
17557
+ ],
17558
+ title: issue.title
17559
+ }
17560
+ };
17561
+ });
17562
+ };
17563
+ }
17564
+ function buildBadgeChildren({ provider, label }) {
17565
+ return [
17566
+ {
17567
+ type: 'mdxJsxTextElement',
17568
+ name: 'IssueLinkIcon',
17569
+ attributes: [
17570
+ {
17571
+ type: 'mdxJsxAttribute',
17572
+ name: 'provider',
17573
+ value: provider
17574
+ }
17575
+ ],
17576
+ children: []
17577
+ },
17578
+ {
17579
+ type: 'text',
17580
+ value: label.text
17581
+ },
17582
+ ...buildReferenceChildren(label.reference)
17583
+ ];
17584
+ }
17585
+ function parseGitHubLink(segments) {
17586
+ const [owner, repo, resource, identifier] = segments;
17587
+ if (void 0 === owner || void 0 === repo || void 0 === identifier) return null;
17588
+ return match_match(resource).when((value)=>'issues' === value && isNumericIdentifier(identifier), ()=>numberedGitHubLink({
17589
+ owner,
17590
+ repo,
17591
+ identifier,
17592
+ kind: 'issue'
17593
+ })).when((value)=>'pull' === value && isNumericIdentifier(identifier), ()=>numberedGitHubLink({
17594
+ owner,
17595
+ repo,
17596
+ identifier,
17597
+ kind: 'pull'
17598
+ })).when((value)=>'discussions' === value && isNumericIdentifier(identifier), ()=>numberedGitHubLink({
17599
+ owner,
17600
+ repo,
17601
+ identifier,
17602
+ kind: 'discussion'
17603
+ })).when((value)=>'commit' === value && /^[a-f\d]{7,64}$/i.test(identifier), ()=>commitLink({
17604
+ provider: 'github',
17605
+ owner,
17606
+ repo,
17607
+ identifier
17608
+ })).with('releases', ()=>parseGitHubRelease({
17609
+ owner,
17610
+ repo,
17611
+ segments
17612
+ })).with('actions', ()=>parseGitHubAction({
17613
+ owner,
17614
+ repo,
17615
+ segments
17616
+ })).otherwise(()=>null);
17617
+ }
17618
+ function parseGitLabLink(segments) {
17619
+ const divider = segments.indexOf('-');
17620
+ if (divider < 1) return null;
17621
+ const resource = segments.at(divider + 1);
17622
+ const identifier = segments.at(divider + 2);
17623
+ if (void 0 === resource || void 0 === identifier) return null;
17624
+ return match_match(resource).when((value)=>'issues' === value && isNumericIdentifier(identifier), ()=>numberedLink({
17625
+ provider: 'gitlab',
17626
+ kind: 'issue',
17627
+ identifier
17628
+ })).when((value)=>'merge_requests' === value && isNumericIdentifier(identifier), ()=>numberedLink({
17629
+ provider: 'gitlab',
17630
+ kind: 'merge',
17631
+ identifier
17632
+ })).with('commit', ()=>commitLink({
17633
+ provider: 'gitlab',
17634
+ owner: '',
17635
+ repo: '',
17636
+ identifier
17637
+ })).with('releases', ()=>({
17638
+ provider: 'gitlab',
17639
+ kind: 'release',
17640
+ label: `Release ${identifier}`,
17641
+ reference: identifier,
17642
+ title: `Release ${identifier} on GitLab`
17643
+ })).otherwise(()=>null);
17644
+ }
17645
+ function parseBitbucketLink(segments) {
17646
+ const [owner, repo, resource, identifier] = segments;
17647
+ if (void 0 === owner || void 0 === repo || void 0 === identifier) return null;
17648
+ return match_match(resource).when((value)=>'issues' === value && isNumericIdentifier(identifier), ()=>numberedLink({
17649
+ provider: 'bitbucket',
17650
+ kind: 'issue',
17651
+ identifier
17652
+ })).when((value)=>'pull-requests' === value && isNumericIdentifier(identifier), ()=>numberedLink({
17653
+ provider: 'bitbucket',
17654
+ kind: 'pull',
17655
+ identifier
17656
+ })).with('commits', ()=>commitLink({
17657
+ provider: 'bitbucket',
17658
+ owner,
17659
+ repo,
17660
+ identifier
17661
+ })).otherwise(()=>null);
17662
+ }
17663
+ function resolveLabel({ issue, node }) {
17664
+ const authored = node.children.map(readInlineText).join('').trim();
17665
+ if (0 === authored.length || authored === node.url) return {
17666
+ text: issue.label,
17667
+ reference: null
17668
+ };
17669
+ return {
17670
+ text: authored,
17671
+ reference: issue.reference
17672
+ };
17673
+ }
17674
+ function readHProperties(data) {
17675
+ const properties = data.hProperties;
17676
+ if ('object' != typeof properties || null === properties || Array.isArray(properties)) return {};
17677
+ return properties;
17678
+ }
17679
+ function readClassNames(value) {
17680
+ if ('string' == typeof value) return value.split(/\s+/).filter(Boolean);
17681
+ if (!Array.isArray(value)) return [];
17682
+ return value.filter((entry)=>'string' == typeof entry);
17683
+ }
17684
+ function isNumericIdentifier(identifier) {
17685
+ return /^\d+$/.test(identifier);
17686
+ }
17687
+ function buildReferenceChildren(reference) {
17688
+ if (null === reference) return [];
17689
+ return [
17690
+ {
17691
+ type: 'mdxJsxTextElement',
17692
+ name: 'span',
17693
+ attributes: [
17694
+ {
17695
+ type: 'mdxJsxAttribute',
17696
+ name: 'className',
17697
+ value: 'cp-issue-link__reference'
17698
+ }
17699
+ ],
17700
+ children: [
17701
+ {
17702
+ type: 'text',
17703
+ value: reference
17704
+ }
17705
+ ]
17706
+ }
17707
+ ];
17708
+ }
17709
+ function readInlineText(node) {
17710
+ if (void 0 !== node.value) return node.value;
17711
+ if (void 0 === node.children) return '';
17712
+ return node.children.map(readInlineText).join('');
17713
+ }
17714
+ function parseLinearLink(segments) {
17715
+ const [workspace, resource, identifier] = segments;
17716
+ if (void 0 === workspace || 'issue' !== resource || void 0 === identifier) return null;
17717
+ if (!/^[A-Z][A-Z0-9]+-\d+$/i.test(identifier)) return null;
17718
+ const label = identifier.toUpperCase();
17719
+ return {
17720
+ provider: 'linear',
17721
+ kind: 'issue',
17722
+ label,
17723
+ reference: label,
17724
+ title: `${label} in ${workspace} on Linear`
17725
+ };
17726
+ }
17727
+ function parseJiraLink(segments) {
17728
+ const [resource, identifier] = segments;
17729
+ if (2 !== segments.length || 'browse' !== resource || void 0 === identifier) return null;
17730
+ if (!/^[A-Z][A-Z0-9]+-\d+$/i.test(identifier)) return null;
17731
+ const label = identifier.toUpperCase();
17732
+ return {
17733
+ provider: 'jira',
17734
+ kind: 'issue',
17735
+ label,
17736
+ reference: label,
17737
+ title: `${label} on Jira`
17738
+ };
17739
+ }
17740
+ function parseNpmLink(segments) {
17741
+ const [resource, ...nameParts] = segments;
17742
+ const packageName = nameParts.join('/');
17743
+ if ('package' !== resource || 0 === packageName.length || nameParts.length > 2) return null;
17744
+ return {
17745
+ provider: 'npm',
17746
+ kind: 'package',
17747
+ label: packageName,
17748
+ reference: 'npm',
17749
+ title: `${packageName} on npm`
17750
+ };
17751
+ }
17752
+ function parseFigmaLink(segments) {
17753
+ const [resource, key] = segments;
17754
+ if (void 0 === key) return null;
17755
+ return match_match(resource).with('design', ()=>opaqueLink({
17756
+ provider: 'figma',
17757
+ kind: 'design',
17758
+ label: 'Figma design'
17759
+ })).with('file', ()=>opaqueLink({
17760
+ provider: 'figma',
17761
+ kind: 'file',
17762
+ label: 'Figma file'
17763
+ })).with('proto', ()=>opaqueLink({
17764
+ provider: 'figma',
17765
+ kind: 'prototype',
17766
+ label: 'Figma prototype'
17767
+ })).with('board', ()=>opaqueLink({
17768
+ provider: 'figma',
17769
+ kind: 'whiteboard',
17770
+ label: 'FigJam board'
17771
+ })).otherwise(()=>null);
17772
+ }
17773
+ function parseGoogleDocsLink(segments) {
17774
+ const [resource, marker, identifier] = segments;
17775
+ if ('d' !== marker || void 0 === identifier) return null;
17776
+ return match_match(resource).with('document', ()=>opaqueLink({
17777
+ provider: 'google-docs',
17778
+ kind: 'document',
17779
+ label: 'Google Doc'
17780
+ })).with('spreadsheets', ()=>opaqueLink({
17781
+ provider: 'google-sheets',
17782
+ kind: 'spreadsheet',
17783
+ label: 'Google Sheet'
17784
+ })).otherwise(()=>null);
17785
+ }
17786
+ function parseGoogleDriveLink(segments) {
17787
+ const [resource, marker, identifier] = segments;
17788
+ if ('file' !== resource || 'd' !== marker || void 0 === identifier) return null;
17789
+ return opaqueLink({
17790
+ provider: 'google-drive',
17791
+ kind: 'file',
17792
+ label: 'Drive file'
17793
+ });
17794
+ }
17795
+ function parseTrelloLink(segments) {
17796
+ const [resource, identifier] = segments;
17797
+ if ('c' !== resource || void 0 === identifier) return null;
17798
+ return opaqueLink({
17799
+ provider: 'trello',
17800
+ kind: 'card',
17801
+ label: 'Trello card'
17802
+ });
17803
+ }
17804
+ function parseAsanaLink(segments) {
17805
+ const [workspace, project, identifier] = segments;
17806
+ if ('0' !== workspace || void 0 === project || void 0 === identifier) return null;
17807
+ return {
17808
+ provider: 'asana',
17809
+ kind: 'task',
17810
+ label: `Task ${identifier}`,
17811
+ reference: identifier,
17812
+ title: `Task ${identifier} on Asana`
17813
+ };
17814
+ }
17815
+ function parseLoomLink(segments) {
17816
+ const [resource, identifier] = segments;
17817
+ if ('share' !== resource || void 0 === identifier) return null;
17818
+ return opaqueLink({
17819
+ provider: 'loom',
17820
+ kind: 'video',
17821
+ label: 'Loom video'
17822
+ });
17823
+ }
17824
+ function parsePostmanLink(segments) {
17825
+ return match_match(segments).when((path)=>path.includes('workspace'), ()=>opaqueLink({
17826
+ provider: 'postman',
17827
+ kind: 'workspace',
17828
+ label: 'Postman workspace'
17829
+ })).when((path)=>path.includes('collection') || path.includes('collections'), ()=>opaqueLink({
17830
+ provider: 'postman',
17831
+ kind: 'collection',
17832
+ label: 'Postman collection'
17833
+ })).otherwise(()=>null);
17834
+ }
17835
+ function parseAtlassianLink(segments) {
17836
+ const jira = parseJiraLink(segments);
17837
+ return match_match({
17838
+ jira,
17839
+ segments
17840
+ }).when(({ jira: parsed })=>null !== parsed, ({ jira: parsed })=>parsed).when(({ segments: path })=>'wiki' === path.at(0), ({ segments: path })=>parseConfluenceLink(path)).otherwise(()=>null);
17841
+ }
17842
+ function parseConfluenceLink(segments) {
17843
+ const pagesIndex = segments.indexOf('pages');
17844
+ if (-1 === pagesIndex) return opaqueLink({
17845
+ provider: 'confluence',
17846
+ kind: 'page',
17847
+ label: 'Confluence page'
17848
+ });
17849
+ const identifier = segments.at(pagesIndex + 1);
17850
+ return match_match(identifier).when((value)=>void 0 !== value, (value)=>({
17851
+ provider: 'confluence',
17852
+ kind: 'page',
17853
+ label: `Page ${value}`,
17854
+ reference: value,
17855
+ title: `Page ${value} on Confluence`
17856
+ })).otherwise(()=>opaqueLink({
17857
+ provider: 'confluence',
17858
+ kind: 'page',
17859
+ label: 'Confluence page'
17860
+ }));
17861
+ }
17862
+ function parseSlackLink(segments) {
17863
+ const [resource, channel, timestamp] = segments;
17864
+ if ('archives' !== resource || void 0 === channel || void 0 === timestamp) return null;
17865
+ return opaqueLink({
17866
+ provider: 'slack',
17867
+ kind: 'message',
17868
+ label: 'Slack message'
17869
+ });
17870
+ }
17871
+ function parseSentryLink(segments) {
17872
+ const issueIndex = segments.indexOf('issues');
17873
+ const identifier = segments.at(issueIndex + 1);
17874
+ if (-1 === issueIndex || void 0 === identifier) return null;
17875
+ return {
17876
+ provider: 'sentry',
17877
+ kind: 'issue',
17878
+ label: `Issue #${identifier}`,
17879
+ reference: `#${identifier}`,
17880
+ title: `Issue #${identifier} on Sentry`
17881
+ };
17882
+ }
17883
+ function numberedGitHubLink({ owner, repo, identifier, kind }) {
17884
+ return match_match(kind).with('issue', ()=>({
17885
+ provider: 'github',
17886
+ kind,
17887
+ label: `Issue #${identifier}`,
17888
+ reference: `#${identifier}`,
17889
+ title: `Issue #${identifier} in ${owner}/${repo} on GitHub`
17890
+ })).with('pull', ()=>({
17891
+ provider: 'github',
17892
+ kind,
17893
+ label: `Pull #${identifier}`,
17894
+ reference: `#${identifier}`,
17895
+ title: `Pull #${identifier} in ${owner}/${repo} on GitHub`
17896
+ })).with('discussion', ()=>({
17897
+ provider: 'github',
17898
+ kind,
17899
+ label: `Discussion #${identifier}`,
17900
+ reference: `#${identifier}`,
17901
+ title: `Discussion #${identifier} in ${owner}/${repo} on GitHub`
17902
+ })).exhaustive();
17903
+ }
17904
+ function numberedLink({ provider, kind, identifier }) {
17905
+ return match_match({
17906
+ provider,
17907
+ kind
17908
+ }).with({
17909
+ provider: 'gitlab',
17910
+ kind: 'issue'
17911
+ }, ()=>({
17912
+ provider: 'gitlab',
17913
+ kind: 'issue',
17914
+ label: `Issue #${identifier}`,
17915
+ reference: `#${identifier}`,
17916
+ title: `Issue #${identifier} on GitLab`
17917
+ })).with({
17918
+ provider: 'gitlab',
17919
+ kind: 'merge'
17920
+ }, ()=>({
17921
+ provider: 'gitlab',
17922
+ kind: 'merge',
17923
+ label: `Merge #${identifier}`,
17924
+ reference: `#${identifier}`,
17925
+ title: `Merge request #${identifier} on GitLab`
17926
+ })).with({
17927
+ provider: 'bitbucket',
17928
+ kind: 'issue'
17929
+ }, ()=>({
17930
+ provider: 'bitbucket',
17931
+ kind: 'issue',
17932
+ label: `Issue #${identifier}`,
17933
+ reference: `#${identifier}`,
17934
+ title: `Issue #${identifier} on Bitbucket`
17935
+ })).with({
17936
+ provider: 'bitbucket',
17937
+ kind: 'pull'
17938
+ }, ()=>({
17939
+ provider: 'bitbucket',
17940
+ kind: 'pull',
17941
+ label: `Pull #${identifier}`,
17942
+ reference: `#${identifier}`,
17943
+ title: `Pull request #${identifier} on Bitbucket`
17944
+ })).otherwise(()=>null);
17945
+ }
17946
+ function commitLink({ provider, owner, repo, identifier }) {
17947
+ const shortHash = identifier.slice(0, 7);
17948
+ const repository = repositoryLabel({
17949
+ owner,
17950
+ repo
17951
+ });
17952
+ return match_match(provider).with('github', ()=>({
17953
+ provider,
17954
+ kind: 'commit',
17955
+ label: `Commit ${shortHash}`,
17956
+ reference: shortHash,
17957
+ title: `Commit ${shortHash}${repository} on GitHub`
17958
+ })).with('gitlab', ()=>({
17959
+ provider,
17960
+ kind: 'commit',
17961
+ label: `Commit ${shortHash}`,
17962
+ reference: shortHash,
17963
+ title: `Commit ${shortHash} on GitLab`
17964
+ })).with('bitbucket', ()=>({
17965
+ provider,
17966
+ kind: 'commit',
17967
+ label: `Commit ${shortHash}`,
17968
+ reference: shortHash,
17969
+ title: `Commit ${shortHash}${repository} on Bitbucket`
17970
+ })).exhaustive();
17971
+ }
17972
+ function repositoryLabel({ owner, repo }) {
17973
+ if (0 === owner.length || 0 === repo.length) return '';
17974
+ return ` in ${owner}/${repo}`;
17975
+ }
17976
+ function parseGitHubRelease({ owner, repo, segments }) {
17977
+ const [tagMarker, identifier] = segments.slice(3);
17978
+ if ('tag' !== tagMarker || void 0 === identifier) return null;
17979
+ return {
17980
+ provider: 'github',
17981
+ kind: 'release',
17982
+ label: `Release ${identifier}`,
17983
+ reference: identifier,
17984
+ title: `Release ${identifier} in ${owner}/${repo} on GitHub`
17985
+ };
17986
+ }
17987
+ function parseGitHubAction({ owner, repo, segments }) {
17988
+ const [runMarker, identifier] = segments.slice(3);
17989
+ if ('runs' !== runMarker || void 0 === identifier) return null;
17990
+ return {
17991
+ provider: 'github',
17992
+ kind: 'action',
17993
+ label: `Run #${identifier}`,
17994
+ reference: `#${identifier}`,
17995
+ title: `Actions run #${identifier} in ${owner}/${repo} on GitHub`
17996
+ };
17997
+ }
17998
+ function parseNotionLink(segments) {
17999
+ if (0 === segments.length) return null;
18000
+ return opaqueLink({
18001
+ provider: 'notion',
18002
+ kind: 'page',
18003
+ label: 'Notion page'
18004
+ });
18005
+ }
18006
+ function opaqueLink(params) {
18007
+ const provider = providerName(params.provider);
18008
+ return {
18009
+ ...params,
18010
+ reference: null,
18011
+ title: `${params.label} on ${provider}`
18012
+ };
18013
+ }
18014
+ function providerName(provider) {
18015
+ return match_match(provider).with('confluence', ()=>'Confluence').with('dash0', ()=>'Dash0').with('datadog', ()=>'Datadog').with('figma', ()=>'Figma').with('google-docs', ()=>'Google Docs').with('google-drive', ()=>'Google Drive').with('google-sheets', ()=>'Google Sheets').with('loom', ()=>'Loom').with('notion', ()=>'Notion').with('postman', ()=>'Postman').with('posthog', ()=>'PostHog').with('slack', ()=>'Slack').with('trello', ()=>'Trello').with('vercel', ()=>'Vercel').exhaustive();
18016
+ }
18017
+ function isNotionHostname(hostname) {
18018
+ return 'notion.so' === hostname || 'www.notion.so' === hostname || 'app.notion.com' === hostname || 'notion.site' === hostname || hostname.endsWith('.notion.site');
18019
+ }
18020
+ function isSlackHostname(hostname) {
18021
+ return hostname.endsWith('.slack.com');
18022
+ }
18023
+ function isSentryHostname(hostname) {
18024
+ return 'sentry.io' === hostname || hostname.endsWith('.sentry.io');
18025
+ }
18026
+ function isDatadogHostname(hostname) {
18027
+ return /^(?:app|ap\d+|us\d+)\.datadoghq\.(?:com|eu)$/.test(hostname);
18028
+ }
18029
+ function isPagerDutyHostname(hostname) {
18030
+ return 'app.pagerduty.com' === hostname || hostname.endsWith('.pagerduty.com');
18031
+ }
17382
18032
  function remarkMathToDiv() {
17383
18033
  return (tree)=>{
17384
18034
  external_unist_util_visit_visit(tree, 'math', (node)=>{
@@ -17451,6 +18101,412 @@ function mermaidPlugin(options = {}) {
17451
18101
  builderConfig: remarkMermaid.builderConfig
17452
18102
  };
17453
18103
  }
18104
+ const SAFE_PROTOCOLS = new Set([
18105
+ 'http:',
18106
+ 'https:',
18107
+ 'mailto:',
18108
+ 'tel:'
18109
+ ]);
18110
+ const PROTOCOL_PATTERN = /^[a-z][a-z0-9+.-]*:/i;
18111
+ const FORBIDDEN_CHARS_PATTERN = /[\u0000-\u0020\u007F]/u;
18112
+ function safeUrl(href) {
18113
+ const trimmed = href.trim();
18114
+ if (FORBIDDEN_CHARS_PATTERN.test(trimmed)) return null;
18115
+ return match_match(trimmed).with('', ()=>null).with(P.string.startsWith('#'), ()=>trimmed).with(P.string.startsWith('/'), ()=>trimmed).with(P.string.startsWith('./'), ()=>trimmed).with(P.string.startsWith('../'), ()=>trimmed).otherwise(()=>{
18116
+ const match_ = trimmed.match(PROTOCOL_PATTERN);
18117
+ if (!match_) return trimmed;
18118
+ const scheme = match_[0].toLowerCase();
18119
+ if (SAFE_PROTOCOLS.has(scheme)) return trimmed;
18120
+ return null;
18121
+ });
18122
+ }
18123
+ const ALLOWED_TAGS = new Set([
18124
+ 'b',
18125
+ 'strong',
18126
+ 'i',
18127
+ 'em',
18128
+ 'code',
18129
+ 'kbd',
18130
+ 'mark',
18131
+ 'sup',
18132
+ 'sub',
18133
+ 'span',
18134
+ 'small',
18135
+ 'u',
18136
+ 's',
18137
+ 'del',
18138
+ 'ins'
18139
+ ]);
18140
+ const STRIPPED_TAGS = new Set([
18141
+ "script",
18142
+ 'style',
18143
+ 'iframe',
18144
+ 'object',
18145
+ 'embed',
18146
+ 'template',
18147
+ "noscript"
18148
+ ]);
18149
+ const ACCENT_CLASS = 'cp-accent';
18150
+ const MARK_CLASS = 'cp-mark';
18151
+ const TOKEN_PATTERN = /(?:\\([*=`[\]<\\]))|(?:`([^`]+)`)|(?:\*\*([\s\S]+?)\*\*)|(?:==([\s\S]+?)==)|(?:(?<!\*)\*(?=[^\s*])([^*\n]+?)(?<=[^\s*])\*(?!\*))|(?:\[([^\]]*)\]\(((?:[^()\s]|\([^()\s]*\))+)\))|(?:<(\/?)\s*([a-zA-Z][a-zA-Z0-9-]*)(?=[\s/>])((?:"[^"]*"|'[^']*'|[^>"'])*)>)/;
18152
+ const ATTR_PATTERN = /([a-zA-Z-]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
18153
+ const CLOSE_TAG_BOUNDARY = /[\s>]/;
18154
+ function parseRichText(text) {
18155
+ if ('string' != typeof text || 0 === text.length) return [];
18156
+ return parseInline({
18157
+ input: text,
18158
+ inLink: false
18159
+ });
18160
+ }
18161
+ function toPlainText(text) {
18162
+ return flattenNodes(parseRichText(text));
18163
+ }
18164
+ function parseInline({ input, inLink }) {
18165
+ return unfold((remaining)=>{
18166
+ if (0 === remaining.length) return false;
18167
+ const found = TOKEN_PATTERN.exec(remaining);
18168
+ if (null === found) return [
18169
+ [
18170
+ {
18171
+ kind: 'text',
18172
+ value: remaining
18173
+ }
18174
+ ],
18175
+ ''
18176
+ ];
18177
+ const lead = remaining.slice(0, found.index);
18178
+ const after = remaining.slice(found.index + found[0].length);
18179
+ const step = consumeToken({
18180
+ found,
18181
+ after,
18182
+ inLink
18183
+ });
18184
+ return [
18185
+ [
18186
+ ...textNodes(lead),
18187
+ ...step.nodes
18188
+ ],
18189
+ step.rest
18190
+ ];
18191
+ }, input).flat();
18192
+ }
18193
+ function textNodes(lead) {
18194
+ if (0 === lead.length) return [];
18195
+ return [
18196
+ {
18197
+ kind: 'text',
18198
+ value: lead
18199
+ }
18200
+ ];
18201
+ }
18202
+ function consumeToken({ found, after, inLink }) {
18203
+ const [, escaped, code, bold, highlight, italic, linkText, linkHref, closing, tagName, rawAttrs] = found;
18204
+ if (void 0 !== escaped) return {
18205
+ nodes: [
18206
+ {
18207
+ kind: 'text',
18208
+ value: escaped
18209
+ }
18210
+ ],
18211
+ rest: after
18212
+ };
18213
+ if (void 0 !== code) return {
18214
+ nodes: [
18215
+ codeNode(code)
18216
+ ],
18217
+ rest: after
18218
+ };
18219
+ if (void 0 !== bold) return {
18220
+ nodes: [
18221
+ accentNode(parseInline({
18222
+ input: bold,
18223
+ inLink
18224
+ }))
18225
+ ],
18226
+ rest: after
18227
+ };
18228
+ if (void 0 !== highlight) return {
18229
+ nodes: [
18230
+ markNode(parseInline({
18231
+ input: highlight,
18232
+ inLink
18233
+ }))
18234
+ ],
18235
+ rest: after
18236
+ };
18237
+ if (void 0 !== italic) return {
18238
+ nodes: [
18239
+ rich_text_parse_element({
18240
+ tag: 'em',
18241
+ children: parseInline({
18242
+ input: italic,
18243
+ inLink
18244
+ })
18245
+ })
18246
+ ],
18247
+ rest: after
18248
+ };
18249
+ if (void 0 !== linkHref) return {
18250
+ nodes: linkNodes({
18251
+ text: linkText ?? '',
18252
+ href: linkHref,
18253
+ inLink
18254
+ }),
18255
+ rest: after
18256
+ };
18257
+ if (void 0 !== tagName) {
18258
+ const tail = (rawAttrs ?? '').trimEnd();
18259
+ const isSelfClosing = tail.endsWith('/');
18260
+ return consumeTag({
18261
+ tagName: tagName.toLowerCase(),
18262
+ attrs: match_match(isSelfClosing).with(true, ()=>tail.slice(0, -1)).otherwise(()=>tail),
18263
+ isClosing: '/' === closing,
18264
+ isSelfClosing,
18265
+ after,
18266
+ inLink
18267
+ });
18268
+ }
18269
+ return {
18270
+ nodes: [
18271
+ {
18272
+ kind: 'text',
18273
+ value: found[0]
18274
+ }
18275
+ ],
18276
+ rest: after
18277
+ };
18278
+ }
18279
+ function consumeTag(params) {
18280
+ const { tagName, attrs, isClosing, isSelfClosing, after, inLink } = params;
18281
+ if (isClosing) return {
18282
+ nodes: [],
18283
+ rest: after
18284
+ };
18285
+ if ('br' === tagName) return {
18286
+ nodes: [
18287
+ {
18288
+ kind: 'break'
18289
+ }
18290
+ ],
18291
+ rest: after
18292
+ };
18293
+ if (isSelfClosing) return {
18294
+ nodes: selfClosingNodes({
18295
+ tagName,
18296
+ attrs
18297
+ }),
18298
+ rest: after
18299
+ };
18300
+ const close = findClosingTag({
18301
+ text: after,
18302
+ tagName
18303
+ });
18304
+ if (null === close) {
18305
+ if (STRIPPED_TAGS.has(tagName)) return {
18306
+ nodes: [],
18307
+ rest: ''
18308
+ };
18309
+ return {
18310
+ nodes: [],
18311
+ rest: after
18312
+ };
18313
+ }
18314
+ const inner = after.slice(0, close.start);
18315
+ const rest = after.slice(close.end);
18316
+ if (STRIPPED_TAGS.has(tagName)) return {
18317
+ nodes: [],
18318
+ rest
18319
+ };
18320
+ if ('a' === tagName) return {
18321
+ nodes: anchorNodes({
18322
+ attrs,
18323
+ inner,
18324
+ inLink
18325
+ }),
18326
+ rest
18327
+ };
18328
+ if (ALLOWED_TAGS.has(tagName)) return {
18329
+ nodes: [
18330
+ taggedElement({
18331
+ tag: tagName,
18332
+ attrs,
18333
+ children: parseInline({
18334
+ input: inner,
18335
+ inLink
18336
+ })
18337
+ })
18338
+ ],
18339
+ rest
18340
+ };
18341
+ return {
18342
+ nodes: parseInline({
18343
+ input: inner,
18344
+ inLink
18345
+ }),
18346
+ rest
18347
+ };
18348
+ }
18349
+ function selfClosingNodes({ tagName, attrs }) {
18350
+ if (!ALLOWED_TAGS.has(tagName)) return [];
18351
+ return [
18352
+ taggedElement({
18353
+ tag: tagName,
18354
+ attrs,
18355
+ children: []
18356
+ })
18357
+ ];
18358
+ }
18359
+ function findClosingTag({ text, tagName }) {
18360
+ return scanForClose({
18361
+ lower: text.toLowerCase(),
18362
+ tagName,
18363
+ from: 0
18364
+ });
18365
+ }
18366
+ function scanForClose({ lower, tagName, from }) {
18367
+ const needle = `</${tagName}`;
18368
+ const candidates = unfold((offset)=>{
18369
+ const at = lower.indexOf(needle, offset);
18370
+ if (-1 === at) return false;
18371
+ return [
18372
+ at,
18373
+ at + needle.length
18374
+ ];
18375
+ }, from);
18376
+ const start = candidates.find((at)=>CLOSE_TAG_BOUNDARY.test(lower.charAt(at + needle.length)));
18377
+ if (void 0 === start) return null;
18378
+ const gt = lower.indexOf('>', start);
18379
+ if (-1 === gt) return null;
18380
+ return {
18381
+ start,
18382
+ end: gt + 1
18383
+ };
18384
+ }
18385
+ function parseAttrs(attrs) {
18386
+ const entries = [
18387
+ ...attrs.matchAll(ATTR_PATTERN)
18388
+ ];
18389
+ return entries.reduce((acc, entry)=>{
18390
+ const name = entry[1].toLowerCase();
18391
+ const value = entry[2] ?? entry[3] ?? '';
18392
+ return match_match(name).with('class', ()=>({
18393
+ ...acc,
18394
+ className: value
18395
+ })).with('classname', ()=>({
18396
+ ...acc,
18397
+ className: value
18398
+ })).with('title', ()=>({
18399
+ ...acc,
18400
+ title: value
18401
+ })).with('href', ()=>({
18402
+ ...acc,
18403
+ href: value
18404
+ })).otherwise(()=>acc);
18405
+ }, {});
18406
+ }
18407
+ function taggedElement({ tag, attrs, children }) {
18408
+ const parsed = parseAttrs(attrs);
18409
+ return {
18410
+ kind: 'element',
18411
+ tag,
18412
+ className: parsed.className,
18413
+ title: parsed.title,
18414
+ children
18415
+ };
18416
+ }
18417
+ function anchorNodes({ attrs, inner, inLink }) {
18418
+ const { href } = parseAttrs(attrs);
18419
+ if (void 0 === href || inLink) return parseInline({
18420
+ input: inner,
18421
+ inLink
18422
+ });
18423
+ const safe = safeUrl(href);
18424
+ if (null === safe) return parseInline({
18425
+ input: inner,
18426
+ inLink
18427
+ });
18428
+ const children = parseInline({
18429
+ input: inner,
18430
+ inLink: true
18431
+ });
18432
+ return linkOrChildren({
18433
+ href: safe,
18434
+ children
18435
+ });
18436
+ }
18437
+ function linkNodes({ text, href, inLink }) {
18438
+ const safe = safeUrl(href);
18439
+ if (null === safe || inLink) return parseInline({
18440
+ input: text,
18441
+ inLink
18442
+ });
18443
+ return linkOrChildren({
18444
+ href: safe,
18445
+ children: parseInline({
18446
+ input: text,
18447
+ inLink: true
18448
+ })
18449
+ });
18450
+ }
18451
+ function linkOrChildren({ href, children }) {
18452
+ if (0 === children.length) return [];
18453
+ return [
18454
+ {
18455
+ kind: 'link',
18456
+ href,
18457
+ children
18458
+ }
18459
+ ];
18460
+ }
18461
+ function codeNode(value) {
18462
+ return {
18463
+ kind: 'code',
18464
+ value
18465
+ };
18466
+ }
18467
+ function accentNode(children) {
18468
+ return {
18469
+ kind: 'element',
18470
+ tag: 'strong',
18471
+ className: ACCENT_CLASS,
18472
+ children
18473
+ };
18474
+ }
18475
+ function markNode(children) {
18476
+ return {
18477
+ kind: 'element',
18478
+ tag: 'mark',
18479
+ className: MARK_CLASS,
18480
+ children
18481
+ };
18482
+ }
18483
+ function rich_text_parse_element({ tag, children }) {
18484
+ return {
18485
+ kind: 'element',
18486
+ tag,
18487
+ children
18488
+ };
18489
+ }
18490
+ function flattenNodes(nodes) {
18491
+ return nodes.map(flattenNode).join('');
18492
+ }
18493
+ function flattenNode(node) {
18494
+ return match_match(node).with({
18495
+ kind: 'text'
18496
+ }, (n)=>n.value).with({
18497
+ kind: 'code'
18498
+ }, (n)=>n.value).with({
18499
+ kind: 'break'
18500
+ }, ()=>' ').with({
18501
+ kind: 'link'
18502
+ }, (n)=>flattenNodes(n.children)).with({
18503
+ kind: 'element'
18504
+ }, (n)=>flattenNodes(n.children)).exhaustive();
18505
+ }
18506
+ function resolveSeoSiteUrl(params) {
18507
+ return new URL(params.base, params.origin).href;
18508
+ }
18509
+ const issueLinkIconPath = node_path.join(import.meta.dirname, 'theme', 'components', 'shared', 'IssueLinkIcon.tsx');
17454
18510
  const DEFAULT_LOADER_MIN_MS = 150;
17455
18511
  const DEFAULT_LOADER_MAX_MS = 5000;
17456
18512
  const VSCODE_SET_JS = "document.documentElement.dataset.ciderpressEnv='vscode'";
@@ -17538,22 +18594,33 @@ function createRspressConfig(options) {
17538
18594
  sidebar,
17539
18595
  footer
17540
18596
  });
18597
+ const seoThemeConfig = match_match(config.seo).with(void 0, ()=>({})).otherwise((seo)=>({
18598
+ seo,
18599
+ seoBase: resolvedBase
18600
+ }));
17541
18601
  return {
17542
18602
  root: paths.contentDir,
17543
18603
  outDir: paths.distDir,
17544
18604
  base: resolvedBase,
18605
+ ...match_match(config.seo).with(void 0, ()=>({})).otherwise((seo)=>({
18606
+ siteOrigin: seo.origin
18607
+ })),
17545
18608
  route: {
17546
18609
  cleanUrls: true
17547
18610
  },
17548
18611
  llms: true,
17549
- title: config.title ?? 'ciderpress',
17550
- description: config.description ?? 'Documentation',
18612
+ title: toPlainText(config.title ?? 'ciderpress'),
18613
+ description: toPlainText(config.description ?? 'Documentation'),
17551
18614
  icon: resolveFaviconPath(favicon),
17552
18615
  logo: match_match(logoRaw).with(P.string, (l)=>l).otherwise(()=>''),
17553
18616
  logoText: '',
17554
18617
  themeDir: node_path.resolve(import.meta.dirname, 'theme'),
17555
18618
  plugins: [
17556
18619
  ciderpressPlugin(),
18620
+ ...resolveSitemapPlugins({
18621
+ config,
18622
+ base: resolvedBase
18623
+ }),
17557
18624
  mermaidPlugin(),
17558
18625
  dist({
17559
18626
  initialExpandDepth: 1
@@ -17563,7 +18630,11 @@ function createRspressConfig(options) {
17563
18630
  ],
17564
18631
  markdown: {
17565
18632
  remarkPlugins: [
17566
- remarkMathToDiv
18633
+ remarkMathToDiv,
18634
+ remarkIssueLinks
18635
+ ],
18636
+ globalComponents: [
18637
+ issueLinkIconPath
17567
18638
  ],
17568
18639
  link: {
17569
18640
  checkDeadLinks: {
@@ -17572,12 +18643,9 @@ function createRspressConfig(options) {
17572
18643
  }
17573
18644
  },
17574
18645
  builderConfig: {
17575
- ...(()=>{
17576
- if (logLevel) return {
17577
- logLevel
17578
- };
17579
- return {};
17580
- })(),
18646
+ ...match_match(logLevel).with(void 0, ()=>({})).otherwise((resolvedLogLevel)=>({
18647
+ logLevel: resolvedLogLevel
18648
+ })),
17581
18649
  html: {
17582
18650
  tags: [
17583
18651
  ...resolveFaviconLinkTags(favicon),
@@ -17645,6 +18713,7 @@ function createRspressConfig(options) {
17645
18713
  standaloneScopePaths,
17646
18714
  pageBadges
17647
18715
  },
18716
+ ...seoThemeConfig,
17648
18717
  ...{
17649
18718
  socialLinks: serializeSocials(config.socials),
17650
18719
  sidebarAbove: resolveSidebarLinks({
@@ -17662,6 +18731,32 @@ function createRspressConfig(options) {
17662
18731
  }
17663
18732
  };
17664
18733
  }
18734
+ function resolveSitemapPlugins(params) {
18735
+ const { config } = params;
18736
+ const { seo } = config;
18737
+ if (void 0 === seo || false === seo.sitemap) return [];
18738
+ const sitemap = seo.sitemap;
18739
+ const siteUrl = resolveSeoSiteUrl({
18740
+ origin: seo.origin,
18741
+ base: params.base
18742
+ });
18743
+ if (void 0 === sitemap || true === sitemap) return [
18744
+ pluginSitemap({
18745
+ siteUrl
18746
+ })
18747
+ ];
18748
+ return [
18749
+ pluginSitemap({
18750
+ siteUrl,
18751
+ ...match_match(sitemap.changeFrequency).with(void 0, ()=>({})).otherwise((defaultChangeFreq)=>({
18752
+ defaultChangeFreq
18753
+ })),
18754
+ ...match_match(sitemap.priority).with(void 0, ()=>({})).otherwise((defaultPriority)=>({
18755
+ defaultPriority
18756
+ }))
18757
+ })
18758
+ ];
18759
+ }
17665
18760
  function loadGenerated(params) {
17666
18761
  const p = node_path.resolve(params.contentDir, '.generated', params.name);
17667
18762
  if (!existsSync(p)) {
@@ -17860,20 +18955,10 @@ function buildSiteBlock(params) {
17860
18955
  };
17861
18956
  }
17862
18957
  function resolveHomeConfig(home) {
17863
- const fallbackShowcase = {
17864
- columns: 2
17865
- };
17866
18958
  if (void 0 === home) return {
17867
- hero: {},
17868
- showcase: fallbackShowcase
17869
- };
17870
- return {
17871
- ...home,
17872
- showcase: {
17873
- columns: 2,
17874
- ...home.showcase
17875
- }
18959
+ hero: {}
17876
18960
  };
18961
+ return home;
17877
18962
  }
17878
18963
  function buildHeadScriptBody(options) {
17879
18964
  const minimalRegistry = options.registry.map((entry)=>({
@@ -17916,13 +19001,10 @@ function buildHeadScriptBody(options) {
17916
19001
  }
17917
19002
  try { localStorage.setItem('rspress-theme-appearance', variant); } catch (_) {}
17918
19003
  })()`;
17919
- const vscodeJs = (()=>{
17920
- if (options.vscode) return [
19004
+ const vscodeJs = match_match(options.vscode).with(true, ()=>[
17921
19005
  VSCODE_SET_JS,
17922
19006
  VSCODE_NAV_JS
17923
- ].join(';');
17924
- return '';
17925
- })();
19007
+ ].join(';')).otherwise(()=>'');
17926
19008
  const fallbackJs = match_match(options.loaderEnabled).with(true, ()=>`setTimeout(function(){var d=document.documentElement;if(d.dataset.cpReady!=='true'){d.classList.add('cp-loader-fade');setTimeout(function(){d.dataset.cpReady='true'},220)}},${options.loaderMaxMs})`).otherwise(()=>'');
17927
19009
  const loaderJs = match_match(options.useDotsLoader).with(true, ()=>LOADER_DOTS_JS).otherwise(()=>'');
17928
19010
  return [