Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sites support #2262

Merged
merged 11 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
Binary file not shown.
35 changes: 35 additions & 0 deletions e2e/pages.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,41 @@ async function waitForCookiesDialog(page: Page) {
}

const testCases: TestsCase[] = [
{
name: 'GitBook Site',
baseUrl: 'https://gitbook.gitbook.io/gitbook-site/',
tests: [
{
name: 'Home',
url: '',
run: waitForCookiesDialog,
},
{
name: 'Search',
url: '?q=',
},
{
name: 'Search Results',
url: '?q=gitbook',
run: async (page) => {
await page.waitForSelector('[data-test="search-results"]');
},
},
{
name: 'AI Search',
url: '?q=What+is+GitBook%3F&ask=true',
run: async (page) => {
await page.waitForSelector('[data-test="search-ask-answer"]');
},
screenshot: false,
},
{
name: 'Not found',
url: 'content-not-found',
run: waitForCookiesDialog,
},
],
},
{
name: 'GitBook',
baseUrl: 'https://docs.gitbook.com',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
],
"dependencies": {
"@geist-ui/icons": "^1.0.2",
"@gitbook/api": "^0.39.0",
"@gitbook/api": "^0.41.0",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-popover": "^1.0.7",
"@sentry/nextjs": "^7.94.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-contentkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"exports": "./src/index.ts",
"dependencies": {
"classnames": "^2.5.1",
"@gitbook/api": "^0.36.0",
"@gitbook/api": "^0.41.0",
"assert-never": "^1.2.1"
},
"peerDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions src/app/(space)/(content)/[[...pathname]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,13 @@ export async function generateViewport({ params }: { params: PagePathParams }):
}

export async function generateMetadata({ params }: { params: PagePathParams }): Promise<Metadata> {
const { space, pages, page, customization, collection } = await fetchPageData(params);
const { space, pages, page, customization, parent } = await fetchPageData(params);
if (!page) {
notFound();
}

return {
title: [page.title, customization.title ?? space.title, collection?.title]
title: [page.title, customization.title ?? space.title, parent?.title]
.filter(Boolean)
.join(' | '),
description: page.description ?? '',
Expand Down
14 changes: 7 additions & 7 deletions src/app/(space)/(content)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export default async function ContentLayout(props: { children: React.ReactNode }
contentTarget,
customization,
pages,
collection,
collectionSpaces,
parent,
spaces,
ancestors,
scripts,
} = await fetchSpaceData();
Expand All @@ -56,8 +56,8 @@ export default async function ContentLayout(props: { children: React.ReactNode }
<SpaceLayout
space={space}
contentTarget={contentTarget}
collection={collection}
collectionSpaces={collectionSpaces}
parent={parent}
spaces={spaces}
customization={customization}
pages={pages}
ancestors={ancestors}
Expand Down Expand Up @@ -100,11 +100,11 @@ export async function generateViewport(): Promise<Viewport> {
}

export async function generateMetadata(): Promise<Metadata> {
const { space, collection, customization } = await fetchSpaceData();
const { space, parent, customization } = await fetchSpaceData();
const customIcon = 'icon' in customization.favicon ? customization.favicon.icon : null;

return {
title: `${collection ? collection.title : customization.title ?? space.title}`,
title: `${parent ? parent.title : customization.title ?? space.title}`,
generator: `GitBook (${buildVersion()})`,
metadataBase: new URL(baseUrl()),
icons: {
Expand All @@ -125,7 +125,7 @@ export async function generateMetadata(): Promise<Metadata> {
},
],
},
robots: shouldIndexSpace({ space, collection }) ? 'index, follow' : 'noindex, nofollow',
robots: shouldIndexSpace({ space, parent }) ? 'index, follow' : 'noindex, nofollow',
};
}

Expand Down
17 changes: 10 additions & 7 deletions src/app/(space)/(core)/robots.txt/route.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ContentVisibility } from '@gitbook/api';
import { NextRequest } from 'next/server';

import { getCollection, getSpace } from '@/lib/api';
import { getCollection, getSite, getSpace } from '@/lib/api';
import { absoluteHref } from '@/lib/links';
import { shouldIndexSpace } from '@/lib/seo';

Expand All @@ -13,16 +13,19 @@ export const runtime = 'edge';
* Generate a robots.txt for the current space.
*/
export async function GET(req: NextRequest) {
const space = await getSpace(getContentPointer().spaceId);
const collection =
space.visibility === ContentVisibility.InCollection && space.parent
? await getCollection(space.parent)
: null;
const pointer = getContentPointer();
const space = await getSpace(pointer.spaceId);
const parent =
'siteId' in pointer
? await getSite(pointer.organizationId, pointer.siteId)
: space.visibility === ContentVisibility.InCollection && space.parent
? await getCollection(space.parent)
: null;

const lines = [
`User-agent: *`,
'Disallow: /~gitbook/',
...(shouldIndexSpace({ space, collection })
...(shouldIndexSpace({ space, parent })
? [`Allow: /`, `Sitemap: ${absoluteHref(`/sitemap.xml`, true)}`]
: [`Disallow: /`]),
];
Expand Down
4 changes: 2 additions & 2 deletions src/app/(space)/(core)/~gitbook/ogimage/[pageId]/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const runtime = 'edge';
* Render the OpenGraph image for a space.
*/
export async function GET(req: NextRequest, { params }: { params: PageIdParams }) {
const { space, page, customization, collection } = await fetchPageData(params);
const { space, page, customization, parent } = await fetchPageData(params);
const url = new URL(space.urls.published ?? space.urls.app);

if (customization.socialPreview.url) {
Expand All @@ -31,7 +31,7 @@ export async function GET(req: NextRequest, { params }: { params: PageIdParams }
}}
>
<h2 tw="text-7xl font-bold tracking-tight text-left">
{collection?.title ?? customization.title ?? space.title}
{parent?.title ?? customization.title ?? space.title}
</h2>
<div tw="flex flex-1">
<p tw="text-4xl">{page ? page.title : 'Not found'}</p>
Expand Down
66 changes: 54 additions & 12 deletions src/app/(space)/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import {
getDocument,
getSpaceData,
ContentTarget,
SiteContentPointer,
getSiteSpaceData,
getSite,
getSiteSpaces,
} from '@/lib/api';
import { resolvePagePath, resolvePageId } from '@/lib/pages';

Expand All @@ -23,7 +27,7 @@ export interface PageIdParams {
/**
* Get the current content pointer from the params.
*/
export function getContentPointer() {
export function getContentPointer(): ContentPointer | SiteContentPointer {
const headerSet = headers();
const spaceId = headerSet.get('x-gitbook-content-space');
if (!spaceId) {
Expand All @@ -32,22 +36,46 @@ export function getContentPointer() {
);
}

const content: ContentPointer = {
spaceId,
revisionId: headerSet.get('x-gitbook-content-revision') ?? undefined,
changeRequestId: headerSet.get('x-gitbook-content-changerequest') ?? undefined,
};
const siteId = headerSet.get('x-gitbook-content-site');
if (siteId) {
const organizationId = headerSet.get('x-gitbook-content-organization');
const siteSpaceId = headerSet.get('x-gitbook-content-site-space');
if (!organizationId || !siteSpaceId) {
throw new Error('Missing site content headers');
}

return content;
const siteContent: SiteContentPointer = {
siteId,
spaceId,
siteSpaceId,
organizationId,
revisionId: headerSet.get('x-gitbook-content-revision') ?? undefined,
changeRequestId: headerSet.get('x-gitbook-content-changerequest') ?? undefined,
};
return siteContent;
} else {
const content: ContentPointer = {
spaceId,
revisionId: headerSet.get('x-gitbook-content-revision') ?? undefined,
changeRequestId: headerSet.get('x-gitbook-content-changerequest') ?? undefined,
};
return content;
}
}

/**
* Fetch all the data needed to render the space layout.
*/
export async function fetchSpaceData() {
const content = getContentPointer();
const { space, contentTarget, pages, customization, scripts } = await getSpaceData(content);
const collection = await fetchParentCollection(space);

const [{ space, contentTarget, pages, customization, scripts }, parentSite] = await Promise.all(
'siteId' in content
? [getSiteSpaceData(content), fetchParentSite(content.organizationId, content.siteId)]
: [getSpaceData(content)],
);

const parent = await (parentSite ?? fetchParentCollection(space));

return {
content,
Expand All @@ -57,7 +85,7 @@ export async function fetchSpaceData() {
customization,
scripts,
ancestors: [],
...collection,
...parent,
};
}

Expand Down Expand Up @@ -133,12 +161,26 @@ async function resolvePage(
async function fetchParentCollection(space: Space) {
const parentCollectionId =
space.visibility === ContentVisibility.InCollection ? space.parent : undefined;
const [collection, collectionSpaces] = await Promise.all([
const [collection, spaces] = await Promise.all([
parentCollectionId ? getCollection(parentCollectionId) : null,
parentCollectionId ? getCollectionSpaces(parentCollectionId) : ([] as Space[]),
]);

return { collection, collectionSpaces };
return { parent: collection, spaces };
}

async function fetchParentSite(organizationId: string, siteId: string) {
const [site, siteSpaces] = await Promise.all([
getSite(organizationId, siteId),
getSiteSpaces(organizationId, siteId),
]);

const spaces: Record<string, Space> = {};
siteSpaces.forEach((siteSpace) => {
spaces[siteSpace.space.id] = siteSpace.space;
});

return { parent: site, spaces: Object.values(spaces) };
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CustomizationSettings, Space } from '@gitbook/api';
import { CustomizationSettings, SiteCustomizationSettings, Space } from '@gitbook/api';
import React from 'react';

import { Image } from '@/components/utils';
Expand All @@ -12,7 +12,7 @@ import { ThemeToggler } from '../ThemeToggler';
export function Footer(props: {
space: Space;
context: ContentRefContext;
customization: CustomizationSettings;
customization: CustomizationSettings | SiteCustomizationSettings;
}) {
const { context, customization } = props;

Expand Down
18 changes: 12 additions & 6 deletions src/components/Header/CompactHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { Collection, CustomizationSettings, Space } from '@gitbook/api';
import {
Collection,
CustomizationSettings,
Site,
SiteCustomizationSettings,
Space,
} from '@gitbook/api';
import React from 'react';

import { t } from '@/intl/server';
Expand All @@ -13,11 +19,11 @@ import { SearchButton } from '../Search';
*/
export function CompactHeader(props: {
space: Space;
collection: Collection | null;
collectionSpaces: Space[];
customization: CustomizationSettings;
parent: Site | Collection | null;
spaces: Space[];
customization: CustomizationSettings | SiteCustomizationSettings;
}) {
const { space, collection, customization } = props;
const { space, parent, customization } = props;

return (
<div
Expand All @@ -34,7 +40,7 @@ export function CompactHeader(props: {
)}
>
<div className={tcls('flex-grow-0', 'mt-5')}>
<HeaderLogo collection={collection} space={space} customization={customization} />
<HeaderLogo parent={parent} space={space} customization={customization} />
</div>
<div
className={tcls(
Expand Down
Loading
Loading