diff --git a/bin/build-inline-script.js b/bin/build-inline-script.js index 5c831230..a6480974 100644 --- a/bin/build-inline-script.js +++ b/bin/build-inline-script.js @@ -1,18 +1,23 @@ #!/usr/bin/env node -const crypto = require('crypto') -const fs = require('fs') -const pify = require('pify') +import crypto from 'crypto' +import fs from 'fs' +import pify from 'pify' +import path from 'path' +import { themes } from '../routes/_static/themes.js' +import { fromPairs } from 'lodash-es' + const readFile = pify(fs.readFile.bind(fs)) const writeFile = pify(fs.writeFile.bind(fs)) -const path = require('path') async function main () { - let headScriptFilepath = path.join(__dirname, '../inline-script.js') - let headScript = await readFile(headScriptFilepath, 'utf8') - headScript = `(function () {'use strict'; ${headScript}})()` + let inlineScriptPath = path.join(__dirname, '../inline-script.js') + let code = await readFile(inlineScriptPath, 'utf8') - let checksum = crypto.createHash('sha256').update(headScript).digest('base64') + code = code.replace('process.env.THEME_COLORS', JSON.stringify(fromPairs(themes.map(_ => ([_.name, _.color]))))) + code = `(function () {'use strict'\n${code}})()` + + let checksum = crypto.createHash('sha256').update(code).digest('base64') let checksumFilepath = path.join(__dirname, '../inline-script-checksum.json') await writeFile(checksumFilepath, JSON.stringify({ checksum }), 'utf8') @@ -21,7 +26,7 @@ async function main () { let html2xxFile = await readFile(html2xxFilepath, 'utf8') html2xxFile = html2xxFile.replace( /[\s\S]+/, - '' + '' ) await writeFile(html2xxFilepath, html2xxFile, 'utf8') } diff --git a/docs/Theming.md b/docs/Theming.md index 318fb748..57bca8ed 100644 --- a/docs/Theming.md +++ b/docs/Theming.md @@ -11,48 +11,17 @@ body.theme-foobar { > Note: You can find all the SCSS variables available in `scss/themes/_default.scss` while the all CSS Custom Properties available are listed in `scss/themes/_base.scss`. -Add the CSS class you just define to `scss/themes/_offlines`. -```scss -... -body.offline, -body.theme-foobar.offline, // <- -body.theme-hotpants.offline, -body.theme-majesty.offline, -body.theme-oaken.offline, -body.theme-scarlet.offline, -body.theme-seafoam.offline, -body.theme-gecko.offline { - @include baseTheme(); -} - -``` - Add your theme to `routes/_static/themes.js` ```js const themes = [ ... { name: 'foobar', - label: 'Foobar' + label: 'Foobar', // user-visible name + color: 'magenta', // main theme color + dark: true // whether it's a dark theme or not } ] - -export { themes } -``` - -Add your theme in `inline-script.js`. -```js -window.__themeColors = { - 'default': "royalblue", - scarlet: "#e04e41", - seafoam: "#177380", - hotpants: "hotpink", - oaken: "saddlebrown", - majesty: "blueviolet", - gecko: "#4ab92f", - foobar: "#BADA55", // <- - offline: "#999999" - } ``` Start the development server (`npm run dev`), go to `http://localhost:4002/settings/instances/your-instance-name` and select your newly created theme. Once you've done that, you can update your theme, and refresh the page to see the change (you don't have to restart the server). diff --git a/inline-script.js b/inline-script.js index 68bb3a60..6af6cd7e 100644 --- a/inline-script.js +++ b/inline-script.js @@ -1,23 +1,8 @@ // For perf reasons, this script is run inline to quickly set certain styles. // To allow CSP to work correctly, we also calculate a sha256 hash during // the build process and write it to inline-script-checksum.json. -// TODO: these should not have to be defined twice, once here and again in themes.js -window.__themeColors = { - 'default': 'royalblue', - scarlet: '#e04e41', - seafoam: '#177380', - hotpants: 'hotpink', - oaken: 'saddlebrown', - majesty: 'blueviolet', - gecko: '#4ab92f', - ozark: '#5263af', - cobalt: '#08439b', - sorcery: '#ae91e8', - punk: '#e04e41', - riot: 'hotpink', - hacker: '#4ab92f', - offline: '#999999' -} +window.__themeColors = process.env.THEME_COLORS + if (localStorage.store_currentInstance && localStorage.store_instanceThemes) { let safeParse = (str) => str === 'undefined' ? undefined : JSON.parse(str) let theme = safeParse(localStorage.store_instanceThemes)[safeParse(localStorage.store_currentInstance)] @@ -32,6 +17,7 @@ if (localStorage.store_currentInstance && localStorage.store_instanceThemes) { } } } + if (!localStorage.store_currentInstance) { // if not logged in, show all these 'hidden-from-ssr' elements let style = document.createElement('style') diff --git a/package.json b/package.json index 86358295..ff7df1b8 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "start": "cross-env NODE_ENV=production npm run serve", "build-and-start": "run-s build start", "build-svg": "node ./bin/build-svg.js", - "build-inline-script": "node ./bin/build-inline-script.js", + "build-inline-script": "node -r esm ./bin/build-inline-script.js", "build-sass": "node ./bin/build-sass.js", "build-sass-watch": "node ./bin/build-sass.js --watch", "run-mastodon": "node -r esm ./bin/run-mastodon.js", diff --git a/scss/themes/_offline.scss b/scss/themes/_offline.scss index efeac8f4..826f0eca 100644 --- a/scss/themes/_offline.scss +++ b/scss/themes/_offline.scss @@ -12,18 +12,6 @@ $compose-background: lighten($main-theme-color, 17%); @import "_base.scss"; -body.offline, -body.theme-hotpants.offline, -body.theme-majesty.offline, -body.theme-oaken.offline, -body.theme-scarlet.offline, -body.theme-seafoam.offline, -body.theme-gecko.offline, -body.theme-ozark.offline, -body.theme-cobalt.offline, -body.theme-sorcery.offline, -body.theme-riot.offline, -body.theme-punk.offline, -body.theme-hacker.offline { +body.the-body.offline { /* "the-body" is a specificity hack to allow offline to always trump themes */ @include baseTheme(); } diff --git a/templates/2xx.html b/templates/2xx.html index dfee8231..95f8022c 100644 --- a/templates/2xx.html +++ b/templates/2xx.html @@ -18,7 +18,7 @@ /* auto-generated w/ build-sass.js */ body{--button-primary-bg: #6081e6;--button-primary-text: #fff;--button-primary-border: #132c76;--button-primary-bg-active: #456ce2;--button-primary-bg-hover: #6988e7;--button-bg: #e6e6e6;--button-text: #333;--button-border: #a7a7a7;--button-bg-active: #bfbfbf;--button-bg-hover: #f2f2f2;--input-border: #dadada;--anchor-text: #4169e1;--main-bg: #fff;--body-bg: #e8edfb;--body-text-color: #333;--main-border: #dadada;--svg-fill: #4169e1;--form-bg: #f7f7f7;--form-border: #c1c1c1;--nav-bg: #4169e1;--nav-border: #214cce;--nav-a-border: #4169e1;--nav-a-selected-border: #fff;--nav-a-selected-bg: #6d8ce8;--nav-svg-fill: #fff;--nav-text-color: #fff;--nav-a-selected-border-hover: #fff;--nav-a-selected-bg-hover: #839deb;--nav-a-bg-hover: #577ae4;--nav-a-border-hover: #4169e1;--nav-svg-fill-hover: #fff;--nav-text-color-hover: #fff;--action-button-fill-color: #90a8ee;--action-button-fill-color-hover: #a2b6f0;--action-button-fill-color-active: #577ae4;--action-button-fill-color-pressed: #2351dc;--action-button-fill-color-pressed-hover: #3862e0;--action-button-fill-color-pressed-active: #1d44b8;--action-button-deemphasized-fill-color: #666;--action-button-deemphasized-fill-color-hover: #9e9e9e;--action-button-deemphasized-fill-color-active: #737373;--action-button-deemphasized-fill-color-pressed: #545454;--action-button-deemphasized-fill-color-pressed-hover: #616161;--action-button-deemphasized-fill-color-pressed-active: #404040;--settings-list-item-bg: #fff;--settings-list-item-text: #4169e1;--settings-list-item-text-hover: #4169e1;--settings-list-item-border: #dadada;--settings-list-item-bg-active: #e6e6e6;--settings-list-item-bg-hover: #fafafa;--toast-bg: #333;--toast-border: #fafafa;--toast-text: #fff;--mask-bg: #333;--mask-svg-fill: #fff;--mask-opaque-bg: rgba(51,51,51,0.8);--loading-bg: #ededed;--account-profile-bg-backdrop-filter: rgba(255,255,255,0.7);--account-profile-bg: rgba(255,255,255,0.9);--deemphasized-text-color: #666;--focus-outline: #c5d1f6;--very-deemphasized-link-color: rgba(65,105,225,0.6);--very-deemphasized-text-color: rgba(102,102,102,0.6);--status-direct-background: #d2dcf8;--main-theme-color: #4169e1;--warning-color: #e01f19;--alt-input-bg: rgba(255,255,255,0.7);--muted-modal-bg: transparent;--muted-modal-focus: #999;--muted-modal-hover: rgba(255,255,255,0.2);--compose-autosuggest-item-hover: #ced8f7;--compose-autosuggest-item-active: #b8c7f4;--compose-autosuggest-outline: #dbe3f9;--compose-button-halo: rgba(255,255,255,0.1)} body{margin:0;font-family:system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;font-size:14px;line-height:1.4;color:var(--body-text-color);background:var(--body-bg);-webkit-tap-highlight-color:transparent}.container{overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;position:absolute;top:42px;left:0;right:0;bottom:0}@media (max-width: 991px){.container{top:52px}}@media (max-width: 767px){.container{top:62px}}main{position:relative;width:602px;max-width:100vw;padding:0;box-sizing:border-box;margin:30px auto 15px;background:var(--main-bg);border:1px solid var(--main-border);border-radius:1px;min-height:70vh}@media (max-width: 767px){main{margin:5px auto 15px}}footer{width:602px;max-width:100vw;box-sizing:border-box;margin:15px auto;border-radius:1px;background:var(--main-bg);font-size:0.9em;padding:20px;border:1px solid var(--main-border)}h1,h2,h3,h4,h5,h6{margin:0 0 0.5em 0;font-weight:400;line-height:1.2}h1{font-size:2em}a{color:var(--anchor-text);text-decoration:none}a:visited{color:var(--anchor-text)}a:hover{text-decoration:underline}input{border:1px solid var(--input-border);padding:5px;box-sizing:border-box}input,textarea{background:inherit;color:inherit}button,.button{font-size:1.2em;background:var(--button-bg);border-radius:2px;padding:10px 15px;border:1px solid var(--button-border);cursor:pointer;color:var(--button-text)}button:hover,.button:hover{background:var(--button-bg-hover);text-decoration:none}button:active,.button:active{background:var(--button-bg-active)}button[disabled],.button[disabled]{opacity:0.35;pointer-events:none;cursor:not-allowed}button.primary,.button.primary{border:1px solid var(--button-primary-border);background:var(--button-primary-bg);color:var(--button-primary-text)}button.primary:hover,.button.primary:hover{background:var(--button-primary-bg-hover)}button.primary:active,.button.primary:active{background:var(--button-primary-bg-active)}p,label,input{font-size:1.3em}ul,li,p{padding:0;margin:0}.hidden{opacity:0}*:focus{outline:2px solid var(--focus-outline)}.container:focus{outline:none}button::-moz-focus-inner{border:0}input:required,input:invalid{box-shadow:none}textarea{font-family:inherit;font-size:inherit;box-sizing:border-box}@keyframes spin{0%{transform:rotate(0deg)}25%{transform:rotate(90deg)}50%{transform:rotate(180deg)}75%{transform:rotate(270deg)}100%{transform:rotate(360deg)}}.spin{animation:spin 1.5s infinite linear}.ellipsis::after{content:"\2026"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.inline-custom-emoji{width:1.4em;height:1.4em;margin:-0.1em 0;object-fit:contain;vertical-align:middle} -body.offline,body.theme-hotpants.offline,body.theme-majesty.offline,body.theme-oaken.offline,body.theme-scarlet.offline,body.theme-seafoam.offline,body.theme-gecko.offline,body.theme-ozark.offline,body.theme-cobalt.offline,body.theme-sorcery.offline,body.theme-riot.offline,body.theme-punk.offline,body.theme-hacker.offline{--button-primary-bg: #ababab;--button-primary-text: #fff;--button-primary-border: #4d4d4d;--button-primary-bg-active: #9c9c9c;--button-primary-bg-hover: #b0b0b0;--button-bg: #e6e6e6;--button-text: #333;--button-border: #a7a7a7;--button-bg-active: #bfbfbf;--button-bg-hover: #f2f2f2;--input-border: #dadada;--anchor-text: #999;--main-bg: #fff;--body-bg: #fafafa;--body-text-color: #333;--main-border: #dadada;--svg-fill: #999;--form-bg: #f7f7f7;--form-border: #c1c1c1;--nav-bg: #999;--nav-border: gray;--nav-a-border: #999;--nav-a-selected-border: #fff;--nav-a-selected-bg: #b3b3b3;--nav-svg-fill: #fff;--nav-text-color: #fff;--nav-a-selected-border-hover: #fff;--nav-a-selected-bg-hover: #bfbfbf;--nav-a-bg-hover: #a6a6a6;--nav-a-border-hover: #999;--nav-svg-fill-hover: #fff;--nav-text-color-hover: #fff;--action-button-fill-color: #c7c7c7;--action-button-fill-color-hover: #d1d1d1;--action-button-fill-color-active: #a6a6a6;--action-button-fill-color-pressed: #878787;--action-button-fill-color-pressed-hover: #949494;--action-button-fill-color-pressed-active: #737373;--action-button-deemphasized-fill-color: #666;--action-button-deemphasized-fill-color-hover: #9e9e9e;--action-button-deemphasized-fill-color-active: #737373;--action-button-deemphasized-fill-color-pressed: #545454;--action-button-deemphasized-fill-color-pressed-hover: #616161;--action-button-deemphasized-fill-color-pressed-active: #404040;--settings-list-item-bg: #fff;--settings-list-item-text: #999;--settings-list-item-text-hover: #999;--settings-list-item-border: #dadada;--settings-list-item-bg-active: #e6e6e6;--settings-list-item-bg-hover: #fafafa;--toast-bg: #333;--toast-border: #fafafa;--toast-text: #fff;--mask-bg: #333;--mask-svg-fill: #fff;--mask-opaque-bg: rgba(51,51,51,0.8);--loading-bg: #ededed;--account-profile-bg-backdrop-filter: rgba(255,255,255,0.7);--account-profile-bg: rgba(255,255,255,0.9);--deemphasized-text-color: #666;--focus-outline: #bfbfbf;--very-deemphasized-link-color: rgba(153,153,153,0.6);--very-deemphasized-text-color: rgba(102,102,102,0.6);--status-direct-background: #ededed;--main-theme-color: #999;--warning-color: #e01f19;--alt-input-bg: rgba(255,255,255,0.7);--muted-modal-bg: transparent;--muted-modal-focus: #999;--muted-modal-hover: rgba(255,255,255,0.2);--compose-autosuggest-item-hover: #c4c4c4;--compose-autosuggest-item-active: #b8b8b8;--compose-autosuggest-outline: #ccc;--compose-button-halo: rgba(255,255,255,0.1)} +body.the-body.offline{--button-primary-bg: #ababab;--button-primary-text: #fff;--button-primary-border: #4d4d4d;--button-primary-bg-active: #9c9c9c;--button-primary-bg-hover: #b0b0b0;--button-bg: #e6e6e6;--button-text: #333;--button-border: #a7a7a7;--button-bg-active: #bfbfbf;--button-bg-hover: #f2f2f2;--input-border: #dadada;--anchor-text: #999;--main-bg: #fff;--body-bg: #fafafa;--body-text-color: #333;--main-border: #dadada;--svg-fill: #999;--form-bg: #f7f7f7;--form-border: #c1c1c1;--nav-bg: #999;--nav-border: gray;--nav-a-border: #999;--nav-a-selected-border: #fff;--nav-a-selected-bg: #b3b3b3;--nav-svg-fill: #fff;--nav-text-color: #fff;--nav-a-selected-border-hover: #fff;--nav-a-selected-bg-hover: #bfbfbf;--nav-a-bg-hover: #a6a6a6;--nav-a-border-hover: #999;--nav-svg-fill-hover: #fff;--nav-text-color-hover: #fff;--action-button-fill-color: #c7c7c7;--action-button-fill-color-hover: #d1d1d1;--action-button-fill-color-active: #a6a6a6;--action-button-fill-color-pressed: #878787;--action-button-fill-color-pressed-hover: #949494;--action-button-fill-color-pressed-active: #737373;--action-button-deemphasized-fill-color: #666;--action-button-deemphasized-fill-color-hover: #9e9e9e;--action-button-deemphasized-fill-color-active: #737373;--action-button-deemphasized-fill-color-pressed: #545454;--action-button-deemphasized-fill-color-pressed-hover: #616161;--action-button-deemphasized-fill-color-pressed-active: #404040;--settings-list-item-bg: #fff;--settings-list-item-text: #999;--settings-list-item-text-hover: #999;--settings-list-item-border: #dadada;--settings-list-item-bg-active: #e6e6e6;--settings-list-item-bg-hover: #fafafa;--toast-bg: #333;--toast-border: #fafafa;--toast-text: #fff;--mask-bg: #333;--mask-svg-fill: #fff;--mask-opaque-bg: rgba(51,51,51,0.8);--loading-bg: #ededed;--account-profile-bg-backdrop-filter: rgba(255,255,255,0.7);--account-profile-bg: rgba(255,255,255,0.9);--deemphasized-text-color: #666;--focus-outline: #bfbfbf;--very-deemphasized-link-color: rgba(153,153,153,0.6);--very-deemphasized-text-color: rgba(102,102,102,0.6);--status-direct-background: #ededed;--main-theme-color: #999;--warning-color: #e01f19;--alt-input-bg: rgba(255,255,255,0.7);--muted-modal-bg: transparent;--muted-modal-focus: #999;--muted-modal-hover: rgba(255,255,255,0.2);--compose-autosuggest-item-hover: #c4c4c4;--compose-autosuggest-item-active: #b8b8b8;--compose-autosuggest-outline: #ccc;--compose-button-halo: rgba(255,255,255,0.1)} @@ -39,27 +39,14 @@ body.offline,body.theme-hotpants.offline,body.theme-majesty.offline,body.theme-o the current page has one --> %sapper.head% - + -