├── .eslintrc.js ├── .github └── CODEOWNERS ├── .gitignore ├── .prettierignore ├── .prettierrc ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── bin ├── commands.sh └── postbuild.js ├── gatsby-browser.js ├── gatsby-config.js ├── gatsby-node.js ├── gatsby-ssr.js ├── package-lock.json ├── package.json ├── src ├── components │ ├── accessible-svg.js │ ├── architecture-diagram.js │ ├── breadcrumbs.js │ ├── browser-resize-tracking.js │ ├── cloudflare-logo.js │ ├── code-block.js │ ├── docs-code-examples-overview.js │ ├── docs-footer.js │ ├── docs-mobile-title-header.js │ ├── docs-nav-logo-lockup.js │ ├── docs-page.js │ ├── docs-product-logo.js │ ├── docs-search.js │ ├── docs-sidebar-more-dropdown.js │ ├── docs-sidebar-nav-data.js │ ├── docs-sidebar-nav-item.js │ ├── docs-sidebar-nav-section.js │ ├── docs-sidebar-nav.js │ ├── docs-sidebar-title-section.js │ ├── docs-sidebar.js │ ├── docs-table-of-contents.js │ ├── docs-title.js │ ├── docs-toolbar.js │ ├── docs-tutorials.js │ ├── dropdown.js │ ├── handle-mobile-page-navigations.js │ ├── icons │ │ ├── base.js │ │ ├── external-link.js │ │ └── nav-menu.js │ ├── mdx-custom-renderer.js │ ├── mdx │ │ ├── anchor-link.js │ │ ├── aside.js │ │ ├── button-group.js │ │ ├── button.js │ │ ├── code-block.js │ │ ├── code.js │ │ ├── content-column.js │ │ ├── custom-syntax-highlighting.js │ │ ├── definitions.js │ │ ├── demo.js │ │ ├── directory-listing.js │ │ ├── example.js │ │ ├── headers.js │ │ ├── inline-code.js │ │ ├── param-type.js │ │ ├── prop-meta.js │ │ ├── root.js │ │ ├── stream-video.js │ │ ├── table-wrap.js │ │ ├── type-link.js │ │ ├── type.js │ │ └── youtube.js │ ├── network-map.js │ ├── scrollbars-with-scroll-shadows.js │ ├── seo.js │ ├── smooth-scroll-hash-changes.js │ ├── theme-toggle.js │ └── worker-starter.js ├── constants │ └── sidebar-collapse-transition-duration.js ├── css │ └── docs │ │ └── components │ │ ├── architecture-diagram.css │ │ ├── docs-body.css │ │ ├── docs-code-examples-overview.css │ │ ├── docs-content.css │ │ ├── docs-footer.css │ │ ├── docs-markdown.css │ │ ├── docs-mobile-header.css │ │ ├── docs-mobile-nav-backdrop.css │ │ ├── docs-mobile-title-header.css │ │ ├── docs-nav-logo-lockup.css │ │ ├── docs-noscript.css │ │ ├── docs-page.css │ │ ├── docs-search.css │ │ ├── docs-sidebar.css │ │ ├── docs-table-of-contents.css │ │ ├── docs-toolbar.css │ │ ├── docs-tutorials.css │ │ ├── skip-nav-link.css │ │ ├── tags-filter.css │ │ └── worker-starter.css ├── html.js ├── images │ └── cloudflare-icon.png ├── pages │ └── 404.js └── utils │ ├── animate.js │ ├── generate-nav-tree.js │ ├── get-breadcrumbs.js │ ├── get-cloudflare-docs-config.js │ ├── get-normalized-path.js │ ├── get-order.js │ ├── get-page-by-path.js │ ├── get-page-title.js │ ├── get-page-type.js │ ├── get-parent-path.js │ ├── get-path-prefix.js │ ├── get-table-of-contents.js │ ├── get-unique-readable-id.js │ ├── google-analytics.js │ ├── has-breadcrumbs.js │ ├── is-mobile.js │ ├── mobile-sidebar-manipulation.js │ └── user-prefers-reduced-motion.js └── workers-site ├── .cargo-ok ├── .gitignore ├── index.js ├── package-lock.json └── package.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | globals: { 3 | __PATH_PREFIX__: true, 4 | }, 5 | extends: `react-app`, 6 | "rules": { 7 | /* Don’t require for proxy elements in https://github.com/nfl/react-helmet */ 8 | "jsx-a11y/html-has-lang": 0 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | src/ @adamschwartz 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # TODO 2 | TODO 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | *.pid.lock 16 | 17 | # Directory for instrumented libs generated by jscoverage/JSCover 18 | lib-cov 19 | 20 | # Coverage directory used by tools like istanbul 21 | coverage 22 | 23 | # nyc test coverage 24 | .nyc_output 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # Bower dependency directory (https://bower.io/) 30 | bower_components 31 | 32 | # node-waf configuration 33 | .lock-wscript 34 | 35 | # Compiled binary addons (http://nodejs.org/api/addons.html) 36 | build/Release 37 | 38 | # Dependency directories 39 | node_modules/ 40 | jspm_packages/ 41 | 42 | # TypeScript v1 declaration files 43 | typings/ 44 | 45 | # Optional npm cache directory 46 | .npm 47 | 48 | # Optional eslint cache 49 | .eslintcache 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | # Output of 'npm pack' 55 | *.tgz 56 | 57 | # dotenv environment variable files 58 | .env* 59 | 60 | # gatsby files 61 | .cache/ 62 | public 63 | 64 | # Mac files 65 | .DS_Store 66 | 67 | # Yarn 68 | yarn-error.log 69 | .pnp/ 70 | .pnp.js 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # Workers dist 76 | dist/ 77 | 78 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .cache 2 | package.json 3 | package-lock.json 4 | public 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Cloudflare 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cloudflare Docs Engine 2 | 3 | Cloudflare’s open-source tool for building documentation. 4 | 5 | https://developers.cloudflare.com/docs-engine 6 | 7 | ## Known issues 8 | 9 | - [@gatsbyjs/gatsby#17506](https://github.com/gatsbyjs/gatsby/issues/17506) Console warning about `lazy=load` images missing dimensions. This is a known issue in Gatsby and the [recommendation as of Sept, 2019](https://github.com/gatsbyjs/gatsby/issues/17506#issuecomment-529904482) is to ignore it. 10 | - Hard page loads with hashes don’t start scrolled when developing locally (e.g. `http://localhost:8000/#docs-content`). 11 | -------------------------------------------------------------------------------- /bin/commands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | realpath() { 5 | [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" 6 | } 7 | 8 | 9 | docs_engine_path=$(dirname $(dirname $(realpath "$0"))) 10 | parent_path=$(dirname $docs_engine_path) 11 | parent_folder_name=$(basename $parent_path) 12 | 13 | if [ "$parent_folder_name" != "node_modules" ]; then 14 | echo "Failed: expected the Cloudflare docs enginee to be inside node_modules" 15 | exit 16 | fi 17 | 18 | project_path=$(dirname $(dirname $docs_engine_path)) 19 | 20 | 21 | if [ "$1" = "ghactionsbootstrap" ]; then 22 | cd $project_path 23 | 24 | echo "Deleting .docs" 25 | rm -rf .docs 26 | 27 | echo "Creating .docs directory" 28 | mkdir .docs 29 | 30 | echo "Moving cloudflare-docs-engine files into .docs" 31 | cp -r node_modules/cloudflare-docs-engine/* .docs 32 | 33 | echo "Entering .docs" 34 | cd .docs 35 | 36 | echo "Running npm install inside .docs" 37 | npm install 38 | fi 39 | 40 | 41 | if [ "$1" = "bootstrap" ]; then 42 | cd $project_path 43 | 44 | echo "Deleting .docs" 45 | rm -rf .docs 46 | 47 | echo "Moving cloudflare-docs-engine files into .docs" 48 | cp -r node_modules/cloudflare-docs-engine/ .docs 49 | 50 | echo "Entering .docs" 51 | cd .docs 52 | 53 | echo "Removing existing node_modules (local npm link case)" 54 | rm -rf node_modules/ 55 | 56 | echo "Running npm install inside .docs" 57 | npm install 58 | fi 59 | 60 | 61 | copysrc() { 62 | cd $project_path 63 | 64 | echo "Entering .docs" 65 | cd .docs 66 | 67 | echo "Copying docs-config.js into .docs" 68 | cp -r ../docs-config.js ./ 69 | 70 | if [ -e ../static ]; then 71 | echo "Copying static into .docs" 72 | cp -r ../static ./ 73 | fi 74 | 75 | echo "Entering .docs/src/" 76 | cd src 77 | 78 | echo "Copying content into .docs/src/" 79 | cp -r ../../src/content ./ 80 | } 81 | 82 | 83 | if [ "$1" = "develop" ]; then 84 | copysrc 85 | 86 | cd $project_path 87 | 88 | echo "Entering .docs" 89 | cd .docs 90 | 91 | echo "Running npm run clean" 92 | npm run clean 93 | 94 | echo "Running npm run develop" 95 | npm run develop -- "${@:2}" 96 | fi 97 | 98 | 99 | if [ "$1" = "build" ]; then 100 | copysrc 101 | 102 | cd $project_path 103 | 104 | echo "Entering .docs" 105 | cd .docs 106 | 107 | echo "Running npm run build" 108 | npm run build -- "${@:2}" 109 | 110 | # We must run from inside `.docs/` 111 | echo "Running bin/postbuild.js" 112 | node bin/postbuild.js 113 | fi 114 | 115 | 116 | if [ "$1" = "serve" ]; then 117 | cd $project_path 118 | 119 | echo "Entering .docs" 120 | cd .docs 121 | 122 | echo "Running npm run serve" 123 | npm run serve -- "${@:2}" 124 | fi 125 | 126 | 127 | if [ "$1" = "savechanges" ]; then 128 | cd $project_path 129 | 130 | cp -r .docs/src/content/ src/content/ 131 | fi 132 | -------------------------------------------------------------------------------- /bin/postbuild.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | const { exec } = require("child_process") 3 | const { pathPrefix } = require("../docs-config.js") 4 | 5 | console.log("Running postbuild.js") 6 | 7 | if (!pathPrefix && pathPrefix !== "") { 8 | console.error(`docs-config.js must have a pathPrefix set`) 9 | } 10 | 11 | if (pathPrefix.length && !pathPrefix.startsWith("/")) { 12 | console.error(`docs-config.js pathPrefix must start with a forward slash "/"`) 13 | return 14 | } 15 | 16 | const handleExec = (completed) => { 17 | return (error, stdout, stderr) => { 18 | if (error) { 19 | console.error(error) 20 | 21 | } else { 22 | const trimmedStdout = stdout.trim() 23 | if (trimmedStdout) console.log(trimmedStdout) 24 | 25 | const trimmedStderr = stderr.trim() 26 | if (trimmedStderr) console.log(trimmedStderr) 27 | 28 | completed() 29 | } 30 | } 31 | } 32 | 33 | const robots = `User-agent: *\nDisallow: /` 34 | 35 | if (pathPrefix !== "") { 36 | // We are running from inside `.docs/` 37 | const dir = "$PWD/" 38 | const folderName = pathPrefix.substr(1) 39 | 40 | exec(`mv "${dir}public" "${dir}${folderName}"`, handleExec(() => { 41 | exec(`mkdir "${dir}public"`, handleExec(() => { 42 | exec(`mv "${dir}${folderName}" "${dir}public/"`, handleExec(() => { 43 | console.log("Completed postbuild") 44 | if (process.env.WORKERS_ENV && process.env.WORKERS_ENV === "development") { 45 | console.log("Building robots.txt for development environment") 46 | fs.writeFile(`${process.env.PWD}/public/robots.txt`, robots, err => err && console.error(err)) 47 | } 48 | })) 49 | })) 50 | })) 51 | } 52 | -------------------------------------------------------------------------------- /gatsby-browser.js: -------------------------------------------------------------------------------- 1 | // See: https://www.gatsbyjs.org/docs/browser-apis/ 2 | 3 | // Required until wider support 4 | // https://caniuse.com/#search=focus-visible 5 | import "focus-visible-polyfill" 6 | 7 | import "@cloudflare/cloudflare-brand-assets/css/global/box-sizing.css" 8 | import "@cloudflare/cloudflare-brand-assets/css/global/element-normalization.css" 9 | import "@cloudflare/cloudflare-brand-assets/css/global/sizes-variables.css" 10 | import "@cloudflare/cloudflare-brand-assets/css/global/font-variables.css" 11 | import "@cloudflare/cloudflare-brand-assets/css/global/brand-color-variables.css" 12 | import "@cloudflare/cloudflare-brand-assets/css/global/theme-color-variables.css" 13 | import "@cloudflare/cloudflare-brand-assets/css/global/theme-helpers.css" 14 | import "@cloudflare/cloudflare-brand-assets/css/global/selection-color.css" 15 | import "@cloudflare/cloudflare-brand-assets/css/global/html.css" 16 | 17 | import "@cloudflare/cloudflare-brand-assets/css/helpers/desktop-and-mobile-only.css" 18 | import "@cloudflare/cloudflare-brand-assets/css/helpers/is-smooth-scrolling.css" 19 | import "@cloudflare/cloudflare-brand-assets/css/helpers/is-visually-hidden.css" 20 | import "@cloudflare/cloudflare-brand-assets/css/helpers/with-styled-webkit-scrollbars.css" 21 | 22 | // TODO: should these be imported by their respective components? 23 | import "@cloudflare/cloudflare-brand-assets/css/components/aspect-ratio.css" 24 | import "@cloudflare/cloudflare-brand-assets/css/components/breadcrumbs.css" 25 | import "@cloudflare/cloudflare-brand-assets/css/components/button.css" 26 | import "@cloudflare/cloudflare-brand-assets/css/components/cloudflare-logo.css" 27 | import "@cloudflare/cloudflare-brand-assets/css/components/cloudflare-workers-logo.css" 28 | import "@cloudflare/cloudflare-brand-assets/css/components/code-block.css" 29 | import "@cloudflare/cloudflare-brand-assets/css/components/theme-toggle.css" 30 | import "@cloudflare/cloudflare-brand-assets/css/components/dropdown.css" 31 | import "@cloudflare/cloudflare-brand-assets/css/components/inline-code.css" 32 | import "@cloudflare/cloudflare-brand-assets/css/components/link.css" 33 | import "@cloudflare/cloudflare-brand-assets/css/components/network-map.css" 34 | import "@cloudflare/cloudflare-brand-assets/css/components/scrollbars.css" 35 | import "@cloudflare/cloudflare-brand-assets/css/components/stream-video.css" 36 | import "@cloudflare/cloudflare-brand-assets/css/components/superscript.css" 37 | import "@cloudflare/cloudflare-brand-assets/css/components/tooltip.css" 38 | 39 | // TODO: should these be imported by their respective components? 40 | import "./src/css/docs/components/skip-nav-link.css" 41 | import "./src/css/docs/components/tags-filter.css" 42 | import "./src/css/docs/components/worker-starter.css" 43 | import "./src/css/docs/components/architecture-diagram.css" 44 | import "./src/css/docs/components/docs-noscript.css" 45 | import "./src/css/docs/components/docs-nav-logo-lockup.css" 46 | import "./src/css/docs/components/docs-page.css" 47 | import "./src/css/docs/components/docs-sidebar.css" 48 | import "./src/css/docs/components/docs-body.css" 49 | import "./src/css/docs/components/docs-table-of-contents.css" 50 | import "./src/css/docs/components/docs-content.css" 51 | import "./src/css/docs/components/docs-markdown.css" 52 | import "./src/css/docs/components/docs-toolbar.css" 53 | import "./src/css/docs/components/docs-search.css" 54 | import "./src/css/docs/components/docs-mobile-title-header.css" 55 | import "./src/css/docs/components/docs-mobile-nav-backdrop.css" 56 | import "./src/css/docs/components/docs-footer.css" 57 | import "./src/css/docs/components/docs-code-examples-overview.css" 58 | import "./src/css/docs/components/docs-tutorials.css" 59 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | const docsConfig = require("./docs-config.js") 2 | 3 | const isProduction = process.env.NODE_ENV === "production" 4 | 5 | const getProduct = (name) => { 6 | const repo = "@cloudflare/cloudflare-brand-assets" 7 | const dir = "resources/product-icons/" 8 | return `./node_modules/${repo}/${dir}/${name}.js` 9 | } 10 | 11 | const products = [ 12 | "1.1.1.1", 13 | "access", 14 | "analytics", 15 | "api", 16 | "automatic-platform-optimization", 17 | "argo-tunnel", 18 | "bots", 19 | "byoip", 20 | "cache", 21 | "client-ip-geolocation", 22 | "cloudflare-for-teams", 23 | "cloudflare-one", 24 | "distributed-web", 25 | "docs-engine", 26 | "events", 27 | "firewall", 28 | "fundamentals", 29 | "gateway", 30 | "http3", 31 | "images", 32 | "load-balancing", 33 | "logs", 34 | "magic-transit", 35 | "magic-wan", 36 | "mobile-sdk", 37 | "network-interconnect", 38 | "page-shield", 39 | "railgun", 40 | "randomness-beacon", 41 | "registrar", 42 | "rules", 43 | "spectrum", 44 | "ssl", 45 | "stream", 46 | "tenant", 47 | "terraform", 48 | "time-services", 49 | "waf", 50 | "waiting-room", 51 | "warp-client", 52 | "workers", 53 | ] 54 | 55 | const productIcons = {} 56 | products.forEach(name => { 57 | productIcons[name] = require(getProduct(name)).pathD 58 | }) 59 | 60 | if (docsConfig.productLogoPathD && docsConfig.productIconKey) { 61 | return Error("Set either `productLogoPathD` or `productIconKey` in docs-config.js, not both") 62 | } 63 | 64 | if (docsConfig.productIconKey) { 65 | docsConfig.productLogoPathD = productIcons[docsConfig.productIconKey] 66 | } 67 | 68 | const siteMetadata = docsConfig.siteMetadata 69 | siteMetadata.cloudflareDocs = {} 70 | Object.keys(docsConfig).forEach(prop => { 71 | if (prop === "siteMetadata") return 72 | siteMetadata.cloudflareDocs[prop] = docsConfig[prop] 73 | }) 74 | 75 | siteMetadata.cloudflareDocs.productIcons = productIcons 76 | 77 | // We exposed friendlier siteMetadata.url to Docs consumers but 78 | // gatsby-plugin-sitemap requires `siteUrl` https://git.io/JUUxW 79 | siteMetadata.siteUrl = siteMetadata.url 80 | delete siteMetadata.url 81 | 82 | module.exports = { 83 | // Deploy production site to the docs config pathPrefix 84 | // but keep local development done at the root due to: 85 | // https://github.com/gatsbyjs/gatsby/issues/16040 86 | pathPrefix: isProduction ? docsConfig.pathPrefix : "", 87 | siteMetadata: siteMetadata, 88 | 89 | plugins: [ 90 | "gatsby-plugin-eslint", 91 | "gatsby-plugin-no-sourcemaps", 92 | "gatsby-plugin-react-helmet", 93 | "gatsby-transformer-sharp", 94 | "gatsby-plugin-sharp", 95 | "gatsby-plugin-remove-trailing-slashes", 96 | 97 | // Sets page.updatedAt to the author time of last commit (https://git.io/JfPCj) 98 | "saber-plugin-git-modification-time", 99 | 100 | // Custom sitemap configuration that fixes prefix issues 101 | { 102 | resolve: `gatsby-plugin-sitemap`, 103 | options: { 104 | resolveSiteUrl: () => new URL(siteMetadata.siteUrl).origin, 105 | }, 106 | }, 107 | 108 | // Prevent nav from (un)mounting on page navigations (https://git.io/JfOKn) 109 | { 110 | resolve: "gatsby-plugin-layout", 111 | options: { 112 | component: require.resolve("./src/components/docs-page.js") 113 | } 114 | }, 115 | { 116 | resolve: "gatsby-source-filesystem", 117 | options: { 118 | path: `${__dirname}/src/content/` 119 | } 120 | }, 121 | { 122 | resolve: "gatsby-plugin-mdx", 123 | options: { 124 | extensions: [".mdx", ".md"], 125 | gatsbyRemarkPlugins: [ 126 | { 127 | resolve: "gatsby-remark-images", 128 | options: { 129 | maxWidth: 1382, 130 | disableBgImageOnAlpha: true 131 | }, 132 | }, 133 | // Copies linked files from Markdown to public directory (ie for gifs) 134 | `gatsby-remark-copy-linked-files`, 135 | ], 136 | remarkPlugins: [require("remark-slug")] 137 | } 138 | }, 139 | { 140 | resolve: "gatsby-plugin-material-ui", 141 | options: { 142 | stylesProvider: { 143 | disableGeneration: true 144 | }, 145 | }, 146 | }, 147 | { 148 | resolve: "gatsby-plugin-manifest", 149 | options: { 150 | name: "Cloudflare docs", 151 | short_name: "Docs", 152 | start_url: "/", 153 | background_color: "#f38020", 154 | theme_color: "#f38020", 155 | display: "minimal-ui" 156 | // icon: "src/images/cloudflare-icon.png" 157 | } 158 | }, 159 | // Consider enabling for PWA + offline functionality 160 | // https://gatsby.dev/offline 161 | // 'gatsby-plugin-offline', 162 | ], 163 | } 164 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | // See: https://www.gatsbyjs.org/docs/node-apis/ 2 | 3 | // https://www.gatsbyjs.org/docs/add-custom-webpack-config/ 4 | exports.onCreateWebpackConfig = ({ 5 | getConfig, 6 | actions, 7 | plugins, 8 | }) => { 9 | const config = getConfig() 10 | 11 | // Hides "[HMR] ..." logs in devtools 12 | if (config.entry.commons) { 13 | config.entry.commons = config.entry.commons.map(path => ( 14 | // Add query param to entry added by Gatsby CLI https://git.io/JvAC5 15 | path.indexOf('/webpack-hot-middleware/client.js?') > -1 ? 16 | path + '&quiet=true' : path 17 | )) 18 | } 19 | 20 | actions.replaceWebpackConfig(config) 21 | 22 | actions.setWebpackConfig({ 23 | plugins: [ 24 | // Hides React Devtools advertisement in devtools 25 | // https://tinyurl.com/hide-react-devtools-advert 26 | plugins.define({ 27 | __REACT_DEVTOOLS_GLOBAL_HOOK__: "({ isDisabled: true })" 28 | }) 29 | ] 30 | }) 31 | } 32 | 33 | 34 | const { createFilePath } = require("gatsby-source-filesystem") 35 | 36 | exports.onCreateNode = ({ node, actions, getNode }) => { 37 | const { createNodeField } = actions 38 | 39 | if (node.internal.type.toLowerCase() === "mdx") { 40 | const value = createFilePath({ node, getNode }).replace(/(.+)(\/)$/, "$1") 41 | 42 | createNodeField({ 43 | name: "slug", 44 | node, 45 | value 46 | }) 47 | } 48 | } 49 | 50 | 51 | const path = require("path") 52 | 53 | exports.createPages = async ({ graphql, actions, reporter }) => { 54 | const { createPage } = actions 55 | 56 | const result = await graphql(` 57 | query { 58 | allMdx { 59 | edges { 60 | node { 61 | id 62 | fields { 63 | slug 64 | } 65 | frontmatter { 66 | title 67 | type 68 | order 69 | hidden 70 | hideChildren 71 | breadcrumbs 72 | } 73 | headings(depth: h1) { 74 | value 75 | depth 76 | } 77 | tableOfContents 78 | parent { 79 | ... on File { 80 | modifiedTime(formatString: "YYYY-MM-DD") 81 | relativePath 82 | } 83 | } 84 | } 85 | } 86 | } 87 | } 88 | `) 89 | 90 | if (result.errors) { 91 | reporter.panicOnBuild('ERROR: Loading "createPages" query') 92 | } 93 | 94 | const pages = result.data.allMdx.edges 95 | 96 | pages.forEach(({ node }) => { 97 | createPage({ 98 | path: node.fields.slug, 99 | component: path.resolve("./src/components/mdx-custom-renderer.js"), 100 | context: node 101 | }) 102 | }) 103 | } 104 | 105 | // We implement type definitions in order to prevent 106 | // Gatsby from erroring that it can’t infer the type 107 | // of a GraphQL-queried frontmatter property when 108 | // there are no md(x) files currently using it. 109 | // https://www.gatsbyjs.org/docs/schema-customization/#creating-type-definitions 110 | exports.createSchemaCustomization = ({ actions }) => { 111 | const { createTypes } = actions 112 | 113 | const typeDefs = ` 114 | type Mdx implements Node { 115 | frontmatter: Frontmatter 116 | } 117 | 118 | type Frontmatter { 119 | demo: String 120 | breadcrumbs: Boolean 121 | difficulty: String 122 | hidden: Boolean 123 | hideChildren: Boolean 124 | order: Int 125 | summary: String 126 | tags: [String] 127 | title: String 128 | type: String 129 | updated: Date @dateformat 130 | } 131 | 132 | type Site { 133 | pathPrefix: String 134 | } 135 | ` 136 | 137 | createTypes(typeDefs) 138 | } 139 | -------------------------------------------------------------------------------- /gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's SSR (Server Side Rendering) APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/ssr-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudflare-docs-engine", 3 | "private": true, 4 | "description": "Cloudflare Workers documentation engine", 5 | "version": "0.1.0", 6 | "author": "Cloudflare ", 7 | "dependencies": { 8 | "@adaptivelink/pops": "0.2.10", 9 | "@cloudflare/cloudflare-brand-assets": "^4.7.7", 10 | "@material-ui/core": "4.11.0", 11 | "@mdx-js/mdx": "1.6.6", 12 | "@mdx-js/react": "1.6.6", 13 | "@reach/skip-nav": "0.10.5", 14 | "animejs": "3.2.0", 15 | "focus-group": "0.3.1", 16 | "focus-visible-polyfill": "1.0.0", 17 | "gatsby": "2.24.7", 18 | "gatsby-image": "2.4.13", 19 | "gatsby-plugin-layout": "1.3.10", 20 | "gatsby-plugin-manifest": "2.4.18", 21 | "gatsby-plugin-material-ui": "2.1.9", 22 | "gatsby-plugin-mdx": "1.2.25", 23 | "gatsby-plugin-no-sourcemaps": "2.2.0", 24 | "gatsby-plugin-offline": "3.2.17", 25 | "gatsby-plugin-react-helmet": "3.3.10", 26 | "gatsby-plugin-sharp": "2.6.19", 27 | "gatsby-plugin-sitemap": "2.4.11", 28 | "gatsby-remark-copy-linked-files": "2.3.9", 29 | "gatsby-remark-images": "3.3.18", 30 | "gatsby-source-filesystem": "2.3.19", 31 | "gatsby-transformer-remark": "2.8.22", 32 | "gatsby-transformer-sharp": "2.5.11", 33 | "graphql": "14.7.0", 34 | "gray-matter": "4.0.2", 35 | "prism-react-renderer": "1.1.1", 36 | "prismjs": "1.21.0", 37 | "prop-types": "15.7.2", 38 | "react": "16.13.1", 39 | "react-copy-to-clipboard": "5.0.2", 40 | "react-custom-scrollbars": "4.2.1", 41 | "react-dom": "16.13.1", 42 | "react-helmet": "6.1.0", 43 | "react-spring": "8.0.27", 44 | "react-timeago": "4.4.0", 45 | "react-transition-group": "4.4.1", 46 | "remark-slug": "6.0.0", 47 | "saber-plugin-git-modification-time": "0.1.3", 48 | "set-interval-visible": "2.0.0" 49 | }, 50 | "engines": { 51 | "node": ">=12.0.0" 52 | }, 53 | "devDependencies": { 54 | "eslint-config-react-app": "5.2.1", 55 | "gatsby-plugin-eslint": "2.0.8", 56 | "gatsby-plugin-remove-trailing-slashes": "2.3.11", 57 | "prettier": "1.19.1" 58 | }, 59 | "license": "Apache-2.0 OR MIT", 60 | "scripts": { 61 | "build": "npm run clean && gatsby build --prefix-paths", 62 | "build:incremental": "GATSBY_EXPERIMENTAL_PAGE_BUILD_ON_DATA_CHANGES=true gatsby build --log-pages --prefix-paths", 63 | "clean": "gatsby clean", 64 | "develop": "gatsby develop -H 0.0.0.0", 65 | "format": "prettier --write \"**/*.{js,jsx,json,md}\"", 66 | "publish": "npm run build && wrangler publish", 67 | "serve": "gatsby serve", 68 | "start": "npm run develop" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/components/accessible-svg.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | 4 | import getUniqueReadableID from "../utils/get-unique-readable-id" 5 | 6 | const AccessibleSVG = props => { 7 | const titleID = getUniqueReadableID("title") 8 | const { title, children, ...svgProps } = props 9 | 10 | return ( 11 | 12 | {title} 13 | {children} 14 | 15 | ) 16 | } 17 | 18 | AccessibleSVG.defaultProps = { 19 | fill: "currentColor", 20 | role: "img" 21 | } 22 | 23 | AccessibleSVG.propTypes = { 24 | title: PropTypes.string.isRequired 25 | } 26 | 27 | export default AccessibleSVG 28 | -------------------------------------------------------------------------------- /src/components/architecture-diagram.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | const ArchitectureDiagram = (props) => { 4 | return ( 5 | <> 6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | 47 |
Traditional architecture
48 |
49 | 50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | 90 |
Workers V8 isolates
91 |
92 | 93 |
94 |
95 |
96 |
97 |
User code
98 |
99 |
100 |
101 |
102 |
103 |
Process overhead
104 |
105 |
106 |
107 |
108 | 109 | ) 110 | } 111 | 112 | export default ArchitectureDiagram 113 | -------------------------------------------------------------------------------- /src/components/breadcrumbs.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link, useStaticQuery, graphql } from "gatsby" 3 | 4 | import getBreadcrumbs from "../utils/get-breadcrumbs" 5 | 6 | const Item = ({ item }) => ( 7 |
  • 8 | 9 | {item.title} 10 | 11 | 12 | {Array.isArray(item.items) && ( 13 | 18 | )} 19 |
  • 20 | ) 21 | 22 | const Breadcrumbs = props => { 23 | const query = useStaticQuery(graphql` 24 | query { 25 | allMdx { 26 | edges { 27 | node { 28 | id 29 | parent { 30 | id 31 | } 32 | fields { 33 | slug 34 | } 35 | frontmatter { 36 | title 37 | } 38 | headings(depth: h1) { 39 | value 40 | depth 41 | } 42 | } 43 | } 44 | } 45 | } 46 | `) 47 | 48 | const pages = query.allMdx.edges 49 | .map(({ node }) => node) 50 | 51 | const { className, location } = props 52 | const breadcrumbs = getBreadcrumbs(pages, location) 53 | 54 | return breadcrumbs.length ? ( 55 |
    56 | 61 |
    62 | ) : null 63 | } 64 | 65 | Breadcrumbs.defaultProps = { 66 | className: "Breadcrumbs---wrapper" 67 | } 68 | 69 | export default Breadcrumbs 70 | -------------------------------------------------------------------------------- /src/components/browser-resize-tracking.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | const attr = "is-resizing" 4 | 5 | class SmoothBrowserResizing extends React.Component { 6 | 7 | constructor(props) { 8 | super(props) 9 | 10 | this.handleWindowResize = this.handleWindowResize.bind(this) 11 | } 12 | 13 | componentDidMount() { 14 | window.addEventListener("resize", this.handleWindowResize) 15 | } 16 | 17 | componentWillUnmount() { 18 | window.removeEventListener("resize", this.handleWindowResize) 19 | } 20 | 21 | handleWindowResize() { 22 | clearTimeout(this.resizeTimeout) 23 | 24 | document.documentElement.setAttribute(attr, "") 25 | 26 | this.resizeTimeout = setTimeout(() => { 27 | document.documentElement.removeAttribute(attr) 28 | }, this.props.debounce) 29 | } 30 | 31 | render() { 32 | return null 33 | } 34 | } 35 | 36 | SmoothBrowserResizing.defaultProps = { 37 | debounce: 400 38 | } 39 | 40 | export default SmoothBrowserResizing 41 | -------------------------------------------------------------------------------- /src/components/cloudflare-logo.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import AccessibleSVG from "./accessible-svg" 3 | 4 | const CloudflareLogo = () => ( 5 | 6 | 7 | 8 | ) 9 | 10 | export default CloudflareLogo 11 | -------------------------------------------------------------------------------- /src/components/code-block.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | import MDXCodeBlock from "./mdx/code-block" 4 | 5 | const CodeBlock = props => { 6 | return ( 7 | 8 | 9 | {props.children} 10 | 11 | 12 | ) 13 | } 14 | 15 | export default CodeBlock 16 | -------------------------------------------------------------------------------- /src/components/docs-code-examples-overview.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link, useStaticQuery, graphql } from "gatsby" 3 | 4 | import getPageTitle from "../utils/get-page-title" 5 | import CodeBlock from "./code-block" 6 | 7 | const getCodeBlockFromMDXAST = ast => { 8 | for (let i = 0; i < ast.children.length; i += 1) { 9 | if (ast.children[i].type === "code") { 10 | return ast.children[i] 11 | } 12 | } 13 | } 14 | 15 | const DocsExamplesData = props => { 16 | const query = useStaticQuery(graphql` 17 | query { 18 | allMdx { 19 | edges { 20 | node { 21 | fields { 22 | slug 23 | } 24 | frontmatter { 25 | order 26 | title 27 | summary 28 | demo 29 | tags 30 | } 31 | headings(depth: h1) { 32 | value 33 | } 34 | parent { 35 | ... on File { 36 | modifiedTime(formatString: "YYYY-MM-DD") 37 | } 38 | } 39 | mdxAST 40 | } 41 | } 42 | } 43 | } 44 | `) 45 | 46 | const examples = query.allMdx.edges 47 | .map(({ node }) => node) 48 | .filter(page => page.fields.slug.match(/^\/examples\/.+/)) 49 | .map(page => ({ 50 | order: page.frontmatter.order, 51 | title: getPageTitle(page), 52 | url: page.fields.slug, 53 | summary: page.frontmatter.summary, 54 | code: getCodeBlockFromMDXAST(page.mdxAST), 55 | tags: page.frontmatter.tags, 56 | demo: page.frontmatter.demo, 57 | updated: page.parent.modifiedTime, 58 | })) 59 | .sort((a, b) => +new Date(b.updated) - +new Date(a.updated)) 60 | .sort((a, b) => a.order - b.order) 61 | 62 | const tagsSet = new Set() 63 | examples.forEach(ex => { 64 | ex.tags.forEach(tag => tagsSet.add(tag)) 65 | }) 66 | 67 | const tags = Array.from(tagsSet) 68 | tags.unshift("All examples") 69 | 70 | return props.children({ examples, tags }) 71 | } 72 | 73 | class DocsCodeExamplesOverview extends React.Component { 74 | 75 | constructor(props) { 76 | super(props) 77 | 78 | this.state = { 79 | activeTag: "All examples" 80 | } 81 | } 82 | 83 | render() { 84 | const activeTag = this.state.activeTag 85 | 86 | return ( 87 | 88 | {({ examples, tags }) => ( 89 | <> 90 |
    91 | {tags.map(tag => ( 92 |
    108 | 109 |
    110 | {examples 111 | .filter(ex => 112 | activeTag === "All examples" ? 113 | true : 114 | ex.tags.indexOf(activeTag) >= 0 115 | ) 116 | .map((example, i) => ( 117 |
    118 |
    119 | 120 | {example.title} 121 | 122 |
    123 | 124 |
    125 |

    {example.summary}

    126 |
    127 | 128 | 129 | 130 | 131 |
    132 | ))} 133 |
    134 | 135 | )} 136 |
    137 | ) 138 | } 139 | } 140 | 141 | export default DocsCodeExamplesOverview 142 | -------------------------------------------------------------------------------- /src/components/docs-footer.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import TimeAgo from "react-timeago" 3 | 4 | import AnchorLink from "./mdx/anchor-link" 5 | import getCloudflareDocsConfig from "../utils/get-cloudflare-docs-config" 6 | 7 | export default ({ page }) => { 8 | if (!page || !page.parent) return null 9 | 10 | const { modifiedTime, relativePath } = page.parent 11 | 12 | const { contentRepo, contentRepoFolder } = getCloudflareDocsConfig() 13 | const filePathPrefix = contentRepoFolder ? `${contentRepoFolder}/` : "" 14 | const pathToFile = `${filePathPrefix}src/content/${relativePath}` 15 | const editOnGithubURL = `https://github.com/${contentRepo}/blob/production/${pathToFile}` 16 | 17 | return ( 18 | 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /src/components/docs-mobile-title-header.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link } from "gatsby" 3 | 4 | import { sidebarToggle } from "../utils/mobile-sidebar-manipulation" 5 | import IconNavMenu from "./icons/nav-menu" 6 | 7 | import DocsTitle from "./docs-title" 8 | import DocsProductLogo from "./docs-product-logo" 9 | import DocsNavLogoLockup from "./docs-nav-logo-lockup" 10 | 11 | const DocsMobileTitleHeader = () => ( 12 |
    13 | 14 | } 17 | scaleTextClassName="DocsMobileTitleHeader--text-scaler" 18 | textLength={DocsTitle().length} 19 | text={} 20 | /> 21 | 22 | 23 | 26 |
    27 | ) 28 | 29 | export default DocsMobileTitleHeader 30 | -------------------------------------------------------------------------------- /src/components/docs-nav-logo-lockup.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | const DocsNavLogoLockup = ({ logo, text, small, scaleTextClassName, textLength }) => { 4 | const wrappedText = (scaleTextClassName && textLength) ? ( 5 | 6 | {text} 7 | 8 | ) : ( 9 | <>{text} 10 | ) 11 | 12 | return ( 13 |
    17 |
    18 | {logo} 19 |
    20 | 21 | {wrappedText} 22 | 23 |
    24 | ) 25 | } 26 | 27 | DocsNavLogoLockup.defaultProps = { 28 | small: false 29 | } 30 | 31 | export default DocsNavLogoLockup 32 | -------------------------------------------------------------------------------- /src/components/docs-page.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { SkipNavLink, SkipNavContent } from "@reach/skip-nav" 3 | // These are overridden by our SkipNavLink styles 4 | // but included here to quiet console warnings 5 | import "@reach/skip-nav/styles.css" 6 | 7 | import Helmet from "react-helmet" 8 | import SEO from "./seo" 9 | 10 | import HandleMobilePageNavigations from "./handle-mobile-page-navigations" 11 | import BrowserResizeTracking from "./browser-resize-tracking" 12 | import SmoothScrollHashChanges from "./smooth-scroll-hash-changes" 13 | import Breadcrumbs from "./breadcrumbs" 14 | 15 | import DocsMobileTitleHeader from "./docs-mobile-title-header" 16 | import DocsSidebar from "./docs-sidebar" 17 | import DocsToolbar from "./docs-toolbar" 18 | import DocsTableOfContents from "./docs-table-of-contents" 19 | import { className as docsMarkdownClassName } from "./mdx/root" 20 | import DocsFooter from "./docs-footer" 21 | 22 | import getCloudflareDocsConfig from "../utils/get-cloudflare-docs-config" 23 | import getPageTitle from "../utils/get-page-title" 24 | import getPageType from "../utils/get-page-type" 25 | import getTableOfContents from "../utils/get-table-of-contents" 26 | import hasBreadcrumbs from "../utils/has-breadcrumbs" 27 | 28 | const DocsPage = ({ pageContext: page, children, location }) => { 29 | const title = getPageTitle(page, true) 30 | const pageType = getPageType(page) 31 | const tableOfContents = getTableOfContents(page) 32 | 33 | const { search } = getCloudflareDocsConfig() 34 | const enableSearch = search.apiKey && search.indexName && search.algoliaOptions 35 | const disableSearchProps = enableSearch ? {} : { "search-disabled": "" } 36 | 37 | return ( 38 | <> 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 |
    52 | {/* */} 53 | 54 |
    55 | 56 | 57 |
    58 | {pageType === "document" && tableOfContents && ( 59 |
    60 |
    61 |
    62 | 65 |
    66 |
    67 | )} 68 | 69 | 70 | 71 | 72 | 73 |
    74 | {hasBreadcrumbs(page) && ( 75 | 76 | )} 77 | 78 |
    79 | {children} 80 |
    81 |
    82 |
    83 | 84 | 85 |
    86 | 87 | ) 88 | } 89 | 90 | export default DocsPage 91 | -------------------------------------------------------------------------------- /src/components/docs-product-logo.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import getCloudflareDocsConfig from "../utils/get-cloudflare-docs-config" 3 | import AccessibleSVG from "./accessible-svg" 4 | 5 | export default () => { 6 | const { product, productLogoPathD } = getCloudflareDocsConfig() 7 | 8 | return ( 9 | 10 | 11 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /src/components/docs-search.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react" 2 | import { navigate } from "@reach/router" 3 | import getPathPrefix from "../utils/get-path-prefix" 4 | import getCloudflareDocsConfig from "../utils/get-cloudflare-docs-config" 5 | 6 | import Helmet from "react-helmet" 7 | 8 | import DocsTitle from "./docs-title" 9 | import AccessibleSVG from "./accessible-svg" 10 | 11 | const DocsSearch = () => { 12 | const pathPrefix = getPathPrefix() 13 | 14 | const { 15 | pathPrefix: productionPathPrefix, 16 | search: { 17 | indexName, 18 | apiKey, 19 | algoliaOptions 20 | } 21 | } = getCloudflareDocsConfig() 22 | 23 | const enableSearch = indexName && apiKey && algoliaOptions 24 | 25 | // Adjust search result URL pathname to work with local development 26 | // See https://github.com/cloudflare/cloudflare-docs-engine/issues/196 27 | const fixSearchResultPathname = (pathname) => { 28 | // When the pathPrefix we get from getPathPrefix() matches the 29 | // productionPathPrefix we get from getCloudflareDocsConfig() 30 | // then we should not strip the prefix from the pathname. This 31 | // is a more reliable check than location.hostname !== "locahost" 32 | // because both `npm run serve` and `npm run develop` serve to 33 | // localhost but only the latter needs the pathPrefix removed. 34 | if (productionPathPrefix === pathPrefix) return pathname 35 | 36 | // The crawled search results should end up including the 37 | // productionPathPrefix (if one exists) so we need to remove 38 | // that for local development (where getPathPrefix() === ""). 39 | if (pathname.startsWith(`${productionPathPrefix}/`)) 40 | return pathname.substr(productionPathPrefix.length) 41 | 42 | // If for some reason the results are missing the pathPrefix, 43 | // then this is likely due to a crawling issue. But we return 44 | // the pathname as it is in this case which should cause a 45 | // 404 when we try to navigate(pathname) below. 46 | return pathname 47 | } 48 | 49 | useEffect(() => { 50 | let frames = 0 51 | const init = () => { 52 | frames += 1 53 | 54 | // Sadly this is needed because of the way Helmet works in local development 55 | if (!window.docsearch && frames < 60) { 56 | return requestAnimationFrame(() => init()) 57 | } 58 | 59 | const search = window.docsearch({ 60 | indexName, 61 | apiKey, 62 | algoliaOptions, 63 | 64 | // TODO: pass DOM in with Reacth.createRef? 65 | inputSelector: "#DocsSearch--input", 66 | 67 | autocompleteOptions: { 68 | // https://github.com/algolia/autocomplete.js#global-options 69 | autoselect: true, 70 | openOnFocus: true, 71 | clearOnSelected: false, 72 | tabAutocomplete: false, 73 | 74 | appendTo: ".DocsSearch--input-wrapper", 75 | hint: false, 76 | 77 | autoselectOnBlur: matchMedia("(pointer: course)").matches 78 | }, 79 | 80 | // https://docsearch.algolia.com/docs/behavior 81 | handleSelected: (input, event, suggestion, datasetNumber, context) => { 82 | // Adjust search result URL pathname to work with local development 83 | // See https://github.com/cloudflare/cloudflare-docs-engine/issues/196 84 | const url = new URL(suggestion.url) 85 | const pathname = fixSearchResultPathname(url.pathname) 86 | 87 | search.input.autocomplete.setVal("") 88 | search.input[0].blur() 89 | 90 | // Don’t scroll to hash when it’s just the h1. 91 | if (suggestion.isLvl0) { 92 | navigate(pathname) 93 | 94 | } else { 95 | navigate(pathname + url.hash) 96 | 97 | // Then focus the anchor in the header anchor 98 | // corresponding to the hash if it exists (it 99 | // should if Algolia’s crawl is up-to-date). 100 | const headerAnchor = document.querySelector(`${url.hash} a`) 101 | if (headerAnchor) headerAnchor.focus() 102 | } 103 | }, 104 | 105 | transformData: function(hits) { 106 | // Remove empty results 107 | for (let i = hits.length - 1; i >= 0; i -= 1) { 108 | if (!hits[i].hierarchy.lvl0 && !hits[i].hierarchy.lvl1) { 109 | hits.splice(i, 1) 110 | } 111 | } 112 | } 113 | }) 114 | 115 | const autocompleteWrapper = search.autocomplete.autocomplete.getWrapper() 116 | 117 | search.autocomplete.on("autocomplete:shown", event => { 118 | autocompleteWrapper.setAttribute("data-expanded", true) 119 | }) 120 | 121 | search.autocomplete.on("autocomplete:closed", event => { 122 | autocompleteWrapper.setAttribute("data-expanded", false) 123 | }) 124 | 125 | const input = search.input[0] 126 | const wrapper = input.closest(".DocsSearch") 127 | 128 | input.addEventListener("focus", () => { 129 | wrapper.setAttribute("is-focused", "") 130 | }) 131 | 132 | input.addEventListener("blur", () => { 133 | wrapper.removeAttribute("is-focused") 134 | }) 135 | 136 | document.addEventListener("keydown", event => { 137 | if (event.target === input) return 138 | 139 | const slashShortcut = event.key === "/" 140 | const commandShortcut = event.key === "S" && event.shiftKey 141 | 142 | if (slashShortcut || commandShortcut) { 143 | event.preventDefault() 144 | window.scrollTo(0, 0) 145 | input.focus() 146 | } 147 | }) 148 | } 149 | 150 | if (enableSearch) { 151 | init() 152 | } 153 | 154 | // eslint-disable-next-line react-hooks/exhaustive-deps 155 | }, []) 156 | 157 | if (!enableSearch) { 158 | return 159 | } 160 | 161 | return ( 162 | <> 163 | 164 | 160 | 161 | 162 |
    163 |
    164 | 170 | 171 | 184 | 185 | 186 | {`Set theme to ${this.state.checked ? "light" : "dark"} (⇧+D)`} 187 | 188 |
    189 |
    190 | 191 | ) 192 | } 193 | } 194 | 195 | export default ThemeToggle 196 | -------------------------------------------------------------------------------- /src/components/worker-starter.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | import { CopyToClipboard } from "react-copy-to-clipboard" 4 | 5 | import AnchorLink from "./mdx/anchor-link" 6 | import CodeBlock from "./code-block" 7 | 8 | const WorkerStarter = props => { 9 | const { title, description, repo } = props 10 | const repoLink = `https://github.com/${repo}` 11 | const command = `wrangler generate my-app ${repoLink}` 12 | 13 | return ( 14 |
    15 |
    16 | {title} 17 |
    18 |
    {description}
    19 |
    20 |
    21 | 22 | 23 | 24 |
    25 |
    26 | {command} 27 |
    28 |
    29 |
    30 | ) 31 | } 32 | 33 | export default WorkerStarter 34 | -------------------------------------------------------------------------------- /src/constants/sidebar-collapse-transition-duration.js: -------------------------------------------------------------------------------- 1 | export default 400 2 | -------------------------------------------------------------------------------- /src/css/docs/components/architecture-diagram.css: -------------------------------------------------------------------------------- 1 | /* Note: px units are used throughout the file to avoid rounding issues */ 2 | 3 | .ArchitectureDiagram { 4 | --user-code-size: 25px; 5 | --accent-color-rgb: var(--orange-rgb); 6 | position: relative; 7 | display: flex; 8 | flex-wrap: wrap; 9 | justify-content: space-between; 10 | width: 100%; 11 | max-width: 100%; 12 | } 13 | 14 | @media (max-width: 1350px) { .ArchitectureDiagram { --user-code-size: 22px }} 15 | @media (max-width: 1280px) { .ArchitectureDiagram { --user-code-size: 24px }} 16 | @media (max-width: 1250px) { .ArchitectureDiagram { --user-code-size: 22px }} 17 | @media (max-width: 1195px) { .ArchitectureDiagram { --user-code-size: 20px }} 18 | @media (max-width: 1152px) { .ArchitectureDiagram { --user-code-size: 25px }} 19 | @media (max-width: 1080px) { .ArchitectureDiagram { --user-code-size: 22px }} 20 | @media (max-width: 986px) { .ArchitectureDiagram { --user-code-size: 20px }} 21 | @media (max-width: 920px) { .ArchitectureDiagram { --user-code-size: 15px }} 22 | @media (max-width: 820px) { .ArchitectureDiagram { --user-code-size: 12px }} 23 | @media (max-width: 768px) { .ArchitectureDiagram { --user-code-size: 20px }} 24 | @media (max-width: 576px) { .ArchitectureDiagram { --user-code-size: 18px }} 25 | @media (max-width: 520px) { .ArchitectureDiagram { --user-code-size: 16px }} 26 | 27 | .ArchitectureDiagram--diagram { 28 | --size: calc(var(--user-code-size) * 9); 29 | width: var(--size); 30 | } 31 | 32 | @media (max-width: 480px) { 33 | .ArchitectureDiagram { 34 | --user-code-size: 25px; 35 | justify-content: flex-start; 36 | } 37 | 38 | .ArchitectureDiagram--diagram { 39 | width: 100%; 40 | } 41 | 42 | .ArchitectureDiagram--diagram + .ArchitectureDiagram--diagram { 43 | margin-top: 2em; 44 | } 45 | 46 | .ArchitectureDiagram--key { 47 | position: absolute; 48 | top: 0; 49 | right: 0; 50 | bottom: 0; 51 | } 52 | 53 | .ArchitectureDiagram--key-content { 54 | position: sticky; 55 | top: calc(var(--docs-header-height) + var(--user-code-size)); 56 | } 57 | 58 | .ArchitectureDiagram--caption { 59 | width: var(--size); 60 | } 61 | } 62 | 63 | @media (max-width: 374px) { 64 | .ArchitectureDiagram--key { 65 | width: 5em; 66 | } 67 | } 68 | 69 | @media (max-width: 414px) { .ArchitectureDiagram { --user-code-size: 22px }} 70 | @media (max-width: 375px) { .ArchitectureDiagram { --user-code-size: 20px }} 71 | @media (max-width: 360px) { .ArchitectureDiagram { --user-code-size: 19px }} 72 | @media (max-width: 340px) { .ArchitectureDiagram { --user-code-size: 18px }} 73 | @media (max-width: 330px) { .ArchitectureDiagram { --user-code-size: 17px }} 74 | 75 | @media (max-width: 319px) { 76 | .ArchitectureDiagram { 77 | /* TODO */ 78 | display: none; 79 | } 80 | } 81 | 82 | .ArchitectureDiagram--content { 83 | position: relative; 84 | display: flex; 85 | flex-wrap: wrap; 86 | flex-shrink: 0; 87 | width: var(--size); 88 | height: var(--size); 89 | } 90 | 91 | .ArchitectureDiagram--caption { 92 | margin-top: .666em; 93 | max-width: 100%; 94 | line-height: 1.3; 95 | } 96 | 97 | .ArchitectureDiagram--process-overhead { 98 | --size: calc(var(--user-code-size) * 3); 99 | position: relative; 100 | display: flex; 101 | flex-wrap: wrap; 102 | flex-shrink: 0; 103 | width: var(--size); 104 | height: var(--size); 105 | } 106 | 107 | .ArchitectureDiagram--process-overhead::after { 108 | content: "↻"; 109 | display: block; 110 | position: absolute; 111 | top: 0; 112 | right: 0; 113 | bottom: 0; 114 | left: 0; 115 | height: 1em; 116 | width: 1em; 117 | margin: auto; 118 | font-size: 2em; 119 | line-height: 1; 120 | text-align: center; 121 | color: rgb(var(--accent-color-rgb)); 122 | } 123 | 124 | .ArchitectureDiagram--process-overhead-background { 125 | position: absolute; 126 | top: 0; 127 | right: 0; 128 | bottom: 0; 129 | left: 0; 130 | background: rgba(var(--accent-color-rgb), .25); 131 | } 132 | 133 | .ArchitectureDiagram--user-code { 134 | position: relative; 135 | z-index: 1; 136 | width: var(--user-code-size); 137 | height: var(--user-code-size); 138 | background: rgba(var(--accent-color-rgb), .9); 139 | } 140 | 141 | .ArchitectureDiagram--process-overhead-background, 142 | .ArchitectureDiagram--user-code { 143 | --box-shadow: inset 0 0 0 1px rgb(var(--background-color-rgb)); /* Workaround for Safari bug - https://bugs.webkit.org/show_bug.cgi?id=185940 */ 144 | box-shadow: var(--box-shadow); 145 | } 146 | 147 | .ArchitectureDiagram--user-code::after { 148 | content: "{ }"; 149 | display: block; 150 | font-size: calc(var(--user-code-size) * .5); 151 | line-height: calc(var(--user-code-size) * .93); 152 | font-weight: bold; 153 | height: 100%; 154 | width: 100%; 155 | text-align: center; 156 | color: rgba(var(--background-color-rgb), .7); 157 | } 158 | 159 | .ArchitectureDiagram--key-user-code { 160 | margin-bottom: 1em; 161 | } 162 | 163 | .ArchitectureDiagram--key-label { 164 | opacity: .8; 165 | padding-top: .25em; 166 | } 167 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-body.css: -------------------------------------------------------------------------------- 1 | .DocsBody { 2 | position: relative; 3 | padding-top: var(--docs-header-height); 4 | padding-left: var(--docs-sidebar-width); 5 | } 6 | 7 | @media (max-width: 768px) { 8 | .DocsBody { 9 | padding-top: 0; 10 | padding-left: 0; 11 | will-change: opacity; 12 | transition: opacity .3s ease; 13 | } 14 | 15 | [is-mobile-sidebar-open] .DocsBody { 16 | opacity: .3; 17 | } 18 | } 19 | 20 | .DocsBody--sidebar { 21 | position: absolute; 22 | right: 0; 23 | top: calc(var(--docs-header-height) + 2.7em - 1em); /* TODO - clean up magic numbers */ 24 | bottom: 1em; 25 | width: var(--docs-body-sidebar-width); 26 | } 27 | 28 | @media (max-width: 1152px) { 29 | .DocsBody--sidebar { 30 | display: none; 31 | } 32 | } 33 | 34 | .DocsBody--sidebar-content-scroll-fade { 35 | position: sticky; 36 | top: 0; 37 | display: block; 38 | background: linear-gradient(var(--background-color), rgba(var(--background-color-rgb), 0)); 39 | height: 1em; 40 | margin-left: -1em; 41 | width: 100%; 42 | z-index: 1; 43 | } 44 | 45 | .DocsBody--sidebar-content { 46 | position: sticky; 47 | top: 0; 48 | width: calc(100% + 1em); 49 | max-height: 100vh; 50 | overflow-y: auto; 51 | -webkit-overflow-scrolling: touch; 52 | padding: 1em 0 0 1em; 53 | margin: -1em; 54 | transition: opacity .3s ease; 55 | scrollbar-width: thin; 56 | scrollbar-color: rgba(var(--color-rgb), .1) transparent; 57 | } 58 | 59 | @media (min-width: 1281px) { 60 | .DocsBody--sidebar { 61 | padding-left: 2em; 62 | } 63 | } 64 | 65 | .DocsBody--sidebar-content:hover { 66 | scrollbar-color: rgba(var(--color-rgb), .35) transparent; 67 | } 68 | 69 | [theme="dark"] .DocsBody--sidebar-content:not(:hover):not(:focus-within) { 70 | opacity: .55; 71 | } 72 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-code-examples-overview.css: -------------------------------------------------------------------------------- 1 | .DocsCodeExamplesOverview { 2 | margin: 2.5rem 0; 3 | display: grid; 4 | grid-template-columns: repeat(2, minmax(0, 1fr)); 5 | grid-gap: var(--docs-content-gap); 6 | } 7 | 8 | .DocsCodeExamplesOverview--example { 9 | border-radius: .5em; 10 | } 11 | 12 | .DocsCodeExamplesOverview--example-title { 13 | font-size: 1.5em; 14 | line-height: 1.2; 15 | font-weight: 500; 16 | margin-bottom: .5em; 17 | white-space: nowrap; 18 | text-overflow: ellipsis; 19 | overflow: hidden; 20 | } 21 | 22 | .DocsCodeExamplesOverview--example-title .Link { /* TODO */ 23 | color: inherit; 24 | --underline-opacity: .75; 25 | text-decoration: underline; 26 | text-decoration-color: rgba(var(--orange-rgb), var(--underline-opacity)); 27 | box-shadow: 0 0 0 var(--focus-size) var(--focus-color); 28 | } 29 | 30 | .DocsCodeExamplesOverview--example-description { 31 | margin-bottom: 1em; 32 | } 33 | 34 | @media (min-width: 1153px) { 35 | .DocsCodeExamplesOverview--example-description { 36 | --lines: 2; 37 | display: -webkit-box; 38 | -webkit-line-clamp: var(--lines); 39 | -webkit-box-orient: vertical; 40 | height: calc(1em * var(--lines) * var(--line-height)); 41 | overflow: hidden; 42 | } 43 | } 44 | 45 | .DocsCodeExamplesOverview--example-description > *:last-child { 46 | margin-bottom: 0; 47 | } 48 | 49 | .DocsCodeExamplesOverview--example-codeblock-link { 50 | display: block; 51 | position: relative; 52 | color: inherit; 53 | } 54 | 55 | .DocsCodeExamplesOverview--example-codeblock-link::after { 56 | content: ""; 57 | position: absolute; 58 | top: 0; 59 | right: 0; 60 | bottom: 0; 61 | left: 0; 62 | --active-box-shadow-color: transparent; 63 | box-shadow: inset 0 .0625em .1875em var(--active-box-shadow-color); 64 | border-radius: .5em; 65 | } 66 | 67 | @media (hover: hover) { 68 | .DocsCodeExamplesOverview--example-codeblock-link:hover:not(:active)::after { 69 | background: rgba(255, 255, 255, .2); 70 | } 71 | 72 | [theme="dark"] .DocsCodeExamplesOverview--example-codeblock-link:hover:not(:active)::after { 73 | background: rgba(var(--color-rgb), .05); 74 | } 75 | } 76 | 77 | .DocsCodeExamplesOverview--example-codeblock-link:active::after { 78 | background: rgba(var(--shadow-color-rgb), .05); 79 | --active-box-shadow-color: rgba(var(--shadow-color-rgb), .2); 80 | } 81 | 82 | .DocsCodeExamplesOverview--example-codeblock-link pre { 83 | height: 19em; 84 | margin-bottom: 0; 85 | pointer-events: none; 86 | } 87 | 88 | .DocsCodeExamplesOverview--example-codeblock-link pre, 89 | .DocsCodeExamplesOverview--example-codeblock-link pre code { 90 | overflow: hidden; 91 | } 92 | 93 | @media (max-width: 1152px) { 94 | .DocsCodeExamplesOverview { 95 | margin-left: 0; 96 | margin-right: 0; 97 | grid-template-columns: 100%; 98 | } 99 | } 100 | 101 | @media (max-width: 768px) { 102 | .DocsCodeExamplesOverview--example-title { 103 | font-size: 1.375em; 104 | margin-bottom: .5rem; 105 | } 106 | 107 | .DocsCodeExamplesOverview--example-codeblock-link { 108 | margin-left: -1rem; 109 | width: calc(100% + 2rem); 110 | } 111 | 112 | .DocsCodeExamplesOverview--example-codeblock-link::after { 113 | border-radius: 0; 114 | } 115 | 116 | .DocsCodeExamplesOverview--example-codeblock-link pre { 117 | height: 12.2em; 118 | --border-radius: 0em; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-content.css: -------------------------------------------------------------------------------- 1 | .DocsContent { 2 | padding: 2.6rem var(--docs-content-gap) 3.5rem; /* TODO */ 3 | min-height: calc(100vh - 12.5em); /* TODO */ 4 | } 5 | 6 | .DocsContent[page-type="document"] { 7 | width: calc(100% - var(--docs-body-sidebar-width)); 8 | } 9 | 10 | @media (min-width: 769px) { 11 | [search-disabled] .DocsContent { 12 | padding-top: 0; 13 | } 14 | } 15 | 16 | @media (max-width: 768px) { 17 | .DocsContent { 18 | --docs-content-horizontal-padding: 1rem; 19 | padding: 2rem var(--docs-content-horizontal-padding); 20 | min-height: 1em; /* TODO */ 21 | } 22 | } 23 | 24 | .DocsContent--breadcrumbs { 25 | margin: -.5em 0 .3125em; 26 | } 27 | 28 | @media (min-width: 769px) { 29 | .DocsContent--breadcrumbs { 30 | display: none; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-footer.css: -------------------------------------------------------------------------------- 1 | .DocsFooter { 2 | margin-left: var(--docs-sidebar-width); 3 | padding: 3.5rem 0; /* TODO */ 4 | padding-left: var(--docs-content-gap); 5 | padding-right: calc(var(--docs-body-sidebar-width) + var(--docs-content-gap)); 6 | --border-color: rgba(var(--color-rgb), .08); 7 | border-top: 1px solid var(--border-color); 8 | } 9 | 10 | @media (max-width: 768px) { 11 | .DocsFooter { 12 | margin-left: 0; 13 | padding: 2rem 1rem 4rem 14 | } 15 | } 16 | 17 | .DocsFooter--content { 18 | display: flex; 19 | } 20 | 21 | @media (max-width: 414px) { 22 | .DocsFooter--edit-on-gh-link-wrapper { 23 | display: block; 24 | margin-bottom: .5em; 25 | } 26 | 27 | .DocsFooter--content-dot-spacer { 28 | display: none; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-mobile-header.css: -------------------------------------------------------------------------------- 1 | .DocsMobileHeader { 2 | position: absolute; 3 | display: flex; 4 | align-items: center; 5 | top: 0; 6 | left: 0; 7 | width: 100%; 8 | height: var(--docs-header-height); 9 | background: var(--background-color); 10 | box-shadow: 0 1px rgba(var(--color-rgb), .05); 11 | z-index: 11; 12 | --content-indent: .666em; 13 | } 14 | 15 | [theme="dark"] .DocsMobileHeader { 16 | background: var(--gray-05); 17 | } 18 | 19 | @media (min-width: 769px) { 20 | .DocsMobileHeader { 21 | display: none; 22 | } 23 | } 24 | 25 | .DocsMobileHeader--cloudflare-logo-link { 26 | --font-size: 1.1em; 27 | display: flex; 28 | align-items: center; 29 | padding-left: var(--content-indent); 30 | padding-right: var(--content-indent); 31 | transition: opacity .2s ease, color .2s ease; 32 | } 33 | 34 | @media (hover: hover) { 35 | .DocsMobileHeader--cloudflare-logo-link:hover { 36 | opacity: .75; 37 | color: rgba(var(--color-rgb), .75); 38 | } 39 | } 40 | 41 | @media (hover: none) { 42 | .DocsMobileHeader--cloudflare-logo-link:active { 43 | opacity: .75; 44 | color: rgba(var(--color-rgb), .75); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-mobile-nav-backdrop.css: -------------------------------------------------------------------------------- 1 | .DocsMobileNavBackdrop { 2 | position: fixed; 3 | top: 0; 4 | right: 0; 5 | bottom: 0; 6 | left: 0; 7 | opacity: 0; 8 | pointer-events: none; 9 | background: rgba(var(--shadow-color-rgb), .5); 10 | will-change: opacity; 11 | transition: opacity .3s ease; 12 | z-index: 8; 13 | } 14 | 15 | @media (min-width: 769px) { 16 | .DocsMobileNavBackdrop { 17 | display: none; 18 | } 19 | } 20 | 21 | [is-mobile-sidebar-open] .DocsMobileNavBackdrop { 22 | opacity: 1; 23 | pointer-events: all; 24 | } 25 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-mobile-title-header.css: -------------------------------------------------------------------------------- 1 | .DocsMobileTitleHeader { 2 | position: sticky; 3 | display: flex; 4 | align-items: center; 5 | top: 0; 6 | left: 0; 7 | width: 100%; 8 | padding-right: .5rem; 9 | height: var(--docs-header-height); 10 | background: var(--background-color); 11 | box-shadow: 0 1px rgba(var(--shadow-color-rgb), .075), 0 .2em .3em -.1em rgba(var(--shadow-color-rgb), .075); 12 | z-index: 10; 13 | --content-indent: .666em; 14 | } 15 | 16 | [theme="dark"] .DocsMobileTitleHeader { 17 | background: var(--gray-05); 18 | } 19 | 20 | @media (min-width: 769px) { 21 | .DocsMobileTitleHeader { 22 | display: none; 23 | } 24 | } 25 | 26 | .DocsMobileTitleHeader--logo-link { 27 | --font-size: 1.333em; 28 | display: flex; 29 | align-items: center; 30 | padding-left: var(--content-indent); 31 | padding-right: var(--content-indent); 32 | transition: opacity .2s ease, color .2s ease; 33 | } 34 | 35 | @media (hover: hover) { 36 | .DocsMobileTitleHeader--logo-link:hover { 37 | opacity: .75; 38 | color: rgba(var(--color-rgb), .75); 39 | } 40 | } 41 | 42 | @media (hover: none) { 43 | .DocsMobileTitleHeader--logo-link:active { 44 | opacity: .75; 45 | color: rgba(var(--color-rgb), .75); 46 | } 47 | } 48 | 49 | .DocsMobileTitleHeader--text-scaler { 50 | /* --length set by React */ 51 | --font-size: 1em * (1 - ((var(--length) - 10) / 50)); 52 | font-size: clamp(.7em, var(--font-size), 1em); 53 | display: inherit; 54 | } 55 | 56 | .DocsMobileTitleHeader--sidebar-toggle-button { 57 | /* For pixel-fitted SVG */ 58 | width: 40px; 59 | height: 40px; 60 | margin-left: auto; 61 | padding: 0; 62 | } 63 | 64 | .DocsMobileTitleHeader--sidebar-toggle-button path { 65 | transition: transform .3s ease, opacity .3s ease; 66 | } 67 | 68 | [is-mobile-sidebar-open] .DocsMobileTitleHeader--sidebar-toggle-button path[data-index="1"] { 69 | transform: translateY(15%) rotate(45deg); 70 | } 71 | 72 | [is-mobile-sidebar-open] .DocsMobileTitleHeader--sidebar-toggle-button path[data-index="2"] { 73 | opacity: 0; 74 | } 75 | 76 | [is-mobile-sidebar-open] .DocsMobileTitleHeader--sidebar-toggle-button path[data-index="3"] { 77 | transform: translateY(-15%) rotate(-45deg); 78 | } 79 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-nav-logo-lockup.css: -------------------------------------------------------------------------------- 1 | .DocsNavLogoLockup { 2 | display: flex; 3 | align-items: center; 4 | flex-shrink: 0; 5 | --gap: var(--docs-logo-lockup-gap); 6 | } 7 | 8 | .DocsNavLogoLockup.DocsNavLogoLockup-with-small-gap { 9 | --gap: var(--docs-logo-lockup-gap-small); 10 | } 11 | 12 | .DocsNavLogoLockup--logo { 13 | --size: var(--logo-size, 2.5em); 14 | height: var(--size); 15 | width: var(--size); 16 | color: var(--orange); 17 | margin-right: var(--gap); 18 | flex-shrink: 0; 19 | } 20 | 21 | .DocsNavLogoLockup--text { 22 | font-size: var(--font-size, 1em); 23 | font-weight: 700; 24 | line-height: 1; 25 | padding-top: .05em; 26 | letter-spacing: -.03em; 27 | } 28 | 29 | @-moz-document url-prefix() { 30 | .DocsNavLogoLockup--text { 31 | letter-spacing: 0; 32 | } 33 | } 34 | 35 | .DocsNavLogoLockup--text [data-text="Cloudflare"] ~ [data-text="Docs"] { 36 | font-weight: 500; 37 | margin-left: -.05em; 38 | } 39 | 40 | @media (max-width: 768px) { 41 | .DocsNavLogoLockup--text { 42 | font-weight: 600; 43 | } 44 | 45 | .DocsNavLogoLockup--text [data-text="Cloudflare"] ~ [data-text="Docs"] { 46 | font-weight: 400; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-noscript.css: -------------------------------------------------------------------------------- 1 | .DocsNoscript { 2 | position: fixed; 3 | top: 0; 4 | left: 50%; 5 | transform: translate3d(-50%, 0, 0); 6 | font-size: .8em; 7 | padding: .5em 1em; 8 | background: rgba(var(--orange-rgb), .15); 9 | border-radius: 0 0 .25em .25em; 10 | z-index: 100; 11 | } 12 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-page.css: -------------------------------------------------------------------------------- 1 | html[is-docs-page], 2 | html[is-docs-page] body { 3 | scroll-behavior: smooth; 4 | height: 100%; 5 | overscroll-behavior-y: none; 6 | } 7 | 8 | .DocsPage { 9 | --sixty-four-px-rem: 3.7647058824rem; /* 64 / 17 */ 10 | --docs-content-gap: var(--sixty-four-px-rem); 11 | --docs-header-height: var(--sixty-four-px-rem); 12 | --docs-sidebar-width: 18.25rem; 13 | --docs-body-sidebar-width: var(--docs-sidebar-width); 14 | --docs-page-side-padding: 1rem; 15 | --docs-max-page-width: 1440px; 16 | --docs-page-width: var(--docs-max-page-width); 17 | 18 | --docs-sidebars-combined-width: calc(var(--docs-sidebar-width) + var(--docs-body-sidebar-width)); 19 | --docs-body-width: calc(var(--docs-page-width) - var(--docs-sidebars-combined-width)); 20 | 21 | --docs-logo-lockup-gap: .4rem; 22 | --docs-logo-lockup-gap-small: .2rem; 23 | 24 | position: relative; 25 | width: 100%; 26 | max-width: var(--docs-max-page-width); 27 | min-height: 100%; 28 | margin: 0 auto; 29 | } 30 | 31 | @media (max-width: 1439px) { 32 | .DocsPage { 33 | --docs-page-width: 100vw; 34 | 35 | --docs-page-sidebar-preserverd-width: calc(100vw - var(--docs-sidebar-width) 36 | - (var(--docs-max-page-width) - 2 * var(--docs-sidebar-width))); 37 | 38 | --docs-body-sidebar-width: calc(15vw + var(--docs-page-sidebar-preserverd-width) / 4); 39 | } 40 | } 41 | 42 | @media (max-width: 1350px) { 43 | .DocsPage { 44 | --docs-sidebar-width: 18rem; 45 | } 46 | } 47 | 48 | @media (max-width: 1280px) { 49 | .DocsPage { 50 | --docs-sidebar-width: 17rem; 51 | --docs-body-sidebar-width: 18vw; 52 | } 53 | } 54 | 55 | @media (max-width: 1152px) { 56 | .DocsPage { 57 | --docs-sidebar-width: calc(10rem + 12vw); 58 | --docs-body-sidebar-width: 0px; 59 | } 60 | } 61 | 62 | @media (max-width: 768px) { 63 | .DocsPage { 64 | --docs-header-height: 3rem; 65 | /* padding-top: var(--docs-header-height); */ 66 | } 67 | 68 | html[is-docs-page][is-mobile-sidebar-open] { 69 | overflow: hidden; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-search.css: -------------------------------------------------------------------------------- 1 | .DocsSearch { 2 | --text-indent: calc(var(--docs-content-gap) + 1px); 3 | height: var(--docs-header-height); 4 | } 5 | 6 | .DocsSearch--input-wrapper { 7 | position: relative; 8 | height: 100%; 9 | } 10 | 11 | .DocsSearch--input { 12 | position: relative; 13 | color: inherit; 14 | height: 100%; 15 | width: 100%; 16 | border: 0; 17 | padding: 0 var(--text-indent) .05em; 18 | background: transparent; 19 | outline: none; 20 | z-index: 2; 21 | } 22 | 23 | @-moz-document url-prefix() { 24 | .DocsSearch--input { 25 | letter-spacing: 0; 26 | } 27 | } 28 | 29 | .DocsSearch--input::placeholder { 30 | color: rgba(var(--color-rgb), .45); 31 | opacity: 1; 32 | } 33 | 34 | [theme="dark"] .DocsSearch--input::placeholder { 35 | color: rgba(var(--color-rgb), .55); 36 | } 37 | 38 | .DocsSearch--input-icon { 39 | position: absolute; 40 | top: 0; 41 | bottom: .05em; 42 | margin-top: auto; 43 | margin-bottom: auto; 44 | left: 2.2em; 45 | height: .8823529411em; 46 | width: .8823529411em; 47 | pointer-events: none; 48 | opacity: .5; 49 | transition: color .3s ease, opacity .3s ease; 50 | z-index: 3; 51 | } 52 | 53 | .DocsSearch--input-wrapper:focus-within .DocsSearch--input-icon { 54 | color: var(--orange); 55 | opacity: 1; 56 | } 57 | 58 | .DocsSearch--input-bottom-border { 59 | position: absolute; 60 | left: 0; 61 | width: 50%; 62 | bottom: 0; 63 | height: 1px; 64 | background: 65 | linear-gradient(to right, 66 | rgba(var(--color-rgb), .07) 0%, 67 | rgba(var(--color-rgb), .07) calc(100% - 6em), 68 | rgba(var(--color-rgb), 0) 100% 69 | ); 70 | } 71 | 72 | [theme="dark"] .DocsSearch--input { 73 | background: 74 | linear-gradient(to right, 75 | rgba(var(--shadow-color-rgb), .1) 0%, 76 | rgba(var(--shadow-color-rgb), .1) calc(30% - 6em), 77 | rgba(var(--shadow-color-rgb), 0) 30% 78 | ); 79 | } 80 | 81 | [theme="dark"] .DocsSearch--input-bottom-border { 82 | bottom: -1px; 83 | } 84 | 85 | [theme="dark"] .DocsSearch--input-bottom-border::before { 86 | content: ""; 87 | display: block; 88 | position: absolute; 89 | top: -1px; 90 | width: 100%; 91 | bottom: 0; 92 | height: 1px; 93 | background: 94 | linear-gradient(to right, 95 | rgba(var(--shadow-color-rgb), .5) 0%, 96 | rgba(var(--shadow-color-rgb), .5) calc(100% - 6em), 97 | rgba(var(--shadow-color-rgb), 0) 100% 98 | ); 99 | } 100 | 101 | /* Algolia DocSearch (https://docsearch.algolia.com) */ 102 | 103 | .DocsSearch .algolia-autocomplete { 104 | --dropdown-text-indent: var(--text-indent); 105 | --suggestion-item-vertical-padding: .5em; 106 | 107 | /* Combat Algolia-set inline styles */ 108 | display: block !important; 109 | top: 0 !important; 110 | left: 0 !important; 111 | right: auto !important; 112 | width: var(--docs-body-width) !important; 113 | z-index: 1 !important; 114 | 115 | background: var(--background-color); 116 | 117 | --box-shadow: 118 | 0 3rem 6rem -1.2rem rgba(var(--shadow-color-rgb), .25), 119 | 0 3rem 6rem -3rem rgba(var(--shadow-color-rgb), .3); 120 | 121 | --backdrop-box-shadow-alpha: .07; 122 | --backdrop-box-shadow: 123 | 0 0 0 999em rgba(var(--shadow-color-rgb), var(--backdrop-box-shadow-alpha)); 124 | 125 | box-shadow: var(--box-shadow), var(--backdrop-box-shadow); 126 | 127 | border-radius: 0 0 .5em .5em; 128 | will-change: opacity; 129 | transition: opacity .15s ease; 130 | } 131 | 132 | [theme="dark"] .DocsSearch .algolia-autocomplete { 133 | --dark-theme-shadow-offset: 1px; 134 | --dropdown-text-indent: calc(var(--text-indent) - var(--dark-theme-shadow-offset)); 135 | --box-shadow: 0 0 0 1px rgb(var(--shadow-color-rgb), .3), 0 .3em 2em rgb(var(--shadow-color-rgb), .3); 136 | --backdrop-box-shadow-alpha: .3; 137 | background: var(--gray-0); 138 | margin-left: var(--dark-theme-shadow-offset); 139 | } 140 | 141 | .DocsSearch .algolia-autocomplete[style*="display: none"], 142 | .DocsSearch .algolia-autocomplete:not([data-expanded="true"]) { 143 | opacity: 0; 144 | --backdrop-box-shadow: none; 145 | pointer-events: none; 146 | } 147 | 148 | @supports ((-webkit-backdrop-filter: blur(1em)) or (backdrop-filter: blur(1em))) { 149 | .DocsSearch .algolia-autocomplete { 150 | background: rgba(var(--background-color-rgb), .8); 151 | -webkit-backdrop-filter: saturate(200%) blur(1.25em); 152 | backdrop-filter: saturate(200%) blur(1.25em); 153 | } 154 | 155 | [theme="dark"] .DocsSearch .algolia-autocomplete { 156 | background: rgba(var(--gray-0-rgb), .8); 157 | } 158 | 159 | /* Safari only hack */ 160 | @media not all and (min-resolution:.001dpcm) { @media { 161 | .DocsSearch .algolia-autocomplete { 162 | background: rgba(var(--background-color-rgb), 1); 163 | } 164 | }} 165 | } 166 | 167 | .DocsSearch .algolia-autocomplete [class|="ds-dataset"] > *:first-child { 168 | position: relative; 169 | --padding-top: calc(var(--docs-header-height) + .66rem); 170 | padding: var(--padding-top) var(--dropdown-text-indent) 0; 171 | } 172 | 173 | .DocsSearch .algolia-autocomplete [class|="ds-dataset"] > *:first-child::before { 174 | content: ""; 175 | position: absolute; 176 | left: 0; 177 | right: 0; 178 | top: var(--docs-header-height); 179 | margin-top: -1px; 180 | height: 1px; 181 | background: rgba(var(--color-rgb), .07); 182 | } 183 | 184 | [theme="dark"] .DocsSearch .algolia-autocomplete [class|="ds-dataset"] > *:first-child::before { 185 | margin-top: 0; 186 | background: rgba(var(--color-rgb), .07); 187 | box-shadow: 188 | 0 -1px rgba(var(--shadow-color-rgb), .2), 189 | 0 calc(-1 * var(--docs-header-height)) rgba(var(--shadow-color-rgb), .1); 190 | } 191 | 192 | .DocsSearch .ds-suggestion { 193 | display: block; 194 | --horizontal-padding: 1em; 195 | padding: var(--suggestion-item-vertical-padding) var(--horizontal-padding); 196 | margin: 0 calc(-1 * var(--horizontal-padding)); 197 | border-radius: .25em; 198 | } 199 | 200 | .DocsSearch .ds-suggestion.ds-cursor { 201 | background: rgba(var(--gray-5-rgb), .2); 202 | } 203 | 204 | [theme="dark"] .DocsSearch .ds-suggestion.ds-cursor { 205 | background: rgba(var(--gray-6-rgb), .15); 206 | } 207 | 208 | .DocsSearch a.algolia-docsearch-suggestion { 209 | display: block; 210 | color: inherit; 211 | text-decoration: none; 212 | } 213 | 214 | .DocsSearch .algolia-docsearch-suggestion--text { 215 | font-size: .9em; 216 | color: rgba(var(--color-rgb), .8); 217 | } 218 | 219 | .DocsSearch .algolia-docsearch-suggestion--highlight { 220 | --highlight-opacity: .2; 221 | background-color: rgba(var(--orange-rgb), var(--highlight-opacity)); 222 | color: var(--color); 223 | } 224 | 225 | [theme="dark"] .DocsSearch .algolia-docsearch-suggestion--highlight { 226 | --highlight-opacity: .4; 227 | } 228 | 229 | .DocsSearch .algolia-docsearch-suggestion--no-results { 230 | padding-top: var(--suggestion-item-vertical-padding); 231 | margin-bottom: 1em; 232 | } 233 | 234 | .DocsSearch .algolia-docsearch-suggestion--no-results .algolia-docsearch-suggestion--text { 235 | padding-top: var(--suggestion-item-vertical-padding); 236 | font-size: 1em; 237 | } 238 | 239 | .DocsSearch .algolia-docsearch-suggestion--no-results b { 240 | font-weight: inherit; 241 | } 242 | 243 | .DocsSearch .algolia-docsearch-footer { 244 | margin-top: .5rem; 245 | padding: 0 var(--dropdown-text-indent) 2rem; 246 | font-size: .7em; 247 | opacity: .5; 248 | } 249 | 250 | .DocsSearch .algolia-docsearch-footer--logo { 251 | color: inherit; 252 | } 253 | 254 | .DocsSearch .algolia-docsearch-suggestion--category-header-lvl0:empty::before { 255 | content: "Document"; 256 | } 257 | 258 | .DocsSearch .algolia-docsearch-suggestion__main .algolia-docsearch-suggestion--subcategory-column, 259 | .DocsSearch .algolia-docsearch-suggestion__main .algolia-docsearch-suggestion--subcategory-inline, 260 | .DocsSearch .algolia-docsearch-suggestion__main .algolia-docsearch-suggestion--title { 261 | display: none; 262 | } 263 | 264 | .DocsSearch .algolia-docsearch-suggestion:not(.algolia-docsearch-suggestion__main) .algolia-docsearch-suggestion--subcategory-column, 265 | .DocsSearch .algolia-docsearch-suggestion:not(.algolia-docsearch-suggestion__main) .algolia-docsearch-suggestion--subcategory-inline { 266 | display: none; 267 | } 268 | 269 | .DocsSearch .algolia-docsearch-suggestion:not(.algolia-docsearch-suggestion__main) .algolia-docsearch-suggestion--category-header, 270 | .DocsSearch .algolia-docsearch-suggestion:not(.algolia-docsearch-suggestion__main) .algolia-docsearch-suggestion--wrapper, 271 | .DocsSearch .algolia-docsearch-suggestion:not(.algolia-docsearch-suggestion__main) .algolia-docsearch-suggestion--content, 272 | .DocsSearch .algolia-docsearch-suggestion:not(.algolia-docsearch-suggestion__main) .algolia-docsearch-suggestion--title { 273 | display: inline; 274 | } 275 | 276 | .DocsSearch .algolia-docsearch-suggestion:not(.algolia-docsearch-suggestion__main) .algolia-docsearch-suggestion--content:not(.algolia-docsearch-suggestion--no-results)::before { 277 | content: "›"; 278 | opacity: .15; 279 | padding: 0 .333em; 280 | display: inline-block; 281 | transform: scale3d(1.5, 1.2, 1); 282 | } 283 | 284 | .DocsSearch .algolia-docsearch-suggestion:not(.algolia-docsearch-suggestion__main) .algolia-docsearch-suggestion--content:not(.algolia-docsearch-suggestion--no-results) .algolia-docsearch-suggestion--title::before { 285 | content: "#"; 286 | padding-right: .25em; 287 | opacity: .5; 288 | } 289 | 290 | @media (max-width: 768px) { 291 | .DocsSearch { 292 | pointer-events: all; 293 | } 294 | 295 | .DocsSearch--input:not(:focus) { 296 | padding: 0; 297 | opacity: 0; 298 | } 299 | 300 | .DocsSearch[is-focused] { 301 | position: fixed; 302 | top: 0; 303 | left: 0; 304 | right: 0; 305 | --text-indent: 3rem; 306 | z-index: 2; 307 | } 308 | 309 | .DocsSearch--input-icon { 310 | left: 15px; 311 | height: 15px; 312 | width: 15px; 313 | } 314 | 315 | .DocsSearch--input-wrapper:focus-within .DocsSearch--input-icon { 316 | left: 19px; 317 | } 318 | 319 | .DocsSearch[is-focused] .DocsSearch--input-wrapper { 320 | background: var(--background-color); 321 | height: var(--docs-header-height); 322 | } 323 | 324 | .DocsSearch--input-bottom-border { 325 | display: none; 326 | } 327 | 328 | .DocsSearch .algolia-autocomplete { 329 | position: fixed; 330 | top: var(--docs-header-height); 331 | width: 100% !important; 332 | } 333 | 334 | @supports ((-webkit-backdrop-filter: blur(1em)) or (backdrop-filter: blur(1em))) { 335 | .DocsSearch .algolia-autocomplete { 336 | background: var(--background-color); 337 | -webkit-backdrop-filter: none; 338 | backdrop-filter: none; 339 | } 340 | 341 | [theme="dark"] .DocsSearch .algolia-autocomplete { 342 | background: var(--background-color); 343 | } 344 | } 345 | } 346 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-sidebar.css: -------------------------------------------------------------------------------- 1 | .DocsSidebar { 2 | position: fixed; 3 | top: 0; 4 | bottom: 0; 5 | --sidebar-background-color: var(--background-color); 6 | --content-indent: var(--docs-page-side-padding); 7 | --logo-size: 2.8235294118rem; /* 48 / 17 */ 8 | --text-indent: calc(var(--content-indent) + var(--logo-size) + var(--docs-logo-lockup-gap) + .1em); 9 | width: var(--docs-sidebar-width); 10 | z-index: 2; 11 | } 12 | 13 | /* TODO: remove once Chromium bug is resolved: 14 | 15 | Reference: 16 | https://github.com/cloudflare/cloudflare-docs-engine/issues/137 17 | https://bugs.chromium.org/p/chromium/issues/detail?id=997607 18 | */ 19 | .DocsSidebar [is-visually-hidden] { 20 | clip-path: none; 21 | left: -10000px; 22 | top: auto; 23 | } 24 | 25 | [theme="dark"] .DocsSidebar { 26 | --sidebar-background-color: var(--gray-0F); 27 | } 28 | 29 | [theme="dark"] .DocsSidebar::before { 30 | content: ""; 31 | position: absolute; 32 | top: 0; 33 | right: 0; 34 | bottom: 0; 35 | width: 999em; 36 | background: var(--sidebar-background-color); 37 | pointer-events: none; 38 | } 39 | 40 | .DocsSidebar--link { 41 | color: inherit; 42 | text-decoration: none; 43 | } 44 | 45 | [js-focus-visible-polyfill-available] .DocsSidebar--link:focus { 46 | outline: none; 47 | } 48 | 49 | .DocsSidebar--link[is-focus-visible]:focus { 50 | box-shadow: 0 0 0 var(--focus-size) var(--focus-color); 51 | } 52 | 53 | .DocsSidebar--link:not([is-focus-visible]) { 54 | --focus-size: 0; 55 | } 56 | 57 | .DocsSidebar--sections { 58 | height: 100%; 59 | display: flex; 60 | flex-direction: column; 61 | } 62 | 63 | .DocsSidebar--shadow { 64 | pointer-events: none; 65 | position: absolute; 66 | top: 0; 67 | right: 0; 68 | bottom: 0; 69 | z-index: 6; 70 | } 71 | 72 | .DocsSidebar--shadow::before, 73 | .DocsSidebar--shadow::after { 74 | content: ""; 75 | position: absolute; 76 | top: 0; 77 | right: 0; 78 | bottom: 0; 79 | background: 80 | linear-gradient(to right, 81 | rgba(var(--shadow-color-rgb), 0), 82 | rgba(var(--shadow-color-rgb), .07) 83 | ); 84 | } 85 | 86 | .DocsSidebar--shadow::before { 87 | width: 5px; 88 | opacity: .8; 89 | } 90 | 91 | .DocsSidebar--shadow::after { 92 | width: 2px; 93 | opacity: .5; 94 | } 95 | 96 | @media (min-width: 769px) { 97 | [theme="dark"] .DocsSidebar--shadow { 98 | left: calc(100% + 2px); 99 | right: auto; 100 | } 101 | 102 | [theme="dark"] .DocsSidebar--shadow::before { 103 | background: rgb(var(--shadow-color-rgb)); 104 | border-right: 1px solid rgba(var(--color-rgb), .15); 105 | } 106 | 107 | [theme="dark"] .DocsSidebar--shadow::before { 108 | width: 1px; 109 | opacity: 1; 110 | } 111 | 112 | [theme="dark"] .DocsSidebar--shadow::after { 113 | opacity: 1; 114 | width: 14px; 115 | right: 1px; 116 | } 117 | } 118 | 119 | .DocsSidebar--section { 120 | position: relative; 121 | } 122 | 123 | .DocsSidebar--section-separator { 124 | position: relative; 125 | flex-shrink: 0; 126 | --fade-indent: 1.25em; 127 | --shadow-opacity: .07; 128 | margin-top: -1px; 129 | } 130 | 131 | [theme="dark"] .DocsSidebar--section-separator { 132 | --shadow-opacity: 1; 133 | } 134 | 135 | .DocsSidebar--section-separator::before, 136 | .DocsSidebar--section-separator::after { 137 | content: ""; 138 | position: absolute; 139 | left: 0; 140 | right: 0; 141 | height: 1px; 142 | } 143 | 144 | .DocsSidebar--section-separator::before { 145 | background: 146 | linear-gradient(to right, 147 | rgba(var(--shadow-color-rgb), 0) 0, 148 | rgba(var(--shadow-color-rgb), var(--shadow-opacity)) var(--fade-indent), 149 | rgba(var(--shadow-color-rgb), var(--shadow-opacity)) 100% 150 | ); 151 | } 152 | 153 | [theme="light"] .DocsSidebar--section-separator::after { 154 | display: none; 155 | } 156 | 157 | [theme="dark"] .DocsSidebar--section-separator::after { 158 | top: 1px; 159 | background: 160 | linear-gradient(to right, 161 | rgba(var(--color-rgb), 0) 0, 162 | rgba(var(--color-rgb), .07) var(--fade-indent), 163 | rgba(var(--color-rgb), .07) 100% 164 | ); 165 | } 166 | 167 | @media (max-width: 1440px) { 168 | .DocsSidebar--section-separator::before { 169 | background: rgba(var(--shadow-color-rgb), var(--shadow-opacity)); 170 | } 171 | 172 | [theme="dark"] .DocsSidebar--section-separator::after { 173 | background: rgba(var(--color-rgb), .07); 174 | } 175 | } 176 | 177 | .DocsSidebar--header-section { 178 | display: flex; 179 | flex-shrink: 0; 180 | height: var(--docs-header-height); 181 | z-index: 1; 182 | } 183 | 184 | .DocsSidebar--cloudflare-logo-link { 185 | --font-size: 1.17647em; /* 20 / 17 */ 186 | display: flex; 187 | align-items: center; 188 | padding-left: var(--content-indent); 189 | padding-right: var(--content-indent); 190 | } 191 | 192 | .DocsSidebar--docs-title-section { 193 | position: relative; 194 | display: flex; 195 | z-index: 7; 196 | } 197 | 198 | .DocsSidebar--docs-title-logo-link { 199 | --font-size: 1.58824em; 200 | padding: .7em var(--content-indent); 201 | max-width: calc(100% - 3em); 202 | } 203 | 204 | .DocsSidebar--cloudflare-logo-link, 205 | .DocsSidebar--docs-title-logo-link { 206 | transition: opacity .2s ease, color .2s ease; 207 | } 208 | 209 | .DocsSidebar--cloudflare-logo-link:hover, 210 | .DocsSidebar--docs-title-logo-link:hover { 211 | opacity: .75; 212 | color: rgba(var(--color-rgb), .75); 213 | } 214 | 215 | .DocsSidebar--docs-title-text-scaler { 216 | /* --length set by React */ 217 | --font-size: 1em * (1 - ((var(--length) - 10) / 20)); 218 | font-size: clamp(.7em, var(--font-size), 1em); 219 | display: inherit; 220 | } 221 | 222 | .DocsSidebar--section-more { 223 | position: absolute; 224 | right: .75em; 225 | top: 0; 226 | bottom: 0; 227 | margin-top: auto; 228 | margin-bottom: auto; 229 | height: 2.5em; 230 | width: 1.75em; 231 | } 232 | 233 | .DocsSidebar--section-more-button { 234 | position: relative; 235 | height: 100%; 236 | width: 100%; 237 | transition: opacity .2s ease; 238 | } 239 | 240 | .DocsSidebar:not(:hover) .DocsSidebar--section-more:not([data-expanded="true"]) .DocsSidebar--section-more-button:not(:focus) { 241 | opacity: 0; 242 | } 243 | 244 | .DocsSidebar--section-more-button-icon { 245 | position: absolute; 246 | top: 0; 247 | right: 0; 248 | bottom: 0; 249 | left: 0; 250 | padding: .625em .4em; 251 | transition: opacity .2s ease; 252 | opacity: .5; 253 | } 254 | 255 | @media (hover: hover) { 256 | .DocsSidebar--section-more-button:hover .DocsSidebar--section-more-button-icon { 257 | opacity: 1; 258 | } 259 | } 260 | 261 | .DocsSidebar--nav-section { 262 | display: flex; 263 | flex-direction: column; 264 | flex: 1; 265 | overflow-y: auto; 266 | -webkit-overflow-scrolling: touch; 267 | scrollbar-width: thin; 268 | scrollbar-color: rgba(var(--color-rgb), .1) transparent; 269 | } 270 | 271 | @media (hover: hover) { 272 | .DocsSidebar--nav-section:hover { 273 | scrollbar-color: rgba(var(--color-rgb), .35) transparent; 274 | } 275 | } 276 | 277 | .DocsSidebar--nav-section-shadow { 278 | position: sticky; 279 | flex-shrink: 0; 280 | top: 0px; 281 | width: 100%; 282 | height: .25em; 283 | box-shadow: inset 0 1px rgba(var(--shadow-color-rgb), .04); 284 | background: 285 | linear-gradient( 286 | rgba(var(--shadow-color-rgb), .09), 287 | rgba(var(--shadow-color-rgb), 0) 288 | ); 289 | opacity: 0; 290 | z-index: 4; 291 | } 292 | 293 | @media (min-width: 1441px) { 294 | .DocsSidebar--nav-section-shadow { 295 | -webkit-mask-image: linear-gradient(to right, transparent, #000 1.5em, #000); 296 | mask-image: linear-gradient(to right, transparent, #000 1.5em, #000); 297 | } 298 | } 299 | 300 | [theme="dark"] .DocsSidebar--nav-section-shadow { 301 | box-shadow: inset 0 1px rgba(var(--shadow-color-rgb), .5); 302 | background: linear-gradient(rgba(var(--shadow-color-rgb), .2), transparent); 303 | height: .5em; 304 | border-top: 1px solid #222; 305 | } 306 | 307 | .DocsSidebar--nav { 308 | list-style: none; 309 | font-size: 1.11em; 310 | padding-top: 0; 311 | padding-bottom: 2em; /* Prevent overlap with browser status bar */ 312 | padding-left: 0; 313 | word-break: break-word; 314 | } 315 | 316 | @media (max-width: 1280px) { 317 | .DocsSidebar--nav { 318 | font-size: 1.05em; 319 | --text-indent: 3rem; 320 | } 321 | } 322 | 323 | .DocsSidebar--nav-item { 324 | position: relative; 325 | } 326 | 327 | .DocsSidebar--nav-item + .DocsSidebar--nav-item { 328 | margin-top: .333em; 329 | } 330 | 331 | .DocsSidebar--nav-expand-collapse-button { 332 | position: absolute; 333 | z-index: 3; 334 | --size: 2em; /* TODO - use calc to derive from effective nav item height */ 335 | --margin-right: .75em; 336 | left: calc(var(--text-indent) - var(--size) - var(--margin-right) + (var(--depth, 0) * 1rem)); 337 | top: 0; 338 | height: var(--size); 339 | width: var(--size); 340 | line-height: .5em; 341 | padding: 0; 342 | text-align: center; 343 | } 344 | 345 | @media (max-width: 1280px) { 346 | .DocsSidebar--nav-expand-collapse-button { 347 | --margin-right: .25em; 348 | } 349 | } 350 | 351 | @media (hover: hover) { 352 | .DocsSidebar--nav-expand-collapse-button:hover, 353 | [theme="dark"] .DocsSidebar--nav-expand-collapse-button:hover { 354 | --hover-box-shadow-color: transparent; 355 | } 356 | 357 | .DocsSidebar--nav-expand-collapse-button:hover { 358 | background: rgba(var(--gray-5-rgb), .2); 359 | } 360 | 361 | [theme="dark"] .DocsSidebar--nav-expand-collapse-button:hover { 362 | color: var(--code-orange); 363 | background: rgba(var(--orange-rgb), .08); 364 | } 365 | } 366 | 367 | .DocsSidebar--nav-expand-collapse-button::before { 368 | content: ""; 369 | position: absolute; 370 | right: 0; 371 | top: 0; 372 | bottom: 0; 373 | width: 5em; 374 | z-index: -1; 375 | } 376 | 377 | .DocsSidebar--nav-expand-collapse-button-content { 378 | display: inline-block; 379 | vertical-align: middle; 380 | transition: transform .4s ease; 381 | border: solid transparent; 382 | border-width: .3333em .6em; 383 | border-left-color: currentColor; 384 | margin-left: 37%; 385 | will-change: transform; 386 | transform: translate3d(0, 0, 0); 387 | transform-origin: .2em .4em; 388 | } 389 | 390 | [theme="dark"] .DocsSidebar--nav-item[is-active] > .DocsSidebar--nav-expand-collapse-button > .DocsSidebar--nav-expand-collapse-button-content, 391 | .DocsSidebar--nav-item[is-active-root]:not([is-expanded]) > .DocsSidebar--nav-expand-collapse-button > .DocsSidebar--nav-expand-collapse-button-content { 392 | color: var(--orange); 393 | } 394 | 395 | @media (hover: hover) { 396 | .DocsSidebar--nav-expand-collapse-button:not(:hover) > .DocsSidebar--nav-expand-collapse-button-content { 397 | opacity: .4; 398 | } 399 | 400 | [theme="dark"] .DocsSidebar--nav-item[is-active] > .DocsSidebar--nav-expand-collapse-button > .DocsSidebar--nav-expand-collapse-button-content { 401 | opacity: .8; 402 | } 403 | 404 | .DocsSidebar--nav-item[is-active-root]:not([is-expanded]) > .DocsSidebar--nav-expand-collapse-button > .DocsSidebar--nav-expand-collapse-button-content { 405 | opacity: 1; 406 | } 407 | } 408 | 409 | .DocsSidebar--nav-item[is-expanded] > .DocsSidebar--nav-expand-collapse-button > .DocsSidebar--nav-expand-collapse-button-content { 410 | transform: rotate(90deg) translate3d(-.1em, 0, 0); 411 | } 412 | 413 | .DocsSidebar--nav-item-collapse-container { 414 | overflow: hidden; 415 | } 416 | 417 | .DocsSidebar--nav-item-collapse-container.DocsSidebar--nav-item-collapse-hidden { 418 | height: 0; 419 | } 420 | 421 | .DocsSidebar--nav-item-collapse-content { 422 | opacity: 0; 423 | transform: translate3d(-.5em, 0, 0); 424 | will-change: transform, opacity; 425 | transition: transform .4s ease, opacity .4s ease; 426 | } 427 | 428 | /* Use > selectors as not to trigger subnavs */ 429 | .DocsSidebar--nav-item[is-expanded] > 430 | .DocsSidebar--nav-item-collapse-container > 431 | .DocsSidebar--nav-item-collapse-wrapper > 432 | .DocsSidebar--nav-item-collapse-wrapperInner > 433 | .DocsSidebar--nav-item-collapse-content, 434 | 435 | /* Handle prefers-reduced-motion case */ 436 | .DocsSidebar--nav-item[is-expanded] > 437 | .DocsSidebar--nav-item-collapse-container > 438 | .DocsSidebar--nav-item-collapse-content { 439 | opacity: 1; 440 | transform: translate3d(0, 0, 0); 441 | } 442 | 443 | @media (prefers-reduced-motion: reduce) { 444 | .DocsSidebar--nav-expand-collapse-button-content, 445 | .DocsSidebar--nav-item-collapse-content { 446 | transition: none; 447 | } 448 | } 449 | 450 | .DocsSidebar--nav-subnav { 451 | list-style: none; 452 | font-size: .94rem; 453 | padding: .25em 0 .75em; 454 | } 455 | 456 | @media (max-width: 1280px) { 457 | .DocsSidebar--nav-subnav { 458 | font-size: .9em; 459 | } 460 | } 461 | 462 | .DocsSidebar--nav-subnav .DocsSidebar--nav-item + .DocsSidebar--nav-item { 463 | margin-top: .0625em; 464 | } 465 | 466 | .DocsSidebar--nav-link { 467 | color: inherit; 468 | text-decoration: none; 469 | position: relative; 470 | display: block; 471 | padding-left: var(--text-indent); 472 | } 473 | 474 | .DocsSidebar--nav-subnav .DocsSidebar--nav-link { 475 | padding-left: calc(var(--text-indent) + (var(--depth) * 1rem)); 476 | } 477 | 478 | .DocsSidebar--nav-link:focus { 479 | z-index: 1; 480 | } 481 | 482 | .DocsSidebar--nav-link[is-active] { 483 | z-index: 2; 484 | } 485 | 486 | .DocsSidebar--nav-link[is-active]::before { 487 | content: ""; 488 | position: absolute; 489 | top: 0; 490 | bottom: 0; 491 | left: 0; 492 | width: .4125em; 493 | background: var(--orange); 494 | z-index: 4; 495 | } 496 | 497 | .DocsSidebar--nav-link-text { 498 | position: relative; 499 | display: inline-block; 500 | padding: .25em .6em; 501 | margin-left: -.6em; 502 | z-index: 1; 503 | } 504 | 505 | @media (hover: hover) { 506 | .DocsSidebar--nav-link:hover .DocsSidebar--nav-link-text::before { 507 | content: ""; 508 | position: absolute; 509 | top: 0; 510 | right: 0; 511 | bottom: 0; 512 | left: 0; 513 | pointer-events: none; 514 | height: 100%; 515 | background: rgba(var(--gray-5-rgb), .2); 516 | z-index: -1; 517 | border-radius: .25em; 518 | } 519 | } 520 | 521 | .DocsSidebar--nav-link[is-active] .DocsSidebar--nav-link-text::before { 522 | content: ""; 523 | position: absolute; 524 | top: 0; 525 | right: 0; 526 | bottom: 0; 527 | left: 0; 528 | pointer-events: none; 529 | height: 100%; 530 | background: rgba(var(--gray-5-rgb), .2); 531 | z-index: -1; 532 | border-radius: .25em; 533 | } 534 | 535 | @media (max-width: 1440px) { 536 | .DocsSidebar--nav-link[is-active] .DocsSidebar--nav-link-text::before { 537 | left: calc(-1 * var(--docs-sidebar-width)); 538 | border-top-left-radius: 0; 539 | border-bottom-left-radius: 0; 540 | } 541 | } 542 | 543 | @media (min-width: 1441px) { 544 | .DocsSidebar--nav-link[is-active]::before { 545 | display: none; 546 | } 547 | } 548 | 549 | @media (hover: hover) { 550 | [theme="dark"] .DocsSidebar--nav-link:hover .DocsSidebar--nav-link-text { 551 | color: var(--code-orange); 552 | } 553 | 554 | [theme="dark"] .DocsSidebar--nav-link:hover .DocsSidebar--nav-link-text::before { 555 | background: rgba(var(--orange-rgb), .08); 556 | } 557 | } 558 | 559 | [theme="dark"] .DocsSidebar--nav-link[is-active] .DocsSidebar--nav-link-text { 560 | color: var(--code-orange); 561 | } 562 | 563 | [theme="dark"] .DocsSidebar--nav-link[is-active] .DocsSidebar--nav-link-text::before { 564 | background: rgba(var(--orange-rgb), .08); 565 | } 566 | 567 | .DocsSidebar--nav-link .DocsSidebar--nav-link-text::after { 568 | content: ""; 569 | position: absolute; 570 | top: 0; 571 | right: 0; 572 | bottom: 0; 573 | left: 0; 574 | pointer-events: none; 575 | border-radius: .25em; 576 | } 577 | 578 | [js-focus-visible-polyfill-available] .DocsSidebar--nav-link:focus { 579 | outline: none; 580 | } 581 | 582 | .DocsSidebar--nav-link[is-focus-visible]:focus .DocsSidebar--nav-link-text::after { 583 | box-shadow: 0 0 0 var(--focus-size) var(--focus-color); 584 | } 585 | 586 | @media (max-width: 768px) { 587 | .DocsSidebar { 588 | z-index: 20; 589 | background: var(--sidebar-background-color); 590 | width: calc(100% - 3.5rem); 591 | transform: translate3d(-100%, 0, 0); 592 | will-change: transform; 593 | transition: transform .3s ease; 594 | } 595 | 596 | [theme="dark"] .DocsSidebar { 597 | --sidebar-background-color: var(--background-color); 598 | } 599 | 600 | .DocsSidebar--shadow { 601 | opacity: 0; 602 | transition: opacity .3s ease; 603 | } 604 | 605 | .DocsSidebar--shadow, 606 | .DocsSidebar--shadow::before, 607 | .DocsSidebar--shadow::after { 608 | right: auto; 609 | left: 100%; 610 | } 611 | 612 | .DocsSidebar--shadow::before, 613 | .DocsSidebar--shadow::after { 614 | background: 615 | linear-gradient(to left, 616 | rgba(var(--shadow-color-rgb), 0), 617 | rgba(var(--shadow-color-rgb), .2) 618 | ); 619 | } 620 | 621 | .DocsSidebar--shadow::before { 622 | width: .3125em; 623 | } 624 | 625 | [is-resizing] .DocsSidebar { 626 | transition: none; 627 | } 628 | 629 | [is-mobile-sidebar-open] .DocsSidebar { 630 | transform: translate3d(0, 0, 0); 631 | } 632 | 633 | [is-mobile-sidebar-open] .DocsSidebar--shadow { 634 | opacity: 1; 635 | } 636 | 637 | .DocsSidebar--header-section, 638 | .DocsSidebar--header-section + .DocsSidebar--section-separator, 639 | .DocsSidebar--docs-title-section, 640 | .DocsSidebar--nav-section-shadow { 641 | display: none; 642 | } 643 | 644 | .DocsSidebar--nav { 645 | padding: 1rem 0; 646 | } 647 | } 648 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-table-of-contents.css: -------------------------------------------------------------------------------- 1 | .DocsTableOfContents { 2 | list-style: none; 3 | font-size: .94117647059em; /* 16 / 17 */ 4 | padding-left: 0; 5 | width: 100%; 6 | } 7 | 8 | .DocsTableOfContents ul { 9 | padding-left: 1.5em; 10 | list-style: none; 11 | } 12 | 13 | .DocsTableOfContents ul ul { 14 | font-size: .9em; 15 | padding-left: 1.5em; 16 | margin-bottom: .25em; 17 | } 18 | 19 | @media (max-height: 768px) { 20 | .DocsTableOfContents ul ul { 21 | display: none; 22 | } 23 | } 24 | 25 | .DocsTableOfContents ul ul ul { 26 | display: none; 27 | } 28 | 29 | .DocsTableOfContents-link { 30 | display: inline-block; 31 | line-height: 1.3; 32 | max-width: 100%; 33 | white-space: nowrap; 34 | text-overflow: ellipsis; 35 | overflow: hidden; 36 | text-decoration: none; 37 | color: inherit; 38 | text-decoration: none; 39 | padding: .2em 0; 40 | margin: -.2em 0; 41 | } 42 | 43 | .DocsTableOfContents-link:hover { 44 | color: var(--orange); 45 | } 46 | 47 | [js-focus-visible-polyfill-available] .DocsTableOfContents-link:focus { 48 | outline: none; 49 | } 50 | 51 | .DocsTableOfContents-link[is-focus-visible]:focus { 52 | box-shadow: 0 0 0 var(--focus-size) var(--focus-color); 53 | } 54 | 55 | .DocsTableOfContents-link:not([is-focus-visible]) { 56 | --focus-size: 0; 57 | } 58 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-toolbar.css: -------------------------------------------------------------------------------- 1 | .DocsToolbar { 2 | position: absolute; 3 | left: var(--docs-sidebar-width); 4 | top: 0; 5 | right: 0; 6 | display: flex; 7 | height: var(--docs-header-height); 8 | z-index: 2; 9 | } 10 | 11 | .DocsToolbar--search { 12 | flex: 1; 13 | max-width: var(--docs-body-width); 14 | margin-right: auto; 15 | } 16 | 17 | [search-disabled] .DocsToolbar--search { 18 | visibility: hidden; 19 | } 20 | 21 | .DocsToolbar--tools { 22 | display: flex; 23 | align-items: center; 24 | justify-content: flex-end; 25 | padding: 0 var(--docs-page-side-padding); 26 | } 27 | 28 | .DocsToolbar--tools-spacer { 29 | display: inline-flex; 30 | height: 1em; 31 | width: 1em; 32 | } 33 | 34 | .DocsToolbar--tools-icon-item { 35 | display: inline-flex; 36 | height: 1.647058823rem; 37 | width: 1.647058823rem; 38 | color: rgba(var(--color-rgb), .7); 39 | } 40 | 41 | [theme="light"] .DocsToolbar--tools-icon-item { 42 | color: var(--gray-3); 43 | } 44 | 45 | .DocsToolbar--tools-icon-item-content > a { 46 | display: block; 47 | height: 100%; 48 | width: 100%; 49 | padding: .1em; 50 | } 51 | 52 | @media (max-width: 768px) { 53 | .DocsToolbar { 54 | left: 0; 55 | z-index: 12; 56 | pointer-events: none; 57 | } 58 | 59 | .DocsToolbar--tools { 60 | pointer-events: all; 61 | padding-left: 0; 62 | padding-right: .9rem; 63 | } 64 | 65 | .DocsToolbar--search { 66 | flex-basis: 3em; 67 | flex-grow: 0; 68 | margin-left: auto; 69 | margin-right: 0; 70 | max-width: 100vw; 71 | } 72 | 73 | .DocsToolbar--tools-spacer, 74 | .DocsToolbar--tools-icon-item { 75 | display: none; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/css/docs/components/docs-tutorials.css: -------------------------------------------------------------------------------- 1 | .DocsTutorials { 2 | margin: 2em 0; 3 | width: 53em; 4 | max-width: 100%; 5 | } 6 | 7 | [theme="dark"] .DocsTutorials { 8 | color: var(--gray-7); 9 | } 10 | 11 | .DocsTutorials--row { 12 | display: flex; 13 | align-items: baseline; 14 | --gap: 1.5em; 15 | padding-bottom: .5em; 16 | border-bottom: 1px solid rgba(var(--color-rgb), .1); 17 | margin-bottom: .5em; 18 | } 19 | 20 | .DocsTutorials--body .DocsTutorials--row:last-child { 21 | margin-bottom: 0; 22 | border-bottom: 0; 23 | } 24 | 25 | .DocsTutorials--header .DocsTutorials--column-text { 26 | font-size: .9em; 27 | font-weight: bold; 28 | } 29 | 30 | .DocsTutorials--header .DocsTutorials--row { 31 | border-bottom-width: .125em; 32 | padding-bottom: .1875em; 33 | } 34 | 35 | .DocsTutorials--body .DocsTutorials--column:not([data-column="name"]) { 36 | position: relative; 37 | top: -.1em; 38 | } 39 | 40 | .DocsTutorials--body .DocsTutorials--column[data-column="length"] { 41 | top: -.2em; 42 | } 43 | 44 | .DocsTutorials--column[data-column="name"] { 45 | flex: 1; 46 | padding-right: calc(var(--gap) / 2); 47 | } 48 | 49 | .DocsTutorials--link { 50 | position: relative; 51 | font-size: 1.2em; 52 | color: inherit; 53 | --underline-opacity: .75; 54 | text-decoration-color: rgba(var(--orange-rgb), var(--underline-opacity)); 55 | box-shadow: 0 0 0 var(--focus-size) var(--focus-color); 56 | } 57 | 58 | [theme="dark"] .DocsTutorials--link { 59 | --underline-opacity: .5; 60 | } 61 | 62 | .DocsTutorials--row-is-new .DocsTutorials--link::after { 63 | content: ""; 64 | position: absolute; 65 | top: .45em; 66 | right: 100%; 67 | margin-right: .625em; 68 | height: 8px; 69 | width: 8px; 70 | border-radius: 999em; 71 | background: var(--orange); 72 | } 73 | 74 | @media (max-width: 1280px) { 75 | .DocsTutorials--link { 76 | text-decoration: none; 77 | box-shadow: inset 0 -2px rgba(var(--orange-rgb), var(--underline-opacity)); 78 | } 79 | 80 | .DocsTutorials--row-is-new .DocsTutorials--link::after { 81 | top: .375em; 82 | } 83 | } 84 | 85 | @media (max-width: 768px) { 86 | .DocsTutorials--link { 87 | font-size: 1.1em; 88 | } 89 | 90 | .DocsTutorials--row-is-new .DocsTutorials--link::after { 91 | display: none; 92 | } 93 | } 94 | 95 | @media (max-width: 414px) { 96 | .DocsTutorials--link { 97 | font-size: 1em; 98 | } 99 | 100 | .DocsTutorials--ago-text { 101 | display: none; 102 | } 103 | } 104 | 105 | [js-focus-visible-polyfill-available] .DocsTutorials--link:focus { 106 | outline: none; 107 | } 108 | 109 | .DocsTutorials--link[is-focus-visible] { 110 | --underline-size: 0; 111 | } 112 | 113 | .DocsTutorials--link:not([is-focus-visible]) { 114 | --focus-size: 0; 115 | } 116 | 117 | .DocsTutorials--column[data-column="updated"] { 118 | padding-left: calc(var(--gap) / 2); 119 | padding-right: calc(var(--gap) / 2); 120 | } 121 | 122 | .DocsTutorials--column[data-column="difficulty"] { 123 | width: 7.5em; 124 | padding-left: calc(var(--gap) / 2); 125 | padding-right: calc(var(--gap) / 2); 126 | flex-shrink: 0; 127 | } 128 | 129 | .DocsTutorials--column[data-column="length"] { 130 | width: 4.5em; 131 | padding-left: calc(var(--gap) / 2); 132 | flex-shrink: 0; 133 | } 134 | 135 | .DocsTutorials--length-bar { 136 | width: 100%; 137 | height: .5em; 138 | border-radius: 1em; 139 | background: rgba(var(--color-rgb), .1); 140 | overflow: hidden; 141 | } 142 | 143 | .DocsTutorials--length-bar-inner { 144 | background: rgba(var(--color-rgb), .5); 145 | border-radius: 1em; 146 | min-width: .6em; 147 | height: 100%; 148 | } 149 | 150 | @media (max-width: 1024px) { 151 | .DocsTutorials--column[data-column="updated"] { 152 | padding-right: 0; 153 | } 154 | 155 | .DocsTutorials--column[data-column="difficulty"], 156 | .DocsTutorials--column[data-column="length"] { 157 | display: none; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/css/docs/components/skip-nav-link.css: -------------------------------------------------------------------------------- 1 | .SkipNavLink { 2 | position: absolute; 3 | overflow: hidden; 4 | color: inherit; 5 | text-decoration: none; 6 | clip: rect(0 0 0 0); 7 | height: 1px; 8 | width: 1px; 9 | margin: -1px; 10 | padding: 0; 11 | } 12 | 13 | .SkipNavLink:focus { 14 | padding: .5em 1em; 15 | position: fixed; 16 | top: 0; 17 | left: 50%; 18 | transform: translate3d(-50%, 0, 0); 19 | background: var(--background-color); 20 | width: auto; 21 | height: auto; 22 | clip: auto; 23 | z-index: 100; 24 | outline: none; 25 | box-shadow: 0 0 0 var(--focus-size) var(--focus-color); 26 | } 27 | -------------------------------------------------------------------------------- /src/css/docs/components/tags-filter.css: -------------------------------------------------------------------------------- 1 | .TagsFilter { 2 | display: flex; 3 | flex-wrap: wrap; 4 | margin: 0 -.25em; 5 | } 6 | 7 | .TagsFilter--button { 8 | --border-color: rgba(var(--color-rgb), .2); 9 | padding: .25em .3125em; 10 | margin: .3125em .25em; 11 | border-radius: .125em; 12 | } 13 | 14 | .TagsFilter--button[is-focus-visible] { 15 | --border-color: rgba(var(--orange-rgb), .7); 16 | } 17 | 18 | .TagsFilter--button-active { 19 | pointer-events: none; 20 | } 21 | 22 | [theme="light"] .TagsFilter--button-active { 23 | --border-color: transparent; 24 | } 25 | 26 | [theme="dark"] .TagsFilter--button-active { 27 | color: var(--code-orange); 28 | } 29 | -------------------------------------------------------------------------------- /src/css/docs/components/worker-starter.css: -------------------------------------------------------------------------------- 1 | .WorkerStarter { 2 | display: block; 3 | margin-top: 2.5rem; 4 | } 5 | 6 | .WorkerStarter + .WorkerStarter { 7 | margin-top: 3rem; 8 | } 9 | 10 | .WorkerStarter--title { 11 | font-size: 1.35em; 12 | line-height: 1.2; 13 | font-weight: 500; 14 | margin-bottom: .3125em; 15 | } 16 | 17 | .WorkerStarter--title .Link { /* TODO */ 18 | color: inherit; 19 | --underline-opacity: .75; 20 | text-decoration: underline; 21 | text-decoration-color: rgba(var(--orange-rgb), var(--underline-opacity)); 22 | box-shadow: 0 0 0 var(--focus-size) var(--focus-color); 23 | } 24 | 25 | @media (max-width: 768px) { 26 | .WorkerStarter--title { 27 | font-size: 1.375em; 28 | margin-bottom: .5rem; 29 | } 30 | } 31 | 32 | .WorkerStarter--description { 33 | display: block; 34 | margin-bottom: .4375rem; 35 | width: calc(100% - var(--docs-body-sidebar-width)); 36 | } 37 | 38 | .WorkerStarter--command { 39 | position: relative; 40 | font-size: .9em; 41 | --copy-button-width: 4rem; 42 | --height: 2.5rem; 43 | } 44 | 45 | .WorkerStarter--command-copy-button-wrapper { 46 | position: absolute; 47 | width: calc(var(--copy-button-width) - 2px); 48 | height: var(--height); 49 | } 50 | 51 | .WorkerStarter--command-copy-button-wrapper button { 52 | width: 100%; 53 | height: 100%; 54 | border-top-right-radius: 0; 55 | border-bottom-right-radius: 0; 56 | font-weight: 600; 57 | background: var(--code-block-background-color); 58 | } 59 | 60 | [theme="light"] .WorkerStarter--command-copy-button-wrapper button { 61 | background: var(--code-block-background-color-light-theme); 62 | } 63 | 64 | .WorkerStarter--command-codeblock-wrapper { 65 | padding-left: var(--copy-button-width); 66 | } 67 | 68 | .WorkerStarter--command .WorkerStarter--command-codeblock-wrapper pre { 69 | height: var(--height); 70 | line-height: 1.4; 71 | margin-bottom: 0; 72 | border-top-left-radius: 0; 73 | border-bottom-left-radius: 0; 74 | overflow: hidden; 75 | } 76 | -------------------------------------------------------------------------------- /src/html.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | import googleAnalytics from "./utils/google-analytics" 4 | 5 | export default function HTML(props) { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | { props.headComponents } 13 |