diff --git a/bun.lock b/bun.lock
index 8feb52c719..e7809d941e 100644
--- a/bun.lock
+++ b/bun.lock
@@ -120,6 +120,8 @@
"version": "0.0.0",
"dependencies": {
"@gitbook/api": "^0.90.0",
+ "@gitbook/icons": "workspace:*",
+ "clsx": "^2.1.1",
"next": "canary",
"react": "^19.0.0",
"react-dom": "^19.0.0",
@@ -1466,7 +1468,7 @@
"clone-response": ["clone-response@1.0.3", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA=="],
- "clsx": ["clsx@2.0.0", "", {}, "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q=="],
+ "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
"code-block-writer": ["code-block-writer@13.0.3", "", {}, "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg=="],
@@ -4272,6 +4274,8 @@
"convict/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="],
+ "cva/clsx": ["clsx@2.0.0", "", {}, "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q=="],
+
"decamelize-keys/map-obj": ["map-obj@1.0.1", "", {}, "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg=="],
"deep-equal/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
diff --git a/packages/gitbook-v2/package.json b/packages/gitbook-v2/package.json
index 164cd1f535..7846545693 100644
--- a/packages/gitbook-v2/package.json
+++ b/packages/gitbook-v2/package.json
@@ -5,7 +5,9 @@
"next": "canary",
"react": "^19.0.0",
"react-dom": "^19.0.0",
- "@gitbook/api": "^0.90.0"
+ "@gitbook/api": "^0.90.0",
+ "@gitbook/icons": "workspace:*",
+ "clsx": "^2.1.1"
},
"devDependencies": {
"@opennextjs/cloudflare": "^0.4.3"
diff --git a/packages/gitbook-v2/src/app/dynamic/url/[...url]/layout.tsx b/packages/gitbook-v2/src/app/dynamic/url/[...url]/layout.tsx
index 76df228243..d37ae8bb26 100644
--- a/packages/gitbook-v2/src/app/dynamic/url/[...url]/layout.tsx
+++ b/packages/gitbook-v2/src/app/dynamic/url/[...url]/layout.tsx
@@ -1,5 +1,5 @@
-import { SiteContentLayout } from '@/components/routes/SiteContentLayout';
-import { createDynamicSiteContext } from '@/lib/context';
+import { SiteContentLayout } from '@v2/components/routes/SiteContentLayout';
+import { createDynamicSiteContext } from '@v2/lib/context';
export default async function RootLayout({
params,
diff --git a/packages/gitbook-v2/src/app/dynamic/url/[...url]/page.tsx b/packages/gitbook-v2/src/app/dynamic/url/[...url]/page.tsx
index afc48a2069..6f0df88deb 100644
--- a/packages/gitbook-v2/src/app/dynamic/url/[...url]/page.tsx
+++ b/packages/gitbook-v2/src/app/dynamic/url/[...url]/page.tsx
@@ -1,5 +1,5 @@
-import { SiteContentPage } from '@/components/routes/SiteContentPage';
-import { createDynamicSiteContext } from '@/lib/context';
+import { SiteContentPage } from '@v2/components/routes/SiteContentPage';
+import { createDynamicSiteContext } from '@v2/lib/context';
export default async function Page({ params }: { params: Promise<{ url: string[] }> }) {
const { url } = await params;
diff --git a/packages/gitbook-v2/src/app/static/url/[...url]/layout.tsx b/packages/gitbook-v2/src/app/static/url/[...url]/layout.tsx
index 9949ade591..ea207c3a4b 100644
--- a/packages/gitbook-v2/src/app/static/url/[...url]/layout.tsx
+++ b/packages/gitbook-v2/src/app/static/url/[...url]/layout.tsx
@@ -1,7 +1,7 @@
import { unstable_cacheTag as cacheTag } from 'next/cache';
-import { SiteContentLayout } from '@/components/routes/SiteContentLayout';
-import { getSiteCacheTag } from '@/lib/cache';
-import { createStaticSiteContext } from '@/lib/context';
+import { SiteContentLayout } from '@v2/components/routes/SiteContentLayout';
+import { getSiteCacheTag } from '@v2/lib/cache';
+import { createStaticSiteContext } from '@v2/lib/context';
export default async function RootLayout({
params,
diff --git a/packages/gitbook-v2/src/app/static/url/[...url]/page.tsx b/packages/gitbook-v2/src/app/static/url/[...url]/page.tsx
index e966f4c089..734e468538 100644
--- a/packages/gitbook-v2/src/app/static/url/[...url]/page.tsx
+++ b/packages/gitbook-v2/src/app/static/url/[...url]/page.tsx
@@ -1,7 +1,7 @@
import { unstable_cacheTag as cacheTag } from 'next/cache';
-import { createStaticSiteContext } from '@/lib/context';
-import { getSiteCacheTag } from '@/lib/cache';
-import { SiteContentPage } from '@/components/routes/SiteContentPage';
+import { createStaticSiteContext } from '@v2/lib/context';
+import { getSiteCacheTag } from '@v2/lib/cache';
+import { SiteContentPage } from '@v2/components/routes/SiteContentPage';
export default async function Page({ params }: { params: Promise<{ url: string[] }> }) {
'use cache';
diff --git a/packages/gitbook/src/components/utils/ZoomImage.module.css b/packages/gitbook-v2/src/components/images/ZoomImage.module.css
similarity index 100%
rename from packages/gitbook/src/components/utils/ZoomImage.module.css
rename to packages/gitbook-v2/src/components/images/ZoomImage.module.css
diff --git a/packages/gitbook/src/components/utils/ZoomImage.tsx b/packages/gitbook-v2/src/components/images/ZoomImage.tsx
similarity index 83%
rename from packages/gitbook/src/components/utils/ZoomImage.tsx
rename to packages/gitbook-v2/src/components/images/ZoomImage.tsx
index 773b44a282..0e68472aa4 100644
--- a/packages/gitbook/src/components/utils/ZoomImage.tsx
+++ b/packages/gitbook-v2/src/components/images/ZoomImage.tsx
@@ -1,12 +1,11 @@
'use client';
+import clsx from 'clsx';
+
import { Icon } from '@gitbook/icons';
-import classNames from 'classnames';
import React from 'react';
import ReactDOM from 'react-dom';
-import { tcls } from '@/lib/tailwind';
-
import styles from './ZoomImage.module.css';
/**
@@ -166,7 +165,7 @@ export function ZoomImage(
startViewTransition(change);
});
}}
- className={classNames(
+ className={clsx(
props.className,
zoomable ? styles.zoomImg : null,
active ? styles.zoomImageActive : null,
@@ -208,19 +207,9 @@ function ZoomImageModal(props: {
return (
@@ -228,43 +217,15 @@ function ZoomImageModal(props: {
src={src}
alt={alt}
crossOrigin={crossOrigin}
- className={tcls(
- 'max-w-full',
- 'max-h-full',
- 'object-contain',
- 'bg-light',
- 'dark:bg-dark',
- )}
+ className="max-w-full max-h-full object-contain bg-light dark:bg-dark"
/>
);
diff --git a/packages/gitbook-v2/src/components/routes/SiteContentLayout.tsx b/packages/gitbook-v2/src/components/routes/SiteContentLayout.tsx
index 664475e7d3..81fced4f45 100644
--- a/packages/gitbook-v2/src/components/routes/SiteContentLayout.tsx
+++ b/packages/gitbook-v2/src/components/routes/SiteContentLayout.tsx
@@ -1,4 +1,5 @@
-import { GitBookSiteContext } from '@/lib/context';
+import { GitBookSiteSpaceContext } from '@v2/lib/context';
+import { Footer } from '@/components/Footer';
/**
* Layout component to render the site content.
@@ -7,20 +8,29 @@ export async function SiteContentLayout({
context,
children,
}: {
- context: GitBookSiteContext;
+ context: GitBookSiteSpaceContext;
children: React.ReactNode;
}) {
- const { api } = context;
- const { data: publishedSite } = await api.orgs.getPublishedContentSite(
- context.organizationId,
- context.siteId,
- );
+ const [publishedSite, space] = await Promise.all([
+ context.getPublishedContentSite(
+ context.organizationId,
+ context.siteId,
+ ),
+ context.getSpaceById(context.spaceId, context.siteShareKey),
+ ]);
return (
{publishedSite.site.title}
{children}
+
);
diff --git a/packages/gitbook-v2/src/components/routes/SiteContentPage.tsx b/packages/gitbook-v2/src/components/routes/SiteContentPage.tsx
index a1ebb8c290..92d97975bc 100644
--- a/packages/gitbook-v2/src/components/routes/SiteContentPage.tsx
+++ b/packages/gitbook-v2/src/components/routes/SiteContentPage.tsx
@@ -1,4 +1,4 @@
-import { GitBookSiteContext } from '@/lib/context';
+import { GitBookSiteContext } from '@v2/lib/context';
export async function SiteContentPage({ context }: { context: GitBookSiteContext }) {
const { api } = context;
diff --git a/packages/gitbook-v2/src/lib/context.ts b/packages/gitbook-v2/src/lib/context.ts
index 8b0fc57d5f..5edd299e36 100644
--- a/packages/gitbook-v2/src/lib/context.ts
+++ b/packages/gitbook-v2/src/lib/context.ts
@@ -1,17 +1,8 @@
import { headers } from 'next/headers';
import { redirect } from 'next/navigation';
import { GitBookAPI } from '@gitbook/api';
-import { GITBOOK_API_TOKEN, GITBOOK_API_URL, GITBOOK_USER_AGENT } from '@/lib/env';
-
-/**
- * Generic context about rendering content.
- */
-export interface GitBookContext {
- /**
- * API client to fetch data from GitBook.
- */
- api: GitBookAPI;
-}
+import { GITBOOK_API_TOKEN, GITBOOK_API_URL, GITBOOK_USER_AGENT } from '@v2/lib/env';
+import { GitBookContext } from '@/lib/v2/context';
/**
* Context when rendering a site.
@@ -28,10 +19,35 @@ export interface GitBookSiteContext extends GitBookContext {
siteId: string;
}
+/**
+ * Context when rendering a space in a site.
+ */
+export interface GitBookSiteSpaceContext extends GitBookSiteContext {
+ /**
+ * ID of the space.
+ */
+ spaceId: string;
+
+ /**
+ * ID of the site section.
+ */
+ siteSectionId: string | undefined;
+
+ /**
+ * ID of the site space.
+ */
+ siteSpaceId: string;
+
+ /**
+ * Share key of the site.
+ */
+ siteShareKey: string | undefined;
+}
+
/**
* Create a site context, when rendering a static page.
*/
-export async function createStaticSiteContext(url: string[]): Promise {
+export async function createStaticSiteContext(url: string[]): Promise {
const context = createStaticContext();
return fetchSiteContext(url, context);
}
@@ -39,7 +55,7 @@ export async function createStaticSiteContext(url: string[]): Promise {
+export async function createDynamicSiteContext(url: string[]): Promise {
const context = await createDynamicContext();
return fetchSiteContext(url, context);
}
@@ -50,7 +66,7 @@ export async function createDynamicSiteContext(url: string[]): Promise {
+): Promise {
const { api } = baseContext;
const url = getURLFromParams(urlParts);
const { data } = await api.urls.getPublishedContentByUrl({
@@ -70,6 +86,9 @@ async function fetchSiteContext(
}),
siteId: data.site,
organizationId: data.organization,
+ siteSectionId: data.siteSection,
+ siteSpaceId: data.siteSpace,
+ spaceId: data.space,
};
}
@@ -83,9 +102,7 @@ function createStaticContext(): GitBookContext {
userAgent: GITBOOK_USER_AGENT,
});
- return {
- api,
- };
+ return createContextFromClient(api);
}
/**
@@ -101,8 +118,36 @@ async function createDynamicContext(): Promise {
userAgent: GITBOOK_USER_AGENT,
});
+ return createContextFromClient(api);
+}
+
+function createContextFromClient(api: GitBookAPI): GitBookContext {
return {
api,
+ getLink: (pathname: string) => pathname,
+ getPublishedContentSite: async (organizationId: string, siteId: string) => {
+ const { data } = await api.orgs.getPublishedContentSite(organizationId, siteId);
+ return data;
+ },
+ getRevisionFile: async (spaceId: string, revisionId: string, file: string) => {
+ throw new Error('Not implemented');
+ },
+ getUserById: async (userId: string) => {
+ const { data } = await api.users.getUserById(userId);
+ return data;
+ },
+ getSpaceById: async (spaceId: string, shareKey: string | undefined) => {
+ const { data } = await api.spaces.getSpaceById(spaceId, { shareKey });
+ return data;
+ },
+ getCollection: async (collectionId: string) => {
+ const { data } = await api.collections.getCollectionById(collectionId);
+ return data;
+ },
+ getReusableContent: async (spaceId: string, revisionId: string, reusableContentId: string) => {
+ const { data } = await api.spaces.getReusableContentInRevisionById(spaceId, revisionId, reusableContentId);
+ return data;
+ },
};
}
diff --git a/packages/gitbook-v2/tsconfig.json b/packages/gitbook-v2/tsconfig.json
index 3ddc429939..5c7cec33b8 100644
--- a/packages/gitbook-v2/tsconfig.json
+++ b/packages/gitbook-v2/tsconfig.json
@@ -19,8 +19,8 @@
}
],
"paths": {
- "@/*": ["./src/*"],
- "@v1/*": ["../gitbook/src/*"]
+ "@v2/*": ["./src/*"],
+ "@/*": ["../gitbook/src/*"]
}
},
"include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"],
diff --git a/packages/gitbook/src/components/utils/Image.tsx b/packages/gitbook/src/components/utils/Image.tsx
index 3ae58ed597..73264a097f 100644
--- a/packages/gitbook/src/components/utils/Image.tsx
+++ b/packages/gitbook/src/components/utils/Image.tsx
@@ -5,7 +5,7 @@ import { checkIsHttpURL, getImageSize, getResizedImageURLFactory } from '@/lib/i
import { ClassValue, tcls } from '@/lib/tailwind';
import { PolymorphicComponentProp } from './types';
-import { ZoomImage } from './ZoomImage';
+import { ZoomImage } from '@v2/components/images/ZoomImage';
export type ImageSize = { width: number; height: number };
diff --git a/packages/gitbook/src/lib/v2/context.ts b/packages/gitbook/src/lib/v2/context.ts
new file mode 100644
index 0000000000..a3fe1759da
--- /dev/null
+++ b/packages/gitbook/src/lib/v2/context.ts
@@ -0,0 +1,47 @@
+import { Collection, GitBookAPI, PublishedContentSite, RevisionFile, RevisionReusableContent, Space, User } from "@gitbook/api";
+
+/**
+ * Global context for rendering GitBook.
+ * The context is designed to help migrate from v1 to v2, with components implemented for both versions.
+ */
+export interface GitBookContext {
+ /**
+ * API client to fetch data from GitBook.
+ */
+ api: GitBookAPI;
+
+ /**
+ * Resolve a url/pathname to a link.
+ */
+ getLink(pathname: string): string;
+
+ /**
+ * Get a published site by ID.
+ */
+ getPublishedContentSite(organizationId: string, siteId: string): Promise;
+
+ /**
+ * Get a file from a revision.
+ */
+ getRevisionFile(spaceId: string, revisionId: string, file: string): Promise;
+
+ /**
+ * Get a user by ID.
+ */
+ getUserById(userId: string): Promise;
+
+ /**
+ * Get a space by ID.
+ */
+ getSpaceById(spaceId: string, shareKey: string | undefined): Promise;
+
+ /**
+ * Get a collection by ID.
+ */
+ getCollection(collectionId: string): Promise;
+
+ /**
+ * Get a reusable content by ID.
+ */
+ getReusableContent(spaceId: string, revisionId: string, reusableContentId: string): Promise;
+}
diff --git a/packages/gitbook/tailwind.config.ts b/packages/gitbook/tailwind.config.ts
index aafa391e4c..53a3642c3f 100644
--- a/packages/gitbook/tailwind.config.ts
+++ b/packages/gitbook/tailwind.config.ts
@@ -55,6 +55,9 @@ const config: Config = {
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
'./src/app/**/*.{js,ts,jsx,tsx,mdx}',
+
+ // V2
+ '../gitbook-v2/src/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
diff --git a/packages/gitbook/tsconfig.json b/packages/gitbook/tsconfig.json
index 4374d4750a..9a58ebdcd0 100644
--- a/packages/gitbook/tsconfig.json
+++ b/packages/gitbook/tsconfig.json
@@ -19,7 +19,8 @@
}
],
"paths": {
- "@/*": ["./src/*"]
+ "@/*": ["./src/*"],
+ "@v2/*": ["../gitbook-v2/src/*"]
},
"types": [
"bun-types" // add Bun global