From 76adb02565d16d6d8904ad9bdccd2c4bd2ff8a38 Mon Sep 17 00:00:00 2001 From: Muffin Date: Tue, 9 Jan 2024 01:01:33 -0600 Subject: [PATCH] merge-upstream: fix long tail of regressions from rewriting themes --- src/addons/settings-store.js | 3 +- src/components/menu-bar/settings-menu.css | 2 +- src/components/menu-bar/tw-theme-blocks.jsx | 7 ++- src/components/monitor/monitor.jsx | 4 +- src/containers/blocks.jsx | 4 +- src/containers/monitor.jsx | 2 +- src/lib/themes/accent/red.js | 3 ++ src/lib/themes/blockHelpers.js | 18 +++---- src/lib/themes/global-styles.css | 4 -- src/lib/themes/guiHelpers.js | 4 +- src/lib/themes/index.js | 59 ++++++++++++--------- src/lib/themes/themePersistance.js | 9 ++-- 12 files changed, 66 insertions(+), 53 deletions(-) diff --git a/src/addons/settings-store.js b/src/addons/settings-store.js index cba2c7e6b..420fee4db 100644 --- a/src/addons/settings-store.js +++ b/src/addons/settings-store.js @@ -17,7 +17,6 @@ import addons from './generated/addon-manifests'; import upstreamMeta from './generated/upstream-meta.json'; import EventTargetShim from './event-target'; -import {isDark} from '../lib/themes'; const SETTINGS_KEY = 'tw:addons'; const VERSION = 4; @@ -366,7 +365,7 @@ class SettingsStore extends EventTargetShim { const result = { core: { // Upstream property. We don't use this. - lightTheme: !isDark(theme), + lightTheme: !theme.isDark(), // Doesn't matter what we set this to version: `v1.0.0-tw-${upstreamMeta.commit}` }, diff --git a/src/components/menu-bar/settings-menu.css b/src/components/menu-bar/settings-menu.css index b2ef9cf1c..64664d3e8 100644 --- a/src/components/menu-bar/settings-menu.css +++ b/src/components/menu-bar/settings-menu.css @@ -75,5 +75,5 @@ border-radius: 100%; box-sizing: border-box; transform-origin: center; - transform: scale(85%); + transform: scale(90%); } diff --git a/src/components/menu-bar/tw-theme-blocks.jsx b/src/components/menu-bar/tw-theme-blocks.jsx index 84b472054..3d17abef7 100644 --- a/src/components/menu-bar/tw-theme-blocks.jsx +++ b/src/components/menu-bar/tw-theme-blocks.jsx @@ -7,7 +7,7 @@ import {connect} from 'react-redux'; import check from './check.svg'; import dropdownCaret from './dropdown-caret.svg'; import {MenuItem, Submenu} from '../menu/menu.jsx'; -import {BLOCKS_HIGH_CONTRAST, BLOCKS_THREE, Theme} from '../../lib/themes/index.js'; +import {BLOCKS_DARK, BLOCKS_HIGH_CONTRAST, BLOCKS_THREE, Theme} from '../../lib/themes/index.js'; import {openBlocksThemeMenu, blocksThemeMenuOpen, closeSettingsMenu} from '../../reducers/menus.js'; import {setTheme} from '../../reducers/theme.js'; import styles from './settings-menu.css'; @@ -24,6 +24,11 @@ const options = defineMessages({ defaultMessage: 'High Contrast', description: 'Name of the high contrast block colors.', id: 'tw.blockColors.highContrast' + }, + [BLOCKS_DARK]: { + defaultMessage: 'Dark REMOVE BEFORE MERGE', + description: 'Name of Scratch\'s experimental dark block colors', + id: 'tw.blockColors.dark' } }); diff --git a/src/components/monitor/monitor.jsx b/src/components/monitor/monitor.jsx index 689d6e8c1..4b5faabc3 100644 --- a/src/components/monitor/monitor.jsx +++ b/src/components/monitor/monitor.jsx @@ -10,7 +10,7 @@ import DefaultMonitor from './default-monitor.jsx'; import LargeMonitor from './large-monitor.jsx'; import SliderMonitor from '../../containers/slider-monitor.jsx'; import ListMonitor from '../../containers/list-monitor.jsx'; -import {Theme, getStageColorsForTheme} from '../../lib/themes/index.js'; +import {Theme} from '../../lib/themes/index.js'; import styles from './monitor.css'; @@ -33,7 +33,7 @@ const modes = { }; const getCategoryColor = (theme, category) => { - const colors = getStageColorsForTheme(theme); + const colors = theme.getStageBlockColors(); return { background: colors[categoryColorMap[category]].primary, text: colors.text diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx index 7593c74de..2a04002e9 100644 --- a/src/containers/blocks.jsx +++ b/src/containers/blocks.jsx @@ -446,7 +446,7 @@ class Blocks extends React.Component { targetCostumes[targetCostumes.length - 1].name, stageCostumes[stageCostumes.length - 1].name, targetSounds.length > 0 ? targetSounds[targetSounds.length - 1].name : '', - getColorsForTheme(this.props.theme) + this.props.theme.getBlockColors() ); } catch { return null; @@ -766,7 +766,7 @@ Blocks.defaultOptions = { Blocks.defaultProps = { isVisible: true, options: Blocks.defaultOptions, - theme: Theme.light() + theme: Theme.light }; const mapStateToProps = state => ({ diff --git a/src/containers/monitor.jsx b/src/containers/monitor.jsx index a2c9d3708..a077d2cfe 100644 --- a/src/containers/monitor.jsx +++ b/src/containers/monitor.jsx @@ -279,7 +279,7 @@ Monitor.propTypes = { y: PropTypes.number }; Monitor.defaultProps = { - theme: Theme.light() + theme: Theme.light }; const mapStateToProps = state => ({ monitorLayout: state.scratchGui.monitorLayout, diff --git a/src/lib/themes/accent/red.js b/src/lib/themes/accent/red.js index 56ec816eb..bc0ca3ea4 100644 --- a/src/lib/themes/accent/red.js +++ b/src/lib/themes/accent/red.js @@ -1,4 +1,7 @@ const guiColors = { + 'motion-primary': '#ff4c4c', + 'motion-tertiary': '#cc3333', + 'looks-secondary': '#ff4c4c', 'looks-transparent': '#ff4d4d59', 'looks-light-transparent': '#ff4d4d26', diff --git a/src/lib/themes/blockHelpers.js b/src/lib/themes/blockHelpers.js index b201241ee..1fc3d07ee 100644 --- a/src/lib/themes/blockHelpers.js +++ b/src/lib/themes/blockHelpers.js @@ -1,4 +1,4 @@ -import {DEFAULT_THEME, getColorsForTheme, themeMap} from '.'; +import {BLOCKS_HIGH_CONTRAST, Theme} from '.'; const getBlockIconURI = extensionIcons => { if (!extensionIcons) return null; @@ -13,7 +13,7 @@ const getCategoryIconURI = extensionIcons => { }; // scratch-blocks colours has a pen property that scratch-gui uses for all extensions -const getExtensionColors = theme => getColorsForTheme(theme).pen; +const getExtensionColors = theme => theme.getBlockColors().pen; /** * Applies extension color theme to categories. @@ -21,15 +21,14 @@ const getExtensionColors = theme => getColorsForTheme(theme).pen; * These colors are not seen if the category provides a blockIconURI. * @param {Array.} dynamicBlockXML - XML for each category of extension blocks, returned from getBlocksXML * in the vm runtime. - * @param {string} theme - Theme name + * @param {Theme} theme - Theme name * @returns {Array.} Dynamic block XML updated with colors. */ const injectExtensionCategoryTheme = (dynamicBlockXML, theme) => { - // Don't do any manipulation for the default theme - if (theme === DEFAULT_THEME) return dynamicBlockXML; + if (theme.blocks !== BLOCKS_HIGH_CONTRAST) return dynamicBlockXML; const extensionColors = getExtensionColors(theme); - const extensionIcons = themeMap[theme].extensions; + const extensionIcons = theme.getExtensions(); const parser = new DOMParser(); const serializer = new XMLSerializer(); @@ -57,7 +56,7 @@ const injectBlockIcons = (blockInfoJson, theme) => { if (!blockInfoJson.args0 || blockInfoJson.args0.length < 1 || blockInfoJson.args0[0].type !== 'field_image') return blockInfoJson; - const extensionIcons = themeMap[theme].extensions; + const extensionIcons = theme.getExtensions(); const extensionId = blockInfoJson.type.substring(0, blockInfoJson.type.indexOf('_')); const blockIconURI = getBlockIconURI(extensionIcons[extensionId]); @@ -80,12 +79,11 @@ const injectBlockIcons = (blockInfoJson, theme) => { * Applies extension color theme to static block json. * No changes are applied if called with the default theme, allowing extensions to provide their own colors. * @param {object} blockInfoJson - Static block json - * @param {string} theme - Theme name + * @param {Theme} theme - Theme name * @returns {object} Block info json with updated colors. The original blockInfoJson is not modified. */ const injectExtensionBlockTheme = (blockInfoJson, theme) => { - // Don't do any manipulation for the default theme - if (theme === DEFAULT_THEME) return blockInfoJson; + if (theme.blocks !== BLOCKS_HIGH_CONTRAST) return blockInfoJson; const extensionColors = getExtensionColors(theme); diff --git a/src/lib/themes/global-styles.css b/src/lib/themes/global-styles.css index 23a67726f..3d8e21e7b 100644 --- a/src/lib/themes/global-styles.css +++ b/src/lib/themes/global-styles.css @@ -3,10 +3,6 @@ /* This is for overriding some styles that don't really "belong" to any existing stylesheets */ /* Try to use this sparingly, otherwise this will become unmaintainable again... */ -:global(:root) { - color-scheme: var(--color-scheme); -} - /* popover is used by gui and paint */ /* some of these are duplicated over there too; !important makes sure these win */ :global(.Popover) { diff --git a/src/lib/themes/guiHelpers.js b/src/lib/themes/guiHelpers.js index 5ec558a90..2718456f8 100644 --- a/src/lib/themes/guiHelpers.js +++ b/src/lib/themes/guiHelpers.js @@ -7,7 +7,7 @@ import AddonHooks from '../../addons/hooks'; const applyGuiColors = theme => { const doc = document.documentElement; - const defaultColors = Theme.light().getGuiColors(); + const defaultColors = Theme.light.getGuiColors(); for (const [name, value] of Object.entries(defaultColors)) { doc.style.setProperty(`--${name}-default`, value); } @@ -17,6 +17,8 @@ const applyGuiColors = theme => { doc.style.setProperty(`--${name}`, value); } + doc.style.colorScheme = colors['color-scheme']; + // a horrible hack window.Recolor = { primary: colors['looks-secondary'] diff --git a/src/lib/themes/index.js b/src/lib/themes/index.js index c4b9f77cc..6981d29b3 100644 --- a/src/lib/themes/index.js +++ b/src/lib/themes/index.js @@ -1,5 +1,4 @@ import defaultsDeep from 'lodash.defaultsdeep'; -import {defineMessages} from 'react-intl'; import * as accentPurple from './accent/purple'; import * as accentBlue from './accent/blue'; @@ -10,7 +9,7 @@ import * as guiDark from './gui/dark'; import * as blocksThree from './blocks/three'; import * as blocksHighContrast from './blocks/high-contrast'; -import * as blocksDark from './blocks/high-contrast'; +import * as blocksDark from './blocks/dark'; const ACCENT_PURPLE = 'purple'; const ACCENT_BLUE = 'blue'; @@ -39,39 +38,34 @@ const BLOCKS_MAP = { [BLOCKS_THREE]: { blocksMediaFolder: 'blocks-media/default', colors: blocksThree.blockColors, - extensions: blocksThree.extensions + extensions: blocksThree.extensions, + useForStage: true }, [BLOCKS_HIGH_CONTRAST]: { blocksMediaFolder: 'blocks-media/high-contrast', colors: defaultsDeep({}, blocksHighContrast.blockColors, defaultBlockColors), - extensions: blocksHighContrast.extensions + extensions: blocksHighContrast.extensions, + useForStage: true }, [BLOCKS_DARK]: { blocksMediaFolder: 'blocks-media/default', colors: defaultsDeep({}, blocksDark.blockColors, defaultBlockColors), - extensions: blocksDark.extensions + extensions: blocksDark.extensions, + useForStage: false } }; class Theme { constructor (accent, gui, blocks) { - // do not modify directly + // do not modify these directly this.accent = Object.keys(ACCENT_MAP).includes(accent) ? accent : ACCENT_DEFAULT; this.gui = Object.keys(GUI_MAP).includes(gui) ? gui : GUI_DEFAULT; this.blocks = Object.keys(BLOCKS_MAP).includes(blocks) ? blocks : BLOCKS_DEFAULT; } - static light () { - return new Theme(ACCENT_DEFAULT, GUI_LIGHT, BLOCKS_DEFAULT); - } - - static dark () { - return new Theme(ACCENT_DEFAULT, GUI_DARK, BLOCKS_DEFAULT); - } - - static highContrast () { - return new Theme(ACCENT_DEFAULT, GUI_DEFAULT, BLOCKS_HIGH_CONTRAST); - } + static light = new Theme(ACCENT_DEFAULT, GUI_LIGHT, BLOCKS_DEFAULT); + static dark = new Theme(ACCENT_DEFAULT, GUI_DARK, BLOCKS_DEFAULT); + static highContrast = new Theme(ACCENT_DEFAULT, GUI_DEFAULT, BLOCKS_HIGH_CONTRAST); set (what, to) { if (what === 'accent') { @@ -89,13 +83,22 @@ class Theme { * @returns {string} a string that uniquely identifies this theme. Intended to be used as a react key. */ key () { - return JSON.stringify(this); + return `${this.accent}|${this.gui}|${this.blocks}`; } getBlocksMediaFolder () { return BLOCKS_MAP[this.blocks].blocksMediaFolder; } + getGuiColors () { + return defaultsDeep( + {}, + ACCENT_MAP[this.accent].guiColors, + GUI_MAP[this.gui].guiColors, + guiLight.guiColors + ); + } + getBlockColors () { return defaultsDeep( {}, @@ -105,13 +108,19 @@ class Theme { ); } - getGuiColors () { - return defaultsDeep( - {}, - ACCENT_MAP[this.accent].guiColors, - GUI_MAP[this.gui].guiColors, - guiLight.guiColors - ); + getExtensions () { + return BLOCKS_MAP[this.blocks].extensions; + } + + isDark () { + return this.getGuiColors()['color-scheme'] === 'dark'; + } + + getStageBlockColors () { + if (BLOCKS_MAP[this.blocks].useForStage) { + return this.getBlockColors(); + } + return Theme.light.getBlockColors(); } } diff --git a/src/lib/themes/themePersistance.js b/src/lib/themes/themePersistance.js index 9f12c3222..c22f07884 100644 --- a/src/lib/themes/themePersistance.js +++ b/src/lib/themes/themePersistance.js @@ -10,13 +10,13 @@ const STORAGE_KEY = 'tw:theme'; const systemPreferencesTheme = () => { if (window.matchMedia) { if (window.matchMedia(PREFERS_HIGH_CONTRAST_QUERY).matches) { - return Theme.highContrast(); + return Theme.highContrast; } if (window.matchMedia(PREFERS_DARK_QUERY).matches) { - return Theme.dark(); + return Theme.dark; } } - return Theme.light(); + return Theme.light; }; /** @@ -28,9 +28,10 @@ const detectTheme = () => { // Migrate legacy preferences if (local === 'dark') { - return Theme.dark(); + return Theme.dark; } if (local === 'light') { + return Theme.light; } const parsed = JSON.parse(local);