@terrafirmagreg-team/kit 0.1.0 → 1.2.1

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 (81) hide show
  1. package/package.json +15 -27
  2. package/src/components/blocks/nav-title.tsx +22 -25
  3. package/src/components/outline/dropdown.tsx +3 -2
  4. package/src/components/outline/index.ts +2 -1
  5. package/src/components/outline/list.tsx +3 -2
  6. package/src/components/outline/outline.tsx +4 -3
  7. package/src/components/outline/popover.tsx +3 -2
  8. package/src/components/page-actions.tsx +10 -9
  9. package/src/components/relative-link.tsx +1 -0
  10. package/src/components/toc/base.tsx +2 -1
  11. package/src/components/toc/block.tsx +1 -0
  12. package/src/components/toc/clerk.tsx +2 -1
  13. package/src/components/toc/default.tsx +3 -2
  14. package/src/components/version-menu.tsx +19 -17
  15. package/src/components/views/dataset.tsx +11 -2
  16. package/src/components/views/section.tsx +88 -44
  17. package/src/components/workspace/content.tsx +1 -0
  18. package/src/components/workspace/index.ts +1 -0
  19. package/src/components/workspace/pagination.tsx +2 -1
  20. package/src/components/workspace/workspace.tsx +1 -0
  21. package/src/hooks/use-catalog.ts +1 -0
  22. package/src/hooks/use-current-dataset.ts +15 -5
  23. package/src/hooks/use-dataset-accent.ts +1 -0
  24. package/src/hooks/use-nav-options.ts +20 -17
  25. package/src/hooks/use-section-names.ts +40 -0
  26. package/src/hooks/{toc.ts → use-toc.ts} +1 -0
  27. package/src/hooks/use-version-pref.ts +1 -0
  28. package/src/hooks/use-versioned-dataset.ts +21 -0
  29. package/src/lib/breadcrumb.ts +3 -16
  30. package/src/lib/config.ts +30 -28
  31. package/src/lib/dataset-links.ts +1 -0
  32. package/src/lib/datasets.ts +98 -68
  33. package/src/lib/landing.ts +4 -2
  34. package/src/lib/layout.ts +1 -0
  35. package/src/lib/locale/renderer.ts +49 -0
  36. package/src/lib/order.ts +1 -0
  37. package/src/lib/page.ts +3 -2
  38. package/src/lib/pin-tree.ts +11 -8
  39. package/src/lib/preview/lookup.ts +8 -5
  40. package/src/lib/section/schema.ts +2 -6
  41. package/src/lib/section/source.ts +59 -22
  42. package/src/lib/sources.ts +1 -0
  43. package/src/lib/tree.ts +1 -0
  44. package/src/lib/urls.ts +1 -0
  45. package/src/locales/en_us.json +7 -10
  46. package/src/locales/ru_ru.json +7 -10
  47. package/src/locales.ts +1 -0
  48. package/src/types/embeds.ts +54 -0
  49. package/src/types/index.ts +13 -9
  50. package/src/{components/outline/types.ts → types/outline.ts} +1 -0
  51. package/src/components/docs-image.tsx +0 -49
  52. package/src/components/search/dialog.tsx +0 -145
  53. package/src/lib/legacy.ts +0 -18
  54. package/src/lib/location.ts +0 -63
  55. package/src/lib/markdown/dom.ts +0 -90
  56. package/src/lib/markdown/index.ts +0 -13
  57. package/src/lib/markdown/providers.ts +0 -25
  58. package/src/lib/mdx/accordions.ts +0 -93
  59. package/src/lib/mdx/banner.ts +0 -52
  60. package/src/lib/mdx/directive-utils.ts +0 -125
  61. package/src/lib/mdx/directives.ts +0 -141
  62. package/src/lib/mdx/game-export.ts +0 -44
  63. package/src/lib/mdx/html-style.ts +0 -135
  64. package/src/lib/mdx/preview.ts +0 -252
  65. package/src/lib/mdx/references.ts +0 -56
  66. package/src/lib/mdx/tabs.ts +0 -80
  67. package/src/lib/mdx-components.tsx +0 -139
  68. package/src/lib/pack-assets.ts +0 -45
  69. package/src/lib/preview/index.ts +0 -8
  70. package/src/lib/preview/og.tsx +0 -115
  71. package/src/lib/preview/resolvers.ts +0 -98
  72. package/src/lib/search/config.ts +0 -13
  73. package/src/lib/search/filters.ts +0 -22
  74. package/src/lib/search/index.ts +0 -19
  75. package/src/lib/search/indexes.ts +0 -43
  76. package/src/lib/search/merge.ts +0 -22
  77. package/src/lib/search/server.ts +0 -18
  78. package/src/lib/search/sources.ts +0 -19
  79. package/src/lib/search/structured.ts +0 -23
  80. package/src/types/mdx.ts +0 -55
  81. package/src/types/turndown-plugin-gfm.d.ts +0 -9
package/package.json CHANGED
@@ -1,47 +1,38 @@
1
1
  {
2
2
  "name": "@terrafirmagreg-team/kit",
3
- "version": "0.1.0",
3
+ "version": "1.2.1",
4
4
  "type": "module",
5
+ "description": "Fumadocs content engine",
6
+ "license": "LGPL-3.0-only",
5
7
  "exports": {
6
8
  "./lib/*": [
7
9
  "./src/lib/*.ts",
8
- "./src/lib/*.tsx",
9
- "./src/lib/*/index.ts",
10
- "./src/lib/*/index.tsx"
10
+ "./src/lib/*/index.ts"
11
11
  ],
12
12
  "./types/*": "./src/types/*.ts",
13
13
  "./hooks/*": [
14
14
  "./src/hooks/*.ts",
15
- "./src/hooks/*.tsx",
16
- "./src/hooks/*/index.ts",
17
- "./src/hooks/*/index.tsx"
15
+ "./src/hooks/*/index.ts"
18
16
  ],
19
17
  "./types": "./src/types/index.ts",
20
18
  "./components/*": [
21
- "./src/components/*.ts",
22
19
  "./src/components/*.tsx",
23
- "./src/components/*/index.ts",
24
- "./src/components/*/index.tsx"
20
+ "./src/components/*/index.tsx",
21
+ "./src/components/*/index.ts"
25
22
  ],
26
23
  "./locales": "./src/locales.ts"
27
24
  },
28
25
  "dependencies": {
29
26
  "@base-ui/react": "^1.9.0",
30
27
  "@icons-pack/react-simple-icons": "13.15.1",
31
- "@terrafirmagreg-team/translate": "0.1.0",
32
- "@terrafirmagreg-team/ui": "0.1.0",
28
+ "@terrafirmagreg-team/data": "1.2.1",
29
+ "@terrafirmagreg-team/mdx": "1.2.1",
30
+ "@terrafirmagreg-team/sites": "1.2.1",
31
+ "@terrafirmagreg-team/translate": "1.2.1",
32
+ "@terrafirmagreg-team/ui": "1.2.1",
33
33
  "fumadocs-core": "16.17.8",
34
- "fumadocs-mdx": "15.4.10",
35
- "fumadocs-twoslash": "^4.0.4",
36
- "lucide-react": "^1.63.0",
37
- "remark-directive": "^4.0.0",
38
- "remark-gfm": "^4.0.1",
39
- "remark-math": "^6.0.0",
40
- "remark-parse": "^11.0.0",
34
+ "lucide-react": "^0.577.0",
41
35
  "server-only": "^0.0.1",
42
- "turndown": "^7.2.4",
43
- "turndown-plugin-gfm": "^1.0.2",
44
- "unified": "^11.0.5",
45
36
  "zod": "4.6.7"
46
37
  },
47
38
  "peerDependencies": {
@@ -52,8 +43,7 @@
52
43
  "@types/mdx": "^2.0.14",
53
44
  "@types/node": "^26.6.5",
54
45
  "@types/react": "^19.3.0",
55
- "@types/react-dom": "^19.3.0",
56
- "@types/turndown": "^5.0.6"
46
+ "@types/react-dom": "^19.3.0"
57
47
  },
58
48
  "repository": {
59
49
  "type": "git",
@@ -64,8 +54,6 @@
64
54
  "access": "public"
65
55
  },
66
56
  "files": [
67
- "src",
68
- "styles",
69
- "styles.css"
57
+ "src"
70
58
  ]
71
59
  }
@@ -8,34 +8,34 @@ import { SiteTitle } from '@terrafirmagreg-team/ui/components/blocks/nav/site-ti
8
8
  import { useAsyncValue } from '@terrafirmagreg-team/ui/hooks/use-async-value';
9
9
  import { clientDumpLoader } from '@terrafirmagreg-team/kit/lib/config';
10
10
  import {
11
- datasetRef,
12
11
  isDumpSection,
13
- parseDatasetRef,
14
12
  parseSectionLocation,
15
- } from '@terrafirmagreg-team/kit/lib/location';
16
- import {
17
- setVersionPreference,
18
- useVersionPreference,
19
- } from '@terrafirmagreg-team/kit/hooks/use-version-pref';
13
+ } from '@terrafirmagreg-team/sites/location';
14
+ import { setVersionPreference } from '@terrafirmagreg-team/kit/hooks/use-version-pref';
15
+ import { useVersionedDataset } from '@terrafirmagreg-team/kit/hooks/use-versioned-dataset';
20
16
  import { VersionMenu } from '@terrafirmagreg-team/kit/components/version-menu';
21
17
 
22
18
  export function NavTitle({ className, ...props }: ComponentProps<'a'>) {
23
19
  const { section, dataset } = parseSectionLocation(usePathname());
24
- const datasetId = dataset ? parseDatasetRef(dataset).id : undefined;
25
- const gameData = isDumpSection(section);
26
- const pref = useVersionPreference(datasetId);
20
+ const datasetId = dataset;
21
+
22
+ const gameData = isDumpSection(section) && datasetId;
23
+ const versions = useAsyncValue(
24
+ gameData ? () => clientDumpLoader().loadVersions(datasetId) : false,
25
+ [datasetId],
26
+ );
27
+ const ref = useVersionedDataset(
28
+ gameData ? datasetId : undefined,
29
+ versions ?? undefined,
30
+ );
27
31
  const version = useAsyncValue(
28
- dataset
32
+ ref
29
33
  ? () =>
30
34
  clientDumpLoader()
31
- .loadDump(dataset)
35
+ .loadDump(ref)
32
36
  .then((dump) => dump?.manifest.pack?.version ?? undefined)
33
37
  : false,
34
- [dataset],
35
- );
36
- const versions = useAsyncValue(
37
- datasetId ? () => clientDumpLoader().loadVersions(datasetId) : false,
38
- [datasetId],
38
+ [ref],
39
39
  );
40
40
  return (
41
41
  <SiteTitle
@@ -43,18 +43,14 @@ export function NavTitle({ className, ...props }: ComponentProps<'a'>) {
43
43
  icon={uiConfig().brand?.icon ?? ''}
44
44
  name={uiConfig().brand?.name ?? ''}
45
45
  subtitle={
46
- dataset && datasetId ? (
46
+ dataset && datasetId && gameData ? (
47
47
  <VersionMenu
48
48
  section={section}
49
49
  datasetId={datasetId}
50
- currentRef={gameData ? dataset : datasetRef(datasetId, pref)}
51
- label={gameData ? version : (pref ?? version)}
50
+ currentRef={ref ?? { id: datasetId }}
51
+ label={version}
52
52
  versions={versions}
53
- onSelect={
54
- gameData || !datasetId
55
- ? undefined
56
- : (next) => setVersionPreference(datasetId, next)
57
- }
53
+ onSelect={(next) => setVersionPreference(datasetId, next)}
58
54
  />
59
55
  ) : undefined
60
56
  }
@@ -63,3 +59,4 @@ export function NavTitle({ className, ...props }: ComponentProps<'a'>) {
63
59
  />
64
60
  );
65
61
  }
62
+
@@ -5,7 +5,7 @@ import { useTranslations } from '@terrafirmagreg-team/translate/hooks/use-transl
5
5
  import { ChevronDownIcon } from 'lucide-react';
6
6
  import { useState } from 'react';
7
7
  import { OutlineActiveHeading, OutlineList, OutlineProgress } from './list';
8
- import type { WorkspaceOutlineDropdownProps } from './types';
8
+ import type { WorkspaceOutlineDropdownProps } from '@terrafirmagreg-team/kit/types/outline';
9
9
 
10
10
  export function WorkspaceOutlineDropdown({
11
11
  trigger,
@@ -31,7 +31,7 @@ export function WorkspaceOutlineDropdown({
31
31
  >
32
32
  <OutlineProgress className="shrink-0" />
33
33
  <OutlineActiveHeading
34
- fallback={t('ui.on_this_page')}
34
+ fallback={t('On this page', { note: 'ui.on_this_page' })}
35
35
  activeClassName="text-foreground"
36
36
  />
37
37
  <ChevronDownIcon
@@ -65,3 +65,4 @@ export function WorkspaceOutlineDropdown({
65
65
  </Popover.Root>
66
66
  );
67
67
  }
68
+
@@ -4,7 +4,8 @@ export type {
4
4
  OutlineProps,
5
5
  WorkspaceOutlineDropdownProps,
6
6
  WorkspaceOutlinePopoverProps,
7
- } from './types';
7
+ } from '@terrafirmagreg-team/kit/types/outline';
8
8
  export { Outline, RightSidebarOutline } from './outline';
9
9
  export { WorkspaceOutlinePopover } from './popover';
10
10
  export { WorkspaceOutlineDropdown } from './dropdown';
11
+
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { type TOCItemInfo, useTOCSelector } from '@terrafirmagreg-team/kit/components/toc/base';
3
- import { useTOCItems } from '@terrafirmagreg-team/kit/hooks/toc';
3
+ import { useTOCItems } from '@terrafirmagreg-team/kit/hooks/use-toc';
4
4
  import * as Base from '@terrafirmagreg-team/kit/components/toc/base';
5
5
  import * as OutlineDefault from '@terrafirmagreg-team/kit/components/toc/default';
6
6
  import * as OutlineClerk from '@terrafirmagreg-team/kit/components/toc/clerk';
@@ -12,7 +12,7 @@ import {
12
12
  type ReactNode,
13
13
  useState,
14
14
  } from 'react';
15
- import type { OutlineStyle } from './types';
15
+ import type { OutlineStyle } from '@terrafirmagreg-team/kit/types/outline';
16
16
 
17
17
  const variants = {
18
18
  normal: OutlineDefault,
@@ -118,3 +118,4 @@ export function OutlineProgress({
118
118
  </svg>
119
119
  );
120
120
  }
121
+
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { useTOCItems } from '@terrafirmagreg-team/kit/hooks/toc';
2
+ import { useTOCItems } from '@terrafirmagreg-team/kit/hooks/use-toc';
3
3
  import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
4
4
  import { useTranslations } from '@terrafirmagreg-team/translate/hooks/use-translations';
5
5
  import { TextIcon } from 'lucide-react';
@@ -8,7 +8,7 @@ import {
8
8
  RightSidebarPortal,
9
9
  } from '@terrafirmagreg-team/ui/components/layouts/right-sidebar';
10
10
  import { OutlineList } from './list';
11
- import type { OutlineProps } from './types';
11
+ import type { OutlineProps } from '@terrafirmagreg-team/kit/types/outline';
12
12
 
13
13
  export function Outline({ container, header, footer, ...props }: OutlineProps) {
14
14
  const t = useTranslations();
@@ -24,7 +24,7 @@ export function Outline({ container, header, footer, ...props }: OutlineProps) {
24
24
  {header}
25
25
  <h3 className="inline-flex items-center gap-1.5 text-sm text-muted-foreground">
26
26
  <TextIcon className="size-4" />
27
- {t('ui.on_this_page')}
27
+ {t('On this page', { note: 'ui.on_this_page' })}
28
28
  </h3>
29
29
  <OutlineList {...props} />
30
30
  {footer}
@@ -47,3 +47,4 @@ export function RightSidebarOutline({ container, ...props }: OutlineProps) {
47
47
  </RightSidebarPortal>
48
48
  );
49
49
  }
50
+
@@ -10,7 +10,7 @@ import { ChevronDownIcon } from 'lucide-react';
10
10
  import { useEffect, useRef, useState } from 'react';
11
11
  import { useTreePath } from '@terrafirmagreg-team/ui/hooks/use-tree';
12
12
  import { OutlineActiveHeading, OutlineList, OutlineProgress } from './list';
13
- import type { WorkspaceOutlinePopoverProps } from './types';
13
+ import type { WorkspaceOutlinePopoverProps } from '@terrafirmagreg-team/kit/types/outline';
14
14
 
15
15
  export function WorkspaceOutlinePopover({
16
16
  container,
@@ -56,7 +56,7 @@ export function WorkspaceOutlinePopover({
56
56
  className={cn('shrink-0', open && 'text-primary')}
57
57
  />
58
58
  <OutlineActiveHeading
59
- fallback={page?.name ?? t('ui.on_this_page')}
59
+ fallback={page?.name ?? t('On this page', { note: 'ui.on_this_page' })}
60
60
  className={cn('flex-1 transition-colors', open && 'text-foreground')}
61
61
  />
62
62
  <ChevronDownIcon
@@ -74,3 +74,4 @@ export function WorkspaceOutlinePopover({
74
74
  </Collapsible>
75
75
  );
76
76
  }
77
+
@@ -17,13 +17,13 @@ import {
17
17
  PopoverContent,
18
18
  } from '@terrafirmagreg-team/ui/components/ui/popover';
19
19
  import { ItemRow } from '@terrafirmagreg-team/ui/components/blocks/list/row';
20
- import { useUntranslated } from '@terrafirmagreg-team/ui/hooks/lang';
20
+ import { useUntranslated } from '@terrafirmagreg-team/ui/hooks/use-lang';
21
21
  import { useTranslations } from '@terrafirmagreg-team/translate/hooks/use-translations';
22
22
  import { useCopyButton } from '@terrafirmagreg-team/ui/hooks/use-copy-button';
23
23
  import {
24
24
  openPageMarkdown,
25
25
  pageMarkdown,
26
- } from '@terrafirmagreg-team/kit/lib/markdown';
26
+ } from '@terrafirmagreg-team/mdx/lib/markdown';
27
27
  import type { TranslationState } from '@terrafirmagreg-team/translate/server';
28
28
 
29
29
  function ActionButton({
@@ -62,10 +62,10 @@ export function MarkdownCopyButton({
62
62
  {checked ? <Check /> : <Copy />}
63
63
  {props.children ??
64
64
  (error
65
- ? t('ui.copy_error')
65
+ ? t('Failed to copy', { note: 'ui.copy_error' })
66
66
  : checked
67
- ? t('ui.copied_markdown')
68
- : t('ui.copy_markdown'))}
67
+ ? t('Copied Markdown', { note: 'ui.copied_markdown' })
68
+ : t('Copy Markdown', { note: 'ui.copy_markdown' }))}
69
69
  </ActionButton>
70
70
  );
71
71
  }
@@ -88,7 +88,7 @@ export function CrowdinButton({ url }: { url: string }) {
88
88
  render={<a href={url} target="_blank" rel="noreferrer" />}
89
89
  >
90
90
  <Languages />
91
- {t('untranslated.translate')}
91
+ {t('Translate on Crowdin', { note: 'untranslated.translate' })}
92
92
  </ActionButton>
93
93
  );
94
94
  }
@@ -118,12 +118,12 @@ export function ViewOptionsPopover({
118
118
  const t = useTranslations();
119
119
  const items = [
120
120
  githubUrl && {
121
- title: t('ui.open_github'),
121
+ title: t('Open in GitHub', { note: 'ui.open_github' }),
122
122
  href: githubUrl,
123
123
  icon: <SiGithub color="currentColor" className="size-4" />,
124
124
  },
125
125
  (mdUrl || title !== undefined) && {
126
- title: t('ui.view_markdown'),
126
+ title: t('View as Markdown', { note: 'ui.view_markdown' }),
127
127
  ...(mdUrl
128
128
  ? { href: mdUrl }
129
129
  : {
@@ -156,7 +156,7 @@ export function ViewOptionsPopover({
156
156
  )
157
157
  }
158
158
  >
159
- {props.children ?? t('ui.open')}
159
+ {props.children ?? t('Open', { note: 'ui.open' })}
160
160
  <ChevronDown className="size-3.5 text-muted-foreground" />
161
161
  </PopoverTrigger>
162
162
  <PopoverContent className="flex flex-col">
@@ -199,3 +199,4 @@ export function PageActions({
199
199
  </>
200
200
  );
201
201
  }
202
+
@@ -16,3 +16,4 @@ export function createRelativeLink<C extends LoaderConfig>(
16
16
  );
17
17
  };
18
18
  }
19
+
@@ -5,7 +5,7 @@ import {
5
5
  type AnchorProviderProps,
6
6
  } from 'fumadocs-core/toc';
7
7
  import { useRef, type ComponentProps } from 'react';
8
- import { TOCContext } from '@terrafirmagreg-team/kit/hooks/toc';
8
+ import { TOCContext } from '@terrafirmagreg-team/kit/hooks/use-toc';
9
9
  import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
10
10
  import { mergeRefs } from '@terrafirmagreg-team/ui/lib/utils/merge-refs';
11
11
 
@@ -63,3 +63,4 @@ export function TOCScrollArea({
63
63
  </div>
64
64
  );
65
65
  }
66
+
@@ -109,3 +109,4 @@ export function TOCItem({
109
109
  </Primitive.TOCItem>
110
110
  );
111
111
  }
112
+
@@ -12,7 +12,7 @@ import {
12
12
  import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
13
13
  import { mergeRefs } from '@terrafirmagreg-team/ui/lib/utils/merge-refs';
14
14
  import * as Primitive from './base';
15
- import { useTOCItems } from '@terrafirmagreg-team/kit/hooks/toc';
15
+ import { useTOCItems } from '@terrafirmagreg-team/kit/hooks/use-toc';
16
16
  import { TOCEmpty } from './default';
17
17
 
18
18
  export { TOCEmpty };
@@ -263,3 +263,4 @@ export function TOCItem({
263
263
  </Primitive.TOCItem>
264
264
  );
265
265
  }
266
+
@@ -13,7 +13,7 @@ import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
13
13
  import { mergeRefs } from '@terrafirmagreg-team/ui/lib/utils/merge-refs';
14
14
  import { useTranslations } from '@terrafirmagreg-team/translate/hooks/use-translations';
15
15
  import * as Primitive from './base';
16
- import { useTOCItems } from '@terrafirmagreg-team/kit/hooks/toc';
16
+ import { useTOCItems } from '@terrafirmagreg-team/kit/hooks/use-toc';
17
17
 
18
18
  interface SvgResult {
19
19
  content: ReactNode;
@@ -144,7 +144,7 @@ export function TOCEmpty() {
144
144
  const t = useTranslations();
145
145
  return (
146
146
  <div className="rounded-lg border bg-card p-3 text-xs text-muted-foreground">
147
- {t('ui.no_headings')}
147
+ {t('No Headings', { note: 'ui.no_headings' })}
148
148
  </div>
149
149
  );
150
150
  }
@@ -331,3 +331,4 @@ export function TOCItem({
331
331
  </Primitive.TOCItem>
332
332
  );
333
333
  }
334
+
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { CheckIcon, ChevronDown } from 'lucide-react';
4
- import { useSearchParams } from 'next/navigation';
4
+ import { useLocationSearchParams } from '@terrafirmagreg-team/ui/hooks/page/use-location-search';
5
5
  import { useState } from 'react';
6
6
  import {
7
7
  DropdownMenu,
@@ -11,7 +11,7 @@ import {
11
11
  } from '@terrafirmagreg-team/ui/components/ui/dropdown-menu';
12
12
  import { useUiComponents } from '@terrafirmagreg-team/ui/provider';
13
13
  import { useTranslations } from '@terrafirmagreg-team/translate/hooks/use-translations';
14
- import { datasetRef, sectionUrl } from '@terrafirmagreg-team/kit/lib/location';
14
+ import { type DatasetRef, sectionUrl } from '@terrafirmagreg-team/sites/location';
15
15
 
16
16
  import type { SectionKey } from '@terrafirmagreg-team/kit/types';
17
17
 
@@ -26,7 +26,7 @@ export function VersionMenu({
26
26
  section?: SectionKey;
27
27
  datasetId: string;
28
28
 
29
- currentRef: string;
29
+ currentRef: DatasetRef;
30
30
 
31
31
  label?: string;
32
32
  versions: { versions: string[]; latest?: string } | null | undefined;
@@ -34,10 +34,7 @@ export function VersionMenu({
34
34
  onSelect?: (version: string | undefined) => void;
35
35
  }) {
36
36
  const [open, setOpen] = useState(false);
37
- const pinned =
38
- currentRef !== datasetId
39
- ? currentRef.slice(datasetId.length + 1)
40
- : undefined;
37
+ const pinned = currentRef.version;
41
38
  const shown = label ?? pinned;
42
39
  const text = shown ? `v${shown}` : datasetId;
43
40
  if (!versions || versions.versions.length < 2 || (!section && !onSelect)) {
@@ -52,7 +49,7 @@ export function VersionMenu({
52
49
  }
53
50
  return (
54
51
  <DropdownMenu open={open} onOpenChange={setOpen} modal={false}>
55
- <DropdownMenuTrigger className="inline-flex items-center gap-0.5 outline-none hover:text-foreground">
52
+ <DropdownMenuTrigger className="inline-flex items-center gap-0.5 rounded-sm outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring">
56
53
  {text}
57
54
  <ChevronDown className="size-3" />
58
55
  </DropdownMenuTrigger>
@@ -61,7 +58,6 @@ export function VersionMenu({
61
58
  align="start"
62
59
  className="max-h-36 min-w-32"
63
60
  >
64
- {}
65
61
  <VersionMenuItems
66
62
  ordered={ordered}
67
63
  latest={versions.latest}
@@ -86,27 +82,32 @@ function VersionMenuItems({
86
82
  ordered: string[];
87
83
  latest: string | undefined;
88
84
  datasetId: string;
89
- currentRef: string;
85
+ currentRef: DatasetRef;
90
86
  section?: SectionKey;
91
87
  onSelect?: (version: string | undefined) => void;
92
88
  }) {
93
89
  const { Link } = useUiComponents();
94
90
  const t = useTranslations();
95
91
 
96
- const search = useSearchParams().toString();
92
+ const current = useLocationSearchParams();
97
93
  return ordered.map((version) => {
98
94
  const isLatest = version === latest;
99
- const ref = isLatest ? datasetId : datasetRef(datasetId, version);
95
+ const selected = currentRef.id === datasetId &&
96
+ currentRef.version === (isLatest ? undefined : version);
97
+ const params = new URLSearchParams(current);
98
+ if (isLatest) params.delete('version');
99
+ else params.set('version', version);
100
+ const q = params.toString();
100
101
  return (
101
102
  <DropdownMenuItem
102
103
  key={version}
103
104
  closeOnClick
104
105
  render={
105
- onSelect ? undefined : (
106
+ section ? (
106
107
  <Link
107
- href={`${sectionUrl(section!, ref)}${search ? `?${search}` : ''}`}
108
+ href={`${sectionUrl(section, datasetId)}${q ? `?${q}` : ''}`}
108
109
  />
109
- )
110
+ ) : undefined
110
111
  }
111
112
  onClick={
112
113
  onSelect ? () => onSelect(isLatest ? undefined : version) : undefined
@@ -117,12 +118,13 @@ function VersionMenuItems({
117
118
  <span className="font-medium">v{version}</span>
118
119
  {isLatest && (
119
120
  <span className="text-2xs text-muted-foreground">
120
- {t('ui.version_latest')}
121
+ {t('latest', { note: 'ui.version_latest' })}
121
122
  </span>
122
123
  )}
123
124
  </span>
124
- {ref === currentRef && <CheckIcon className="size-3.5 text-primary" />}
125
+ {selected && <CheckIcon className="size-3.5 text-primary" />}
125
126
  </DropdownMenuItem>
126
127
  );
127
128
  });
128
129
  }
130
+
@@ -8,13 +8,15 @@ import {
8
8
  resolveDatasetLanding,
9
9
  } from '@terrafirmagreg-team/kit/lib/landing';
10
10
  import { sectionDatasets } from '@terrafirmagreg-team/kit/lib/datasets';
11
- import { sectionUrl } from '@terrafirmagreg-team/kit/lib/location';
11
+ import { sectionUrl } from '@terrafirmagreg-team/sites/location';
12
12
  import { canonicalUrl } from '@terrafirmagreg-team/kit/lib/urls';
13
13
  import type { DatasetLanding, SectionKey } from '@terrafirmagreg-team/kit/types';
14
+ import { localeLoader } from '@terrafirmagreg-team/kit/lib/locale/renderer';
14
15
  import { langContent } from '@terrafirmagreg-team/translate/server';
15
16
 
16
17
  interface DatasetPageParams {
17
18
  params: Promise<{ slug?: string[] }>;
19
+ searchParams: Promise<Record<string, string | string[] | undefined>>;
18
20
  }
19
21
 
20
22
  export function createDatasetLandingPage<S extends SectionKey>(
@@ -30,7 +32,13 @@ export function createDatasetLandingPage<S extends SectionKey>(
30
32
  render,
31
33
  );
32
34
  if (!content) notFound();
33
- return <LangContentSwitch content={content} />;
35
+ return (
36
+ <LangContentSwitch
37
+ key={[section, ...(slug ?? [])].join('/')}
38
+ content={content}
39
+ loadLang={localeLoader()?.bind(null, { section, slug })}
40
+ />
41
+ );
34
42
  }
35
43
 
36
44
  function generateStaticParams() {
@@ -61,3 +69,4 @@ export function createDatasetLandingPage<S extends SectionKey>(
61
69
 
62
70
  return { Page, generateStaticParams, generateMetadata };
63
71
  }
72
+