Skip to content

Commit b5494cc

Browse files
Restyle the toolbar in CR and revision preview links (#3631)
Co-authored-by: Samy Pessé <samypesse@gmail.com>
1 parent 229f2ba commit b5494cc

File tree

13 files changed

+1102
-203
lines changed

13 files changed

+1102
-203
lines changed

bun.lock

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
},
6565
"packages/expr": {
6666
"name": "@gitbook/expr",
67-
"version": "1.1.0",
67+
"version": "1.2.0",
6868
"dependencies": {
6969
"acorn": "^8.14.0",
7070
"acorn-loose": "8.4.0",
@@ -95,7 +95,7 @@
9595
},
9696
"packages/gitbook": {
9797
"name": "gitbook",
98-
"version": "0.17.1",
98+
"version": "0.18.0",
9999
"dependencies": {
100100
"@gitbook/api": "catalog:",
101101
"@gitbook/browser-types": "workspace:*",
@@ -142,6 +142,7 @@
142142
"memoizee": "^0.4.17",
143143
"micromark-extension-frontmatter": "^2.0.0",
144144
"micromark-extension-gfm": "^3.0.0",
145+
"motion": "^12.23.12",
145146
"next": "15.4.0",
146147
"next-themes": "^0.2.1",
147148
"nuqs": "^2.2.3",
@@ -197,7 +198,7 @@
197198
},
198199
"packages/icons": {
199200
"name": "@gitbook/icons",
200-
"version": "0.3.0",
201+
"version": "0.3.1",
201202
"bin": {
202203
"gitbook-icons": "./bin/gitbook-icons.js",
203204
},
@@ -233,7 +234,7 @@
233234
},
234235
"packages/react-contentkit": {
235236
"name": "@gitbook/react-contentkit",
236-
"version": "0.7.4",
237+
"version": "0.7.5",
237238
"dependencies": {
238239
"@gitbook/api": "catalog:",
239240
"@gitbook/icons": "workspace:*",
@@ -265,7 +266,7 @@
265266
},
266267
"packages/react-openapi": {
267268
"name": "@gitbook/react-openapi",
268-
"version": "1.4.1",
269+
"version": "1.4.3",
269270
"dependencies": {
270271
"@gitbook/expr": "workspace:*",
271272
"@gitbook/openapi-parser": "workspace:*",
@@ -2432,6 +2433,12 @@
24322433

24332434
"mnemonist": ["mnemonist@0.38.3", "", { "dependencies": { "obliterator": "^1.6.1" } }, "sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw=="],
24342435

2436+
"motion": ["motion@12.23.12", "", { "dependencies": { "framer-motion": "^12.23.12", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-8jCD8uW5GD1csOoqh1WhH1A6j5APHVE15nuBkFeRiMzYBdRwyAHmSP/oXSuW0WJPZRXTFdBoG4hY9TFWNhhwng=="],
2437+
2438+
"motion-dom": ["motion-dom@12.23.12", "", { "dependencies": { "motion-utils": "^12.23.6" } }, "sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw=="],
2439+
2440+
"motion-utils": ["motion-utils@12.23.6", "", {}, "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ=="],
2441+
24352442
"mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
24362443

24372444
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
@@ -4352,6 +4359,10 @@
43524359

43534360
"minizlib/minipass": ["minipass@2.9.0", "", { "dependencies": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } }, "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg=="],
43544361

4362+
"motion/framer-motion": ["framer-motion@12.23.12", "", { "dependencies": { "motion-dom": "^12.23.12", "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg=="],
4363+
4364+
"motion/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
4365+
43554366
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
43564367

43574368
"p-filter/p-map": ["p-map@2.1.0", "", {}, "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw=="],

packages/gitbook/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"memoizee": "^0.4.17",
4747
"micromark-extension-frontmatter": "^2.0.0",
4848
"micromark-extension-gfm": "^3.0.0",
49+
"motion": "^12.23.12",
4950
"next": "15.4.0",
5051
"next-themes": "^0.2.1",
5152
"nuqs": "^2.2.3",
Lines changed: 86 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,143 +1,103 @@
11
import type { GitBookSiteContext } from '@/lib/context';
2-
import { Icon } from '@gitbook/icons';
3-
import React from 'react';
2+
import { AdminToolbarClient } from './AdminToolbarClient';
43

5-
import { tcls } from '@/lib/tailwind';
6-
import { DateRelative } from '../primitives';
7-
import { IframeWrapper } from './IframeWrapper';
8-
import { RefreshChangeRequestButton } from './RefreshChangeRequestButton';
9-
import { Toolbar, ToolbarBody, ToolbarButton, ToolbarButtonGroups } from './Toolbar';
10-
11-
interface AdminToolbarProps {
4+
export interface AdminToolbarProps {
125
context: GitBookSiteContext;
136
}
147

15-
function ToolbarLayout(props: { children: React.ReactNode }) {
16-
return (
17-
<div
18-
className={tcls(
19-
'fixed',
20-
'bottom-5',
21-
'left-1/2',
22-
'z-50',
23-
'transform',
24-
'-translate-x-1/2',
25-
'rounded-full',
8+
// Minimal types containing only the fields needed for AdminToolbar to restrict what gets serialized
9+
export type MinimalChangeRequest = {
10+
id: string;
11+
number: number;
12+
subject: string | null;
13+
revision: string;
14+
updatedAt: string;
15+
createdBy: {
16+
displayName: string;
17+
};
18+
urls: {
19+
app: string;
20+
};
21+
};
22+
23+
export type MinimalRevision = {
24+
createdAt: string;
25+
urls: {
26+
app: string;
27+
};
28+
git?: {
29+
url: string | undefined;
30+
} | null;
31+
};
2632

27-
'bg-tint-12/9',
28-
'dark:bg-tint-1/9',
33+
export type AdminToolbarContext = {
34+
space: {
35+
id: string;
36+
revision: string;
37+
};
38+
changeRequest: MinimalChangeRequest | null;
39+
revision: MinimalRevision;
40+
revisionId: string;
41+
site: {
42+
title: string;
43+
urls: {
44+
published: string | undefined;
45+
};
46+
};
47+
};
2948

30-
'shadow-lg',
31-
'min-h-10',
32-
'min-w-40',
33-
'p-2',
34-
'max-w-md',
35-
'border-tint-12/1',
36-
'backdrop-blur-md'
37-
)}
38-
>
39-
<React.Suspense fallback={null}>{props.children}</React.Suspense>
40-
</div>
41-
);
49+
export interface AdminToolbarClientProps {
50+
context: AdminToolbarContext;
4251
}
4352

4453
/**
45-
* Toolbar with information for the content admin when previewing a revision or change-request.
54+
* Server component that determines what type of toolbar to show and passes data to client component
4655
*/
4756
export async function AdminToolbar(props: AdminToolbarProps) {
4857
const { context } = props;
4958

50-
if (context.changeRequest) {
51-
return (
52-
<IframeWrapper>
53-
<ChangeRequestToolbar context={context} />
54-
</IframeWrapper>
55-
);
56-
}
57-
58-
if (context.revisionId !== context.space.revision) {
59-
return (
60-
<IframeWrapper>
61-
<RevisionToolbar context={context} />
62-
</IframeWrapper>
63-
);
64-
}
65-
66-
return null;
67-
}
68-
69-
async function ChangeRequestToolbar(props: { context: GitBookSiteContext }) {
70-
const { context } = props;
71-
const { space, changeRequest } = context;
59+
if (context.changeRequest || context.revisionId !== context.space.revision) {
60+
// Create a minimal context with only the fields needed for AdminToolbar
61+
const minimalContext: AdminToolbarContext = {
62+
space: {
63+
id: context.space.id,
64+
revision: context.space.revision,
65+
},
66+
changeRequest: context.changeRequest
67+
? {
68+
id: context.changeRequest.id,
69+
number: context.changeRequest.number,
70+
subject: context.changeRequest.subject,
71+
revision: context.changeRequest.revision,
72+
updatedAt: context.changeRequest.updatedAt,
73+
createdBy: {
74+
displayName: context.changeRequest.createdBy.displayName,
75+
},
76+
urls: {
77+
app: context.changeRequest.urls.app,
78+
},
79+
}
80+
: null,
81+
revision: {
82+
createdAt: context.revision.createdAt,
83+
urls: {
84+
app: context.revision.urls.app,
85+
},
86+
git: context.revision.git
87+
? {
88+
url: context.revision.git.url,
89+
}
90+
: null,
91+
},
92+
revisionId: context.revisionId,
93+
site: {
94+
title: context.site.title,
95+
urls: {
96+
published: context.site.urls.published,
97+
},
98+
},
99+
};
72100

73-
if (!changeRequest) {
74-
return null;
101+
return <AdminToolbarClient context={minimalContext} />;
75102
}
76-
77-
return (
78-
<ToolbarLayout>
79-
<Toolbar>
80-
<ToolbarButton title="Open in application" href={changeRequest.urls.app}>
81-
<Icon icon="code-branch" className="size-4" />
82-
</ToolbarButton>
83-
<ToolbarBody>
84-
<p>
85-
#{changeRequest.number}: {changeRequest.subject ?? 'No subject'}
86-
</p>
87-
<p className="text-tint-2 text-xs dark:text-tint-11">
88-
Change request updated <DateRelative value={changeRequest.updatedAt} />
89-
</p>
90-
</ToolbarBody>
91-
<ToolbarButtonGroups>
92-
<ToolbarButton title="Open in application" href={changeRequest.urls.app}>
93-
<Icon icon="arrow-up-right-from-square" className="size-4" />
94-
</ToolbarButton>
95-
<RefreshChangeRequestButton
96-
spaceId={space.id}
97-
changeRequestId={changeRequest.id}
98-
revisionId={changeRequest.revision}
99-
updatedAt={new Date(changeRequest.updatedAt).getTime()}
100-
/>
101-
</ToolbarButtonGroups>
102-
</Toolbar>
103-
</ToolbarLayout>
104-
);
105-
}
106-
107-
async function RevisionToolbar(props: { context: GitBookSiteContext }) {
108-
const { context } = props;
109-
const { revision } = context;
110-
111-
return (
112-
<ToolbarLayout>
113-
<Toolbar>
114-
<ToolbarButton title="Open in application" href={revision.urls.app}>
115-
<Icon icon="code-commit" className="size-4" />
116-
</ToolbarButton>
117-
<ToolbarBody>
118-
<p>
119-
Revision created <DateRelative value={revision.createdAt} />
120-
</p>
121-
{revision.git ? (
122-
<p className="text-tint-2 text-xs dark:text-tint-11">
123-
{revision.git.message}
124-
</p>
125-
) : null}
126-
</ToolbarBody>
127-
<ToolbarButtonGroups>
128-
<ToolbarButton title="Open in application" href={revision.urls.app}>
129-
<Icon icon="arrow-up-right-from-square" className="size-4" />
130-
</ToolbarButton>
131-
{revision.git?.url ? (
132-
<ToolbarButton title="Open git commit" href={revision.git.url}>
133-
<Icon
134-
icon={revision.git.url.includes('github.com') ? 'github' : 'gitlab'}
135-
className="size-4"
136-
/>
137-
</ToolbarButton>
138-
) : null}
139-
</ToolbarButtonGroups>
140-
</Toolbar>
141-
</ToolbarLayout>
142-
);
143103
}

0 commit comments

Comments
 (0)