mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-29 13:39:11 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8660c59a5a | |||
| 52dc989a7c | |||
| afbad208a7 |
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Send the previous page's URL with site insights events so broken links can be traced to the page linking to them.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Improve dark theme contrast for Mermaid edge labels.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Point the "Powered by GitBook" trademark link to gitbook.com/powered-by.
|
||||
@@ -129,8 +129,8 @@
|
||||
"@gitbook/react-openapi": "workspace:*",
|
||||
"@mermaid-js/mermaid-zenuml": "^0.2.2",
|
||||
"@modelcontextprotocol/sdk": "1.17.5",
|
||||
"@opennextjs/aws": "4.1.6",
|
||||
"@opennextjs/cloudflare": "1.20.7",
|
||||
"@opennextjs/aws": "4.1.3",
|
||||
"@opennextjs/cloudflare": "1.20.5",
|
||||
"@panzoom/panzoom": "^4.6.1",
|
||||
"@sindresorhus/fnv1a": "^3.1.0",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
@@ -346,6 +346,7 @@
|
||||
},
|
||||
"overrides": {
|
||||
"@codemirror/state": "6.4.1",
|
||||
"@opennextjs/aws": "4.1.5",
|
||||
"@types/react": "catalog:",
|
||||
"@types/react-dom": "catalog:",
|
||||
"axios": "1.8.4",
|
||||
@@ -943,9 +944,9 @@
|
||||
|
||||
"@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
|
||||
|
||||
"@opennextjs/aws": ["@opennextjs/aws@4.1.6", "", { "dependencies": { "@ast-grep/napi": "^0.40.5", "@aws-sdk/client-cloudfront": "3.984.0", "@aws-sdk/client-dynamodb": "3.984.0", "@aws-sdk/client-lambda": "3.984.0", "@aws-sdk/client-s3": "3.984.0", "@aws-sdk/client-sqs": "3.984.0", "@node-minify/core": "^8.0.6", "@node-minify/terser": "^8.0.6", "@tsconfig/node18": "^1.0.3", "aws4fetch": "^1.0.20", "chalk": "^5.6.2", "cookie": "^1.0.2", "esbuild": "0.25.4", "express": "^5.1.0", "path-to-regexp": "^6.3.0", "urlpattern-polyfill": "^10.1.0", "yaml": "^2.8.1" }, "peerDependencies": { "next": ">=15.5.26 <16 || >=16.3.6" }, "bin": { "open-next": "dist/index.js" } }, "sha512-J5mzpWo6duetc3ZtcyBxrUqtD6Dwh8msRcMTNQdvpsgTUjEFp03AJmSOnJ/7BKkuF791YTQgjk4iJYIIYLmKqA=="],
|
||||
"@opennextjs/aws": ["@opennextjs/aws@4.1.5", "", { "dependencies": { "@ast-grep/napi": "^0.40.5", "@aws-sdk/client-cloudfront": "3.984.0", "@aws-sdk/client-dynamodb": "3.984.0", "@aws-sdk/client-lambda": "3.984.0", "@aws-sdk/client-s3": "3.984.0", "@aws-sdk/client-sqs": "3.984.0", "@node-minify/core": "^8.0.6", "@node-minify/terser": "^8.0.6", "@tsconfig/node18": "^1.0.3", "aws4fetch": "^1.0.20", "chalk": "^5.6.2", "cookie": "^1.0.2", "esbuild": "0.25.4", "express": "^5.1.0", "path-to-regexp": "^6.3.0", "urlpattern-polyfill": "^10.1.0", "yaml": "^2.8.1" }, "peerDependencies": { "next": ">=15.5.24 <16 || >=16.3.3" }, "bin": { "open-next": "dist/index.js" } }, "sha512-41LNGtS5R5SCfn9zFxHx9QKJIRnmf1uZH+jonHkUMlRKER0bSmUSGjK6GJF7e50XdLXFpTHzaqgRvGmzvr9Btw=="],
|
||||
|
||||
"@opennextjs/cloudflare": ["@opennextjs/cloudflare@1.20.7", "", { "dependencies": { "@ast-grep/napi": "^0.40.5", "@dotenvx/dotenvx": "1.31.0", "@opennextjs/aws": "4.1.6", "ci-info": "^4.2.0", "cloudflare": "^4.4.1", "comment-json": "^4.5.1", "enquirer": "^2.4.1", "glob": "^12.0.0", "ts-tqdm": "^0.8.6", "yargs": "^18.0.0" }, "peerDependencies": { "next": ">=15.5.26 <16 || >=16.3.6", "rclone.js": "^0.6.6", "wrangler": "^4.125.0" }, "optionalPeers": ["rclone.js"], "bin": { "opennextjs-cloudflare": "dist/cli/index.js" } }, "sha512-obZ5l96+MUmGqKd7akJlT9tv0XAvaUDDJj13MyGTVTzA+lbal8kNRoUwei08rtu1Gv+anASAwwMP3dvzcZx+Jw=="],
|
||||
"@opennextjs/cloudflare": ["@opennextjs/cloudflare@1.20.5", "", { "dependencies": { "@ast-grep/napi": "^0.40.5", "@dotenvx/dotenvx": "1.31.0", "@opennextjs/aws": "4.1.3", "ci-info": "^4.2.0", "cloudflare": "^4.4.1", "comment-json": "^4.5.1", "enquirer": "^2.4.1", "glob": "^12.0.0", "ts-tqdm": "^0.8.6", "yargs": "^18.0.0" }, "peerDependencies": { "next": ">=15.5.24 <16 || >=16.3.3", "rclone.js": "^0.6.6", "wrangler": "^4.125.0" }, "optionalPeers": ["rclone.js"], "bin": { "opennextjs-cloudflare": "dist/cli/index.js" } }, "sha512-Y4qCnHTYMa8waEHvf7iqDJuiresuREp0zithSZ8hT33Wn9WyvOUMBM0SWNH961Wv7ynHRdxAJ0ggmnQ3aSdzdg=="],
|
||||
|
||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||
|
||||
|
||||
+2
-1
@@ -19,7 +19,8 @@
|
||||
"react": "catalog:",
|
||||
"react-dom": "catalog:",
|
||||
"esbuild": "0.27.3",
|
||||
"axios": "1.8.4"
|
||||
"axios": "1.8.4",
|
||||
"@opennextjs/aws": "4.1.5"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
"@gitbook/react-openapi": "workspace:*",
|
||||
"@mermaid-js/mermaid-zenuml": "^0.2.2",
|
||||
"@modelcontextprotocol/sdk": "1.17.5",
|
||||
"@opennextjs/aws": "4.1.6",
|
||||
"@opennextjs/cloudflare": "1.20.7",
|
||||
"@opennextjs/aws": "4.1.3",
|
||||
"@opennextjs/cloudflare": "1.20.5",
|
||||
"@panzoom/panzoom": "^4.6.1",
|
||||
"@sindresorhus/fnv1a": "^3.1.0",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
|
||||
@@ -247,15 +247,11 @@ async function renderMermaidDiagram(args: {
|
||||
const { source, id, darkMode, mermaidRuntimeURL } = args;
|
||||
const { mermaid } = await loadMermaid(mermaidRuntimeURL);
|
||||
|
||||
// Mermaid's default dark edge label pill only reaches 4.43:1 contrast, below WCAG AA.
|
||||
const themeVariables = darkMode ? { edgeLabelBackground: '#3a3a3a' } : undefined;
|
||||
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
securityLevel: 'strict',
|
||||
darkMode,
|
||||
theme: darkMode ? 'dark' : undefined,
|
||||
themeVariables,
|
||||
});
|
||||
|
||||
const renderContainer = createMermaidRenderContainer();
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as React from 'react';
|
||||
import { useDebounceCallback, useEventCallback } from 'usehooks-ts';
|
||||
|
||||
import type * as api from '@gitbook/api';
|
||||
import { SiteInsightsDisplayContext } from '@gitbook/api';
|
||||
import { OpenAPIOperationContextProvider } from '@gitbook/react-openapi';
|
||||
|
||||
import { type CurrentContentContext, useCurrentContent } from '../hooks';
|
||||
@@ -75,12 +76,15 @@ export function InsightsProvider(props: InsightsProviderProps) {
|
||||
[pathname: string]:
|
||||
| {
|
||||
url: string;
|
||||
previousUrl: string | null;
|
||||
events: TrackEventInput<InsightsEventName>[];
|
||||
context: CurrentContentContext;
|
||||
pageContext?: InsightsEventPageContext;
|
||||
}
|
||||
| undefined;
|
||||
}>({});
|
||||
// Href of the last page an event was tracked on; `undefined` until the first event.
|
||||
const lastUrlRef = React.useRef<string | null | undefined>(undefined);
|
||||
|
||||
/**
|
||||
* Synchronously flush all the pending events.
|
||||
@@ -105,6 +109,7 @@ export function InsightsProvider(props: InsightsProviderProps) {
|
||||
allEvents.push(
|
||||
...transformEvents({
|
||||
url: eventsForPathname.url,
|
||||
previousUrl: eventsForPathname.previousUrl,
|
||||
events: eventsForPathname.events,
|
||||
context: currentContent,
|
||||
pageContext: eventsForPathname.pageContext,
|
||||
@@ -154,6 +159,9 @@ export function InsightsProvider(props: InsightsProviderProps) {
|
||||
) => {
|
||||
const pathname = window.location.pathname;
|
||||
const previous = eventsRef.current[pathname];
|
||||
const lastUrl =
|
||||
lastUrlRef.current === undefined ? getSameOriginReferrer() : lastUrlRef.current;
|
||||
lastUrlRef.current = window.location.href;
|
||||
eventsRef.current[pathname] = {
|
||||
// An explicitly-provided context wins so page-scoped events (e.g. feedback) can
|
||||
// attribute to their page even when the pathname's ambient context has none — such
|
||||
@@ -161,6 +169,7 @@ export function InsightsProvider(props: InsightsProviderProps) {
|
||||
// context keep the stored one.
|
||||
pageContext: ctx ?? previous?.pageContext,
|
||||
url: previous?.url ?? window.location.href,
|
||||
previousUrl: previous ? previous.previousUrl : lastUrl,
|
||||
events: [
|
||||
...(previous?.events ?? []),
|
||||
{
|
||||
@@ -214,6 +223,18 @@ export function useTrackEvent(): TrackEventCallback {
|
||||
return React.useContext(InsightsContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* The referrer when it's another page of this origin, so a full page load (e.g. an absolute link
|
||||
* to a missing page) still records the page it came from.
|
||||
*/
|
||||
function getSameOriginReferrer(): string | null {
|
||||
if (document.referrer === window.location.href || !URL.canParse(document.referrer)) {
|
||||
return null;
|
||||
}
|
||||
const referrer = new URL(document.referrer);
|
||||
return referrer.origin === window.location.origin ? referrer.href : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post the events to the server.
|
||||
*/
|
||||
@@ -240,6 +261,7 @@ function sendEvents(args: { eventUrl: string; events: api.SiteInsightsEvent[] })
|
||||
*/
|
||||
function transformEvents(input: {
|
||||
url: string;
|
||||
previousUrl: string | null;
|
||||
events: TrackEventInput<InsightsEventName>[];
|
||||
context: CurrentContentContext;
|
||||
pageContext: InsightsEventPageContext;
|
||||
@@ -258,6 +280,11 @@ function transformEvents(input: {
|
||||
|
||||
const location: api.SiteInsightsEventLocation = {
|
||||
url: input.url,
|
||||
// The embed's navigation is between its own tabs, not pages of the site.
|
||||
previousUrl:
|
||||
input.pageContext.displayContext === SiteInsightsDisplayContext.Embed
|
||||
? null
|
||||
: input.previousUrl,
|
||||
siteSection: input.context.siteSectionId ?? null,
|
||||
siteSpace: input.context.siteSpaceId ?? null,
|
||||
space: input.context.spaceId,
|
||||
|
||||
@@ -19,7 +19,7 @@ export async function Trademark(
|
||||
const { space } = context;
|
||||
const language = await getSpaceLanguage(context);
|
||||
|
||||
const url = new URL('https://www.gitbook.com/powered-by');
|
||||
const url = new URL('https://www.gitbook.com');
|
||||
url.searchParams.set('utm_source', 'content');
|
||||
url.searchParams.set('utm_medium', 'trademark');
|
||||
url.searchParams.set('utm_campaign', space.id);
|
||||
|
||||
Reference in New Issue
Block a user