mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-14 14:45:17 +00:00
Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 02b1bdbfa1 | |||
| 6217a2ed3b | |||
| ffa866cb99 | |||
| 011aa931cf | |||
| 68308154b5 | |||
| 36af03f4d5 | |||
| cbc71a56b6 | |||
| 1420180220 | |||
| e1b2cf6d81 | |||
| c0e9c49679 | |||
| afc4bd4415 | |||
| bcfa8d8b19 | |||
| 43766d6519 | |||
| 42c17f5c74 | |||
| d655d3eece | |||
| 3500de95e8 | |||
| 7f03b94949 | |||
| f0cf060191 | |||
| 5a137e7b14 | |||
| 28f7fbaa8a | |||
| ff96bb5787 | |||
| 87841124e0 | |||
| a650b58276 | |||
| 388b20d44f | |||
| ea7e94fc51 | |||
| d30bcbabdb | |||
| fb858a1941 | |||
| cc2e615b9a | |||
| a862cde6b4 | |||
| e2b7bec162 | |||
| c1b577ecc9 | |||
| ba7ec14f76 | |||
| 9f0117723c | |||
| f72b6a20db | |||
| 2f798209bb | |||
| eec8f16424 | |||
| 885264f132 | |||
| f1a6dec951 | |||
| 44f41510fa | |||
| f220229e5e | |||
| 61b4cb8d7c | |||
| 185cdb4883 | |||
| 2cdba53451 | |||
| 950f6c36cf | |||
| ea37977b1e | |||
| 81da82aed7 | |||
| 39a3518651 | |||
| d903273759 | |||
| d130532f69 | |||
| 94fcd21f34 | |||
| 1d2db4ae2b | |||
| d270b4af9b | |||
| ccfbd3c1a8 | |||
| 5c4923557f | |||
| b1f608b865 | |||
| c7993756dd | |||
| d02465823f | |||
| 6b9f6b5b79 | |||
| df7de8fb0c | |||
| 72f5ce3985 | |||
| 04c80262e2 | |||
| 56d1b8fe2d | |||
| 054a1634ab | |||
| 6ff63f2db6 | |||
| b5ad0ce1e5 | |||
| 2ba7e54c81 | |||
| 0a858e74ad | |||
| b0c534fc2c | |||
| 250c194a02 | |||
| 5b10cde936 | |||
| 4aeb81bfa5 | |||
| 955cebf944 | |||
| 7c951ef437 | |||
| 68f0dbcc35 | |||
| 39c4f76aea | |||
| 2fe58e8cbb | |||
| 765141a4d8 | |||
| eb1bd3aa01 | |||
| b7284b0223 | |||
| 5bbd254742 | |||
| 611e28626a |
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Improve `Button` and `ButtonGroup` styling
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix scroll of page outline
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Support "objectivec" as alias for Objective C syntax
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Support custom AI providers
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@gitbook/browser-types": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
First version of the public package for typing script integrations.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Small fixes to search modal
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fixes to `PageAside`
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Tweaks to AIChatButton and AIChatInput
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Allow integrations to provide tools to the Docs Assistant
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Improve vertical alignment of site items and fix floating page aside
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix search bar layout shift caused by ToC
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Emit a <link rel="alternate"> for the markdown version of a page
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'gitbook': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Support new coverDefinitionDark for cards & image type
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Clear AI chat properly
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix bug in search highlight in GBO
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Page outline: scroll to active item
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"@gitbook/openapi-parser": patch
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Improve OpenAPI parsing errors
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix Custom logo not rendering on the published site
|
||||||
@@ -102,7 +102,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Visual Testing v2
|
name: Visual Testing v2
|
||||||
needs: deploy-v2-vercel
|
needs: deploy-v2-vercel
|
||||||
timeout-minutes: 10
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -123,7 +123,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Visual Testing v2 (Cloudflare)
|
name: Visual Testing v2 (Cloudflare)
|
||||||
needs: deploy-v2-cloudflare
|
needs: deploy-v2-cloudflare
|
||||||
timeout-minutes: 10
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -144,7 +144,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Visual Testing Customers v2
|
name: Visual Testing Customers v2
|
||||||
needs: deploy-v2-vercel
|
needs: deploy-v2-vercel
|
||||||
timeout-minutes: 10
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -165,7 +165,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Visual Testing Customers v2 (Cloudflare)
|
name: Visual Testing Customers v2 (Cloudflare)
|
||||||
needs: deploy-v2-cloudflare
|
needs: deploy-v2-cloudflare
|
||||||
timeout-minutes: 10
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|||||||
+2
-1
@@ -21,7 +21,8 @@
|
|||||||
"packages/openapi-parser/src/fixtures/**/*",
|
"packages/openapi-parser/src/fixtures/**/*",
|
||||||
"packages/emoji-codepoints/index.ts",
|
"packages/emoji-codepoints/index.ts",
|
||||||
"packages/icons/src/data/*.json",
|
"packages/icons/src/data/*.json",
|
||||||
"packages/gitbook/worker-configuration.d.ts"
|
"packages/gitbook/worker-configuration.d.ts",
|
||||||
|
"**/*.css"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"formatter": {
|
"formatter": {
|
||||||
|
|||||||
@@ -10,6 +10,17 @@
|
|||||||
"vercel": "^39.3.0",
|
"vercel": "^39.3.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"packages/browser-types": {
|
||||||
|
"name": "@gitbook/browser-types",
|
||||||
|
"version": "0.3.1",
|
||||||
|
"dependencies": {
|
||||||
|
"@gitbook/api": "catalog:",
|
||||||
|
"@gitbook/icons": "workspace:",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.5.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
"packages/cache-tags": {
|
"packages/cache-tags": {
|
||||||
"name": "@gitbook/cache-tags",
|
"name": "@gitbook/cache-tags",
|
||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
@@ -48,9 +59,10 @@
|
|||||||
},
|
},
|
||||||
"packages/gitbook": {
|
"packages/gitbook": {
|
||||||
"name": "gitbook",
|
"name": "gitbook",
|
||||||
"version": "0.13.1",
|
"version": "0.15.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitbook/api": "catalog:",
|
"@gitbook/api": "catalog:",
|
||||||
|
"@gitbook/browser-types": "workspace:*",
|
||||||
"@gitbook/cache-tags": "workspace:*",
|
"@gitbook/cache-tags": "workspace:*",
|
||||||
"@gitbook/colors": "workspace:*",
|
"@gitbook/colors": "workspace:*",
|
||||||
"@gitbook/emoji-codepoints": "workspace:*",
|
"@gitbook/emoji-codepoints": "workspace:*",
|
||||||
@@ -60,7 +72,7 @@
|
|||||||
"@gitbook/react-contentkit": "workspace:*",
|
"@gitbook/react-contentkit": "workspace:*",
|
||||||
"@gitbook/react-math": "workspace:*",
|
"@gitbook/react-math": "workspace:*",
|
||||||
"@gitbook/react-openapi": "workspace:*",
|
"@gitbook/react-openapi": "workspace:*",
|
||||||
"@opennextjs/cloudflare": "^1.4.0",
|
"@opennextjs/cloudflare": "^1.6.4",
|
||||||
"@radix-ui/react-checkbox": "^1.0.4",
|
"@radix-ui/react-checkbox": "^1.0.4",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.12",
|
"@radix-ui/react-dropdown-menu": "^2.1.12",
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.3",
|
"@radix-ui/react-navigation-menu": "^1.2.3",
|
||||||
@@ -118,8 +130,9 @@
|
|||||||
"zustand": "^5.0.3",
|
"zustand": "^5.0.3",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@argos-ci/playwright": "^5.0.5",
|
"@argos-ci/playwright": "^5.0.9",
|
||||||
"@playwright/test": "^1.51.1",
|
"@playwright/test": "^1.54.2",
|
||||||
|
"@tailwindcss/postcss": "^4.1.11",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/jsontoxml": "^1.0.5",
|
"@types/jsontoxml": "^1.0.5",
|
||||||
"@types/jsonwebtoken": "^9.0.6",
|
"@types/jsonwebtoken": "^9.0.6",
|
||||||
@@ -131,14 +144,13 @@
|
|||||||
"@types/react": "18.3.13",
|
"@types/react": "18.3.13",
|
||||||
"@types/react-dom": "18.3.1",
|
"@types/react-dom": "18.3.1",
|
||||||
"@types/rison": "^0.0.9",
|
"@types/rison": "^0.0.9",
|
||||||
"autoprefixer": "^10",
|
|
||||||
"deepmerge": "^4.3.1",
|
"deepmerge": "^4.3.1",
|
||||||
"env-cmd": "^10.1.0",
|
"env-cmd": "^10.1.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"psi": "^4.1.0",
|
"psi": "^4.1.0",
|
||||||
"stylelint": "^16.16.0",
|
"stylelint": "^16.16.0",
|
||||||
"tailwindcss": "^3.4.0",
|
"tailwindcss": "^4.1.11",
|
||||||
"ts-essentials": "^10.0.1",
|
"ts-essentials": "^10.0.1",
|
||||||
"typescript": "^5.5.3",
|
"typescript": "^5.5.3",
|
||||||
"vercel": "^39.3.0",
|
"vercel": "^39.3.0",
|
||||||
@@ -146,7 +158,7 @@
|
|||||||
},
|
},
|
||||||
"packages/icons": {
|
"packages/icons": {
|
||||||
"name": "@gitbook/icons",
|
"name": "@gitbook/icons",
|
||||||
"version": "0.2.0",
|
"version": "0.2.2",
|
||||||
"bin": {
|
"bin": {
|
||||||
"gitbook-icons": "./bin/gitbook-icons.js",
|
"gitbook-icons": "./bin/gitbook-icons.js",
|
||||||
},
|
},
|
||||||
@@ -166,7 +178,7 @@
|
|||||||
},
|
},
|
||||||
"packages/openapi-parser": {
|
"packages/openapi-parser": {
|
||||||
"name": "@gitbook/openapi-parser",
|
"name": "@gitbook/openapi-parser",
|
||||||
"version": "2.2.0",
|
"version": "3.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@scalar/openapi-parser": "^0.18.0",
|
"@scalar/openapi-parser": "^0.18.0",
|
||||||
"@scalar/openapi-types": "^0.1.9",
|
"@scalar/openapi-types": "^0.1.9",
|
||||||
@@ -181,7 +193,7 @@
|
|||||||
},
|
},
|
||||||
"packages/react-contentkit": {
|
"packages/react-contentkit": {
|
||||||
"name": "@gitbook/react-contentkit",
|
"name": "@gitbook/react-contentkit",
|
||||||
"version": "0.7.1",
|
"version": "0.7.3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitbook/api": "catalog:",
|
"@gitbook/api": "catalog:",
|
||||||
"@gitbook/icons": "workspace:*",
|
"@gitbook/icons": "workspace:*",
|
||||||
@@ -196,7 +208,7 @@
|
|||||||
},
|
},
|
||||||
"packages/react-math": {
|
"packages/react-math": {
|
||||||
"name": "@gitbook/react-math",
|
"name": "@gitbook/react-math",
|
||||||
"version": "0.6.0",
|
"version": "0.6.1",
|
||||||
"bin": {
|
"bin": {
|
||||||
"gitbook-math": "./bin/gitbook-math.js",
|
"gitbook-math": "./bin/gitbook-math.js",
|
||||||
},
|
},
|
||||||
@@ -213,7 +225,7 @@
|
|||||||
},
|
},
|
||||||
"packages/react-openapi": {
|
"packages/react-openapi": {
|
||||||
"name": "@gitbook/react-openapi",
|
"name": "@gitbook/react-openapi",
|
||||||
"version": "1.3.2",
|
"version": "1.3.5",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitbook/openapi-parser": "workspace:*",
|
"@gitbook/openapi-parser": "workspace:*",
|
||||||
"@scalar/api-client-react": "^1.3.16",
|
"@scalar/api-client-react": "^1.3.16",
|
||||||
@@ -246,7 +258,7 @@
|
|||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
},
|
},
|
||||||
"catalog": {
|
"catalog": {
|
||||||
"@gitbook/api": "^0.128.0",
|
"@gitbook/api": "^0.136.0",
|
||||||
},
|
},
|
||||||
"packages": {
|
"packages": {
|
||||||
"@ai-sdk/provider": ["@ai-sdk/provider@1.1.0", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-0M+qjp+clUD0R1E5eWQFhxEvWLNaOtGQRUaBn8CUABnSKredagq92hUS9VjOzGsTm37xLfpaxl97AVtbeOsHew=="],
|
"@ai-sdk/provider": ["@ai-sdk/provider@1.1.0", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-0M+qjp+clUD0R1E5eWQFhxEvWLNaOtGQRUaBn8CUABnSKredagq92hUS9VjOzGsTm37xLfpaxl97AVtbeOsHew=="],
|
||||||
@@ -259,15 +271,17 @@
|
|||||||
|
|
||||||
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
|
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
|
||||||
|
|
||||||
|
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
|
||||||
|
|
||||||
"@argos-ci/api-client": ["@argos-ci/api-client@0.8.1", "", { "dependencies": { "debug": "^4.4.0", "openapi-fetch": "0.13.5" } }, "sha512-3IHv7ANSPNO6OwWgwULlHbP9/tFV9kQDu6+nL9jysfPkGj0GgtrOsyBb+iU931c7wSMo1OD+XNujCnRzDD968w=="],
|
"@argos-ci/api-client": ["@argos-ci/api-client@0.8.1", "", { "dependencies": { "debug": "^4.4.0", "openapi-fetch": "0.13.5" } }, "sha512-3IHv7ANSPNO6OwWgwULlHbP9/tFV9kQDu6+nL9jysfPkGj0GgtrOsyBb+iU931c7wSMo1OD+XNujCnRzDD968w=="],
|
||||||
|
|
||||||
"@argos-ci/browser": ["@argos-ci/browser@4.1.2", "", {}, "sha512-OljPFzxSNndWSwMBxKGtN3p8lSbt73z+/0CIXbBVTQOPjPMErXWjgtrFL23xqtTq5wdds3uxGv7tjVDWJbgBYg=="],
|
"@argos-ci/browser": ["@argos-ci/browser@4.2.0", "", {}, "sha512-xztv7hMNJyAYw2FXZDm4OCtw+jotJv0BPp5/9dljKrJ0us/2dDEEYKAvVcxzdzRpSe7VOtXSdsoFf0XCCPmxtQ=="],
|
||||||
|
|
||||||
"@argos-ci/core": ["@argos-ci/core@3.2.0", "", { "dependencies": { "@argos-ci/api-client": "0.8.1", "@argos-ci/util": "2.3.1", "axios": "^1.8.4", "convict": "^6.2.4", "debug": "^4.4.0", "fast-glob": "^3.3.3", "sharp": "^0.33.5", "tmp": "^0.2.3" } }, "sha512-wraH5RGFpoU7zcKV2BVi4LvY+5bWR/Ds6OVhUtq3jtd7I3qJRFVFq2IX1TfPPvBBA7wX0OqcrqgIWAQwy+vsoA=="],
|
"@argos-ci/core": ["@argos-ci/core@3.2.1", "", { "dependencies": { "@argos-ci/api-client": "0.8.1", "@argos-ci/util": "2.3.2", "axios": "^1.8.4", "convict": "^6.2.4", "debug": "^4.4.0", "fast-glob": "^3.3.3", "sharp": "^0.33.5", "tmp": "^0.2.3" } }, "sha512-P+tGofNLAtH0+e87M8sZc+juAtbOcnV6z2nA2MwB2OzUVVXGINJHAF2cK0ZUyXC9d8a7RL0+rQWkP4vXDA/gBw=="],
|
||||||
|
|
||||||
"@argos-ci/playwright": ["@argos-ci/playwright@5.0.5", "", { "dependencies": { "@argos-ci/browser": "4.1.2", "@argos-ci/core": "3.2.0", "@argos-ci/util": "2.3.1", "chalk": "^5.4.1", "debug": "^4.4.0" } }, "sha512-ZqaqptjI8rVUjD2KQzpvI1olFDiiMjgDaIyFOMWo8531cB7CMCwPXDNsFw2psUfsz3a3LP91eH2OrJopmevEkQ=="],
|
"@argos-ci/playwright": ["@argos-ci/playwright@5.0.9", "", { "dependencies": { "@argos-ci/browser": "4.2.0", "@argos-ci/core": "3.2.1", "@argos-ci/util": "2.3.2", "chalk": "^5.4.1", "debug": "^4.4.0" } }, "sha512-FbUPjNVm+Qer9aUU56oGNiPeynqDCh33GOYKekzjikBlxWFZfhiW4NA+sOXF0VWzGb5ni9l1U7fy6ycOTSalAA=="],
|
||||||
|
|
||||||
"@argos-ci/util": ["@argos-ci/util@2.3.1", "", {}, "sha512-kE61HU2480fbAnimmA4x9HK45ZJvkoqLdW5GxT5uvwhkclQykVd2S6WfGFUr3JokTXfZ5LZEEfoWgtGA316KSQ=="],
|
"@argos-ci/util": ["@argos-ci/util@2.3.2", "", {}, "sha512-xtNHJxpWYNst/sMNn4Jv/vkODuFsJ+APr4FBeoFUdIa+Izjl4ZFHsYA2PUyu+ygIpQCkof8yZLL9U1/VpiyyIw=="],
|
||||||
|
|
||||||
"@ast-grep/napi": ["@ast-grep/napi@0.35.0", "", { "optionalDependencies": { "@ast-grep/napi-darwin-arm64": "0.35.0", "@ast-grep/napi-darwin-x64": "0.35.0", "@ast-grep/napi-linux-arm64-gnu": "0.35.0", "@ast-grep/napi-linux-arm64-musl": "0.35.0", "@ast-grep/napi-linux-x64-gnu": "0.35.0", "@ast-grep/napi-linux-x64-musl": "0.35.0", "@ast-grep/napi-win32-arm64-msvc": "0.35.0", "@ast-grep/napi-win32-ia32-msvc": "0.35.0", "@ast-grep/napi-win32-x64-msvc": "0.35.0" } }, "sha512-3ucaaSxV6fxXoqHrE/rxAvP1THnDdY5jNzGlnvx+JvnY9C/dSRKc0jlRMRz59N3El572+/yNRUUpAV1T9aBJug=="],
|
"@ast-grep/napi": ["@ast-grep/napi@0.35.0", "", { "optionalDependencies": { "@ast-grep/napi-darwin-arm64": "0.35.0", "@ast-grep/napi-darwin-x64": "0.35.0", "@ast-grep/napi-linux-arm64-gnu": "0.35.0", "@ast-grep/napi-linux-arm64-musl": "0.35.0", "@ast-grep/napi-linux-x64-gnu": "0.35.0", "@ast-grep/napi-linux-x64-musl": "0.35.0", "@ast-grep/napi-win32-arm64-msvc": "0.35.0", "@ast-grep/napi-win32-ia32-msvc": "0.35.0", "@ast-grep/napi-win32-x64-msvc": "0.35.0" } }, "sha512-3ucaaSxV6fxXoqHrE/rxAvP1THnDdY5jNzGlnvx+JvnY9C/dSRKc0jlRMRz59N3El572+/yNRUUpAV1T9aBJug=="],
|
||||||
|
|
||||||
@@ -609,7 +623,9 @@
|
|||||||
|
|
||||||
"@fortawesome/fontawesome-svg-core": ["@fortawesome/fontawesome-svg-core@6.6.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.6.0" } }, "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg=="],
|
"@fortawesome/fontawesome-svg-core": ["@fortawesome/fontawesome-svg-core@6.6.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.6.0" } }, "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg=="],
|
||||||
|
|
||||||
"@gitbook/api": ["@gitbook/api@0.128.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-VO98hRGfUcFdwMplvFW49jz72/ew2waE7RCu+URKAY2AyPHAduv2zgluF5gF1VcDyuJM9PKFtsdsMtpUjI5sYg=="],
|
"@gitbook/api": ["@gitbook/api@0.136.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-IxNqmXE6yUEUq0IzbenN8S/PcMfgxr4+akY8xh6V5ShI/+U37ixujJHZp2zJq6NdZOdBQoR3UQmhPnvtWrkF7g=="],
|
||||||
|
|
||||||
|
"@gitbook/browser-types": ["@gitbook/browser-types@workspace:packages/browser-types"],
|
||||||
|
|
||||||
"@gitbook/cache-tags": ["@gitbook/cache-tags@workspace:packages/cache-tags"],
|
"@gitbook/cache-tags": ["@gitbook/cache-tags@workspace:packages/cache-tags"],
|
||||||
|
|
||||||
@@ -787,9 +803,9 @@
|
|||||||
|
|
||||||
"@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
|
"@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
|
||||||
|
|
||||||
"@opennextjs/aws": ["@opennextjs/aws@3.7.0", "", { "dependencies": { "@ast-grep/napi": "^0.35.0", "@aws-sdk/client-cloudfront": "3.398.0", "@aws-sdk/client-dynamodb": "^3.398.0", "@aws-sdk/client-lambda": "^3.398.0", "@aws-sdk/client-s3": "^3.398.0", "@aws-sdk/client-sqs": "^3.398.0", "@node-minify/core": "^8.0.6", "@node-minify/terser": "^8.0.6", "@tsconfig/node18": "^1.0.1", "aws4fetch": "^1.0.18", "chalk": "^5.3.0", "cookie": "^1.0.2", "esbuild": "0.25.4", "express": "5.0.1", "path-to-regexp": "^6.3.0", "urlpattern-polyfill": "^10.0.0", "yaml": "^2.7.0" }, "bin": { "open-next": "dist/index.js" } }, "sha512-JXUZice+CedEQW20hnBVqzBEj+jfr4Oe2LVYSE4RNKdfHVIeYG+WJAop14TxRJ+NugKWGcJx6opf944l+ZG7XQ=="],
|
"@opennextjs/aws": ["@opennextjs/aws@3.7.4", "", { "dependencies": { "@ast-grep/napi": "^0.35.0", "@aws-sdk/client-cloudfront": "3.398.0", "@aws-sdk/client-dynamodb": "^3.398.0", "@aws-sdk/client-lambda": "^3.398.0", "@aws-sdk/client-s3": "^3.398.0", "@aws-sdk/client-sqs": "^3.398.0", "@node-minify/core": "^8.0.6", "@node-minify/terser": "^8.0.6", "@tsconfig/node18": "^1.0.1", "aws4fetch": "^1.0.18", "chalk": "^5.3.0", "cookie": "^1.0.2", "esbuild": "0.25.4", "express": "5.0.1", "path-to-regexp": "^6.3.0", "urlpattern-polyfill": "^10.0.0", "yaml": "^2.7.0" }, "bin": { "open-next": "dist/index.js" } }, "sha512-s50dmKrgQ62GliffoI/hGGQVb3q/7ZN5VRa4jJw0ZsEGLfk25XuAulO/ySCYeE7/A23KoAYuhafnKr/h+vxOeQ=="],
|
||||||
|
|
||||||
"@opennextjs/cloudflare": ["@opennextjs/cloudflare@1.4.0", "", { "dependencies": { "@dotenvx/dotenvx": "1.31.0", "@opennextjs/aws": "3.7.0", "enquirer": "^2.4.1", "glob": "^11.0.0", "ts-tqdm": "^0.8.6" }, "peerDependencies": { "wrangler": "^4.19.1" }, "bin": { "opennextjs-cloudflare": "dist/cli/index.js" } }, "sha512-nEtxmSo6/y83Qw2TSU8rBpljaGl3NUl5GenD/c71h6YqgbP4QURSxMh7ySe7KK+vtQbilD7WePXovqL4Y6D6dw=="],
|
"@opennextjs/cloudflare": ["@opennextjs/cloudflare@1.6.4", "", { "dependencies": { "@dotenvx/dotenvx": "1.31.0", "@opennextjs/aws": "3.7.4", "cloudflare": "^4.4.1", "enquirer": "^2.4.1", "glob": "^11.0.0", "ts-tqdm": "^0.8.6", "yargs": "^18.0.0" }, "peerDependencies": { "wrangler": "^4.24.4" }, "bin": { "opennextjs-cloudflare": "dist/cli/index.js" } }, "sha512-vGEHr1+Dli4BSrs+CM+b2bnXoUdY/GUFiLfdH28UTRHggLMG7cL49M39LtzIVR5D8eqzZ38PDB2CZMn1LJ2gSw=="],
|
||||||
|
|
||||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||||
|
|
||||||
@@ -797,7 +813,7 @@
|
|||||||
|
|
||||||
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
||||||
|
|
||||||
"@playwright/test": ["@playwright/test@1.51.1", "", { "dependencies": { "playwright": "1.51.1" }, "bin": { "playwright": "cli.js" } }, "sha512-nM+kEaTSAoVlXmMPH10017vn3FSiFqr/bh4fKg9vmAdMfd9SDqRZNvPSiAHADc/itWak+qPvMPZQOPwCBW7k7Q=="],
|
"@playwright/test": ["@playwright/test@1.54.2", "", { "dependencies": { "playwright": "1.54.2" }, "bin": { "playwright": "cli.js" } }, "sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA=="],
|
||||||
|
|
||||||
"@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="],
|
"@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="],
|
||||||
|
|
||||||
@@ -1247,6 +1263,36 @@
|
|||||||
|
|
||||||
"@tailwindcss/container-queries": ["@tailwindcss/container-queries@0.1.1", "", { "peerDependencies": { "tailwindcss": ">=3.2.0" } }, "sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA=="],
|
"@tailwindcss/container-queries": ["@tailwindcss/container-queries@0.1.1", "", { "peerDependencies": { "tailwindcss": ">=3.2.0" } }, "sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA=="],
|
||||||
|
|
||||||
|
"@tailwindcss/node": ["@tailwindcss/node@4.1.11", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.11" } }, "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.11", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.11", "@tailwindcss/oxide-darwin-arm64": "4.1.11", "@tailwindcss/oxide-darwin-x64": "4.1.11", "@tailwindcss/oxide-freebsd-x64": "4.1.11", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.11", "@tailwindcss/oxide-linux-arm64-musl": "4.1.11", "@tailwindcss/oxide-linux-x64-gnu": "4.1.11", "@tailwindcss/oxide-linux-x64-musl": "4.1.11", "@tailwindcss/oxide-wasm32-wasi": "4.1.11", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.11", "@tailwindcss/oxide-win32-x64-msvc": "4.1.11" } }, "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.11", "", { "os": "android", "cpu": "arm64" }, "sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.11", "", { "os": "freebsd", "cpu": "x64" }, "sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11", "", { "os": "linux", "cpu": "arm" }, "sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.11", "", { "os": "linux", "cpu": "x64" }, "sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.11", "", { "os": "linux", "cpu": "x64" }, "sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.11", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@emnapi/wasi-threads": "^1.0.2", "@napi-rs/wasm-runtime": "^0.2.11", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.11", "", { "os": "win32", "cpu": "x64" }, "sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.11", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.11", "@tailwindcss/oxide": "4.1.11", "postcss": "^8.4.41", "tailwindcss": "4.1.11" } }, "sha512-q/EAIIpF6WpLhKEuQSEVMZNMIY8KhWoAemZ9eylNAih9jxMGAYPPWBn3I9QL/2jZ+e7OEz/tZkX5HwbBR4HohA=="],
|
||||||
|
|
||||||
"@tailwindcss/typography": ["@tailwindcss/typography@0.5.16", "", { "dependencies": { "lodash.castarray": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.merge": "^4.6.2", "postcss-selector-parser": "6.0.10" }, "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA=="],
|
"@tailwindcss/typography": ["@tailwindcss/typography@0.5.16", "", { "dependencies": { "lodash.castarray": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.merge": "^4.6.2", "postcss-selector-parser": "6.0.10" }, "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA=="],
|
||||||
|
|
||||||
"@tanstack/virtual-core": ["@tanstack/virtual-core@3.10.8", "", {}, "sha512-PBu00mtt95jbKFi6Llk9aik8bnR3tR/oQP1o3TSi+iG//+Q2RTIzCEgKkHG8BB86kxMNW6O8wku+Lmi+QFR6jA=="],
|
"@tanstack/virtual-core": ["@tanstack/virtual-core@3.10.8", "", {}, "sha512-PBu00mtt95jbKFi6Llk9aik8bnR3tR/oQP1o3TSi+iG//+Q2RTIzCEgKkHG8BB86kxMNW6O8wku+Lmi+QFR6jA=="],
|
||||||
@@ -1301,6 +1347,8 @@
|
|||||||
|
|
||||||
"@types/node": ["@types/node@20.19.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA=="],
|
"@types/node": ["@types/node@20.19.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA=="],
|
||||||
|
|
||||||
|
"@types/node-fetch": ["@types/node-fetch@2.6.12", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.0" } }, "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA=="],
|
||||||
|
|
||||||
"@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="],
|
"@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="],
|
||||||
|
|
||||||
"@types/object-hash": ["@types/object-hash@3.0.6", "", {}, "sha512-fOBV8C1FIu2ELinoILQ+ApxcUKz4ngq+IWUYrxSGjXzzjUALijilampwkMgEtJ+h2njAW3pi853QpzNVCHB73w=="],
|
"@types/object-hash": ["@types/object-hash@3.0.6", "", {}, "sha512-fOBV8C1FIu2ELinoILQ+ApxcUKz4ngq+IWUYrxSGjXzzjUALijilampwkMgEtJ+h2njAW3pi853QpzNVCHB73w=="],
|
||||||
@@ -1407,6 +1455,8 @@
|
|||||||
|
|
||||||
"agent-base": ["agent-base@7.1.3", "", {}, "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw=="],
|
"agent-base": ["agent-base@7.1.3", "", {}, "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw=="],
|
||||||
|
|
||||||
|
"agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="],
|
||||||
|
|
||||||
"ai": ["ai@4.3.0", "", { "dependencies": { "@ai-sdk/provider": "1.1.0", "@ai-sdk/provider-utils": "2.2.4", "@ai-sdk/react": "1.2.6", "@ai-sdk/ui-utils": "1.2.5", "@opentelemetry/api": "1.9.0", "jsondiffpatch": "0.6.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.23.8" }, "optionalPeers": ["react"] }, "sha512-PxyQYKhWaU3LiZEpeKRaekVonZIbWdKAwgnqm0CSAxy1MFufmYEC5SM5Mc9uiK2DoHcbAL3d1jyaQ2fSDAJL8w=="],
|
"ai": ["ai@4.3.0", "", { "dependencies": { "@ai-sdk/provider": "1.1.0", "@ai-sdk/provider-utils": "2.2.4", "@ai-sdk/react": "1.2.6", "@ai-sdk/ui-utils": "1.2.5", "@opentelemetry/api": "1.9.0", "jsondiffpatch": "0.6.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.23.8" }, "optionalPeers": ["react"] }, "sha512-PxyQYKhWaU3LiZEpeKRaekVonZIbWdKAwgnqm0CSAxy1MFufmYEC5SM5Mc9uiK2DoHcbAL3d1jyaQ2fSDAJL8w=="],
|
||||||
|
|
||||||
"ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
|
"ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
|
||||||
@@ -1429,7 +1479,7 @@
|
|||||||
|
|
||||||
"anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
|
"anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
|
||||||
|
|
||||||
"arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="],
|
"arg": ["arg@4.1.0", "", {}, "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg=="],
|
||||||
|
|
||||||
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
||||||
|
|
||||||
@@ -1453,8 +1503,6 @@
|
|||||||
|
|
||||||
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
||||||
|
|
||||||
"autoprefixer": ["autoprefixer@10.4.20", "", { "dependencies": { "browserslist": "^4.23.3", "caniuse-lite": "^1.0.30001646", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g=="],
|
|
||||||
|
|
||||||
"aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="],
|
"aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="],
|
||||||
|
|
||||||
"axios": ["axios@1.8.4", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw=="],
|
"axios": ["axios@1.8.4", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw=="],
|
||||||
@@ -1489,8 +1537,6 @@
|
|||||||
|
|
||||||
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||||
|
|
||||||
"browserslist": ["browserslist@4.24.0", "", { "dependencies": { "caniuse-lite": "^1.0.30001663", "electron-to-chromium": "^1.5.28", "node-releases": "^2.0.18", "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A=="],
|
|
||||||
|
|
||||||
"buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
|
"buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
|
||||||
|
|
||||||
"buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="],
|
"buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="],
|
||||||
@@ -1549,8 +1595,12 @@
|
|||||||
|
|
||||||
"client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="],
|
"client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="],
|
||||||
|
|
||||||
|
"cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="],
|
||||||
|
|
||||||
"clone-response": ["clone-response@1.0.3", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA=="],
|
"clone-response": ["clone-response@1.0.3", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA=="],
|
||||||
|
|
||||||
|
"cloudflare": ["cloudflare@4.5.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-fPcbPKx4zF45jBvQ0z7PCdgejVAPBBCZxwqk1k7krQNfpM07Cfj97/Q6wBzvYqlWXx/zt1S9+m8vnfCe06umbQ=="],
|
||||||
|
|
||||||
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
||||||
|
|
||||||
"code-block-writer": ["code-block-writer@10.1.1", "", {}, "sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw=="],
|
"code-block-writer": ["code-block-writer@10.1.1", "", {}, "sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw=="],
|
||||||
@@ -1653,7 +1703,7 @@
|
|||||||
|
|
||||||
"detect-indent": ["detect-indent@6.1.0", "", {}, "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="],
|
"detect-indent": ["detect-indent@6.1.0", "", {}, "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="],
|
||||||
|
|
||||||
"detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="],
|
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
|
||||||
|
|
||||||
"detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
|
"detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
|
||||||
|
|
||||||
@@ -1697,8 +1747,6 @@
|
|||||||
|
|
||||||
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
||||||
|
|
||||||
"electron-to-chromium": ["electron-to-chromium@1.5.36", "", {}, "sha512-HYTX8tKge/VNp6FGO+f/uVDmUkq+cEfcxYhKf15Akc4M5yxt5YmorwlAitKWjWhWQnKcDRBAQKXkhqqXMqcrjw=="],
|
|
||||||
|
|
||||||
"emoji-assets": ["emoji-assets@8.0.0", "", {}, "sha512-Y2M8Y5N6AUxKtE7AYj61+V3tU1CAcLQLX4kCO7HJEH1K+o2lgFd3ieiGSbZ8/qfz6qYxr0NUY+5Ds0WQer85og=="],
|
"emoji-assets": ["emoji-assets@8.0.0", "", {}, "sha512-Y2M8Y5N6AUxKtE7AYj61+V3tU1CAcLQLX4kCO7HJEH1K+o2lgFd3ieiGSbZ8/qfz6qYxr0NUY+5Ds0WQer85og=="],
|
||||||
|
|
||||||
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||||
@@ -1709,6 +1757,8 @@
|
|||||||
|
|
||||||
"end-of-stream": ["end-of-stream@1.1.0", "", { "dependencies": { "once": "~1.3.0" } }, "sha512-EoulkdKF/1xa92q25PbjuDcgJ9RDHYU2Rs3SCIvs2/dSQ3BpmxneNHmA/M7fe60M3PrV7nNGTTNbkK62l6vXiQ=="],
|
"end-of-stream": ["end-of-stream@1.1.0", "", { "dependencies": { "once": "~1.3.0" } }, "sha512-EoulkdKF/1xa92q25PbjuDcgJ9RDHYU2Rs3SCIvs2/dSQ3BpmxneNHmA/M7fe60M3PrV7nNGTTNbkK62l6vXiQ=="],
|
||||||
|
|
||||||
|
"enhanced-resolve": ["enhanced-resolve@5.18.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ=="],
|
||||||
|
|
||||||
"enquirer": ["enquirer@2.4.1", "", { "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" } }, "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ=="],
|
"enquirer": ["enquirer@2.4.1", "", { "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" } }, "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ=="],
|
||||||
|
|
||||||
"entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
|
"entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
|
||||||
@@ -1823,11 +1873,13 @@
|
|||||||
|
|
||||||
"form-data": ["form-data@4.0.1", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } }, "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw=="],
|
"form-data": ["form-data@4.0.1", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } }, "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw=="],
|
||||||
|
|
||||||
|
"form-data-encoder": ["form-data-encoder@1.7.2", "", {}, "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="],
|
||||||
|
|
||||||
"format": ["format@0.2.2", "", {}, "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww=="],
|
"format": ["format@0.2.2", "", {}, "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww=="],
|
||||||
|
|
||||||
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
"formdata-node": ["formdata-node@4.4.1", "", { "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" } }, "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ=="],
|
||||||
|
|
||||||
"fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="],
|
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
||||||
|
|
||||||
"framer-motion": ["framer-motion@10.18.0", "", { "dependencies": { "tslib": "^2.4.0" }, "optionalDependencies": { "@emotion/is-prop-valid": "^0.8.2" }, "peerDependencies": { "react": "^18.0.0", "react-dom": "^18.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-oGlDh1Q1XqYPksuTD/usb0I70hq95OUzmL9+6Zd+Hs4XV0oaISBa/UUMSjYiq6m8EUF32132mOJ8xVZS+I0S6w=="],
|
"framer-motion": ["framer-motion@10.18.0", "", { "dependencies": { "tslib": "^2.4.0" }, "optionalDependencies": { "@emotion/is-prop-valid": "^0.8.2" }, "peerDependencies": { "react": "^18.0.0", "react-dom": "^18.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-oGlDh1Q1XqYPksuTD/usb0I70hq95OUzmL9+6Zd+Hs4XV0oaISBa/UUMSjYiq6m8EUF32132mOJ8xVZS+I0S6w=="],
|
||||||
|
|
||||||
@@ -1851,6 +1903,10 @@
|
|||||||
|
|
||||||
"generic-pool": ["generic-pool@3.4.2", "", {}, "sha512-H7cUpwCQSiJmAHM4c/aFu6fUfrhWXW1ncyh8ftxEPMu6AiYkHw9K8br720TGPZJbk5eOH2bynjZD1yPvdDAmag=="],
|
"generic-pool": ["generic-pool@3.4.2", "", {}, "sha512-H7cUpwCQSiJmAHM4c/aFu6fUfrhWXW1ncyh8ftxEPMu6AiYkHw9K8br720TGPZJbk5eOH2bynjZD1yPvdDAmag=="],
|
||||||
|
|
||||||
|
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
|
||||||
|
|
||||||
|
"get-east-asian-width": ["get-east-asian-width@1.3.0", "", {}, "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ=="],
|
||||||
|
|
||||||
"get-intrinsic": ["get-intrinsic@1.2.4", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" } }, "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ=="],
|
"get-intrinsic": ["get-intrinsic@1.2.4", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" } }, "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ=="],
|
||||||
|
|
||||||
"get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
|
"get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
|
||||||
@@ -1865,7 +1921,7 @@
|
|||||||
|
|
||||||
"glob": ["glob@11.0.1", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^4.0.1", "minimatch": "^10.0.0", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw=="],
|
"glob": ["glob@11.0.1", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^4.0.1", "minimatch": "^10.0.0", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw=="],
|
||||||
|
|
||||||
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||||
|
|
||||||
"glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="],
|
"glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="],
|
||||||
|
|
||||||
@@ -1979,6 +2035,8 @@
|
|||||||
|
|
||||||
"human-signals": ["human-signals@1.1.1", "", {}, "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw=="],
|
"human-signals": ["human-signals@1.1.1", "", {}, "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw=="],
|
||||||
|
|
||||||
|
"humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="],
|
||||||
|
|
||||||
"humanize-url": ["humanize-url@2.1.1", "", { "dependencies": { "normalize-url": "^4.5.1" } }, "sha512-V4nxsPGNE7mPjr1qDp471YfW8nhBiTRWrG/4usZlpvFU8I7gsV7Jvrrzv/snbLm5dWO3dr1ennu2YqnhTWFmYA=="],
|
"humanize-url": ["humanize-url@2.1.1", "", { "dependencies": { "normalize-url": "^4.5.1" } }, "sha512-V4nxsPGNE7mPjr1qDp471YfW8nhBiTRWrG/4usZlpvFU8I7gsV7Jvrrzv/snbLm5dWO3dr1ennu2YqnhTWFmYA=="],
|
||||||
|
|
||||||
"iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
|
"iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
|
||||||
@@ -2059,7 +2117,7 @@
|
|||||||
|
|
||||||
"jackspeak": ["jackspeak@4.0.2", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" } }, "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw=="],
|
"jackspeak": ["jackspeak@4.0.2", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" } }, "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw=="],
|
||||||
|
|
||||||
"jiti": ["jiti@1.21.6", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w=="],
|
"jiti": ["jiti@2.5.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w=="],
|
||||||
|
|
||||||
"js-cookie": ["js-cookie@3.0.5", "", {}, "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw=="],
|
"js-cookie": ["js-cookie@3.0.5", "", {}, "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw=="],
|
||||||
|
|
||||||
@@ -2117,6 +2175,28 @@
|
|||||||
|
|
||||||
"leven": ["leven@4.0.0", "", {}, "sha512-puehA3YKku3osqPlNuzGDUHq8WpwXupUg1V6NXdV38G+gr+gkBwFC8g1b/+YcIvp8gnqVIus+eJCH/eGsRmJNw=="],
|
"leven": ["leven@4.0.0", "", {}, "sha512-puehA3YKku3osqPlNuzGDUHq8WpwXupUg1V6NXdV38G+gr+gkBwFC8g1b/+YcIvp8gnqVIus+eJCH/eGsRmJNw=="],
|
||||||
|
|
||||||
|
"lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="],
|
||||||
|
|
||||||
|
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="],
|
||||||
|
|
||||||
|
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA=="],
|
||||||
|
|
||||||
|
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig=="],
|
||||||
|
|
||||||
|
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.1", "", { "os": "linux", "cpu": "arm" }, "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q=="],
|
||||||
|
|
||||||
|
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw=="],
|
||||||
|
|
||||||
|
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ=="],
|
||||||
|
|
||||||
|
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw=="],
|
||||||
|
|
||||||
|
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ=="],
|
||||||
|
|
||||||
|
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA=="],
|
||||||
|
|
||||||
|
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="],
|
||||||
|
|
||||||
"lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
|
"lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
|
||||||
|
|
||||||
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
|
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
|
||||||
@@ -2163,7 +2243,7 @@
|
|||||||
|
|
||||||
"lru-queue": ["lru-queue@0.1.0", "", { "dependencies": { "es5-ext": "~0.10.2" } }, "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ=="],
|
"lru-queue": ["lru-queue@0.1.0", "", { "dependencies": { "es5-ext": "~0.10.2" } }, "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ=="],
|
||||||
|
|
||||||
"magic-string": ["magic-string@0.30.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw=="],
|
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
|
||||||
|
|
||||||
"make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="],
|
"make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="],
|
||||||
|
|
||||||
@@ -2331,22 +2411,20 @@
|
|||||||
|
|
||||||
"next-tick": ["next-tick@1.1.0", "", {}, "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="],
|
"next-tick": ["next-tick@1.1.0", "", {}, "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="],
|
||||||
|
|
||||||
|
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
|
||||||
|
|
||||||
"node-fetch": ["node-fetch@2.6.7", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ=="],
|
"node-fetch": ["node-fetch@2.6.7", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ=="],
|
||||||
|
|
||||||
"node-forge": ["node-forge@0.10.0", "", {}, "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA=="],
|
"node-forge": ["node-forge@0.10.0", "", {}, "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA=="],
|
||||||
|
|
||||||
"node-gyp-build": ["node-gyp-build@4.8.2", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw=="],
|
"node-gyp-build": ["node-gyp-build@4.8.2", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw=="],
|
||||||
|
|
||||||
"node-releases": ["node-releases@2.0.18", "", {}, "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g=="],
|
|
||||||
|
|
||||||
"nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="],
|
"nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="],
|
||||||
|
|
||||||
"normalize-package-data": ["normalize-package-data@2.5.0", "", { "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA=="],
|
"normalize-package-data": ["normalize-package-data@2.5.0", "", { "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA=="],
|
||||||
|
|
||||||
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
||||||
|
|
||||||
"normalize-range": ["normalize-range@0.1.2", "", {}, "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="],
|
|
||||||
|
|
||||||
"normalize-url": ["normalize-url@4.5.1", "", {}, "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA=="],
|
"normalize-url": ["normalize-url@4.5.1", "", {}, "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA=="],
|
||||||
|
|
||||||
"npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
|
"npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
|
||||||
@@ -2723,7 +2801,9 @@
|
|||||||
|
|
||||||
"tailwind-shades": ["tailwind-shades@1.1.2", "", {}, "sha512-gsyyr9NtfPS1QNWV/YQMcoO5tLStTwp/So2I6jnPWmCFmqY8JEM1csBoq0nbFtuRsjYypC/Bm09pprUyLL/Zjg=="],
|
"tailwind-shades": ["tailwind-shades@1.1.2", "", {}, "sha512-gsyyr9NtfPS1QNWV/YQMcoO5tLStTwp/So2I6jnPWmCFmqY8JEM1csBoq0nbFtuRsjYypC/Bm09pprUyLL/Zjg=="],
|
||||||
|
|
||||||
"tailwindcss": ["tailwindcss@3.4.13", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.0", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", "postcss": "^8.4.23", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw=="],
|
"tailwindcss": ["tailwindcss@4.1.11", "", {}, "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="],
|
||||||
|
|
||||||
|
"tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="],
|
||||||
|
|
||||||
"tar": ["tar@4.4.18", "", { "dependencies": { "chownr": "^1.1.4", "fs-minipass": "^1.2.7", "minipass": "^2.9.0", "minizlib": "^1.3.3", "mkdirp": "^0.5.5", "safe-buffer": "^5.2.1", "yallist": "^3.1.1" } }, "sha512-ZuOtqqmkV9RE1+4odd+MhBpibmCxNP6PJhH/h2OqNuotTX7/XHPZQJv2pKvWMplFH9SIZZhitehh6vBH6LO8Pg=="],
|
"tar": ["tar@4.4.18", "", { "dependencies": { "chownr": "^1.1.4", "fs-minipass": "^1.2.7", "minipass": "^2.9.0", "minizlib": "^1.3.3", "mkdirp": "^0.5.5", "safe-buffer": "^5.2.1", "yallist": "^3.1.1" } }, "sha512-ZuOtqqmkV9RE1+4odd+MhBpibmCxNP6PJhH/h2OqNuotTX7/XHPZQJv2pKvWMplFH9SIZZhitehh6vBH6LO8Pg=="],
|
||||||
|
|
||||||
@@ -2841,8 +2921,6 @@
|
|||||||
|
|
||||||
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
|
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
|
||||||
|
|
||||||
"update-browserslist-db": ["update-browserslist-db@1.1.1", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.0" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A=="],
|
|
||||||
|
|
||||||
"update-notifier": ["update-notifier@4.1.3", "", { "dependencies": { "boxen": "^4.2.0", "chalk": "^3.0.0", "configstore": "^5.0.1", "has-yarn": "^2.1.0", "import-lazy": "^2.1.0", "is-ci": "^2.0.0", "is-installed-globally": "^0.3.1", "is-npm": "^4.0.0", "is-yarn-global": "^0.3.0", "latest-version": "^5.0.0", "pupa": "^2.0.1", "semver-diff": "^3.1.1", "xdg-basedir": "^4.0.0" } }, "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A=="],
|
"update-notifier": ["update-notifier@4.1.3", "", { "dependencies": { "boxen": "^4.2.0", "chalk": "^3.0.0", "configstore": "^5.0.1", "has-yarn": "^2.1.0", "import-lazy": "^2.1.0", "is-ci": "^2.0.0", "is-installed-globally": "^0.3.1", "is-npm": "^4.0.0", "is-yarn-global": "^0.3.0", "latest-version": "^5.0.0", "pupa": "^2.0.1", "semver-diff": "^3.1.1", "xdg-basedir": "^4.0.0" } }, "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A=="],
|
||||||
|
|
||||||
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
||||||
@@ -2897,6 +2975,8 @@
|
|||||||
|
|
||||||
"web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
|
"web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
|
||||||
|
|
||||||
|
"web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="],
|
||||||
|
|
||||||
"web-vitals": ["web-vitals@0.2.4", "", {}, "sha512-6BjspCO9VriYy12z356nL6JBS0GYeEcA457YyRzD+dD6XYCQ75NKhcOHUMHentOE7OcVCIXXDvOm0jKFfQG2Gg=="],
|
"web-vitals": ["web-vitals@0.2.4", "", {}, "sha512-6BjspCO9VriYy12z356nL6JBS0GYeEcA457YyRzD+dD6XYCQ75NKhcOHUMHentOE7OcVCIXXDvOm0jKFfQG2Gg=="],
|
||||||
|
|
||||||
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
|
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
|
||||||
@@ -2913,7 +2993,7 @@
|
|||||||
|
|
||||||
"wrangler": ["wrangler@4.10.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.3.1", "blake3-wasm": "2.1.5", "esbuild": "0.24.2", "miniflare": "4.20250409.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.15", "workerd": "1.20250409.0" }, "optionalDependencies": { "fsevents": "~2.3.2", "sharp": "^0.33.5" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250409.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-fTE4hZ79msEUt8+HEjl/8Q72haCyzPLu4PgrU3L81ysmjrMEdiYfUPqnvCkBUVtJvrDNdctTEimkufT1Y0ipNg=="],
|
"wrangler": ["wrangler@4.10.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.3.1", "blake3-wasm": "2.1.5", "esbuild": "0.24.2", "miniflare": "4.20250409.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.15", "workerd": "1.20250409.0" }, "optionalDependencies": { "fsevents": "~2.3.2", "sharp": "^0.33.5" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250409.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-fTE4hZ79msEUt8+HEjl/8Q72haCyzPLu4PgrU3L81ysmjrMEdiYfUPqnvCkBUVtJvrDNdctTEimkufT1Y0ipNg=="],
|
||||||
|
|
||||||
"wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
|
"wrap-ansi": ["wrap-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q=="],
|
||||||
|
|
||||||
"wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
"wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||||
|
|
||||||
@@ -2929,10 +3009,14 @@
|
|||||||
|
|
||||||
"xdg-portable": ["xdg-portable@7.3.0", "", { "dependencies": { "os-paths": "^4.0.1" } }, "sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw=="],
|
"xdg-portable": ["xdg-portable@7.3.0", "", { "dependencies": { "os-paths": "^4.0.1" } }, "sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw=="],
|
||||||
|
|
||||||
|
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
||||||
|
|
||||||
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||||
|
|
||||||
"yaml": ["yaml@2.7.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA=="],
|
"yaml": ["yaml@2.7.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA=="],
|
||||||
|
|
||||||
|
"yargs": ["yargs@18.0.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^7.2.0", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg=="],
|
||||||
|
|
||||||
"yargs-parser": ["yargs-parser@18.1.3", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="],
|
"yargs-parser": ["yargs-parser@18.1.3", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="],
|
||||||
|
|
||||||
"yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="],
|
"yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="],
|
||||||
@@ -3607,12 +3691,16 @@
|
|||||||
|
|
||||||
"@formatjs/intl-localematcher/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
"@formatjs/intl-localematcher/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss": ["tailwindcss@3.4.13", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.0", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", "postcss": "^8.4.23", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw=="],
|
||||||
|
|
||||||
"@hyperjump/json-schema/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
|
"@hyperjump/json-schema/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
|
||||||
|
|
||||||
"@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
"@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
||||||
|
|
||||||
"@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
"@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
|
||||||
|
|
||||||
"@lezer/css/@lezer/common": ["@lezer/common@1.2.2", "", {}, "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw=="],
|
"@lezer/css/@lezer/common": ["@lezer/common@1.2.2", "", {}, "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw=="],
|
||||||
|
|
||||||
"@lezer/highlight/@lezer/common": ["@lezer/common@1.2.2", "", {}, "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw=="],
|
"@lezer/highlight/@lezer/common": ["@lezer/common@1.2.2", "", {}, "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw=="],
|
||||||
@@ -3637,6 +3725,8 @@
|
|||||||
|
|
||||||
"@manypkg/get-packages/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="],
|
"@manypkg/get-packages/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="],
|
||||||
|
|
||||||
|
"@mapbox/node-pre-gyp/detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="],
|
||||||
|
|
||||||
"@mapbox/node-pre-gyp/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
|
"@mapbox/node-pre-gyp/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
|
||||||
|
|
||||||
"@mapbox/node-pre-gyp/tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="],
|
"@mapbox/node-pre-gyp/tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="],
|
||||||
@@ -3647,6 +3737,8 @@
|
|||||||
|
|
||||||
"@opennextjs/aws/path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="],
|
"@opennextjs/aws/path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="],
|
||||||
|
|
||||||
|
"@playwright/test/playwright": ["playwright@1.54.2", "", { "dependencies": { "playwright-core": "1.54.2" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw=="],
|
||||||
|
|
||||||
"@radix-ui/react-collection/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
|
"@radix-ui/react-collection/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
|
||||||
|
|
||||||
"@radix-ui/react-collection/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.1", "", { "dependencies": { "@radix-ui/react-slot": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg=="],
|
"@radix-ui/react-collection/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.1", "", { "dependencies": { "@radix-ui/react-slot": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg=="],
|
||||||
@@ -3965,6 +4057,20 @@
|
|||||||
|
|
||||||
"@swc/helpers/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
"@swc/helpers/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide/tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.5", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.4", "tslib": "^2.4.0" }, "bundled": true }, "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.5", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.4", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" }, "bundled": true }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
"@tailwindcss/typography/postcss-selector-parser": ["postcss-selector-parser@6.0.10", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w=="],
|
"@tailwindcss/typography/postcss-selector-parser": ["postcss-selector-parser@6.0.10", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w=="],
|
||||||
|
|
||||||
"@ts-morph/common/fast-glob": ["fast-glob@3.3.2", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow=="],
|
"@ts-morph/common/fast-glob": ["fast-glob@3.3.2", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow=="],
|
||||||
@@ -4013,6 +4119,8 @@
|
|||||||
|
|
||||||
"@vue/compiler-core/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
|
"@vue/compiler-core/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
|
||||||
|
|
||||||
|
"@vue/compiler-sfc/magic-string": ["magic-string@0.30.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw=="],
|
||||||
|
|
||||||
"@vue/compiler-sfc/postcss": ["postcss@8.4.47", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.0", "source-map-js": "^1.2.1" } }, "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ=="],
|
"@vue/compiler-sfc/postcss": ["postcss@8.4.47", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.0", "source-map-js": "^1.2.1" } }, "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ=="],
|
||||||
|
|
||||||
"@vueuse/integrations/@vueuse/core": ["@vueuse/core@11.2.0", "", { "dependencies": { "@types/web-bluetooth": "^0.0.20", "@vueuse/metadata": "11.2.0", "@vueuse/shared": "11.2.0", "vue-demi": ">=0.14.10" } }, "sha512-JIUwRcOqOWzcdu1dGlfW04kaJhW3EXnnjJJfLTtddJanymTL7lF1C0+dVVZ/siLfc73mWn+cGP1PE1PKPruRSA=="],
|
"@vueuse/integrations/@vueuse/core": ["@vueuse/core@11.2.0", "", { "dependencies": { "@types/web-bluetooth": "^0.0.20", "@vueuse/metadata": "11.2.0", "@vueuse/shared": "11.2.0", "vue-demi": ">=0.14.10" } }, "sha512-JIUwRcOqOWzcdu1dGlfW04kaJhW3EXnnjJJfLTtddJanymTL7lF1C0+dVVZ/siLfc73mWn+cGP1PE1PKPruRSA=="],
|
||||||
@@ -4049,6 +4157,14 @@
|
|||||||
|
|
||||||
"camelcase-keys/quick-lru": ["quick-lru@4.0.1", "", {}, "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g=="],
|
"camelcase-keys/quick-lru": ["quick-lru@4.0.1", "", {}, "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g=="],
|
||||||
|
|
||||||
|
"cliui/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||||
|
|
||||||
|
"cliui/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||||
|
|
||||||
|
"cloudflare/@types/node": ["@types/node@18.19.121", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-bHOrbyztmyYIi4f1R0s17QsPs1uyyYnGcXeZoGEd227oZjry0q6XQBQxd82X1I57zEfwO8h9Xo+Kl5gX1d9MwQ=="],
|
||||||
|
|
||||||
|
"cloudflare/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
|
||||||
|
|
||||||
"codemirror/@codemirror/autocomplete": ["@codemirror/autocomplete@6.18.1", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA=="],
|
"codemirror/@codemirror/autocomplete": ["@codemirror/autocomplete@6.18.1", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA=="],
|
||||||
|
|
||||||
"codemirror/@codemirror/commands": ["@codemirror/commands@6.7.0", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.4.0", "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } }, "sha512-+cduIZ2KbesDhbykV02K25A5xIVrquSPz4UxxYBemRlAT2aW8dhwUgLDwej7q/RJUHKk4nALYcR1puecDvbdqw=="],
|
"codemirror/@codemirror/commands": ["@codemirror/commands@6.7.0", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.4.0", "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } }, "sha512-+cduIZ2KbesDhbykV02K25A5xIVrquSPz4UxxYBemRlAT2aW8dhwUgLDwej7q/RJUHKk4nALYcR1puecDvbdqw=="],
|
||||||
@@ -4085,8 +4201,6 @@
|
|||||||
|
|
||||||
"express/http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
|
"express/http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
|
||||||
|
|
||||||
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
|
||||||
|
|
||||||
"finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
"finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||||
|
|
||||||
"finalhandler/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="],
|
"finalhandler/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="],
|
||||||
@@ -4155,8 +4269,6 @@
|
|||||||
|
|
||||||
"meow/type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="],
|
"meow/type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="],
|
||||||
|
|
||||||
"micro/arg": ["arg@4.1.0", "", {}, "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg=="],
|
|
||||||
|
|
||||||
"micro/content-type": ["content-type@1.0.4", "", {}, "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="],
|
"micro/content-type": ["content-type@1.0.4", "", {}, "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="],
|
||||||
|
|
||||||
"micromark/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
|
"micromark/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
|
||||||
@@ -4241,6 +4353,8 @@
|
|||||||
|
|
||||||
"send/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
"send/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
||||||
|
|
||||||
|
"sharp/detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="],
|
||||||
|
|
||||||
"sharp/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
|
"sharp/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
|
||||||
|
|
||||||
"simple-swizzle/is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
|
"simple-swizzle/is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
|
||||||
@@ -4255,14 +4369,6 @@
|
|||||||
|
|
||||||
"sucrase/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
"sucrase/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
||||||
|
|
||||||
"tailwindcss/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
|
||||||
|
|
||||||
"tailwindcss/fast-glob": ["fast-glob@3.3.2", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow=="],
|
|
||||||
|
|
||||||
"tailwindcss/postcss": ["postcss@8.4.47", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.0", "source-map-js": "^1.2.1" } }, "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ=="],
|
|
||||||
|
|
||||||
"tailwindcss/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
|
|
||||||
|
|
||||||
"tar/minipass": ["minipass@2.9.0", "", { "dependencies": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } }, "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg=="],
|
"tar/minipass": ["minipass@2.9.0", "", { "dependencies": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } }, "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg=="],
|
||||||
|
|
||||||
"terminal-link/supports-hyperlinks": ["supports-hyperlinks@2.3.0", "", { "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" } }, "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA=="],
|
"terminal-link/supports-hyperlinks": ["supports-hyperlinks@2.3.0", "", { "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" } }, "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA=="],
|
||||||
@@ -4271,8 +4377,6 @@
|
|||||||
|
|
||||||
"ts-node/acorn": ["acorn@8.12.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg=="],
|
"ts-node/acorn": ["acorn@8.12.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg=="],
|
||||||
|
|
||||||
"ts-node/arg": ["arg@4.1.0", "", {}, "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg=="],
|
|
||||||
|
|
||||||
"unenv/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
"unenv/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||||
|
|
||||||
"update-notifier/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="],
|
"update-notifier/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="],
|
||||||
@@ -4287,10 +4391,14 @@
|
|||||||
|
|
||||||
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
|
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
|
||||||
|
|
||||||
"wrap-ansi/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
"wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||||
|
|
||||||
"wrap-ansi/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
"wrap-ansi/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||||
|
|
||||||
|
"yargs/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||||
|
|
||||||
|
"yargs/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="],
|
||||||
|
|
||||||
"youch/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
"youch/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
||||||
|
|
||||||
"@argos-ci/core/sharp/@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="],
|
"@argos-ci/core/sharp/@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="],
|
||||||
@@ -4331,6 +4439,8 @@
|
|||||||
|
|
||||||
"@argos-ci/core/sharp/@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="],
|
"@argos-ci/core/sharp/@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="],
|
||||||
|
|
||||||
|
"@argos-ci/core/sharp/detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="],
|
||||||
|
|
||||||
"@aws-crypto/crc32/@aws-sdk/types/@smithy/types": ["@smithy/types@4.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw=="],
|
"@aws-crypto/crc32/@aws-sdk/types/@smithy/types": ["@smithy/types@4.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw=="],
|
||||||
|
|
||||||
"@aws-crypto/crc32c/@aws-sdk/types/@smithy/types": ["@smithy/types@4.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw=="],
|
"@aws-crypto/crc32c/@aws-sdk/types/@smithy/types": ["@smithy/types@4.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw=="],
|
||||||
@@ -4765,10 +4875,26 @@
|
|||||||
|
|
||||||
"@dotenvx/dotenvx/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="],
|
"@dotenvx/dotenvx/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss/arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss/fast-glob": ["fast-glob@3.3.2", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss/glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss/jiti": ["jiti@1.21.6", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss/postcss": ["postcss@8.4.47", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.0", "source-map-js": "^1.2.1" } }, "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
|
||||||
|
|
||||||
"@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
"@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
||||||
|
|
||||||
"@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
"@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
|
||||||
|
|
||||||
"@mapbox/node-pre-gyp/tar/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
"@mapbox/node-pre-gyp/tar/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
||||||
|
|
||||||
"@mapbox/node-pre-gyp/tar/minizlib": ["minizlib@3.0.1", "", { "dependencies": { "minipass": "^7.0.4", "rimraf": "^5.0.5" } }, "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg=="],
|
"@mapbox/node-pre-gyp/tar/minizlib": ["minizlib@3.0.1", "", { "dependencies": { "minipass": "^7.0.4", "rimraf": "^5.0.5" } }, "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg=="],
|
||||||
@@ -4783,6 +4909,8 @@
|
|||||||
|
|
||||||
"@node-minify/core/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
|
"@node-minify/core/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
|
||||||
|
|
||||||
|
"@playwright/test/playwright/playwright-core": ["playwright-core@1.54.2", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA=="],
|
||||||
|
|
||||||
"@radix-ui/react-dismissable-layer/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g=="],
|
"@radix-ui/react-dismissable-layer/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g=="],
|
||||||
|
|
||||||
"@radix-ui/react-dropdown-menu/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="],
|
"@radix-ui/react-dropdown-menu/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="],
|
||||||
@@ -4871,7 +4999,15 @@
|
|||||||
|
|
||||||
"@smithy/util-endpoints/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
|
"@smithy/util-endpoints/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
|
||||||
|
|
||||||
"@ts-morph/common/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide/tar/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide/tar/minizlib": ["minizlib@3.0.1", "", { "dependencies": { "minipass": "^7.0.4", "rimraf": "^5.0.5" } }, "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide/tar/mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide/tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
||||||
|
|
||||||
"@ts-morph/common/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
"@ts-morph/common/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
||||||
|
|
||||||
@@ -4909,6 +5045,12 @@
|
|||||||
|
|
||||||
"bun-types/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
|
"bun-types/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
|
||||||
|
|
||||||
|
"cliui/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
|
||||||
|
|
||||||
|
"cliui/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||||
|
|
||||||
|
"cloudflare/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
|
||||||
|
|
||||||
"codemirror/@codemirror/autocomplete/@lezer/common": ["@lezer/common@1.2.2", "", {}, "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw=="],
|
"codemirror/@codemirror/autocomplete/@lezer/common": ["@lezer/common@1.2.2", "", {}, "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw=="],
|
||||||
|
|
||||||
"codemirror/@codemirror/commands/@lezer/common": ["@lezer/common@1.2.2", "", {}, "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw=="],
|
"codemirror/@codemirror/commands/@lezer/common": ["@lezer/common@1.2.2", "", {}, "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw=="],
|
||||||
@@ -4929,8 +5071,6 @@
|
|||||||
|
|
||||||
"gaxios/https-proxy-agent/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
|
"gaxios/https-proxy-agent/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
|
||||||
|
|
||||||
"globby/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
|
||||||
|
|
||||||
"google-auth-library/jws/jwa": ["jwa@2.0.0", "", { "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA=="],
|
"google-auth-library/jws/jwa": ["jwa@2.0.0", "", { "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA=="],
|
||||||
|
|
||||||
"gtoken/jws/jwa": ["jwa@2.0.0", "", { "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA=="],
|
"gtoken/jws/jwa": ["jwa@2.0.0", "", { "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA=="],
|
||||||
@@ -4969,16 +5109,6 @@
|
|||||||
|
|
||||||
"sucrase/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
|
"sucrase/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
|
||||||
|
|
||||||
"tailwindcss/chokidar/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
|
||||||
|
|
||||||
"tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
|
||||||
|
|
||||||
"tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
|
||||||
|
|
||||||
"tailwindcss/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
|
||||||
|
|
||||||
"tailwindcss/postcss/nanoid": ["nanoid@3.3.7", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g=="],
|
|
||||||
|
|
||||||
"wrangler/sharp/@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="],
|
"wrangler/sharp/@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="],
|
||||||
|
|
||||||
"wrangler/sharp/@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="],
|
"wrangler/sharp/@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="],
|
||||||
@@ -5017,10 +5147,16 @@
|
|||||||
|
|
||||||
"wrangler/sharp/@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="],
|
"wrangler/sharp/@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="],
|
||||||
|
|
||||||
"wrap-ansi/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
"wrangler/sharp/detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="],
|
||||||
|
|
||||||
|
"wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
|
||||||
|
|
||||||
"wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
"wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||||
|
|
||||||
|
"yargs/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
|
||||||
|
|
||||||
|
"yargs/string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||||
|
|
||||||
"@argos-ci/core/sharp/@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.3.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw=="],
|
"@argos-ci/core/sharp/@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.3.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw=="],
|
||||||
|
|
||||||
"@aws-sdk/client-dynamodb/@aws-crypto/sha256-js/@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
"@aws-sdk/client-dynamodb/@aws-crypto/sha256-js/@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
||||||
@@ -5157,6 +5293,16 @@
|
|||||||
|
|
||||||
"@babel/highlight/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
|
"@babel/highlight/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss/chokidar/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||||
|
|
||||||
|
"@headlessui/tailwindcss/tailwindcss/postcss/nanoid": ["nanoid@3.3.7", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g=="],
|
||||||
|
|
||||||
"@node-minify/core/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
"@node-minify/core/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||||
|
|
||||||
"@node-minify/core/glob/path-scurry/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
"@node-minify/core/glob/path-scurry/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
||||||
@@ -5181,6 +5327,8 @@
|
|||||||
|
|
||||||
"wrangler/sharp/@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.3.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw=="],
|
"wrangler/sharp/@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.3.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw=="],
|
||||||
|
|
||||||
|
"yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||||
|
|
||||||
"@argos-ci/core/sharp/@img/sharp-wasm32/@emnapi/runtime/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
"@argos-ci/core/sharp/@img/sharp-wasm32/@emnapi/runtime/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
"@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw=="],
|
"@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw=="],
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@
|
|||||||
"workspaces": {
|
"workspaces": {
|
||||||
"packages": ["packages/*"],
|
"packages": ["packages/*"],
|
||||||
"catalog": {
|
"catalog": {
|
||||||
"@gitbook/api": "^0.128.0"
|
"@gitbook/api": "^0.136.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"patchedDependencies": {
|
"patchedDependencies": {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
dist/
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# `@gitbook/browser-types`
|
||||||
|
|
||||||
|
Typescript types for the global variables available in a GitBook website. These types can be used by integrations embedding scripts.
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "@gitbook/browser-types",
|
||||||
|
"description": "Typescript types for the global variables available in a GitBook website. These types can be used by integrations embedding scripts.",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"default": "./dist/index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": "0.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@gitbook/api": "catalog:",
|
||||||
|
"@gitbook/icons": "workspace:"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.5.3"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"typecheck": "tsc --noEmit"
|
||||||
|
},
|
||||||
|
"files": ["dist", "README.md", "CHANGELOG.md"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import type { AIToolCallResult, AIToolDefinition } from '@gitbook/api';
|
||||||
|
import type { IconName } from '@gitbook/icons';
|
||||||
|
|
||||||
|
export type GitBookIntegrationEvent = 'load' | 'unload';
|
||||||
|
|
||||||
|
export type GitBookIntegrationEventCallback = (...args: any[]) => void;
|
||||||
|
|
||||||
|
export type GitBookIntegrationTool = AIToolDefinition & {
|
||||||
|
/**
|
||||||
|
* Confirmation action to be displayed to the user before executing the tool.
|
||||||
|
*/
|
||||||
|
confirmation?: {
|
||||||
|
icon?: IconName;
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback when the tool is executed.
|
||||||
|
* The input is provided by the AI assistant following the input schema of the tool.
|
||||||
|
*/
|
||||||
|
execute: (input: object) => Promise<Pick<AIToolCallResult, 'output' | 'summary'>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GitBookAssistant = {
|
||||||
|
/**
|
||||||
|
* Name of the assistant displayed in the UI.
|
||||||
|
*/
|
||||||
|
label: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icon of the assistant displayed in the UI.
|
||||||
|
* Any FontAwesome icon name is supported.
|
||||||
|
* @example 'sparkle'
|
||||||
|
*/
|
||||||
|
icon: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback when the assistant is opened.
|
||||||
|
*/
|
||||||
|
open: (query?: string) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to display the triggers for this assistant in the UI.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
ui?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GitBookGlobal = {
|
||||||
|
/**
|
||||||
|
* Register an event listener.
|
||||||
|
*/
|
||||||
|
addEventListener: (
|
||||||
|
type: GitBookIntegrationEvent,
|
||||||
|
func: GitBookIntegrationEventCallback
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an event listener.
|
||||||
|
*/
|
||||||
|
removeEventListener: (
|
||||||
|
type: GitBookIntegrationEvent,
|
||||||
|
func: GitBookIntegrationEventCallback
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a custom tool to be exposed to the AI assistant.
|
||||||
|
*/
|
||||||
|
registerTool: (tool: GitBookIntegrationTool) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a custom assistant to be available on the site.
|
||||||
|
*/
|
||||||
|
registerAssistant: (assistant: GitBookAssistant) => () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
/**
|
||||||
|
* Global `window.GitBook` object accessible by integrations.
|
||||||
|
*/
|
||||||
|
GitBook?: GitBookGlobal;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "esnext",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": false,
|
||||||
|
"declaration": true,
|
||||||
|
"outDir": "dist",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"incremental": true,
|
||||||
|
"types": [
|
||||||
|
"bun-types" // add Bun global
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
@@ -90,7 +90,7 @@ export function getCacheTag(
|
|||||||
| {
|
| {
|
||||||
tag: 'translation';
|
tag: 'translation';
|
||||||
organization: string;
|
organization: string;
|
||||||
translationSettings: string;
|
translation: string;
|
||||||
}
|
}
|
||||||
): string {
|
): string {
|
||||||
switch (spec.tag) {
|
switch (spec.tag) {
|
||||||
@@ -115,7 +115,7 @@ export function getCacheTag(
|
|||||||
case 'openapi':
|
case 'openapi':
|
||||||
return `organization:${spec.organization}:openapi:${spec.openAPISpec}`;
|
return `organization:${spec.organization}:openapi:${spec.openAPISpec}`;
|
||||||
case 'translation':
|
case 'translation':
|
||||||
return `organization:${spec.organization}:translation:${spec.translationSettings}`;
|
return `organization:${spec.organization}:translation:${spec.translation}`;
|
||||||
default:
|
default:
|
||||||
assertNever(spec);
|
assertNever(spec);
|
||||||
}
|
}
|
||||||
@@ -144,6 +144,10 @@ export function getComputedContentSourceCacheTags(
|
|||||||
) {
|
) {
|
||||||
const tags: string[] = [];
|
const tags: string[] = [];
|
||||||
|
|
||||||
|
if (!('dependencies' in source)) {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
// We add the dependencies as tags, to ensure that the computed content is invalidated
|
// We add the dependencies as tags, to ensure that the computed content is invalidated
|
||||||
// when the dependencies are updated.
|
// when the dependencies are updated.
|
||||||
const dependencies = Object.values(source.dependencies ?? {});
|
const dependencies = Object.values(source.dependencies ?? {});
|
||||||
@@ -167,12 +171,12 @@ export function getComputedContentSourceCacheTags(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'translation-language':
|
case 'translation':
|
||||||
tags.push(
|
tags.push(
|
||||||
getCacheTag({
|
getCacheTag({
|
||||||
tag: 'translation',
|
tag: 'translation',
|
||||||
organization: inContext.organizationId,
|
organization: inContext.organizationId,
|
||||||
translationSettings: dependency.ref.translationSettings,
|
translation: dependency.ref.translation,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,5 +1,48 @@
|
|||||||
# gitbook
|
# gitbook
|
||||||
|
|
||||||
|
## 0.15.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- d130532: Suggest questions in the current space context
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 44f4151: Fix close buttons tooltips
|
||||||
|
- d903273: Strip visitor params from URL
|
||||||
|
- df7de8f: Fix an issue where links were not rendering properly in Ask AI answers
|
||||||
|
- d270b4a: All tracking is now disabled for dynamic routes such as the site preview.
|
||||||
|
- b1f608b: Implement basic URL scheme for assistant with ask
|
||||||
|
- d024658: Prevent page breaks inside blocks when printing
|
||||||
|
- 185cdb4: Fix scrolling to anchor positionning
|
||||||
|
- 5c49235: Remove highlighting in Safari for PowerShell and C++ to avoid page crash until next version with bug fix is released
|
||||||
|
- f1a6dec: Update OpenAPI parser
|
||||||
|
- 2cdba53: Upgrade to Tailwind v4
|
||||||
|
- Updated dependencies [2cdba53]
|
||||||
|
- Updated dependencies [f1a6dec]
|
||||||
|
- @gitbook/react-math@0.6.1
|
||||||
|
- @gitbook/icons@0.2.2
|
||||||
|
- @gitbook/openapi-parser@3.0.0
|
||||||
|
- @gitbook/react-contentkit@0.7.3
|
||||||
|
- @gitbook/react-openapi@1.3.5
|
||||||
|
|
||||||
|
## 0.14.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 7c951ef: 'Support new colors in text formatting
|
||||||
|
- 39c4f76: Add fullwidth page option
|
||||||
|
- eb1bd3a: AI response feedback buttons
|
||||||
|
- 2ba7e54: Fix headings styles in hint block
|
||||||
|
- 250c194: Add nosnippet to announcement banner.
|
||||||
|
- 4aeb81b: Fix search input styling & text cutoff
|
||||||
|
- 68f0dbc: Add confirmation modal to contentkit button
|
||||||
|
- 611e286: Remove padding on first Heading in Columns
|
||||||
|
- b0c534f: Tweaks to AI Chat and AI Actions Dropdown
|
||||||
|
- Updated dependencies [b5ad0ce]
|
||||||
|
- @gitbook/openapi-parser@2.2.2
|
||||||
|
- @gitbook/react-openapi@1.3.4
|
||||||
|
|
||||||
## 0.14.0
|
## 0.14.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
CustomizationAIMode,
|
||||||
CustomizationBackground,
|
CustomizationBackground,
|
||||||
CustomizationCorners,
|
CustomizationCorners,
|
||||||
CustomizationDefaultMonospaceFont,
|
CustomizationDefaultMonospaceFont,
|
||||||
@@ -19,6 +20,7 @@ import {
|
|||||||
|
|
||||||
import { getSiteAPIToken } from '../tests/utils';
|
import { getSiteAPIToken } from '../tests/utils';
|
||||||
import {
|
import {
|
||||||
|
type Test,
|
||||||
type TestsCase,
|
type TestsCase,
|
||||||
allDeprecatedThemePresets,
|
allDeprecatedThemePresets,
|
||||||
allLocales,
|
allLocales,
|
||||||
@@ -34,6 +36,179 @@ import {
|
|||||||
waitForNotFound,
|
waitForNotFound,
|
||||||
} from './util';
|
} from './util';
|
||||||
|
|
||||||
|
const searchTestCases: Test[] = [
|
||||||
|
{
|
||||||
|
name: 'Search - AI Mode: None - Complete flow',
|
||||||
|
url: getCustomizationURL({
|
||||||
|
ai: {
|
||||||
|
mode: CustomizationAIMode.None,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
screenshot: false,
|
||||||
|
run: async (page) => {
|
||||||
|
const searchInput = page.getByTestId('search-input');
|
||||||
|
await searchInput.focus();
|
||||||
|
await expect(page.getByTestId('search-results')).toHaveCount(0); // No pop-up yet because there's no recommended questions.
|
||||||
|
|
||||||
|
// Fill search input, expecting search results
|
||||||
|
await searchInput.fill('gitbook');
|
||||||
|
await expect(page.getByTestId('search-results')).toBeVisible();
|
||||||
|
const pageResults = await page.getByTestId('search-page-result').all();
|
||||||
|
await expect(pageResults.length).toBeGreaterThan(2);
|
||||||
|
const pageSectionResults = await page.getByTestId('search-page-section-result').all();
|
||||||
|
await expect(pageSectionResults.length).toBeGreaterThan(2);
|
||||||
|
await expect(page.getByTestId('search-ask-question')).toHaveCount(0); // No AI search results with aiMode=None.
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Search - AI Mode: None - Keyboard shortcut',
|
||||||
|
url: getCustomizationURL({
|
||||||
|
ai: {
|
||||||
|
mode: CustomizationAIMode.None,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
screenshot: false,
|
||||||
|
run: async (page) => {
|
||||||
|
await page.keyboard.press('ControlOrMeta+K');
|
||||||
|
await expect(page.getByTestId('search-input')).toBeFocused();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Search - AI Mode: None - URL query (Initial)',
|
||||||
|
url: `${getCustomizationURL({
|
||||||
|
ai: {
|
||||||
|
mode: CustomizationAIMode.None,
|
||||||
|
},
|
||||||
|
})}&q=`,
|
||||||
|
run: async (page) => {
|
||||||
|
await expect(page.getByTestId('search-results')).toHaveCount(0); // No pop-up yet because there's no recommended questions.
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Search - AI Mode: None - URL query (Results)',
|
||||||
|
url: `${getCustomizationURL({
|
||||||
|
ai: {
|
||||||
|
mode: CustomizationAIMode.None,
|
||||||
|
},
|
||||||
|
})}&q=gitbook`,
|
||||||
|
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:
|
||||||
|
// - Search - AI Mode: Search - Complete flow
|
||||||
|
// - Search - AI Mode: Search - URL query (Initial)
|
||||||
|
{
|
||||||
|
name: 'Search - AI Mode: Search - URL query (Results)',
|
||||||
|
url: `${getCustomizationURL({
|
||||||
|
ai: {
|
||||||
|
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({
|
||||||
|
ai: {
|
||||||
|
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();
|
||||||
|
// 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('What is gitbook?');
|
||||||
|
const aiSearchResult = page.getByTestId('search-ask-question');
|
||||||
|
await expect(aiSearchResult).toBeVisible();
|
||||||
|
await aiSearchResult.click();
|
||||||
|
await expect(page.getByTestId('ai-chat')).toBeVisible();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Ask - AI Mode: Assistant - Keyboard shortcut',
|
||||||
|
url: getCustomizationURL({
|
||||||
|
ai: {
|
||||||
|
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();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Ask - AI Mode: Assistant - Button',
|
||||||
|
url: getCustomizationURL({
|
||||||
|
ai: {
|
||||||
|
mode: CustomizationAIMode.Assistant,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
screenshot: false,
|
||||||
|
run: async (page) => {
|
||||||
|
await page.getByTestId('ai-chat-button').click();
|
||||||
|
await expect(page.getByTestId('ai-chat')).toBeVisible();
|
||||||
|
await expect(page.getByTestId('ai-chat-input')).toBeFocused();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Ask - AI Mode: Assistant - URL query (Initial)',
|
||||||
|
url: `${getCustomizationURL({
|
||||||
|
ai: {
|
||||||
|
mode: CustomizationAIMode.Assistant,
|
||||||
|
},
|
||||||
|
})}&ask=`,
|
||||||
|
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-input')).toBeFocused();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Ask - AI Mode: Assistant - URL query (Results)',
|
||||||
|
url: `${getCustomizationURL({
|
||||||
|
ai: {
|
||||||
|
mode: CustomizationAIMode.Assistant,
|
||||||
|
},
|
||||||
|
})}&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({
|
||||||
|
timeout: 15_000,
|
||||||
|
});
|
||||||
|
await expect(page.getByTestId('ai-chat-message').first()).toHaveText(
|
||||||
|
'What is GitBook?'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const testCases: TestsCase[] = [
|
const testCases: TestsCase[] = [
|
||||||
{
|
{
|
||||||
name: 'GitBook Site (Single Variant)',
|
name: 'GitBook Site (Single Variant)',
|
||||||
@@ -53,34 +228,7 @@ const testCases: TestsCase[] = [
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
...searchTestCases,
|
||||||
name: 'Search',
|
|
||||||
url: '?q=',
|
|
||||||
screenshot: false,
|
|
||||||
run: async (page) => {
|
|
||||||
await expect(page.getByTestId('search-results')).toBeVisible();
|
|
||||||
const allItems = await page.getByTestId('search-result-item').all();
|
|
||||||
// Expect at least 3 questions
|
|
||||||
await expect(allItems.length).toBeGreaterThan(2);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Search Results',
|
|
||||||
url: '?q=gitbook',
|
|
||||||
run: async (page) => {
|
|
||||||
await expect(page.getByTestId('search-results')).toBeVisible();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'AI Search',
|
|
||||||
url: '?q=What+is+GitBook%3F&ask=true',
|
|
||||||
run: async (page) => {
|
|
||||||
await expect(page.getByTestId('search-ask-answer')).toBeVisible({
|
|
||||||
timeout: 15_000,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
screenshot: false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'Not found',
|
name: 'Not found',
|
||||||
url: 'content-not-found',
|
url: 'content-not-found',
|
||||||
@@ -279,34 +427,7 @@ const testCases: TestsCase[] = [
|
|||||||
url: '',
|
url: '',
|
||||||
run: waitForCookiesDialog,
|
run: waitForCookiesDialog,
|
||||||
},
|
},
|
||||||
{
|
...searchTestCases,
|
||||||
name: 'Search',
|
|
||||||
url: '?q=',
|
|
||||||
screenshot: false,
|
|
||||||
run: async (page) => {
|
|
||||||
await expect(page.getByTestId('search-results')).toBeVisible();
|
|
||||||
const allItems = await page.getByTestId('search-result-item').all();
|
|
||||||
// Expect at least 3 questions
|
|
||||||
await expect(allItems.length).toBeGreaterThan(2);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Search Results',
|
|
||||||
url: '?q=gitbook',
|
|
||||||
run: async (page) => {
|
|
||||||
await expect(page.getByTestId('search-results')).toBeVisible();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'AI Search',
|
|
||||||
url: '?q=What+is+GitBook%3F&ask=true',
|
|
||||||
run: async (page) => {
|
|
||||||
await expect(page.getByTestId('search-ask-answer')).toBeVisible({
|
|
||||||
timeout: 15_000,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
screenshot: false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'Not found',
|
name: 'Not found',
|
||||||
url: 'content-not-found',
|
url: 'content-not-found',
|
||||||
@@ -932,6 +1053,22 @@ const testCases: TestsCase[] = [
|
|||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Page actions',
|
||||||
|
contentBaseURL: 'https://gitbook.gitbook.io/test-gitbook-open/',
|
||||||
|
tests: [
|
||||||
|
{
|
||||||
|
name: 'Without page actions',
|
||||||
|
url: getCustomizationURL({
|
||||||
|
pageActions: {
|
||||||
|
markdown: false,
|
||||||
|
externalAI: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
run: waitForCookiesDialog,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Ads',
|
name: 'Ads',
|
||||||
contentBaseURL: 'https://gitbook.gitbook.io/test-gitbook-open/',
|
contentBaseURL: 'https://gitbook.gitbook.io/test-gitbook-open/',
|
||||||
|
|||||||
@@ -318,10 +318,6 @@ export function getCustomizationURL(partial: DeepPartial<SiteCustomizationSettin
|
|||||||
feedback: {
|
feedback: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
// TODO: remove aiSearch once the cache has been fully updated (after 11/07/2025)
|
|
||||||
aiSearch: {
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
ai: {
|
ai: {
|
||||||
mode: CustomizationAIMode.None,
|
mode: CustomizationAIMode.None,
|
||||||
},
|
},
|
||||||
@@ -337,6 +333,10 @@ export function getCustomizationURL(partial: DeepPartial<SiteCustomizationSettin
|
|||||||
pagination: {
|
pagination: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
|
pageActions: {
|
||||||
|
externalAI: true,
|
||||||
|
markdown: true,
|
||||||
|
},
|
||||||
trademark: {
|
trademark: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ const nextConfig = {
|
|||||||
dynamic: 3600, // 1 hour
|
dynamic: 3600, // 1 hour
|
||||||
static: 3600, // 1 hour
|
static: 3600, // 1 hour
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Since content is fully static, we don't want to fetch on hover again
|
||||||
|
optimisticClientCache: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
env: {
|
env: {
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ import { runWithCloudflareRequestContext } from '../../.open-next/cloudflare/ini
|
|||||||
|
|
||||||
import { DurableObject } from 'cloudflare:workers';
|
import { DurableObject } from 'cloudflare:workers';
|
||||||
|
|
||||||
|
//Only needed to run locally, in prod we'll use the one from do.js
|
||||||
|
export { DOShardedTagCache } from '../../.open-next/.build/durable-objects/sharded-tag-cache.js';
|
||||||
|
|
||||||
// Only needed to run locally, in prod we'll use the one from do.js
|
// Only needed to run locally, in prod we'll use the one from do.js
|
||||||
export class R2WriteBuffer extends DurableObject {
|
export class R2WriteBuffer extends DurableObject {
|
||||||
writePromise;
|
writePromise;
|
||||||
|
|||||||
@@ -36,13 +36,17 @@
|
|||||||
{
|
{
|
||||||
"name": "WRITE_BUFFER",
|
"name": "WRITE_BUFFER",
|
||||||
"class_name": "R2WriteBuffer"
|
"class_name": "R2WriteBuffer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "NEXT_TAG_CACHE_DO_SHARDED",
|
||||||
|
"class_name": "DOShardedTagCache"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"migrations": [
|
"migrations": [
|
||||||
{
|
{
|
||||||
"tag": "v1",
|
"tag": "v1",
|
||||||
"new_sqlite_classes": ["R2WriteBuffer"]
|
"new_sqlite_classes": ["R2WriteBuffer", "DOShardedTagCache"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export default class extends WorkerEntrypoint {
|
|||||||
`gitbook-open-v2-${this.env.STAGE}="${this.env.WORKER_VERSION_ID}"`
|
`gitbook-open-v2-${this.env.STAGE}="${this.env.WORKER_VERSION_ID}"`
|
||||||
);
|
);
|
||||||
return this.env.DEFAULT_WORKER?.fetch(reqOrResp, {
|
return this.env.DEFAULT_WORKER?.fetch(reqOrResp, {
|
||||||
|
redirect: 'manual',
|
||||||
cf: {
|
cf: {
|
||||||
cacheEverything: false,
|
cacheEverything: false,
|
||||||
},
|
},
|
||||||
@@ -33,6 +34,9 @@ export default class extends WorkerEntrypoint {
|
|||||||
modifiedUrl.hostname = this.env.PREVIEW_HOSTNAME;
|
modifiedUrl.hostname = this.env.PREVIEW_HOSTNAME;
|
||||||
const nextRequest = new Request(modifiedUrl, reqOrResp);
|
const nextRequest = new Request(modifiedUrl, reqOrResp);
|
||||||
return fetch(nextRequest, {
|
return fetch(nextRequest, {
|
||||||
|
// We never want to follow the redirects here.
|
||||||
|
// Redirects are supposed to happen from the client.
|
||||||
|
redirect: 'manual',
|
||||||
cf: {
|
cf: {
|
||||||
cacheEverything: false,
|
cacheEverything: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -22,7 +22,11 @@
|
|||||||
"vars": {
|
"vars": {
|
||||||
"STAGE": "dev",
|
"STAGE": "dev",
|
||||||
"NEXT_PRIVATE_DEBUG_CACHE": "true",
|
"NEXT_PRIVATE_DEBUG_CACHE": "true",
|
||||||
"OPEN_NEXT_REQUEST_ID_HEADER": "true"
|
// When deployed locally, we don't have access to the tag cache here,
|
||||||
|
// we should just bypass the cache to go to the server directly
|
||||||
|
"SHOULD_BYPASS_CACHE": "true",
|
||||||
|
"OPEN_NEXT_REQUEST_ID_HEADER": "true",
|
||||||
|
"GITBOOK_URL": "http://localhost:8771"
|
||||||
},
|
},
|
||||||
"r2_buckets": [
|
"r2_buckets": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ class GitbookIncrementalCache implements IncrementalCache {
|
|||||||
const r2 = getCloudflareContext().env[BINDING_NAME];
|
const r2 = getCloudflareContext().env[BINDING_NAME];
|
||||||
const localCache = await this.getCacheInstance();
|
const localCache = await this.getCacheInstance();
|
||||||
if (!r2) throw new Error('No R2 bucket');
|
if (!r2) throw new Error('No R2 bucket');
|
||||||
|
if (process.env.SHOULD_BYPASS_CACHE === 'true') {
|
||||||
|
// We are in a local middleware environment, we should bypass the cache
|
||||||
|
// and go directly to the server.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
// Check local cache first if available
|
// Check local cache first if available
|
||||||
const localCacheEntry = await localCache.match(this.getCacheUrlKey(cacheKey));
|
const localCacheEntry = await localCache.match(this.getCacheUrlKey(cacheKey));
|
||||||
@@ -43,7 +48,13 @@ class GitbookIncrementalCache implements IncrementalCache {
|
|||||||
const result = (await localCacheEntry.json()) as WithLastModified<
|
const result = (await localCacheEntry.json()) as WithLastModified<
|
||||||
CacheValue<CacheType>
|
CacheValue<CacheType>
|
||||||
>;
|
>;
|
||||||
return this.returnNullOn404(result);
|
return this.returnNullOn404({
|
||||||
|
...result,
|
||||||
|
// Because we use tag cache and also invalidate them every time,
|
||||||
|
// if we get a cache hit, we don't need to check the tag cache as we already know it's not been revalidated
|
||||||
|
// this should improve performance even further, and reduce costs
|
||||||
|
shouldBypassTagCache: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const r2Object = await r2.get(cacheKey);
|
const r2Object = await r2.get(cacheKey);
|
||||||
@@ -134,19 +145,27 @@ class GitbookIncrementalCache implements IncrementalCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async writeToR2(key: string, value: string): Promise<void> {
|
async writeToR2(key: string, value: string): Promise<void> {
|
||||||
const env = getCloudflareContext().env as {
|
try {
|
||||||
WRITE_BUFFER: DurableObjectNamespace<
|
const env = getCloudflareContext().env as {
|
||||||
Rpc.DurableObjectBranded & {
|
WRITE_BUFFER: DurableObjectNamespace<
|
||||||
write: (key: string, value: string) => Promise<void>;
|
Rpc.DurableObjectBranded & {
|
||||||
}
|
write: (key: string, value: string) => Promise<void>;
|
||||||
>;
|
}
|
||||||
};
|
>;
|
||||||
const id = env.WRITE_BUFFER.idFromName(key);
|
};
|
||||||
|
const id = env.WRITE_BUFFER.idFromName(key);
|
||||||
|
|
||||||
// A stub is a client used to invoke methods on the Durable Object
|
// A stub is a client used to invoke methods on the Durable Object
|
||||||
const stub = env.WRITE_BUFFER.get(id);
|
const stub = env.WRITE_BUFFER.get(id);
|
||||||
|
|
||||||
await stub.write(key, value);
|
await stub.write(key, value);
|
||||||
|
} catch {
|
||||||
|
// We fallback to writing directly to R2
|
||||||
|
// it can fail locally because the limit is 1Mb per args
|
||||||
|
// It is 32Mb in production, so we should be fine
|
||||||
|
const r2 = getCloudflareContext().env[BINDING_NAME];
|
||||||
|
r2?.put(key, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCacheInstance(): Promise<Cache> {
|
async getCacheInstance(): Promise<Cache> {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { getLogger } from '@/lib/logger';
|
import { createLogger, getLogger } from '@/lib/logger';
|
||||||
import type { NextModeTagCache } from '@opennextjs/aws/types/overrides.js';
|
import type { NextModeTagCache } from '@opennextjs/aws/types/overrides.js';
|
||||||
import doShardedTagCache from '@opennextjs/cloudflare/overrides/tag-cache/do-sharded-tag-cache';
|
import doShardedTagCache from '@opennextjs/cloudflare/overrides/tag-cache/do-sharded-tag-cache';
|
||||||
import { softTagFilter } from '@opennextjs/cloudflare/overrides/tag-cache/tag-cache-filter';
|
import { softTagFilter } from '@opennextjs/cloudflare/overrides/tag-cache/tag-cache-filter';
|
||||||
@@ -6,8 +6,9 @@ import { softTagFilter } from '@opennextjs/cloudflare/overrides/tag-cache/tag-ca
|
|||||||
const originalTagCache = doShardedTagCache({
|
const originalTagCache = doShardedTagCache({
|
||||||
baseShardSize: 12,
|
baseShardSize: 12,
|
||||||
regionalCache: true,
|
regionalCache: true,
|
||||||
// We can probably increase this value even further
|
regionalCacheTtlSec: 60 * 5 /* 5 minutes */,
|
||||||
regionalCacheTtlSec: 60,
|
// Because we invalidate the Cache API on update, we can safely set this to true
|
||||||
|
regionalCacheDangerouslyPersistMissingTags: true,
|
||||||
shardReplication: {
|
shardReplication: {
|
||||||
numberOfSoftReplicas: 2,
|
numberOfSoftReplicas: 2,
|
||||||
numberOfHardReplicas: 1,
|
numberOfHardReplicas: 1,
|
||||||
@@ -20,6 +21,7 @@ const originalTagCache = doShardedTagCache({
|
|||||||
export default {
|
export default {
|
||||||
name: 'GitbookTagCache',
|
name: 'GitbookTagCache',
|
||||||
mode: 'nextMode',
|
mode: 'nextMode',
|
||||||
|
// We don't really use this one, as of now it is only used for soft tags
|
||||||
getLastRevalidated: async (tags: string[]) => {
|
getLastRevalidated: async (tags: string[]) => {
|
||||||
const tagsToCheck = tags.filter(softTagFilter);
|
const tagsToCheck = tags.filter(softTagFilter);
|
||||||
if (tagsToCheck.length === 0) {
|
if (tagsToCheck.length === 0) {
|
||||||
@@ -29,12 +31,20 @@ export default {
|
|||||||
return await originalTagCache.getLastRevalidated(tagsToCheck);
|
return await originalTagCache.getLastRevalidated(tagsToCheck);
|
||||||
},
|
},
|
||||||
hasBeenRevalidated: async (tags: string[], lastModified?: number) => {
|
hasBeenRevalidated: async (tags: string[], lastModified?: number) => {
|
||||||
const tagsToCheck = tags.filter(softTagFilter);
|
try {
|
||||||
if (tagsToCheck.length === 0) {
|
const tagsToCheck = tags.filter(softTagFilter);
|
||||||
return false; // If no tags to check, return false
|
if (tagsToCheck.length === 0) {
|
||||||
}
|
return false; // If no tags to check, return false
|
||||||
|
}
|
||||||
|
|
||||||
return await originalTagCache.hasBeenRevalidated(tagsToCheck, lastModified);
|
return await originalTagCache.hasBeenRevalidated(tagsToCheck, lastModified);
|
||||||
|
} catch (e) {
|
||||||
|
createLogger('gitbookTagCache', {}).error(
|
||||||
|
`hasBeenRevalidated - Error checking tags ${tags.join(', ')}`,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
return false; // In case of error, return false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
writeTags: async (tags: string[]) => {
|
writeTags: async (tags: string[]) => {
|
||||||
const tagsToWrite = tags.filter(softTagFilter);
|
const tagsToWrite = tags.filter(softTagFilter);
|
||||||
@@ -43,7 +53,7 @@ export default {
|
|||||||
logger.warn('writeTags - No valid tags to write');
|
logger.warn('writeTags - No valid tags to write');
|
||||||
return; // If no tags to write, exit early
|
return; // If no tags to write, exit early
|
||||||
}
|
}
|
||||||
// Write only the filtered tags
|
|
||||||
await originalTagCache.writeTags(tagsToWrite);
|
await originalTagCache.writeTags(tagsToWrite);
|
||||||
},
|
},
|
||||||
} satisfies NextModeTagCache;
|
} satisfies NextModeTagCache;
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "gitbook",
|
"name": "gitbook",
|
||||||
"version": "0.14.0",
|
"version": "0.15.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitbook/api": "catalog:",
|
"@gitbook/api": "catalog:",
|
||||||
"@gitbook/cache-tags": "workspace:*",
|
"@gitbook/cache-tags": "workspace:*",
|
||||||
"@gitbook/colors": "workspace:*",
|
"@gitbook/colors": "workspace:*",
|
||||||
|
"@gitbook/browser-types": "workspace:*",
|
||||||
"@gitbook/emoji-codepoints": "workspace:*",
|
"@gitbook/emoji-codepoints": "workspace:*",
|
||||||
"@gitbook/fonts": "workspace:*",
|
"@gitbook/fonts": "workspace:*",
|
||||||
"@gitbook/icons": "workspace:*",
|
"@gitbook/icons": "workspace:*",
|
||||||
@@ -13,7 +14,7 @@
|
|||||||
"@gitbook/react-contentkit": "workspace:*",
|
"@gitbook/react-contentkit": "workspace:*",
|
||||||
"@gitbook/react-math": "workspace:*",
|
"@gitbook/react-math": "workspace:*",
|
||||||
"@gitbook/react-openapi": "workspace:*",
|
"@gitbook/react-openapi": "workspace:*",
|
||||||
"@opennextjs/cloudflare": "^1.4.0",
|
"@opennextjs/cloudflare": "^1.6.4",
|
||||||
"@radix-ui/react-checkbox": "^1.0.4",
|
"@radix-ui/react-checkbox": "^1.0.4",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.12",
|
"@radix-ui/react-dropdown-menu": "^2.1.12",
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.3",
|
"@radix-ui/react-navigation-menu": "^1.2.3",
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
"@sindresorhus/fnv1a": "^3.1.0",
|
"@sindresorhus/fnv1a": "^3.1.0",
|
||||||
"@tailwindcss/container-queries": "^0.1.1",
|
"@tailwindcss/container-queries": "^0.1.1",
|
||||||
"@tailwindcss/typography": "^0.5.16",
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
|
"@tusbar/cache-control": "^1.0.2",
|
||||||
"ai": "^4.2.2",
|
"ai": "^4.2.2",
|
||||||
"assert-never": "^1.2.1",
|
"assert-never": "^1.2.1",
|
||||||
"bun-types": "^1.1.20",
|
"bun-types": "^1.1.20",
|
||||||
@@ -49,7 +51,7 @@
|
|||||||
"object-identity": "^0.1.2",
|
"object-identity": "^0.1.2",
|
||||||
"openapi-types": "^12.1.3",
|
"openapi-types": "^12.1.3",
|
||||||
"p-map": "^7.0.3",
|
"p-map": "^7.0.3",
|
||||||
"@tusbar/cache-control": "^1.0.2",
|
"quick-lru": "^7.0.1",
|
||||||
"react-hotkeys-hook": "^4.4.1",
|
"react-hotkeys-hook": "^4.4.1",
|
||||||
"rehype-sanitize": "^6.0.0",
|
"rehype-sanitize": "^6.0.0",
|
||||||
"rehype-stringify": "^10.0.1",
|
"rehype-stringify": "^10.0.1",
|
||||||
@@ -67,12 +69,12 @@
|
|||||||
"url-join": "^5.0.0",
|
"url-join": "^5.0.0",
|
||||||
"usehooks-ts": "^3.1.0",
|
"usehooks-ts": "^3.1.0",
|
||||||
"warn-once": "^0.1.1",
|
"warn-once": "^0.1.1",
|
||||||
"zustand": "^5.0.3",
|
"zustand": "^5.0.3"
|
||||||
"quick-lru": "^7.0.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@argos-ci/playwright": "^5.0.5",
|
"@argos-ci/playwright": "^5.0.9",
|
||||||
"@playwright/test": "^1.51.1",
|
"@playwright/test": "^1.54.2",
|
||||||
|
"@tailwindcss/postcss": "^4.1.11",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/jsontoxml": "^1.0.5",
|
"@types/jsontoxml": "^1.0.5",
|
||||||
"@types/jsonwebtoken": "^9.0.6",
|
"@types/jsonwebtoken": "^9.0.6",
|
||||||
@@ -84,14 +86,13 @@
|
|||||||
"@types/react": "18.3.13",
|
"@types/react": "18.3.13",
|
||||||
"@types/react-dom": "18.3.1",
|
"@types/react-dom": "18.3.1",
|
||||||
"@types/rison": "^0.0.9",
|
"@types/rison": "^0.0.9",
|
||||||
"autoprefixer": "^10",
|
|
||||||
"deepmerge": "^4.3.1",
|
"deepmerge": "^4.3.1",
|
||||||
"env-cmd": "^10.1.0",
|
"env-cmd": "^10.1.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"psi": "^4.1.0",
|
"psi": "^4.1.0",
|
||||||
"stylelint": "^16.16.0",
|
"stylelint": "^16.16.0",
|
||||||
"tailwindcss": "^3.4.0",
|
"tailwindcss": "^4.1.11",
|
||||||
"ts-essentials": "^10.0.1",
|
"ts-essentials": "^10.0.1",
|
||||||
"typescript": "^5.5.3",
|
"typescript": "^5.5.3",
|
||||||
"vercel": "^39.3.0"
|
"vercel": "^39.3.0"
|
||||||
@@ -100,7 +101,7 @@
|
|||||||
"generate": "gitbook-icons ./public/~gitbook/static/icons custom-icons && gitbook-math ./public/~gitbook/static/math && wrangler types",
|
"generate": "gitbook-icons ./public/~gitbook/static/icons custom-icons && gitbook-math ./public/~gitbook/static/math && wrangler types",
|
||||||
"copy:icons": "gitbook-icons ./public/~gitbook/static/icons",
|
"copy:icons": "gitbook-icons ./public/~gitbook/static/icons",
|
||||||
"clean": "rm -rf ./.next && rm -rf ./public/~gitbook/static/icons && rm -rf ./public/~gitbook/static/math",
|
"clean": "rm -rf ./.next && rm -rf ./public/~gitbook/static/icons && rm -rf ./public/~gitbook/static/math",
|
||||||
"dev": "env-cmd --silent -f ../../.env.local next --turbopack",
|
"dev": "env-cmd --silent -f ../../.env.local next",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"build:cloudflare": "opennextjs-cloudflare build",
|
"build:cloudflare": "opennextjs-cloudflare build",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: {
|
plugins: {
|
||||||
tailwindcss: {},
|
'@tailwindcss/postcss': {},
|
||||||
autoprefixer: {},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
+4
-2
@@ -5,8 +5,9 @@ import {
|
|||||||
generateSiteLayoutMetadata,
|
generateSiteLayoutMetadata,
|
||||||
generateSiteLayoutViewport,
|
generateSiteLayoutViewport,
|
||||||
} from '@/components/SiteLayout';
|
} from '@/components/SiteLayout';
|
||||||
import { GITBOOK_DISABLE_TRACKING } from '@/lib/env';
|
|
||||||
import { getThemeFromMiddleware } from '@/lib/middleware';
|
import { getThemeFromMiddleware } from '@/lib/middleware';
|
||||||
|
import { shouldTrackEvents } from '@/lib/tracking';
|
||||||
|
import { headers } from 'next/headers';
|
||||||
|
|
||||||
interface SiteDynamicLayoutProps {
|
interface SiteDynamicLayoutProps {
|
||||||
params: Promise<RouteLayoutParams>;
|
params: Promise<RouteLayoutParams>;
|
||||||
@@ -18,13 +19,14 @@ export default async function SiteDynamicLayout({
|
|||||||
}: React.PropsWithChildren<SiteDynamicLayoutProps>) {
|
}: React.PropsWithChildren<SiteDynamicLayoutProps>) {
|
||||||
const { context, visitorAuthClaims } = await getDynamicSiteContext(await params);
|
const { context, visitorAuthClaims } = await getDynamicSiteContext(await params);
|
||||||
const forcedTheme = await getThemeFromMiddleware();
|
const forcedTheme = await getThemeFromMiddleware();
|
||||||
|
const withTracking = shouldTrackEvents(await headers());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomizationRootLayout forcedTheme={forcedTheme} customization={context.customization}>
|
<CustomizationRootLayout forcedTheme={forcedTheme} customization={context.customization}>
|
||||||
<SiteLayout
|
<SiteLayout
|
||||||
context={context}
|
context={context}
|
||||||
forcedTheme={forcedTheme}
|
forcedTheme={forcedTheme}
|
||||||
withTracking={!GITBOOK_DISABLE_TRACKING}
|
withTracking={withTracking}
|
||||||
visitorAuthClaims={visitorAuthClaims}
|
visitorAuthClaims={visitorAuthClaims}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
generateSiteLayoutMetadata,
|
generateSiteLayoutMetadata,
|
||||||
generateSiteLayoutViewport,
|
generateSiteLayoutViewport,
|
||||||
} from '@/components/SiteLayout';
|
} from '@/components/SiteLayout';
|
||||||
import { GITBOOK_DISABLE_TRACKING } from '@/lib/env';
|
import { shouldTrackEvents } from '@/lib/tracking';
|
||||||
|
|
||||||
interface SiteStaticLayoutProps {
|
interface SiteStaticLayoutProps {
|
||||||
params: Promise<RouteLayoutParams>;
|
params: Promise<RouteLayoutParams>;
|
||||||
@@ -16,12 +16,13 @@ export default async function SiteStaticLayout({
|
|||||||
children,
|
children,
|
||||||
}: React.PropsWithChildren<SiteStaticLayoutProps>) {
|
}: React.PropsWithChildren<SiteStaticLayoutProps>) {
|
||||||
const { context, visitorAuthClaims } = await getStaticSiteContext(await params);
|
const { context, visitorAuthClaims } = await getStaticSiteContext(await params);
|
||||||
|
const withTracking = shouldTrackEvents();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomizationRootLayout customization={context.customization}>
|
<CustomizationRootLayout customization={context.customization}>
|
||||||
<SiteLayout
|
<SiteLayout
|
||||||
context={context}
|
context={context}
|
||||||
withTracking={!GITBOOK_DISABLE_TRACKING}
|
withTracking={withTracking}
|
||||||
visitorAuthClaims={visitorAuthClaims}
|
visitorAuthClaims={visitorAuthClaims}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
export * from './useAI';
|
||||||
export * from './useAIChat';
|
export * from './useAIChat';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { GitBookSiteContext } from '@/lib/context';
|
import type { GitBookSiteContext } from '@/lib/context';
|
||||||
|
import { tcls } from '@/lib/tailwind';
|
||||||
import type { AIMessage } from '@gitbook/api';
|
import type { AIMessage } from '@gitbook/api';
|
||||||
import { DocumentView } from '../../DocumentView';
|
import { DocumentView } from '../../DocumentView';
|
||||||
import { AIToolCallsSummary } from './AIToolCallsSummary';
|
import { AIToolCallsSummary } from './AIToolCallsSummary';
|
||||||
@@ -19,7 +20,13 @@ export function AIMessageView(
|
|||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
{message.steps.map((step, index) => {
|
{message.steps.map((step, index) => {
|
||||||
return (
|
return (
|
||||||
<div key={index} className="flex animate-[fadeIn_500ms_both] flex-col gap-2">
|
<div
|
||||||
|
key={index}
|
||||||
|
className={tcls(
|
||||||
|
'flex animate-fade-in-slow flex-col gap-2',
|
||||||
|
step.content.nodes.length > 0 ? 'has-content' : ''
|
||||||
|
)}
|
||||||
|
>
|
||||||
<DocumentView
|
<DocumentView
|
||||||
document={step.content}
|
document={step.content}
|
||||||
context={{
|
context={{
|
||||||
@@ -28,8 +35,9 @@ export function AIMessageView(
|
|||||||
wrapBlocksInSuspense: false,
|
wrapBlocksInSuspense: false,
|
||||||
shouldRenderLinkPreviews: true,
|
shouldRenderLinkPreviews: true,
|
||||||
}}
|
}}
|
||||||
style={['space-y-4']}
|
style="mt-2 space-y-4 empty:hidden"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{renderToolCalls && step.toolCalls && step.toolCalls.length > 0 ? (
|
{renderToolCalls && step.toolCalls && step.toolCalls.length > 0 ? (
|
||||||
<AIToolCallsSummary toolCalls={step.toolCalls} context={context} />
|
<AIToolCallsSummary toolCalls={step.toolCalls} context={context} />
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import { getSpaceLanguage } from '@/intl/server';
|
|||||||
import { t } from '@/intl/translate';
|
import { t } from '@/intl/translate';
|
||||||
import type { GitBookSiteContext } from '@/lib/context';
|
import type { GitBookSiteContext } from '@/lib/context';
|
||||||
import { resolveContentRef } from '@/lib/references';
|
import { resolveContentRef } from '@/lib/references';
|
||||||
|
import { tcls } from '@/lib/tailwind';
|
||||||
import type {
|
import type {
|
||||||
AIToolCall,
|
AIToolCall,
|
||||||
AIToolCallGetPageContent,
|
AIToolCallGetPageContent,
|
||||||
AIToolCallGetPages,
|
AIToolCallGetPages,
|
||||||
AIToolCallMCP,
|
AIToolCallMCP,
|
||||||
|
AIToolCallOther,
|
||||||
AIToolCallSearch,
|
AIToolCallSearch,
|
||||||
ContentRef,
|
ContentRef,
|
||||||
} from '@gitbook/api';
|
} from '@gitbook/api';
|
||||||
@@ -37,7 +39,7 @@ function ToolCallSummary(props: { toolCall: AIToolCall; context: GitBookSiteCont
|
|||||||
const { toolCall, context } = props;
|
const { toolCall, context } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex 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
|
||||||
icon={getIconForToolCall(toolCall)}
|
icon={getIconForToolCall(toolCall)}
|
||||||
className="mt-1 size-3 shrink-0 text-tint-subtle/8"
|
className="mt-1 size-3 shrink-0 text-tint-subtle/8"
|
||||||
@@ -57,6 +59,8 @@ function getDescriptionForToolCall(toolCall: AIToolCall, context: GitBookSiteCon
|
|||||||
return <DescriptionForGetPagesToolCall toolCall={toolCall} context={context} />;
|
return <DescriptionForGetPagesToolCall toolCall={toolCall} context={context} />;
|
||||||
case 'mcp':
|
case 'mcp':
|
||||||
return <DescriptionForMCPToolCall toolCall={toolCall} context={context} />;
|
return <DescriptionForMCPToolCall toolCall={toolCall} context={context} />;
|
||||||
|
case 'other':
|
||||||
|
return <DescriptionForOtherToolCall toolCall={toolCall} context={context} />;
|
||||||
default:
|
default:
|
||||||
return <>{toolCall.tool}</>;
|
return <>{toolCall.tool}</>;
|
||||||
}
|
}
|
||||||
@@ -111,6 +115,15 @@ function DescriptionForMCPToolCall(props: {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function DescriptionForOtherToolCall(props: {
|
||||||
|
toolCall: AIToolCallOther;
|
||||||
|
context: GitBookSiteContext;
|
||||||
|
}) {
|
||||||
|
const { toolCall } = props;
|
||||||
|
|
||||||
|
return <p>{toolCall.summary.text}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
async function DescriptionForSearchToolCall(props: {
|
async function DescriptionForSearchToolCall(props: {
|
||||||
toolCall: AIToolCallSearch;
|
toolCall: AIToolCallSearch;
|
||||||
context: GitBookSiteContext;
|
context: GitBookSiteContext;
|
||||||
@@ -144,69 +157,80 @@ async function DescriptionForSearchToolCall(props: {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hasResults = toolCall.results.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<details className="-ml-5 group flex w-full flex-col gap-2">
|
<details className={tcls('-ml-5 group flex w-full flex-col', hasResults ? 'gap-2' : '')}>
|
||||||
<summary className="-mx-2 -mt-2 flex cursor-pointer list-none items-center gap-2 rounded-corners:rounded-md py-2 pr-4 pl-7 transition-colors marker:hidden hover:bg-primary-hover">
|
<summary
|
||||||
<div className="flex flex-col">
|
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',
|
||||||
|
hasResults ? '-my-2 cursor-pointer py-2 hover:bg-primary-hover' : ''
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col leading-snug">
|
||||||
<p>{t(language, 'searched_for', <strong>{toolCall.query}</strong>)}</p>
|
<p>{t(language, 'searched_for', <strong>{toolCall.query}</strong>)}</p>
|
||||||
<p className="text-tint-subtle text-xs">
|
<p className="mt-0.5 text-tint-subtle text-xs">
|
||||||
{toolCall.results.length
|
{hasResults
|
||||||
? t(language, 'search_results_count', toolCall.results.length)
|
? t(language, 'search_results_count', toolCall.results.length)
|
||||||
: t(language, 'search_no_results')}
|
: t(language, 'search_no_results')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-auto flex items-center gap-1">
|
{hasResults ? (
|
||||||
<span className="block group-open:hidden">{t(language, 'view')}</span>
|
<div className="ml-auto flex items-center gap-1">
|
||||||
<span className="hidden group-open:block">{t(language, 'close')}</span>
|
<span className="block group-open:hidden">{t(language, 'view')}</span>
|
||||||
<Icon
|
<span className="hidden group-open:block">{t(language, 'close')}</span>
|
||||||
icon="chevron-right"
|
<Icon
|
||||||
className="size-3 shrink-0 transition-transform group-open:rotate-90"
|
icon="chevron-right"
|
||||||
/>
|
className="size-3 shrink-0 transition-transform group-open:rotate-90"
|
||||||
</div>
|
/>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</summary>
|
</summary>
|
||||||
<div className="max-h-0 overflow-y-auto circular-corners:rounded-2xl rounded-corners:rounded-lg border border-tint-subtle p-2 opacity-0 transition-all duration-500 [transition-behavior:allow-discrete] group-open:max-h-96 group-open:opacity-11">
|
{hasResults ? (
|
||||||
<ol className="space-y-1">
|
<div className="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">
|
||||||
{searchResultsWithHrefs.map((result, index) => (
|
<ol className="space-y-1">
|
||||||
<li
|
{searchResultsWithHrefs.map((result, index) => (
|
||||||
key={`${result.pageId}-${index}`}
|
<li
|
||||||
className="animate-fadeIn"
|
key={`${result.pageId}-${index}`}
|
||||||
style={{
|
className="animate-fade-in-slow"
|
||||||
animationDelay: `${index * 25}ms`,
|
style={{
|
||||||
}}
|
animationDelay: `${index * 25}ms`,
|
||||||
>
|
}}
|
||||||
<Link
|
|
||||||
href={result.href}
|
|
||||||
className="flex items-start gap-2 circular-corners:rounded-2xl rounded-corners:rounded-md px-3 py-2 transition-colors hover:bg-primary-hover"
|
|
||||||
>
|
>
|
||||||
<Icon
|
<Link
|
||||||
icon="memo"
|
href={result.href}
|
||||||
className="mt-1 size-3 shrink-0 text-tint-subtle"
|
className="flex items-start gap-2 circular-corners:rounded-2xl rounded-corners:rounded-md px-3 py-2 transition-colors hover:bg-primary-hover"
|
||||||
/>
|
>
|
||||||
<div className="flex flex-col gap-1 text-tint">
|
<Icon
|
||||||
<h3 className="line-clamp-2 font-medium text-sm text-tint">
|
icon="memo"
|
||||||
<HighlightQuery
|
className="mt-1 size-3 shrink-0 text-tint-subtle"
|
||||||
query={toolCall.query}
|
/>
|
||||||
text={result.title}
|
<div className="flex flex-col gap-1 text-tint">
|
||||||
/>
|
<h3 className="line-clamp-2 font-medium text-sm text-tint">
|
||||||
</h3>
|
|
||||||
{result.description && (
|
|
||||||
<p className="line-clamp-2 text-tint-subtle text-xs">
|
|
||||||
<HighlightQuery
|
<HighlightQuery
|
||||||
query={toolCall.query}
|
query={toolCall.query}
|
||||||
text={result.description}
|
text={result.title}
|
||||||
/>
|
/>
|
||||||
</p>
|
</h3>
|
||||||
)}
|
{result.description && (
|
||||||
</div>
|
<p className="line-clamp-2 text-tint-subtle text-xs">
|
||||||
<Icon
|
<HighlightQuery
|
||||||
icon="chevron-right"
|
query={toolCall.query}
|
||||||
className="ml-auto size-3 shrink-0 self-center"
|
text={result.description}
|
||||||
/>
|
/>
|
||||||
</Link>
|
</p>
|
||||||
</li>
|
)}
|
||||||
))}
|
</div>
|
||||||
</ol>
|
<Icon
|
||||||
</div>
|
icon="chevron-right"
|
||||||
|
className="ml-auto size-3 shrink-0 self-center"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</details>
|
</details>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -235,6 +259,8 @@ function getIconForToolCall(toolCall: AIToolCall): IconName {
|
|||||||
return 'magnifying-glass';
|
return 'magnifying-glass';
|
||||||
case 'getPages':
|
case 'getPages':
|
||||||
return 'files';
|
return 'files';
|
||||||
|
case 'other':
|
||||||
|
return (toolCall.summary.icon as IconName) ?? 'hammer';
|
||||||
default:
|
default:
|
||||||
return 'hammer';
|
return 'hammer';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use server';
|
'use server';
|
||||||
import type { GitBookBaseContext } from '@/lib/context';
|
import type { GitBookBaseContext } from '@/lib/context';
|
||||||
import { fetchServerActionSiteContext } from '@/lib/server-actions';
|
import { fetchServerActionSiteContext } from '@/lib/server-actions';
|
||||||
|
import { traceErrorOnly } from '@/lib/tracing';
|
||||||
import {
|
import {
|
||||||
type AIMessage,
|
type AIMessage,
|
||||||
AIMessageRole,
|
AIMessageRole,
|
||||||
@@ -19,97 +20,100 @@ export async function streamRenderAIMessage(
|
|||||||
rawStream: AsyncIterable<AIStreamResponse>,
|
rawStream: AsyncIterable<AIStreamResponse>,
|
||||||
options?: RenderAIMessageOptions
|
options?: RenderAIMessageOptions
|
||||||
) {
|
) {
|
||||||
const message: AIMessage = {
|
return traceErrorOnly('AI.streamRenderAIMessage', async () => {
|
||||||
id: '',
|
const message: AIMessage = {
|
||||||
role: AIMessageRole.Assistant,
|
id: '',
|
||||||
steps: [],
|
role: AIMessageRole.Assistant,
|
||||||
};
|
steps: [],
|
||||||
|
|
||||||
const updateProcessingMessageStep = (
|
|
||||||
stepIndex: number,
|
|
||||||
callback: (step: AIMessageStep) => void
|
|
||||||
) => {
|
|
||||||
if (stepIndex > message.steps.length) {
|
|
||||||
throw new Error(
|
|
||||||
`Step index out of bounds ${stepIndex} (${message.steps.length} steps)`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.steps[stepIndex]) {
|
|
||||||
message.steps = [...message.steps];
|
|
||||||
message.steps[stepIndex] = { ...message.steps[stepIndex] };
|
|
||||||
callback(message.steps[stepIndex]);
|
|
||||||
} else {
|
|
||||||
message.steps = [
|
|
||||||
...message.steps,
|
|
||||||
{
|
|
||||||
content: {
|
|
||||||
object: 'document',
|
|
||||||
data: {},
|
|
||||||
nodes: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
callback(message.steps[stepIndex]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fetch the full-context in the background to avoid blocking the stream.
|
|
||||||
const promiseContext = fetchServerActionSiteContext(baseContext);
|
|
||||||
|
|
||||||
return parseResponse<{
|
|
||||||
content: React.ReactNode;
|
|
||||||
event: AIStreamResponse;
|
|
||||||
}>(rawStream, async (event) => {
|
|
||||||
switch (event.type) {
|
|
||||||
/**
|
|
||||||
* The agent is processing a tool call in a new message.
|
|
||||||
*/
|
|
||||||
case 'response_tool_call': {
|
|
||||||
updateProcessingMessageStep(event.stepIndex, (step) => {
|
|
||||||
step.toolCalls ??= [];
|
|
||||||
step.toolCalls.push(event.toolCall);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The agent is writing the content of a new message.
|
|
||||||
*/
|
|
||||||
case 'response_reasoning':
|
|
||||||
case 'response_document': {
|
|
||||||
updateProcessingMessageStep(event.stepIndex, (step) => {
|
|
||||||
const container = event.type === 'response_reasoning' ? 'reasoning' : 'content';
|
|
||||||
|
|
||||||
step[container] ??= {
|
|
||||||
object: 'document',
|
|
||||||
data: {},
|
|
||||||
nodes: [],
|
|
||||||
};
|
|
||||||
step[container] = {
|
|
||||||
...step[container],
|
|
||||||
nodes: [...step[container].nodes],
|
|
||||||
};
|
|
||||||
if (event.operation === 'insert') {
|
|
||||||
step[container].nodes.push(...event.blocks);
|
|
||||||
} else {
|
|
||||||
step[container].nodes.splice(
|
|
||||||
-event.blocks.length,
|
|
||||||
event.blocks.length,
|
|
||||||
...event.blocks
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
event,
|
|
||||||
content: (
|
|
||||||
<AIMessageView message={message} context={await promiseContext} {...options} />
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateProcessingMessageStep = (
|
||||||
|
stepIndex: number,
|
||||||
|
callback: (step: AIMessageStep) => void
|
||||||
|
) => {
|
||||||
|
if (stepIndex > message.steps.length) {
|
||||||
|
throw new Error(
|
||||||
|
`Step index out of bounds ${stepIndex} (${message.steps.length} steps)`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.steps[stepIndex]) {
|
||||||
|
message.steps = [...message.steps];
|
||||||
|
message.steps[stepIndex] = { ...message.steps[stepIndex] };
|
||||||
|
callback(message.steps[stepIndex]);
|
||||||
|
} else {
|
||||||
|
message.steps = [
|
||||||
|
...message.steps,
|
||||||
|
{
|
||||||
|
content: {
|
||||||
|
object: 'document',
|
||||||
|
data: {},
|
||||||
|
nodes: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
callback(message.steps[stepIndex]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch the full-context in the background to avoid blocking the stream.
|
||||||
|
const promiseContext = fetchServerActionSiteContext(baseContext);
|
||||||
|
|
||||||
|
return parseResponse<{
|
||||||
|
content: React.ReactNode;
|
||||||
|
event: AIStreamResponse;
|
||||||
|
}>(rawStream, async (event) => {
|
||||||
|
switch (event.type) {
|
||||||
|
/**
|
||||||
|
* The agent is processing a tool call in a new message.
|
||||||
|
*/
|
||||||
|
case 'response_tool_call': {
|
||||||
|
updateProcessingMessageStep(event.stepIndex, (step) => {
|
||||||
|
step.toolCalls ??= [];
|
||||||
|
step.toolCalls.push(event.toolCall);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The agent is writing the content of a new message.
|
||||||
|
*/
|
||||||
|
case 'response_reasoning':
|
||||||
|
case 'response_document': {
|
||||||
|
updateProcessingMessageStep(event.stepIndex, (step) => {
|
||||||
|
const container =
|
||||||
|
event.type === 'response_reasoning' ? 'reasoning' : 'content';
|
||||||
|
|
||||||
|
step[container] ??= {
|
||||||
|
object: 'document',
|
||||||
|
data: {},
|
||||||
|
nodes: [],
|
||||||
|
};
|
||||||
|
step[container] = {
|
||||||
|
...step[container],
|
||||||
|
nodes: [...step[container].nodes],
|
||||||
|
};
|
||||||
|
if (event.operation === 'insert') {
|
||||||
|
step[container].nodes.push(...event.blocks);
|
||||||
|
} else {
|
||||||
|
step[container].nodes.splice(
|
||||||
|
-event.blocks.length,
|
||||||
|
event.blocks.length,
|
||||||
|
...event.blocks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
event,
|
||||||
|
content: (
|
||||||
|
<AIMessageView message={message} context={await promiseContext} {...options} />
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
'use server';
|
'use server';
|
||||||
import { getSiteURLDataFromMiddleware } from '@/lib/middleware';
|
import { getSiteURLDataFromMiddleware } from '@/lib/middleware';
|
||||||
import { getServerActionBaseContext } from '@/lib/server-actions';
|
import { getServerActionBaseContext } from '@/lib/server-actions';
|
||||||
import { type AIMessageContext, AIMessageRole, AIModel } from '@gitbook/api';
|
import { traceErrorOnly } from '@/lib/tracing';
|
||||||
|
import {
|
||||||
|
type AIMessageContext,
|
||||||
|
AIMessageRole,
|
||||||
|
AIModel,
|
||||||
|
type AIToolCallResult,
|
||||||
|
type AIToolDefinition,
|
||||||
|
} from '@gitbook/api';
|
||||||
import { streamRenderAIMessage } from './api';
|
import { streamRenderAIMessage } from './api';
|
||||||
import type { RenderAIMessageOptions } from './types';
|
import type { RenderAIMessageOptions } from './types';
|
||||||
|
|
||||||
@@ -12,32 +19,44 @@ export async function* streamAIChatResponse({
|
|||||||
message,
|
message,
|
||||||
messageContext,
|
messageContext,
|
||||||
previousResponseId,
|
previousResponseId,
|
||||||
|
toolCall,
|
||||||
|
tools,
|
||||||
options,
|
options,
|
||||||
}: {
|
}: {
|
||||||
message: string;
|
message?: string;
|
||||||
messageContext: AIMessageContext;
|
messageContext: AIMessageContext;
|
||||||
previousResponseId?: string;
|
previousResponseId?: string;
|
||||||
|
toolCall?: AIToolCallResult;
|
||||||
|
tools?: AIToolDefinition[];
|
||||||
options?: RenderAIMessageOptions;
|
options?: RenderAIMessageOptions;
|
||||||
}) {
|
}) {
|
||||||
const context = await getServerActionBaseContext();
|
const { stream } = await traceErrorOnly('AI.streamAIChatResponse', async () => {
|
||||||
const siteURLData = await getSiteURLDataFromMiddleware();
|
const context = await getServerActionBaseContext();
|
||||||
|
const siteURLData = await getSiteURLDataFromMiddleware();
|
||||||
|
|
||||||
const api = await context.dataFetcher.api();
|
const api = await context.dataFetcher.api();
|
||||||
const rawStream = api.orgs.streamAiResponseInSite(siteURLData.organization, siteURLData.site, {
|
const rawStream = api.orgs.streamAiResponseInSite(
|
||||||
mode: 'assistant',
|
siteURLData.organization,
|
||||||
input: [
|
siteURLData.site,
|
||||||
{
|
{
|
||||||
role: AIMessageRole.User,
|
input: message
|
||||||
content: message,
|
? [
|
||||||
context: messageContext,
|
{
|
||||||
},
|
role: AIMessageRole.User,
|
||||||
],
|
content: message,
|
||||||
output: { type: 'document' },
|
context: messageContext,
|
||||||
model: AIModel.ReasoningLow,
|
},
|
||||||
previousResponseId,
|
]
|
||||||
});
|
: [],
|
||||||
|
model: AIModel.ReasoningLow,
|
||||||
|
previousResponseId,
|
||||||
|
toolCall,
|
||||||
|
tools,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const { stream } = await streamRenderAIMessage(context, rawStream, options);
|
return await streamRenderAIMessage(context, rawStream, options);
|
||||||
|
});
|
||||||
|
|
||||||
for await (const output of stream) {
|
for await (const output of stream) {
|
||||||
yield output;
|
yield output;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use server';
|
'use server';
|
||||||
import { getSiteURLDataFromMiddleware } from '@/lib/middleware';
|
import { getSiteURLDataFromMiddleware } from '@/lib/middleware';
|
||||||
import { getServerActionBaseContext } from '@/lib/server-actions';
|
import { getServerActionBaseContext } from '@/lib/server-actions';
|
||||||
|
import { traceErrorOnly } from '@/lib/tracing';
|
||||||
import { streamRenderAIMessage } from './api';
|
import { streamRenderAIMessage } from './api';
|
||||||
import type { RenderAIMessageOptions } from './types';
|
import type { RenderAIMessageOptions } from './types';
|
||||||
|
|
||||||
@@ -14,16 +15,18 @@ export async function* streamAIResponseById({
|
|||||||
responseId: string;
|
responseId: string;
|
||||||
options?: RenderAIMessageOptions;
|
options?: RenderAIMessageOptions;
|
||||||
}) {
|
}) {
|
||||||
const context = await getServerActionBaseContext();
|
const { stream } = await traceErrorOnly('AI.streamAIResponseById', async () => {
|
||||||
const siteURLData = await getSiteURLDataFromMiddleware();
|
const context = await getServerActionBaseContext();
|
||||||
|
const siteURLData = await getSiteURLDataFromMiddleware();
|
||||||
|
|
||||||
const api = await context.dataFetcher.api();
|
const api = await context.dataFetcher.api();
|
||||||
const rawStream = api.orgs.streamExistingAiResponseInSite(
|
const rawStream = api.orgs.streamExistingAiResponseInSite(
|
||||||
siteURLData.organization,
|
siteURLData.organization,
|
||||||
siteURLData.site,
|
siteURLData.site,
|
||||||
responseId
|
responseId
|
||||||
);
|
);
|
||||||
const { stream } = await streamRenderAIMessage(context, rawStream, options);
|
return await streamRenderAIMessage(context, rawStream, options);
|
||||||
|
});
|
||||||
|
|
||||||
for await (const output of stream) {
|
for await (const output of stream) {
|
||||||
yield output;
|
yield output;
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { CustomizationAIMode } from '@gitbook/api';
|
||||||
|
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, getAIChatName } from '../AIChat';
|
||||||
|
import { useIntegrationAssistants } from '../Integrations';
|
||||||
|
import { useSearch } from '../Search/useSearch';
|
||||||
|
|
||||||
|
// Unify assistants configuration context with the assistants hook in one place
|
||||||
|
export type AIConfig = {
|
||||||
|
aiMode: CustomizationAIMode;
|
||||||
|
trademark: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Assistant = Omit<GitBookAssistant, 'icon'> & {
|
||||||
|
/**
|
||||||
|
* Unique identifier for the assistant. Generated automatically using Crypto.randomUUID().
|
||||||
|
* @example '123e4567-e89b-12d3-a456-426614174000'
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display mode for the assistant. Currently, only `overlay` is supported for custom assistants.
|
||||||
|
* - `overlay`: Display the assistant in an overlay on top of the page.
|
||||||
|
* - `sidebar`: Display the assistant in a sidebar next to the page. Only supported for the GitBook Assistant.
|
||||||
|
* - `search`: Display the assistant inside the search container. Only supported for GitBook AI Search.
|
||||||
|
* @default 'overlay'
|
||||||
|
*/
|
||||||
|
mode?: 'overlay' | 'sidebar' | 'search';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icon of the assistant displayed in the UI.
|
||||||
|
*/
|
||||||
|
icon: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const AIContext = React.createContext<AIConfig | null>(null);
|
||||||
|
|
||||||
|
export function AIContextProvider(props: React.PropsWithChildren<AIConfig>): React.ReactElement {
|
||||||
|
const { aiMode, trademark, children } = props;
|
||||||
|
const value = React.useMemo(() => ({ aiMode, trademark }), [aiMode, trademark]);
|
||||||
|
return <AIContext.Provider value={value}>{children}</AIContext.Provider>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useAIConfig(): AIConfig {
|
||||||
|
const ctx = React.useContext(AIContext);
|
||||||
|
if (!ctx) {
|
||||||
|
throw new Error('useAI must be used within AIContextProvider');
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
type AIContext = {
|
||||||
|
config: AIConfig;
|
||||||
|
assistants: Assistant[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unified assistants list combining the built-in GitBook Assistant (when enabled)
|
||||||
|
* with any custom assistants registered at runtime.
|
||||||
|
*/
|
||||||
|
export function useAI(): AIContext {
|
||||||
|
const config = useAIConfig();
|
||||||
|
const chat = useAIChatState();
|
||||||
|
const chatController = useAIChatController();
|
||||||
|
const language = useLanguage();
|
||||||
|
const [, setSearchState] = useSearch();
|
||||||
|
|
||||||
|
const assistants: Assistant[] = [];
|
||||||
|
|
||||||
|
if (config.aiMode === CustomizationAIMode.Assistant) {
|
||||||
|
assistants.push({
|
||||||
|
id: 'gitbook-assistant',
|
||||||
|
label: getAIChatName(config.trademark),
|
||||||
|
icon: (
|
||||||
|
<AIChatIcon
|
||||||
|
state={chat.loading ? 'thinking' : 'default'}
|
||||||
|
trademark={config.trademark}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
open: (query?: string) => {
|
||||||
|
chatController.open();
|
||||||
|
if (query) {
|
||||||
|
chatController.postMessage({ message: query });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ui: true,
|
||||||
|
mode: 'sidebar',
|
||||||
|
});
|
||||||
|
} else if (config.aiMode === CustomizationAIMode.Search) {
|
||||||
|
assistants.push({
|
||||||
|
id: 'gitbook-ai-search',
|
||||||
|
label: tString(language, 'ai_chat_context_badge'),
|
||||||
|
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) =>
|
||||||
|
prev ? { ...prev, query: null, ask: query, open: true } : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ui: false,
|
||||||
|
mode: 'search',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const integrationAssistants = useIntegrationAssistants();
|
||||||
|
if (integrationAssistants.length > 0) {
|
||||||
|
assistants.push(
|
||||||
|
...integrationAssistants.map((assistant) => ({
|
||||||
|
...assistant,
|
||||||
|
icon: <Icon icon={assistant.icon as IconName} className="size-4" />,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
config,
|
||||||
|
assistants,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -2,15 +2,40 @@
|
|||||||
|
|
||||||
import * as zustand from 'zustand';
|
import * as zustand from 'zustand';
|
||||||
|
|
||||||
import { AIMessageRole } from '@gitbook/api';
|
import { useLanguage } from '@/intl/client';
|
||||||
|
import { tString } from '@/intl/translate';
|
||||||
|
import {
|
||||||
|
AIMessageRole,
|
||||||
|
type AIStreamResponseToolCallPending,
|
||||||
|
type AIToolCallResult,
|
||||||
|
} from '@gitbook/api';
|
||||||
|
import type { IconName } from '@gitbook/icons';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useTrackEvent } from '../Insights';
|
import { useTrackEvent } from '../Insights';
|
||||||
|
import { integrationsAssistantTools } from '../Integrations';
|
||||||
|
import { useSearch } from '../Search';
|
||||||
import { streamAIChatResponse } from './server-actions';
|
import { streamAIChatResponse } from './server-actions';
|
||||||
import { useAIMessageContextRef } from './useAIMessageContext';
|
import { useAIMessageContextRef } from './useAIMessageContext';
|
||||||
|
|
||||||
export type AIChatMessage = {
|
export type AIChatMessage = {
|
||||||
role: AIMessageRole;
|
role: AIMessageRole;
|
||||||
content: React.ReactNode;
|
content: React.ReactNode;
|
||||||
|
query?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AIChatPendingTool = {
|
||||||
|
icon?: IconName;
|
||||||
|
label: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm the tool call by calling this function.
|
||||||
|
*/
|
||||||
|
confirm: () => Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tool call result to cancel it.
|
||||||
|
*/
|
||||||
|
cancelToolCall: AIToolCallResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AIChatState = {
|
export type AIChatState = {
|
||||||
@@ -24,6 +49,16 @@ export type AIChatState = {
|
|||||||
*/
|
*/
|
||||||
responseId: string | null;
|
responseId: string | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The latest query sent to the AI.
|
||||||
|
*/
|
||||||
|
query: string | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first query sent to the AI. This is appended to the URL when the AI chat is opened.
|
||||||
|
*/
|
||||||
|
initialQuery: string | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Messages in the session.
|
* Messages in the session.
|
||||||
*/
|
*/
|
||||||
@@ -34,6 +69,11 @@ export type AIChatState = {
|
|||||||
*/
|
*/
|
||||||
followUpSuggestions: string[];
|
followUpSuggestions: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tools that are pending confirmation to be executed.
|
||||||
|
*/
|
||||||
|
pendingTools: AIChatPendingTool[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, the session is in progress.
|
* If true, the session is in progress.
|
||||||
*/
|
*/
|
||||||
@@ -50,34 +90,26 @@ export type AIChatState = {
|
|||||||
export type AIChatController = {
|
export type AIChatController = {
|
||||||
/** Open the dialog */
|
/** Open the dialog */
|
||||||
open: () => void;
|
open: () => void;
|
||||||
|
|
||||||
/** Close the dialog */
|
/** Close the dialog */
|
||||||
close: () => void;
|
close: () => void;
|
||||||
|
|
||||||
/** Post a message to the session */
|
/** Post a message to the session */
|
||||||
postMessage: (input: {
|
postMessage: (input: { message: string }) => void;
|
||||||
/** The message to post to the session. it can be markdown formatted. */
|
|
||||||
message: string;
|
|
||||||
}) => void;
|
|
||||||
|
|
||||||
/** Clear the conversation */
|
/** Clear the conversation */
|
||||||
clear: () => void;
|
clear: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const globalState = zustand.create<{
|
// Global state store for AI chat
|
||||||
state: AIChatState;
|
const globalState = zustand.create<AIChatState>(() => {
|
||||||
setState: (fn: (state: AIChatState) => Partial<AIChatState>) => void;
|
|
||||||
}>((set) => {
|
|
||||||
return {
|
return {
|
||||||
state: {
|
opened: false,
|
||||||
opened: false,
|
responseId: null,
|
||||||
responseId: null,
|
messages: [],
|
||||||
messages: [],
|
query: null,
|
||||||
followUpSuggestions: [],
|
followUpSuggestions: [],
|
||||||
loading: false,
|
pendingTools: [],
|
||||||
error: false,
|
loading: false,
|
||||||
},
|
error: false,
|
||||||
setState: (fn) => set((state) => ({ state: { ...state.state, ...fn(state.state) } })),
|
initialQuery: null,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -85,116 +117,317 @@ const globalState = zustand.create<{
|
|||||||
* Get the current state of the AI chat.
|
* Get the current state of the AI chat.
|
||||||
*/
|
*/
|
||||||
export function useAIChatState(): AIChatState {
|
export function useAIChatState(): AIChatState {
|
||||||
const state = zustand.useStore(globalState, (state) => state.state);
|
const state = zustand.useStore(globalState);
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the controller to interact with the AI chat.
|
* Get the controller to interact with the AI chat.
|
||||||
|
* Integrates with search state to synchronize ?ask= parameter.
|
||||||
*/
|
*/
|
||||||
export function useAIChatController(): AIChatController {
|
export function useAIChatController(): AIChatController {
|
||||||
const messageContextRef = useAIMessageContextRef();
|
const messageContextRef = useAIMessageContextRef();
|
||||||
const setState = zustand.useStore(globalState, (state) => state.setState);
|
|
||||||
const trackEvent = useTrackEvent();
|
const trackEvent = useTrackEvent();
|
||||||
|
const [, setSearchState] = useSearch();
|
||||||
|
const language = useLanguage();
|
||||||
|
|
||||||
|
// Open AI chat and sync with search state
|
||||||
|
const onOpen = React.useCallback(() => {
|
||||||
|
const { initialQuery } = globalState.getState();
|
||||||
|
globalState.setState((state) => ({ ...state, opened: true }));
|
||||||
|
|
||||||
|
// Update search state to show ask mode with first message or current ask value
|
||||||
|
setSearchState((prev) => ({
|
||||||
|
ask: prev?.ask ?? initialQuery ?? '',
|
||||||
|
query: prev?.query ?? null,
|
||||||
|
global: prev?.global ?? false,
|
||||||
|
open: false, // Close search popover when opening chat
|
||||||
|
}));
|
||||||
|
}, [setSearchState]);
|
||||||
|
|
||||||
|
// Close AI chat and clear ask parameter
|
||||||
|
const onClose = React.useCallback(() => {
|
||||||
|
globalState.setState((state) => ({ ...state, opened: false }));
|
||||||
|
|
||||||
|
// Clear ask parameter but keep other search state
|
||||||
|
setSearchState((prev) => ({
|
||||||
|
ask: null,
|
||||||
|
query: prev?.query ?? null,
|
||||||
|
global: prev?.global ?? false,
|
||||||
|
open: false,
|
||||||
|
}));
|
||||||
|
}, [setSearchState]);
|
||||||
|
|
||||||
|
// Stream a message with the AI backend
|
||||||
|
const streamResponse = React.useCallback(
|
||||||
|
async (input: {
|
||||||
|
/** Text message to send to the AI backend */
|
||||||
|
message?: string;
|
||||||
|
/** Tool call to send to the AI backend */
|
||||||
|
toolCall?: AIToolCallResult;
|
||||||
|
}) => {
|
||||||
|
globalState.setState((state) => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
followUpSuggestions: [],
|
||||||
|
pendingTools: [],
|
||||||
|
loading: true,
|
||||||
|
error: false,
|
||||||
|
messages: [
|
||||||
|
...state.messages,
|
||||||
|
{
|
||||||
|
role: AIMessageRole.Assistant,
|
||||||
|
content: null, // Placeholder for streaming response
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Execute a tool call
|
||||||
|
const executeToolCall = async (event: AIStreamResponseToolCallPending) => {
|
||||||
|
const integrationTools = integrationsAssistantTools.getState().tools;
|
||||||
|
const toolDef = integrationTools.find((tool) => tool.name === event.toolCall.tool);
|
||||||
|
|
||||||
|
if (!toolDef) {
|
||||||
|
throw new Error(`Tool ${event.toolCall.tool} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await toolDef.execute(event.toolCall.input);
|
||||||
|
streamResponse({
|
||||||
|
toolCall: {
|
||||||
|
tool: event.toolCall.tool,
|
||||||
|
toolCallId: event.toolCallId,
|
||||||
|
output: result.output,
|
||||||
|
summary: result.summary,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
streamResponse({
|
||||||
|
toolCall: {
|
||||||
|
tool: event.toolCall.tool,
|
||||||
|
toolCallId: event.toolCallId,
|
||||||
|
output: {
|
||||||
|
error: error instanceof Error ? error.message : 'Unknown error',
|
||||||
|
},
|
||||||
|
summary: {
|
||||||
|
icon: 'bomb',
|
||||||
|
text: 'An error occurred while executing the tool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let toolToExecute: AIStreamResponseToolCallPending | null = null;
|
||||||
|
try {
|
||||||
|
const integrationTools = integrationsAssistantTools.getState().tools;
|
||||||
|
const stream = await streamAIChatResponse({
|
||||||
|
message: input.message,
|
||||||
|
toolCall: input.toolCall,
|
||||||
|
messageContext: messageContextRef.current,
|
||||||
|
previousResponseId: globalState.getState().responseId ?? undefined,
|
||||||
|
tools: integrationTools.map((tool) => ({
|
||||||
|
name: tool.name,
|
||||||
|
description: tool.description,
|
||||||
|
inputSchema: tool.inputSchema,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Process streaming response
|
||||||
|
for await (const data of stream) {
|
||||||
|
if (!data) continue;
|
||||||
|
|
||||||
|
if (input.message && globalState.getState().query !== input.message) {
|
||||||
|
// Chat was cleared, stop processing the stream
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = data.event;
|
||||||
|
|
||||||
|
switch (event.type) {
|
||||||
|
case 'response_finish': {
|
||||||
|
globalState.setState((state) => ({
|
||||||
|
...state,
|
||||||
|
responseId: event.responseId,
|
||||||
|
// Mark as not loading when the response is finished
|
||||||
|
// Even if the stream might continue as we receive 'response_followup_suggestion'
|
||||||
|
loading: false,
|
||||||
|
error: false,
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'response_followup_suggestion': {
|
||||||
|
globalState.setState((state) => ({
|
||||||
|
...state,
|
||||||
|
followUpSuggestions: [
|
||||||
|
...state.followUpSuggestions,
|
||||||
|
...event.suggestions,
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'response_tool_call_pending': {
|
||||||
|
const toolDef = integrationTools.find(
|
||||||
|
(tool) => tool.name === event.toolCall.tool
|
||||||
|
);
|
||||||
|
if (!toolDef) {
|
||||||
|
throw new Error(`Tool ${event.toolCall.tool} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmation = toolDef.confirmation;
|
||||||
|
if (confirmation) {
|
||||||
|
globalState.setState((state) => ({
|
||||||
|
...state,
|
||||||
|
pendingTools: [
|
||||||
|
...state.pendingTools,
|
||||||
|
{
|
||||||
|
icon: confirmation.icon,
|
||||||
|
label: confirmation.label,
|
||||||
|
cancelToolCall: {
|
||||||
|
tool: event.toolCall.tool,
|
||||||
|
toolCallId: event.toolCallId,
|
||||||
|
output: {
|
||||||
|
cancelled: 'User did not confirm the tool call',
|
||||||
|
},
|
||||||
|
summary: {
|
||||||
|
icon: 'forward',
|
||||||
|
text: tString(
|
||||||
|
language,
|
||||||
|
'tool_call_skipped',
|
||||||
|
confirmation.label
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
confirm: async () => {
|
||||||
|
await executeToolCall(event);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
toolToExecute = event;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the assistant message with streamed content
|
||||||
|
globalState.setState((state) => ({
|
||||||
|
...state,
|
||||||
|
messages: [
|
||||||
|
...state.messages.slice(0, -1),
|
||||||
|
{
|
||||||
|
role: AIMessageRole.Assistant,
|
||||||
|
content: data.content,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the tool call if it doesn't require confirmation
|
||||||
|
if (toolToExecute) {
|
||||||
|
await executeToolCall(toolToExecute);
|
||||||
|
}
|
||||||
|
|
||||||
|
globalState.setState((state) => ({
|
||||||
|
...state,
|
||||||
|
loading: false,
|
||||||
|
error: false,
|
||||||
|
}));
|
||||||
|
} catch {
|
||||||
|
globalState.setState((state) => ({
|
||||||
|
...state,
|
||||||
|
loading: false,
|
||||||
|
error: true,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[messageContextRef.current]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Post a message to the AI chat
|
||||||
|
const onPostMessage = React.useCallback(
|
||||||
|
async (input: { message: string }) => {
|
||||||
|
const { query, messages, pendingTools } = globalState.getState();
|
||||||
|
|
||||||
|
// For first message, update the ask parameter in URL
|
||||||
|
if (messages.length === 0) {
|
||||||
|
setSearchState((prev) => ({
|
||||||
|
ask: input.message,
|
||||||
|
query: prev?.query ?? null,
|
||||||
|
global: prev?.global ?? false,
|
||||||
|
open: false,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query === input.message) {
|
||||||
|
// Return early if the message is the same as the previous message
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
trackEvent({ type: 'ask_question', query: input.message });
|
||||||
|
|
||||||
|
// Add user message and placeholder for AI response
|
||||||
|
globalState.setState((state) => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
messages: [
|
||||||
|
...state.messages,
|
||||||
|
{
|
||||||
|
role: AIMessageRole.User,
|
||||||
|
content: input.message,
|
||||||
|
query: input.message,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
query: input.message,
|
||||||
|
followUpSuggestions: [],
|
||||||
|
loading: true,
|
||||||
|
error: false,
|
||||||
|
initialQuery: state.initialQuery ?? input.message,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const pendingTool = pendingTools[0];
|
||||||
|
streamResponse({
|
||||||
|
message: input.message,
|
||||||
|
// If we had a pending tool call, we need to send it as being cancelled
|
||||||
|
// otherwise the AI will fail to process the message
|
||||||
|
...(pendingTool ? { toolCall: pendingTool.cancelToolCall } : {}),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[setSearchState, trackEvent, streamResponse]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Clear the conversation and reset ask parameter
|
||||||
|
const onClear = React.useCallback(() => {
|
||||||
|
globalState.setState((state) => ({
|
||||||
|
opened: state.opened,
|
||||||
|
loading: false,
|
||||||
|
messages: [],
|
||||||
|
query: null,
|
||||||
|
followUpSuggestions: [],
|
||||||
|
pendingTools: [],
|
||||||
|
responseId: null,
|
||||||
|
error: false,
|
||||||
|
initialQuery: null,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Reset ask parameter to empty string (keeps chat open but clears content)
|
||||||
|
setSearchState((prev) => ({
|
||||||
|
ask: '',
|
||||||
|
query: prev?.query ?? null,
|
||||||
|
global: prev?.global ?? false,
|
||||||
|
open: false,
|
||||||
|
}));
|
||||||
|
}, [setSearchState]);
|
||||||
|
|
||||||
return React.useMemo(() => {
|
return React.useMemo(() => {
|
||||||
return {
|
return {
|
||||||
open: () => setState((state) => ({ ...state, opened: true })),
|
open: onOpen,
|
||||||
close: () => setState((state) => ({ ...state, opened: false })),
|
close: onClose,
|
||||||
clear: () =>
|
clear: onClear,
|
||||||
setState((state) => ({
|
postMessage: onPostMessage,
|
||||||
opened: state.opened,
|
|
||||||
loading: false,
|
|
||||||
messages: [],
|
|
||||||
followUpSuggestions: [],
|
|
||||||
responseId: null,
|
|
||||||
error: false,
|
|
||||||
})),
|
|
||||||
postMessage: async (input: { message: string }) => {
|
|
||||||
trackEvent({ type: 'ask_question', query: input.message });
|
|
||||||
setState((state) => {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
messages: [
|
|
||||||
...state.messages,
|
|
||||||
{
|
|
||||||
// TODO: how to handle markdown here?
|
|
||||||
// to avoid rendering as plain text
|
|
||||||
role: AIMessageRole.User,
|
|
||||||
content: input.message,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: AIMessageRole.Assistant,
|
|
||||||
content: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
followUpSuggestions: [],
|
|
||||||
loading: true,
|
|
||||||
error: false,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const stream = await streamAIChatResponse({
|
|
||||||
message: input.message,
|
|
||||||
messageContext: messageContextRef.current,
|
|
||||||
previousResponseId: globalState.getState().state.responseId ?? undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
for await (const data of stream) {
|
|
||||||
if (!data) continue;
|
|
||||||
|
|
||||||
const event = data.event;
|
|
||||||
|
|
||||||
switch (event.type) {
|
|
||||||
case 'response_finish': {
|
|
||||||
setState((state) => ({
|
|
||||||
...state,
|
|
||||||
responseId: event.responseId,
|
|
||||||
// Mark as not loading when the response is finished
|
|
||||||
// Even if the stream might continue as we receive 'response_followup_suggestion'
|
|
||||||
loading: false,
|
|
||||||
error: false,
|
|
||||||
}));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'response_followup_suggestion': {
|
|
||||||
setState((state) => ({
|
|
||||||
...state,
|
|
||||||
followUpSuggestions: [
|
|
||||||
...state.followUpSuggestions,
|
|
||||||
...event.suggestions,
|
|
||||||
],
|
|
||||||
}));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setState((state) => ({
|
|
||||||
...state,
|
|
||||||
messages: [
|
|
||||||
...state.messages.slice(0, -1),
|
|
||||||
{
|
|
||||||
role: AIMessageRole.Assistant,
|
|
||||||
content: data.content,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
setState((state) => ({
|
|
||||||
...state,
|
|
||||||
loading: false,
|
|
||||||
error: false,
|
|
||||||
}));
|
|
||||||
} catch {
|
|
||||||
setState((state) => ({
|
|
||||||
...state,
|
|
||||||
loading: false,
|
|
||||||
error: true,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}, [messageContextRef, setState, trackEvent]);
|
}, [onOpen, onClose, onClear, onPostMessage]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useAIChatController } from '@/components/AI/useAIChat';
|
import { useAIChatState } from '@/components/AI';
|
||||||
import { useAIChatState } from '@/components/AI/useAIChat';
|
import type { Assistant } from '@/components/AI';
|
||||||
import { ChatGPTIcon } from '@/components/AIActions/assets/ChatGPTIcon';
|
import { ChatGPTIcon } from '@/components/AIActions/assets/ChatGPTIcon';
|
||||||
import { ClaudeIcon } from '@/components/AIActions/assets/ClaudeIcon';
|
import { ClaudeIcon } from '@/components/AIActions/assets/ClaudeIcon';
|
||||||
import { MarkdownIcon } from '@/components/AIActions/assets/MarkdownIcon';
|
import { MarkdownIcon } from '@/components/AIActions/assets/MarkdownIcon';
|
||||||
import { getAIChatName } from '@/components/AIChat';
|
|
||||||
import { AIChatIcon } from '@/components/AIChat';
|
|
||||||
import { Button } from '@/components/primitives/Button';
|
import { Button } from '@/components/primitives/Button';
|
||||||
import { DropdownMenuItem, useDropdownMenuClose } from '@/components/primitives/DropdownMenu';
|
import { DropdownMenuItem, useDropdownMenuClose } from '@/components/primitives/DropdownMenu';
|
||||||
import { tString, useLanguage } from '@/intl/client';
|
import { tString, useLanguage } from '@/intl/client';
|
||||||
@@ -22,32 +20,21 @@ type AIActionType = 'button' | 'dropdown-menu-item';
|
|||||||
/**
|
/**
|
||||||
* Opens our AI Docs Assistant.
|
* Opens our AI Docs Assistant.
|
||||||
*/
|
*/
|
||||||
export function OpenDocsAssistant(props: { type: AIActionType; trademark: boolean }) {
|
export function OpenAIAssistant(props: { assistant: Assistant; type: AIActionType }) {
|
||||||
const { type, trademark } = props;
|
const { assistant, type } = props;
|
||||||
const chatController = useAIChatController();
|
|
||||||
const chat = useAIChatState();
|
const chat = useAIChatState();
|
||||||
const language = useLanguage();
|
const language = useLanguage();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AIActionWrapper
|
<AIActionWrapper
|
||||||
type={type}
|
type={type}
|
||||||
icon={
|
icon={assistant.icon}
|
||||||
<AIChatIcon state={chat.loading ? 'thinking' : 'default'} trademark={trademark} />
|
label={assistant.label}
|
||||||
}
|
|
||||||
label={tString(language, 'ai_chat_ask', getAIChatName(trademark))}
|
|
||||||
shortLabel={tString(language, 'ask')}
|
shortLabel={tString(language, 'ask')}
|
||||||
description={tString(language, 'ai_chat_ask_about_page', getAIChatName(trademark))}
|
description={tString(language, 'ai_chat_ask_about_page', assistant.label)}
|
||||||
disabled={chat.loading}
|
disabled={chat.loading}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// Open the chat if it's not already open
|
assistant.open(tString(language, 'ai_chat_suggested_questions_about_this_page'));
|
||||||
if (!chat.opened) {
|
|
||||||
chatController.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the "What is this page about?" message
|
|
||||||
chatController.postMessage({
|
|
||||||
message: tString(language, 'ai_chat_suggested_questions_about_this_page'),
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -231,13 +218,15 @@ function AIActionWrapper(props: {
|
|||||||
}
|
}
|
||||||
size="xsmall"
|
size="xsmall"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
label={shortLabel || label}
|
label={label ?? shortLabel}
|
||||||
className="hover:!scale-100 !shadow-none !rounded-r-none hover:!translate-y-0 border-r-0 bg-tint-base text-sm"
|
className="bg-tint-base text-sm"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
href={href}
|
href={href}
|
||||||
target={href ? '_blank' : undefined}
|
target={href ? '_blank' : undefined}
|
||||||
disabled={disabled || loading}
|
disabled={disabled || loading}
|
||||||
/>
|
>
|
||||||
|
{shortLabel}
|
||||||
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,13 +240,13 @@ function AIActionWrapper(props: {
|
|||||||
>
|
>
|
||||||
<div className="flex size-5 items-center justify-center text-tint">
|
<div className="flex size-5 items-center justify-center text-tint">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Icon icon="spinner-third" className="size-4 animate-spin" />
|
<Icon icon="spinner-third" className="size-4 shrink-0 animate-spin" />
|
||||||
) : icon ? (
|
) : icon ? (
|
||||||
typeof icon === 'string' ? (
|
typeof icon === 'string' ? (
|
||||||
<Icon
|
<Icon
|
||||||
icon={icon as IconName}
|
icon={icon as IconName}
|
||||||
iconStyle={IconStyle.Regular}
|
iconStyle={IconStyle.Regular}
|
||||||
className="size-4 fill-transparent stroke-current"
|
className="size-4 shrink-0 fill-transparent stroke-current"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
icon
|
icon
|
||||||
@@ -268,9 +257,9 @@ function AIActionWrapper(props: {
|
|||||||
<div className="flex flex-1 flex-col gap-0.5">
|
<div className="flex flex-1 flex-col gap-0.5">
|
||||||
<span className="flex items-center gap-2 text-tint-strong">
|
<span className="flex items-center gap-2 text-tint-strong">
|
||||||
<span className="truncate font-medium text-sm">{label}</span>
|
<span className="truncate font-medium text-sm">{label}</span>
|
||||||
{href ? <Icon icon="arrow-up-right" className="size-3" /> : null}
|
{href ? <Icon icon="arrow-up-right" className="size-3 shrink-0" /> : null}
|
||||||
</span>
|
</span>
|
||||||
{description && <span className="truncate text-tint text-xs">{description}</span>}
|
{description && <span className="text-tint text-xs">{description}</span>}
|
||||||
</div>
|
</div>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,24 +2,22 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
CopyMarkdown,
|
CopyMarkdown,
|
||||||
OpenDocsAssistant,
|
OpenAIAssistant,
|
||||||
OpenInLLM,
|
OpenInLLM,
|
||||||
ViewAsMarkdown,
|
ViewAsMarkdown,
|
||||||
} from '@/components/AIActions/AIActions';
|
} from '@/components/AIActions/AIActions';
|
||||||
import { Button } from '@/components/primitives/Button';
|
import { Button, ButtonGroup } from '@/components/primitives/Button';
|
||||||
import { DropdownMenu } from '@/components/primitives/DropdownMenu';
|
import { DropdownMenu, DropdownMenuSeparator } from '@/components/primitives/DropdownMenu';
|
||||||
|
import { tString, useLanguage } from '@/intl/client';
|
||||||
|
import type { SiteCustomizationSettings } from '@gitbook/api';
|
||||||
import { Icon } from '@gitbook/icons';
|
import { Icon } from '@gitbook/icons';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
|
import { useAI } from '../AI';
|
||||||
|
|
||||||
interface AIActionsDropdownProps {
|
interface AIActionsDropdownProps {
|
||||||
markdownPageUrl: string;
|
markdownPageUrl: string;
|
||||||
withAIChat?: boolean;
|
className?: string;
|
||||||
trademark: boolean;
|
actions: SiteCustomizationSettings['pageActions'];
|
||||||
/**
|
|
||||||
* Whether to include the "Open in LLM" entries in the dropdown menu.
|
|
||||||
*/
|
|
||||||
withLLMActions?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,55 +25,71 @@ interface AIActionsDropdownProps {
|
|||||||
*/
|
*/
|
||||||
export function AIActionsDropdown(props: AIActionsDropdownProps) {
|
export function AIActionsDropdown(props: AIActionsDropdownProps) {
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
const assistants = useAI().assistants.filter((assistant) => assistant.ui === true);
|
||||||
|
const language = useLanguage();
|
||||||
|
|
||||||
return (
|
return assistants.length > 0 || props.actions.markdown || props.actions.externalAI ? (
|
||||||
<div ref={ref} className="flex h-fit items-stretch justify-start">
|
<ButtonGroup ref={ref} className={props.className}>
|
||||||
<DefaultAction {...props} />
|
<DefaultAction {...props} />
|
||||||
<DropdownMenu
|
{props.actions.markdown || props.actions.externalAI ? (
|
||||||
align="end"
|
<DropdownMenu
|
||||||
className="!min-w-60 max-w-max"
|
align="end"
|
||||||
button={
|
className="!min-w-60 max-w-max"
|
||||||
<Button
|
button={
|
||||||
icon={
|
<Button
|
||||||
<Icon
|
icon={
|
||||||
icon="chevron-down"
|
<Icon
|
||||||
className="size-3 transition-transform group-data-[state=open]/button:rotate-180"
|
icon="chevron-down"
|
||||||
/>
|
className="size-3 transition-transform group-data-[state=open]/button:rotate-180"
|
||||||
}
|
/>
|
||||||
iconOnly
|
}
|
||||||
size="xsmall"
|
label={tString(language, 'more')}
|
||||||
variant="secondary"
|
iconOnly
|
||||||
className="hover:!scale-100 hover:!translate-y-0 !shadow-none !rounded-l-none bg-tint-base text-sm"
|
size="xsmall"
|
||||||
/>
|
variant="secondary"
|
||||||
}
|
className="bg-tint-base text-sm"
|
||||||
>
|
/>
|
||||||
<AIActionsDropdownMenuContent {...props} />
|
}
|
||||||
</DropdownMenu>
|
>
|
||||||
</div>
|
<AIActionsDropdownMenuContent {...props} />
|
||||||
);
|
</DropdownMenu>
|
||||||
|
) : null}
|
||||||
|
</ButtonGroup>
|
||||||
|
) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The content of the dropdown menu.
|
* The content of the dropdown menu.
|
||||||
*/
|
*/
|
||||||
function AIActionsDropdownMenuContent(props: AIActionsDropdownProps) {
|
function AIActionsDropdownMenuContent(props: AIActionsDropdownProps) {
|
||||||
const { markdownPageUrl, withAIChat, trademark, withLLMActions } = props;
|
const { markdownPageUrl, actions } = props;
|
||||||
|
const assistants = useAI().assistants.filter((assistant) => assistant.ui === true);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{withAIChat ? (
|
{assistants.map((assistant) => (
|
||||||
<OpenDocsAssistant trademark={trademark} type="dropdown-menu-item" />
|
<OpenAIAssistant
|
||||||
|
key={assistant.label}
|
||||||
|
assistant={assistant}
|
||||||
|
type="dropdown-menu-item"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{actions.markdown ? (
|
||||||
|
<>
|
||||||
|
<DropdownMenuSeparator className="first:hidden" />
|
||||||
|
<CopyMarkdown
|
||||||
|
isDefaultAction={!assistants.length}
|
||||||
|
markdownPageUrl={markdownPageUrl}
|
||||||
|
type="dropdown-menu-item"
|
||||||
|
/>
|
||||||
|
<ViewAsMarkdown markdownPageUrl={markdownPageUrl} type="dropdown-menu-item" />
|
||||||
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<CopyMarkdown
|
{actions.externalAI ? (
|
||||||
isDefaultAction={!withAIChat}
|
|
||||||
markdownPageUrl={markdownPageUrl}
|
|
||||||
type="dropdown-menu-item"
|
|
||||||
/>
|
|
||||||
<ViewAsMarkdown markdownPageUrl={markdownPageUrl} type="dropdown-menu-item" />
|
|
||||||
|
|
||||||
{withLLMActions ? (
|
|
||||||
<>
|
<>
|
||||||
|
<DropdownMenuSeparator className="first:hidden" />
|
||||||
<OpenInLLM provider="chatgpt" url={markdownPageUrl} type="dropdown-menu-item" />
|
<OpenInLLM provider="chatgpt" url={markdownPageUrl} type="dropdown-menu-item" />
|
||||||
<OpenInLLM provider="claude" url={markdownPageUrl} type="dropdown-menu-item" />
|
<OpenInLLM provider="claude" url={markdownPageUrl} type="dropdown-menu-item" />
|
||||||
</>
|
</>
|
||||||
@@ -88,17 +102,28 @@ function AIActionsDropdownMenuContent(props: AIActionsDropdownProps) {
|
|||||||
* A default action shown as a quick-access button beside the dropdown menu
|
* A default action shown as a quick-access button beside the dropdown menu
|
||||||
*/
|
*/
|
||||||
function DefaultAction(props: AIActionsDropdownProps) {
|
function DefaultAction(props: AIActionsDropdownProps) {
|
||||||
const { markdownPageUrl, withAIChat, trademark } = props;
|
const { markdownPageUrl, actions } = props;
|
||||||
|
const assistants = useAI().assistants.filter((assistant) => assistant.ui === true);
|
||||||
|
|
||||||
if (withAIChat) {
|
if (assistants.length) {
|
||||||
return <OpenDocsAssistant trademark={trademark} type="button" />;
|
return <OpenAIAssistant assistant={assistants[0]} type="button" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
if (actions.markdown) {
|
||||||
<CopyMarkdown
|
return (
|
||||||
isDefaultAction={!withAIChat}
|
<CopyMarkdown
|
||||||
markdownPageUrl={markdownPageUrl}
|
isDefaultAction={!assistants.length}
|
||||||
type="button"
|
markdownPageUrl={markdownPageUrl}
|
||||||
/>
|
type="button"
|
||||||
);
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actions.externalAI) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<OpenInLLM provider="chatgpt" url={markdownPageUrl} type="button" />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { t, tString, useLanguage } from '@/intl/client';
|
import { t, tString, useLanguage } from '@/intl/client';
|
||||||
|
import { tcls } from '@/lib/tailwind';
|
||||||
import { Icon } from '@gitbook/icons';
|
import { Icon } from '@gitbook/icons';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
@@ -9,7 +10,7 @@ import {
|
|||||||
type AIChatState,
|
type AIChatState,
|
||||||
useAIChatController,
|
useAIChatController,
|
||||||
useAIChatState,
|
useAIChatState,
|
||||||
} from '../AI/useAIChat';
|
} from '../AI';
|
||||||
import { useNow } from '../hooks';
|
import { useNow } from '../hooks';
|
||||||
import { Button } from '../primitives';
|
import { Button } from '../primitives';
|
||||||
import { DropdownMenu, DropdownMenuItem } from '../primitives/DropdownMenu';
|
import { DropdownMenu, DropdownMenuItem } from '../primitives/DropdownMenu';
|
||||||
@@ -24,12 +25,14 @@ export function AIChat(props: { trademark: boolean }) {
|
|||||||
const chatController = useAIChatController();
|
const chatController = useAIChatController();
|
||||||
|
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
'mod+j',
|
'mod+i',
|
||||||
(e) => {
|
(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
chatController.open();
|
chatController.open();
|
||||||
},
|
},
|
||||||
[]
|
{
|
||||||
|
enableOnFormTags: true,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
@@ -93,6 +96,15 @@ export function AIChatWindow(props: {
|
|||||||
block: 'start',
|
block: 'start',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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.
|
// 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.
|
// 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) => {
|
const observer = new ResizeObserver((entries) => {
|
||||||
@@ -103,16 +115,25 @@ export function AIChatWindow(props: {
|
|||||||
if (inputRef.current) {
|
if (inputRef.current) {
|
||||||
observer.observe(inputRef.current);
|
observer.observe(inputRef.current);
|
||||||
}
|
}
|
||||||
return () => observer.disconnect();
|
return () => {
|
||||||
}, [chat.opened]);
|
observer.disconnect();
|
||||||
|
clearTimeout(timeout);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
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-enterFromRight lg:pr-4 lg:pl-0 xl:w-96"
|
data-testid="ai-chat"
|
||||||
|
className={tcls(
|
||||||
|
'ai-chat sticky right-0 z-40 ml-8 flex max-w-3xl animate-present scroll-mt-36 px-4 py-4 transition-[width] duration-300 sm:px-6 lg:w-80 lg:animate-enter-from-right lg:px-0 xl:w-96',
|
||||||
|
'lg:[html[style*="--toc-top-offset"]_&]:top-(--toc-top-offset)!',
|
||||||
|
'lg:[html[style*="--toc-height"]_&]:h-(--toc-height)!',
|
||||||
|
'lg:-mr-[calc(max(0px,((100vw-96rem)/2)))]' // screen (100vw) - sidebar (18rem) - content (48rem) - chat window (20rem)
|
||||||
|
)}
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
>
|
>
|
||||||
<div className="relative flex h-full grow flex-col overflow-hidden circular-corners:rounded-3xl rounded-corners:rounded-md bg-tint-base text-sm text-tint depth-subtle:shadow-lg shadow-tint ring-1 ring-tint-subtle">
|
<div className="relative flex h-full grow flex-col overflow-hidden circular-corners:rounded-3xl rounded-corners:rounded-md bg-tint-base text-sm text-tint depth-subtle:shadow-lg shadow-tint ring-1 ring-tint-subtle">
|
||||||
<div className="flex items-center gap-2 border-tint-subtle border-b bg-tint-subtle px-4 py-2 text-tint-strong">
|
<div className="flex select-none items-center gap-2 border-tint-subtle border-b bg-tint-subtle px-4 py-2 text-tint-strong">
|
||||||
<AIChatIcon
|
<AIChatIcon
|
||||||
className="size-5 text-tint"
|
className="size-5 text-tint"
|
||||||
trademark={trademark}
|
trademark={trademark}
|
||||||
@@ -124,7 +145,9 @@ export function AIChatWindow(props: {
|
|||||||
? 'working'
|
? 'working'
|
||||||
: 'thinking'
|
: 'thinking'
|
||||||
: chat.messages.length > 0
|
: chat.messages.length > 0
|
||||||
? 'done'
|
? chat.pendingTools.length > 0
|
||||||
|
? 'confirm'
|
||||||
|
: 'done'
|
||||||
: 'default'
|
: 'default'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -149,8 +172,7 @@ export function AIChatWindow(props: {
|
|||||||
onClick={() => {}}
|
onClick={() => {}}
|
||||||
iconOnly
|
iconOnly
|
||||||
icon="ellipsis"
|
icon="ellipsis"
|
||||||
label={tString(language, 'more')}
|
label={tString(language, 'actions')}
|
||||||
className="!px-2"
|
|
||||||
variant="blank"
|
variant="blank"
|
||||||
size="default"
|
size="default"
|
||||||
/>
|
/>
|
||||||
@@ -162,7 +184,10 @@ export function AIChatWindow(props: {
|
|||||||
}}
|
}}
|
||||||
disabled={isEmpty}
|
disabled={isEmpty}
|
||||||
>
|
>
|
||||||
<Icon icon="broom-wide" className="size-3 text-tint-subtle" />
|
<Icon
|
||||||
|
icon="broom-wide"
|
||||||
|
className="size-3 shrink-0 text-tint-subtle"
|
||||||
|
/>
|
||||||
{t(language, 'ai_chat_clear_conversation')}
|
{t(language, 'ai_chat_clear_conversation')}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
@@ -171,7 +196,6 @@ export function AIChatWindow(props: {
|
|||||||
iconOnly
|
iconOnly
|
||||||
icon="close"
|
icon="close"
|
||||||
label={tString(language, 'close')}
|
label={tString(language, 'close')}
|
||||||
className="!px-2"
|
|
||||||
variant="blank"
|
variant="blank"
|
||||||
size="default"
|
size="default"
|
||||||
/>
|
/>
|
||||||
@@ -186,7 +210,7 @@ export function AIChatWindow(props: {
|
|||||||
>
|
>
|
||||||
{isEmpty ? (
|
{isEmpty ? (
|
||||||
<div className="flex min-h-full w-full shrink-0 flex-col items-center justify-center gap-6 py-4">
|
<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-[fadeIn_500ms_both] items-center justify-center rounded-full bg-tint-subtle">
|
<div className="flex size-32 animate-fade-in-slow items-center justify-center rounded-full bg-tint-subtle">
|
||||||
<AIChatIcon
|
<AIChatIcon
|
||||||
state="intro"
|
state="intro"
|
||||||
trademark={trademark}
|
trademark={trademark}
|
||||||
@@ -215,7 +239,7 @@ export function AIChatWindow(props: {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
className="absolute inset-x-0 bottom-0 mr-2 flex flex-col gap-4 bg-gradient-to-b from-transparent to-50% to-tint-base/9 p-4 pr-2"
|
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. */}
|
{/* Display an error banner when something went wrong. */}
|
||||||
{chat.error ? <AIChatError chatController={chatController} /> : null}
|
{chat.error ? <AIChatError chatController={chatController} /> : null}
|
||||||
@@ -241,7 +265,7 @@ function AIChatError(props: { chatController: AIChatController }) {
|
|||||||
const { chatController } = props;
|
const { chatController } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap justify-between gap-2 rounded-md bg-danger p-3 text-danger text-sm ring-1 ring-danger">
|
<div className="flex animate-scale-in flex-wrap justify-between gap-2 circular-corners:rounded-2xl rounded-corners:rounded-md bg-danger px-3 py-2 text-danger text-sm ring-1 ring-danger">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Icon icon="exclamation-triangle" className="size-3.5" />
|
<Icon icon="exclamation-triangle" className="size-3.5" />
|
||||||
<span className="flex items-center gap-1">{t(language, 'ai_chat_error')}</span>
|
<span className="flex items-center gap-1">{t(language, 'ai_chat_error')}</span>
|
||||||
@@ -255,7 +279,7 @@ function AIChatError(props: { chatController: AIChatController }) {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
chatController.clear();
|
chatController.clear();
|
||||||
}}
|
}}
|
||||||
className="!text-danger hover:bg-danger-5"
|
className="text-danger! hover:bg-danger-5"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,39 +1,38 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
import { useLanguage } from '@/intl/client';
|
||||||
|
import { t } from '@/intl/translate';
|
||||||
import { tcls } from '@/lib/tailwind';
|
import { tcls } from '@/lib/tailwind';
|
||||||
import { useAIChatController, useAIChatState } from '../AI/useAIChat';
|
import type { Assistant } from '../AI';
|
||||||
import { Button } from '../primitives';
|
import { Button } from '../primitives';
|
||||||
import { KeyboardShortcut } from '../primitives/KeyboardShortcut';
|
import { KeyboardShortcut } from '../primitives/KeyboardShortcut';
|
||||||
import { getAIChatName } from './AIChat';
|
|
||||||
import { AIChatIcon } from './AIChatIcon';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Button to open/close the AI chat.
|
* Button to open/close the AI chat.
|
||||||
*/
|
*/
|
||||||
export function AIChatButton(props: { trademark: boolean }) {
|
export function AIChatButton(props: {
|
||||||
const { trademark } = props;
|
assistant: Assistant;
|
||||||
const chatController = useAIChatController();
|
showLabel?: boolean;
|
||||||
const chat = useAIChatState();
|
}) {
|
||||||
|
const { assistant, showLabel = true } = props;
|
||||||
|
const language = useLanguage();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
icon={<AIChatIcon trademark={trademark} />}
|
icon={assistant.icon}
|
||||||
iconOnly
|
data-testid="ai-chat-button"
|
||||||
size="default"
|
iconOnly={!showLabel}
|
||||||
|
size="medium"
|
||||||
variant="header"
|
variant="header"
|
||||||
className={tcls('h-9 px-2.5')}
|
className={tcls('h-9 px-2.5')}
|
||||||
label={
|
label={
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{getAIChatName(trademark)}
|
{t(language, 'ai_chat_ask', assistant.label)}
|
||||||
<KeyboardShortcut keys={['mod', 'j']} className="border-tint-11 text-tint-1" />
|
<KeyboardShortcut keys={['mod', 'i']} className="border-tint-11 text-tint-1" />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
onClick={() => {
|
onClick={() => assistant.open()}
|
||||||
if (chat.opened) {
|
>
|
||||||
chatController.close();
|
{showLabel ? <span className="max-md:hidden">{t(language, 'ask')}</span> : null}
|
||||||
} else {
|
</Button>
|
||||||
chatController.open();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import type React from 'react';
|
|||||||
interface AIChatIconProps extends React.SVGProps<SVGSVGElement> {
|
interface AIChatIconProps extends React.SVGProps<SVGSVGElement> {
|
||||||
className?: string;
|
className?: string;
|
||||||
size?: number;
|
size?: number;
|
||||||
state?: 'default' | 'intro' | 'thinking' | 'working' | 'done' | 'error';
|
state?: 'default' | 'intro' | 'thinking' | 'working' | 'done' | 'error' | 'confirm';
|
||||||
trademark?: boolean;
|
trademark?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +38,7 @@ export const AIChatIcon = ({
|
|||||||
preserveAspectRatio="xMaxYMid meet"
|
preserveAspectRatio="xMaxYMid meet"
|
||||||
className={className}
|
className={className}
|
||||||
aria-busy={state === 'thinking'}
|
aria-busy={state === 'thinking'}
|
||||||
|
overflow="visible"
|
||||||
{...props}
|
{...props}
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@@ -54,8 +55,9 @@ export const AIChatIcon = ({
|
|||||||
state === 'intro' &&
|
state === 'intro' &&
|
||||||
'animate-[fadeIn_.5s_.7s_both,spin_2s_1s_forwards_cubic-bezier(.43,1.54,.64,1)]',
|
'animate-[fadeIn_.5s_.7s_both,spin_2s_1s_forwards_cubic-bezier(.43,1.54,.64,1)]',
|
||||||
(state === 'working' || state === 'thinking') &&
|
(state === 'working' || state === 'thinking') &&
|
||||||
'animate-[fadeIn_.5s_.3s_both,spin_2s_infinite_forwards_cubic-bezier(0.16,1,0.3,1)]',
|
'animate-[fadeIn_.5s_.3s_both,spin_2s_1s_infinite_forwards_cubic-bezier(0.16,1,0.3,1)]',
|
||||||
state === 'done' && 'animate-[fadeOut_.5s_both]',
|
state === 'done' && 'animate-[fadeOut_.5s_both]',
|
||||||
|
state === 'confirm' && 'animate-[fadeOut_.5s_both]',
|
||||||
state === 'default' && 'animate-[fadeIn_0s_both]',
|
state === 'default' && 'animate-[fadeIn_0s_both]',
|
||||||
state === 'error' && 'hidden'
|
state === 'error' && 'hidden'
|
||||||
)}
|
)}
|
||||||
@@ -95,10 +97,24 @@ export const AIChatIcon = ({
|
|||||||
state === 'done'
|
state === 'done'
|
||||||
? 'animate-[fadeIn_.5s_.3s_both]'
|
? 'animate-[fadeIn_.5s_.3s_both]'
|
||||||
: 'animate-[fadeOut_.5s_both]',
|
: 'animate-[fadeOut_.5s_both]',
|
||||||
state === 'intro' && 'hidden'
|
state === 'intro' && 'hidden',
|
||||||
|
state === 'confirm' && 'hidden'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Confirm */}
|
||||||
|
<path
|
||||||
|
className={tcls(
|
||||||
|
'fill-primary-9',
|
||||||
|
state === 'confirm'
|
||||||
|
? 'animate-[fadeIn_.5s_.3s_both,bounceSmall_1s_infinite_both]'
|
||||||
|
: state === 'thinking'
|
||||||
|
? 'animate-[fadeOut_.5s_both]'
|
||||||
|
: 'hidden'
|
||||||
|
)}
|
||||||
|
d="M12.9463 5.24512C13.3688 5.24422 13.713 5.58625 13.7139 6.00879C13.7146 6.43114 13.3725 6.77338 12.9502 6.77441C12.5279 6.77505 12.1845 6.43408 12.1836 6.01172C12.1828 5.58953 12.5242 5.24649 12.9463 5.24512ZM13.0391 0.0751953C14.0688 0.0730893 14.9049 0.90586 14.9072 1.93555C14.9084 2.5063 14.6484 3.04679 14.2012 3.40137L13.7773 3.7373C13.6151 3.86604 13.5201 4.06239 13.5205 4.26953V4.30371C13.5211 4.62139 13.2639 4.879 12.9463 4.87988C12.6288 4.88032 12.3701 4.62417 12.3691 4.30664V4.27246C12.3679 3.71272 12.6238 3.18263 13.0625 2.83496L13.4854 2.49902C13.6565 2.36341 13.7562 2.1568 13.7559 1.93848C13.755 1.54463 13.4358 1.22503 13.042 1.22559H12.9385C12.488 1.22679 12.1225 1.59352 12.123 2.04395L12.124 2.21875C12.1245 2.53649 11.8676 2.79522 11.5498 2.7959C11.2321 2.79653 10.9746 2.53928 10.9736 2.22168L10.9727 2.04688C10.9706 0.960578 11.8493 0.0778178 12.9355 0.0751953H13.0391Z"
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Background */}
|
{/* Background */}
|
||||||
<path
|
<path
|
||||||
d="M3.5625 8.78512L7.26347 10.9219C7.88227 11.2791 8.64467 11.2791 9.26347 10.9219L14.25 8.0429C14.5833 7.85045 15 8.09101 15 8.47591V10.2777C15 10.4563 14.9047 10.6214 14.75 10.7107L9.26347 13.8784C8.64467 14.2356 7.88228 14.2356 7.26347 13.8784L3.5625 11.7416C2.70833 11.2978 1 9.93199 1 8.01949M1 8.01949C1 6.6448 1.84765 5.98698 2.62903 5.71701C3.15426 5.53555 3.71577 5.70568 4.19701 5.98353L7.26347 7.75395C7.88228 8.11122 8.64467 8.11122 9.26347 7.75395L10.9095 6.80362M1 8.01949C1 6.4945 2.03973 5.30731 2.5596 4.90434L7.37937 2.12165C7.79013 1.88449 8.26417 1.80476 8.71747 1.88245"
|
d="M3.5625 8.78512L7.26347 10.9219C7.88227 11.2791 8.64467 11.2791 9.26347 10.9219L14.25 8.0429C14.5833 7.85045 15 8.09101 15 8.47591V10.2777C15 10.4563 14.9047 10.6214 14.75 10.7107L9.26347 13.8784C8.64467 14.2356 7.88228 14.2356 7.26347 13.8784L3.5625 11.7416C2.70833 11.2978 1 9.93199 1 8.01949M1 8.01949C1 6.6448 1.84765 5.98698 2.62903 5.71701C3.15426 5.53555 3.71577 5.70568 4.19701 5.98353L7.26347 7.75395C7.88228 8.11122 8.64467 8.11122 9.26347 7.75395L10.9095 6.80362M1 8.01949C1 6.4945 2.03973 5.30731 2.5596 4.90434L7.37937 2.12165C7.79013 1.88449 8.26417 1.80476 8.71747 1.88245"
|
||||||
|
|||||||
@@ -38,33 +38,36 @@ export function AIChatInput(props: {
|
|||||||
// This fixes inconsistent focus behaviour across browsers
|
// This fixes inconsistent focus behaviour across browsers
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
}, 50);
|
}, 150);
|
||||||
|
|
||||||
return () => clearTimeout(timeout);
|
return () => clearTimeout(timeout);
|
||||||
}
|
}
|
||||||
}, [disabled, loading]);
|
}, [disabled, loading]);
|
||||||
|
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
'mod+j',
|
'mod+i',
|
||||||
(e) => {
|
(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
},
|
},
|
||||||
[]
|
{
|
||||||
|
enableOnFormTags: true,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative flex flex-col overflow-hidden circular-corners:rounded-2xl rounded-corners:rounded-md bg-tint-base/9 ring-1 ring-tint-subtle backdrop-blur-lg transition-all depth-subtle:has-[textarea:focus]:shadow-lg has-[textarea:focus]:ring-2 has-[textarea:focus]:ring-primary-hover contrast-more:bg-tint-base">
|
<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
|
<textarea
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
disabled={disabled || loading}
|
disabled={disabled || loading}
|
||||||
data-loading={loading}
|
data-loading={loading}
|
||||||
|
data-testid="ai-chat-input"
|
||||||
className={tcls(
|
className={tcls(
|
||||||
'resize-none',
|
'resize-none',
|
||||||
'focus:outline-none',
|
'focus:outline-hidden',
|
||||||
'focus:ring-0',
|
'focus:ring-0',
|
||||||
'w-full',
|
'w-full',
|
||||||
'px-4',
|
'px-3',
|
||||||
'py-3',
|
'py-3',
|
||||||
'pb-12',
|
'pb-12',
|
||||||
'h-auto',
|
'h-auto',
|
||||||
@@ -98,10 +101,12 @@ export function AIChatInput(props: {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="absolute top-2.5 right-4 animate-[fadeIn_0.2s_0.5s_ease-in-out_both] peer-focus:hidden">
|
{!disabled ? (
|
||||||
<KeyboardShortcut keys={['mod', 'j']} />
|
<div className="absolute top-2.5 right-3 animate-[fadeIn_0.2s_0.5s_ease-in-out_both] peer-focus:hidden">
|
||||||
</div>
|
<KeyboardShortcut keys={['mod', 'i']} className="bg-tint-base" />
|
||||||
<div className="absolute inset-x-0 bottom-0 flex items-center px-2 py-2">
|
</div>
|
||||||
|
) : null}
|
||||||
|
<div className="absolute inset-x-0 bottom-0 flex items-center gap-2 px-2 py-2">
|
||||||
<Tooltip
|
<Tooltip
|
||||||
label={
|
label={
|
||||||
<div className="flex flex-col gap-3 p-2">
|
<div className="flex flex-col gap-3 p-2">
|
||||||
@@ -125,11 +130,11 @@ export function AIChatInput(props: {
|
|||||||
}
|
}
|
||||||
arrow
|
arrow
|
||||||
>
|
>
|
||||||
<div className="flex cursor-help items-center gap-1 circular-corners:rounded-2xl rounded-corners:rounded-md px-2 py-1 text-tint/7 text-xs transition-all hover:bg-tint">
|
<div className="flex cursor-help items-center gap-1 circular-corners:rounded-2xl rounded-corners:rounded-md px-2.5 py-1.5 text-tint/7 text-xs transition-all hover:bg-tint">
|
||||||
<span className="-ml-1 rounded-corners:rounded circular-corners:rounded-2xl bg-tint-11/7 px-1 py-0.5 font-mono font-semibold text-[0.65rem] text-contrast-tint-11 leading-none">
|
<span className="-ml-1 circular-corners:rounded-2xl rounded-corners:rounded-sm bg-tint-11/7 px-1 py-0.5 font-mono font-semibold text-[0.65rem] text-contrast-tint-11 leading-none">
|
||||||
{t(language, 'ai_chat_context_badge')}
|
{t(language, 'ai_chat_context_badge')}
|
||||||
</span>{' '}
|
</span>{' '}
|
||||||
<span>{t(language, 'ai_chat_context_title')}</span>
|
<span className="leading-none">{t(language, 'ai_chat_context_title')}</span>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { tcls } from '@/lib/tailwind';
|
import { tcls } from '@/lib/tailwind';
|
||||||
import { AIMessageRole } from '@gitbook/api';
|
import { AIMessageRole } from '@gitbook/api';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import type { AIChatController, AIChatState } from '../AI/useAIChat';
|
import type { AIChatController, AIChatState } from '../AI';
|
||||||
|
import { AIChatToolConfirmations } from './AIChatToolConfirmations';
|
||||||
|
import { AIResponseFeedback } from './AIResponseFeedback';
|
||||||
import { AIChatFollowupSuggestions } from './AiChatFollowupSuggestions';
|
import { AIChatFollowupSuggestions } from './AiChatFollowupSuggestions';
|
||||||
|
|
||||||
export function AIChatMessages(props: {
|
export function AIChatMessages(props: {
|
||||||
@@ -22,30 +24,32 @@ export function AIChatMessages(props: {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={isLastUserMessage ? lastUserMessageRef : undefined}
|
ref={isLastUserMessage ? lastUserMessageRef : undefined}
|
||||||
|
data-testid="ai-chat-message"
|
||||||
className={tcls(
|
className={tcls(
|
||||||
message.content ? 'animate-[fadeIn_500ms_both]' : '',
|
message.content ? 'animate-fade-in-slow' : '',
|
||||||
'shrink-0',
|
'shrink-0',
|
||||||
'last:min-h-[calc(100%-5rem)]',
|
'last:min-h-[calc(100%-5rem)]',
|
||||||
'scroll-mt-36',
|
'scroll-mt-36',
|
||||||
'lg:scroll-mt-0',
|
'lg:scroll-mt-0',
|
||||||
'flex flex-col gap-6',
|
'flex flex-col gap-6',
|
||||||
|
'group/message',
|
||||||
message.role === AIMessageRole.User
|
message.role === AIMessageRole.User
|
||||||
? 'max-w-[80%] self-end circular-corners:rounded-2xl rounded-corners:rounded-md bg-tint px-4 py-2'
|
? 'max-w-[80%] self-end circular-corners:rounded-2xl rounded-corners:rounded-md bg-tint px-4 py-2'
|
||||||
: ''
|
: 'text-tint-strong'
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
animationDelay: `${Math.min(index * 0.05, 0.5)}s`,
|
animationDelay: `${Math.min(index * 0.05, 0.5)}s`,
|
||||||
}}
|
}}
|
||||||
key={index}
|
key={index}
|
||||||
>
|
>
|
||||||
{message.content ? (
|
{message.content ? message.content : null}
|
||||||
message.content
|
|
||||||
) : chat.loading ? (
|
{isLastMessage && chat.loading ? (
|
||||||
<div className="flex w-full animate-[fadeIn_500ms_both] flex-wrap gap-2">
|
<div className="flex w-full animate-fade-in-slow flex-wrap gap-2">
|
||||||
{Array.from({ length: 7 }).map((_, index) => (
|
{Array.from({ length: 7 }).map((_, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="h-4 animate-[fadeIn_0.5s_ease_both,pulse_1.5s_infinite] rounded-md bg-tint-4"
|
className="h-4 animate-[fadeIn_500ms_ease_both,pulse_1.5s_infinite] circular-corners:rounded-2xl rounded-corners:rounded-md bg-tint-4"
|
||||||
style={{
|
style={{
|
||||||
width: `calc(${(index % 4) * 20 + 10}% - 4px)`,
|
width: `calc(${(index % 4) * 20 + 10}% - 4px)`,
|
||||||
animationDelay: `${index * 0.1}s`,
|
animationDelay: `${index * 0.1}s`,
|
||||||
@@ -54,11 +58,26 @@ export function AIChatMessages(props: {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{isLastMessage ? (
|
{isLastMessage ? (
|
||||||
<AIChatFollowupSuggestions
|
<>
|
||||||
chat={chat}
|
{!chat.loading &&
|
||||||
chatController={chatController}
|
!chat.error &&
|
||||||
/>
|
chat.query &&
|
||||||
|
chat.responseId &&
|
||||||
|
chat.pendingTools.length === 0 ? (
|
||||||
|
<AIResponseFeedback
|
||||||
|
responseId={chat.responseId}
|
||||||
|
query={chat.query}
|
||||||
|
className="-ml-1 -mt-4"
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
<AIChatToolConfirmations chat={chat} />
|
||||||
|
<AIChatFollowupSuggestions
|
||||||
|
chat={chat}
|
||||||
|
chatController={chatController}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { tString, useLanguage } from '@/intl/client';
|
import { tString, useLanguage } from '@/intl/client';
|
||||||
import type { AIChatController } from '../AI/useAIChat';
|
import type { AIChatController } from '../AI';
|
||||||
import { Button } from '../primitives';
|
import { Button } from '../primitives';
|
||||||
|
|
||||||
export default function AIChatSuggestedQuestions(props: { chatController: AIChatController }) {
|
export default function AIChatSuggestedQuestions(props: { chatController: AIChatController }) {
|
||||||
@@ -17,7 +17,6 @@ export default function AIChatSuggestedQuestions(props: { chatController: AIChat
|
|||||||
{DEFAULT_SUGGESTED_QUESTIONS.map((question, index) => (
|
{DEFAULT_SUGGESTED_QUESTIONS.map((question, index) => (
|
||||||
<Button
|
<Button
|
||||||
key={question}
|
key={question}
|
||||||
label={question}
|
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
size="medium"
|
size="medium"
|
||||||
className="max-w-full animate-[present_500ms_both] whitespace-normal"
|
className="max-w-full animate-[present_500ms_both] whitespace-normal"
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
'use client';
|
||||||
|
import { useLanguage } from '@/intl/client';
|
||||||
|
import { t } from '@/intl/translate';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
|
import type { AIChatState } from '../AI';
|
||||||
|
import { Button } from '../primitives';
|
||||||
|
import { KeyboardShortcut } from '../primitives/KeyboardShortcut';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display buttons to confirm tool calls.
|
||||||
|
*/
|
||||||
|
export function AIChatToolConfirmations(props: {
|
||||||
|
chat: AIChatState;
|
||||||
|
}) {
|
||||||
|
const { chat } = props;
|
||||||
|
|
||||||
|
const language = useLanguage();
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
'mod+enter',
|
||||||
|
(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
chat.pendingTools[0]?.confirm();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enableOnFormTags: true,
|
||||||
|
},
|
||||||
|
[chat.pendingTools]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex w-full flex-wrap justify-end gap-2">
|
||||||
|
{chat.pendingTools.map((tool, index) => (
|
||||||
|
<div
|
||||||
|
className="flex w-full animate-present-slow flex-col gap-1"
|
||||||
|
key={index}
|
||||||
|
style={{ animationDelay: `${0.5 + index * 0.1}s` }}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
tool.confirm();
|
||||||
|
}}
|
||||||
|
tabIndex={index}
|
||||||
|
label={tool.label}
|
||||||
|
className="w-full justify-center"
|
||||||
|
size={index === 0 ? 'default' : 'medium'}
|
||||||
|
variant={index === 0 ? 'primary' : 'secondary'}
|
||||||
|
icon={tool.icon}
|
||||||
|
/>
|
||||||
|
{index === 0 && (
|
||||||
|
<div
|
||||||
|
className="flex pointer-none:hidden w-full animate-fade-in-slow items-center justify-end gap-2 text-tint text-xs"
|
||||||
|
style={{ animationDelay: '1000ms' }}
|
||||||
|
>
|
||||||
|
{t(
|
||||||
|
language,
|
||||||
|
'press_to_confirm',
|
||||||
|
<KeyboardShortcut
|
||||||
|
keys={['mod', 'enter']}
|
||||||
|
className="mx-0 text-tint"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useLanguage } from '@/intl/client';
|
||||||
|
import { t, tString } from '@/intl/translate';
|
||||||
|
import { type ClassValue, tcls } from '@/lib/tailwind';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useTrackEvent } from '../Insights';
|
||||||
|
import { Button } from '../primitives';
|
||||||
|
|
||||||
|
export function AIResponseFeedback(props: {
|
||||||
|
className?: ClassValue;
|
||||||
|
responseId: string;
|
||||||
|
query: string;
|
||||||
|
}) {
|
||||||
|
const { className, responseId, query } = props;
|
||||||
|
|
||||||
|
const language = useLanguage();
|
||||||
|
const [rating, setRating] = useState<1 | -1 | null>(null);
|
||||||
|
const trackEvent = useTrackEvent();
|
||||||
|
|
||||||
|
const handleRating = (rating: 1 | -1) => {
|
||||||
|
setRating(rating);
|
||||||
|
trackEvent({ type: 'ask_rate_response', query, responseId, rating });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={tcls('flex h-fit items-center', className)}>
|
||||||
|
<Button
|
||||||
|
icon="thumbs-up"
|
||||||
|
iconOnly
|
||||||
|
label={tString(language, 'was_this_helpful_positive_label')}
|
||||||
|
variant="blank"
|
||||||
|
className={tcls(
|
||||||
|
'animate-fade-in overflow-hidden text-tint-subtle transition-all',
|
||||||
|
rating !== null && rating !== 1 && 'px-0 text-[0rem] opacity-0'
|
||||||
|
)}
|
||||||
|
size="medium"
|
||||||
|
style={{ animationDuration: '.5s' }}
|
||||||
|
onClick={() => handleRating(1)}
|
||||||
|
disabled={rating !== null}
|
||||||
|
active={rating === 1}
|
||||||
|
key="positive"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon="thumbs-down"
|
||||||
|
iconOnly
|
||||||
|
label={tString(language, 'was_this_helpful_negative_label')}
|
||||||
|
variant="blank"
|
||||||
|
className={tcls(
|
||||||
|
'animate-fade-in overflow-hidden text-tint-subtle transition-all',
|
||||||
|
rating !== null && rating !== -1 && 'px-0 text-[0rem] opacity-0'
|
||||||
|
)}
|
||||||
|
size="medium"
|
||||||
|
style={{ animationDelay: '.2s', animationDuration: '.5s' }}
|
||||||
|
onClick={() => handleRating(-1)}
|
||||||
|
disabled={rating !== null}
|
||||||
|
active={rating === -1}
|
||||||
|
key="negative"
|
||||||
|
/>
|
||||||
|
{rating !== null ? (
|
||||||
|
<span
|
||||||
|
className="ml-2 animate-fade-in-slow text-tint-subtle"
|
||||||
|
style={{ animationDelay: '.3s' }}
|
||||||
|
>
|
||||||
|
{t(language, 'was_this_helpful_thank_you')}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ export function AIChatFollowupSuggestions(props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-auto flex flex-row flex-wrap justify-end gap-2">
|
<div className="mt-auto flex w-full flex-wrap justify-end gap-2">
|
||||||
{chat.followUpSuggestions.map((suggestion, index) => (
|
{chat.followUpSuggestions.map((suggestion, index) => (
|
||||||
<Button
|
<Button
|
||||||
key={index}
|
key={index}
|
||||||
@@ -23,7 +23,7 @@ export function AIChatFollowupSuggestions(props: {
|
|||||||
chatController.postMessage({ message: suggestion });
|
chatController.postMessage({ message: suggestion });
|
||||||
}}
|
}}
|
||||||
label={suggestion}
|
label={suggestion}
|
||||||
className="max-w-[80%] animate-[present_500ms_both] whitespace-normal text-left ring-1 ring-tint-subtle"
|
className="whitespace-normal! max-w-full animate-[present_500ms_both] text-left ring-1 ring-tint-subtle"
|
||||||
size="medium"
|
size="medium"
|
||||||
variant="blank"
|
variant="blank"
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from './AIChat';
|
export * from './AIChat';
|
||||||
export * from './AIChatButton';
|
export * from './AIChatButton';
|
||||||
export * from './AIChatIcon';
|
export * from './AIChatIcon';
|
||||||
|
export * from './AIResponseFeedback';
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export async function AdCoverRendering({
|
|||||||
'rounded-lg',
|
'rounded-lg',
|
||||||
'p-4',
|
'p-4',
|
||||||
'overflow-hidden',
|
'overflow-hidden',
|
||||||
'shadow-sm'
|
'shadow-xs'
|
||||||
)}
|
)}
|
||||||
style={{ backgroundColor: ad.backgroundColor, color: ad.textColor ?? '#ffffff' }}
|
style={{ backgroundColor: ad.backgroundColor, color: ad.textColor ?? '#ffffff' }}
|
||||||
href={ad.statlink}
|
href={ad.statlink}
|
||||||
@@ -68,7 +68,7 @@ export async function AdCoverRendering({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={tcls('z-[2]')}>
|
<div className={tcls('z-2')}>
|
||||||
<img
|
<img
|
||||||
alt="Large cover"
|
alt="Large cover"
|
||||||
src={largeImage}
|
src={largeImage}
|
||||||
@@ -81,10 +81,10 @@ export async function AdCoverRendering({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={tcls('z-[2]')}>
|
<div className={tcls('z-2')}>
|
||||||
<img alt={ad.company} src={ad.logo} className={tcls('max-w-36', 'max-h-12')} />
|
<img alt={ad.company} src={ad.logo} className={tcls('max-w-36', 'max-h-12')} />
|
||||||
</div>
|
</div>
|
||||||
<div className={tcls('flex', 'flex-col', 'z-[2]')}>
|
<div className={tcls('flex', 'flex-col', 'z-2')}>
|
||||||
<div className={tcls('text-sm', 'font-semibold', 'mb-2')}>{ad.companyTagline}</div>
|
<div className={tcls('text-sm', 'font-semibold', 'mb-2')}>{ad.companyTagline}</div>
|
||||||
<div
|
<div
|
||||||
className={tcls(
|
className={tcls(
|
||||||
@@ -99,7 +99,7 @@ export async function AdCoverRendering({
|
|||||||
{ad.description}
|
{ad.description}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={tcls('z-[2]')}>
|
<div className={tcls('z-2')}>
|
||||||
<span
|
<span
|
||||||
className={tcls(
|
className={tcls(
|
||||||
'text-sm',
|
'text-sm',
|
||||||
@@ -119,7 +119,7 @@ export async function AdCoverRendering({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={tcls('absolute', 'inset-0', 'backdrop-blur', 'z-[1]')}
|
className={tcls('absolute', 'inset-0', 'backdrop-blur-sm', 'z-1')}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: hexToRgba(ad.backgroundColor, 0.8),
|
backgroundColor: hexToRgba(ad.backgroundColor, 0.8),
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type { SiteInsightsAd, SiteInsightsAdPlacement } from '@gitbook/api';
|
|||||||
import { headers } from 'next/headers';
|
import { headers } from 'next/headers';
|
||||||
|
|
||||||
import { getServerActionBaseContext } from '@/lib/server-actions';
|
import { getServerActionBaseContext } from '@/lib/server-actions';
|
||||||
|
import { traceErrorOnly } from '@/lib/tracing';
|
||||||
import { AdClassicRendering } from './AdClassicRendering';
|
import { AdClassicRendering } from './AdClassicRendering';
|
||||||
import { AdCoverRendering } from './AdCoverRendering';
|
import { AdCoverRendering } from './AdCoverRendering';
|
||||||
import { AdPixels } from './AdPixels';
|
import { AdPixels } from './AdPixels';
|
||||||
@@ -40,40 +41,42 @@ interface FetchPlaceholderAdOptions {
|
|||||||
* and properly access user-agent and IP.
|
* and properly access user-agent and IP.
|
||||||
*/
|
*/
|
||||||
export async function renderAd(options: FetchAdOptions) {
|
export async function renderAd(options: FetchAdOptions) {
|
||||||
const [context, result] = await Promise.all([
|
return traceErrorOnly('Ads.renderAd', async () => {
|
||||||
getServerActionBaseContext(),
|
const [context, result] = await Promise.all([
|
||||||
options.source === 'live' ? fetchAd(options) : getPlaceholderAd(),
|
getServerActionBaseContext(),
|
||||||
]);
|
options.source === 'live' ? fetchAd(options) : getPlaceholderAd(),
|
||||||
|
]);
|
||||||
|
|
||||||
const mode = options.source === 'live' ? options.mode : 'classic';
|
const mode = options.source === 'live' ? options.mode : 'classic';
|
||||||
if (!result || !result.ad.description || !result.ad.statlink) {
|
if (!result || !result.ad.description || !result.ad.statlink) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { ad } = result;
|
const { ad } = result;
|
||||||
|
|
||||||
const insightsAd: SiteInsightsAd | null =
|
const insightsAd: SiteInsightsAd | null =
|
||||||
options.source === 'live'
|
options.source === 'live'
|
||||||
? {
|
? {
|
||||||
placement: options.placement,
|
placement: options.placement,
|
||||||
zoneId: options.zoneId,
|
zoneId: options.zoneId,
|
||||||
domain: 'company' in ad ? ad.company : '',
|
domain: 'company' in ad ? ad.company : '',
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
children: (
|
children: (
|
||||||
<>
|
<>
|
||||||
{mode === 'classic' || !('callToAction' in ad) ? (
|
{mode === 'classic' || !('callToAction' in ad) ? (
|
||||||
<AdClassicRendering ad={ad} insightsAd={insightsAd} context={context} />
|
<AdClassicRendering ad={ad} insightsAd={insightsAd} context={context} />
|
||||||
) : (
|
) : (
|
||||||
<AdCoverRendering ad={ad} insightsAd={insightsAd} context={context} />
|
<AdCoverRendering ad={ad} insightsAd={insightsAd} context={context} />
|
||||||
)}
|
)}
|
||||||
{ad.pixel ? <AdPixels rawPixel={ad.pixel} /> : null}
|
{ad.pixel ? <AdPixels rawPixel={ad.pixel} /> : null}
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
insightsAd,
|
insightsAd,
|
||||||
};
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchAd({
|
async function fetchAd({
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { tcls } from '@/lib/tailwind';
|
|||||||
import { type CustomizationAnnouncement, SiteInsightsLinkPosition } from '@gitbook/api';
|
import { type CustomizationAnnouncement, SiteInsightsLinkPosition } from '@gitbook/api';
|
||||||
import { Icon, type IconName } from '@gitbook/icons';
|
import { Icon, type IconName } from '@gitbook/icons';
|
||||||
import { CONTAINER_STYLE } from '../layout';
|
import { CONTAINER_STYLE } from '../layout';
|
||||||
import { Link } from '../primitives';
|
import { Button, Link } from '../primitives';
|
||||||
import { LinkStyles } from '../primitives/styles';
|
import { LinkStyles } from '../primitives/styles';
|
||||||
import { ANNOUNCEMENT_CSS_CLASS, ANNOUNCEMENT_STORAGE_KEY } from './constants';
|
import { ANNOUNCEMENT_CSS_CLASS, ANNOUNCEMENT_STORAGE_KEY } from './constants';
|
||||||
|
|
||||||
@@ -29,9 +29,13 @@ export function AnnouncementBanner(props: {
|
|||||||
const style = BANNER_STYLES[announcement.style];
|
const style = BANNER_STYLES[announcement.style];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="announcement-banner" className="theme-bold:bg-header-background pt-4 pb-2">
|
<div
|
||||||
|
id="announcement-banner"
|
||||||
|
className="theme-bold:bg-header-background pt-4 pb-2"
|
||||||
|
data-nosnippet=""
|
||||||
|
>
|
||||||
<div className="scroll-nojump">
|
<div className="scroll-nojump">
|
||||||
<div className="transition-all duration-300 lg:chat-open:pr-80 xl:chat-open:pr-96">
|
<div className="transition-all duration-300">
|
||||||
<div className={tcls('relative', CONTAINER_STYLE)}>
|
<div className={tcls('relative', CONTAINER_STYLE)}>
|
||||||
<Tag
|
<Tag
|
||||||
href={contentRef?.href ?? ''}
|
href={contentRef?.href ?? ''}
|
||||||
@@ -82,14 +86,15 @@ export function AnnouncementBanner(props: {
|
|||||||
</div>
|
</div>
|
||||||
</Tag>
|
</Tag>
|
||||||
{closeable ? (
|
{closeable ? (
|
||||||
<button
|
<Button
|
||||||
className={`absolute top-0 right-4 mt-2 mr-2 rounded circular-corners:rounded-lg straight-corners:rounded-none p-1.5 transition-all hover:ring-1 sm:right-6 md:right-8 ${style.close}`}
|
iconOnly
|
||||||
type="button"
|
icon="close"
|
||||||
|
label={tString(language, 'close')}
|
||||||
|
variant="blank"
|
||||||
|
size="default"
|
||||||
onClick={dismissAnnouncement}
|
onClick={dismissAnnouncement}
|
||||||
title={tString(language, 'close')}
|
className={`absolute top-0 right-4 mt-2 mr-2 circular-corners:rounded-lg rounded-sm straight-corners:rounded-none p-1.5 transition-all hover:ring-1 sm:right-6 md:right-8 ${style.close}`}
|
||||||
>
|
/>
|
||||||
<Icon icon="close" className="size-4" />
|
|
||||||
</button>
|
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -126,7 +131,7 @@ const BANNER_STYLES = {
|
|||||||
icon: 'circle-exclamation',
|
icon: 'circle-exclamation',
|
||||||
iconColor: 'text-warning-subtle',
|
iconColor: 'text-warning-subtle',
|
||||||
close: 'hover:bg-tint-base hover:ring-warning-subtle',
|
close: 'hover:bg-tint-base hover:ring-warning-subtle',
|
||||||
link: 'links-default:text-warning links-default:hover:text-warning-strong links-default:decoration-warning/6 links-accent:decoration-warning',
|
link: 'links-default:text-warning hover:links-default:text-warning-strong links-default:decoration-warning/6 links-accent:decoration-warning',
|
||||||
},
|
},
|
||||||
danger: {
|
danger: {
|
||||||
container: 'bg-danger decoration-danger/6 ring-danger-subtle',
|
container: 'bg-danger decoration-danger/6 ring-danger-subtle',
|
||||||
@@ -134,7 +139,7 @@ const BANNER_STYLES = {
|
|||||||
icon: 'triangle-exclamation',
|
icon: 'triangle-exclamation',
|
||||||
iconColor: 'text-danger-subtle',
|
iconColor: 'text-danger-subtle',
|
||||||
close: 'hover:bg-tint-base hover:ring-danger-subtle',
|
close: 'hover:bg-tint-base hover:ring-danger-subtle',
|
||||||
link: 'links-default:text-danger links-default:hover:text-danger-strong links-default:decoration-danger/6 links-accent:decoration-danger',
|
link: 'links-default:text-danger hover:links-default:text-danger-strong links-default:decoration-danger/6 links-accent:decoration-danger',
|
||||||
},
|
},
|
||||||
success: {
|
success: {
|
||||||
container: 'bg-success decoration-success/6 ring-success-subtle',
|
container: 'bg-success decoration-success/6 ring-success-subtle',
|
||||||
@@ -142,6 +147,6 @@ const BANNER_STYLES = {
|
|||||||
icon: 'circle-check',
|
icon: 'circle-check',
|
||||||
iconColor: 'text-success-subtle',
|
iconColor: 'text-success-subtle',
|
||||||
close: 'hover:bg-tint-base hover:ring-success-subtle',
|
close: 'hover:bg-tint-base hover:ring-success-subtle',
|
||||||
link: 'links-default:text-success links-default:hover:text-success-strong links-default:decoration-success/6 links-accent:decoration-success',
|
link: 'links-default:text-success hover:links-default:text-success-strong links-default:decoration-success/6 links-accent:decoration-success',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { getDataOrNull } from '@/lib/data';
|
import { getDataOrNull } from '@/lib/data';
|
||||||
import { getServerActionBaseContext } from '@/lib/server-actions';
|
import { getServerActionBaseContext } from '@/lib/server-actions';
|
||||||
|
import { traceErrorOnly } from '@/lib/tracing';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if a change-request has been updated.
|
* Return true if a change-request has been updated.
|
||||||
@@ -11,15 +12,17 @@ export async function hasContentBeenUpdated(props: {
|
|||||||
changeRequestId: string;
|
changeRequestId: string;
|
||||||
revisionId: string;
|
revisionId: string;
|
||||||
}) {
|
}) {
|
||||||
const context = await getServerActionBaseContext();
|
return traceErrorOnly('AutoRefreshContent.hasContentBeenUpdated', async () => {
|
||||||
const changeRequest = await getDataOrNull(
|
const context = await getServerActionBaseContext();
|
||||||
context.dataFetcher.getChangeRequest({
|
const changeRequest = await getDataOrNull(
|
||||||
spaceId: props.spaceId,
|
context.dataFetcher.getChangeRequest({
|
||||||
changeRequestId: props.changeRequestId,
|
spaceId: props.spaceId,
|
||||||
})
|
changeRequestId: props.changeRequestId,
|
||||||
);
|
})
|
||||||
if (!changeRequest) {
|
);
|
||||||
return false;
|
if (!changeRequest) {
|
||||||
}
|
return false;
|
||||||
return changeRequest.revision !== props.revisionId;
|
}
|
||||||
|
return changeRequest.revision !== props.revisionId;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { Icon } from '@gitbook/icons';
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { Button, StyledLink } from '@/components/primitives';
|
import { Button, StyledLink } from '@/components/primitives';
|
||||||
@@ -45,7 +43,7 @@ export function CookiesToast(props: { privacyPolicy?: string }) {
|
|||||||
'fixed',
|
'fixed',
|
||||||
'z-10',
|
'z-10',
|
||||||
'bg-tint-base',
|
'bg-tint-base',
|
||||||
'rounded',
|
'rounded-sm',
|
||||||
'straight-corners:rounded-none',
|
'straight-corners:rounded-none',
|
||||||
'circular-corners:rounded-2xl',
|
'circular-corners:rounded-2xl',
|
||||||
'ring-1',
|
'ring-1',
|
||||||
@@ -61,7 +59,7 @@ export function CookiesToast(props: { privacyPolicy?: string }) {
|
|||||||
'text-balance',
|
'text-balance',
|
||||||
'sm:left-auto',
|
'sm:left-auto',
|
||||||
'lg:chat-open:mr-80',
|
'lg:chat-open:mr-80',
|
||||||
'xl:chat-open:mr-[25rem]',
|
'xl:chat-open:mr-100',
|
||||||
'transition-all',
|
'transition-all',
|
||||||
'duration-300'
|
'duration-300'
|
||||||
)}
|
)}
|
||||||
@@ -75,27 +73,14 @@ export function CookiesToast(props: { privacyPolicy?: string }) {
|
|||||||
</StyledLink>
|
</StyledLink>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
<button
|
<Button
|
||||||
type="button"
|
iconOnly
|
||||||
|
icon="close"
|
||||||
|
label={tString(language, 'close')}
|
||||||
|
variant="blank"
|
||||||
onClick={() => setShow(false)}
|
onClick={() => setShow(false)}
|
||||||
aria-label={tString(language, 'close')}
|
className={tcls('absolute', 'top-2', 'right-2', 'hover:bg-tint-hover')}
|
||||||
className={tcls(
|
/>
|
||||||
'absolute',
|
|
||||||
'top-3',
|
|
||||||
'right-3',
|
|
||||||
'w-6',
|
|
||||||
'h-6',
|
|
||||||
'flex',
|
|
||||||
'justify-center',
|
|
||||||
'items-center',
|
|
||||||
'rounded-sm',
|
|
||||||
'circular-corners:rounded-full',
|
|
||||||
'hover:bg-tint-hover'
|
|
||||||
)}
|
|
||||||
title={tString(language, 'close')}
|
|
||||||
>
|
|
||||||
<Icon icon="xmark" className={tcls('size-4')} />
|
|
||||||
</button>
|
|
||||||
<div className={tcls('mt-3', 'flex', 'flex-row', 'gap-2')}>
|
<div className={tcls('mt-3', 'flex', 'flex-row', 'gap-2')}>
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export function AnnotationPopover(props: { children: React.ReactNode; body: Reac
|
|||||||
'bg-tint',
|
'bg-tint',
|
||||||
'ring-1',
|
'ring-1',
|
||||||
'ring-tint',
|
'ring-tint',
|
||||||
'rounded',
|
'rounded-sm',
|
||||||
'shadow-1xs',
|
'shadow-1xs',
|
||||||
'shadow-tint-12/1',
|
'shadow-tint-12/1',
|
||||||
'dark:shadow-tint-1/2',
|
'dark:shadow-tint-1/2',
|
||||||
@@ -53,7 +53,7 @@ export function AnnotationPopover(props: { children: React.ReactNode; body: Reac
|
|||||||
viewBox="0 0 8 5"
|
viewBox="0 0 8 5"
|
||||||
className={tcls(
|
className={tcls(
|
||||||
'relative',
|
'relative',
|
||||||
'z-[2]',
|
'z-2',
|
||||||
'fill-tint-3', // Same as bg-tint
|
'fill-tint-3', // Same as bg-tint
|
||||||
'stroke-tint-7', // Same as ring-tint
|
'stroke-tint-7', // Same as ring-tint
|
||||||
'[paint-order:stroke_fill]'
|
'[paint-order:stroke_fill]'
|
||||||
|
|||||||
@@ -47,6 +47,23 @@ type UnwrappedBlocksProps<TBlock extends DocumentBlock> = DocumentContextProps &
|
|||||||
isOffscreen?: boolean;
|
isOffscreen?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Blocks that can be full width are automatically expanded on full-width pages.
|
||||||
|
* Ideally we'd rely on the block type to determine if it can be full width, but
|
||||||
|
* the block's `fullWidth` property does not differentiate between `undefined` and `false`.
|
||||||
|
* So instead we hardcode a list of blocks that can be full width. */
|
||||||
|
const FULL_WIDTH_BLOCKS = [
|
||||||
|
'table',
|
||||||
|
'tabs',
|
||||||
|
'integration',
|
||||||
|
'openapi',
|
||||||
|
'images',
|
||||||
|
'embed',
|
||||||
|
'columns',
|
||||||
|
'code',
|
||||||
|
'content-ref',
|
||||||
|
'hint',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a list of blocks without a wrapper element.
|
* Renders a list of blocks without a wrapper element.
|
||||||
*/
|
*/
|
||||||
@@ -68,10 +85,11 @@ export function UnwrappedBlocks<TBlock extends DocumentBlock>(props: UnwrappedBl
|
|||||||
key={node.key || `${node.type}-${index}`}
|
key={node.key || `${node.type}-${index}`}
|
||||||
block={node}
|
block={node}
|
||||||
style={[
|
style={[
|
||||||
'mx-auto w-full decoration-primary/6',
|
'mx-auto page-width-wide:mx-0 w-full decoration-primary/6 print:break-inside-avoid',
|
||||||
node.data && 'fullWidth' in node.data && node.data.fullWidth
|
node.data && 'fullWidth' in node.data && node.data.fullWidth
|
||||||
? 'max-w-screen-2xl'
|
? 'max-w-screen-xl'
|
||||||
: 'page-full-width:ml-0 max-w-3xl',
|
: 'max-w-3xl',
|
||||||
|
FULL_WIDTH_BLOCKS.includes(node.type) && 'page-width-wide:max-w-screen-2xl',
|
||||||
blockStyle,
|
blockStyle,
|
||||||
]}
|
]}
|
||||||
isEstimatedOffscreen={isOffscreen}
|
isEstimatedOffscreen={isOffscreen}
|
||||||
|
|||||||
@@ -38,11 +38,11 @@ export function Caption(
|
|||||||
'overflow-hidden',
|
'overflow-hidden',
|
||||||
'after:block',
|
'after:block',
|
||||||
'after:absolute',
|
'after:absolute',
|
||||||
'after:-inset-[0]',
|
'after:-inset-0',
|
||||||
'after:pointer-events-none',
|
'after:pointer-events-none',
|
||||||
fit ? 'w-fit' : null,
|
fit ? 'w-fit' : null,
|
||||||
withBorder
|
withBorder
|
||||||
? 'rounded circular-corners:rounded-2xl straight-corners:rounded-none after:border-tint-subtle after:border after:rounded circular-corners:after:rounded-2xl straight-corners:after:rounded-none dark:after:mix-blend-plus-lighter after:pointer-events-none'
|
? 'rounded-corners:rounded-sm circular-corners:rounded-2xl after:border-tint-subtle after:border after:rounded circular-corners:after:rounded-2xl rounded-corners:after:rounded-sm dark:after:mix-blend-plus-lighter after:pointer-events-none'
|
||||||
: null,
|
: null,
|
||||||
],
|
],
|
||||||
style,
|
style,
|
||||||
|
|||||||
@@ -43,12 +43,12 @@ export const CodeBlockRenderer = forwardRef(function CodeBlockRenderer(
|
|||||||
</div>
|
</div>
|
||||||
<CopyCodeButton
|
<CopyCodeButton
|
||||||
codeId={id}
|
codeId={id}
|
||||||
style="z-[2] mt-2 mr-2 self-start justify-self-end rounded-md bg-transparent p-1 text-tint text-xs leading-none opacity-0 ring-1 ring-tint backdrop-blur-md transition-opacity duration-75 [grid-area:2/1] hover:ring-tint-hover group-hover/codeblock:opacity-[1]"
|
style="z-2 mt-2 mr-2 self-start justify-self-end leading-none opacity-0 backdrop-blur-md [grid-area:2/1] group-hover/codeblock:opacity-11"
|
||||||
/>
|
/>
|
||||||
<pre
|
<pre
|
||||||
className={tcls(
|
className={tcls(
|
||||||
'relative overflow-auto border border-tint-subtle bg-tint-subtle theme-muted:bg-tint-base p-2 [grid-area:2/1] contrast-more:border-tint contrast-more:bg-tint-base [html.theme-bold.sidebar-filled_&]:bg-tint-base',
|
'relative overflow-auto border border-tint-subtle bg-tint-subtle theme-muted:bg-tint-base p-2 [grid-area:2/1] contrast-more:border-tint contrast-more:bg-tint-base [html.theme-bold.sidebar-filled_&]:bg-tint-base',
|
||||||
'rounded-md straight-corners:rounded-sm shadow-sm',
|
'rounded-md straight-corners:rounded-xs shadow-xs',
|
||||||
title && 'rounded-ss-none'
|
title && 'rounded-ss-none'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import { Button } from '@/components/primitives';
|
||||||
import { t, useLanguage } from '@/intl/client';
|
import { t, useLanguage } from '@/intl/client';
|
||||||
import { type ClassValue, tcls } from '@/lib/tailwind';
|
import { type ClassValue, tcls } from '@/lib/tailwind';
|
||||||
|
|
||||||
@@ -41,9 +42,14 @@ export function CopyCodeButton(props: { codeId: string; style: ClassValue }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button onClick={onClick} className={tcls(style, 'print:hidden')}>
|
<Button
|
||||||
|
size="xsmall"
|
||||||
|
variant="secondary"
|
||||||
|
onClick={onClick}
|
||||||
|
className={tcls(style, 'translate-y-0!', 'print:hidden')}
|
||||||
|
>
|
||||||
{t(language, copied ? 'code_copied' : 'code_copy')}
|
{t(language, copied ? 'code_copied' : 'code_copy')}
|
||||||
</button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ export type RenderedInline = {
|
|||||||
body: React.ReactNode;
|
body: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isSafari =
|
||||||
|
typeof navigator !== 'undefined' && /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
||||||
const theme = createCssVariablesTheme();
|
const theme = createCssVariablesTheme();
|
||||||
|
|
||||||
const { getSingletonHighlighter } = createSingletonShorthands(
|
const { getSingletonHighlighter } = createSingletonShorthands(
|
||||||
@@ -65,8 +67,13 @@ export async function highlight(
|
|||||||
inlines: RenderedInline[]
|
inlines: RenderedInline[]
|
||||||
): Promise<HighlightLine[]> {
|
): Promise<HighlightLine[]> {
|
||||||
const langName = getBlockLang(block);
|
const langName = getBlockLang(block);
|
||||||
if (!langName) {
|
|
||||||
// Language not found, fallback to plain highlighting
|
if (!langName || (isSafari && ['powershell', 'cpp'].includes(langName))) {
|
||||||
|
// Fallback to plain highlighting if
|
||||||
|
// - language is not found
|
||||||
|
// - TEMP : language is PowerShell or C++ and browser is Safari:
|
||||||
|
// RegExp#[Symbol.search] throws TypeError when `lastIndex` isn’t writable
|
||||||
|
// Fixed in upcoming Safari 18.6, remove when it'll be released - RND-7772
|
||||||
return plainHighlight(block, inlines);
|
return plainHighlight(block, inlines);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +136,9 @@ const syntaxAliases: Record<string, BundledLanguage> = {
|
|||||||
// "Parser" language does not exist in Shiki, but it's used in GitBook
|
// "Parser" language does not exist in Shiki, but it's used in GitBook
|
||||||
// The closest language is "Blade"
|
// The closest language is "Blade"
|
||||||
parser: 'blade',
|
parser: 'blade',
|
||||||
|
|
||||||
|
// From GitBook App we receive "objectivec" instead of "objective-c"
|
||||||
|
objectivec: 'objective-c',
|
||||||
};
|
};
|
||||||
|
|
||||||
function checkIsBundledLanguage(lang: string): lang is BundledLanguage {
|
function checkIsBundledLanguage(lang: string): lang is BundledLanguage {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export function Columns(props: BlockProps<DocumentBlockColumns>) {
|
|||||||
document={document}
|
document={document}
|
||||||
ancestorBlocks={[...ancestorBlocks, block, columnBlock]}
|
ancestorBlocks={[...ancestorBlocks, block, columnBlock]}
|
||||||
context={context}
|
context={context}
|
||||||
style="w-full space-y-4 *:max-w-full"
|
style="group/column w-full space-y-4 *:max-w-full"
|
||||||
/>
|
/>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
@@ -51,7 +51,7 @@ function transformLengthToCSS(length: Length | undefined) {
|
|||||||
if (length.unit === '%') {
|
if (length.unit === '%') {
|
||||||
return {
|
return {
|
||||||
className: [
|
className: [
|
||||||
'md:flex-shrink-0',
|
'md:shrink-0',
|
||||||
COLUMN_WIDTHS[Math.round(length.value * 0.01 * (COLUMN_WIDTHS.length - 1))],
|
COLUMN_WIDTHS[Math.round(length.value * 0.01 * (COLUMN_WIDTHS.length - 1))],
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ import type { BlockProps } from './Block';
|
|||||||
export function Divider(props: BlockProps<DocumentBlockDivider>) {
|
export function Divider(props: BlockProps<DocumentBlockDivider>) {
|
||||||
const { style } = props;
|
const { style } = props;
|
||||||
|
|
||||||
return <hr className={tcls(style, 'page-full-width:max-w-full border-tint-subtle')} />;
|
return <hr className={tcls(style, 'page-width-wide:max-w-full border-tint-subtle')} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,12 +50,12 @@ export function Details(props: {
|
|||||||
'border-b-0',
|
'border-b-0',
|
||||||
'border-tint-subtle',
|
'border-tint-subtle',
|
||||||
//all
|
//all
|
||||||
'[&]:mt-[0px]',
|
'mt-0!',
|
||||||
//select first child
|
//select first child
|
||||||
'[&:first-child]:mt-5',
|
'first:mt-5!',
|
||||||
'[&:first-child]:rounded-t-lg',
|
'first:rounded-t-lg',
|
||||||
//select first in group
|
//select first in group
|
||||||
'[:not(&)_+&]:mt-5',
|
'[:not(&)_+&]:mt-5!',
|
||||||
'[:not(&)_+&]:rounded-t-lg',
|
'[:not(&)_+&]:rounded-t-lg',
|
||||||
//select last in group
|
//select last in group
|
||||||
'[&:not(:has(+_&))]:mb-5',
|
'[&:not(:has(+_&))]:mb-5',
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ export function HashLinkButton(props: {
|
|||||||
'opacity-0',
|
'opacity-0',
|
||||||
'group-hover/hash:opacity-[0]',
|
'group-hover/hash:opacity-[0]',
|
||||||
'group-focus/hash:opacity-[0]',
|
'group-focus/hash:opacity-[0]',
|
||||||
'md:group-hover/hash:md:opacity-[1]',
|
'md:group-hover/hash:opacity-[1]',
|
||||||
'md:group-focus/hash:md:opacity-[1]',
|
'md:group-focus/hash:opacity-[1]',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -24,28 +24,32 @@ export function Heading(props: BlockProps<DocumentBlockHeading>) {
|
|||||||
className={tcls(
|
className={tcls(
|
||||||
textStyle.textSize,
|
textStyle.textSize,
|
||||||
'heading',
|
'heading',
|
||||||
'grid',
|
'flex',
|
||||||
'scroll-m-12',
|
'items-baseline',
|
||||||
|
'scroll-mt-(--content-scroll-margin)',
|
||||||
|
getTextAlignment(block.data.align),
|
||||||
hashLinkButtonWrapperStyles,
|
hashLinkButtonWrapperStyles,
|
||||||
style
|
style,
|
||||||
|
textStyle.marginTop
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<HashLinkButton
|
<HashLinkButton
|
||||||
id={id}
|
id={id}
|
||||||
block={block}
|
block={block}
|
||||||
className={tcls('-ml-6', textStyle.anchorButtonMarginTop)}
|
className={tcls('-ml-6', 'pr-2')}
|
||||||
iconClassName={tcls('size-4')}
|
iconClassName={tcls('size-4')}
|
||||||
label="Direct link to heading"
|
label="Direct link to heading"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={tcls(
|
className={tcls(
|
||||||
'grid-area-1-1',
|
'flex-1',
|
||||||
'z-[1]',
|
'z-1',
|
||||||
'justify-self-start',
|
'justify-self-start',
|
||||||
|
'max-w-full',
|
||||||
|
'break-words',
|
||||||
getTextAlignment(block.data.align),
|
getTextAlignment(block.data.align),
|
||||||
textStyle.lineHeight,
|
textStyle.lineHeight
|
||||||
textStyle.marginTop
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Inlines {...rest} context={context} nodes={block.nodes} ancestorInlines={[]} />
|
<Inlines {...rest} context={context} nodes={block.nodes} ancestorInlines={[]} />
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export function Hint(props: BlockProps<DocumentBlockHint>) {
|
|||||||
'hint',
|
'hint',
|
||||||
'transition-colors',
|
'transition-colors',
|
||||||
'rounded-md',
|
'rounded-md',
|
||||||
hasHeading ? 'rounded-l' : null,
|
hasHeading ? 'rounded-l-sm' : null,
|
||||||
'straight-corners:rounded-none',
|
'straight-corners:rounded-none',
|
||||||
'circular-corners:rounded-xl',
|
'circular-corners:rounded-xl',
|
||||||
'overflow-hidden',
|
'overflow-hidden',
|
||||||
@@ -52,8 +52,10 @@ export function Hint(props: BlockProps<DocumentBlockHint>) {
|
|||||||
{hasHeading ? (
|
{hasHeading ? (
|
||||||
<Block
|
<Block
|
||||||
style={tcls(
|
style={tcls(
|
||||||
'flip-heading-hash p-4 pl-3 text-[1em] *:mt-0',
|
'w-full items-start py-4! pl-3 text-[1em] *:flex-none',
|
||||||
hasHeading ? hintStyle.header : null
|
// Heading hash styles
|
||||||
|
'flip-heading-hash pr-8',
|
||||||
|
hintStyle.header
|
||||||
)}
|
)}
|
||||||
ancestorBlocks={[...ancestorBlocks, block]}
|
ancestorBlocks={[...ancestorBlocks, block]}
|
||||||
{...contextProps}
|
{...contextProps}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export async function InlineButton(props: InlineProps<api.DocumentInlineButton>)
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
// Set the leading to have some vertical space between adjacent buttons
|
// Set the leading to have some vertical space between adjacent buttons
|
||||||
<span className="inline-button leading-[3rem] [&:has(+.inline-button)]:mr-2">
|
<span className="inline-button leading-12 [&:has(+.inline-button)]:mr-2">
|
||||||
<Button
|
<Button
|
||||||
href={resolved.href}
|
href={resolved.href}
|
||||||
label={inline.data.label}
|
label={inline.data.label}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export async function InlineImage(props: InlineProps<DocumentInlineImage>) {
|
|||||||
}}
|
}}
|
||||||
priority="lazy"
|
priority="lazy"
|
||||||
preload
|
preload
|
||||||
style={[size === 'line' ? ['max-h-[1lh]', 'h-[1lh]', 'w-auto'] : null]}
|
style={[size === 'line' ? ['max-h-lh', 'h-lh', 'w-auto'] : null]}
|
||||||
inline
|
inline
|
||||||
zoom={!isInLink}
|
zoom={!isInLink}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { type DocumentInlineLink, SiteInsightsLinkPosition } from '@gitbook/api';
|
import { type DocumentInlineLink, SiteInsightsLinkPosition } from '@gitbook/api';
|
||||||
|
|
||||||
import { getSpaceLanguage, tString } from '@/intl/server';
|
import { getSpaceLanguage, tString } from '@/intl/server';
|
||||||
import { languages } from '@/intl/translations';
|
import { type TranslationLanguage, languages } from '@/intl/translations';
|
||||||
import type { GitBookAnyContext } from '@/lib/context';
|
|
||||||
import { type ResolvedContentRef, resolveContentRef } from '@/lib/references';
|
import { type ResolvedContentRef, resolveContentRef } from '@/lib/references';
|
||||||
import { Icon } from '@gitbook/icons';
|
import { Icon } from '@gitbook/icons';
|
||||||
import { StyledLink } from '../../primitives';
|
import { HoverCard, HoverCardRoot, HoverCardTrigger, StyledLink } from '../../primitives';
|
||||||
import type { InlineProps } from '../Inline';
|
import type { InlineProps } from '../Inline';
|
||||||
import { Inlines } from '../Inlines';
|
import { Inlines } from '../Inlines';
|
||||||
import { InlineLinkTooltip } from './InlineLinkTooltip';
|
import { InlineLinkTooltip } from './InlineLinkTooltip';
|
||||||
@@ -19,17 +18,34 @@ export async function InlineLink(props: InlineProps<DocumentInlineLink>) {
|
|||||||
resolveAnchorText: false,
|
resolveAnchorText: false,
|
||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
|
const { contentContext } = context;
|
||||||
|
|
||||||
if (!context.contentContext || !resolved) {
|
const language =
|
||||||
|
contentContext && 'customization' in contentContext
|
||||||
|
? getSpaceLanguage(contentContext.customization)
|
||||||
|
: languages.en;
|
||||||
|
|
||||||
|
if (!contentContext || !resolved) {
|
||||||
return (
|
return (
|
||||||
<span title="Broken link" className="underline">
|
<HoverCardRoot>
|
||||||
<Inlines
|
<HoverCardTrigger>
|
||||||
context={context}
|
<span className="cursor-not-allowed underline">
|
||||||
document={document}
|
<Inlines
|
||||||
nodes={inline.nodes}
|
context={context}
|
||||||
ancestorInlines={[...ancestorInlines, inline]}
|
document={document}
|
||||||
/>
|
nodes={inline.nodes}
|
||||||
</span>
|
ancestorInlines={[...ancestorInlines, inline]}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</HoverCardTrigger>
|
||||||
|
<HoverCard className="flex flex-col gap-1 p-4">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Icon icon="ban" className="size-4 text-tint-subtle" />
|
||||||
|
<h5 className="font-semibold">{tString(language, 'notfound_title')}</h5>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-tint">{tString(language, 'notfound_link')}</p>
|
||||||
|
</HoverCard>
|
||||||
|
</HoverCardRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const isExternal = inline.data.ref.kind === 'url';
|
const isExternal = inline.data.ref.kind === 'url';
|
||||||
@@ -61,11 +77,7 @@ export async function InlineLink(props: InlineProps<DocumentInlineLink>) {
|
|||||||
|
|
||||||
if (context.shouldRenderLinkPreviews) {
|
if (context.shouldRenderLinkPreviews) {
|
||||||
return (
|
return (
|
||||||
<InlineLinkTooltipWrapper
|
<InlineLinkTooltipWrapper inline={inline} language={language} resolved={resolved}>
|
||||||
inline={inline}
|
|
||||||
context={context.contentContext}
|
|
||||||
resolved={resolved}
|
|
||||||
>
|
|
||||||
{content}
|
{content}
|
||||||
</InlineLinkTooltipWrapper>
|
</InlineLinkTooltipWrapper>
|
||||||
);
|
);
|
||||||
@@ -80,15 +92,13 @@ export async function InlineLink(props: InlineProps<DocumentInlineLink>) {
|
|||||||
*/
|
*/
|
||||||
function InlineLinkTooltipWrapper(props: {
|
function InlineLinkTooltipWrapper(props: {
|
||||||
inline: DocumentInlineLink;
|
inline: DocumentInlineLink;
|
||||||
context: GitBookAnyContext;
|
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
resolved: ResolvedContentRef;
|
resolved: ResolvedContentRef;
|
||||||
|
language: TranslationLanguage;
|
||||||
}) {
|
}) {
|
||||||
const { inline, context, resolved, children } = props;
|
const { inline, language, resolved, children } = props;
|
||||||
|
|
||||||
let breadcrumbs = resolved.ancestors ?? [];
|
let breadcrumbs = resolved.ancestors ?? [];
|
||||||
const language =
|
|
||||||
'customization' in context ? getSpaceLanguage(context.customization) : languages.en;
|
|
||||||
const isExternal = inline.data.ref.kind === 'url';
|
const isExternal = inline.data.ref.kind === 'url';
|
||||||
const isSamePage = inline.data.ref.kind === 'anchor' && inline.data.ref.page === undefined;
|
const isSamePage = inline.data.ref.kind === 'anchor' && inline.data.ref.page === undefined;
|
||||||
if (isExternal) {
|
if (isExternal) {
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { tcls } from '@/lib/tailwind';
|
import { tcls } from '@/lib/tailwind';
|
||||||
import { Icon } from '@gitbook/icons';
|
import { Icon } from '@gitbook/icons';
|
||||||
import * as Tooltip from '@radix-ui/react-tooltip';
|
|
||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
import { Button, StyledLink } from '../../primitives';
|
import { Button, HoverCard, HoverCardRoot, HoverCardTrigger, StyledLink } from '../../primitives';
|
||||||
|
|
||||||
export function InlineLinkTooltipImpl(props: {
|
export function InlineLinkTooltipImpl(props: {
|
||||||
isSamePage: boolean;
|
isSamePage: boolean;
|
||||||
@@ -21,89 +20,76 @@ export function InlineLinkTooltipImpl(props: {
|
|||||||
const { isSamePage, isExternal, openInNewTabLabel, target, breadcrumbs, children } = props;
|
const { isSamePage, isExternal, openInNewTabLabel, target, breadcrumbs, children } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip.Provider delayDuration={200}>
|
<HoverCardRoot>
|
||||||
<Tooltip.Root>
|
<HoverCardTrigger>{children}</HoverCardTrigger>
|
||||||
<Tooltip.Trigger asChild>{children}</Tooltip.Trigger>
|
<HoverCard className="p-4">
|
||||||
<Tooltip.Portal>
|
<div className="flex items-start gap-4">
|
||||||
<Tooltip.Content className="z-40 w-screen max-w-md animate-present px-4 sm:w-auto">
|
<div className="flex flex-col">
|
||||||
<div className="overflow-hidden rounded-md straight-corners:rounded-none shadow-lg shadow-tint-12/4 ring-1 ring-tint-subtle dark:shadow-tint-1 ">
|
{breadcrumbs && breadcrumbs.length > 0 ? (
|
||||||
<div className="bg-tint-base p-4">
|
<div className="mb-1 flex grow flex-wrap items-center gap-x-2 gap-y-0.5 font-semibold text-tint text-xs uppercase leading-tight tracking-wide">
|
||||||
<div className="flex items-start gap-4">
|
{breadcrumbs.map((crumb, index) => {
|
||||||
<div className="flex flex-col">
|
const Tag = crumb.href ? StyledLink : 'div';
|
||||||
{breadcrumbs && breadcrumbs.length > 0 ? (
|
|
||||||
<div className="mb-1 flex grow flex-wrap items-center gap-x-2 gap-y-0.5 font-semibold text-tint text-xs uppercase leading-tight tracking-wide">
|
|
||||||
{breadcrumbs.map((crumb, index) => {
|
|
||||||
const Tag = crumb.href ? StyledLink : 'div';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment key={crumb.label}>
|
<Fragment key={crumb.label}>
|
||||||
{index !== 0 ? (
|
{index !== 0 ? (
|
||||||
<Icon
|
<Icon
|
||||||
icon="chevron-right"
|
icon="chevron-right"
|
||||||
className="size-3 text-tint-subtle"
|
className="size-3 text-tint-subtle"
|
||||||
/>
|
/>
|
||||||
) : null}
|
|
||||||
<Tag
|
|
||||||
className={tcls(
|
|
||||||
'flex gap-1',
|
|
||||||
crumb.href &&
|
|
||||||
'links-default:text-tint no-underline hover:underline contrast-more:underline contrast-more:decoration-current'
|
|
||||||
)}
|
|
||||||
href={crumb.href ?? '#'}
|
|
||||||
>
|
|
||||||
{crumb.icon ? (
|
|
||||||
<span className="mt-0.5 text-tint-subtle empty:hidden">
|
|
||||||
{crumb.icon}
|
|
||||||
</span>
|
|
||||||
) : null}
|
|
||||||
{crumb.label}
|
|
||||||
</Tag>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<div
|
|
||||||
className={tcls(
|
|
||||||
'flex gap-2 leading-snug',
|
|
||||||
isExternal && 'text-sm [overflow-wrap:anywhere]'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{target.icon ? (
|
|
||||||
<div className="mt-1 text-tint-subtle empty:hidden">
|
|
||||||
{target.icon}
|
|
||||||
</div>
|
|
||||||
) : null}
|
) : null}
|
||||||
<h5 className="font-semibold">{target.text}</h5>
|
<Tag
|
||||||
</div>
|
className={tcls(
|
||||||
</div>
|
'flex gap-1',
|
||||||
{!isSamePage && target.href ? (
|
crumb.href &&
|
||||||
<Button
|
'links-default:text-tint no-underline hover:underline contrast-more:underline contrast-more:decoration-current'
|
||||||
className={tcls(
|
)}
|
||||||
'-mx-2 -my-2 ml-auto',
|
href={crumb.href ?? '#'}
|
||||||
breadcrumbs?.length === 0
|
>
|
||||||
? 'place-self-center'
|
{crumb.icon ? (
|
||||||
: null
|
<span className="mt-0.5 text-tint-subtle empty:hidden">
|
||||||
)}
|
{crumb.icon}
|
||||||
variant="blank"
|
</span>
|
||||||
href={target.href}
|
) : null}
|
||||||
target="_blank"
|
{crumb.label}
|
||||||
label={openInNewTabLabel}
|
</Tag>
|
||||||
size="small"
|
</Fragment>
|
||||||
icon="arrow-up-right-from-square"
|
);
|
||||||
iconOnly={true}
|
})}
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
{target.subText ? (
|
|
||||||
<p className="mt-1 text-sm text-tint">{target.subText}</p>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
|
) : null}
|
||||||
|
<div
|
||||||
|
className={tcls(
|
||||||
|
'flex gap-2 leading-snug',
|
||||||
|
isExternal && 'wrap-anywhere text-sm'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{target.icon ? (
|
||||||
|
<div className="mt-1 text-tint-subtle empty:hidden">
|
||||||
|
{target.icon}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<h5 className="font-semibold">{target.text}</h5>
|
||||||
</div>
|
</div>
|
||||||
<Tooltip.Arrow className="fill-tint-1" />
|
</div>
|
||||||
</Tooltip.Content>
|
{!isSamePage && target.href ? (
|
||||||
</Tooltip.Portal>
|
<Button
|
||||||
</Tooltip.Root>
|
className={tcls(
|
||||||
</Tooltip.Provider>
|
'-mx-2 -my-2 ml-auto',
|
||||||
|
breadcrumbs?.length === 0 ? 'place-self-center' : null
|
||||||
|
)}
|
||||||
|
variant="blank"
|
||||||
|
href={target.href}
|
||||||
|
target="_blank"
|
||||||
|
label={openInNewTabLabel}
|
||||||
|
size="small"
|
||||||
|
icon="arrow-up-right-from-square"
|
||||||
|
iconOnly={true}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
{target.subText ? <p className="mt-1 text-sm text-tint">{target.subText}</p> : null}
|
||||||
|
</HoverCard>
|
||||||
|
</HoverCardRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@reference '../../RootLayout/globals.css';
|
||||||
|
|
||||||
/** Stacks */
|
/** Stacks */
|
||||||
.contentkit-stack {
|
.contentkit-stack {
|
||||||
@apply flex gap-4;
|
@apply flex gap-4;
|
||||||
@@ -114,7 +116,7 @@
|
|||||||
|
|
||||||
/** Modals */
|
/** Modals */
|
||||||
.contentkit-modal-backdrop {
|
.contentkit-modal-backdrop {
|
||||||
@apply fixed inset-0 z-40 px-7 pb-11 pt-4 md:pt-[min(8vw,_6rem)] flex items-start justify-center backdrop-blur-2xl bg-tint-12/4 dark:bg-tint-1/6;
|
@apply fixed inset-0 z-40 px-7 pb-11 pt-4 md:pt-[min(8vw,6rem)] flex items-start justify-center backdrop-blur-2xl bg-tint-12/4 dark:bg-tint-1/6;
|
||||||
}
|
}
|
||||||
.contentkit-modal {
|
.contentkit-modal {
|
||||||
@apply flex flex-col gap-6 relative z-50 bg-tint
|
@apply flex flex-col gap-6 relative z-50 bg-tint
|
||||||
@@ -195,3 +197,18 @@
|
|||||||
.contentkit-hstack > .contentkit-divider-large {
|
.contentkit-hstack > .contentkit-divider-large {
|
||||||
@apply mx-4;
|
@apply mx-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Confirmation modal */
|
||||||
|
|
||||||
|
.contentkit-modal-confirm {
|
||||||
|
@apply p-4;
|
||||||
|
}
|
||||||
|
.contentkit-modal-confirm .contentkit-modal-footer {
|
||||||
|
@apply flex gap-2 justify-end;
|
||||||
|
}
|
||||||
|
.contentkit-button-confirm {
|
||||||
|
@apply w-auto flex-grow-0 flex-shrink-0;
|
||||||
|
}
|
||||||
|
.contentkit-button-style-danger {
|
||||||
|
@apply bg-danger text-danger hover:bg-danger-hover hover:text-danger-strong contrast-more:bg-tint-subtle;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use server';
|
'use server';
|
||||||
|
|
||||||
import { getServerActionBaseContext } from '@/lib/server-actions';
|
import { getServerActionBaseContext } from '@/lib/server-actions';
|
||||||
|
import { traceErrorOnly } from '@/lib/tracing';
|
||||||
import type { RenderIntegrationUI } from '@gitbook/api';
|
import type { RenderIntegrationUI } from '@gitbook/api';
|
||||||
import { ContentKitOutput } from '@gitbook/react-contentkit';
|
import { ContentKitOutput } from '@gitbook/react-contentkit';
|
||||||
import { contentKitServerContext } from './contentkit';
|
import { contentKitServerContext } from './contentkit';
|
||||||
@@ -19,20 +20,22 @@ export async function renderIntegrationUi({
|
|||||||
};
|
};
|
||||||
request: RenderIntegrationUI;
|
request: RenderIntegrationUI;
|
||||||
}) {
|
}) {
|
||||||
const serverAction = await getServerActionBaseContext();
|
return traceErrorOnly('DocumentView.renderIntegrationUi', async () => {
|
||||||
const output = await fetchSafeIntegrationUI(serverAction, {
|
const serverAction = await getServerActionBaseContext();
|
||||||
integrationName: renderContext.integrationName,
|
const output = await fetchSafeIntegrationUI(serverAction, {
|
||||||
request,
|
integrationName: renderContext.integrationName,
|
||||||
});
|
request,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (output.error) {
|
||||||
|
return {
|
||||||
|
error: output.error.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (output.error) {
|
|
||||||
return {
|
return {
|
||||||
error: output.error.message,
|
children: <ContentKitOutput output={output.data} context={contentKitServerContext} />,
|
||||||
|
output: output.data,
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
|
|
||||||
return {
|
|
||||||
children: <ContentKitOutput output={output.data} context={contentKitServerContext} />,
|
|
||||||
output: output.data,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,13 +31,13 @@ export function ListItem(props: BlockProps<DocumentBlockListItem>) {
|
|||||||
nodes={block.nodes}
|
nodes={block.nodes}
|
||||||
ancestorBlocks={[...ancestorBlocks, block]}
|
ancestorBlocks={[...ancestorBlocks, block]}
|
||||||
blockStyle={tcls(
|
blockStyle={tcls(
|
||||||
'min-h-[1lh]',
|
'min-h-lh',
|
||||||
// flip heading hash icon if list item is a heading
|
// flip heading hash icon if list item is a heading
|
||||||
'flip-heading-hash',
|
'flip-heading-hash',
|
||||||
// remove margin-top for the first heading in a list
|
// remove margin-top for the first heading in a list
|
||||||
'[&:is(h2)>div]:mt-0',
|
'[h2]:pt-0',
|
||||||
'[&:is(h3)>div]:mt-0',
|
'[h3]:pt-0',
|
||||||
'[&:is(h4)>div]:mt-0',
|
'[h4]:pt-0',
|
||||||
// Override the "mx-auto" class from UnwrappedBlocks
|
// Override the "mx-auto" class from UnwrappedBlocks
|
||||||
'mx-0'
|
'mx-0'
|
||||||
)}
|
)}
|
||||||
@@ -137,7 +137,7 @@ function ListItemPrefix(props: { block: DocumentBlockListItem; children: React.R
|
|||||||
className={tcls(
|
className={tcls(
|
||||||
textStyle.textSize,
|
textStyle.textSize,
|
||||||
textStyle.lineHeight,
|
textStyle.lineHeight,
|
||||||
'mr-1 flex min-h-[1lh] min-w-6 items-center justify-center text-tint'
|
'mr-1 flex min-h-lh min-w-6 items-center justify-center text-tint'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
@@ -165,7 +165,7 @@ function PseudoBefore(props: {
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="before:font-var before:content-[--pseudoBefore--content]"
|
className="before:font-var before:content-(--pseudoBefore--content)"
|
||||||
style={
|
style={
|
||||||
{
|
{
|
||||||
'--pseudoBefore--content': `'${props.content}'`,
|
'--pseudoBefore--content': `'${props.content}'`,
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export function getOpenAPIContext(args: {
|
|||||||
style={tcls([
|
style={tcls([
|
||||||
headingProps.deprecated ? 'line-through' : undefined,
|
headingProps.deprecated ? 'line-through' : undefined,
|
||||||
headingProps.deprecated || !!headingProps.stability
|
headingProps.deprecated || !!headingProps.stability
|
||||||
? '[&>div]:mt-0'
|
? '[&>div]:pt-0'
|
||||||
: undefined,
|
: undefined,
|
||||||
])}
|
])}
|
||||||
block={{
|
block={{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
@import "@scalar/api-client-react/style.css";
|
@import "@scalar/api-client-react/style.css";
|
||||||
|
@reference "../../RootLayout/globals.css";
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@reference "../../RootLayout/globals.css";
|
||||||
|
|
||||||
/* Layout Components */
|
/* Layout Components */
|
||||||
.openapi-operation,
|
.openapi-operation,
|
||||||
.openapi-schemas,
|
.openapi-schemas,
|
||||||
@@ -32,7 +34,7 @@
|
|||||||
|
|
||||||
.openapi-deprecated,
|
.openapi-deprecated,
|
||||||
.openapi-stability {
|
.openapi-stability {
|
||||||
@apply py-0.5 px-1.5 min-w-[1.625rem] font-normal w-fit justify-center items-center ring-1 ring-inset ring-tint bg-tint rounded text-sm leading-[calc(max(1.20em,1.25rem))] before:!content-none after:!content-none;
|
@apply py-0.5 px-1.5 min-w-[1.625rem] font-normal w-fit justify-center items-center ring-1 ring-inset ring-tint bg-tint rounded text-sm leading-[calc(max(1.20em,1.25rem))] before:content-none! after:!content-none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-stability-alpha {
|
.openapi-stability-alpha {
|
||||||
@@ -70,7 +72,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-markdown code {
|
.openapi-markdown code {
|
||||||
@apply py-px px-1 min-w-[1.625rem] font-normal w-fit justify-center items-center ring-1 ring-inset ring-tint bg-tint rounded text-sm leading-[calc(max(1.20em,1.25rem))] before:!content-none after:!content-none;
|
@apply py-px px-1 min-w-[1.625rem] font-normal w-fit justify-center items-center ring-1 ring-inset ring-tint bg-tint rounded text-sm leading-[calc(max(1.20em,1.25rem))] before:content-none! after:!content-none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-markdown pre code {
|
.openapi-markdown pre code {
|
||||||
@@ -79,7 +81,7 @@
|
|||||||
|
|
||||||
/* Markdown Base */
|
/* Markdown Base */
|
||||||
.openapi-markdown {
|
.openapi-markdown {
|
||||||
@apply prose text-tint-strong prose-p:!my-2 dark:prose-invert max-w-none whitespace-normal;
|
@apply prose text-tint-strong prose-p:my-2! dark:prose-invert max-w-none whitespace-normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-markdown > *:first-child {
|
.openapi-markdown > *:first-child {
|
||||||
@@ -145,7 +147,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-column-preview-body {
|
.openapi-column-preview-body {
|
||||||
@apply flex flex-col gap-4 sticky top-4 site-header:top-20 site-header:xl:max-2xl:top-32 site-header-sections:top-32 site-header-sections:xl:max-2xl:top-44 print-mode:static;
|
@apply flex flex-col gap-4 sticky top-[calc(var(--toc-top-offset)+5rem)] print-mode:static;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-column-preview pre {
|
.openapi-column-preview pre {
|
||||||
@@ -158,7 +160,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema-root-description.openapi-markdown {
|
.openapi-schema-root-description.openapi-markdown {
|
||||||
@apply prose-sm text-balance mt-1.5 !text-[0.813rem] text-tint overflow-hidden !font-normal select-text prose-strong:font-semibold prose-strong:text-inherit;
|
@apply prose-sm text-balance mt-1.5 text-[0.813rem]! text-tint overflow-hidden font-normal! select-text prose-strong:font-semibold prose-strong:text-inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-section-schemas > .openapi-section-body > .openapi-schema-root-description {
|
.openapi-section-schemas > .openapi-section-body > .openapi-schema-root-description {
|
||||||
@@ -273,7 +275,7 @@
|
|||||||
|
|
||||||
/* Schema Description */
|
/* Schema Description */
|
||||||
.openapi-schema-description.openapi-markdown {
|
.openapi-schema-description.openapi-markdown {
|
||||||
@apply prose-sm text-tint overflow-hidden text-pretty !font-normal select-text prose-strong:font-semibold prose-strong:text-inherit;
|
@apply prose-sm text-tint overflow-hidden text-pretty font-normal! select-text prose-strong:font-semibold prose-strong:text-inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema-description.openapi-markdown pre:has(code) {
|
.openapi-schema-description.openapi-markdown pre:has(code) {
|
||||||
@@ -302,7 +304,7 @@
|
|||||||
.openapi-schema-pattern code,
|
.openapi-schema-pattern code,
|
||||||
.openapi-schema-enum-value code,
|
.openapi-schema-enum-value code,
|
||||||
.openapi-schema-default code {
|
.openapi-schema-default code {
|
||||||
@apply py-px px-1 min-w-[1.625rem] text-tint-strong font-normal w-fit justify-center items-center ring-1 ring-inset ring-tint-subtle bg-tint rounded text-xs leading-[calc(max(1.20em,1.25rem))] before:!content-none after:!content-none;
|
@apply py-px px-1 min-w-[1.625rem] text-tint-strong font-normal w-fit justify-center items-center ring-1 ring-inset ring-tint-subtle bg-tint rounded text-xs leading-[calc(max(1.20em,1.25rem))] before:content-none! after:!content-none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Authentication */
|
/* Authentication */
|
||||||
@@ -335,7 +337,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-securities-description.openapi-markdown {
|
.openapi-securities-description.openapi-markdown {
|
||||||
@apply prose-sm text-tint !font-normal select-text text-pretty prose-strong:font-semibold prose-strong:text-inherit;
|
@apply prose-sm text-tint font-normal! select-text text-pretty prose-strong:font-semibold prose-strong:text-inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-securities-label {
|
.openapi-securities-label {
|
||||||
@@ -366,7 +368,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-requestbody-description.openapi-markdown {
|
.openapi-requestbody-description.openapi-markdown {
|
||||||
@apply prose-sm text-tint !font-normal text-pretty select-text prose-strong:font-semibold prose-strong:text-inherit;
|
@apply prose-sm text-tint font-normal! text-pretty select-text prose-strong:font-semibold prose-strong:text-inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Responses */
|
/* Responses */
|
||||||
@@ -379,21 +381,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-response-tab-content {
|
.openapi-response-tab-content {
|
||||||
@apply flex items-baseline truncate grow shrink max-w-max basis-[60%] mr-auto;
|
@apply flex items-baseline truncate grow shrink max-w-max basis-full mr-auto;
|
||||||
@apply text-left text-pretty relative leading-tight text-tint select-text;
|
@apply text-left text-pretty relative leading-tight text-tint select-text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-response-description.openapi-markdown {
|
.openapi-response-description.openapi-markdown {
|
||||||
@apply text-left truncate prose-sm text-sm leading-tight text-tint select-text prose-strong:font-semibold prose-strong:text-inherit;
|
@apply text-left prose-sm text-sm leading-tight text-tint select-text prose-strong:font-semibold prose-strong:text-inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-trigger[aria-expanded="true"] .openapi-response-tab-content {
|
.openapi-disclosure-group-trigger[aria-expanded="false"] {
|
||||||
@apply basis-full;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-disclosure-group-trigger[aria-expanded="true"]
|
|
||||||
.openapi-response-description.openapi-markdown {
|
.openapi-response-description.openapi-markdown {
|
||||||
@apply whitespace-normal;
|
@apply truncate;
|
||||||
|
@apply [&>*:not(:first-child)]:hidden *:truncate *:!p-0 *:!m-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-response-tab-content {
|
||||||
|
@apply basis-[60%]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-response-body {
|
.openapi-response-body {
|
||||||
@@ -465,7 +469,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-path-variable {
|
.openapi-path-variable {
|
||||||
@apply p-px min-w-[1.625rem] text-tint-strong font-normal w-fit justify-center items-center ring-1 ring-inset ring-tint bg-tint rounded text-sm leading-none before:!content-none after:!content-none;
|
@apply p-px min-w-[1.625rem] text-tint-strong font-normal w-fit justify-center items-center ring-1 ring-inset ring-tint bg-tint rounded text-sm leading-none before:content-none! after:!content-none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-path-server {
|
.openapi-path-server {
|
||||||
@@ -551,6 +555,10 @@
|
|||||||
@apply text-[0.813rem] truncate text-tint font-normal;
|
@apply text-[0.813rem] truncate text-tint font-normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openapi-response-examples-statuscode-label {
|
||||||
|
@apply truncate;
|
||||||
|
}
|
||||||
|
|
||||||
.openapi-response-examples-panel,
|
.openapi-response-examples-panel,
|
||||||
.openapi-codesample-panel {
|
.openapi-codesample-panel {
|
||||||
@apply flex-1 text-sm relative focus-visible:outline-none;
|
@apply flex-1 text-sm relative focus-visible:outline-none;
|
||||||
@@ -583,10 +591,6 @@ body:has(.openapi-select-popover) {
|
|||||||
@apply shrink truncate flex items-center;
|
@apply shrink truncate flex items-center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-select > button > span.react-aria-SelectValue span:not(.openapi-statuscode) {
|
|
||||||
@apply truncate;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-select > button .openapi-markdown {
|
.openapi-select > button .openapi-markdown {
|
||||||
@apply *:leading-none;
|
@apply *:leading-none;
|
||||||
}
|
}
|
||||||
@@ -610,18 +614,18 @@ body:has(.openapi-select-popover) {
|
|||||||
|
|
||||||
.openapi-select-item {
|
.openapi-select-item {
|
||||||
@apply text-sm flex items-center cursor-pointer px-1.5 overflow-hidden py-1 *:truncate text-tint ring-0 border-none rounded !outline-none;
|
@apply text-sm flex items-center cursor-pointer px-1.5 overflow-hidden py-1 *:truncate text-tint ring-0 border-none rounded !outline-none;
|
||||||
@apply hover:bg-tint-hover theme-gradient:hover:bg-tint-12/1 hover:text-tint-strong contrast-more:hover:ring-1 contrast-more:hover:ring-inset contrast-more:hover:ring-current;
|
@apply hover:bg-tint-hover hover:theme-gradient:bg-tint-12/1 hover:text-tint-strong contrast-more:hover:ring-1 contrast-more:hover:ring-inset contrast-more:hover:ring-current;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-select button .openapi-markdown,
|
.openapi-select button .openapi-markdown,
|
||||||
.openapi-select-item .openapi-markdown {
|
.openapi-select-item .openapi-markdown {
|
||||||
@apply text-[0.813rem] *:truncate;
|
@apply text-[0.813rem] *:truncate *:!p-0 *:!m-0 [&>*:not(:first-child)]:hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-select-item-selected,
|
.openapi-select-item-selected,
|
||||||
.openapi-select-item-selected .openapi-markdown {
|
.openapi-select-item-selected .openapi-markdown {
|
||||||
@apply text-primary-subtle hover:text-primary hover:bg-primary-hover;
|
@apply text-primary-subtle hover:text-primary hover:bg-primary-hover;
|
||||||
@apply theme-muted:hover:bg-primary-active theme-gradient:hover:bg-primary-active tint:font-semibold;
|
@apply hover:theme-muted:bg-primary-active hover:theme-gradient:bg-primary-active tint:font-semibold;
|
||||||
@apply contrast-more:text-primary contrast-more:hover:text-primary-strong contrast-more:font-semibold;
|
@apply contrast-more:text-primary contrast-more:hover:text-primary-strong contrast-more:font-semibold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,7 +697,7 @@ body:has(.openapi-select-popover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-tabs-tab[aria-selected="true"] {
|
.openapi-tabs-tab[aria-selected="true"] {
|
||||||
@apply !text-primary-subtle after:absolute after:-bottom-[calc(0.375rem_+_1px)] after:z-20 after:left-0 after:w-full after:h-px after:bg-primary-solid after:transition-all;
|
@apply text-primary-subtle! after:absolute after:-bottom-[calc(0.375rem+1px)] after:z-20 after:left-0 after:w-full after:h-px after:bg-primary-solid after:transition-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-tabs-panel {
|
.openapi-tabs-panel {
|
||||||
@@ -769,7 +773,7 @@ body:has(.openapi-select-popover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema .openapi-schema-properties .openapi-schema {
|
.openapi-schema .openapi-schema-properties .openapi-schema {
|
||||||
@apply animate-fadeIn [animation-fill-mode:both];
|
animation: fadeIn 0.2s ease-in-out both;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schemas-disclosure > .openapi-disclosure-trigger[aria-expanded="true"] > svg {
|
.openapi-schemas-disclosure > .openapi-disclosure-trigger[aria-expanded="true"] > svg {
|
||||||
@@ -830,7 +834,8 @@ body:has(.openapi-select-popover) {
|
|||||||
|
|
||||||
.openapi-disclosure-trigger:hover > .openapi-disclosure-trigger-label span,
|
.openapi-disclosure-trigger:hover > .openapi-disclosure-trigger-label span,
|
||||||
.openapi-disclosure-trigger[aria-expanded="true"] > .openapi-disclosure-trigger-label span {
|
.openapi-disclosure-trigger[aria-expanded="true"] > .openapi-disclosure-trigger-label span {
|
||||||
@apply block animate-fadeIn;
|
@apply block;
|
||||||
|
animation: fadeIn 0.2s ease-in-out both;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (hover: none) {
|
@media (hover: none) {
|
||||||
|
|||||||
@@ -26,14 +26,15 @@ export async function ReusableContent(props: BlockProps<DocumentBlockReusableCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { reusableContent } = resolved;
|
const { reusableContent } = resolved;
|
||||||
if (!reusableContent || !reusableContent.revisionReusableContent.document) {
|
if (!reusableContent) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const document = await getDataOrNull(
|
const document = await getDataOrNull(
|
||||||
dataFetcher.getDocument({
|
dataFetcher.getRevisionReusableContentDocument({
|
||||||
spaceId: reusableContent.context.space.id,
|
spaceId: reusableContent.context.space.id,
|
||||||
documentId: reusableContent.revisionReusableContent.document,
|
revisionId: reusableContent.context.revisionId,
|
||||||
|
reusableContentId: reusableContent.revisionReusableContent.id,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ export function StepperStep(props: BlockProps<DocumentBlockStepperStep>) {
|
|||||||
return '-mt-9';
|
return '-mt-9';
|
||||||
case 'heading-2':
|
case 'heading-2':
|
||||||
return '-mt-[calc(1.25rem+1px)]';
|
return '-mt-[calc(1.25rem+1px)]';
|
||||||
|
case 'heading-3':
|
||||||
|
return '-mt-[calc(0.50rem+1px)]';
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -40,7 +42,7 @@ export function StepperStep(props: BlockProps<DocumentBlockStepperStep>) {
|
|||||||
>
|
>
|
||||||
{index + 1}
|
{index + 1}
|
||||||
</div>
|
</div>
|
||||||
<div className="can-override-bg absolute top-9 bottom-2 left-[0.875rem] w-px bg-primary-7 theme-muted:bg-primary-subtle" />
|
<div className="can-override-bg absolute top-9 bottom-2 left-3.5 w-px bg-primary-7 theme-muted:bg-primary-subtle" />
|
||||||
</div>
|
</div>
|
||||||
<Blocks
|
<Blocks
|
||||||
{...contextProps}
|
{...contextProps}
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
|
import { LinkBox, LinkOverlay } from '@/components/primitives';
|
||||||
|
import { Image } from '@/components/utils';
|
||||||
|
import { type ResolvedContentRef, resolveContentRef } from '@/lib/references';
|
||||||
|
import { tcls } from '@/lib/tailwind';
|
||||||
import {
|
import {
|
||||||
type ContentRef,
|
type ContentRef,
|
||||||
type DocumentTableViewCards,
|
type DocumentTableViewCards,
|
||||||
SiteInsightsLinkPosition,
|
SiteInsightsLinkPosition,
|
||||||
} from '@gitbook/api';
|
} from '@gitbook/api';
|
||||||
|
|
||||||
import { LinkBox, LinkOverlay } from '@/components/primitives';
|
|
||||||
import { Image } from '@/components/utils';
|
|
||||||
import { resolveContentRef } from '@/lib/references';
|
|
||||||
import { tcls } from '@/lib/tailwind';
|
|
||||||
|
|
||||||
import { RecordColumnValue } from './RecordColumnValue';
|
import { RecordColumnValue } from './RecordColumnValue';
|
||||||
import type { TableRecordKV, TableViewProps } from './Table';
|
import type { TableRecordKV, TableViewProps } from './Table';
|
||||||
import { RecordCardStyles } from './styles';
|
import { RecordCardStyles } from './styles';
|
||||||
import { getRecordValue } from './utils';
|
import { getRecordCardCovers } from './utils';
|
||||||
|
|
||||||
export async function RecordCard(
|
export async function RecordCard(
|
||||||
props: TableViewProps<DocumentTableViewCards> & {
|
props: TableViewProps<DocumentTableViewCards> & {
|
||||||
@@ -21,25 +19,21 @@ export async function RecordCard(
|
|||||||
) {
|
) {
|
||||||
const { view, record, context, block, isOffscreen } = props;
|
const { view, record, context, block, isOffscreen } = props;
|
||||||
|
|
||||||
const coverFile = view.coverDefinition
|
const { dark, light } = getRecordCardCovers(record[1], view);
|
||||||
? getRecordValue<string[]>(record[1], view.coverDefinition)?.[0]
|
|
||||||
: null;
|
|
||||||
const targetRef = view.targetDefinition
|
const targetRef = view.targetDefinition
|
||||||
? (record[1].values[view.targetDefinition] as ContentRef)
|
? (record[1].values[view.targetDefinition] as ContentRef)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
const [cover, target] = await Promise.all([
|
const [lightCover, darkCover, target] = await Promise.all([
|
||||||
coverFile && context.contentContext
|
light && context.contentContext ? resolveContentRef(light, context.contentContext) : null,
|
||||||
? resolveContentRef({ kind: 'file', file: coverFile }, context.contentContext)
|
dark && context.contentContext ? resolveContentRef(dark, context.contentContext) : null,
|
||||||
: null,
|
|
||||||
targetRef && context.contentContext
|
targetRef && context.contentContext
|
||||||
? resolveContentRef(targetRef, context.contentContext)
|
? resolveContentRef(targetRef, context.contentContext)
|
||||||
: null,
|
: null,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const coverIsSquareOrPortrait =
|
const darkCoverIsSquareOrPortrait = isSquareOrPortrait(darkCover);
|
||||||
cover?.file?.dimensions &&
|
const lightCoverIsSquareOrPortrait = isSquareOrPortrait(lightCover);
|
||||||
cover.file?.dimensions?.width / cover.file?.dimensions?.height <= 1;
|
|
||||||
|
|
||||||
const body = (
|
const body = (
|
||||||
<div
|
<div
|
||||||
@@ -50,36 +44,45 @@ export async function RecordCard(
|
|||||||
'bg-tint-base',
|
'bg-tint-base',
|
||||||
'w-[calc(100%+2px)]',
|
'w-[calc(100%+2px)]',
|
||||||
'h-[calc(100%+2px)]',
|
'h-[calc(100%+2px)]',
|
||||||
'inset-[-1px]',
|
'-inset-px',
|
||||||
'rounded',
|
'rounded-sm',
|
||||||
'straight-corners:rounded-none',
|
'straight-corners:rounded-none',
|
||||||
'circular-corners:rounded-xl',
|
'circular-corners:rounded-xl',
|
||||||
'overflow-hidden',
|
'overflow-hidden',
|
||||||
'[&_.heading>div:first-child]:hidden',
|
'[&_.heading>div:first-child]:hidden',
|
||||||
'[&_.heading>div]:text-[.8em]',
|
'[&_.heading>div]:text-[.8em]',
|
||||||
'md:[&_.heading>div]:text-[1em]',
|
'md:[&_.heading>div]:text-[1em]',
|
||||||
'[&_.blocks:first-child_.heading:first-child_div]:mt-0', // Remove margin on first heading in card
|
'[&_.blocks:first-child_.heading]:pt-0', // Remove padding-top on first heading in card
|
||||||
|
|
||||||
// On mobile, check if we can display the cover responsively or not:
|
// On mobile, check if we can display the cover responsively or not:
|
||||||
// - If the file has a landscape aspect ratio, we display it normally
|
// - If the file has a landscape aspect ratio, we display it normally
|
||||||
// - If the file is square or portrait, we display it left with 40% of the card width
|
// - If the file is square or portrait, we display it left with 40% of the card width
|
||||||
coverIsSquareOrPortrait
|
lightCoverIsSquareOrPortrait || darkCoverIsSquareOrPortrait
|
||||||
? [
|
? [
|
||||||
'grid-cols-[40%,_1fr]',
|
lightCoverIsSquareOrPortrait
|
||||||
'min-[432px]:grid-cols-none',
|
? 'grid-cols-[40%__1fr] min-[432px]:grid-cols-none min-[432px]:grid-rows-[auto_1fr]'
|
||||||
'min-[432px]:grid-rows-[auto,1fr]',
|
: '',
|
||||||
]
|
darkCoverIsSquareOrPortrait
|
||||||
: 'grid-rows-[auto,1fr]'
|
? 'dark:grid-cols-[40%__1fr] dark:min-[432px]:grid-cols-none dark:min-[432px]:grid-rows-[auto_1fr]'
|
||||||
|
: '',
|
||||||
|
].filter(Boolean)
|
||||||
|
: 'grid-rows-[auto_1fr]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{cover ? (
|
{lightCover ? (
|
||||||
<Image
|
<Image
|
||||||
alt="Cover"
|
alt="Cover"
|
||||||
sources={{
|
sources={{
|
||||||
light: {
|
light: {
|
||||||
src: cover.href,
|
src: lightCover.href,
|
||||||
size: cover.file?.dimensions,
|
size: lightCover.file?.dimensions,
|
||||||
},
|
},
|
||||||
|
dark: darkCover
|
||||||
|
? {
|
||||||
|
src: darkCover.href,
|
||||||
|
size: darkCover.file?.dimensions,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
}}
|
}}
|
||||||
sizes={[
|
sizes={[
|
||||||
{
|
{
|
||||||
@@ -92,8 +95,15 @@ export async function RecordCard(
|
|||||||
'w-full',
|
'w-full',
|
||||||
'h-full',
|
'h-full',
|
||||||
'object-cover',
|
'object-cover',
|
||||||
coverIsSquareOrPortrait
|
lightCoverIsSquareOrPortrait || darkCoverIsSquareOrPortrait
|
||||||
? ['min-[432px]:h-auto', 'min-[432px]:aspect-video']
|
? [
|
||||||
|
lightCoverIsSquareOrPortrait
|
||||||
|
? 'min-[432px]:aspect-video min-[432px]:h-auto'
|
||||||
|
: '',
|
||||||
|
darkCoverIsSquareOrPortrait
|
||||||
|
? 'dark:min-[432px]:aspect-video dark:min-[432px]:h-auto'
|
||||||
|
: '',
|
||||||
|
].filter(Boolean)
|
||||||
: ['h-auto', 'aspect-video']
|
: ['h-auto', 'aspect-video']
|
||||||
)}
|
)}
|
||||||
priority={isOffscreen ? 'lazy' : 'high'}
|
priority={isOffscreen ? 'lazy' : 'high'}
|
||||||
@@ -167,3 +177,16 @@ export async function RecordCard(
|
|||||||
|
|
||||||
return <div className={tcls(RecordCardStyles)}>{body}</div>;
|
return <div className={tcls(RecordCardStyles)}>{body}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a file is square or portrait.
|
||||||
|
*/
|
||||||
|
function isSquareOrPortrait(contentRef: ResolvedContentRef | null) {
|
||||||
|
const file = contentRef?.file;
|
||||||
|
|
||||||
|
if (!file || !file.dimensions) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return file.dimensions?.width / file.dimensions?.height <= 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ import type { TableRecordKV } from './Table';
|
|||||||
import { type VerticalAlignment, getColumnAlignment } from './utils';
|
import { type VerticalAlignment, getColumnAlignment } from './utils';
|
||||||
|
|
||||||
const alignmentMap: Record<'text-left' | 'text-center' | 'text-right', string> = {
|
const alignmentMap: Record<'text-left' | 'text-center' | 'text-right', string> = {
|
||||||
'text-left': '[&_*]:text-left text-left',
|
'text-left': '**:text-left text-left',
|
||||||
'text-center': '[&_*]:text-center text-center',
|
'text-center': '**:text-center text-center',
|
||||||
'text-right': '[&_*]:text-right text-right',
|
'text-right': '**:text-right text-right',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,7 +174,6 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
|
|||||||
<StyledLink
|
<StyledLink
|
||||||
key={index}
|
key={index}
|
||||||
href={ref.href}
|
href={ref.href}
|
||||||
target="_blank"
|
|
||||||
className="flex flex-row items-center gap-2"
|
className="flex flex-row items-center gap-2"
|
||||||
insights={
|
insights={
|
||||||
ref.file
|
ref.file
|
||||||
@@ -193,7 +192,7 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
|
|||||||
>
|
>
|
||||||
{contentType === 'image' ? (
|
{contentType === 'image' ? (
|
||||||
<Image
|
<Image
|
||||||
style={['max-h-[1lh]', 'h-[1lh]']}
|
style={['max-h-lh', 'h-lh']}
|
||||||
alt={ref.text}
|
alt={ref.text}
|
||||||
sizes={[{ width: 24 }]}
|
sizes={[{ width: 24 }]}
|
||||||
resize={context.contentContext?.imageResizer}
|
resize={context.contentContext?.imageResizer}
|
||||||
@@ -314,7 +313,7 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
|
|||||||
className={tcls(
|
className={tcls(
|
||||||
'text-sm',
|
'text-sm',
|
||||||
'whitespace-pre',
|
'whitespace-pre',
|
||||||
'rounded',
|
'rounded-sm',
|
||||||
'py-1',
|
'py-1',
|
||||||
'px-2',
|
'px-2',
|
||||||
'bg-primary',
|
'bg-primary',
|
||||||
@@ -329,6 +328,50 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
|
|||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
case 'image': {
|
||||||
|
const image = context.contentContext
|
||||||
|
? await resolveContentRef(value as ContentRef, context.contentContext)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (!image) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tag className={tcls('text-base')} aria-labelledby={ariaLabelledBy}>
|
||||||
|
<StyledLink
|
||||||
|
href={image.href}
|
||||||
|
className="flex flex-row items-center gap-2"
|
||||||
|
insights={
|
||||||
|
image.file
|
||||||
|
? {
|
||||||
|
type: 'link_click',
|
||||||
|
link: {
|
||||||
|
target: value as ContentRef,
|
||||||
|
position: SiteInsightsLinkPosition.Content,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
style={['max-h-lh', 'h-lh']}
|
||||||
|
alt={image.text}
|
||||||
|
sizes={[{ width: 24 }]}
|
||||||
|
resize={context.contentContext?.imageResizer}
|
||||||
|
sources={{
|
||||||
|
light: {
|
||||||
|
src: image.href,
|
||||||
|
size: image.file?.dimensions,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
priority="lazy"
|
||||||
|
/>
|
||||||
|
{image.text}
|
||||||
|
</StyledLink>
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
assertNever(definition);
|
assertNever(definition);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export const RecordCardStyles = [
|
|||||||
'shadow-1xs',
|
'shadow-1xs',
|
||||||
'shadow-tint-9/1',
|
'shadow-tint-9/1',
|
||||||
'depth-flat:shadow-none',
|
'depth-flat:shadow-none',
|
||||||
'rounded',
|
'rounded-sm',
|
||||||
'straight-corners:rounded-none',
|
'straight-corners:rounded-none',
|
||||||
'circular-corners:rounded-xl',
|
'circular-corners:rounded-xl',
|
||||||
'dark:shadow-transparent',
|
'dark:shadow-transparent',
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@reference "../../RootLayout/globals.css";
|
||||||
|
|
||||||
/* Detect whether a scrollbar exists on the table */
|
/* Detect whether a scrollbar exists on the table */
|
||||||
@keyframes detect-scroll {
|
@keyframes detect-scroll {
|
||||||
from,
|
from,
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
import type { ContentRef, DocumentTableDefinition, DocumentTableRecord } from '@gitbook/api';
|
import type {
|
||||||
|
ContentRef,
|
||||||
|
ContentRefFile,
|
||||||
|
ContentRefURL,
|
||||||
|
DocumentTableDefinition,
|
||||||
|
DocumentTableRecord,
|
||||||
|
DocumentTableViewCards,
|
||||||
|
} from '@gitbook/api';
|
||||||
import assertNever from 'assert-never';
|
import assertNever from 'assert-never';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -12,6 +19,57 @@ export function getRecordValue<T extends number | string | boolean | string[] |
|
|||||||
return record.values[definitionId];
|
return record.values[definitionId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the covers for a record card.
|
||||||
|
* Returns both the light and dark covers.
|
||||||
|
* The light cover is a string or a content ref (image or files column type).
|
||||||
|
* The dark cover is a content ref (image column type).
|
||||||
|
*/
|
||||||
|
export function getRecordCardCovers(
|
||||||
|
record: DocumentTableRecord,
|
||||||
|
view: DocumentTableViewCards
|
||||||
|
): { [key in 'light' | 'dark']: ContentRefFile | ContentRefURL | null } {
|
||||||
|
return {
|
||||||
|
light: (() => {
|
||||||
|
if (!view.coverDefinition) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = getRecordValue(record, view.coverDefinition) as
|
||||||
|
| ContentRefFile
|
||||||
|
| ContentRefURL
|
||||||
|
| string[];
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
if (value.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value[0] === 'string') {
|
||||||
|
return { kind: 'file', file: value[0] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value as ContentRefFile | ContentRefURL;
|
||||||
|
})(),
|
||||||
|
dark: (() => {
|
||||||
|
if (!view.coverDefinitionDark) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = getRecordValue(record, view.coverDefinitionDark) as
|
||||||
|
| ContentRefFile
|
||||||
|
| ContentRefURL;
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
})(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the text alignment for a column.
|
* Get the text alignment for a column.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ export function DynamicTabs(
|
|||||||
<div
|
<div
|
||||||
className={tcls(
|
className={tcls(
|
||||||
'rounded-lg',
|
'rounded-lg',
|
||||||
'straight-corners:rounded-sm',
|
'straight-corners:rounded-xs',
|
||||||
'ring-1',
|
'ring-1',
|
||||||
'ring-inset',
|
'ring-inset',
|
||||||
'ring-tint-subtle',
|
'ring-tint-subtle',
|
||||||
@@ -161,7 +161,7 @@ export function DynamicTabs(
|
|||||||
'inline-flex',
|
'inline-flex',
|
||||||
'flex-row',
|
'flex-row',
|
||||||
'self-stretch',
|
'self-stretch',
|
||||||
'after:flex-[1]',
|
'after:flex-1',
|
||||||
'after:bg-tint-12/1',
|
'after:bg-tint-12/1',
|
||||||
// if last tab is selected, apply rounded to :after element
|
// if last tab is selected, apply rounded to :after element
|
||||||
'[&:has(button.active-tab:last-of-type):after]:rounded-bl-md'
|
'[&:has(button.active-tab:last-of-type):after]:rounded-bl-md'
|
||||||
@@ -180,7 +180,7 @@ export function DynamicTabs(
|
|||||||
'[&:has(+_.active-tab)]:rounded-br-md',
|
'[&:has(+_.active-tab)]:rounded-br-md',
|
||||||
|
|
||||||
//next from active-tab
|
//next from active-tab
|
||||||
'[.active-tab_+_&]:rounded-bl-md',
|
'[.active-tab+&]:rounded-bl-md',
|
||||||
|
|
||||||
//next from active-tab
|
//next from active-tab
|
||||||
'[.active-tab_+_:after]:rounded-br-md',
|
'[.active-tab_+_:after]:rounded-br-md',
|
||||||
@@ -193,7 +193,7 @@ export function DynamicTabs(
|
|||||||
'after:border-tint',
|
'after:border-tint',
|
||||||
'after:top-[15%]',
|
'after:top-[15%]',
|
||||||
'after:h-[70%]',
|
'after:h-[70%]',
|
||||||
'after:w-[1px]',
|
'after:w-px',
|
||||||
|
|
||||||
'px-3.5',
|
'px-3.5',
|
||||||
'py-2',
|
'py-2',
|
||||||
@@ -212,9 +212,9 @@ export function DynamicTabs(
|
|||||||
'active-tab',
|
'active-tab',
|
||||||
'text-tint-strong',
|
'text-tint-strong',
|
||||||
'bg-transparent',
|
'bg-transparent',
|
||||||
'after:[&.active-tab]:border-transparent',
|
'[&.active-tab]:after:border-transparent',
|
||||||
'after:[:has(+_&.active-tab)]:border-transparent',
|
'[:has(+_&.active-tab)]:after:border-transparent',
|
||||||
'after:[:has(&_+)]:border-transparent',
|
'[:has(&_+)]:after:border-transparent',
|
||||||
]
|
]
|
||||||
: null
|
: null
|
||||||
)}
|
)}
|
||||||
@@ -232,7 +232,7 @@ export function DynamicTabs(
|
|||||||
'inline-block',
|
'inline-block',
|
||||||
'text-sm',
|
'text-sm',
|
||||||
'transition-[color]',
|
'transition-[color]',
|
||||||
'font-[500]',
|
'font-medium',
|
||||||
'relative',
|
'relative',
|
||||||
'max-w-full',
|
'max-w-full',
|
||||||
'truncate'
|
'truncate'
|
||||||
|
|||||||
@@ -71,11 +71,7 @@ function Strikethrough(props: MarkedLeafProps<DocumentMarkStrikethrough>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Keyboard(props: MarkedLeafProps<DocumentMarkKeyboard>) {
|
function Keyboard(props: MarkedLeafProps<DocumentMarkKeyboard>) {
|
||||||
return (
|
return <kbd className="rounded-xs border border-b-2 px-1 font-mono">{props.children}</kbd>;
|
||||||
<kbd className="rounded border px-1 font-mono shadow-[0_1px_0_0_theme(borderColor.DEFAULT)]">
|
|
||||||
{props.children}
|
|
||||||
</kbd>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Superscript(props: MarkedLeafProps<DocumentMarkSuperscript>) {
|
function Superscript(props: MarkedLeafProps<DocumentMarkSuperscript>) {
|
||||||
@@ -90,9 +86,9 @@ function Code(props: MarkedLeafProps<DocumentMarkCode>) {
|
|||||||
return (
|
return (
|
||||||
<code
|
<code
|
||||||
className={tcls(
|
className={tcls(
|
||||||
'py-[1px]',
|
'py-px',
|
||||||
'px-1.5',
|
'px-1.5',
|
||||||
'min-w-[1.625rem]',
|
'min-w-6.5',
|
||||||
'justify-center',
|
'justify-center',
|
||||||
'items-center',
|
'items-center',
|
||||||
'leading-normal',
|
'leading-normal',
|
||||||
@@ -100,7 +96,7 @@ function Code(props: MarkedLeafProps<DocumentMarkCode>) {
|
|||||||
'ring-inset',
|
'ring-inset',
|
||||||
'ring-tint',
|
'ring-tint',
|
||||||
'bg-tint',
|
'bg-tint',
|
||||||
'rounded',
|
'rounded-sm',
|
||||||
// Text size is proportional to the font-size of the parent element
|
// Text size is proportional to the font-size of the parent element
|
||||||
'text-[.875em]',
|
'text-[.875em]',
|
||||||
// We ensure that the code is not making the parent bigger, especially in headings
|
// We ensure that the code is not making the parent bigger, especially in headings
|
||||||
@@ -126,7 +122,25 @@ function Color(props: MarkedLeafProps<DocumentMarkColor>) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const textColorToStyle: { [color in DocumentMarkColor['data']['text']]: ClassValue } = {
|
/**
|
||||||
|
* @TODO replace by DocumentMarkColor['data']['text'] and DocumentMarkColor['data']['background']
|
||||||
|
* once the API is updated.
|
||||||
|
*/
|
||||||
|
type DocumentMarkColorValue =
|
||||||
|
| 'default'
|
||||||
|
| 'green'
|
||||||
|
| 'blue'
|
||||||
|
| 'red'
|
||||||
|
| 'orange'
|
||||||
|
| 'yellow'
|
||||||
|
| 'purple'
|
||||||
|
| '$primary'
|
||||||
|
| '$info'
|
||||||
|
| '$success'
|
||||||
|
| '$warning'
|
||||||
|
| '$danger';
|
||||||
|
|
||||||
|
const textColorToStyle: { [color in DocumentMarkColorValue]: ClassValue } = {
|
||||||
default: [],
|
default: [],
|
||||||
blue: ['text-blue-500'],
|
blue: ['text-blue-500'],
|
||||||
red: ['text-red-500'],
|
red: ['text-red-500'],
|
||||||
@@ -134,9 +148,14 @@ const textColorToStyle: { [color in DocumentMarkColor['data']['text']]: ClassVal
|
|||||||
yellow: ['text-yellow-600'],
|
yellow: ['text-yellow-600'],
|
||||||
purple: ['text-purple-500'],
|
purple: ['text-purple-500'],
|
||||||
orange: ['text-orange-500'],
|
orange: ['text-orange-500'],
|
||||||
|
$primary: ['text-primary'],
|
||||||
|
$info: ['text-info'],
|
||||||
|
$success: ['text-success'],
|
||||||
|
$warning: ['text-warning'],
|
||||||
|
$danger: ['text-danger'],
|
||||||
};
|
};
|
||||||
|
|
||||||
const backgroundColorToStyle: { [color in DocumentMarkColor['data']['background']]: ClassValue } = {
|
const backgroundColorToStyle: { [color in DocumentMarkColorValue]: ClassValue } = {
|
||||||
default: [],
|
default: [],
|
||||||
blue: ['bg-mark-blue'],
|
blue: ['bg-mark-blue'],
|
||||||
red: ['bg-mark-red'],
|
red: ['bg-mark-red'],
|
||||||
@@ -144,4 +163,9 @@ const backgroundColorToStyle: { [color in DocumentMarkColor['data']['background'
|
|||||||
yellow: ['bg-mark-yellow'],
|
yellow: ['bg-mark-yellow'],
|
||||||
purple: ['bg-mark-purple'],
|
purple: ['bg-mark-purple'],
|
||||||
orange: ['bg-mark-orange'],
|
orange: ['bg-mark-orange'],
|
||||||
|
$primary: ['bg-primary'],
|
||||||
|
$info: ['bg-info'],
|
||||||
|
$success: ['bg-success'],
|
||||||
|
$warning: ['bg-warning'],
|
||||||
|
$danger: ['bg-danger'],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ export function getBlockTextStyle(block: DocumentBlock): {
|
|||||||
lineHeight: string;
|
lineHeight: string;
|
||||||
/** Tailwind class for the margin top (mt-*) */
|
/** Tailwind class for the margin top (mt-*) */
|
||||||
marginTop?: string;
|
marginTop?: string;
|
||||||
/** Tailwind class for the margin top to apply on the anchor link button */
|
|
||||||
anchorButtonMarginTop?: string;
|
|
||||||
} {
|
} {
|
||||||
switch (block.type) {
|
switch (block.type) {
|
||||||
case 'paragraph':
|
case 'paragraph':
|
||||||
@@ -23,22 +21,19 @@ export function getBlockTextStyle(block: DocumentBlock): {
|
|||||||
return {
|
return {
|
||||||
textSize: 'text-3xl font-semibold',
|
textSize: 'text-3xl font-semibold',
|
||||||
lineHeight: 'leading-tight',
|
lineHeight: 'leading-tight',
|
||||||
marginTop: 'mt-[1em]',
|
marginTop: 'column-first-of-type:pt-0 pt-[1em]',
|
||||||
anchorButtonMarginTop: 'mt-[1.05em]',
|
|
||||||
};
|
};
|
||||||
case 'heading-2':
|
case 'heading-2':
|
||||||
return {
|
return {
|
||||||
textSize: 'text-2xl font-semibold',
|
textSize: 'text-2xl font-semibold',
|
||||||
lineHeight: 'leading-snug',
|
lineHeight: 'leading-snug',
|
||||||
marginTop: 'mt-[0.75em]',
|
marginTop: 'column-first-of-type:pt-0 pt-[0.75em]',
|
||||||
anchorButtonMarginTop: 'mt-[0.9em]',
|
|
||||||
};
|
};
|
||||||
case 'heading-3':
|
case 'heading-3':
|
||||||
return {
|
return {
|
||||||
textSize: 'text-xl font-semibold',
|
textSize: 'text-xl font-semibold',
|
||||||
lineHeight: 'leading-snug',
|
lineHeight: 'leading-snug',
|
||||||
marginTop: 'mt-[0.5em]',
|
marginTop: 'column-first-of-type:pt-0 pt-[0.5em]',
|
||||||
anchorButtonMarginTop: 'mt-[0.65em]',
|
|
||||||
};
|
};
|
||||||
case 'divider':
|
case 'divider':
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -36,16 +36,16 @@ export function Footer(props: { context: GitBookSiteContext }) {
|
|||||||
<div className={tcls(CONTAINER_STYLE, 'px-4', 'py-8', 'lg:py-12', 'mx-auto')}>
|
<div className={tcls(CONTAINER_STYLE, 'px-4', 'py-8', 'lg:py-12', 'mx-auto')}>
|
||||||
<div
|
<div
|
||||||
className={tcls(
|
className={tcls(
|
||||||
'lg:!max-w-none mx-auto grid max-w-3xl site-full-width:max-w-screen-2xl justify-between gap-12',
|
'mx-auto grid max-w-3xl site-width-wide:max-w-screen-2xl justify-between gap-12 lg:max-w-none!',
|
||||||
'grid-cols-[auto_auto]',
|
'grid-cols-[auto_auto]',
|
||||||
'lg:grid-cols-[18rem_minmax(auto,_48rem)_auto]',
|
'lg:grid-cols-[18rem_minmax(auto,48rem)_auto]',
|
||||||
'xl:grid-cols-[18rem_minmax(auto,_48rem)_14rem]',
|
'xl:grid-cols-[18rem_minmax(auto,48rem)_14rem]',
|
||||||
'site-full-width:lg:grid-cols-[18rem_minmax(auto,_80rem)_auto]',
|
'lg:site-width-wide:grid-cols-[18rem_minmax(auto,80rem)_auto]',
|
||||||
'site-full-width:xl:grid-cols-[18rem_minmax(auto,_80rem)_14rem]',
|
'xl:site-width-wide:grid-cols-[18rem_minmax(auto,80rem)_14rem]',
|
||||||
'page-no-toc:lg:grid-cols-[minmax(auto,_48rem)_auto]',
|
'lg:page-no-toc:grid-cols-[minmax(auto,48rem)_auto]',
|
||||||
'page-no-toc:xl:grid-cols-[14rem_minmax(auto,_48rem)_14rem]',
|
'xl:page-no-toc:grid-cols-[14rem_minmax(auto,48rem)_14rem]',
|
||||||
'[body:has(.site-full-width,.page-no-toc)_&]:lg:grid-cols-[minmax(auto,_90rem)_auto]',
|
'lg:[body:has(.site-width-wide,.page-no-toc)_&]:grid-cols-[minmax(auto,90rem)_auto]',
|
||||||
'[body:has(.site-full-width,.page-no-toc)_&]:xl:grid-cols-[14rem_minmax(auto,_90rem)_14rem]'
|
'xl:[body:has(.site-width-wide,.page-no-toc)_&]:grid-cols-[14rem_minmax(auto,90rem)_14rem]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
@@ -74,8 +74,8 @@ export function Footer(props: { context: GitBookSiteContext }) {
|
|||||||
'lg:max-h-12',
|
'lg:max-h-12',
|
||||||
'object-contain',
|
'object-contain',
|
||||||
'object-left',
|
'object-left',
|
||||||
'rounded',
|
'rounded-sm',
|
||||||
'straight-corners:rounded-sm',
|
'straight-corners:rounded-xs',
|
||||||
]}
|
]}
|
||||||
sizes={[
|
sizes={[
|
||||||
{
|
{
|
||||||
@@ -103,10 +103,10 @@ export function Footer(props: { context: GitBookSiteContext }) {
|
|||||||
customization.footer.groups?.length > 0 ? (
|
customization.footer.groups?.length > 0 ? (
|
||||||
<div
|
<div
|
||||||
className={tcls(
|
className={tcls(
|
||||||
'col-span-2 page-has-toc:lg:col-span-1 page-has-toc:lg:col-start-2 page-no-toc:xl:col-span-1 page-no-toc:xl:col-start-2'
|
'col-span-2 lg:page-has-toc:col-span-1 lg:page-has-toc:col-start-2 xl:page-no-toc:col-span-1 xl:page-no-toc:col-start-2'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="mx-auto flex max-w-3xl site-full-width:max-w-screen-2xl flex-col gap-10 sm:flex-row sm:gap-6">
|
<div className="mx-auto flex max-w-3xl site-width-wide:max-w-screen-2xl flex-col gap-10 sm:flex-row sm:gap-6">
|
||||||
{partition(customization.footer.groups, FOOTER_COLUMNS).map(
|
{partition(customization.footer.groups, FOOTER_COLUMNS).map(
|
||||||
(column, columnIndex) => (
|
(column, columnIndex) => (
|
||||||
<div
|
<div
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user