Compare commits

..

65 Commits

Author SHA1 Message Date
Zeno Kapitein 00bb7d4220 Log api 2024-11-28 15:35:15 +01:00
Zeno Kapitein 259a8aa7ac is broken 2024-11-28 15:13:29 +01:00
Zeno Kapitein 150269a6ee First version of new header 2024-11-28 14:01:26 +01:00
spastorelli fc8065b7a8 Revert "Fix canonical URL ending with "/" (#2586)" (#2588) 2024-11-27 13:05:34 +01:00
Greg Bergé 28f1ed9205 Fix canonical URL ending with "/" (#2586) 2024-11-26 21:57:15 +01:00
Viktor Renkema 568266bc9a Add transitions to Sections bg and line (#2491) 2024-11-26 19:59:07 +01:00
Samy Pessé 7739f341b8 Revert "Serve the correct status code for not found and redirects 👌" (#2587) 2024-11-26 18:36:00 +01:00
Greg Bergé 2b501f191c Serve the correct status code for not found and redirects 👌 (#2582) 2024-11-26 18:05:47 +01:00
Zeno Kapitein aa2ed0fda1 Restyle hint block (#2579) 2024-11-26 12:41:47 +01:00
Greg Bergé 51cba074d7 Update shiki (#2583) 2024-11-26 11:50:08 +01:00
Taran Vohra 2c945c663c Get the best possible target space for content refs (#2580) 2024-11-26 10:53:37 +05:30
Viktor Renkema d9a18ecabb Improve contrast ratio for text color on image captions (#2584) 2024-11-25 14:01:09 +01:00
Greg Bergé eab7931afb Parallelize and remove useless Promise.all (#2581) 2024-11-22 15:54:56 +01:00
Taran Vohra 99b6c92377 Resolve site level redirects (#2577) 2024-11-22 12:04:15 +05:30
Zeno Kapitein 4d56f1163b Improve styling of search & ask AI box (#2576) 2024-11-20 16:59:15 +01:00
Brett Jephson 07cf835551 Add a scroll margin to the top when layout has sections (#2574) 2024-11-19 16:34:27 +00:00
Steven H 061c0c1a90 Fix a regression in variant drop-down caused by missing z-index. (#2575) 2024-11-19 17:23:44 +01:00
Anthony Lio 1ed18c05ef Adds missing css variables (#2558)
Co-authored-by: Steven H <steven@gitbook.io>
2024-11-19 16:08:07 +01:00
Steven H ca134c8a60 Fix an issue where the active site section indicator appeared above any dropdowns. (#2568) 2024-11-19 15:16:47 +01:00
Amrit Kahlon 7ba67fd852 chore: scalar bump (#2571)
Co-authored-by: Steven Hall <steven@gitbook.io>
2024-11-19 13:54:35 +01:00
Taran Vohra 7675c2c411 use getPublishedContentSite API (#2570)
Co-authored-by: Samy Pessé <samypesse@gmail.com>
2024-11-15 09:21:08 +01:00
Brett Jephson 7c71363af8 Set adjustFallbackFont to false for mono font (#2569) 2024-11-12 13:03:25 +00:00
Steven H d48926eb2a Fix an issue where the space dropdown was shown under the site sections in Safari. (#2567) 2024-11-05 11:49:33 +00:00
Steven H d843e5e06f Fix an issue where the space dropdown could appear behind the header. (#2566) 2024-11-05 09:47:32 +00:00
Steven H a2e564738e Fix the styling of site section tabs on smaller screens. (#2565) 2024-11-04 17:36:10 +00:00
Greg Bergé 54a797a0b1 Nested list support (#2562) 2024-10-31 14:02:42 +01:00
Amrit Kahlon a78c1ecb4d Bump scalar api client package (#2563) 2024-10-30 11:45:56 -07:00
Amrit Kahlon 4771c78001 Fix Scalar ApiClient routing (#2561) 2024-10-28 12:38:18 -07:00
Samy Pessé b7a5106f36 Disable logs for cache-do (#2560) 2024-10-27 08:16:56 -04:00
Samy Pessé 4bcbdc50ff Output caching headers on RSC/prefetch responses (#2559) 2024-10-26 10:57:52 +02:00
Brett Jephson 5d72b35c7f Improve animation of section tabs (#2553) 2024-10-25 14:00:27 +01:00
Amrit Kahlon ff50ac215c Bump @scalar/api-client-react version (#2555)
Co-authored-by: taranvohra <taranvohra@outlook.com>
Co-authored-by: Samy Pessé <samypesse@gmail.com>
2024-10-25 12:06:49 +05:30
Samy Pessé 3fe3809416 Version Packages (#2415)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-24 15:54:23 +02:00
Samy Pessé 363d337a72 Cleanup GitHub workflows (#2554) 2024-10-24 14:50:39 +02:00
Amrit Kahlon f89b31c940 Upgrade to the new scalar client (#2539)
Co-authored-by: Samy Pessé <samypesse@gmail.com>
2024-10-24 14:40:33 +02:00
Samy Pessé 630c3e84dd Migrate to cloudflare/wrangler-action for deployment (#2549) 2024-10-24 14:30:13 +02:00
Samy Pessé d43202f137 Reduce bundle size of shiki (#2551) 2024-10-24 10:16:56 +02:00
Scott Cazan 0964043489 Use updated endpoint for page feedbacks (#2548) 2024-10-24 10:16:46 +02:00
Taran Vohra e9b31a545d Unify section tab styles with page item styles (#2552) 2024-10-24 13:28:15 +05:30
Greg Bergé 7f28a88374 Use transparent bg for secondary button (#2545) 2024-10-24 06:51:39 +02:00
Steven H 07ea45bf84 Remove deprecated synced block from GitBook Open (#2546) 2024-10-23 15:45:31 +01:00
Zeno Kapitein a86d35f721 Fixes variant selector for sites without variants (#2544) 2024-10-22 17:22:07 +02:00
Zeno Kapitein d6c28a0ff6 Update header styling of sections, variant selector, and button links (#2543) 2024-10-22 16:58:27 +02:00
Brett Jephson a7af3ca7bc Improving the new tabs (#2537) 2024-10-21 19:15:22 +01:00
Taran Vohra cda08a9843 Add support for search in a sections site (#2541) 2024-10-21 15:54:29 +05:30
Taran Vohra 7588774237 add all mode while searching site content (#2540) 2024-10-21 12:13:00 +05:30
Greg Bergé 683373b263 Fix CLS and others (#2536) 2024-10-20 12:55:37 +02:00
spastorelli 673ec8fb5d Update Placeholder ad & Sponsored by GitBook links (#2538) 2024-10-19 08:51:22 +02:00
spastorelli 63bacaa671 Ensure pending or in-review sites still get placeholder ads even without preview query param (#2535) 2024-10-18 17:08:54 +02:00
Samy Pessé e3a3d6a505 Improve perf perception and fix flickering in Ask answer (#2534) 2024-10-18 15:53:57 +02:00
Taran Vohra 175171dda1 Add siteSectionId to lookup result (#2533) 2024-10-18 16:53:15 +05:30
Taran Vohra a4b63b88c8 generate upto URL with 4 segments to support sites with sections (#2532) 2024-10-18 16:34:25 +05:30
Steven H c3675fdfe7 Add support for reusable content (#2531) 2024-10-18 10:59:46 +01:00
Brett Jephson 2fa08519b6 RND-5227: Site section tabs (#2530) 2024-10-18 09:47:53 +01:00
spastorelli 065627060b Show placeholder ad when site ads status is pending or in-review (#2529) 2024-10-17 19:20:34 +02:00
Greg Bergé 2982b6a808 Implement Stepper (#2528) 2024-10-17 09:52:45 +02:00
Greg Bergé c3f56ecd40 Return null if block not handled (#2527) 2024-10-16 22:12:54 +02:00
Zeno Kapitein fe9e6c1afd Update ogimage with new design (#2517)
Co-authored-by: Samy Pessé <samypesse@gmail.com>
2024-10-15 17:28:37 +02:00
Taran Vohra 73394ae929 Mock data for getSpaceCustomization and getSpaceIntegrationScripts (#2522) 2024-10-15 15:40:05 +05:30
Zeno Kapitein c754fc9ff4 Add automatic color contrast in site header, restyle search button (#2512) 2024-10-15 11:05:25 +02:00
Zeno Kapitein 1ca6208057 Update Playwright test for share links (#2523) 2024-10-15 10:53:58 +02:00
Greg Bergé cdfae4d4df Remove custom types for HeaderLink (#2521) 2024-10-14 13:33:01 +02:00
Samy Pessé c3da5469ca Add basic support for computed pages types (#2520) 2024-10-14 10:04:12 +02:00
Taran Vohra 79f2d8ba76 Refactor getContentPointer usage into getSiteContentPointer (#2519) 2024-10-14 12:07:14 +05:30
Taran Vohra 7b1bdb92a6 Remove getContentPointer usage from search (#2516) 2024-10-14 10:26:14 +05:30
227 changed files with 3446 additions and 2681 deletions
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Avoid multiple <h1> in the page by using a <div> for the title in the header
-6
View File
@@ -1,6 +0,0 @@
---
'@gitbook/react-openapi': patch
'gitbook': patch
---
Adds content-visibility css property to OpenAPI Operation for better render performance
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/cache-do': minor
---
Experiment with optimizing billable duration in Cloudflare by using multiple RPC sessions instead of one
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Fix scroll position when navigating pages on mobile
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/react-openapi': minor
---
Add Python support in Code Samples
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
RND-3532: drop down menu for hidden links at small screen size
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Change dark mode shadow for multi-space search toolbar
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Use ellipsis and fix icon color for more links in the header on small screen
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Improve consistency of change request preview by removing cache-control on response
+5
View File
@@ -0,0 +1,5 @@
---
'@gitbook/cache-do': patch
---
Disable cloudflare observability in production
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/icons': patch
---
Update version for static assets to fix invalid caching
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': patch
---
Update styling of search+ask modal
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Revalidate change request cached content when pressing refresh button
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/icons': patch
---
Fix first run of the package in development mode
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Improve performances of loading pages with embeds by caching them
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': patch
---
Fix a regression in variant drop-down caused by missing z-index.
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Replace all icons, previously imported from Geist, by new package `@gitbook/icons`
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/cache-do': minor
---
First version of a new cache backend powered by Cloudflare Durable Objects
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': patch
---
Add scroll margin to the top when there are sections
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Add support for Norwegian language
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Optimize layout shift while transitioning between pages with full width blocks (ex: OpenAPI blocks)
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Add support for page icons
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': patch
---
Smoother tab transition for sections
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Fix GitBook specific static assets not being served correctly when deployed on Cloudflare
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Only display spaces dropdown in compact header when site is multi-variants
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': minor
---
Fix an issue where the active site section indicator appeared above any dropdowns.
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': patch
---
Don't adjust fallback font for mono font.
@@ -2,4 +2,4 @@
'@gitbook/react-openapi': patch
---
bump: scalar from 1.0.5 to 1.0.7
Fixed scalar api client routing
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/cache-do': patch
---
Enable Workers observability with a sampling of 0.1
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': patch
---
Optimize performances by using new API endpoint for fetching site data.
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/icons': minor
---
Initial release for `@gitbook/icons`, a package of content icons to be used for pages, documents, etc.
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Automatically scroll to active item in TOC
@@ -2,4 +2,4 @@
'@gitbook/react-openapi': patch
---
Update Scalar client to latest version
Bump @scalar/api-client-react version
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Persist state of tabs and dynamically sync them based on title
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Ensure "Sponsored via GitBook" can be translated in all languages
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Show the caption for file blocks
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Use url hash to open Expandable and scroll to anchor
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Fix margin for paragraphs in quote blocks
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Use new cache backend, powered by Durable Objects, alongside the existing ones (KV, etc).
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': patch
---
Restyle hint blocks
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Include offset in calculations of whether scrollable element is in view
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/react-openapi': minor
---
Add required query parameters to the code sample
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/react-openapi': minor
---
Display pattern if available in parmas in OpenAPI block
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Fix inconsistent click area in table because of scroll indicator
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Stop using KV cache backend for now, but also improves it for higher performances
-6
View File
@@ -1,6 +0,0 @@
---
'@gitbook/react-openapi': minor
'gitbook': patch
---
Synchronize response and response example tabs
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Show definition title when visible in cards
-6
View File
@@ -1,6 +0,0 @@
---
'@gitbook/react-openapi': minor
'gitbook': patch
---
Rollback of scalar modal while fixing perf issue
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Optimize images rendered in community ads
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Update design of Checkbox to be more consistent and readable
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/react-contentkit': patch
---
Fix rendering of webframe with SSR causing wrong communication between frame and renderer
@@ -2,4 +2,4 @@
'@gitbook/react-openapi': patch
---
Render mandatory headers in code sample
bumped the scalar api client dependency
+5
View File
@@ -0,0 +1,5 @@
---
'@gitbook/react-openapi': patch
---
Bumped scalar api client pacakge
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Disable KV cache for docs.gitbook.com as a test, also disable it for change-request to improve consistency
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': minor
---
Fix an issue where the space dropdown was shown under the site sections in Safari.
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Add optional env `GITBOOK_INTEGRATIONS_HOST` to configure the host serving the integrations
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/react-openapi': patch
---
Fix crash when `example` is undefined for a response
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Improve the toolbar for change-requests and revisions to show more actions
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Add support for icons style customization for sites
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/react-openapi': patch
---
Adds tabs to Response Example section e.g. for status code examples
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Prevent search indexation for pages where it's configured as disabled
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Fix table of contents being visible on mobile when disabled at the page level
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': patch
---
style: adds missing scalar css variables
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Fix accessibility of the table of contents by using `aria-current` instead of `aria-selected`
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Update rendering of community ads to match new API response, and make it possible to preview ads.
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/react-math': minor
---
Export binary `gitbook-math` to copy assets to a directory
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': minor
---
Fix an issue where the space dropdown could appear behind the header.
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Fix "ip" being passed to BSA for community ads
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': minor
---
Fix the styling of site section tabs on smaller screens.
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Changed the alternative URL resolution criteria in order to support site URLs without /v/ prefix
-5
View File
@@ -1,5 +0,0 @@
---
'@gitbook/icons': minor
---
Fix bin gitbook-icons when installed without the Pro token
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': patch
---
Don't show hidden pages in the empty state of a page
-5
View File
@@ -1,5 +0,0 @@
---
'gitbook': minor
---
Fix linking to a tab itself
+43 -11
View File
@@ -13,8 +13,12 @@ jobs:
permissions:
contents: read
deployments: write
issues: write
pull-requests: write
checks: write
statuses: write
outputs:
deployment_url: ${{ steps.cloudflare.outputs.url }}
deployment_url: ${{ steps.deploy.outputs.deployment-url }}
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -52,27 +56,55 @@ jobs:
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT }}
SENTRY_DSN: ${{ vars.SENTRY_DSN }}
- id: cloudflare
name: Publish to Cloudflare Pages
uses: cloudflare/pages-action@v1
- id: deploy
name: Deploy to Cloudflare
uses: cloudflare/wrangler-action@v3.11.0
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: ${{ vars.CLOUDFLARE_PROJECT_NAME }}
directory: ./packages/gitbook/.vercel/output/static
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
workingDirectory: ./
wranglerVersion: '3.82.0'
command: pages deploy ./packages/gitbook/.vercel/output/static --project-name=${{ vars.CLOUDFLARE_PROJECT_NAME }} --branch=${{ github.ref == 'refs/heads/main' && 'main' || format('pr{0}', github.event.pull_request.number) }}
- name: Outputs
run: |
echo "ID: ${{ steps.cloudflare.outputs.id }}"
echo "URL: ${{ steps.cloudflare.outputs.url }}"
echo "Environment: ${{ steps.cloudflare.outputs.environment }}"
echo "Alias: ${{ steps.cloudflare.outputs.alias }}"
echo "URL: ${{ steps.deploy.outputs.deployment-url }}"
echo "Alias URL: ${{ steps.deploy.outputs.deployment-alias-url }}"
- name: Archive build output
uses: actions/upload-artifact@v4
with:
name: build-output
path: .vercel/
# Until https://github.com/cloudflare/wrangler-action/issues/301 is done
- name: Update Deployment Status to Success
env:
DEPLOYMENT_URL: ${{ steps.deploy.outputs.deployment-url }}
run: |
curl -X POST \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
-d '{"state": "success", "target_url": "${{ steps.deploy.outputs.deployment-url }}", "description": "Deployed Preview URL for commit", "context": "cloudflare/preview"}' \
https://api.github.com/repos/${{ github.repository }}/statuses/${{ github.sha }}
- name: Find GitHub Comment
uses: peter-evans/find-comment@v3
id: fc
if: 1 && !startsWith(github.ref, 'refs/heads/main')
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-includes: GitBook Preview
- name: Create or update GitHub comment
uses: peter-evans/create-or-update-comment@v4
if: 1 && !startsWith(github.ref, 'refs/heads/main')
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body: |
**GitBook Preview**
Latest commit: [${{ steps.deploy.outputs.deployment-url }}](${{ steps.deploy.outputs.deployment-url }})
PR: [${{ steps.deploy.outputs.deployment-alias-url }}](${{ steps.deploy.outputs.deployment-alias-url }})
edit-mode: replace
visual-testing:
runs-on: ubuntu-latest
name: Visual Testing
BIN
View File
Binary file not shown.
+2 -1
View File
@@ -8,7 +8,8 @@
},
"packageManager": "bun@1.1.18",
"patchedDependencies": {
"@vercel/next@4.3.6": "patches/@vercel%2Fnext@4.3.6.patch"
"@vercel/next@4.3.15": "patches/@vercel%2Fnext@4.3.15.patch",
"@cloudflare/next-on-pages@1.13.5": "patches/@cloudflare%2Fnext-on-pages@1.13.5.patch"
},
"private": true,
"scripts": {
+12
View File
@@ -0,0 +1,12 @@
# @gitbook/cache-do
## 0.1.0
### Minor Changes
- 9b8d519: Experiment with optimizing billable duration in Cloudflare by using multiple RPC sessions instead of one
- 636b868: First version of a new cache backend powered by Cloudflare Durable Objects
### Patch Changes
- 56f5fa1: Enable Workers observability with a sampling of 0.1
+2 -2
View File
@@ -14,14 +14,14 @@
"default": "./dist/api.js"
}
},
"version": "0.0.0",
"version": "0.1.0",
"dependencies": {
"@msgpack/msgpack": "^3.0.0-beta2",
"lru_map": "^0.4.1"
},
"devDependencies": {
"typescript": "^5.5.3",
"wrangler": "^3.78.7"
"wrangler": "3.82.0"
},
"scripts": {
"generate": "wrangler types --experimental-include-runtime",
+2 -3
View File
@@ -11,8 +11,7 @@ migrations = [
]
[observability]
enabled = true
head_sampling_rate = 0.01
enabled = false
[env.preview]
name = "gitbook-open-cache-preview"
@@ -25,4 +24,4 @@ migrations = [
[env.preview.observability]
enabled = true
head_sampling_rate = 1
head_sampling_rate = 0.1
+2 -1
View File
@@ -32,4 +32,5 @@ screenshots/
/playwright/.cache/
# Generated public files
/public/~gitbook/static/
/public/~gitbook/static/*
!/public/~gitbook/static/images
+95
View File
@@ -1,5 +1,100 @@
# gitbook
## 0.4.0
### Minor Changes
- e09f747: Revalidate change request cached content when pressing refresh button
- 2fa0851: Add navigation tabs for sections
- a4b63b8: Support resolution of new site URLs with sections
- 5c35f36: Replace all icons, previously imported from Geist, by new package `@gitbook/icons`
- e9b31a5: Unify section tab styles with page item styles
- f12a215: Add support for Norwegian language
- f4c9536: Optimize layout shift while transitioning between pages with full width blocks (ex: OpenAPI blocks)
- 1f24fe4: Add support for page icons
- cda08a9: Add support for searching results in a sections site
- b32e40c: Persist state of tabs and dynamically sync them based on title
- 15d2ee3: Show the caption for file blocks
- f885e88: Improve the toolbar for change-requests and revisions to show more actions
- 07ea45b: Remove deprecated synced block from GitBook Open
- c3675fd: Added support for new Reusable Content block.
- 1f24fe4: Add support for icons style customization for sites
- 4c19014: Prevent search indexation for pages where it's configured as disabled
- 3422ad4: Update rendering of community ads to match new API response, and make it possible to preview ads.
- 1152445: Changed the alternative URL resolution criteria in order to support site URLs without /v/ prefix
- 2c437f7: Fix linking to a tab itself
### Patch Changes
- aa32198: Avoid multiple <h1> in the page by using a <div> for the title in the header
- 51fa3ab: Adds content-visibility css property to OpenAPI Operation for better render performance
- a7066cc: Fix scroll position when navigating pages on mobile
- c754fc9: Add automatic color contrast in site header, restyle search button
- 5fe7adb: RND-3532: drop down menu for hidden links at small screen size
- 6295881: Change dark mode shadow for multi-space search toolbar
- f89b31c: Upgrade the scalar api client package
- 13c7534: Use ellipsis and fix icon color for more links in the header on small screen
- f885e88: Improve consistency of change request preview by removing cache-control on response
- 16e6171: Improve performances of loading pages with embeds by caching them
- 34d36c6: Fix GitBook specific static assets not being served correctly when deployed on Cloudflare
- af9e66e: Only display spaces dropdown in compact header when site is multi-variants
- e3a3d6a: Improve perception of fast loading by not rendering skeletons for individual blocks in the top part of the viewport
- 042b850: Automatically scroll to active item in TOC
- d43202f: Optimize bundle size of the server output by reducing bundle size of shiki (skipping themes)
- bfbed1a: Ensure "Sponsored via GitBook" can be translated in all languages
- fe9e6c1: Update ogimage with new design
- 17f71ba: Use url hash to open Expandable and scroll to anchor
- 3c07e65: Fix margin for paragraphs in quote blocks
- 636b868: Use new cache backend, powered by Durable Objects, alongside the existing ones (KV, etc).
- f16560c: Include offset in calculations of whether scrollable element is in view
- 689f553: Fix inconsistent click area in table because of scroll indicator
- 6ce3cea: Stop using KV cache backend for now, but also improves it for higher performances
- e914903: Synchronize response and response example tabs
- 0f990c7: Show definition title when visible in cards
- e3a3d6a: Fix flickering when displaying an "Ask" answer with code blocks
- 4cbcc5b: Rollback of scalar modal while fixing perf issue
- 3996110: Optimize images rendered in community ads
- 133c3e7: Update design of Checkbox to be more consistent and readable
- 5096f7f: Disable KV cache for docs.gitbook.com as a test, also disable it for change-request to improve consistency
- 0f1565c: Add optional env `GITBOOK_INTEGRATIONS_HOST` to configure the host serving the integrations
- 2ff7ed1: Fix table of contents being visible on mobile when disabled at the page level
- b075f0f: Fix accessibility of the table of contents by using `aria-current` instead of `aria-selected`
- cb782a7: Fix "ip" being passed to BSA for community ads
- a7af3ca: Improving the look and feel of new section tabs
- 0bf985a: Don't show hidden pages in the empty state of a page
- d6c28a0: Update header styling of sections, variant selector, and button links
- Change position of variant selector depending on context (next to logo or in table of contents)
- Update section tab styling and animation
- Make header buttons smaller with a new `medium` button size
- Updated dependencies [51fa3ab]
- Updated dependencies [9b8d519]
- Updated dependencies [cf3045a]
- Updated dependencies [f89b31c]
- Updated dependencies [d0f4860]
- Updated dependencies [ef9d012]
- Updated dependencies [094e9cd]
- Updated dependencies [636b868]
- Updated dependencies [56f5fa1]
- Updated dependencies [5c35f36]
- Updated dependencies [4247361]
- Updated dependencies [aa8c49e]
- Updated dependencies [e914903]
- Updated dependencies [4cbcc5b]
- Updated dependencies [0f1565c]
- Updated dependencies [237b703]
- Updated dependencies [51955da]
- Updated dependencies [a679e72]
- Updated dependencies [c079c3c]
- Updated dependencies [5c35f36]
- Updated dependencies [776bc31]
- @gitbook/react-openapi@0.7.0
- @gitbook/cache-do@0.1.0
- @gitbook/icons@0.1.0
- @gitbook/react-contentkit@0.5.1
- @gitbook/react-math@0.6.0
## 0.3.0
### Minor Changes
+56 -34
View File
@@ -3,7 +3,6 @@ import {
CustomizationHeaderPreset,
CustomizationIconsStyle,
CustomizationLocale,
PublishedSiteContentLookup,
SiteCustomizationSettings,
} from '@gitbook/api';
import { test, expect, Page } from '@playwright/test';
@@ -15,7 +14,7 @@ import { getContentTestURL } from '../tests/utils';
interface Test {
name: string;
url: string | (() => Promise<string>); // URL to visit for testing
url: string; // URL to visit for testing
run?: (page: Page) => Promise<unknown>; // The test to run
fullPage?: boolean; // Whether the test should be fullscreened during testing
screenshot?: false; // Should a screenshot be stored
@@ -396,6 +395,10 @@ const testCases: TestsCase[] = [
await page.click('[data-testid="annotation-button"]');
},
},
{
name: 'Stepper',
url: 'blocks/stepper',
},
],
},
{
@@ -463,13 +466,11 @@ const testCases: TestsCase[] = [
{
title: 'Secondary button',
to: { kind: 'url', url: 'https://www.gitbook.com' },
// @ts-ignore Remove once we upgrade to the latest version of the API
style: 'button-secondary',
},
{
title: 'Primary button',
to: { kind: 'url', url: 'https://www.gitbook.com' },
// @ts-ignore Remove once we upgrade to the latest version of the API
style: 'button-primary',
},
],
@@ -490,13 +491,62 @@ const testCases: TestsCase[] = [
},
],
},
{
name: 'Shared space navigation (first site)',
baseUrl: 'https://gitbook-open-e2e-sites.gitbook.io/shared-space-uno/',
tests: [
{
name: 'Navigation to shared space',
url: '',
run: async (page) => {
const sharedSpaceLink = page.locator('a.underline');
await sharedSpaceLink.click();
expect(page.locator('h1')).toHaveText('shared');
const url = page.url();
expect(url.includes('shared-space-uno')).toBeTruthy(); // same uno site
expect(url.endsWith('/shared')).toBeTruthy(); // correct page
},
},
],
},
{
name: 'Shared space navigation (second site)',
baseUrl: 'https://gitbook-open-e2e-sites.gitbook.io/shared-space-dos/',
tests: [
{
name: 'Navigation to shared space',
url: '',
run: async (page) => {
const sharedSpaceLink = page.locator('a.underline');
await sharedSpaceLink.click();
expect(page.locator('h1')).toHaveText('shared');
const url = page.url();
expect(url.includes('shared-space-dos')).toBeTruthy(); // same dos site
expect(url.endsWith('/shared')).toBeTruthy(); // correct page
},
},
],
},
{
name: 'Site Redirects',
baseUrl: 'https://gitbook-open-e2e-sites.gitbook.io/gitbook-doc/',
tests: [
{
name: 'Redirect to SSO page',
url: 'a/redirect/to/sso',
run: async (page) => {
await expect(page.locator('h1')).toHaveText('SSO');
},
},
],
},
{
name: 'Share links',
baseUrl: 'https://gitbook.gitbook.io/gbo-tests-share-links/',
tests: [
{
name: 'Valid link',
url: 'TGs8PkF4GWVtbmPnWhYL/',
url: 'thDznyWXCeEoT55WB7HC/',
},
{
name: 'Invalid link',
@@ -764,32 +814,6 @@ const testCases: TestsCase[] = [
},
],
},
{
name: 'open.gitbook.com',
baseUrl: 'https://open.gitbook.com/',
tests: [
{
name: 'GitBook Docs',
url: async () => {
const res = await fetch(
`https://api.gitbook.com/v1/urls/published?url=https://docs.gitbook.com`,
);
if (!res.ok) {
throw new Error('Failed to get published URL');
}
const published = await res.json<PublishedSiteContentLookup>();
if (!('site' in published)) {
throw new Error('Expected site for published URL');
}
return `~site/${published.site}?token=${published.apiToken}`;
},
run: waitForCookiesDialog,
},
],
},
];
for (const testCase of testCases) {
@@ -797,9 +821,7 @@ for (const testCase of testCases) {
for (const testEntry of testCase.tests) {
const testFn = testEntry.only ? test.only : test;
testFn(testEntry.name, async ({ page, baseURL }) => {
const testEntryUrl =
typeof testEntry.url === 'string' ? testEntry.url : await testEntry.url();
const contentUrl = new URL(testEntryUrl, testCase.baseUrl);
const contentUrl = new URL(testEntry.url, testCase.baseUrl);
const url = getContentTestURL(contentUrl.toString(), baseURL);
await page.goto(url);
if (testEntry.run) {
+6 -6
View File
@@ -1,11 +1,11 @@
{
"name": "gitbook",
"version": "0.3.0",
"version": "0.4.0",
"private": true,
"scripts": {
"dev": "env-cmd --silent -f ../../.env.local next dev",
"build": "next build",
"build:cloudflare": "next-on-pages",
"build:cloudflare": "next-on-pages --custom-entrypoint=./src/cloudflare-entrypoint.ts",
"start": "next start",
"lint": "next lint",
"typecheck": "tsc --noEmit",
@@ -16,7 +16,7 @@
"clean": "rm -rf ./.next && rm -rf ./public/~gitbook/static"
},
"dependencies": {
"@gitbook/api": "0.60.0",
"@gitbook/api": "^0.77.0",
"@gitbook/cache-do": "workspace:*",
"@gitbook/emoji-codepoints": "workspace:*",
"@gitbook/icons": "workspace:*",
@@ -41,7 +41,7 @@
"katex": "^0.16.9",
"mathjax": "^3.2.2",
"memoizee": "^0.4.15",
"next": "^14.2.5",
"next": "14.2.15",
"next-themes": "^0.2.1",
"nuqs": "^1.17.4",
"object-hash": "^3.0.0",
@@ -60,7 +60,7 @@
"remark-rehype": "^11.1.0",
"rison": "^0.1.1",
"server-only": "^0.0.1",
"shiki": "^1.11.1",
"shiki": "^1.23.1",
"tailwind-merge": "^2.2.0",
"tailwind-shades": "^1.1.2",
"unified": "^11.0.4",
@@ -69,7 +69,7 @@
"devDependencies": {
"@argos-ci/playwright": "^2.0.0",
"@playwright/test": "^1.42.1",
"@cloudflare/next-on-pages": "^1.13.3",
"@cloudflare/next-on-pages": "^1.13.5",
"@cloudflare/workers-types": "^4.20240725.0",
"@types/js-cookie": "^3.0.6",
"@types/jsontoxml": "^1.0.5",
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

@@ -8,10 +8,10 @@ import { useScrollPage } from '@/components/hooks';
/**
* Client component to initialize interactivity for a page.
*/
export function PageClientLayout(props: {}) {
export function PageClientLayout(props: { withSections?: boolean }) {
// We use this hook in the page layout to ensure the elements for the blocks
// are rendered before we scroll to a hash or to the top of the page
useScrollPage();
useScrollPage({ scrollMarginTop: props.withSections ? 50 : undefined });
useStripFallbackQueryParam();
return null;
@@ -1,14 +1,11 @@
import { getSpaceLanguage, t } from '@/intl/server';
import { getCurrentSiteLayoutData, getSpaceLayoutData } from '@/lib/api';
import { getSiteData } from '@/lib/api';
import { getSiteContentPointer } from '@/lib/pointer';
import { tcls } from '@/lib/tailwind';
import { getContentPointer } from '../../fetch';
export default async function NotFound() {
const pointer = getContentPointer();
const { customization } = await ('siteId' in pointer
? getCurrentSiteLayoutData(pointer)
: getSpaceLayoutData(pointer.spaceId));
const pointer = getSiteContentPointer();
const { customization } = await getSiteData(pointer);
const language = getSpaceLanguage(customization);
@@ -29,8 +29,9 @@ export default async function Page(props: {
const {
content: contentPointer,
contentTarget,
sections,
space,
parent,
site,
customization,
pages,
page,
@@ -65,22 +66,39 @@ export default async function Page(props: {
const withPageFeedback = customization.feedback.enabled;
const contentRefContext: ContentRefContext = {
siteContext: 'siteId' in contentPointer ? contentPointer : null,
siteContext: contentPointer,
space,
revisionId: contentTarget.revisionId,
pages,
page,
};
const withSections = Boolean(sections && sections.list.length > 0);
const headerOffset = { sectionsHeader: withSections, topHeader: withTopHeader };
return (
<>
{withFullPageCover && page.cover ? (
<PageCover as="full" page={page} cover={page.cover} context={contentRefContext} />
) : null}
<div className={tcls('flex', 'flex-row')}>
{/* We use a flex row reverse to render the aside first because the page is streamed. */}
<div className="flex flex-row-reverse justify-end">
{page.layout.outline ? (
<PageAside
space={space}
site={site}
customization={customization}
page={page}
document={document}
withHeaderOffset={headerOffset}
withFullPageCover={withFullPageCover}
withPageFeedback={withPageFeedback}
context={contentRefContext}
/>
) : null}
<PageBody
space={space}
contentPointer={contentPointer}
pointer={contentPointer}
contentTarget={contentTarget}
customization={customization}
context={contentRefContext}
@@ -91,22 +109,9 @@ export default async function Page(props: {
withPageFeedback && !page.layout.outline
}
/>
{page.layout.outline ? (
<PageAside
space={space}
site={parent?.object === 'site' ? parent : undefined}
customization={customization}
page={page}
document={document}
withHeaderOffset={withTopHeader}
withFullPageCover={withFullPageCover}
withPageFeedback={withPageFeedback}
context={contentRefContext}
/>
) : null}
</div>
<React.Suspense fallback={null}>
<PageClientLayout />
<PageClientLayout withSections={withSections} />
</React.Suspense>
</>
);
@@ -130,7 +135,7 @@ export async function generateMetadata({
params: PagePathParams;
searchParams: { fallback?: string };
}): Promise<Metadata> {
const { space, pages, page, customization, parent, ancestors } = await getPageDataWithFallback({
const { space, pages, page, customization, site, ancestors } = await getPageDataWithFallback({
pagePathParams: params,
searchParams,
});
@@ -140,7 +145,7 @@ export async function generateMetadata({
}
return {
title: [page.title, getContentTitle(space, customization, parent)]
title: [page.title, getContentTitle(space, customization, site ?? null)]
.filter(Boolean)
.join(' | '),
description: page.description ?? '',
@@ -154,7 +159,7 @@ export async function generateMetadata({
],
},
robots:
isSpaceIndexable({ space, parent }) && isPageIndexable(ancestors, page)
isSpaceIndexable({ space, site: site ?? null }) && isPageIndexable(ancestors, page)
? 'index, follow'
: 'noindex, nofollow',
};
@@ -18,7 +18,7 @@ import { getContentTitle } from '@/lib/utils';
import { ClientContexts } from './ClientContexts';
import { RocketLoaderDetector } from './RocketLoaderDetector';
import { fetchSpaceData } from '../fetch';
import { fetchContentData } from '../fetch';
export const runtime = 'edge';
@@ -35,11 +35,12 @@ export default async function ContentLayout(props: { children: React.ReactNode }
contentTarget,
customization,
pages,
parent,
site,
spaces,
ancestors,
scripts,
} = await fetchSpaceData();
sections,
} = await fetchContentData();
ReactDOM.preconnect(api().endpoint);
if (assetsDomain) {
@@ -64,8 +65,9 @@ export default async function ContentLayout(props: { children: React.ReactNode }
<SpaceLayout
space={space}
contentTarget={contentTarget}
parent={parent}
site={site}
spaces={spaces}
sections={sections}
customization={customization}
pages={pages}
ancestors={ancestors}
@@ -97,7 +99,7 @@ export default async function ContentLayout(props: { children: React.ReactNode }
}
export async function generateViewport(): Promise<Viewport> {
const { customization } = await fetchSpaceData();
const { customization } = await fetchContentData();
return {
colorScheme: customization.themes.toggeable
? customization.themes.default === CustomizationThemeMode.Dark
@@ -108,11 +110,11 @@ export async function generateViewport(): Promise<Viewport> {
}
export async function generateMetadata(): Promise<Metadata> {
const { space, parent, customization } = await fetchSpaceData();
const { space, site, customization } = await fetchContentData();
const customIcon = 'icon' in customization.favicon ? customization.favicon.icon : null;
return {
title: getContentTitle(space, customization, parent),
title: getContentTitle(space, customization, site),
generator: `GitBook (${buildVersion()})`,
metadataBase: new URL(baseUrl()),
icons: {
@@ -133,7 +135,7 @@ export async function generateMetadata(): Promise<Metadata> {
},
],
},
robots: isSpaceIndexable({ space, parent }) ? 'index, follow' : 'noindex, nofollow',
robots: isSpaceIndexable({ space, site }) ? 'index, follow' : 'noindex, nofollow',
};
}
@@ -0,0 +1,34 @@
import { NextRequest } from 'next/server';
import { getSpace, getSite } from '@/lib/api';
import { absoluteHref } from '@/lib/links';
import { getSiteContentPointer } from '@/lib/pointer';
import { isSpaceIndexable } from '@/lib/seo';
export const runtime = 'edge';
/**
* Generate a robots.txt for the current space.
*/
export async function GET(req: NextRequest) {
const pointer = getSiteContentPointer();
const [site, space] = await Promise.all([
getSite(pointer.organizationId, pointer.siteId),
getSpace(pointer.spaceId, pointer.siteShareKey),
]);
const lines = [
`User-agent: *`,
'Disallow: /~gitbook/',
...(isSpaceIndexable({ space, site })
? [`Allow: /`, `Sitemap: ${absoluteHref(`/sitemap.xml`, true)}`]
: [`Disallow: /`]),
];
const content = lines.join('\n');
return new Response(content, {
headers: {
'Content-Type': 'text/plain',
},
});
}
@@ -5,21 +5,17 @@ import { NextRequest } from 'next/server';
import { getSpaceContentData } from '@/lib/api';
import { absoluteHref } from '@/lib/links';
import { getPagePath } from '@/lib/pages';
import { getSiteContentPointer } from '@/lib/pointer';
import { isPageIndexable } from '@/lib/seo';
import { getContentPointer } from '../../fetch';
export const runtime = 'edge';
/**
* Generate a sitemap.xml for the current space.
*/
export async function GET(req: NextRequest) {
const pointer = getContentPointer();
const { pages: rootPages } = await getSpaceContentData(
pointer,
'siteId' in pointer ? pointer.siteShareKey : undefined,
);
const pointer = getSiteContentPointer();
const { pages: rootPages } = await getSpaceContentData(pointer, pointer.siteShareKey);
const pages = flattenPages(rootPages, (page) => !page.hidden && isPageIndexable([], page));
const urls = pages.map(({ page, depth }) => {
@@ -88,10 +84,12 @@ function flattenPages(
return [
...(page.type === 'document' ? [{ page, depth }] : []),
...page.pages.flatMap((child) =>
child.type === 'link' ? [] : flattenPage(child, depth + 1),
child.type === 'document' ? flattenPage(child, depth + 1) : [],
),
];
};
return rootPags.flatMap((page) => (page.type === 'link' ? [] : flattenPage(page, 0)));
return rootPags.flatMap((page) =>
page.type === 'group' || page.type === 'document' ? flattenPage(page, 0) : [],
);
}
@@ -1,18 +1,11 @@
import { ContentVisibility } from '@gitbook/api';
import { notFound } from 'next/navigation';
import { ImageResponse } from 'next/og';
import { NextRequest } from 'next/server';
import React from 'react';
import { getContentPointer } from '@/app/(space)/fetch';
import {
getCollection,
getCurrentSiteCustomization,
getSite,
getSpace,
getSpaceCustomization,
} from '@/lib/api';
import { getSite, getSiteData, getSpace } from '@/lib/api';
import { getEmojiForCode } from '@/lib/emojis';
import { getSiteContentPointer } from '@/lib/pointer';
import { tcls } from '@/lib/tailwind';
import { getContentTitle } from '@/lib/utils';
@@ -42,20 +35,15 @@ export async function GET(req: NextRequest) {
const options = getOptions(req.url);
const size = SIZES[options.size];
const pointer = getContentPointer();
const pointer = getSiteContentPointer();
const spaceId = pointer.spaceId;
const [space, customization] = await Promise.all([
getSpace(spaceId, 'siteId' in pointer ? pointer.siteShareKey : undefined),
'siteId' in pointer ? getCurrentSiteCustomization(pointer) : getSpaceCustomization(spaceId),
const [space, { customization }] = await Promise.all([
getSpace(spaceId, pointer.siteShareKey),
getSiteData(pointer),
]);
const parent =
'siteId' in pointer
? await getSite(pointer.organizationId, pointer.siteId)
: space.visibility === ContentVisibility.InCollection && space.parent
? await getCollection(space.parent)
: null;
const contentTitle = getContentTitle(space, customization, parent);
const site = await getSite(pointer.organizationId, pointer.siteId);
const contentTitle = getContentTitle(space, customization, site);
return new ImageResponse(
(
@@ -0,0 +1,223 @@
import { CustomizationHeaderPreset } from '@gitbook/api';
import { redirect } from 'next/navigation';
import { ImageResponse } from 'next/og';
import { NextRequest } from 'next/server';
import colorContrast from 'postcss-color-contrast/js';
import React from 'react';
import { absoluteHref } from '@/lib/links';
import { tcls } from '@/lib/tailwind';
import { getContentTitle } from '@/lib/utils';
import { PageIdParams, fetchPageData } from '../../../../fetch';
export const runtime = 'edge';
/**
* Render the OpenGraph image for a space.
*/
export async function GET(req: NextRequest, { params }: { params: PageIdParams }) {
const { space, page, customization, site } = await fetchPageData(params);
if (customization.socialPreview.url) {
// If user configured a custom social preview, we redirect to it.
redirect(customization.socialPreview.url);
}
// TODO: Support all fonts available in GitBook
// Right now this is impossible since next/font/google does not expose the cached font file
// Another option would be to use the Satori prop `loadAdditionalAsset` [example](https://github.com/vercel/satori/blob/main/playground/pages/index.tsx),
// but this prop isn't (yet) exposed through `ImageResponse`.
const interRegular = await fetch(
new URL('../../../../../../fonts/Inter/Inter-Regular.ttf', import.meta.url),
).then((res) => res.arrayBuffer());
const interBold = await fetch(
new URL('../../../../../../fonts/Inter/Inter-Bold.ttf', import.meta.url),
).then((res) => res.arrayBuffer());
const theme = customization.themes.default;
const useLightTheme = theme === 'light';
// We have no access to CSS variables, so we'll have to hardcode some values
const baseColors = {
light: '#ffffff',
dark: '#111827',
};
let colors = {
background: baseColors[theme],
gradient: customization.styling.primaryColor[theme],
title: customization.styling.primaryColor[theme],
body: baseColors[useLightTheme ? 'dark' : 'light'], // Invert text on background
};
const gridWhite = absoluteHref('~gitbook/static/images/ogimage-grid-white.png', true);
const gridBlack = absoluteHref('~gitbook/static/images/ogimage-grid-black.png', true);
let gridAsset = useLightTheme ? gridBlack : gridWhite;
switch (customization.header.preset) {
case CustomizationHeaderPreset.Custom:
colors = {
background: customization.header.backgroundColor?.[theme] || colors.background,
gradient: customization.header.linkColor?.[theme] || colors.gradient,
title: customization.header.linkColor?.[theme] || colors.title,
body: colorContrast(
customization.header.backgroundColor?.[theme] || colors.background,
[baseColors.light, baseColors.dark],
),
};
gridAsset = colors.body == baseColors.light ? gridWhite : gridBlack;
break;
case CustomizationHeaderPreset.Bold:
colors = {
background: customization.styling.primaryColor[theme],
gradient: colorContrast(customization.styling.primaryColor[theme], [
baseColors.light,
baseColors.dark,
]),
title: colorContrast(customization.styling.primaryColor[theme], [
baseColors.light,
baseColors.dark,
]),
body: colorContrast(customization.styling.primaryColor[theme], [
baseColors.light,
baseColors.dark,
]),
};
gridAsset = colors.body == baseColors.light ? gridWhite : gridBlack;
break;
}
const favicon = function () {
if ('icon' in customization.favicon)
return (
<img
src={customization.favicon.icon[theme]}
width={40}
height={40}
tw={tcls('mr-4')}
alt="Icon"
/>
);
if ('emoji' in customization.favicon)
return (
<span tw={tcls('text-4xl', 'mr-4')}>
{String.fromCodePoint(parseInt('0x' + customization.favicon.emoji))}
</span>
);
return (
<img
src={absoluteHref(
`~gitbook/icon?size=medium&theme=${customization.themes.default}`,
true,
)}
alt="Icon"
width={40}
height={40}
tw={tcls('mr-4')}
/>
);
};
return new ImageResponse(
(
<div
tw={tcls(
'justify-between',
'p-20',
'relative',
'w-full',
'h-full',
'flex',
'flex-col',
`bg-[${colors.background}]`,
`text-[${colors.body}]`,
)}
>
{/* Gradient */}
<div
tw={tcls('absolute', 'inset-0')}
style={{
backgroundImage: `radial-gradient(ellipse 100% 100% at top right , ${colors.gradient}, ${colors.gradient}00)`,
opacity: 0.5,
}}
></div>
{/* Grid */}
<img
tw={tcls('absolute', 'inset-0', 'w-[100vw]', 'h-[100vh]')}
src={gridAsset}
alt="Grid"
/>
{/* Logo */}
{customization.header.logo ? (
<img
alt="Logo"
height={60}
src={
useLightTheme
? customization.header.logo.light
: customization.header.logo.dark
}
/>
) : (
<div tw={tcls('flex')}>
{favicon()}
<h3 tw={tcls('text-4xl', 'my-0')}>
{getContentTitle(space, customization, site ?? null)}
</h3>
</div>
)}
{/* Title and description */}
<div tw={tcls('flex', 'flex-col')}>
<h1
tw={tcls(
'text-8xl',
'my-0',
'tracking-tight',
'leading-none',
'text-left',
`text-[${colors.title}]`,
'font-bold',
)}
>
{page
? page.title.length > 64
? page.title.slice(0, 64) + '...'
: page.title
: 'Not found'}
</h1>
{page?.description && page?.title.length <= 64 ? (
<h2 tw={tcls('text-4xl', 'mb-0', 'mt-8', 'w-[75%]', 'font-normal')}>
{page.description.length > 164
? page.description.slice(0, 164) + '...'
: page.description}
</h2>
) : null}
</div>
</div>
),
{
width: 1200,
height: 630,
fonts: [
{
name: 'Inter',
data: interRegular,
weight: 400,
style: 'normal',
},
{
name: 'Inter',
data: interBold,
weight: 700,
style: 'normal',
},
],
},
);
}
+145
View File
@@ -0,0 +1,145 @@
import { RevisionPage } from '@gitbook/api';
import { redirect } from 'next/navigation';
import {
getRevisionPageByPath,
getDocument,
getSpaceContentData,
getSiteData,
getSiteRedirectBySource,
} from '@/lib/api';
import { resolvePagePath, resolvePageId } from '@/lib/pages';
import { getSiteContentPointer } from '@/lib/pointer';
export interface PagePathParams {
pathname?: string[];
}
export interface PageIdParams {
pageId: string;
}
/**
* Fetch all the data needed to render the content layout.
*/
export async function fetchContentData() {
const content = getSiteContentPointer();
const [{ space, contentTarget, pages }, { customization, site, sections, spaces, scripts }] =
await Promise.all([
getSpaceContentData(content, content.siteShareKey),
getSiteData(content),
]);
// we grab the space attached to the parent as it contains overriden customizations
const spaceRelativeToParent = spaces?.find((space) => space.id === content.spaceId);
return {
content,
contentTarget,
space: spaceRelativeToParent ?? space,
pages,
site,
sections,
spaces,
shareKey: content.siteShareKey,
customization,
scripts,
ancestors: [],
};
}
/**
* Fetch all the data needed to render the content.
* Optimized to fetch in parallel as much as possible.
*/
export async function fetchPageData(params: PagePathParams | PageIdParams) {
const contentData = await fetchContentData();
const page = await resolvePage({
organizationId: contentData.space.organization,
siteId: contentData.site.id,
spaceId: contentData.contentTarget.spaceId,
revisionId: contentData.contentTarget.revisionId,
pages: contentData.pages,
shareKey: contentData.shareKey,
params,
});
const document = page?.page.documentId
? await getDocument(contentData.space.id, page.page.documentId)
: null;
return {
...contentData,
...page,
document,
};
}
/**
* Resolve a page from the params.
* If the path can't be found, we try to resolve it from the API to handle redirects.
*/
async function resolvePage(input: {
organizationId: string;
siteId: string;
spaceId: string;
revisionId: string;
shareKey: string | undefined;
pages: RevisionPage[];
params: PagePathParams | PageIdParams;
}) {
const { organizationId, siteId, spaceId, revisionId, pages, shareKey, params } = input;
if ('pageId' in params) {
return resolvePageId(pages, params.pageId);
}
const rawPathname = getPathnameParam(params);
const pathname = normalizePathname(rawPathname);
// When resolving a page, we use the lowercased pathname
const page = resolvePagePath(pages, pathname);
if (page) {
return page;
}
// We don't test path that are too long as GitBook doesn't support them and will return a 404 anyway.
if (rawPathname.length <= 512) {
// If page can't be found, we try with the API, in case we have a redirect at space level.
// We use the raw pathname to handle special/malformed redirects setup by users in the GitSync.
// The page rendering will take care of redirecting to a normalized pathname.
const resolved = await getRevisionPageByPath(spaceId, revisionId, rawPathname);
if (resolved) {
return resolvePageId(pages, resolved.id);
}
// If a page still can't be found, we try with the API, in case we have a redirect at site level.
const resolvedSiteRedirect = await getSiteRedirectBySource({
organizationId,
siteId,
source: rawPathname.startsWith('/') ? rawPathname : `/${rawPathname}`,
siteShareKey: input.shareKey,
});
if (resolvedSiteRedirect) {
return redirect(resolvedSiteRedirect.target);
}
}
return undefined;
}
/**
* Get the page path from the params.
*/
export function getPathnameParam(params: PagePathParams): string {
const { pathname } = params;
return pathname ? pathname.map((part) => decodeURIComponent(part)).join('/') : '';
}
/**
* Normalize the URL pathname into the format used in the revision page path.
*/
export function normalizePathname(pathname: string) {
return pathname.toLowerCase();
}
@@ -0,0 +1,18 @@
import { CustomizationRootLayout } from '@/components/RootLayout';
import { getSiteData } from '@/lib/api';
import { getSiteContentPointer } from '@/lib/pointer';
/**
* Layout to be used for the site root. It fetches the customization data for the site
* and initializes the CustomizationRootLayout with it.
*/
export default async function SiteRootLayout(props: { children: React.ReactNode }) {
const { children } = props;
const pointer = getSiteContentPointer();
const { customization } = await getSiteData(pointer);
return (
<CustomizationRootLayout customization={customization}>{children}</CustomizationRootLayout>
);
}
@@ -1,42 +0,0 @@
import { ContentVisibility } from '@gitbook/api';
import { NextRequest } from 'next/server';
import { getCollection, getSite, getSpace } from '@/lib/api';
import { absoluteHref } from '@/lib/links';
import { isSpaceIndexable } from '@/lib/seo';
import { getContentPointer } from '../../fetch';
export const runtime = 'edge';
/**
* Generate a robots.txt for the current space.
*/
export async function GET(req: NextRequest) {
const pointer = getContentPointer();
const space = await getSpace(
pointer.spaceId,
'siteId' in pointer ? pointer.siteShareKey : undefined,
);
const parent =
'siteId' in pointer
? await getSite(pointer.organizationId, pointer.siteId)
: space.visibility === ContentVisibility.InCollection && space.parent
? await getCollection(space.parent)
: null;
const lines = [
`User-agent: *`,
'Disallow: /~gitbook/',
...(isSpaceIndexable({ space, parent })
? [`Allow: /`, `Sitemap: ${absoluteHref(`/sitemap.xml`, true)}`]
: [`Disallow: /`]),
];
const content = lines.join('\n');
return new Response(content, {
headers: {
'Content-Type': 'text/plain',
},
});
}

Some files were not shown because too many files have changed in this diff Show More