@tuwaio/docs-ui 0.5.7 → 0.6.0

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 (42) hide show
  1. package/README.md +91 -3
  2. package/bin/i18n-check.js +19 -0
  3. package/dist/components/DocsLayout.cjs +82 -0
  4. package/dist/components/DocsLayout.d.cts +50 -0
  5. package/dist/components/DocsLayout.d.ts +50 -0
  6. package/dist/components/DocsLayout.js +58 -0
  7. package/dist/components/LocalizedPage.cjs +42 -0
  8. package/dist/components/LocalizedPage.d.cts +37 -0
  9. package/dist/components/LocalizedPage.d.ts +37 -0
  10. package/dist/components/LocalizedPage.js +18 -0
  11. package/dist/docsI18n.cjs +33 -0
  12. package/dist/docsI18n.d.cts +16 -0
  13. package/dist/docsI18n.d.ts +16 -0
  14. package/dist/docsI18n.js +8 -0
  15. package/dist/docsLabels.cjs +140 -0
  16. package/dist/docsLabels.d.cts +72 -0
  17. package/dist/docsLabels.d.ts +72 -0
  18. package/dist/docsLabels.js +116 -0
  19. package/dist/docsPage.cjs +70 -0
  20. package/dist/docsPage.d.cts +56 -0
  21. package/dist/docsPage.d.ts +56 -0
  22. package/dist/docsPage.js +46 -0
  23. package/dist/i18n.d.cts +1 -1
  24. package/dist/i18n.d.ts +1 -1
  25. package/dist/index.cjs +4 -0
  26. package/dist/index.css +3 -0
  27. package/dist/index.d.cts +3 -0
  28. package/dist/index.d.ts +3 -0
  29. package/dist/index.js +2 -0
  30. package/dist/nextra.cjs +26 -0
  31. package/dist/nextra.d.cts +10 -0
  32. package/dist/nextra.d.ts +10 -0
  33. package/dist/nextra.js +3 -0
  34. package/dist/pageMap.cjs +55 -0
  35. package/dist/pageMap.d.cts +20 -0
  36. package/dist/pageMap.d.ts +20 -0
  37. package/dist/pageMap.js +31 -0
  38. package/dist/translationCheck.cjs +186 -0
  39. package/dist/translationCheck.d.cts +89 -0
  40. package/dist/translationCheck.d.ts +89 -0
  41. package/dist/translationCheck.js +157 -0
  42. package/package.json +15 -3
package/README.md CHANGED
@@ -13,6 +13,7 @@
13
13
  - **Logo:** `RemoteLogo` is an async React Server Component that fetches an SVG (by default the TUWA logo) and renders it as React elements, so it takes `className` and `currentColor`.
14
14
  - **Theme switch:** `ThemeSwitcher` is a light/dark switch for any theme state (for example `next-themes`).
15
15
  - **Language select:** `LocaleSwitcher` is an accessible glassmorphic select dropdown for switching languages (English, Українська, 简体中文, etc.), styled to match `ThemeSwitcher`. Features zero layout shift, Nova UI Kit animated directional chevron, collision detection with auto-flip (`placement="auto"`), multi-layout Latin typeahead navigation (independent of user OS keyboard language), and an invisible native `<select>` overlay on touch devices (`pointer: coarse`) for native mobile system pickers (iOS wheel, Android sheet). Full WCAG 2.1/2.2 AA/AAA compliance. It renders an invisible placeholder during SSR to avoid hydration shifts.
16
+ - **Three languages (project sites):** `@tuwaio/docs-ui/nextra` and `@tuwaio/docs-ui/nextra/page` turn a Nextra site into an English, Ukrainian and Simplified Chinese site with one URL per page, as on the [docs hub](https://docs.tuwa.io). `DocsLayout` is the Nextra layout with the navbar (the language switch after the links; the theme switch stays in the Nextra sidebar and the mobile menu), the footer, the search, the table of contents, the edit, feedback and last-updated texts and the sidebar titles in the language of the reader (`docsLabels`, `localizePageMap`). `createDocsPage` creates the `[[...mdxPath]]` route: each page is prerendered in English and in the languages it is translated into, and `LocalizedPage` shows the reader's language without a request; pages without a translation (package READMEs, the generated API reference) show English with a note in the reader's language. The language is detected after mount (`tuwa-locale`, then the browser languages and the time zone; no cookie, no request). The `tuwa-docs-i18n-check` command keeps the translations in line with their English pages.
16
17
  - **Interface settings for 30 days:** `PreferenceExpiry` is an inline script for the `<head>` of a site's root layout. It forgets the Local Storage values of the given keys (by default `theme`) 30 days after they were written, as the [Cookie Policy](https://tuwa.io/cookie) states, and dates each later write, whatever library writes it (`next-themes`, the `Tabs` of Nextra).
17
18
  - **Decoration:** `Orb` (an animated sphere in the brand color of a TUWA project), `StarryBackground` (an animated star field on a canvas) and `NoSSR` (renders its children only on the client).
18
19
  - **Policy pages:** `policies` lists the TUWA policies (Terms, Privacy, Cookie, Refund, Security, Data Processing Addendum) with their paths and whether they are in force (`publishedPolicies`; footers use `footerPolicies`). `loadPolicy` loads the text of a policy in a language, and `PolicyDocument` renders it with the date of the version, a Download PDF button, a language switch (English, Українська) when the policy is translated, anchored sections (the same anchors in every language) and a list of sections. The texts and PDFs come from [`TuwaIO/workflows/docs`](https://github.com/TuwaIO/workflows/tree/main/docs). Code that needs only the list or `loadPolicy` (footers, sitemaps, route handlers) imports them from `@tuwaio/docs-ui/policies`, which has no React, Next.js or Nextra imports.
@@ -27,7 +28,7 @@
27
28
  pnpm add @tuwaio/docs-ui next nextra nextra-theme-docs react react-dom @heroicons/react
28
29
  ```
29
30
 
30
- `nextra-theme-docs` (and its peer `nextra`) is needed by `Navbar` and `Footer`, `next` by `RemoteLogo` (a Server Component that uses the `fetch` cache of Next.js) and `@heroicons/react` by `ThemeSwitcher`.
31
+ `nextra-theme-docs` is needed by `Navbar`, `Footer` and `DocsLayout`, `nextra` by `DocsLayout`, `LocalizedPage` and `createDocsPage`, `next` by `RemoteLogo` (a Server Component that uses the `fetch` cache of Next.js) and `createDocsPage`, and `@heroicons/react` by `ThemeSwitcher`.
31
32
 
32
33
  Import the stylesheet after the Nextra theme:
33
34
 
@@ -122,6 +123,93 @@ export function PolicyLinks() {
122
123
 
123
124
  Sections have stable anchors (`/refund#how-to-request-a-refund`), so hints and FAQ answers can link to a section.
124
125
 
126
+ ### Languages of a project site
127
+
128
+ A TUWA project site (Orbit, SIWX, Satellite Connect, Pulsar, SDK) in English, Ukrainian and Simplified Chinese. The root layout renders `DocsLayout` around the page and keeps the language for 30 days:
129
+
130
+ ```tsx
131
+ import { PreferenceExpiry, SiteLogo } from '@tuwaio/docs-ui';
132
+ import { DocsLayout } from '@tuwaio/docs-ui/nextra';
133
+ import { Head } from 'nextra/components';
134
+ import { getPageMap } from 'nextra/page-map';
135
+ import type { ReactNode } from 'react';
136
+
137
+ const logo = <SiteLogo width={126} height={40} />;
138
+
139
+ export default async function RootLayout({ children }: { children: ReactNode }) {
140
+ return (
141
+ <html lang="en" dir="ltr" suppressHydrationWarning>
142
+ <Head>
143
+ <PreferenceExpiry keys={['theme', 'tuwa-locale']} />
144
+ </Head>
145
+ <body>
146
+ <DocsLayout
147
+ logo={logo}
148
+ pageMap={await getPageMap()}
149
+ docsRepositoryBase="https://github.com/TuwaIO/pulsar-core/tree/main/apps/docs"
150
+ sidebarTitles={{ uk: { 'EVM Trackers Standalone': 'EVM-трекери окремо' } }}
151
+ >
152
+ {children}
153
+ </DocsLayout>
154
+ </body>
155
+ </html>
156
+ );
157
+ }
158
+ ```
159
+
160
+ `src/app/[[...mdxPath]]/page.tsx` renders every page of `src/content` with its translations:
161
+
162
+ ```tsx
163
+ import { createDocsPage } from '@tuwaio/docs-ui/nextra/page';
164
+
165
+ import { localizedPages } from '@/i18n/pages';
166
+
167
+ const { generateStaticParams, generateMetadata, Page } = createDocsPage({ localizedPages });
168
+
169
+ export { generateMetadata, generateStaticParams };
170
+ export default Page;
171
+ ```
172
+
173
+ The translations are MDX files with the path of their English page under `src/i18n/<language>` (`src/i18n/uk/index.mdx` translates `src/content/index.mdx`), listed by route in `src/i18n/pages.ts`:
174
+
175
+ ```ts
176
+ import type { LocalizedPageLoaders } from '@tuwaio/docs-ui/nextra/page';
177
+
178
+ export const localizedPages: Record<string, LocalizedPageLoaders> = {
179
+ '/': {
180
+ uk: () => import('./uk/index.mdx'),
181
+ 'zh-CN': () => import('./zh-CN/index.mdx'),
182
+ },
183
+ };
184
+ ```
185
+
186
+ TypeScript types the imported MDX files with a declaration next to it (`src/i18n/mdx.d.ts`):
187
+
188
+ ```ts
189
+ declare module '*.mdx' {
190
+ import type { EvaluateResult } from 'nextra';
191
+
192
+ const MDXContent: EvaluateResult['default'];
193
+ export default MDXContent;
194
+ export const toc: EvaluateResult['toc'];
195
+ export const metadata: EvaluateResult['metadata'];
196
+ export const sourceCode: EvaluateResult['sourceCode'];
197
+ }
198
+ ```
199
+
200
+ A translation keeps the structure of its English page: the same code blocks in the same order, the same heading levels with the English heading ids written as `## Встановлення [#-installation]` (so anchors work in every language) and the same links. `tuwa-docs-i18n-check`, run from the docs app, checks it and that every translated page exists in every language; add it to the build and to the pre-commit hook:
201
+
202
+ ```json
203
+ {
204
+ "scripts": {
205
+ "build": "tuwa-docs-i18n-check && next build && pnpm postbuild",
206
+ "i18n:check": "tuwa-docs-i18n-check"
207
+ }
208
+ }
209
+ ```
210
+
211
+ Client components inside `DocsLayout` read the language and the interface texts with `useDocsI18n()`.
212
+
125
213
  ### Search index
126
214
 
127
215
  Run the command after `next build`. It uses the `pagefind` package of the site, so add it to the site's dependencies:
@@ -144,11 +232,11 @@ It writes the index to `public/_pagefind` (keep that directory in `.gitignore`)
144
232
 
145
233
  ## 🗄️ Browser Storage
146
234
 
147
- `LocaleSwitcher` and `ThemeSwitcher` store nothing; they only call `onSelect` / `onToggle`, and the site keeps the choice. `PreferenceExpiry` stores `<key>:expires` (the time in epoch milliseconds) next to each key it is given, removes both once that time has passed, and wraps `Storage.prototype.setItem` on the page to date later writes of those keys.
235
+ `LocaleSwitcher` and `ThemeSwitcher` store nothing; they only call `onSelect` / `onToggle`, and the site keeps the choice. `DocsLayout`, `useLocaleState` and the providers of `createI18n` save the language the reader picks to `tuwa-locale` (`en`, `uk` or `zh-CN`) and read it on the next visit; list the key in `PreferenceExpiry` to forget it after 30 days. `PreferenceExpiry` stores `<key>:expires` (the time in epoch milliseconds) next to each key it is given, removes both once that time has passed, and wraps `Storage.prototype.setItem` on the page to date later writes of those keys.
148
236
 
149
237
  ## 🌐 External Services
150
238
 
151
- `RemoteLogo` requests its `url` on the server (by default `tuwa.io/brand/logo_v2.svg`), cached by Next.js for 24 hours. `loadPolicy` requests `raw.githubusercontent.com/TuwaIO/workflows/main/docs/<slug>.json` (a translation: `docs/<language>/<slug>.json`, and the English file when it does not exist) on the server, cached by Next.js for an hour by default. The Download PDF button of `PolicyDocument` links to the PDF on the same host; the browser requests it only when it is clicked. The other components send no requests.
239
+ `RemoteLogo` requests its `url` on the server (by default `tuwa.io/brand/logo_v2.svg`), cached by Next.js for 24 hours. `loadPolicy` requests `raw.githubusercontent.com/TuwaIO/workflows/main/docs/<slug>.json` (a translation: `docs/<language>/<slug>.json`, and the English file when it does not exist) on the server, cached by Next.js for an hour by default. The Download PDF button of `PolicyDocument` links to the PDF on the same host; the browser requests it only when it is clicked. `createDocsPage` and `LocalizedPage` send no requests: the translations are part of the page. The other components send no requests.
152
240
 
153
241
  ---
154
242
 
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ // `tuwa-docs-i18n-check`: checks the translated pages of a TUWA documentation site (src/i18n/<locale>) against their
3
+ // English pages (src/content), run from the docs app (see README)
4
+ import { checkSiteTranslations } from '../dist/translationCheck.js';
5
+
6
+ checkSiteTranslations().then(
7
+ ({ files, issues }) => {
8
+ for (const { file, message } of issues) console.error(`${file}: ${message}`);
9
+ if (issues.length > 0) {
10
+ console.error(`Translations: ${issues.length} problem(s) in ${files} translated page(s)`);
11
+ process.exit(1);
12
+ }
13
+ console.log(`Translations: ${files} translated page(s) match their English pages`);
14
+ },
15
+ (error) => {
16
+ console.error(error instanceof Error ? error.message : error);
17
+ process.exit(1);
18
+ },
19
+ );
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var DocsLayout_exports = {};
21
+ __export(DocsLayout_exports, {
22
+ DocsLayout: () => DocsLayout
23
+ });
24
+ module.exports = __toCommonJS(DocsLayout_exports);
25
+ var import_jsx_runtime = require("react/jsx-runtime");
26
+ var import_components = require("nextra/components");
27
+ var import_nextra_theme_docs = require("nextra-theme-docs");
28
+ var import_react = require("react");
29
+ var import_docsI18n = require("../docsI18n");
30
+ var import_locale = require("../locale");
31
+ var import_pageMap = require("../pageMap");
32
+ var import_Footer = require("./Footer");
33
+ var import_LocaleSwitcher = require("./LocaleSwitcher");
34
+ var import_NavBar = require("./NavBar");
35
+ function LocalizedLayout({
36
+ logo,
37
+ links,
38
+ footerLinks,
39
+ pageMap,
40
+ docsRepositoryBase,
41
+ sidebarTitles,
42
+ children
43
+ }) {
44
+ const { locale, setLocale, t } = (0, import_docsI18n.useDocsI18n)();
45
+ const siteTitles = locale === "en" ? void 0 : sidebarTitles?.[locale];
46
+ const localizedPageMap = (0, import_react.useMemo)(
47
+ () => (0, import_pageMap.localizePageMap)(pageMap, { ...t.sidebar, ...siteTitles }),
48
+ [pageMap, t.sidebar, siteTitles]
49
+ );
50
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
51
+ import_nextra_theme_docs.Layout,
52
+ {
53
+ navbar: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_NavBar.Navbar, { logo, links, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_LocaleSwitcher.LocaleSwitcher, { locale, onSelect: setLocale, ariaLabel: t.selectLanguage }) }),
54
+ footer: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_Footer.Footer, { logo, links: footerLinks, labels: t.footer, policyLanguage: (0, import_locale.policyLanguageOf)(locale) }),
55
+ pageMap: localizedPageMap,
56
+ docsRepositoryBase,
57
+ navigation: { prev: true, next: true },
58
+ editLink: t.nextra.editThisPage,
59
+ feedback: { content: t.nextra.feedback },
60
+ lastUpdated: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_nextra_theme_docs.LastUpdated, { locale, children: t.nextra.lastUpdated }),
61
+ toc: { title: t.nextra.onThisPage, backToTop: t.nextra.scrollToTop },
62
+ themeSwitch: { light: t.nextra.themeLight, dark: t.nextra.themeDark, system: t.nextra.themeSystem },
63
+ search: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
64
+ import_components.Search,
65
+ {
66
+ placeholder: t.nextra.searchPlaceholder,
67
+ emptyResult: t.nextra.searchEmpty,
68
+ errorText: t.nextra.searchError,
69
+ loading: t.nextra.searchLoading
70
+ }
71
+ ),
72
+ children
73
+ }
74
+ );
75
+ }
76
+ function DocsLayout({ initialLocale, ...props }) {
77
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_docsI18n.DocsI18nProvider, { initialLocale, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocalizedLayout, { ...props }) });
78
+ }
79
+ // Annotate the CommonJS export names for ESM import in node:
80
+ 0 && (module.exports = {
81
+ DocsLayout
82
+ });
@@ -0,0 +1,50 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { PageMapItem } from 'nextra';
4
+ import { TuwaLocale } from '../locale.cjs';
5
+ import { SocialLink } from './NavBar.cjs';
6
+
7
+ /**
8
+ * Props of {@link DocsLayout}.
9
+ */
10
+ interface DocsLayoutProps {
11
+ /** Logo of the site, for example `SiteLogo`; rendered in the navbar and the footer. */
12
+ logo: ReactNode;
13
+ /** External links of the navbar (default: `baseNavLinks`). */
14
+ links?: SocialLink[];
15
+ /** External links of the footer (default: `baseFooterLinks`). */
16
+ footerLinks?: SocialLink[];
17
+ /** The page map of the site, the result of `getPageMap()` of `nextra/page-map`. */
18
+ pageMap: PageMapItem[];
19
+ /** URL of the docs app in the repository, for the edit links (`https://github.com/TuwaIO/<repo>/tree/main/apps/docs`). */
20
+ docsRepositoryBase: string;
21
+ /**
22
+ * Sidebar titles of the site's own pages, by language and English title (for example `{ uk: { 'EVM Trackers
23
+ * Standalone': '…' } }`). `Introduction`, `Packages`, `Guides` and `Overview` are translated already.
24
+ */
25
+ sidebarTitles?: Partial<Record<Exclude<TuwaLocale, 'en'>, Record<string, string>>>;
26
+ /** Fixed language (tests, previews): detection and the stored choice are skipped. */
27
+ initialLocale?: TuwaLocale;
28
+ /** The page and anything rendered next to it, such as a top loading bar. */
29
+ children: ReactNode;
30
+ }
31
+ /**
32
+ * The layout of a TUWA project documentation site in three languages (English, Ukrainian, Simplified Chinese): the
33
+ * Nextra `Layout` with the docs-ui {@link Navbar} (the language switch after the links; the theme switch stays in the
34
+ * Nextra sidebar and the mobile menu), the {@link Footer}, the search, the table of contents, the edit, feedback and
35
+ * last-updated texts and the sidebar titles in the language of the reader. Render it in the `<body>` of the root
36
+ * layout, around the page; pages rendered with `createDocsPage` (`@tuwaio/docs-ui/nextra/page`) switch to their
37
+ * translation.
38
+ *
39
+ * The URL never changes with the language. The server renders English; after mount the language is read from
40
+ * `tuwa-locale` in Local Storage, then the browser languages and the time zone (no cookie, no request), and a pick in
41
+ * the switch is saved to `tuwa-locale` (add the key to `PreferenceExpiry`, so it is forgotten after 30 days) and sets
42
+ * `<html lang>`.
43
+ *
44
+ * @param props - See {@link DocsLayoutProps}.
45
+ * @returns The layout.
46
+ */
47
+ declare function DocsLayout({ initialLocale, ...props }: DocsLayoutProps): react.JSX.Element;
48
+
49
+ export { DocsLayout };
50
+ export type { DocsLayoutProps };
@@ -0,0 +1,50 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { PageMapItem } from 'nextra';
4
+ import { TuwaLocale } from '../locale.js';
5
+ import { SocialLink } from './NavBar.js';
6
+
7
+ /**
8
+ * Props of {@link DocsLayout}.
9
+ */
10
+ interface DocsLayoutProps {
11
+ /** Logo of the site, for example `SiteLogo`; rendered in the navbar and the footer. */
12
+ logo: ReactNode;
13
+ /** External links of the navbar (default: `baseNavLinks`). */
14
+ links?: SocialLink[];
15
+ /** External links of the footer (default: `baseFooterLinks`). */
16
+ footerLinks?: SocialLink[];
17
+ /** The page map of the site, the result of `getPageMap()` of `nextra/page-map`. */
18
+ pageMap: PageMapItem[];
19
+ /** URL of the docs app in the repository, for the edit links (`https://github.com/TuwaIO/<repo>/tree/main/apps/docs`). */
20
+ docsRepositoryBase: string;
21
+ /**
22
+ * Sidebar titles of the site's own pages, by language and English title (for example `{ uk: { 'EVM Trackers
23
+ * Standalone': '…' } }`). `Introduction`, `Packages`, `Guides` and `Overview` are translated already.
24
+ */
25
+ sidebarTitles?: Partial<Record<Exclude<TuwaLocale, 'en'>, Record<string, string>>>;
26
+ /** Fixed language (tests, previews): detection and the stored choice are skipped. */
27
+ initialLocale?: TuwaLocale;
28
+ /** The page and anything rendered next to it, such as a top loading bar. */
29
+ children: ReactNode;
30
+ }
31
+ /**
32
+ * The layout of a TUWA project documentation site in three languages (English, Ukrainian, Simplified Chinese): the
33
+ * Nextra `Layout` with the docs-ui {@link Navbar} (the language switch after the links; the theme switch stays in the
34
+ * Nextra sidebar and the mobile menu), the {@link Footer}, the search, the table of contents, the edit, feedback and
35
+ * last-updated texts and the sidebar titles in the language of the reader. Render it in the `<body>` of the root
36
+ * layout, around the page; pages rendered with `createDocsPage` (`@tuwaio/docs-ui/nextra/page`) switch to their
37
+ * translation.
38
+ *
39
+ * The URL never changes with the language. The server renders English; after mount the language is read from
40
+ * `tuwa-locale` in Local Storage, then the browser languages and the time zone (no cookie, no request), and a pick in
41
+ * the switch is saved to `tuwa-locale` (add the key to `PreferenceExpiry`, so it is forgotten after 30 days) and sets
42
+ * `<html lang>`.
43
+ *
44
+ * @param props - See {@link DocsLayoutProps}.
45
+ * @returns The layout.
46
+ */
47
+ declare function DocsLayout({ initialLocale, ...props }: DocsLayoutProps): react.JSX.Element;
48
+
49
+ export { DocsLayout };
50
+ export type { DocsLayoutProps };
@@ -0,0 +1,58 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Search } from "nextra/components";
4
+ import { LastUpdated, Layout } from "nextra-theme-docs";
5
+ import { useMemo } from "react";
6
+ import { DocsI18nProvider, useDocsI18n } from "../docsI18n";
7
+ import { policyLanguageOf } from "../locale";
8
+ import { localizePageMap } from "../pageMap";
9
+ import { Footer } from "./Footer";
10
+ import { LocaleSwitcher } from "./LocaleSwitcher";
11
+ import { Navbar } from "./NavBar";
12
+ function LocalizedLayout({
13
+ logo,
14
+ links,
15
+ footerLinks,
16
+ pageMap,
17
+ docsRepositoryBase,
18
+ sidebarTitles,
19
+ children
20
+ }) {
21
+ const { locale, setLocale, t } = useDocsI18n();
22
+ const siteTitles = locale === "en" ? void 0 : sidebarTitles?.[locale];
23
+ const localizedPageMap = useMemo(
24
+ () => localizePageMap(pageMap, { ...t.sidebar, ...siteTitles }),
25
+ [pageMap, t.sidebar, siteTitles]
26
+ );
27
+ return /* @__PURE__ */ jsx(
28
+ Layout,
29
+ {
30
+ navbar: /* @__PURE__ */ jsx(Navbar, { logo, links, children: /* @__PURE__ */ jsx(LocaleSwitcher, { locale, onSelect: setLocale, ariaLabel: t.selectLanguage }) }),
31
+ footer: /* @__PURE__ */ jsx(Footer, { logo, links: footerLinks, labels: t.footer, policyLanguage: policyLanguageOf(locale) }),
32
+ pageMap: localizedPageMap,
33
+ docsRepositoryBase,
34
+ navigation: { prev: true, next: true },
35
+ editLink: t.nextra.editThisPage,
36
+ feedback: { content: t.nextra.feedback },
37
+ lastUpdated: /* @__PURE__ */ jsx(LastUpdated, { locale, children: t.nextra.lastUpdated }),
38
+ toc: { title: t.nextra.onThisPage, backToTop: t.nextra.scrollToTop },
39
+ themeSwitch: { light: t.nextra.themeLight, dark: t.nextra.themeDark, system: t.nextra.themeSystem },
40
+ search: /* @__PURE__ */ jsx(
41
+ Search,
42
+ {
43
+ placeholder: t.nextra.searchPlaceholder,
44
+ emptyResult: t.nextra.searchEmpty,
45
+ errorText: t.nextra.searchError,
46
+ loading: t.nextra.searchLoading
47
+ }
48
+ ),
49
+ children
50
+ }
51
+ );
52
+ }
53
+ function DocsLayout({ initialLocale, ...props }) {
54
+ return /* @__PURE__ */ jsx(DocsI18nProvider, { initialLocale, children: /* @__PURE__ */ jsx(LocalizedLayout, { ...props }) });
55
+ }
56
+ export {
57
+ DocsLayout
58
+ };
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var LocalizedPage_exports = {};
21
+ __export(LocalizedPage_exports, {
22
+ LocalizedPage: () => LocalizedPage
23
+ });
24
+ module.exports = __toCommonJS(LocalizedPage_exports);
25
+ var import_jsx_runtime = require("react/jsx-runtime");
26
+ var import_components = require("nextra/components");
27
+ var import_nextra_theme_docs = require("nextra-theme-docs");
28
+ var import_docsI18n = require("../docsI18n");
29
+ function LocalizedPage({ variants }) {
30
+ const { locale, t } = (0, import_docsI18n.useDocsI18n)();
31
+ const Wrapper = (0, import_nextra_theme_docs.useMDXComponents)().wrapper;
32
+ const translated = variants[locale];
33
+ const page = translated ?? variants.en;
34
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrapper, { toc: page.toc, metadata: page.metadata, sourceCode: page.sourceCode, children: [
35
+ !translated && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "tuwadocs:clear-both", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Callout, { type: "info", children: t.englishOnly }) }),
36
+ page.content
37
+ ] });
38
+ }
39
+ // Annotate the CommonJS export names for ESM import in node:
40
+ 0 && (module.exports = {
41
+ LocalizedPage
42
+ });
@@ -0,0 +1,37 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { Heading, $NextraMetadata } from 'nextra';
4
+ import { TuwaLocale } from '../locale.cjs';
5
+
6
+ /** One language of a page: the rendered MDX and what the Nextra page wrapper needs. */
7
+ interface LocalizedPageVariant {
8
+ /** The rendered MDX content. */
9
+ content: ReactNode;
10
+ /** The table of contents of the MDX file (its `toc` export). */
11
+ toc: Heading[];
12
+ /** The metadata of the MDX file (its `metadata` export): the title, the file of the edit link, the last change. */
13
+ metadata: $NextraMetadata;
14
+ /** The source of the MDX file (its `sourceCode` export), for the copy-page button. */
15
+ sourceCode?: string;
16
+ }
17
+ /** Props of {@link LocalizedPage}. */
18
+ interface LocalizedPageProps {
19
+ /** The page in English (the server renders it) and in the languages it is translated into. */
20
+ variants: Partial<Record<TuwaLocale, LocalizedPageVariant>> & {
21
+ en: LocalizedPageVariant;
22
+ };
23
+ }
24
+ /**
25
+ * A page of a TUWA documentation site in the language of the reader, inside the Nextra page wrapper (sidebar, table of
26
+ * contents, breadcrumbs, pagination). All variants come prerendered from the server, so switching the language makes no
27
+ * request and the URL stays the same; the server HTML and the search index hold English. A page without a translation
28
+ * in the active language (package READMEs and the generated API reference) shows English with a short note in that
29
+ * language. Must be rendered inside {@link DocsLayout}; `createDocsPage` (`@tuwaio/docs-ui/nextra/page`) renders it.
30
+ *
31
+ * @param props - See {@link LocalizedPageProps}.
32
+ * @returns The page.
33
+ */
34
+ declare function LocalizedPage({ variants }: LocalizedPageProps): react.JSX.Element;
35
+
36
+ export { LocalizedPage };
37
+ export type { LocalizedPageProps, LocalizedPageVariant };
@@ -0,0 +1,37 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { Heading, $NextraMetadata } from 'nextra';
4
+ import { TuwaLocale } from '../locale.js';
5
+
6
+ /** One language of a page: the rendered MDX and what the Nextra page wrapper needs. */
7
+ interface LocalizedPageVariant {
8
+ /** The rendered MDX content. */
9
+ content: ReactNode;
10
+ /** The table of contents of the MDX file (its `toc` export). */
11
+ toc: Heading[];
12
+ /** The metadata of the MDX file (its `metadata` export): the title, the file of the edit link, the last change. */
13
+ metadata: $NextraMetadata;
14
+ /** The source of the MDX file (its `sourceCode` export), for the copy-page button. */
15
+ sourceCode?: string;
16
+ }
17
+ /** Props of {@link LocalizedPage}. */
18
+ interface LocalizedPageProps {
19
+ /** The page in English (the server renders it) and in the languages it is translated into. */
20
+ variants: Partial<Record<TuwaLocale, LocalizedPageVariant>> & {
21
+ en: LocalizedPageVariant;
22
+ };
23
+ }
24
+ /**
25
+ * A page of a TUWA documentation site in the language of the reader, inside the Nextra page wrapper (sidebar, table of
26
+ * contents, breadcrumbs, pagination). All variants come prerendered from the server, so switching the language makes no
27
+ * request and the URL stays the same; the server HTML and the search index hold English. A page without a translation
28
+ * in the active language (package READMEs and the generated API reference) shows English with a short note in that
29
+ * language. Must be rendered inside {@link DocsLayout}; `createDocsPage` (`@tuwaio/docs-ui/nextra/page`) renders it.
30
+ *
31
+ * @param props - See {@link LocalizedPageProps}.
32
+ * @returns The page.
33
+ */
34
+ declare function LocalizedPage({ variants }: LocalizedPageProps): react.JSX.Element;
35
+
36
+ export { LocalizedPage };
37
+ export type { LocalizedPageProps, LocalizedPageVariant };
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Callout } from "nextra/components";
4
+ import { useMDXComponents } from "nextra-theme-docs";
5
+ import { useDocsI18n } from "../docsI18n";
6
+ function LocalizedPage({ variants }) {
7
+ const { locale, t } = useDocsI18n();
8
+ const Wrapper = useMDXComponents().wrapper;
9
+ const translated = variants[locale];
10
+ const page = translated ?? variants.en;
11
+ return /* @__PURE__ */ jsxs(Wrapper, { toc: page.toc, metadata: page.metadata, sourceCode: page.sourceCode, children: [
12
+ !translated && /* @__PURE__ */ jsx("div", { className: "tuwadocs:clear-both", children: /* @__PURE__ */ jsx(Callout, { type: "info", children: t.englishOnly }) }),
13
+ page.content
14
+ ] });
15
+ }
16
+ export {
17
+ LocalizedPage
18
+ };
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var docsI18n_exports = {};
21
+ __export(docsI18n_exports, {
22
+ DocsI18nProvider: () => DocsI18nProvider,
23
+ useDocsI18n: () => useDocsI18n
24
+ });
25
+ module.exports = __toCommonJS(docsI18n_exports);
26
+ var import_docsLabels = require("./docsLabels");
27
+ var import_i18n = require("./i18n");
28
+ const { I18nProvider: DocsI18nProvider, useI18n: useDocsI18n } = (0, import_i18n.createI18n)(import_docsLabels.docsLabels);
29
+ // Annotate the CommonJS export names for ESM import in node:
30
+ 0 && (module.exports = {
31
+ DocsI18nProvider,
32
+ useDocsI18n
33
+ });
@@ -0,0 +1,16 @@
1
+ import { DocsLabels } from './docsLabels.cjs';
2
+ import * as react from 'react';
3
+ import { I18nProviderProps, I18nContextValue } from './i18n.cjs';
4
+ import './locale.cjs';
5
+ import './policies.cjs';
6
+
7
+ /**
8
+ * The i18n kit of the TUWA documentation sites, on {@link docsLabels}: `DocsI18nProvider` provides the language of the
9
+ * reader and the interface texts, `useDocsI18n` reads them (outside the provider: English and a no-op setter).
10
+ * `DocsLayout` renders the provider, so a site's client components inside the layout call `useDocsI18n` directly.
11
+ * The language is detected after mount and kept under `tuwa-locale` in Local Storage (list it in `PreferenceExpiry`).
12
+ */
13
+ declare const DocsI18nProvider: react.ComponentType<I18nProviderProps>;
14
+ declare const useDocsI18n: () => I18nContextValue<DocsLabels>;
15
+
16
+ export { DocsI18nProvider, useDocsI18n };
@@ -0,0 +1,16 @@
1
+ import { DocsLabels } from './docsLabels.js';
2
+ import * as react from 'react';
3
+ import { I18nProviderProps, I18nContextValue } from './i18n.js';
4
+ import './locale.js';
5
+ import './policies.js';
6
+
7
+ /**
8
+ * The i18n kit of the TUWA documentation sites, on {@link docsLabels}: `DocsI18nProvider` provides the language of the
9
+ * reader and the interface texts, `useDocsI18n` reads them (outside the provider: English and a no-op setter).
10
+ * `DocsLayout` renders the provider, so a site's client components inside the layout call `useDocsI18n` directly.
11
+ * The language is detected after mount and kept under `tuwa-locale` in Local Storage (list it in `PreferenceExpiry`).
12
+ */
13
+ declare const DocsI18nProvider: react.ComponentType<I18nProviderProps>;
14
+ declare const useDocsI18n: () => I18nContextValue<DocsLabels>;
15
+
16
+ export { DocsI18nProvider, useDocsI18n };
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import { docsLabels } from "./docsLabels";
3
+ import { createI18n } from "./i18n";
4
+ const { I18nProvider: DocsI18nProvider, useI18n: useDocsI18n } = createI18n(docsLabels);
5
+ export {
6
+ DocsI18nProvider,
7
+ useDocsI18n
8
+ };