mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-16 07:35:16 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 88fe9e97c0 |
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Hide sections if only one is present
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Unify section display condition
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@gitbook/expr": patch
|
||||
---
|
||||
|
||||
Add dev script for @gitbook/expr
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix missing geo data in site insights because of incorrect proxying of events.
|
||||
@@ -3,4 +3,4 @@
|
||||
'gitbook': patch
|
||||
---
|
||||
|
||||
Improve OpenAPI circular references
|
||||
Enhance OpenAPI security scopes handling
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Add stable scroll gutter to search container
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix robots.txt preventing favicon from being indexed.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Redo search scope UI
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@gitbook/react-openapi": patch
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Highlight discriminator properties in oneOf, allOf, anyOf objects
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Make search accessible
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@gitbook/react-openapi": patch
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Adapt OpenAPI code samples to prefill API key using visitor data
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix markdownPageURL for PageActions
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Improve default site icon
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Use sitespace title instead of space title in search
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
'@gitbook/openapi-parser': patch
|
||||
'@gitbook/react-openapi': patch
|
||||
---
|
||||
|
||||
Add x-gitbook-prefix and x-gitbook-token-placeholder for OpenAPI security scheme
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Support nested site section groups
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": minor
|
||||
---
|
||||
|
||||
Show a toolbar for authenticated users with access to the current site.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Add support for inline expressions rendering with visitor data on GBO side
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Update to column width sizing
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": minor
|
||||
---
|
||||
|
||||
Move inline expression evaluation from API to GBO
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix rounded outline items
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@gitbook/react-openapi": patch
|
||||
---
|
||||
|
||||
Ensure operation security requirements inherits from spec-level when not defined
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": minor
|
||||
---
|
||||
|
||||
Add Italian translation
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Expose "Best match" when site has translations
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Improve screen reader accessibility for hints
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Add alt text to inline image
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@gitbook/react-openapi": minor
|
||||
---
|
||||
|
||||
Fix OpenAPISecurities and code sample not using operation security requirements
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix crash for card cover defined without objectFit
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Improve wide page width layout
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Add scrollcontainer component
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix links to other spaces and root page in embeddable view.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Refactor section tabs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix button content truncate
|
||||
@@ -2,4 +2,4 @@
|
||||
'@gitbook/react-openapi': patch
|
||||
---
|
||||
|
||||
Fix OpenAPI basic auth placeholder
|
||||
Fix merge logic for allOf alternatives
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"gitbook": minor
|
||||
---
|
||||
|
||||
Add a RSS feed to all pages with update blocks.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'gitbook': patch
|
||||
---
|
||||
|
||||
Remove hidden site spaces from navigation
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'gitbook': patch
|
||||
---
|
||||
|
||||
Fix hidden section not found
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix OpenAPI response dropdown & vertical overflow
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@gitbook/react-openapi": patch
|
||||
---
|
||||
|
||||
Fix OpenAPI response showing as JSON instead of YAML when it should
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@gitbook/react-openapi": patch
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix OpenAPI alternatives not showing
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": minor
|
||||
---
|
||||
|
||||
Scope search across sections and variants
|
||||
@@ -54,9 +54,10 @@ After forking this repository, you'll want to [create a branch](https://docs.git
|
||||
#### 3. Install dependencies and run the project locally
|
||||
|
||||
##### Prerequisites:
|
||||
|
||||
- [Node.js](https://nodejs.org/en) (see "engines" in `package.json`)
|
||||
- [Bun](https://bun.sh/) (see "packageManager" in `package.json`)
|
||||
- Node.js (Version: >=20.6)
|
||||
- Use `nvm` for easy Node management
|
||||
- [Bun](https://bun.sh/) (Version: >=1.2.15)
|
||||
- We use a text-based lockfile which isn't supported below 1.2.15
|
||||
|
||||
##### Setup steps:
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ runs:
|
||||
apiToken: ${{ inputs.apiToken }}
|
||||
accountId: ${{ inputs.accountId }}
|
||||
workingDirectory: ./
|
||||
wranglerVersion: '4.43.0'
|
||||
wranglerVersion: '4.10.0'
|
||||
environment: ${{ inputs.environment }}
|
||||
command: deployments status --config ./packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc
|
||||
|
||||
@@ -49,7 +49,7 @@ runs:
|
||||
apiToken: ${{ inputs.apiToken }}
|
||||
accountId: ${{ inputs.accountId }}
|
||||
workingDirectory: ./
|
||||
wranglerVersion: '4.43.0'
|
||||
wranglerVersion: '4.10.0'
|
||||
environment: ${{ inputs.environment }}
|
||||
command: versions deploy ${{ steps.extract_current_version.outputs.version_id }}@100% ${{ inputs.serverVersionId }}@0% -y --config ./packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc
|
||||
|
||||
@@ -61,7 +61,7 @@ runs:
|
||||
apiToken: ${{ inputs.apiToken }}
|
||||
accountId: ${{ inputs.accountId }}
|
||||
workingDirectory: ./
|
||||
wranglerVersion: '4.43.0'
|
||||
wranglerVersion: '4.10.0'
|
||||
environment: ${{ inputs.environment }}
|
||||
command: versions deploy ${{ inputs.middlewareVersionId }}@100% -y --config ./packages/gitbook/openNext/customWorkers/middlewareWrangler.jsonc
|
||||
|
||||
@@ -71,7 +71,7 @@ runs:
|
||||
apiToken: ${{ inputs.apiToken }}
|
||||
accountId: ${{ inputs.accountId }}
|
||||
workingDirectory: ./
|
||||
wranglerVersion: '4.43.0'
|
||||
wranglerVersion: '4.10.0'
|
||||
environment: ${{ inputs.environment }}
|
||||
command: versions deploy ${{ inputs.serverVersionId }}@100% -y --config ./packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ runs:
|
||||
apiToken: ${{ inputs.apiToken }}
|
||||
accountId: ${{ inputs.accountId }}
|
||||
workingDirectory: ./
|
||||
wranglerVersion: '4.43.0'
|
||||
wranglerVersion: '4.10.0'
|
||||
environment: ${{ inputs.environment }}
|
||||
command: deploy --config ./packages/gitbook/openNext/customWorkers/doWrangler.jsonc
|
||||
|
||||
@@ -81,7 +81,7 @@ runs:
|
||||
apiToken: ${{ inputs.apiToken }}
|
||||
accountId: ${{ inputs.accountId }}
|
||||
workingDirectory: ./
|
||||
wranglerVersion: '4.43.0'
|
||||
wranglerVersion: '4.10.0'
|
||||
environment: ${{ inputs.environment }}
|
||||
command: ${{ format('versions upload --tag {0} --message "{1}"', inputs.commitTag, inputs.commitMessage) }} --config ./packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc
|
||||
|
||||
@@ -104,7 +104,7 @@ runs:
|
||||
apiToken: ${{ inputs.apiToken }}
|
||||
accountId: ${{ inputs.accountId }}
|
||||
workingDirectory: ./
|
||||
wranglerVersion: '4.43.0'
|
||||
wranglerVersion: '4.10.0'
|
||||
environment: ${{ inputs.environment }}
|
||||
command: ${{ format('versions upload --tag {0} --message "{1}"', inputs.commitTag, inputs.commitMessage) }} --config ./packages/gitbook/openNext/customWorkers/middlewareWrangler.jsonc
|
||||
|
||||
|
||||
@@ -4,9 +4,8 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- changeset-release/main
|
||||
env:
|
||||
BUN_NPM_TOKEN: ${{ secrets.NPM_TOKEN_READONLY }}
|
||||
NPM_TOKEN_READONLY: ${{ secrets.NPM_TOKEN_READONLY }}
|
||||
jobs:
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -42,7 +41,7 @@ jobs:
|
||||
name: Build (Open Source)
|
||||
timeout-minutes: 6
|
||||
env:
|
||||
BUN_NPM_TOKEN: ''
|
||||
NPM_TOKEN_READONLY: ''
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -5,7 +5,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
env:
|
||||
BUN_NPM_TOKEN: ${{ secrets.NPM_TOKEN_READONLY }}
|
||||
NPM_TOKEN_READONLY: ${{ secrets.NPM_TOKEN_READONLY }}
|
||||
jobs:
|
||||
deploy-v2-vercel:
|
||||
name: Deploy v2 to Vercel (preview)
|
||||
|
||||
@@ -4,7 +4,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
env:
|
||||
BUN_NPM_TOKEN: ${{ secrets.NPM_TOKEN_READONLY }}
|
||||
NPM_TOKEN_READONLY: ${{ secrets.NPM_TOKEN_READONLY }}
|
||||
jobs:
|
||||
deploy-v2-vercel:
|
||||
name: Deploy v2 to Vercel (production)
|
||||
|
||||
@@ -4,7 +4,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
env:
|
||||
BUN_NPM_TOKEN: ${{ secrets.NPM_TOKEN_READONLY }}
|
||||
NPM_TOKEN_READONLY: ${{ secrets.NPM_TOKEN_READONLY }}
|
||||
jobs:
|
||||
deploy-v2-vercel:
|
||||
name: Deploy v2 to Vercel (staging)
|
||||
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
- main
|
||||
|
||||
env:
|
||||
BUN_NPM_TOKEN: ${{ secrets.NPM_TOKEN_READONLY }}
|
||||
NPM_TOKEN_READONLY: ${{ secrets.NPM_TOKEN_READONLY }}
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
@@ -14,38 +14,29 @@ jobs:
|
||||
publish:
|
||||
name: Publish
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
pull-requests: write
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
|
||||
fetch-depth: 0
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
# Ensure npm 11.5.1 or later is installed
|
||||
- name: Update npm
|
||||
run: npm install -g npm@latest
|
||||
- name: Setup Bun
|
||||
uses: ./.github/composite/setup-bun
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
env:
|
||||
PUPPETEER_SKIP_DOWNLOAD: 1
|
||||
- name: Create Release Pull Request
|
||||
- name: Create Release Pull Request or Publish to npm
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
publish: bun run publish-all-packages
|
||||
version: bun run changeset-version
|
||||
publish: npm run release
|
||||
version: npm run changeset-version
|
||||
env:
|
||||
# Using a PAT instead of GITHUB_TOKEN because we need to run workflows when releases are created
|
||||
# https://github.com/orgs/community/discussions/26875#discussioncomment-3253761
|
||||
GITHUB_TOKEN: ${{ secrets.GH_PERSONAL_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
|
||||
|
||||
@@ -25,7 +25,3 @@ yarn-error.log*
|
||||
|
||||
# TypeScript
|
||||
*.tsbuildinfo
|
||||
.npmrc
|
||||
|
||||
# Bun pack artifacts
|
||||
packages/*/*.tgz
|
||||
|
||||
@@ -35,7 +35,7 @@ To run a local version of this project, please follow these simple steps.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js (Version: >= 22.3)
|
||||
- Node.js (Version: >=20.6)
|
||||
- Use nvm for easy Node management
|
||||
- [Bun](https://bun.sh/) (Version: >=1.2.15)
|
||||
- We use a text-based lockfile which isn't supported below 1.2.15
|
||||
@@ -90,7 +90,7 @@ If you are GitBook staff, you'll need our NPM token in your local environment.
|
||||
```
|
||||
.env.local
|
||||
|
||||
BUN_NPM_TOKEN=xxx
|
||||
NPM_TOKEN_READONLY=xxx
|
||||
```
|
||||
|
||||
and then reinstall dependencies.
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
[install.scopes]
|
||||
"gitbook" = { token = "$BUN_NPM_TOKEN", url = "https://registry.npmjs.org" }
|
||||
"gitbook" = { token = "$NPM_TOKEN_READONLY", url = "https://registry.npmjs.org" }
|
||||
|
||||
+10
-28
@@ -1,22 +1,17 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "0.1.0",
|
||||
"engines": {
|
||||
"node": "^22.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.4",
|
||||
"@changesets/cli": "^2.29.7",
|
||||
"turbo": "^2.6.1",
|
||||
"vercel": "^39.4.2"
|
||||
"@changesets/cli": "^2.27.12",
|
||||
"turbo": "^2.5.0",
|
||||
"vercel": "^39.3.0"
|
||||
},
|
||||
"packageManager": "bun@1.3.2",
|
||||
"packageManager": "bun@1.2.15",
|
||||
"overrides": {
|
||||
"@codemirror/state": "6.4.1",
|
||||
"@types/react": "catalog:",
|
||||
"@types/react-dom": "catalog:",
|
||||
"react": "catalog:",
|
||||
"react-dom": "catalog:",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"esbuild": "0.24.2"
|
||||
},
|
||||
"private": true,
|
||||
@@ -31,29 +26,16 @@
|
||||
"e2e": "turbo run e2e",
|
||||
"e2e-customers": "turbo run e2e-customers",
|
||||
"changeset": "changeset",
|
||||
"changeset-version": "changeset version && bun run format && bun update",
|
||||
"publish-all-packages": "turbo run publish-to-npm --continue=dependencies-successful",
|
||||
"changeset-version": "changeset version && bun run format",
|
||||
"release": "turbo run release && changeset publish",
|
||||
"download:env": "op read op://gitbook-x-dev/gitbook-open/.env.local >> .env.local",
|
||||
"clean": "turbo run clean"
|
||||
},
|
||||
"workspaces": {
|
||||
"packages": ["packages/*"],
|
||||
"catalog": {
|
||||
"@tsconfig/strictest": "^2.0.6",
|
||||
"@tsconfig/node20": "^20.1.6",
|
||||
"@gitbook/api": "0.151.0",
|
||||
"@scalar/api-client-react": "^1.3.46",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
"assert-never": "^1.4.0",
|
||||
"bidc": "^0.0.2",
|
||||
"bun-types": "^1.1.20",
|
||||
"classnames": "^2.5.1",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"tsdown": "^0.15.6",
|
||||
"typescript": "^5.5.3",
|
||||
"usehooks-ts": "^3.1.1"
|
||||
"@gitbook/api": "0.143.2",
|
||||
"bidc": "^0.0.2"
|
||||
}
|
||||
},
|
||||
"patchedDependencies": {
|
||||
|
||||
@@ -1,29 +1,5 @@
|
||||
# @gitbook/browser-types
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 10995e0: Use NPM Trusted publishing for publishing the package.
|
||||
- Updated dependencies [10995e0]
|
||||
- @gitbook/icons@0.3.4
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6142d6b: Mark as sideEffects, fix all package bundles
|
||||
- Updated dependencies [6142d6b]
|
||||
- @gitbook/icons@0.3.3
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 295f03d: Republish packages
|
||||
- Updated dependencies [295f03d]
|
||||
- @gitbook/icons@0.3.2
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -8,29 +8,17 @@
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"sideEffects": false,
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@gitbook/api": "catalog:",
|
||||
"@gitbook/icons": "workspace:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bun-types": "catalog:",
|
||||
"tsdown": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
"typescript": "^5.5.3"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"dev": "bun run build -- --watch ./src",
|
||||
"publish-to-npm": "../../scripts/publish-if-new.sh"
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"files": ["dist", "README.md", "CHANGELOG.md"],
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"repository": {
|
||||
"url": "https://github.com/GitbookIO/gitbook"
|
||||
}
|
||||
"files": ["dist", "README.md", "CHANGELOG.md"]
|
||||
}
|
||||
|
||||
@@ -1,23 +1,5 @@
|
||||
# @gitbook/cache-tags
|
||||
|
||||
## 0.3.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 10995e0: Use NPM Trusted publishing for publishing the package.
|
||||
|
||||
## 0.3.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6142d6b: Mark as sideEffects, fix all package bundles
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 295f03d: Republish packages
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -4,32 +4,22 @@
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"development": "./src/index.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"sideEffects": false,
|
||||
"version": "0.3.4",
|
||||
"version": "0.3.1",
|
||||
"dependencies": {
|
||||
"@gitbook/api": "catalog:",
|
||||
"assert-never": "catalog:"
|
||||
"assert-never": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bun-types": "catalog:",
|
||||
"tsdown": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
"typescript": "^5.5.3"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"dev": "bun run build -- --watch ./src",
|
||||
"publish-to-npm": "../../scripts/publish-if-new.sh"
|
||||
"dev": "tsc -w"
|
||||
},
|
||||
"files": ["dist", "README.md", "CHANGELOG.md"],
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"repository": {
|
||||
"url": "https://github.com/GitbookIO/gitbook"
|
||||
}
|
||||
"files": ["dist", "src", "README.md", "CHANGELOG.md"]
|
||||
}
|
||||
|
||||
@@ -1,23 +1,5 @@
|
||||
# @gitbook/colors
|
||||
|
||||
## 0.4.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 10995e0: Use NPM Trusted publishing for publishing the package.
|
||||
|
||||
## 0.4.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6142d6b: Mark as sideEffects, fix all package bundles
|
||||
|
||||
## 0.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 295f03d: Republish packages
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -4,28 +4,18 @@
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"development": "./src/index.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"sideEffects": false,
|
||||
"version": "0.4.3",
|
||||
"version": "0.4.0",
|
||||
"devDependencies": {
|
||||
"bun-types": "catalog:",
|
||||
"tsdown": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
"typescript": "^5.5.3"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"dev": "bun run build -- --watch ./src",
|
||||
"publish-to-npm": "../../scripts/publish-if-new.sh"
|
||||
"dev": "tsc -w"
|
||||
},
|
||||
"files": ["dist", "README.md", "CHANGELOG.md"],
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"repository": {
|
||||
"url": "https://github.com/GitbookIO/gitbook"
|
||||
}
|
||||
"files": ["dist", "src", "README.md", "CHANGELOG.md"]
|
||||
}
|
||||
|
||||
@@ -1,35 +1,5 @@
|
||||
# @gitbook/embed
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 10995e0: Use NPM Trusted publishing for publishing the package.
|
||||
- Updated dependencies [10995e0]
|
||||
- @gitbook/icons@0.3.4
|
||||
|
||||
## 0.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6142d6b: Mark as sideEffects, fix all package bundles
|
||||
- Updated dependencies [6142d6b]
|
||||
- @gitbook/icons@0.3.3
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 295f03d: Republish packages
|
||||
- Updated dependencies [295f03d]
|
||||
- @gitbook/icons@0.3.2
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 7508674: Fix bundling of packages
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
+10
-27
@@ -5,44 +5,27 @@
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./react": {
|
||||
"types": "./dist/react/index.d.ts",
|
||||
"default": "./dist/react/index.js"
|
||||
"default": "./dist/index.js",
|
||||
"standalone": "./dist/standalone/index.js",
|
||||
"react": "./dist/react/index.js"
|
||||
}
|
||||
},
|
||||
"sideEffects": false,
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.1",
|
||||
"dependencies": {
|
||||
"@gitbook/api": "catalog:",
|
||||
"@gitbook/icons": "workspace:",
|
||||
"bidc": "catalog:"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
"react": "^18.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "catalog:",
|
||||
"tsdown": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
"react": "catalog:"
|
||||
"typescript": "^5.5.3",
|
||||
"react": "^19.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "bun run build-lib && bun run build-standalone",
|
||||
"build-lib": "tsdown",
|
||||
"build-standalone": "bun build src/standalone/index.ts --bundle --minify --outdir=standalone",
|
||||
"clean": "rm -rf ./dist",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"dev": "bun run build -- --watch ./src",
|
||||
"publish-to-npm": "../../scripts/publish-if-new.sh"
|
||||
"build": "tsc && bun build src/standalone/index.ts --bundle --minify --outdir=standalone",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"files": ["dist", "README.md", "CHANGELOG.md"],
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"repository": {
|
||||
"url": "https://github.com/GitbookIO/gitbook"
|
||||
}
|
||||
"files": ["dist", "README.md", "CHANGELOG.md", "standalone"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import React from 'react';
|
||||
import type {
|
||||
GetFrameURLOptions,
|
||||
GitBookEmbeddableConfiguration,
|
||||
@@ -19,19 +17,19 @@ export type GitBookFrameProps = {
|
||||
export function GitBookFrame(props: GitBookFrameProps) {
|
||||
const { className, visitor, buttons, welcomeMessage, suggestions, tools } = props;
|
||||
|
||||
const frameRef = useRef<HTMLIFrameElement>(null);
|
||||
const frameRef = React.useRef<HTMLIFrameElement>(null);
|
||||
const gitbook = useGitBook();
|
||||
const [gitbookFrame, setGitbookFrame] = useState<GitBookFrameClient | null>(null);
|
||||
const [gitbookFrame, setGitbookFrame] = React.useState<GitBookFrameClient | null>(null);
|
||||
|
||||
const frameURL = useMemo(() => gitbook.getFrameURL({ visitor }), [gitbook, visitor]);
|
||||
const frameURL = React.useMemo(() => gitbook.getFrameURL({ visitor }), [gitbook, visitor]);
|
||||
|
||||
useEffect(() => {
|
||||
React.useEffect(() => {
|
||||
if (frameRef.current) {
|
||||
setGitbookFrame(gitbook.createFrame(frameRef.current));
|
||||
}
|
||||
}, [gitbook]);
|
||||
|
||||
useEffect(() => {
|
||||
React.useEffect(() => {
|
||||
gitbookFrame?.configure({
|
||||
buttons,
|
||||
welcomeMessage,
|
||||
|
||||
@@ -29,16 +29,6 @@
|
||||
--gitbook-widget-easing-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--gitbook-widget-text-color: #FFFFFF;
|
||||
--gitbook-widget-border-color: #202020;
|
||||
--gitbook-widget-background-translucent: rgba(15, 15, 15, 0.9);
|
||||
--gitbook-widget-background-translucent-hover: rgba(20, 20, 20, 0.9);
|
||||
--gitbook-widget-background-solid: #f0f0f0;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -130,8 +120,7 @@
|
||||
z-index: 9998;
|
||||
width: calc(min(var(--gitbook-widget-window-width), calc(100vw - var(--gitbook-widget-right) - var(--gitbook-widget-left))));
|
||||
height: calc(min(var(--gitbook-widget-window-height), calc(100vh - var(--gitbook-widget-window-bottom) - var(--gitbook-widget-top))));
|
||||
background-color: var(--gitbook-widget-background-translucent);
|
||||
backdrop-filter: blur(48px);
|
||||
background-color: var(--gitbook-widget-background-solid);
|
||||
border: 1px solid var(--gitbook-widget-border-color);
|
||||
border-radius: var(--gitbook-widget-radius);
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { defineConfig } from 'tsdown';
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
entry: 'src/index.ts',
|
||||
outDir: 'dist',
|
||||
},
|
||||
{
|
||||
entry: 'src/react/index.ts',
|
||||
outDir: 'dist/react',
|
||||
unbundle: true,
|
||||
},
|
||||
]);
|
||||
@@ -1,25 +1,13 @@
|
||||
# @gitbook/emoji-codepoints
|
||||
|
||||
## 0.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6142d6b: Mark as sideEffects, fix all package bundles
|
||||
|
||||
## 0.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 295f03d: Republish packages
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 57adb3e: Second release to fix publishing with changeset
|
||||
- 57adb3e: Second release to fix publishing with changeset
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 5f8a8fe: Initial release
|
||||
- 5f8a8fe: Initial release
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@gitbook/emoji-codepoints",
|
||||
"description": "Optimized mapping of codepoints to the fully qualified emoji codepoints",
|
||||
"version": "0.2.2",
|
||||
"version": "0.2.0",
|
||||
"private": true,
|
||||
"exports": "./dist/index.ts",
|
||||
"sideEffects": false,
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"emoji-assets": "^9.0.0"
|
||||
"emoji-assets": "^8.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"generate": "bun ./build.ts",
|
||||
|
||||
@@ -1,30 +1,5 @@
|
||||
# @gitbook/expr
|
||||
|
||||
## 1.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 10995e0: Use NPM Trusted publishing for publishing the package.
|
||||
- 10995e0: Use NPM dependency for eval-estree-expression
|
||||
|
||||
## 1.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6142d6b: Mark as sideEffects, fix all package bundles
|
||||
|
||||
## 1.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 295f03d: Republish packages
|
||||
|
||||
## 1.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a629900: Add dev script for @gitbook/expr
|
||||
|
||||
## 1.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
+11
-20
@@ -1,47 +1,38 @@
|
||||
{
|
||||
"name": "@gitbook/expr",
|
||||
"description": "Safely evaluate & parse user-defined GitBook expressions.",
|
||||
"version": "1.2.4",
|
||||
"version": "1.2.0",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"sideEffects": false,
|
||||
"dependencies": {
|
||||
"eval-estree-expression": "github:jonschlinkert/eval-estree-expression#9cf28d2",
|
||||
"acorn": "^8.14.0",
|
||||
"acorn-loose": "8.4.0",
|
||||
"acorn-walk": "^8.3.4",
|
||||
"assert-never": "catalog:",
|
||||
"escodegen": "^2.1.0",
|
||||
"eval-estree-expression": "github:jonschlinkert/eval-estree-expression#fb0246a"
|
||||
"assert-never": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/strictest": "catalog:",
|
||||
"@tsconfig/node20": "catalog:",
|
||||
"@types/escodegen": "^0.0.10",
|
||||
"bun-types": "^1.1.20",
|
||||
"tsdown": "^0.15.0",
|
||||
"@types/estree": "^1.0.6",
|
||||
"@babel/types": "^7.26.0",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"bun-types": "catalog:",
|
||||
"tsdown": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
"@types/escodegen": "^0.0.10"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"build": "tsdown --project tsconfig.build.json",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"unit": "bun test",
|
||||
"clean": "rm -rf ./dist",
|
||||
"dev": "bun run build -- --watch ./src",
|
||||
"publish-to-npm": "../../scripts/publish-if-new.sh"
|
||||
"dev": "bun run build -- --watch"
|
||||
},
|
||||
"files": ["dist", "README.md", "CHANGELOG.md"],
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"repository": {
|
||||
"url": "https://github.com/GitbookIO/gitbook"
|
||||
}
|
||||
"files": ["dist", "README.md", "CHANGELOG.md"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": ["./tsconfig.json"],
|
||||
"exclude": ["**/*.test.ts"],
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"noEmit": false,
|
||||
"outDir": "dist"
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,8 @@ import { defineConfig } from 'tsdown';
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
entry: ['src/index.ts', 'src/icons.ts'],
|
||||
unbundle: true,
|
||||
entry: ['src/index.ts'],
|
||||
dts: true,
|
||||
format: ['esm'],
|
||||
},
|
||||
]);
|
||||
@@ -1,23 +1,5 @@
|
||||
# @gitbook/fonts
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 10995e0: Use NPM Trusted publishing for publishing the package.
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6142d6b: Mark as sideEffects, fix all package bundles
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 295f03d: Republish packages
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -4,38 +4,28 @@
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"development": "./src/index.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"sideEffects": false,
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@gitbook/api": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bun-types": "catalog:",
|
||||
"google-font-metadata": "^6.0.7",
|
||||
"tsdown": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
"google-font-metadata": "^6.0.3",
|
||||
"typescript": "^5.5.3"
|
||||
},
|
||||
"scripts": {
|
||||
"generate": "bun ./bin/generate.js",
|
||||
"build": "tsdown",
|
||||
"build": "tsc --project tsconfig.build.json",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"dev": "bun run build -- --watch ./src",
|
||||
"dev": "tsc -w",
|
||||
"clean": "rm -rf ./dist && rm -rf ./src/data",
|
||||
"unit": "bun test",
|
||||
"publish-to-npm": "../../scripts/publish-if-new.sh"
|
||||
"unit": "bun test"
|
||||
},
|
||||
"files": ["dist", "bin", "README.md", "CHANGELOG.md"],
|
||||
"files": ["dist", "src", "bin", "README.md", "CHANGELOG.md"],
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"repository": {
|
||||
"url": "https://github.com/GitbookIO/gitbook"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +1,57 @@
|
||||
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots
|
||||
// Bun Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`getDefaultFont should return correct object for Latin text 1`] = `
|
||||
{
|
||||
"font": "Inter",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZ9hjp-Ek-_0ew.woff",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZ9hjp-Ek-_0ew.woff",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`getDefaultFont should return correct object for Cyrillic text 1`] = `
|
||||
{
|
||||
"font": "Inter",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZthjp-Ek-_0ewmM.woff",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZthjp-Ek-_0ewmM.woff",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`getDefaultFont should return correct object for Greek text 1`] = `
|
||||
{
|
||||
"font": "Inter",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZxhjp-Ek-_0ewmM.woff",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZxhjp-Ek-_0ewmM.woff",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`getDefaultFont should handle mixed script text 1`] = `
|
||||
{
|
||||
"font": "Inter",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZthjp-Ek-_0ewmM.woff",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZthjp-Ek-_0ewmM.woff",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`getDefaultFont should handle different font weights: regular 1`] = `
|
||||
{
|
||||
"font": "Inter",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZ9hjp-Ek-_0ew.woff",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZ9hjp-Ek-_0ew.woff",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`getDefaultFont should handle different font weights: bold 1`] = `
|
||||
{
|
||||
"font": "Inter",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuFuYAZ9hjp-Ek-_0ew.woff",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuFuYAZ9hjp-Ek-_0ew.woff",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`getDefaultFont should handle different fonts: inter 1`] = `
|
||||
{
|
||||
"font": "Inter",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZ9hjp-Ek-_0ew.woff",
|
||||
"url": "https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZ9hjp-Ek-_0ew.woff",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`getDefaultFont should handle different fonts: roboto 1`] = `
|
||||
{
|
||||
"font": "Roboto",
|
||||
"url": "https://fonts.gstatic.com/s/roboto/v49/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmUiAz0klQm_20.woff",
|
||||
"url": "https://fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxMKTU1Kg.woff",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "src/**/*.test.ts"]
|
||||
}
|
||||
@@ -1,149 +1,5 @@
|
||||
# gitbook
|
||||
|
||||
## 0.20.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 1d92dc1: Update site layout and blocks with container queries and better transitions
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 8fdc5c8: Fix webframe height issue
|
||||
- 9022d87: Add breadcrumbs to search results
|
||||
- 0c01832: SearchInput fixes — Translate Clear button, Bold theme color, "Esc" keyboard shortcut
|
||||
- 1d1f0a7: Fix search container shadow
|
||||
- 2aa4f2e: Update dropdown menu styling
|
||||
- a49781e: Printable collapsed code block
|
||||
- 7d6a316: Revert contentref anchor title
|
||||
- e27986b: Reword "Everywhere" search scope to "All docs"
|
||||
- 758b34d: Move the "Ask <query>" to the bottom of search results if query is not a question
|
||||
- 0ae7cfd: Improve AI Search branding
|
||||
- f9f8011: Add alt text support to card covers
|
||||
- ebbb476: Improve ancestor label in references
|
||||
- 1b0613e: Tweak language dropdown styling
|
||||
- 3355960: Fix ToggeableLinkItem display
|
||||
- c31e564: Fix icon resolution for page group
|
||||
- 55c0b03: Support translations and generic variants together
|
||||
- 3876f70: Edgeless Assistant window on `depth: flat` sites
|
||||
- 683bb8f: Add confirmation to "Copy MCP URL" page action
|
||||
- 4534ea8: Implement unique title tags for sections & variants
|
||||
- 6d56df7: Treat pages without visible TOC items as `no-toc`
|
||||
- 8606f22: Add padding to TOC page group items
|
||||
- 3676d64: Update search scope UI
|
||||
- c32d449: Fix OpenAPI path display
|
||||
- 8ce7322: Add OpenAPI servers selection
|
||||
- 2c3066e: Improve OAuth2 scopes handling in OpenAPI
|
||||
- 6b1c9fe: Fix opacity of ScrollContainer buttons on bold themes
|
||||
- Updated dependencies [b4a021a]
|
||||
- Updated dependencies [a512c90]
|
||||
- Updated dependencies [df1966d]
|
||||
- Updated dependencies [b45feaf]
|
||||
- Updated dependencies [10995e0]
|
||||
- Updated dependencies [f9f8011]
|
||||
- Updated dependencies [10995e0]
|
||||
- Updated dependencies [8ce7322]
|
||||
- Updated dependencies [2c3066e]
|
||||
- @gitbook/react-openapi@1.5.3
|
||||
- @gitbook/openapi-parser@3.0.5
|
||||
- @gitbook/react-contentkit@0.7.8
|
||||
- @gitbook/browser-types@0.1.3
|
||||
- @gitbook/cache-tags@0.3.4
|
||||
- @gitbook/react-math@0.6.4
|
||||
- @gitbook/colors@0.4.3
|
||||
- @gitbook/embed@0.1.5
|
||||
- @gitbook/fonts@0.1.3
|
||||
- @gitbook/icons@0.3.4
|
||||
- @gitbook/expr@1.2.4
|
||||
|
||||
## 0.19.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6142d6b: Mark as sideEffects, fix all package bundles
|
||||
- 75543b1: Update minimum Node version in .npmrc
|
||||
- 511f1cf: Add scroll margin to Expandable
|
||||
- Updated dependencies [6142d6b]
|
||||
- @gitbook/emoji-codepoints@0.2.2
|
||||
- @gitbook/react-contentkit@0.7.7
|
||||
- @gitbook/openapi-parser@3.0.4
|
||||
- @gitbook/browser-types@0.1.2
|
||||
- @gitbook/react-openapi@1.5.2
|
||||
- @gitbook/cache-tags@0.3.3
|
||||
- @gitbook/react-math@0.6.3
|
||||
- @gitbook/colors@0.4.2
|
||||
- @gitbook/fonts@0.1.2
|
||||
- @gitbook/icons@0.3.3
|
||||
- @gitbook/expr@1.2.3
|
||||
|
||||
## 0.19.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 295f03d: Republish packages
|
||||
- Updated dependencies [bdde392]
|
||||
- Updated dependencies [295f03d]
|
||||
- @gitbook/react-contentkit@0.7.6
|
||||
- @gitbook/browser-types@0.1.1
|
||||
- @gitbook/cache-tags@0.3.2
|
||||
- @gitbook/colors@0.4.1
|
||||
- @gitbook/emoji-codepoints@0.2.1
|
||||
- @gitbook/expr@1.2.2
|
||||
- @gitbook/fonts@0.1.1
|
||||
- @gitbook/icons@0.3.2
|
||||
- @gitbook/openapi-parser@3.0.3
|
||||
- @gitbook/react-math@0.6.2
|
||||
- @gitbook/react-openapi@1.5.1
|
||||
|
||||
## 0.19.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ed7d47d: Show a toolbar for authenticated users with access to the current site.
|
||||
- 50c1be3: Move inline expression evaluation from API to GBO
|
||||
- 56e46ce: Add Italian translation
|
||||
- b932e4e: Scope search across sections and variants
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 162cfe4: Hide sections if only one is present
|
||||
- 1456251: Unify section display condition
|
||||
- 9344431: Fix missing geo data in site insights because of incorrect proxying of events.
|
||||
- eea8f1e: Enhance OpenAPI security scopes handling
|
||||
- 2b8a2d2: Add stable scroll gutter to search container
|
||||
- b498521: Fix robots.txt preventing favicon from being indexed.
|
||||
- ceb32b1: Redo search scope UI
|
||||
- 8e99871: Highlight discriminator properties in oneOf, allOf, anyOf objects
|
||||
- 2fc2127: Make search accessible
|
||||
- f3e4041: Adapt OpenAPI code samples to prefill API key using visitor data
|
||||
- 6815dd1: Fix markdownPageURL for PageActions
|
||||
- c06b3dd: Improve default site icon
|
||||
- cba583a: Use sitespace title instead of space title in search
|
||||
- e434442: Support nested site section groups
|
||||
- 469b332: Add support for inline expressions rendering with visitor data on GBO side
|
||||
- 0ef5dc8: Update to column width sizing
|
||||
- 1e4e54e: Fix rounded outline items
|
||||
- 379d486: Expose "Best match" when site has translations
|
||||
- c21693f: Improve screen reader accessibility for hints
|
||||
- badf3a9: Add alt text to inline image
|
||||
- c23d4ef: Fix crash for card cover defined without objectFit
|
||||
- d74f8a7: Improve wide page width layout
|
||||
- b8388e5: Add scrollcontainer component
|
||||
- b85eccd: Refactor section tabs
|
||||
- 1e53f46: Fix button content truncate
|
||||
- 7a504b7: Fix OpenAPI response dropdown & vertical overflow
|
||||
- a4c3399: Fix OpenAPI alternatives not showing
|
||||
- Updated dependencies [a629900]
|
||||
- Updated dependencies [eea8f1e]
|
||||
- Updated dependencies [8e99871]
|
||||
- Updated dependencies [f3e4041]
|
||||
- Updated dependencies [319a1e5]
|
||||
- Updated dependencies [529f940]
|
||||
- Updated dependencies [754cc11]
|
||||
- Updated dependencies [d7948e3]
|
||||
- Updated dependencies [a4c3399]
|
||||
- @gitbook/expr@1.2.1
|
||||
- @gitbook/react-openapi@1.5.0
|
||||
|
||||
## 0.18.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -112,11 +112,11 @@ const testCases: TestsCase[] = [
|
||||
contentBaseURL: 'https://adiblar.gitbook.io',
|
||||
tests: [{ name: 'Home', url: '/' }],
|
||||
},
|
||||
// {
|
||||
// name: 'docs.gradient.network',
|
||||
// contentBaseURL: 'https://docs.gradient.network',
|
||||
// tests: [{ name: 'Home', url: '/' }],
|
||||
// },
|
||||
{
|
||||
name: 'docs.gradient.network',
|
||||
contentBaseURL: 'https://docs.gradient.network',
|
||||
tests: [{ name: 'Home', url: '/' }],
|
||||
},
|
||||
// {
|
||||
// name: 'mygate-network.gitbook.io',
|
||||
// contentBaseURL: 'https://mygate-network.gitbook.io',
|
||||
@@ -172,6 +172,11 @@ const testCases: TestsCase[] = [
|
||||
contentBaseURL: 'https://docs.realapp.link',
|
||||
tests: [{ name: 'Home', url: '/' }],
|
||||
},
|
||||
{
|
||||
name: 'docs.plaza.finance',
|
||||
contentBaseURL: 'https://docs.plaza.finance',
|
||||
tests: [{ name: 'Home', url: '/' }],
|
||||
},
|
||||
{
|
||||
name: 'docs.publicai.io',
|
||||
contentBaseURL: 'https://docs.publicai.io',
|
||||
|
||||
@@ -33,35 +33,9 @@ import {
|
||||
headerLinks,
|
||||
runTestCases,
|
||||
waitForCookiesDialog,
|
||||
waitForCoverImages,
|
||||
waitForNotFound,
|
||||
} from './util';
|
||||
|
||||
const AI_PROMPT = `You're being invoked by the GitBook CI/CD pipeline. To make screenshot testing of the GitBook Assistant visually consistent, look up the title of the first page you find and respond with only EXACTLY its title. To find the page title, invoke the search tool with the query "GitBook". Before invoking the search tool, respond with the exact text: "I'm going to look up 'GitBook' and then respond with only the page title.". Do not execute any other tools or output any other text.`;
|
||||
|
||||
const overrideAIInitialState = () => {
|
||||
const greeting = document.querySelector('[data-testid="ai-chat-time-greeting"]');
|
||||
if (greeting) {
|
||||
greeting.textContent = 'Good morning';
|
||||
}
|
||||
};
|
||||
const overrideAIResponse = () => {
|
||||
const userMessage = document.querySelector('[data-testid="ai-chat-message-user"]');
|
||||
if (userMessage) {
|
||||
userMessage.textContent = '[Replaced message] Chat message sent by the user';
|
||||
}
|
||||
const assistantMessage = document.querySelectorAll(
|
||||
'[data-testid="ai-chat-message-assistant"] .ai-response-document'
|
||||
);
|
||||
assistantMessage.forEach((message) => {
|
||||
message.innerHTML = '[Replaced message] AI chat response';
|
||||
});
|
||||
const suggestions = document.querySelectorAll('[data-testid="ai-chat-followup-suggestion"]');
|
||||
suggestions.forEach((suggestion) => {
|
||||
suggestion.textContent = 'Follow-up suggestion';
|
||||
});
|
||||
};
|
||||
|
||||
const searchTestCases: Test[] = [
|
||||
{
|
||||
name: 'Search - AI Mode: None - Complete flow',
|
||||
@@ -78,9 +52,7 @@ const searchTestCases: Test[] = [
|
||||
|
||||
// Fill search input, expecting search results
|
||||
await searchInput.fill('gitbook');
|
||||
await expect(page.getByTestId('search-results')).toBeVisible({
|
||||
timeout: 10_000,
|
||||
});
|
||||
await expect(page.getByTestId('search-results')).toBeVisible();
|
||||
const pageResults = await page.getByTestId('search-page-result').all();
|
||||
await expect(pageResults.length).toBeGreaterThanOrEqual(1);
|
||||
const pageSectionResults = await page.getByTestId('search-page-section-result').all();
|
||||
@@ -125,6 +97,9 @@ const searchTestCases: Test[] = [
|
||||
await expect(page.getByTestId('search-results')).toBeVisible();
|
||||
},
|
||||
},
|
||||
// TODO: Re-enable the following tests when we have fixed the AI Search timing out:
|
||||
// - Search - AI Mode: Search - Complete flow
|
||||
// - Search - AI Mode: Search - URL query (Initial)
|
||||
{
|
||||
name: 'Search - AI Mode: Search - URL query (Results)',
|
||||
url: `${getCustomizationURL({
|
||||
@@ -132,12 +107,16 @@ const searchTestCases: Test[] = [
|
||||
mode: CustomizationAIMode.Search,
|
||||
},
|
||||
})}&q=gitbook`,
|
||||
screenshot: false,
|
||||
run: async (page) => {
|
||||
await expect(page.getByTestId('search-input')).toBeFocused();
|
||||
await expect(page.getByTestId('search-input')).toHaveValue('gitbook');
|
||||
await expect(page.getByTestId('search-results')).toBeVisible();
|
||||
},
|
||||
},
|
||||
// TODO: Re-enable the following tests when we have fixed the AI Search timing out:
|
||||
// - Ask - AI Mode: Search - URL query (Ask initial)
|
||||
// - Ask - AI Mode: Search - URL query (Ask results)
|
||||
{
|
||||
name: 'Ask - AI Mode: Assistant - Complete flow',
|
||||
url: getCustomizationURL({
|
||||
@@ -145,32 +124,25 @@ const searchTestCases: Test[] = [
|
||||
mode: CustomizationAIMode.Assistant,
|
||||
},
|
||||
}),
|
||||
screenshot: false,
|
||||
run: async (page) => {
|
||||
const searchInput = page.locator('css=[data-testid="search-input"]');
|
||||
|
||||
// Focus search input, expecting recommended questions
|
||||
await searchInput.focus();
|
||||
await expect(page.getByTestId('search-results')).toBeVisible({
|
||||
timeout: 30_000,
|
||||
});
|
||||
const recommendedQuestions = await page
|
||||
.getByTestId('search-recommended-question')
|
||||
.all();
|
||||
await expect(recommendedQuestions.length).toBeGreaterThan(2); // Expect at least 3 questions
|
||||
// TODO: Re-enable this part of the test when we have fixed the AI Search timing out
|
||||
// await expect(page.getByTestId('search-results')).toBeVisible();
|
||||
// const recommendedQuestions = await page
|
||||
// .getByTestId('search-recommended-question')
|
||||
// .all();
|
||||
// await expect(recommendedQuestions.length).toBeGreaterThan(2); // Expect at least 3 questions
|
||||
|
||||
// Fill search input, expecting AI search option
|
||||
await searchInput.fill(AI_PROMPT);
|
||||
await searchInput.fill('What is gitbook?');
|
||||
const aiSearchResult = page.getByTestId('search-ask-question');
|
||||
await expect(aiSearchResult).toBeVisible();
|
||||
await aiSearchResult.click();
|
||||
await expect(page.getByTestId('ai-chat')).toBeVisible();
|
||||
await expect(page.getByTestId('ai-chat-message-user').first()).toHaveText(AI_PROMPT);
|
||||
await expect(page.getByTestId('ai-chat-message-assistant').first()).toBeVisible();
|
||||
await expect(page.getByTestId('ai-chat-followup-suggestion')).toHaveCount(3, {
|
||||
timeout: 60_000,
|
||||
});
|
||||
// Override text content for visual consistency in screenshots
|
||||
await page.evaluate(overrideAIResponse);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -180,12 +152,11 @@ const searchTestCases: Test[] = [
|
||||
mode: CustomizationAIMode.Assistant,
|
||||
},
|
||||
}),
|
||||
screenshot: false,
|
||||
run: async (page) => {
|
||||
await page.keyboard.press('ControlOrMeta+I');
|
||||
await expect(page.getByTestId('ai-chat')).toBeVisible();
|
||||
await expect(page.getByTestId('ai-chat-input')).toBeFocused();
|
||||
// Override text content for visual consistency in screenshots
|
||||
await page.evaluate(overrideAIInitialState);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -200,8 +171,6 @@ const searchTestCases: Test[] = [
|
||||
await page.getByTestId('ai-chat-button').click();
|
||||
await expect(page.getByTestId('ai-chat')).toBeVisible();
|
||||
await expect(page.getByTestId('ai-chat-input')).toBeFocused();
|
||||
// Override text content for visual consistency in screenshots
|
||||
await page.evaluate(overrideAIInitialState);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -211,13 +180,12 @@ const searchTestCases: Test[] = [
|
||||
mode: CustomizationAIMode.Assistant,
|
||||
},
|
||||
})}&ask=`,
|
||||
screenshot: false,
|
||||
run: async (page) => {
|
||||
await expect(page.getByTestId('search-input')).not.toBeFocused();
|
||||
await expect(page.getByTestId('search-input')).toBeEmpty();
|
||||
await expect(page.getByTestId('search-input')).not.toHaveValue('What is GitBook?');
|
||||
await expect(page.getByTestId('ai-chat')).toBeVisible();
|
||||
await expect(page.getByTestId('ai-chat-input')).toBeFocused();
|
||||
// Override text content for visual consistency in screenshots
|
||||
await page.evaluate(overrideAIInitialState);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -226,18 +194,17 @@ const searchTestCases: Test[] = [
|
||||
ai: {
|
||||
mode: CustomizationAIMode.Assistant,
|
||||
},
|
||||
})}&ask=${encodeURIComponent(AI_PROMPT)}`,
|
||||
})}&ask=What+is+GitBook%3F`,
|
||||
screenshot: false,
|
||||
run: async (page) => {
|
||||
await expect(page.getByTestId('search-input')).not.toBeFocused();
|
||||
await expect(page.getByTestId('search-input')).not.toHaveValue('What is GitBook?');
|
||||
await expect(page.getByTestId('ai-chat')).toBeVisible();
|
||||
await expect(page.getByTestId('ai-chat-message-user').first()).toHaveText(AI_PROMPT);
|
||||
await expect(page.getByTestId('ai-chat-message-assistant').first()).toBeVisible();
|
||||
await expect(page.getByTestId('ai-chat-followup-suggestion')).toHaveCount(3, {
|
||||
timeout: 60_000,
|
||||
await expect(page.getByTestId('ai-chat')).toBeVisible({
|
||||
timeout: 15_000,
|
||||
});
|
||||
// Override text content for visual consistency in screenshots
|
||||
await page.evaluate(overrideAIResponse);
|
||||
await expect(page.getByTestId('ai-chat-message').first()).toHaveText(
|
||||
'What is GitBook?'
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -261,58 +228,6 @@ const testCases: TestsCase[] = [
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Expandable TOC navigation',
|
||||
url: '',
|
||||
run: async (page) => {
|
||||
await waitForCookiesDialog(page);
|
||||
|
||||
// Verify "Navigation" link is not visible initially
|
||||
const navigationLink = page.getByRole('link', { name: 'Navigation' });
|
||||
await expect(navigationLink).not.toBeVisible();
|
||||
|
||||
// Find and click the chevron element that is next to "Editor" in the TOC
|
||||
// It is a span inside the link
|
||||
const editorChevron = page
|
||||
.getByRole('link', { name: 'Editor' })
|
||||
.locator('span');
|
||||
await editorChevron.click();
|
||||
|
||||
// Verify "Navigation" link becomes visible after expansion
|
||||
await expect(navigationLink).toBeVisible();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Expandable nested TOC navigation',
|
||||
url: '',
|
||||
screenshot: false,
|
||||
run: async (page) => {
|
||||
await waitForCookiesDialog(page);
|
||||
|
||||
// Verify "Spaces" link is not visible initially
|
||||
const navigationLink = page.getByRole('link', { name: 'Spaces' });
|
||||
await expect(navigationLink).not.toBeVisible();
|
||||
|
||||
// Find and click the chevron element that is next to "Editor" in the TOC
|
||||
// It is a span inside the link
|
||||
const editorChevron = page
|
||||
.getByRole('link', { name: 'Editor' })
|
||||
.locator('span');
|
||||
await editorChevron.click();
|
||||
|
||||
// At this stage the link should still not be visible
|
||||
await expect(navigationLink).not.toBeVisible();
|
||||
|
||||
// Then we click 'Content Structure' chevron to expand further
|
||||
const contentStructureChevron = page
|
||||
.getByRole('link', { name: 'Content Structure' })
|
||||
.locator('span');
|
||||
await contentStructureChevron.click();
|
||||
|
||||
// Verify "Spaces" link becomes visible after expansion
|
||||
await expect(navigationLink).toBeVisible();
|
||||
},
|
||||
},
|
||||
...searchTestCases,
|
||||
{
|
||||
name: 'Not found',
|
||||
@@ -370,37 +285,6 @@ const testCases: TestsCase[] = [
|
||||
).toBeVisible();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Switch variant with alternate link in metadata',
|
||||
url: 'rfcs',
|
||||
run: async (page) => {
|
||||
const spaceDropdown = page
|
||||
.locator('[data-testid="space-dropdown-button"]')
|
||||
.locator('visible=true');
|
||||
await spaceDropdown.click();
|
||||
|
||||
const variantSelectionDropdown = page.locator(
|
||||
'css=[data-testid="dropdown-menu"]'
|
||||
);
|
||||
|
||||
// Click the variant space called 'Multi-Variants' for which
|
||||
// there is an alternate link in the current (RFC variant) page metadata
|
||||
await variantSelectionDropdown
|
||||
.getByRole('menuitem', {
|
||||
name: 'Multi-Variants',
|
||||
})
|
||||
.click();
|
||||
|
||||
// It should navigate to the alternate link defined in the metadata (a completely different page)
|
||||
await page.waitForURL((url) =>
|
||||
url.pathname.includes('multi-variants/reference/api-reference/pets')
|
||||
);
|
||||
// Verify we are on the correct page by checking the h1
|
||||
await expect(
|
||||
page.getByRole('heading', { level: 1, name: 'Pets' })
|
||||
).toBeVisible();
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -843,10 +727,7 @@ const testCases: TestsCase[] = [
|
||||
url: 'blocks/integrations',
|
||||
run: async (page) => {
|
||||
await waitForCookiesDialog(page);
|
||||
const mermaidIframe = page
|
||||
.locator('iframe[title*="mermaid"]')
|
||||
.first()
|
||||
.contentFrame();
|
||||
const mermaidIframe = page.locator('iframe[title*="mermaid"]').contentFrame();
|
||||
await expect(mermaidIframe.getByText('Mermaid', { exact: true })).toBeVisible();
|
||||
await expect(mermaidIframe.getByText('Diagram', { exact: true })).toBeVisible();
|
||||
},
|
||||
@@ -912,11 +793,6 @@ const testCases: TestsCase[] = [
|
||||
url: 'blocks/cards',
|
||||
fullPage: true,
|
||||
},
|
||||
{
|
||||
name: 'Updates',
|
||||
url: 'blocks/updates',
|
||||
fullPage: true,
|
||||
},
|
||||
{
|
||||
name: 'Math',
|
||||
url: 'blocks/math',
|
||||
@@ -975,10 +851,7 @@ const testCases: TestsCase[] = [
|
||||
{
|
||||
name: 'With cover',
|
||||
url: 'page-options/page-with-cover',
|
||||
run: async (page) => {
|
||||
await waitForCookiesDialog(page);
|
||||
await waitForCoverImages(page);
|
||||
},
|
||||
run: waitForCookiesDialog,
|
||||
},
|
||||
{
|
||||
name: 'With cover for dark mode',
|
||||
@@ -993,18 +866,12 @@ const testCases: TestsCase[] = [
|
||||
{
|
||||
name: 'With hero cover',
|
||||
url: 'page-options/page-with-hero-cover',
|
||||
run: async (page) => {
|
||||
await waitForCookiesDialog(page);
|
||||
await waitForCoverImages(page);
|
||||
},
|
||||
run: waitForCookiesDialog,
|
||||
},
|
||||
{
|
||||
name: 'With cover and no TOC',
|
||||
url: 'page-options/page-with-cover-and-no-toc',
|
||||
run: async (page) => {
|
||||
await waitForCookiesDialog(page);
|
||||
await waitForCoverImages(page);
|
||||
},
|
||||
run: waitForCookiesDialog,
|
||||
screenshot: {
|
||||
waitForTOCScrolling: false,
|
||||
},
|
||||
@@ -1587,7 +1454,10 @@ const testCases: TestsCase[] = [
|
||||
locale,
|
||||
},
|
||||
}),
|
||||
run: waitForCookiesDialog,
|
||||
run: async (page) => {
|
||||
const dialog = page.getByTestId('cookies-dialog');
|
||||
await expect(dialog).toBeVisible();
|
||||
},
|
||||
})),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -143,10 +143,7 @@ export const headerLinks: CustomizationHeaderItem[] = [
|
||||
|
||||
export async function waitForCookiesDialog(page: Page) {
|
||||
const dialog = page.getByTestId('cookies-dialog');
|
||||
await expect(dialog).toBeVisible({
|
||||
// Cookies dialog may take some times to appear
|
||||
timeout: 10_000,
|
||||
});
|
||||
await expect(dialog).toBeVisible();
|
||||
}
|
||||
|
||||
export async function waitForNotFound(_page: Page, response: Response | null) {
|
||||
@@ -154,13 +151,6 @@ export async function waitForNotFound(_page: Page, response: Response | null) {
|
||||
expect(response?.status()).toBe(404);
|
||||
}
|
||||
|
||||
export async function waitForCoverImages(page: Page) {
|
||||
// Wait for cover images to exist (not the shimmer placeholder)
|
||||
await expect(page.locator('img[alt="Page cover"]').first()).toBeVisible({
|
||||
timeout: 10_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform test cases into Playwright tests and run it.
|
||||
*/
|
||||
|
||||
@@ -7,8 +7,7 @@ export default {
|
||||
converter: 'edge',
|
||||
proxyExternalRequest: 'fetch',
|
||||
queue: () => import('./openNext/queue/middleware').then((m) => m.default),
|
||||
incrementalCache: () =>
|
||||
import('./openNext/incrementalCache/server').then((m) => m.default),
|
||||
incrementalCache: () => import('./openNext/incrementalCache').then((m) => m.default),
|
||||
tagCache: () => import('./openNext/tagCache/middleware').then((m) => m.default),
|
||||
},
|
||||
},
|
||||
@@ -19,8 +18,7 @@ export default {
|
||||
converter: 'edge',
|
||||
proxyExternalRequest: 'fetch',
|
||||
queue: () => import('./openNext/queue/middleware').then((m) => m.default),
|
||||
incrementalCache: () =>
|
||||
import('./openNext/incrementalCache/middleware').then((m) => m.default),
|
||||
incrementalCache: () => import('./openNext/incrementalCache').then((m) => m.default),
|
||||
tagCache: () => import('./openNext/tagCache/middleware').then((m) => m.default),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{
|
||||
"main": "default.js",
|
||||
"name": "gitbook-open-v2-server",
|
||||
"keep_names": false,
|
||||
"compatibility_date": "2025-04-14",
|
||||
"compatibility_flags": [
|
||||
"nodejs_compat",
|
||||
"allow_importable_env",
|
||||
"global_fetch_strictly_public"
|
||||
],
|
||||
"observability": {
|
||||
"enabled": true
|
||||
},
|
||||
"vars": {
|
||||
"NEXT_CACHE_DO_QUEUE_DISABLE_SQLITE": "true"
|
||||
},
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
"main": "do.js",
|
||||
"name": "gitbook-open-v2-do",
|
||||
"compatibility_date": "2025-04-14",
|
||||
"keep_names": false,
|
||||
"compatibility_flags": [
|
||||
"nodejs_compat",
|
||||
"allow_importable_env",
|
||||
"global_fetch_strictly_public"
|
||||
],
|
||||
"observability": {
|
||||
"enabled": true
|
||||
},
|
||||
"env": {
|
||||
"preview": {
|
||||
"vars": {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"main": "middleware.js",
|
||||
"name": "gitbook-open-v2",
|
||||
"compatibility_date": "2025-04-14",
|
||||
"keep_names": false,
|
||||
"compatibility_flags": [
|
||||
"nodejs_compat",
|
||||
"allow_importable_env",
|
||||
@@ -12,6 +11,9 @@
|
||||
"directory": "../../.open-next/assets",
|
||||
"binding": "ASSETS"
|
||||
},
|
||||
"observability": {
|
||||
"enabled": true
|
||||
},
|
||||
"vars": {
|
||||
"NEXT_CACHE_DO_QUEUE_DISABLE_SQLITE": "true"
|
||||
},
|
||||
|
||||
+12
-1
@@ -7,6 +7,8 @@ import type {
|
||||
} from '@opennextjs/aws/types/overrides.js';
|
||||
import { getCloudflareContext } from '@opennextjs/cloudflare';
|
||||
|
||||
import { withRegionalCache } from '@opennextjs/cloudflare/overrides/incremental-cache/regional-cache';
|
||||
|
||||
import type { DurableObjectNamespace, Rpc } from '@cloudflare/workers-types';
|
||||
|
||||
export const BINDING_NAME = 'NEXT_INC_CACHE_R2_BUCKET';
|
||||
@@ -21,7 +23,7 @@ export type KeyOptions = {
|
||||
* It is very similar to the `R2IncrementalCache` in the `@opennextjs/cloudflare` package, but it has an additional
|
||||
* R2WriteBuffer Durable Object to handle writes to R2. Given how we set up cache, we often end up writing to the same key too fast.
|
||||
*/
|
||||
export class GitbookIncrementalCache implements IncrementalCache {
|
||||
class GitbookIncrementalCache implements IncrementalCache {
|
||||
name = 'GitbookIncrementalCache';
|
||||
|
||||
async get<CacheType extends CacheEntryType = 'cache'>(
|
||||
@@ -135,3 +137,12 @@ export class GitbookIncrementalCache implements IncrementalCache {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withRegionalCache(new GitbookIncrementalCache(), {
|
||||
mode: 'long-lived',
|
||||
// We can do it because we use our own logic to invalidate the cache
|
||||
bypassTagCacheOnCacheHit: true,
|
||||
defaultLongLivedTtlSec: 60 * 60 * 24 /* 24 hours */,
|
||||
// We don't want to update the cache entry on every cache hit
|
||||
shouldLazilyUpdateOnCacheHit: false,
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
import { withRegionalCache } from '@opennextjs/cloudflare/overrides/incremental-cache/regional-cache';
|
||||
import { GitbookIncrementalCache } from './incrementalCache';
|
||||
|
||||
export default withRegionalCache(new GitbookIncrementalCache(), {
|
||||
mode: 'long-lived',
|
||||
// We can do it because we use our own logic to invalidate the cache
|
||||
bypassTagCacheOnCacheHit: true,
|
||||
defaultLongLivedTtlSec: 60 * 60 * 24 /* 24 hours */,
|
||||
// We don't want to update the cache entry on every cache hit
|
||||
shouldLazilyUpdateOnCacheHit: false,
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
import { withRegionalCache } from '@opennextjs/cloudflare/overrides/incremental-cache/regional-cache';
|
||||
import { GitbookIncrementalCache } from './incrementalCache';
|
||||
|
||||
export default withRegionalCache(new GitbookIncrementalCache(), {
|
||||
mode: 'long-lived',
|
||||
// Because of a race condition, the middleware may have populated the cache entry before `cache.match` had time to run on the server.
|
||||
// TODO: We should bypass the incremental cache entirely when the interceptor has caught the request. Should be done in OpenNext.
|
||||
bypassTagCacheOnCacheHit: false,
|
||||
defaultLongLivedTtlSec: 60 * 60 * 24 /* 24 hours */,
|
||||
// We don't want to update the cache entry on every cache hit
|
||||
shouldLazilyUpdateOnCacheHit: false,
|
||||
});
|
||||
@@ -1,25 +1,22 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "0.20.0",
|
||||
"version": "0.18.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@cloudflare/workers-types": "^4.20251011.0",
|
||||
"@gitbook/api": "catalog:",
|
||||
"@gitbook/expr": "workspace:*",
|
||||
"@gitbook/browser-types": "workspace:*",
|
||||
"@gitbook/cache-tags": "workspace:*",
|
||||
"@gitbook/colors": "workspace:*",
|
||||
"@gitbook/embed": "workspace:*",
|
||||
"@gitbook/emoji-codepoints": "workspace:*",
|
||||
"@gitbook/expr": "workspace:*",
|
||||
"@gitbook/fonts": "workspace:*",
|
||||
"@gitbook/icons": "workspace:*",
|
||||
"@gitbook/openapi-parser": "workspace:*",
|
||||
"@gitbook/react-contentkit": "workspace:*",
|
||||
"@gitbook/react-math": "workspace:*",
|
||||
"@gitbook/react-openapi": "workspace:*",
|
||||
"@modelcontextprotocol/sdk": "1.17.5",
|
||||
"@opennextjs/aws": "^3.8.5",
|
||||
"@opennextjs/cloudflare": "^1.11.0",
|
||||
"@modelcontextprotocol/sdk": "^1.17.5",
|
||||
"@opennextjs/cloudflare": "^1.8.3",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.12",
|
||||
"@radix-ui/react-hover-card": "^1.1.15",
|
||||
@@ -31,16 +28,19 @@
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@tusbar/cache-control": "^1.0.2",
|
||||
"ai": "^4.2.2",
|
||||
"assert-never": "catalog:",
|
||||
"assert-never": "^1.2.1",
|
||||
"bidc": "catalog:",
|
||||
"classnames": "catalog:",
|
||||
"bun-types": "^1.1.20",
|
||||
"classnames": "^2.5.1",
|
||||
"direction": "^2.0.1",
|
||||
"event-iterator": "^2.0.0",
|
||||
"feed": "^5.1.0",
|
||||
"framer-motion": "^10.16.14",
|
||||
"image-size": "^2.0.2",
|
||||
"js-cookie": "^3.0.5",
|
||||
"jsontoxml": "^1.0.1",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"katex": "^0.16.9",
|
||||
"mathjax": "^3.2.2",
|
||||
"mcp-handler": "^1.0.2",
|
||||
"mdast-util-from-markdown": "^2.0.2",
|
||||
"mdast-util-frontmatter": "^2.0.1",
|
||||
@@ -49,7 +49,7 @@
|
||||
"memoizee": "^0.4.17",
|
||||
"micromark-extension-frontmatter": "^2.0.0",
|
||||
"micromark-extension-gfm": "^3.0.0",
|
||||
"motion": "^12.23.24",
|
||||
"motion": "^12.23.12",
|
||||
"next": "15.4.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"nuqs": "^2.2.3",
|
||||
@@ -58,8 +58,6 @@
|
||||
"openapi-types": "^12.1.3",
|
||||
"p-map": "^7.0.3",
|
||||
"quick-lru": "^7.0.1",
|
||||
"react": "catalog:",
|
||||
"react-dom": "catalog:",
|
||||
"react-hotkeys-hook": "^4.4.1",
|
||||
"rehype-sanitize": "^6.0.0",
|
||||
"rehype-stringify": "^10.0.1",
|
||||
@@ -75,7 +73,7 @@
|
||||
"unist-util-remove": "^4.0.0",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"url-join": "^5.0.0",
|
||||
"usehooks-ts": "catalog:",
|
||||
"usehooks-ts": "^3.1.0",
|
||||
"warn-once": "^0.1.1",
|
||||
"zod": "^3",
|
||||
"zustand": "^5.0.3"
|
||||
@@ -83,7 +81,6 @@
|
||||
"devDependencies": {
|
||||
"@argos-ci/playwright": "^5.0.9",
|
||||
"@playwright/test": "^1.54.2",
|
||||
"@scalar/api-client-react": "catalog:",
|
||||
"@tailwindcss/postcss": "^4.1.11",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/jsontoxml": "^1.0.5",
|
||||
@@ -92,10 +89,9 @@
|
||||
"@types/node": "^20",
|
||||
"@types/object-hash": "^3.0.6",
|
||||
"@types/parse-cache-control": "^1.0.4",
|
||||
"@types/react": "catalog:",
|
||||
"@types/react-dom": "catalog:",
|
||||
"@types/react": "18.3.13",
|
||||
"@types/react-dom": "18.3.1",
|
||||
"@types/rison": "^0.0.9",
|
||||
"bun-types": "catalog:",
|
||||
"deepmerge": "^4.3.1",
|
||||
"env-cmd": "^10.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
@@ -103,10 +99,8 @@
|
||||
"stylelint": "^16.16.0",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"ts-essentials": "^10.0.1",
|
||||
"typescript": "catalog:",
|
||||
"vercel": "^39.3.0",
|
||||
"wrangler": "^4.43.0",
|
||||
"rss-parser": "^3.13.0"
|
||||
"typescript": "^5.5.3",
|
||||
"vercel": "^39.3.0"
|
||||
},
|
||||
"scripts": {
|
||||
"generate": "./scripts/generate.sh",
|
||||
@@ -127,9 +121,5 @@
|
||||
},
|
||||
"browserslist": [
|
||||
">0.3%, chrome >= 64, edge >= 79, firefox >= 67, opera >= 51, safari >= 12 and not dead"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+1
-5
@@ -22,11 +22,7 @@ export default async function SiteDynamicLayout({
|
||||
const withTracking = shouldTrackEvents(await headers());
|
||||
|
||||
return (
|
||||
<CustomizationRootLayout
|
||||
className="site-background"
|
||||
forcedTheme={forcedTheme}
|
||||
context={context}
|
||||
>
|
||||
<CustomizationRootLayout forcedTheme={forcedTheme} context={context}>
|
||||
<SiteLayout
|
||||
context={context}
|
||||
forcedTheme={forcedTheme}
|
||||
|
||||
+11
-2
@@ -1,7 +1,16 @@
|
||||
import type { RouteLayoutParams } from '@/app/utils';
|
||||
import { EmbeddableAssistantPage } from '@/components/Embeddable';
|
||||
import { getEmbeddableDynamicContext } from '@/lib/embeddable';
|
||||
|
||||
export const dynamic = 'force-static';
|
||||
|
||||
export default async function Page() {
|
||||
return <EmbeddableAssistantPage />;
|
||||
type PageProps = {
|
||||
params: Promise<RouteLayoutParams>;
|
||||
};
|
||||
|
||||
export default async function Page(props: PageProps) {
|
||||
const params = await props.params;
|
||||
const { context } = await getEmbeddableDynamicContext(params);
|
||||
|
||||
return <EmbeddableAssistantPage context={context} />;
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ export default async function SiteStaticLayout({
|
||||
const withTracking = shouldTrackEvents();
|
||||
|
||||
return (
|
||||
<CustomizationRootLayout className="site-background" context={context}>
|
||||
<CustomizationRootLayout context={context}>
|
||||
<SiteLayout
|
||||
context={context}
|
||||
withTracking={withTracking}
|
||||
|
||||
+11
-2
@@ -1,7 +1,16 @@
|
||||
import type { RouteLayoutParams } from '@/app/utils';
|
||||
import { EmbeddableAssistantPage } from '@/components/Embeddable';
|
||||
import { getEmbeddableStaticContext } from '@/lib/embeddable';
|
||||
|
||||
export const dynamic = 'force-static';
|
||||
|
||||
export default async function Page() {
|
||||
return <EmbeddableAssistantPage />;
|
||||
type PageProps = {
|
||||
params: Promise<RouteLayoutParams>;
|
||||
};
|
||||
|
||||
export default async function Page(props: PageProps) {
|
||||
const params = await props.params;
|
||||
const { context } = await getEmbeddableStaticContext(params);
|
||||
|
||||
return <EmbeddableAssistantPage context={context} />;
|
||||
}
|
||||
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
import { type RouteParams, getPagePathFromParams, getStaticSiteContext } from '@/app/utils';
|
||||
import { servePageRSS } from '@/routes/rss';
|
||||
import type { NextRequest } from 'next/server';
|
||||
|
||||
export const dynamic = 'force-static';
|
||||
|
||||
export async function GET(_request: NextRequest, { params }: { params: Promise<RouteParams> }) {
|
||||
const { context } = await getStaticSiteContext(await params);
|
||||
const pathname = getPagePathFromParams(await params);
|
||||
|
||||
return servePageRSS(context, pathname);
|
||||
}
|
||||
@@ -16,14 +16,14 @@ export function AIMessageView(
|
||||
) {
|
||||
const { message, context, withToolCalls = true, withLinkPreviews = true } = props;
|
||||
|
||||
return message.steps.length > 0 ? (
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
{message.steps.map((step, index) => {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={tcls(
|
||||
'flex flex-col gap-2',
|
||||
'flex animate-fade-in-slow flex-col gap-2',
|
||||
step.content.nodes.length > 0 ? 'has-content' : ''
|
||||
)}
|
||||
>
|
||||
@@ -35,7 +35,7 @@ export function AIMessageView(
|
||||
wrapBlocksInSuspense: false,
|
||||
withLinkPreviews,
|
||||
}}
|
||||
style="ai-response-document mt-2 space-y-4 *:origin-top-left *:animate-blur-in-slow"
|
||||
style="mt-2 space-y-4 empty:hidden"
|
||||
/>
|
||||
|
||||
{withToolCalls && step.toolCalls && step.toolCalls.length > 0 ? (
|
||||
@@ -45,5 +45,5 @@ export function AIMessageView(
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null;
|
||||
);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ function ToolCallSummary(props: { toolCall: AIToolCall; context: GitBookSiteCont
|
||||
const { toolCall, context } = props;
|
||||
|
||||
return (
|
||||
<div className="mt-2 flex origin-top-left animate-blur-in-slow items-start gap-2 text-sm text-tint-subtle">
|
||||
<div className="flex origin-left animate-scale-in-slow items-start gap-2 text-sm text-tint-subtle">
|
||||
<Icon
|
||||
icon={getIconForToolCall(toolCall)}
|
||||
className="mt-1 size-3 shrink-0 text-tint-subtle/8"
|
||||
@@ -160,7 +160,7 @@ async function DescriptionForSearchToolCall(props: {
|
||||
const hasResults = toolCall.results.length > 0;
|
||||
|
||||
return (
|
||||
<details className="-ml-5 group flex w-full flex-col">
|
||||
<details className={tcls('-ml-5 group flex w-full flex-col', hasResults ? 'gap-2' : '')}>
|
||||
<summary
|
||||
className={tcls(
|
||||
'-mx-2 flex list-none items-center gap-2 circular-corners:rounded-2xl rounded-corners:rounded-md pr-4 pl-7 transition-colors marker:hidden',
|
||||
@@ -187,7 +187,7 @@ async function DescriptionForSearchToolCall(props: {
|
||||
) : null}
|
||||
</summary>
|
||||
{hasResults ? (
|
||||
<div className="hide-scrollbar mt-4 max-h-0 overflow-y-auto circular-corners:rounded-2xl rounded-corners:rounded-lg border border-tint-subtle p-2 opacity-0 transition-all transition-discrete duration-500 group-open:max-h-96 group-open:opacity-11">
|
||||
<div className="hide-scrollbar mt-1 max-h-0 overflow-y-auto circular-corners:rounded-2xl rounded-corners:rounded-lg border border-tint-subtle p-2 opacity-0 transition-all transition-discrete duration-500 group-open:max-h-96 group-open:opacity-11">
|
||||
<ol className="space-y-1">
|
||||
{searchResultsWithHrefs.map((result, index) => (
|
||||
<li
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
'use client';
|
||||
|
||||
import { CustomizationAIMode } from '@gitbook/api';
|
||||
import { Icon, type IconName } from '@gitbook/icons';
|
||||
import { Icon, type IconName, IconStyle } from '@gitbook/icons';
|
||||
import * as React from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
import { tString, useLanguage } from '@/intl/client';
|
||||
import type { GitBookAssistant } from '@gitbook/browser-types';
|
||||
import { useAIChatController, useAIChatState } from '.';
|
||||
import { AIChatIcon, AISearchIcon, getAIChatName } from '../AIChat';
|
||||
import { AIChatIcon, getAIChatName } from '../AIChat';
|
||||
import { useIntegrationAssistants } from '../Integrations';
|
||||
import { useSearch } from '../Search/useSearch';
|
||||
|
||||
@@ -104,7 +104,16 @@ export function useAI(): AIContext {
|
||||
assistants.push({
|
||||
id: 'gitbook-ai-search',
|
||||
label: tString(language, 'ai_chat_context_badge'),
|
||||
icon: <AISearchIcon />,
|
||||
icon: (
|
||||
<div className="relative">
|
||||
<Icon icon="search" className="size-4" />
|
||||
<Icon
|
||||
icon="sparkle"
|
||||
iconStyle={IconStyle.Solid}
|
||||
className="absolute top-[2.5px] left-[2.6px] size-2"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
open: (query?: string) => {
|
||||
if (query) {
|
||||
setSearchState((prev) =>
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
|
||||
import { t, tString, useLanguage } from '@/intl/client';
|
||||
import type { TranslationLanguage } from '@/intl/translations';
|
||||
import { tcls } from '@/lib/tailwind';
|
||||
import { Icon } from '@gitbook/icons';
|
||||
import React from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import {
|
||||
type AIChatController,
|
||||
type AIChatState,
|
||||
useAI,
|
||||
useAIChatController,
|
||||
useAIChatState,
|
||||
} from '../AI';
|
||||
@@ -25,15 +23,15 @@ import {
|
||||
import { useTrackEvent } from '../Insights';
|
||||
import { useNow } from '../hooks';
|
||||
import { Button } from '../primitives';
|
||||
import { ScrollContainer } from '../primitives/ScrollContainer';
|
||||
import { AIChatControlButton } from './AIChatControlButton';
|
||||
import { AIChatIcon } from './AIChatIcon';
|
||||
import { AIChatInput } from './AIChatInput';
|
||||
import { AIChatMessages } from './AIChatMessages';
|
||||
import AIChatSuggestedQuestions from './AIChatSuggestedQuestions';
|
||||
|
||||
export function AIChat() {
|
||||
const { config } = useAI();
|
||||
export function AIChat(props: { trademark: boolean }) {
|
||||
const { trademark } = props;
|
||||
|
||||
const language = useLanguage();
|
||||
const chat = useAIChatState();
|
||||
const chatController = useAIChatController();
|
||||
@@ -67,22 +65,21 @@ export function AIChat() {
|
||||
}
|
||||
}, [chat.opened, trackEvent]);
|
||||
|
||||
if (!chat.opened) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid="ai-chat"
|
||||
className={tcls(
|
||||
'ai-chat inset-y-0 right-0 z-40 mx-auto flex max-w-3xl scroll-mt-36 px-4 py-4 transition-[width,opacity,margin,display] transition-discrete duration-300 sm:px-6 lg:fixed lg:w-80 lg:p-0 xl:w-96',
|
||||
chat.opened
|
||||
? 'lg:starting:ml-0 lg:starting:w-0 lg:starting:opacity-0'
|
||||
: 'hidden lg:ml-0 lg:w-0! lg:opacity-0'
|
||||
)}
|
||||
className="ai-chat inset-y-0 right-0 z-40 mx-auto flex max-w-3xl animate-present scroll-mt-36 px-4 py-4 transition-all duration-300 sm:px-6 lg:fixed lg:w-80 lg:animate-enter-from-right lg:pr-4 lg:pl-0 xl:w-96"
|
||||
>
|
||||
<EmbeddableFrame className="relative shrink-0 border-tint-subtle border-l to-tint-base transition-all duration-300 max-lg:circular-corners:rounded-3xl max-lg:rounded-corners:rounded-md max-lg:border lg:w-80 xl:w-96">
|
||||
<EmbeddableFrame className="relative circular-corners:rounded-3xl rounded-corners:rounded-md depth-subtle:shadow-lg shadow-tint ring-1 ring-tint-subtle">
|
||||
<EmbeddableFrameHeader>
|
||||
<AIChatDynamicIcon trademark={config.trademark} />
|
||||
<AIChatDynamicIcon trademark={trademark} />
|
||||
<EmbeddableFrameHeaderMain>
|
||||
<EmbeddableFrameTitle>
|
||||
{getAIChatName(language, config.trademark)}
|
||||
{getAIChatName(language, trademark)}
|
||||
</EmbeddableFrameTitle>
|
||||
<AIChatSubtitle chat={chat} />
|
||||
</EmbeddableFrameHeaderMain>
|
||||
@@ -99,7 +96,7 @@ export function AIChat() {
|
||||
</EmbeddableFrameButtons>
|
||||
</EmbeddableFrameHeader>
|
||||
<EmbeddableFrameBody>
|
||||
<AIChatBody chatController={chatController} chat={chat} />
|
||||
<AIChatBody chatController={chatController} chat={chat} trademark={trademark} />
|
||||
</EmbeddableFrameBody>
|
||||
</EmbeddableFrame>
|
||||
</div>
|
||||
@@ -146,33 +143,10 @@ export function AIChatSubtitle(props: {
|
||||
const language = useLanguage();
|
||||
|
||||
return (
|
||||
<EmbeddableFrameSubtitle
|
||||
className={tcls('relative', chat.loading ? 'h-3 opacity-11' : 'h-0 opacity-0')}
|
||||
>
|
||||
<span
|
||||
className={tcls(
|
||||
'absolute left-0',
|
||||
chat.loading
|
||||
? chat.messages[chat.messages.length - 1]?.content
|
||||
? 'animate-blur-in-slow'
|
||||
: 'hidden'
|
||||
: 'animate-blur-out-slow'
|
||||
)}
|
||||
>
|
||||
{t(language, 'ai_chat_working')}
|
||||
</span>
|
||||
<span
|
||||
className={tcls(
|
||||
'absolute left-0',
|
||||
chat.loading
|
||||
? chat.messages[chat.messages.length - 1]?.content
|
||||
? 'animate-blur-out-slow'
|
||||
: 'animate-blur-in-slow'
|
||||
: 'hidden'
|
||||
)}
|
||||
>
|
||||
{t(language, 'ai_chat_thinking')}
|
||||
</span>
|
||||
<EmbeddableFrameSubtitle className={chat.loading ? 'h-3 opacity-11' : 'h-0 opacity-0'}>
|
||||
{chat.messages[chat.messages.length - 1]?.content
|
||||
? tString(language, 'ai_chat_working')
|
||||
: tString(language, 'ai_chat_thinking')}
|
||||
</EmbeddableFrameSubtitle>
|
||||
);
|
||||
}
|
||||
@@ -183,13 +157,20 @@ export function AIChatSubtitle(props: {
|
||||
export function AIChatBody(props: {
|
||||
chatController: AIChatController;
|
||||
chat: AIChatState;
|
||||
trademark: boolean;
|
||||
welcomeMessage?: string;
|
||||
suggestions?: string[];
|
||||
}) {
|
||||
const { chatController, chat, suggestions } = props;
|
||||
const { trademark } = useAI().config;
|
||||
const { chatController, chat, trademark, suggestions } = props;
|
||||
|
||||
const [input, setInput] = React.useState('');
|
||||
|
||||
const scrollContainerRef = React.useRef<HTMLDivElement>(null);
|
||||
// Ref for the last user message element
|
||||
const lastUserMessageRef = React.useRef<HTMLDivElement>(null);
|
||||
const inputRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
const [inputHeight, setInputHeight] = React.useState(0);
|
||||
const language = useLanguage();
|
||||
const now = useNow(60 * 60 * 1000); // Refresh every hour for greeting
|
||||
|
||||
@@ -203,43 +184,67 @@ export function AIChatBody(props: {
|
||||
return tString(language, 'ai_chat_assistant_greeting_evening');
|
||||
}, [now, language]);
|
||||
|
||||
// Auto-scroll to the latest user message when messages change
|
||||
React.useEffect(() => {
|
||||
if (chat.messages.length > 0 && lastUserMessageRef.current) {
|
||||
lastUserMessageRef.current.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start',
|
||||
});
|
||||
}
|
||||
}, [chat.messages.length]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
if (lastUserMessageRef.current) {
|
||||
lastUserMessageRef.current.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start',
|
||||
});
|
||||
}
|
||||
}, 100);
|
||||
|
||||
// We want the chat messages to scroll underneath the input, but they should scroll past the input when scrolling all the way down.
|
||||
// The best way to do this is to observe the input height and adjust the padding bottom of the scroll container accordingly.
|
||||
const observer = new ResizeObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
setInputHeight(entry.contentRect.height + 32);
|
||||
});
|
||||
});
|
||||
if (inputRef.current) {
|
||||
observer.observe(inputRef.current);
|
||||
}
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ScrollContainer
|
||||
className="shrink grow basis-80 animate-fade-in-slow [container-type:size]"
|
||||
contentClassName="p-4 gutter-stable flex flex-col gap-4"
|
||||
orientation="vertical"
|
||||
fadeEdges={['leading']}
|
||||
active={`message-group-${chat.messages.filter((message) => message.role === 'user').length - 1}`}
|
||||
<div
|
||||
ref={scrollContainerRef}
|
||||
className="gutter-stable flex grow scroll-pt-4 flex-col gap-4 overflow-y-auto p-4"
|
||||
style={{
|
||||
paddingBottom: `${inputHeight}px`,
|
||||
}}
|
||||
>
|
||||
{isEmpty ? (
|
||||
<div className="flex grow flex-col">
|
||||
<div className="my-auto flex flex-row items-center gap-4 pb-6 [@container(min-height:400px)]:flex-col">
|
||||
<div
|
||||
className="flex size-16 shrink-0 animate-scale-in items-center justify-center rounded-full bg-primary-solid/1 [@container(min-height:400px)]:size-32"
|
||||
style={{ animationDelay: '.3s' }}
|
||||
>
|
||||
<AIChatIcon
|
||||
state="intro"
|
||||
trademark={trademark}
|
||||
className="size-8 text-primary [@container(min-height:400px)]:size-16"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col items-start [@container(min-height:400px)]:items-center">
|
||||
<h5
|
||||
className="animate-blur-in-slow font-bold text-lg text-tint-strong [@container(min-height:400px)]:text-center"
|
||||
style={{ animationDelay: '.5s' }}
|
||||
data-testid="ai-chat-time-greeting"
|
||||
>
|
||||
{timeGreeting}
|
||||
</h5>
|
||||
<p
|
||||
className="animate-blur-in-slow text-tint [@container(min-height:400px)]:text-center"
|
||||
style={{ animationDelay: '.6s' }}
|
||||
>
|
||||
{t(language, 'ai_chat_assistant_description')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex min-h-full w-full shrink-0 flex-col items-center justify-center gap-6 py-4">
|
||||
<div className="flex size-32 animate-fade-in-slow items-center justify-center rounded-full bg-tint-subtle">
|
||||
<AIChatIcon
|
||||
state="intro"
|
||||
trademark={trademark}
|
||||
className="size-16 animate-[present_500ms_200ms_both]"
|
||||
/>
|
||||
</div>
|
||||
<div className="animate-[fadeIn_500ms_400ms_both]">
|
||||
<h5 className=" text-center font-bold text-lg text-tint-strong">
|
||||
{timeGreeting}
|
||||
</h5>
|
||||
<p className="text-center text-tint">
|
||||
{t(language, 'ai_chat_assistant_description')}
|
||||
</p>
|
||||
</div>
|
||||
{!chat.error ? (
|
||||
<AIChatSuggestedQuestions
|
||||
@@ -249,11 +254,17 @@ export function AIChatBody(props: {
|
||||
) : null}
|
||||
</div>
|
||||
) : (
|
||||
<AIChatMessages chat={chat} chatController={chatController} />
|
||||
<AIChatMessages
|
||||
chat={chat}
|
||||
chatController={chatController}
|
||||
lastUserMessageRef={lastUserMessageRef}
|
||||
/>
|
||||
)}
|
||||
</ScrollContainer>
|
||||
|
||||
<div className="flex flex-col gap-2 px-4 pb-4">
|
||||
</div>
|
||||
<div
|
||||
ref={inputRef}
|
||||
className="absolute inset-x-0 bottom-0 mr-2 flex select-none flex-col gap-4 bg-linear-to-b from-transparent to-50% to-tint-base/9 p-4 pr-2"
|
||||
>
|
||||
{/* Display an error banner when something went wrong. */}
|
||||
{chat.error ? <AIChatError chatController={chatController} /> : null}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ export function AIChatButton(props: {
|
||||
iconOnly={!showLabel}
|
||||
size="medium"
|
||||
variant="header"
|
||||
className="h-9 px-2.5 @max-2xl:[&_.button-content]:hidden"
|
||||
className="h-9 px-2.5 max-md:[&_.button-content]:hidden"
|
||||
label={
|
||||
<div className="flex items-center gap-2">
|
||||
{t(language, 'ai_chat_ask', assistant.label)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { tcls } from '@/lib/tailwind';
|
||||
import { Icon, IconStyle } from '@gitbook/icons';
|
||||
import { Icon } from '@gitbook/icons';
|
||||
import type React from 'react';
|
||||
|
||||
interface AIChatIconProps extends React.SVGProps<SVGSVGElement> {
|
||||
@@ -9,18 +9,17 @@ interface AIChatIconProps extends React.SVGProps<SVGSVGElement> {
|
||||
trademark?: boolean;
|
||||
}
|
||||
|
||||
export function AIChatIcon({
|
||||
export const AIChatIcon = ({
|
||||
className = 'size-4',
|
||||
size,
|
||||
trademark = true,
|
||||
state = 'default',
|
||||
...props
|
||||
}: AIChatIconProps) {
|
||||
}: AIChatIconProps) => {
|
||||
if (!trademark) {
|
||||
return (
|
||||
<Icon
|
||||
icon="sparkle"
|
||||
{...props}
|
||||
className={tcls(
|
||||
className,
|
||||
(state === 'thinking' || state === 'working') &&
|
||||
@@ -164,36 +163,4 @@ export function AIChatIcon({
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function AISearchIcon({
|
||||
className = 'size-4',
|
||||
state = 'default',
|
||||
}: Pick<AIChatIconProps, 'className' | 'state'>) {
|
||||
return (
|
||||
<div
|
||||
className={tcls(
|
||||
'relative',
|
||||
state === 'intro' && 'animate-[fadeIn_1s_both,orbit_1s_cubic-bezier(0.16,1,0.3,1)]',
|
||||
state === 'thinking' || state === 'working'
|
||||
? 'animate-[fadeIn_1s_both,orbit_1s_ease-out,orbit_2s_1s_infinite_forwards_linear]'
|
||||
: ''
|
||||
)}
|
||||
>
|
||||
<Icon icon="search" className={className} />
|
||||
<Icon
|
||||
icon="sparkle"
|
||||
iconStyle={IconStyle.Solid}
|
||||
className={tcls(
|
||||
'absolute top-[15.7%] left-[15.6%] size-[50%]',
|
||||
state === 'thinking' || state === 'working'
|
||||
? 'animate-[spin_2s_infinite_forwards_cubic-bezier(0.16,1,0.3,1)]'
|
||||
: '',
|
||||
state === 'intro'
|
||||
? 'animate-[spin_2s_.5s_forwards_cubic-bezier(0.16,1,0.3,1)]'
|
||||
: ''
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@ import { tcls } from '@/lib/tailwind';
|
||||
import { Icon } from '@gitbook/icons';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useAIChatState } from '../AI/useAIChat';
|
||||
import { Button, HoverCard, HoverCardRoot, HoverCardTrigger } from '../primitives';
|
||||
import { KeyboardShortcut } from '../primitives/KeyboardShortcut';
|
||||
|
||||
@@ -20,7 +19,6 @@ export function AIChatInput(props: {
|
||||
const { value, onChange, onSubmit, disabled, loading } = props;
|
||||
|
||||
const language = useLanguage();
|
||||
const chat = useAIChatState();
|
||||
|
||||
const inputRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
@@ -34,7 +32,7 @@ export function AIChatInput(props: {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (chat.opened && !disabled && !loading) {
|
||||
if (!disabled && !loading) {
|
||||
// Add a small delay to ensure the input is rendered before focusing
|
||||
// This fixes inconsistent focus behaviour across browsers
|
||||
const timeout = setTimeout(() => {
|
||||
@@ -43,7 +41,7 @@ export function AIChatInput(props: {
|
||||
|
||||
return () => clearTimeout(timeout);
|
||||
}
|
||||
}, [disabled, loading, chat.opened]);
|
||||
}, [disabled, loading]);
|
||||
|
||||
useHotkeys(
|
||||
'mod+i',
|
||||
@@ -57,7 +55,7 @@ export function AIChatInput(props: {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="depth-subtle:has-[textarea:focus]:-translate-y-px relative flex animate-blur-in-slow flex-col overflow-hidden circular-corners:rounded-3xl rounded-corners:rounded-xl bg-tint-base/9 depth-subtle:shadow-sm shadow-tint/6 ring-1 ring-tint-subtle backdrop-blur-lg transition-all depth-subtle:has-[textarea:focus]:shadow-lg has-[textarea:focus]:shadow-primary-subtle has-[textarea:focus]:ring-2 has-[textarea:focus]:ring-primary-hover contrast-more:bg-tint-base dark:shadow-tint-1">
|
||||
<div className="depth-subtle:has-[textarea:focus]:-translate-y-px relative flex flex-col overflow-hidden circular-corners:rounded-2xl rounded-corners:rounded-md bg-tint-base/9 depth-subtle:shadow-sm shadow-tint/6 ring-1 ring-tint-subtle backdrop-blur-lg transition-all depth-subtle:has-[textarea:focus]:shadow-lg has-[textarea:focus]:shadow-primary-subtle has-[textarea:focus]:ring-2 has-[textarea:focus]:ring-primary-hover contrast-more:bg-tint-base dark:shadow-tint-1">
|
||||
<textarea
|
||||
ref={inputRef}
|
||||
disabled={disabled || loading}
|
||||
@@ -108,7 +106,7 @@ export function AIChatInput(props: {
|
||||
</div>
|
||||
) : null}
|
||||
<div className="absolute inset-x-0 bottom-0 flex items-center gap-2 px-2 py-2">
|
||||
<HoverCardRoot openDelay={500}>
|
||||
<HoverCardRoot>
|
||||
<HoverCard
|
||||
className="max-w-xs bg-tint p-2 text-sm text-tint"
|
||||
arrow={{ className: 'fill-tint-3' }}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user