├── static └── admin │ ├── index.html │ ├── config.yml │ └── dark.css ├── functions └── api │ ├── auth.js │ └── callback.js ├── LICENSE └── README.md /static/admin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Content Manager 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /static/admin/config.yml: -------------------------------------------------------------------------------- 1 | backend: 2 | name: github 3 | repo: username/repo 4 | branch: main # Branch to update (optional; defaults to master) 5 | base_url: https://example.com 6 | auth_endpoint: /api/auth 7 | media_folder: static/img 8 | public_folder: /img 9 | collections: 10 | - name: 'blog' 11 | label: 'Blog' 12 | folder: 'content/blog' 13 | create: true 14 | slug: '{{slug}}' 15 | editor: 16 | preview: false 17 | fields: 18 | - { label: 'Title', name: 'title', widget: 'string' } 19 | - { label: 'Publish Date', name: 'date', widget: 'datetime' } 20 | - { label: 'Description', name: 'description', widget: 'string' } 21 | - { label: 'Body', name: 'body', widget: 'markdown' } 22 | -------------------------------------------------------------------------------- /functions/api/auth.js: -------------------------------------------------------------------------------- 1 | export async function onRequest(context) { 2 | const { 3 | request, // same as existing Worker API 4 | env, // same as existing Worker API 5 | params, // if filename includes [id] or [[path]] 6 | waitUntil, // same as ctx.waitUntil in existing Worker API 7 | next, // used for middleware or to fetch assets 8 | data, // arbitrary space for passing data between middlewares 9 | } = context; 10 | 11 | const client_id = env.GITHUB_CLIENT_ID; 12 | 13 | try { 14 | const url = new URL(request.url); 15 | const redirectUrl = new URL('https://github.com/login/oauth/authorize'); 16 | redirectUrl.searchParams.set('client_id', client_id); 17 | redirectUrl.searchParams.set('redirect_uri', url.origin + '/api/callback'); 18 | redirectUrl.searchParams.set('scope', 'repo user'); 19 | redirectUrl.searchParams.set( 20 | 'state', 21 | crypto.getRandomValues(new Uint8Array(12)).join(''), 22 | ); 23 | return Response.redirect(redirectUrl.href, 301); 24 | 25 | } catch (error) { 26 | console.error(error); 27 | return new Response(error.message, { 28 | status: 500, 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, Jeremy Nixon 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /functions/api/callback.js: -------------------------------------------------------------------------------- 1 | function renderBody(status, content) { 2 | const html = ` 3 | 14 | `; 15 | const blob = new Blob([html]); 16 | return blob; 17 | } 18 | 19 | export async function onRequest(context) { 20 | const { 21 | request, // same as existing Worker API 22 | env, // same as existing Worker API 23 | params, // if filename includes [id] or [[path]] 24 | waitUntil, // same as ctx.waitUntil in existing Worker API 25 | next, // used for middleware or to fetch assets 26 | data, // arbitrary space for passing data between middlewares 27 | } = context; 28 | 29 | const client_id = env.GITHUB_CLIENT_ID; 30 | const client_secret = env.GITHUB_CLIENT_SECRET; 31 | 32 | try { 33 | const url = new URL(request.url); 34 | const code = url.searchParams.get('code'); 35 | const response = await fetch( 36 | 'https://github.com/login/oauth/access_token', 37 | { 38 | method: 'POST', 39 | headers: { 40 | 'content-type': 'application/json', 41 | 'user-agent': 'cloudflare-functions-github-oauth-login-demo', 42 | 'accept': 'application/json', 43 | }, 44 | body: JSON.stringify({ client_id, client_secret, code }), 45 | }, 46 | ); 47 | const result = await response.json(); 48 | if (result.error) { 49 | return new Response(renderBody('error', result), { 50 | headers: { 51 | 'content-type': 'text/html;charset=UTF-8', 52 | }, 53 | status: 401 54 | }); 55 | } 56 | const token = result.access_token; 57 | const provider = 'github'; 58 | const responseBody = renderBody('success', { 59 | token, 60 | provider, 61 | }); 62 | return new Response(responseBody, { 63 | headers: { 64 | 'content-type': 'text/html;charset=UTF-8', 65 | }, 66 | status: 200 67 | }); 68 | 69 | } catch (error) { 70 | console.error(error); 71 | return new Response(error.message, { 72 | headers: { 73 | 'content-type': 'text/html;charset=UTF-8', 74 | }, 75 | status: 500, 76 | }); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # netlify-cms-cloudflare-pages 2 | 3 | [Decap CMS](https://www.decapcms.org) (formerly Netlify CMS) needs to authenticate to Github with OAuth. Github needs a server to talk to during the authentication process. If you’re hosting at Netlify, they take care of that. If not, you’re on your own, and the documentation is... imperfect. 😂 4 | 5 | If you’re deploying to [Cloudflare Pages](https://pages.cloudflare.com) this may be the code you’re looking for. It provides API endpoints for Github to talk to, running on Cloudflare Functions. Functions are kind of like Cloudflare Workers, but they run right from your Pages site. 6 | 7 | ## Credits 8 | This is based on [d3v1an7/netlify-cms-oauth-cloudflare](https://github.com/d3v1an7/netlify-cms-oauth-cloudflare) adapted for Cloudflare Functions. 9 | 10 | ## Installation 11 | 12 | ### 1. Create OAuth application at Github 13 | 14 | Go to Settings -> Developer Settings and choose [OAuth Apps](https://github.com/settings/developers). Create a new OAuth App. Name it anything you like. **Homepage URL** should be set to your site’s URL. **Authorization callback URL** is the important part; it, too, can be set to your homepage URL (like `https://example.com`). Other guides say to set this to the callback API endpoint, but the documented requirement is that the callback URL be a subdirectory of this URL, and using the callback URL itself didn’t work for me. 15 | 16 | Github will give you a **Client ID**, and you can generate a **Client Secret** at this time. You will need both. 17 | 18 | ### 2. Add Client ID and Secret to your Cloudflare project 19 | 20 | In your Cloudflare Pages project, go to Settings -> Environment variables. Add two environment variables, **GITHUB_CLIENT_ID** set to the client ID from above, and **GITHUB_CLIENT_SECRET** set to the secret. 21 | 22 | ### 3. Add the files to your project 23 | 24 | Take the `functions` directory from this repo and add it to your project at the top level. **NOTE:** This means the actual top-level of the project itself, _not_ the top level of your output directory. So, if you’re using Hugo, `functions` goes at the top of the project next to `content` and `layouts` and `archetypes` and so forth, _not_ inside the `static` or `assets` directory. 25 | 26 | If you haven’t already installed the Decap CMS files, take the `static/admin` directory from this repo and add it to your `static` directory (for Hugo) or wherever you add files to be deployed as-is to your site. There are two files under `admin`, a stub HTML file that loads the CMS, and the CMS config file `config.yml`. You can change the name of the `admin` directory. 27 | 28 | The config file included here is a starter file only; you need to set this up for your site, which is beyond the scope of these instructions. However, you must set `base_url` in this config to the URL of your site (like `https://example.com`). Setting `auth_endpoint` here is optional because the default path works for the way this repo is set up. 29 | 30 | ### 4. Profit! 31 | 32 | Publish your site and let Cloudflare build it. Go to `/admin/` on your site, and you should see a Login with Github button, which should authenticate you to Github and launch the CMS. 33 | 34 | 35 | -------------------------------------------------------------------------------- /static/admin/dark.css: -------------------------------------------------------------------------------- 1 | @media (min-width: 1120px) { 2 | .css-1f3mf5k-StyledModal { 3 | width: calc(940px); 4 | } 5 | } 6 | 7 | @media (prefers-color-scheme: dark) { 8 | :root { 9 | --body-bg-color: #0d1117; 10 | --primary-text-color: #c9d1d9; 11 | --secondary-text-color: #8b949e; 12 | --success-text-color: #3fb950; 13 | --danger-text-color: #ff003b; 14 | --disabled-text-color: #484f58; 15 | --url-text-color: #58a6ff; 16 | --input-bg-color: #0d1117; 17 | --input-border-color: #21262d; 18 | --input-placeholder-color: #8b949e; 19 | --btn-gray-default-bg: #21262d; 20 | --btn-gray-default-border: #30363d; 21 | --btn-gray-hover-bg: #30363d; 22 | --btn-gray-hover-border: #8b949e; 23 | --btn-gray-focus-bg: #21262d; 24 | --btn-gray-disabled-text: #484f58; 25 | --btn-gray-disabled-bg: #21262d; 26 | --btn-gray-disabled-border: #30363d; 27 | --btn-red-default-text: #f85149; 28 | --btn-red-default-bg: #21262d; 29 | --btn-red-default-border: #30363d; 30 | --btn-red-hover-text: #fff; 31 | --btn-red-hover-bg: #da3633; 32 | --btn-red-hover-border: #f85149; 33 | --btn-red-active-bg: #b62324; 34 | --btn-red-active-border: rgb(240 246 252 / 10%); 35 | --btn-red-disabled-text: rgb(248 81 73 / 50%); 36 | --btn-red-disabled-bg: #0d1117; 37 | --btn-green-default-text: #fff; 38 | --btn-green-default-bg: #238636; 39 | --btn-green-default-border: #2ea043; 40 | --btn-green-hover-bg: #2ea043; 41 | --btn-green-hover-border: #3fb950; 42 | --btn-green-active-bg: #238636; 43 | --btn-green-disabled-text: rgb(240 246 252 / 50%); 44 | --btn-green-disabled-bg: rgb(35 134 54 / 60%); 45 | --btn-green-disabled-border: transparent; 46 | --scrollbar-thumb-color: #4c5258; 47 | --scrollbar-thumb-hover-color: #30363d; 48 | --dropdownlist-bg: #21262d; 49 | --dropdownlist-border: #30363d; 50 | --dropdownlist-shadow: 0 16px 32px rgba(1,4,9,0.85); 51 | --dropdownitem-bg: #21262d; 52 | --dropdownitem-hover-bg: #161b22; 53 | --header-bg: #161b22; 54 | --header-button-text: #8b949e; 55 | --header-button-text-hover: #c9d1d9; 56 | --header-button-text-active: #fff; 57 | --header-dropdownitem-hover-text: #f0f6fc; 58 | --header-dropdownitem-hover-bg: #1f6feb; 59 | --card-bg: #0d1117; 60 | --card-border: #30363d; 61 | --card-hover-bg: #161b22; 62 | --modal-bg-color: #0d1117; 63 | --modal-border-color: #30363d; 64 | --modal-box-shadow: 0 0 18px rgb(0 0 0 / 40%); 65 | --card-active-border: #8b949e; 66 | --checkerboard-dark-color: #161b22; 67 | --checkerboard-bg-color: #21262d; 68 | --widgets-bg-color: #090d13; 69 | --widgets-label-bg-color: #21262d; 70 | --widgets-border-color: #21262d; 71 | --widgets-active-label-bg-color: #388bfd; 72 | --widgets-active-border-color: #388bfd; 73 | --widgets-error-label-bg-color: #ff003b; 74 | --widgets-error-border-color: #ff003b; 75 | --rdtPicker-bg-color: #21262d; 76 | --rdtPicker-border-color: #30363d; 77 | --rdtPicker-shadow: 0 16px 32px rgb(1 4 9 / 85%); 78 | --rdtPicker-hover-bg-color: #161b22; 79 | --rdtPicker-active-bg-color: #388bfd; 80 | --color-picker-bg-color: #21262d; 81 | --color-picker-border-color: #30363d; 82 | --color-picker-shadow: 0 16px 32px rgb(1 4 9 / 85%); 83 | --toggle-true-bg-color: #8b949e; 84 | --toggle-false-bg-color: #30363d; 85 | --toggle-handle-color: #414b54; 86 | --topbar-bg-color: #161b22; 87 | --short-code-bg-color: rgb(240 246 252 / 15%); 88 | --code-block-bg-color: #161b22; 89 | --code-line-number-color: #8b949e; 90 | } 91 | 92 | body { 93 | background-color: var(--body-bg-color); 94 | color: var(--primary-text-color); 95 | } 96 | a { 97 | font-size: inherit; 98 | color: var(--url-text-color); 99 | } 100 | h1, h2, h3, h4, h5, h6, p { 101 | color: inherit; 102 | } 103 | ::-webkit-scrollbar-thumb { 104 | background-color: var(--scrollbar-thumb-color) !important; 105 | border: unset !important; 106 | border-radius: 4px; 107 | } 108 | ::-webkit-scrollbar-thumb:hover { 109 | background-color: var(--scrollbar-thumb-hover-color) !important; 110 | } 111 | ::-webkit-scrollbar-track { 112 | background: var(--body-bg-color) !important; 113 | } 114 | iframe#netlify-identity-widget { 115 | z-index: 400 !important; 116 | } 117 | /* button */ 118 | /* gray button */ 119 | [class*="button-default-gray"], 120 | [class*="button-medium-gray "], 121 | [class*="button-default-disabled"], 122 | [class*="button-default-lightBlue"], 123 | [class*="AddButton-button"], 124 | [class*="FileWidgetButton-button"], 125 | [class*="SaveButton-lightBlue"], 126 | [class*="StatusButton"], 127 | [class*="StyledDropdownButton"]:not([class*="grayText"]):not([class*="Publish"]) 128 | { 129 | color: var(--primary-text-color); 130 | background-color: var(--btn-gray-default-bg); 131 | border: 1px solid; 132 | border-color: var(--btn-gray-default-border); 133 | border-radius: 6px; 134 | transition: .2s cubic-bezier(.3,0,.5,1); 135 | transition-property: color,background-color,border-color; 136 | } 137 | 138 | [class*="button-default-gray"]:hover, 139 | [class*="button-medium-gray "]:hover, 140 | [class*="button-default-disabled"]:hover, 141 | [class*="button-default-lightBlue"]:hover, 142 | [class*="AddButton-button"]:hover, 143 | [class*="FileWidgetButton-button"]:hover, 144 | [class*="SaveButton-lightBlue"]:hover, 145 | [class*="StatusButton"]:hover, 146 | [class*="StyledDropdownButton"]:not([class*="grayText"]):not([class*="Publish"]):hover 147 | { 148 | background-color: var(--btn-gray-hover-bg); 149 | border-color: var(--btn-gray-hover-border); 150 | transition-duration: .1s; 151 | } 152 | 153 | [class*="button-default-gray"]:focus, 154 | [class*="button-medium-gray "]:focus, 155 | [class*="button-default-disabled"]:focus, 156 | [class*="button-default-lightBlue"]:focus, 157 | [class*="AddButton-button"]:focus, 158 | [class*="FileWidgetButton-button"]:focus, 159 | [class*="SaveButton-lightBlue"]:focus, 160 | [class*="StatusButton"]:focus, 161 | [class*="StyledDropdownButton"]:not([class*="grayText"]):not([class*="Publish"]):focus 162 | { 163 | color: var(--primary-text-color); 164 | background-color: var(--btn-gray-focus-bg); 165 | } 166 | 167 | [class*="button-default-disabled"][disabled] { 168 | color: var(--btn-gray-disabled-text); 169 | background-color: var(--btn-gray-disabled-bg); 170 | border: 1px solid; 171 | border-color: var(--btn-gray-disabled-border); 172 | border-radius: 6px; 173 | } 174 | 175 | /* red button */ 176 | [class*="utton-lightRed"], 177 | [class*="FileWidgetButtonRemove-button"], 178 | [class*="DeleteButton"] 179 | { 180 | color: var(--btn-red-default-text); 181 | background-color: var(--btn-red-default-bg); 182 | border: 1px solid; 183 | border-color: var(--btn-red-default-border); 184 | border-radius: 6px; 185 | transition: .2s cubic-bezier(.3,0,.5,1); 186 | transition-property: color,background-color,border-color; 187 | } 188 | 189 | [class*="utton-lightRed"]:hover, 190 | [class*="FileWidgetButtonRemove-button"]:hover, 191 | [class*="DeleteButton"]:hover 192 | { 193 | color: var(--btn-red-hover-text); 194 | background-color: var(--btn-red-hover-bg); 195 | border-color: var(--btn-red-hover-border); 196 | transition-duration: .1s; 197 | } 198 | 199 | [class*="utton-lightRed"]:focus, 200 | [class*="FileWidgetButtonRemove-button"]:focus, 201 | [class*="DeleteButton"]:focus 202 | { 203 | border-color: var(--btn-red-hover-border); 204 | } 205 | 206 | [class*="utton-lightRed"]:active, 207 | [class*="FileWidgetButtonRemove-button"]:active, 208 | [class*="DeleteButton"]:active 209 | { 210 | color: var(--btn-red-hover-text); 211 | background-color: var(--btn-red-active-bg); 212 | border-color: var(--btn-red-active-border); 213 | } 214 | 215 | [class*="utton-lightRed"][disabled] { 216 | color: var(--btn-red-disabled-text); 217 | background-color: var(--btn-red-disabled-bg); 218 | border: 1px solid; 219 | border-color: var(--btn-red-default-border); 220 | border-radius: 6px; 221 | } 222 | /* green button */ 223 | [class*="button-green"], 224 | [class*="PublishButton"], 225 | [class*="publishedButton"] 226 | { 227 | color: var(--btn-green-default-text); 228 | background-color: var(--btn-green-default-bg); 229 | border: 1px solid; 230 | border-color: var(--btn-green-default-border); 231 | border-radius: 6px; 232 | transition: .2s cubic-bezier(.3,0,.5,1); 233 | transition-property: color,background-color,border-color; 234 | } 235 | 236 | [class*="button-green"]:hover, 237 | [class*="PublishButton"]:hover, 238 | [class*="publishedButton"]:hover 239 | { 240 | background-color: var(--btn-green-hover-bg); 241 | border-color: var(--btn-green-hover-border); 242 | transition-duration: .1s; 243 | } 244 | 245 | [class*="button-green"]:active, 246 | [class*="PublishButton"]:active, 247 | [class*="publishedButton"]:active 248 | { 249 | background-color: var(--btn-green-active-bg); 250 | } 251 | 252 | [class*="button-green"]:focus, 253 | [class*="PublishButton"]:focus, 254 | [class*="publishedButton"]:focus 255 | { 256 | background-color: var(--btn-green-active-bg); 257 | border-color: var(--btn-green-hover-border); 258 | } 259 | 260 | [class*="button-green"][disabled], 261 | [class*="PublishButton"][disabled] 262 | { 263 | color: var(--btn-green-disabled-text); 264 | background-color: var(--btn-green-disabled-bg); 265 | border: 1px solid; 266 | border-color: var(--btn-green-disabled-border); 267 | border-radius: 6px; 268 | } 269 | /* notification */ 270 | [class*="toast-success"] { 271 | color: var(--success-text-color); 272 | background-color: var(--dropdownitem-bg); 273 | box-shadow: var(--dropdownlist-shadow); 274 | border-radius: 6px; 275 | } 276 | [class*="toast-danger"] { 277 | color: var(--danger-text-color); 278 | background-color: var(--dropdownitem-bg); 279 | box-shadow: var(--dropdownlist-shadow); 280 | border-radius: 6px; 281 | } 282 | 283 | /* dropdown */ 284 | ul[class*="dropdownList"], 285 | ul[class*="Suggestions"], 286 | [class*="ControlContainer"] [class*="menu"] 287 | { 288 | background-color: var(--dropdownlist-bg); 289 | border: 1px solid var(--dropdownlist-border); 290 | border-radius: 6px; 291 | box-shadow: var(--dropdownlist-shadow); 292 | } 293 | 294 | ul[class*="dropdownList"] > [class*="dropdownItem"], 295 | ul[class*="Suggestions"] > li[class*="SuggestionItem"], 296 | [class*="ControlContainer"] [class*="menu"] [class*="option"] 297 | { 298 | color: var(--primary-text-color); 299 | background-color: var(--dropdownitem-bg); 300 | border-width: 0; 301 | } 302 | 303 | ul[class*="dropdownList"] > [class*="dropdownItem"]:hover, 304 | ul[class*="Suggestions"] > li[class*="SuggestionItem"]:hover, 305 | [class*="ControlContainer"] [class*="menu"] [class*="option"]:hover 306 | { 307 | color: inherit; 308 | background-color: var(--dropdownitem-hover-bg); 309 | } 310 | 311 | li[class*="SuggestionItem"] { 312 | display: flex; 313 | justify-content: space-between; 314 | padding: 6px 20px 6px 32px; 315 | } 316 | 317 | li.css-fmy46h-SuggestionItem::after { 318 | content: "✓"; 319 | position: relative; 320 | right: 0px; 321 | } 322 | [role="menuitem"].css-zcym63-button-dropdownItem-StyledMenuItem > span { 323 | display: contents; 324 | } 325 | [role="menuitem"].css-zcym63-button-dropdownItem-StyledMenuItem > span:only-child::after { 326 | content: "✓"; 327 | position: relative; 328 | right: 0px; 329 | } 330 | 331 | div.css-8fe0f3-option::after { 332 | content: "✓"; 333 | position: absolute; 334 | right: 22px; 335 | } 336 | 337 | [role="menuitem"] > input[type="checkbox"] { 338 | display: none; 339 | } 340 | [role="menuitem"] > input[type="checkbox"] + span::before { 341 | content: "✓"; 342 | color: transparent; 343 | display: inline-block; 344 | padding-right: 6px; 345 | } 346 | 347 | [role="menuitem"] > input[type="checkbox"]:checked + span::before { 348 | color: inherit; 349 | } 350 | 351 | li[class*="SuggestionHeader"] { 352 | color: inherit; 353 | } 354 | 355 | [class*="MenuItemIconContainer"] > [class*="IconWrapper"] { 356 | color: inherit; 357 | } 358 | 359 | ul[class*="dropdownList"]::-webkit-scrollbar-track, 360 | ul[class*="Suggestions"]::-webkit-scrollbar-track, 361 | [class*="ControlContainer"] [class*="menu"] > div::-webkit-scrollbar-track { 362 | background: var(--dropdownlist-bg) !important; 363 | } 364 | 365 | /*header*/ 366 | header[class*="AppHeader"] { 367 | background-color: var(--header-bg); 368 | } 369 | 370 | header [class*="AppHeaderButton"] { 371 | color: var(--header-button-text); 372 | } 373 | 374 | header [class*="AppHeaderButton"]:hover, header [class*="AppHeaderButton"]:focus { 375 | color: var(--header-button-text-hover); 376 | } 377 | 378 | header [class*="AppHeaderButton"].header-link-active { 379 | color: var(--header-button-text-active); 380 | } 381 | 382 | header [class*="AppHeaderNavList"] [class*="IconWrapper"] { 383 | color: inherit !important; 384 | } 385 | 386 | header ul[class*="dropdownList"] > [class*="dropdownItem"]:hover, 387 | [class*="EditorContainer"] > [class*="ToolbarContainer"] ul[class*="dropdownList"] > [class*="dropdownItem"]:hover { 388 | color: var(--header-dropdownitem-hover-text); 389 | background-color: var(--header-dropdownitem-hover-bg); 390 | z-index: 320; 391 | } 392 | 393 | [class*="EditorContainer"] > [class*="ToolbarContainer"] { 394 | background-color: var(--header-bg); 395 | } 396 | 397 | [class*="EditorContainer"] > [class*="ToolbarContainer"] [class*="ToolbarSectionBackLink"] { 398 | border-color: var(--btn-gray-default-border); 399 | } 400 | 401 | [class*="EditorContainer"] > [class*="ToolbarContainer"] [class*="ToolbarSectionBackLink"]:hover, 402 | [class*="EditorContainer"] > [class*="ToolbarContainer"] [class*="ToolbarSectionBackLink"]:focus 403 | { 404 | background-color: var(--btn-gray-default-bg); 405 | } 406 | 407 | [class*="EditorContainer"] > [class*="ToolbarContainer"] [class*="ToolbarSectionBackLink"] [class*="BackArrow"], 408 | [class*="EditorContainer"] > [class*="ToolbarContainer"] [class*="ToolbarSectionBackLink"] [class*= "BackCollection"] 409 | { 410 | color: var(--primary-text-color); 411 | } 412 | 413 | [class*="EditorContainer"] > [class*="ToolbarContainer"] [class*="ToolbarSectionBackLink"] [class*="textBadgeSuccess"] 414 | { 415 | color: var(--success-text-color); 416 | } 417 | 418 | [class*="EditorContainer"] > [class*="ToolbarContainer"] [class*="ToolbarSectionMeta"] { 419 | border-color: var(--btn-gray-default-border); 420 | } 421 | /* card */ 422 | [class*="CollectionContainer"] [class*="Container-card"], 423 | [class*="CollectionContainer"] [class*="ListCard-card"], 424 | [class*="CollectionContainer"] [class*="GridCard-card"], 425 | [class*="WorkflowContainer"] [class*="WorkflowTop-card-cardTop"], 426 | [class*="WorkflowContainer"] [class*="WorkflowCardContainer-card"], 427 | [class*="WorkflowContainer"] [class*="ColumnHeader"] 428 | { 429 | background-color: var(--card-bg); 430 | border: 1px solid var(--card-border); 431 | box-shadow: none; 432 | border-radius: 6px; 433 | } 434 | 435 | [class*="CollectionContainer"] [class*="GridCardLink"] { 436 | color: var(--primary-text-color); 437 | background-color: unset; 438 | } 439 | 440 | [class*="CollectionContainer"] [class*="ListCardLink"] { 441 | color: var(--primary-text-color); 442 | } 443 | 444 | [class*="CollectionContainer"] [class*="GridCardLink"] [class*="CardBody"]::after { 445 | content: unset; 446 | } 447 | 448 | [class*="CollectionContainer"] [class*="ListCardLink"]:hover, 449 | [class*="CollectionContainer"] [class*="GridCardLink"]:hover, 450 | [class*="WorkflowContainer"] [class*="WorkflowCardContainer-card"]:hover 451 | { 452 | color: inherit; 453 | background-color: var(--card-hover-bg); 454 | } 455 | 456 | [class*="CardButtonContainer"] { 457 | background-color: inherit; 458 | } 459 | 460 | a[class*="AppHeaderTestRepoIndicator"], a[class*="AppHeaderSiteLink"] { 461 | color: var(--secondary-text-color); 462 | } 463 | a[class*="RefreshPreviewButton"], a[class*="RefreshPreviewButton"] > [class*="IconWrapper"] { 464 | color: var(--url-text-color); 465 | } 466 | /* auth page */ 467 | section[class*="StyledAuthenticationPage"] a[class*="GoBackButtonStyle"] { 468 | color: var(--secondary-text-color); 469 | } 470 | section[class*="StyledAuthenticationPage"] a[class*="GoBackButtonStyle"]>p[class*="ButtonText"] { 471 | color: inherit; 472 | } 473 | section[class*="StyledAuthenticationPage"] span[class*="PageLogoIcon"], section[class*="StyledAuthenticationPage"] a[class*="GoBackButtonStyle"]:hover { 474 | color: var(--primary-text-color); 475 | } 476 | /* contents */ 477 | /*sidebar*/ 478 | [class*="SidebarHeading"] { 479 | color: inherit; 480 | } 481 | [class*="SidebarNavLink"], [class*="TreeNavLink"] { 482 | border-left: none; 483 | color: var(--header-button-text); 484 | } 485 | [class*="SidebarNavLink"]:hover, [class*="TreeNavLink"]:hover { 486 | color: var(--header-button-text); 487 | background-color: var(--dropdownitem-hover-bg); 488 | } 489 | [class*="SidebarNavLink"].sidebar-active, [class*="TreeNavLink"].sidebar-active { 490 | color: var(--header-button-text-active); 491 | background-color: var(--header-dropdownitem-hover-bg); 492 | } 493 | [class*="SearchContainer"] input[class*="SearchInput"] { 494 | background-color: var(--input-bg-color); 495 | border: 1px solid var(--input-border-color); 496 | color: inherit; 497 | } 498 | [class*="SearchContainer"] [class*="IconWrapper"] { 499 | color: var(--input-placeholder-color); 500 | } 501 | [class*="SearchContainer"] input[class*="SearchInput"]::placeholder { 502 | color: var(--input-placeholder-color); 503 | } 504 | 505 | /*collection*/ 506 | [class*="CollectionControlsContainer"] .css-14aa6nw-StyledDropdownButton-button-default-caret-caretDown-Button-button-medium-grayText-ControlButton { 507 | color: var(--header-button-text); 508 | } 509 | [class*="CollectionControlsContainer"] .css-14aa6nw-StyledDropdownButton-button-default-caret-caretDown-Button-button-medium-grayText-ControlButton:hover { 510 | color: var(--header-button-text-hover); 511 | } 512 | [class*="CollectionControlsContainer"] .css-58ai8s-StyledDropdownButton-button-default-caret-caretDown-Button-button-medium-grayText-ControlButton { 513 | color: var(--header-button-text-active); 514 | } 515 | [class*="CollectionControlsContainer"] .css-1jfbwn6-ViewControlsButton-button { 516 | color: var(--header-button-text); 517 | } 518 | [class*="CollectionControlsContainer"] .css-1jfbwn6-ViewControlsButton-button:hover { 519 | color: var(--header-button-text-hover); 520 | } 521 | [class*="CollectionControlsContainer"] .css-1fh4556-ViewControlsButton-button { 522 | color: var(--header-button-text-active); 523 | } 524 | [class*="GroupHeading"] [class*="cardTopDescription"] { 525 | color: var(--secondary-text-color); 526 | } 527 | /* workflow */ 528 | [class*="WorkflowContainer"] [class*="ColumnHeader"] { 529 | color: var(--primary-text-color); 530 | } 531 | .css-1njtcvy-column-WorkflowList::before, .css-1njtcvy-column-WorkflowList::after, 532 | .css-lhns9r-column-columnHovered-WorkflowList::before, .css-lhns9r-column-columnHovered-WorkflowList::after 533 | { 534 | background-color: var(--card-border); 535 | height: 100%; 536 | top: 0px; 537 | } 538 | [class*="WorkflowLink"] [class*="CardCollection"], [class*="WorkflowLink"] [class*="CardTitle"] { 539 | color: var(--primary-text-color); 540 | } 541 | [class*="WorkflowLink"] [class*="CardDate"], [class*="WorkflowLink"] [class*="CardBody"], p[class*="WorkflowTopDescription"] { 542 | color: var(--secondary-text-color); 543 | } 544 | 545 | /* media */ 546 | [class*="StyledModal"] { 547 | background-color: var(--modal-bg-color); 548 | box-shadow: var(--modal-box-shadow); 549 | border: 1px solid var(--modal-border-color); 550 | border-radius: 6px; 551 | } 552 | [class*="StyledModal"] [class*="CloseButton"] { 553 | color: var(--primary-text-color); 554 | background-color: var(--btn-gray-default-bg); 555 | border: 1px solid; 556 | border-color: var(--btn-gray-default-border); 557 | } 558 | [class*="StyledModal"] .css-1er4xqr-Card { 559 | border: 2px solid var(--card-border); 560 | } 561 | [class*="StyledModal"] .css-1v1y2wn-Card { 562 | border: 2px solid var(--card-active-border); 563 | } 564 | [class*="StyledModal"] [class*="checkerboard"] { 565 | background-color: var(--checkerboard-bg-color); 566 | border-bottom: 2px solid var(--modal-border-color); 567 | background-image: linear-gradient(45deg, var(--checkerboard-dark-color) 25%, transparent 25%, transparent 75%, var(--checkerboard-dark-color) 75%, var(--checkerboard-dark-color)), 568 | linear-gradient(45deg, var(--checkerboard-dark-color) 25%, transparent 25%, transparent 75%, var(--checkerboard-dark-color) 75%, var(--checkerboard-dark-color)); 569 | } 570 | [class*="StyledModal"] [class*="DraftText"] { 571 | color: inherit; 572 | background-color: var(--modal-border-color); 573 | padding: 5px 8px; 574 | } 575 | [class*="StyledModal"] [class*="CardText"] { 576 | color: inherit; 577 | } 578 | 579 | /*editor*/ 580 | [class*="EditorContainer"] [class*="card-splitPane"] { 581 | background-color: var(--body-bg-color); 582 | } 583 | #preview-pane { 584 | background-color: var(--body-bg-color); 585 | border-radius: 0; 586 | } 587 | .Resizer.vertical { 588 | width: 5px; 589 | border-right: 1px solid var(--modal-border-color); 590 | } 591 | .Resizer.vertical::before { 592 | content: none; 593 | } 594 | button.css-1glyzdz-ButtonRound-button-EditorToggle { 595 | color: var(--toggle-true-bg-color); 596 | background-color: var(--btn-gray-default-bg); 597 | border: 1px solid; 598 | border-color: var(--btn-gray-default-border); 599 | transition: .2s cubic-bezier(.3,0,.5,1); 600 | transition-property: color,background-color,border-color; 601 | } 602 | button.css-1f8dk1z-ButtonRound-button-EditorToggle { 603 | color: var(--toggle-false-bg-color); 604 | background-color: var(--btn-gray-default-bg); 605 | border: 1px solid; 606 | border-color: var(--btn-gray-default-border); 607 | transition: .2s cubic-bezier(.3,0,.5,1); 608 | transition-property: color,background-color,border-color; 609 | } 610 | button.css-1glyzdz-ButtonRound-button-EditorToggle:hover { 611 | color: var(--header-button-text-active); 612 | background-color: var(--btn-gray-hover-bg); 613 | border-color: var(--btn-gray-hover-border); 614 | transition-duration: .1s; 615 | } 616 | button.css-1f8dk1z-ButtonRound-button-EditorToggle:hover { 617 | color: var(--secondary-text-color); 618 | background-color: var(--btn-gray-hover-bg); 619 | border-color: var(--btn-gray-hover-border); 620 | transition-duration: .1s; 621 | } 622 | 623 | /*widgets*/ 624 | [class*="FieldLabel"]::after { 625 | background-color: var(--body-bg-color); 626 | } 627 | [class*="pcief1-FieldLabel"] { 628 | color: var(--primary-text-color); 629 | background-color: var(--widgets-label-bg-color); 630 | padding: 3px 8px 2px; 631 | text-transform: capitalize; 632 | } 633 | .css-83wr9v, .css-2ek3w9, .css-wesa1q-TextControl, .css-182avcw, .css-18h6btn, .css-12fzmby, .css-xa00c7, .css-1d0dxug { 634 | color: inherit; 635 | background-color: var(--widgets-bg-color); 636 | border: 1px solid var(--widgets-border-color); 637 | border-radius: 0 6px 6px; 638 | } 639 | [class*="1vur7zs-FieldLabel"] { 640 | color: var(--header-button-text-active); 641 | background-color: var(--widgets-active-label-bg-color); 642 | padding: 3px 8px 2px; 643 | text-transform: capitalize; 644 | } 645 | .css-188efjc, .css-3yr7zq-TextControl, .css-12fzmby { 646 | color: inherit; 647 | background-color: var(--widgets-bg-color); 648 | border: 1px solid var(--widgets-active-border-color); 649 | border-radius: 0 6px 6px; 650 | } 651 | .css-1noq96f-FieldLabel-fieldLabel { 652 | background-color: var(--widgets-error-label-bg-color); 653 | padding: 3px 8px 2px; 654 | text-transform: capitalize; 655 | } 656 | .css-9guxbf-ControlErrorsList { 657 | color: var(--danger-text-color); 658 | } 659 | .css-1caau9x, .css-xo8dlj, .css-14hxnzs-TextControl, .css-1eeq9l0-TextControl, .css-ntdq13 { 660 | color: inherit; 661 | background-color: var(--widgets-bg-color); 662 | border: 1px solid var(--widgets-error-border-color); 663 | border-radius: 0 6px 6px; 664 | } 665 | /*dropdown*/ 666 | [class*="ControlContainer"] div[class$="-control"] { 667 | background-color: transparent; 668 | } 669 | [class*="ControlContainer"] div[class$="-control"] [class*="indicatorContainer"] { 670 | color: var(--input-placeholder-color); 671 | } 672 | [class*="ControlContainer"] div[class$="-control"] [class*="indicatorContainer"]:hover { 673 | color: var(--header-button-text-hover); 674 | } 675 | [class*="ControlContainer"] div[class$="-control"] [class*="-loadingIndicator"] > span { 676 | background-color: var(--input-placeholder-color); 677 | } 678 | [class*="ControlContainer"] div[class$="-control"] [class*="css-1g6gooi"], [class*="ControlContainer"] div[class$="-control"] [class*="-singleValue"] { 679 | color: inherit; 680 | } 681 | /*date*/ 682 | .rdt .rdtPicker { 683 | background-color: var(--rdtPicker-bg-color); 684 | box-shadow: var(--rdtPicker-shadow); 685 | border: 1px solid var(--rdtPicker-border-color); 686 | border-radius: 6px; 687 | } 688 | .rdt .rdtPicker thead tr:first-child th:hover, .rdt .rdtPicker td.rdtDay:hover, .rdt .rdtPicker td.rdtHour:hover, .rdt .rdtPicker td.rdtMinute:hover, .rdt .rdtPicker td.rdtSecond:hover, 689 | .rdt .rdtPicker .rdtTimeToggle:hover, .rdt .rdtPicker .rdtCounter .rdtBtn:hover, .rdt .rdtPicker td.rdtMonth:hover, .rdt .rdtPicker td.rdtYear:hover 690 | { 691 | background-color: var(--rdtPicker-hover-bg-color); 692 | } 693 | .rdt .rdtPicker td.rdtActive, .rdt .rdtPicker td.rdtActive:hover { 694 | background-color: var(--rdtPicker-active-bg-color); 695 | } 696 | .rdt .rdtPicker td.rdtOld, .rdt .rdtPicker td.rdtNew { 697 | color: var(--disabled-text-color); 698 | } 699 | .rdt .rdtPicker td.rdtToday::before { 700 | border-bottom: 7px solid var(--rdtPicker-active-bg-color); 701 | } 702 | .rdt .rdtPicker th { 703 | border-bottom: 1px solid var(--rdtPicker-border-color); 704 | } 705 | /*image uplaod*/ 706 | [class*="ImageWrapper-checkerboard"] { 707 | border: 2px solid var(--widgets-border-color); 708 | background-color: var(--checkerboard-bg-color); 709 | background-image: linear-gradient(45deg, var(--checkerboard-dark-color) 25%, transparent 25%, transparent 75%, var(--checkerboard-dark-color) 75%, var(--checkerboard-dark-color)), 710 | linear-gradient(45deg, var(--checkerboard-dark-color) 25%, transparent 25%, transparent 75%, var(--checkerboard-dark-color) 75%, var(--checkerboard-dark-color)); 711 | } 712 | /*color picker*/ 713 | [class*="ColorSwatch"] { 714 | border-color: var(--btn-gray-default-border); 715 | } 716 | .css-177o7zx-ColorSwatch { 717 | color: var(--primary-text-color); 718 | background-color: var(--btn-gray-default-bg); 719 | } 720 | .chrome-picker { 721 | background: var(--color-picker-bg-color) !important; 722 | overflow: hidden; 723 | border: 1px solid var(--color-picker-border-color); 724 | border-radius: 6px !important; 725 | box-shadow: var(--color-picker-shadow) !important; 726 | } 727 | [id^="rc-editable-input-"] { 728 | box-shadow: none !important; 729 | background-color: var(--color-picker-bg-color); 730 | border: 1px solid var(--color-picker-border-color) !important; 731 | border-radius: 4px !important; 732 | color: inherit !important; 733 | } 734 | div.chrome-picker > div >.flexbox-fix:nth-child(1) > div:nth-child(1) > div > div:nth-child(1) { 735 | box-shadow: none !important; 736 | border: 1px solid var(--color-picker-border-color); 737 | } 738 | div.chrome-picker > div >.flexbox-fix:nth-child(1) > div:nth-child(2) > div:nth-child(2) > div > div:nth-child(1)::after { 739 | content: ""; 740 | height: 100%; 741 | display: block; 742 | background-color: white; 743 | } 744 | div.chrome-picker > div >.flexbox-fix:nth-child(2) > div:nth-child(2) svg { 745 | fill: var(--secondary-text-color) !important; 746 | } 747 | div.chrome-picker > div >.flexbox-fix:nth-child(2) > div:nth-child(2) svg:hover { 748 | fill: var(--primary-text-color) !important; 749 | background: var(--btn-gray-default-border) !important; 750 | } 751 | /* toggle */ 752 | [class*=ToggleContainer-StyledToggle][aria-checked="true"] > span[class*="ToggleBackground"] { 753 | background-color: var(--toggle-true-bg-color); 754 | } 755 | [class*=ToggleContainer-StyledToggle][aria-checked="false"] > span[class*="ToggleBackground"] { 756 | background-color: var(--toggle-false-bg-color); 757 | } 758 | [class*=ToggleContainer-StyledToggle] > span[class*="ToggleHandle"] { 759 | background-color: var(--toggle-handle-color); 760 | } 761 | /* object */ 762 | [class*="listControlItem"] { 763 | border: 1px solid var(--widgets-border-color); 764 | border-radius: 6px; 765 | } 766 | [class*="TopBarContainer"], [class*="StyledListItemTopBar"], [class*="NestedObjectLabel"] { 767 | background-color: var(--topbar-bg-color); 768 | border-top-right-radius: 6px; 769 | } 770 | .css-1cjg468, .css-55unpk { 771 | border: 0px; 772 | color: inherit; 773 | background-color: var(--widgets-bg-color); 774 | } 775 | [class*="TopBarContainer"] button[class*="ExpandButton"], 776 | [class*="StyledListItemTopBar"] [class*="TopBarButton"] 777 | { 778 | color: var(--header-button-text); 779 | } 780 | [class*="TopBarContainer"] button[class*="ExpandButton"]:hover, 781 | [class*="StyledListItemTopBar"] [class*="TopBarButton"]:hover 782 | { 783 | color: var(--header-button-text-hover); 784 | } 785 | /* markdown */ 786 | [class*="cms-editor"] { 787 | border: 1px solid var(--widgets-border-color); 788 | border-radius: 0 6px 6px; 789 | } 790 | [class*="cms-editor"] [class*="ToolbarContainer"] { 791 | background-color: var(--topbar-bg-color); 792 | border-top-right-radius: 6px; 793 | } 794 | .css-12vfcwo, .css-isnoua { 795 | border-color: transparent; 796 | color: inherit; 797 | background-color: var(--widgets-bg-color); 798 | } 799 | .css-189bh5w, .css-f8f1e2 { 800 | border-color: var(--widgets-error-border-color); 801 | color: inherit; 802 | background-color: var(--widgets-bg-color); 803 | } 804 | [class*="cms-editor"] [class*="ToolbarContainer"] button[class*="StyledToolbarButton"], 805 | [class*="cms-editor"] [class*="ToolbarContainer"] div[class*="ToolbarDropdownWrapper"] 806 | { 807 | color: var(--header-button-text); 808 | } 809 | [class*="cms-editor"] [class*="ToolbarContainer"] button[class*="StyledToolbarButton"]:hover, 810 | [class*="cms-editor"] [class*="ToolbarContainer"] div[class*="ToolbarDropdownWrapper"]:hover 811 | { 812 | color: var(--header-button-text-hover); 813 | } 814 | [class*="cms-editor"] [class*="ToolbarContainer"] button[class*="StyledToolbarButton"][disabled], 815 | [class*="cms-editor"] [class*="ToolbarContainer"] div[class*="ToolbarDropdownWrapper"][disabled] 816 | { 817 | color: var(--disabled-text-color); 818 | } 819 | [class*="ToolbarToggleLabel"] { 820 | color: var(--header-button-text); 821 | } 822 | [class*="ToolbarToggleLabel-ToolbarToggleLabel"] { 823 | color: var(--header-button-text-active); 824 | } 825 | [class*="cms-editor"] blockquote { 826 | color: var(--secondary-text-color); 827 | border-left: 3px solid var(--secondary-text-color); 828 | } 829 | [class*="cms-editor"] code[class*="StyledCode"] { 830 | background-color: var(--short-code-bg-color); 831 | border-radius: 6px; 832 | padding: 4px 6px; 833 | } 834 | /*code*/ 835 | [class*="react-codemirror"] .cm-s-material.CodeMirror, [class*="react-codemirror"] .cm-s-material .CodeMirror-gutters { 836 | background-color: var(--code-block-bg-color); 837 | } 838 | [class*="ControlContainer"] [class*="SettingsPaneContainer"] { 839 | color: var(--primary-text-color); 840 | background-color: var(--dropdownlist-bg); 841 | border-left: 1px solid var(--dropdownlist-border); 842 | overflow: hidden; 843 | } 844 | [class*="react-codemirror"] .cm-s-material .CodeMirror-linenumber { 845 | color: var(--code-line-number-color); 846 | } 847 | [class*="ControlContainer"] [class*="SettingsPaneContainer"] > label { 848 | color: var(--primary-text-color); 849 | } 850 | [class*="ControlContainer"] [class*="SettingsPaneContainer"] [class$="-control"] { 851 | border: 1px solid var(--dropdownlist-border); 852 | } 853 | [class*="ControlContainer"] button[class*="StyledSettingsButton-button"] { 854 | background-color: transparent; 855 | color: var(--header-button-text); 856 | } 857 | [class*="ControlContainer"] button[class*="StyledSettingsButton-button"]:hover { 858 | color: var(--header-button-text-hover); 859 | } 860 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar { 861 | cursor: default; 862 | } 863 | .CodeMirror-vscrollbar::-webkit-scrollbar-track, .CodeMirror-hscrollbar::-webkit-scrollbar-track { 864 | background: var(--code-block-bg-color) !important; 865 | } 866 | } --------------------------------------------------------------------------------