diff --git a/sandstone/custom-skin/.gitignore b/sandstone/feature-custom-skin-generator/.gitignore similarity index 100% rename from sandstone/custom-skin/.gitignore rename to sandstone/feature-custom-skin-generator/.gitignore diff --git a/sandstone/custom-skin/README-devs.md b/sandstone/feature-custom-skin-generator/README-devs.md similarity index 100% rename from sandstone/custom-skin/README-devs.md rename to sandstone/feature-custom-skin-generator/README-devs.md diff --git a/sandstone/custom-skin/README.md b/sandstone/feature-custom-skin-generator/README.md similarity index 100% rename from sandstone/custom-skin/README.md rename to sandstone/feature-custom-skin-generator/README.md diff --git a/sandstone/custom-skin/package.json b/sandstone/feature-custom-skin-generator/package.json similarity index 96% rename from sandstone/custom-skin/package.json rename to sandstone/feature-custom-skin-generator/package.json index 5e6de64c5..ca38ed127 100644 --- a/sandstone/custom-skin/package.json +++ b/sandstone/feature-custom-skin-generator/package.json @@ -1,5 +1,5 @@ { - "name": "custom-skin", + "name": "custom-skin-generator", "version": "1.0.0", "description": "A general template for an Enact Sandstone application.", "author": "", diff --git a/sandstone/custom-skin/resources/ilibmanifest.json b/sandstone/feature-custom-skin-generator/resources/ilibmanifest.json similarity index 100% rename from sandstone/custom-skin/resources/ilibmanifest.json rename to sandstone/feature-custom-skin-generator/resources/ilibmanifest.json diff --git a/sandstone/custom-skin/screenTypes.json b/sandstone/feature-custom-skin-generator/screenTypes.json similarity index 100% rename from sandstone/custom-skin/screenTypes.json rename to sandstone/feature-custom-skin-generator/screenTypes.json diff --git a/sandstone/custom-skin/src/App/App.js b/sandstone/feature-custom-skin-generator/src/App/App.js similarity index 100% rename from sandstone/custom-skin/src/App/App.js rename to sandstone/feature-custom-skin-generator/src/App/App.js diff --git a/sandstone/custom-skin/src/App/App.module.less b/sandstone/feature-custom-skin-generator/src/App/App.module.less similarity index 100% rename from sandstone/custom-skin/src/App/App.module.less rename to sandstone/feature-custom-skin-generator/src/App/App.module.less diff --git a/sandstone/custom-skin/src/App/package.json b/sandstone/feature-custom-skin-generator/src/App/package.json similarity index 100% rename from sandstone/custom-skin/src/App/package.json rename to sandstone/feature-custom-skin-generator/src/App/package.json diff --git a/sandstone/custom-skin/src/common/styles.module.less b/sandstone/feature-custom-skin-generator/src/common/styles.module.less similarity index 100% rename from sandstone/custom-skin/src/common/styles.module.less rename to sandstone/feature-custom-skin-generator/src/common/styles.module.less diff --git a/sandstone/custom-skin/src/components/AutoPopup/AutoPopup.js b/sandstone/feature-custom-skin-generator/src/components/AutoPopup/AutoPopup.js similarity index 100% rename from sandstone/custom-skin/src/components/AutoPopup/AutoPopup.js rename to sandstone/feature-custom-skin-generator/src/components/AutoPopup/AutoPopup.js diff --git a/sandstone/custom-skin/src/components/ColorField/ColorField.js b/sandstone/feature-custom-skin-generator/src/components/ColorField/ColorField.js similarity index 100% rename from sandstone/custom-skin/src/components/ColorField/ColorField.js rename to sandstone/feature-custom-skin-generator/src/components/ColorField/ColorField.js diff --git a/sandstone/custom-skin/src/components/ColorFields/ColorFields.js b/sandstone/feature-custom-skin-generator/src/components/ColorFields/ColorFields.js similarity index 100% rename from sandstone/custom-skin/src/components/ColorFields/ColorFields.js rename to sandstone/feature-custom-skin-generator/src/components/ColorFields/ColorFields.js diff --git a/sandstone/custom-skin/src/components/ColorPicker/ColorPicker.js b/sandstone/feature-custom-skin-generator/src/components/ColorPicker/ColorPicker.js similarity index 100% rename from sandstone/custom-skin/src/components/ColorPicker/ColorPicker.js rename to sandstone/feature-custom-skin-generator/src/components/ColorPicker/ColorPicker.js diff --git a/sandstone/custom-skin/src/components/ColorPicker/ColorPicker.module.less b/sandstone/feature-custom-skin-generator/src/components/ColorPicker/ColorPicker.module.less similarity index 100% rename from sandstone/custom-skin/src/components/ColorPicker/ColorPicker.module.less rename to sandstone/feature-custom-skin-generator/src/components/ColorPicker/ColorPicker.module.less diff --git a/sandstone/custom-skin/src/components/ImportSkin/ImportSkin.js b/sandstone/feature-custom-skin-generator/src/components/ImportSkin/ImportSkin.js similarity index 100% rename from sandstone/custom-skin/src/components/ImportSkin/ImportSkin.js rename to sandstone/feature-custom-skin-generator/src/components/ImportSkin/ImportSkin.js diff --git a/sandstone/custom-skin/src/components/ImportSkin/ImportSkin.module.less b/sandstone/feature-custom-skin-generator/src/components/ImportSkin/ImportSkin.module.less similarity index 100% rename from sandstone/custom-skin/src/components/ImportSkin/ImportSkin.module.less rename to sandstone/feature-custom-skin-generator/src/components/ImportSkin/ImportSkin.module.less diff --git a/sandstone/custom-skin/src/components/NameField/NameField.js b/sandstone/feature-custom-skin-generator/src/components/NameField/NameField.js similarity index 100% rename from sandstone/custom-skin/src/components/NameField/NameField.js rename to sandstone/feature-custom-skin-generator/src/components/NameField/NameField.js diff --git a/sandstone/custom-skin/src/components/NameField/NameField.module.less b/sandstone/feature-custom-skin-generator/src/components/NameField/NameField.module.less similarity index 100% rename from sandstone/custom-skin/src/components/NameField/NameField.module.less rename to sandstone/feature-custom-skin-generator/src/components/NameField/NameField.module.less diff --git a/sandstone/custom-skin/src/components/OutputField/OutputField.js b/sandstone/feature-custom-skin-generator/src/components/OutputField/OutputField.js similarity index 100% rename from sandstone/custom-skin/src/components/OutputField/OutputField.js rename to sandstone/feature-custom-skin-generator/src/components/OutputField/OutputField.js diff --git a/sandstone/custom-skin/src/components/OutputField/OutputField.module.less b/sandstone/feature-custom-skin-generator/src/components/OutputField/OutputField.module.less similarity index 100% rename from sandstone/custom-skin/src/components/OutputField/OutputField.module.less rename to sandstone/feature-custom-skin-generator/src/components/OutputField/OutputField.module.less diff --git a/sandstone/custom-skin/src/components/SingleField/SingleField.js b/sandstone/feature-custom-skin-generator/src/components/SingleField/SingleField.js similarity index 100% rename from sandstone/custom-skin/src/components/SingleField/SingleField.js rename to sandstone/feature-custom-skin-generator/src/components/SingleField/SingleField.js diff --git a/sandstone/custom-skin/src/components/SingleField/SingleField.module.less b/sandstone/feature-custom-skin-generator/src/components/SingleField/SingleField.module.less similarity index 100% rename from sandstone/custom-skin/src/components/SingleField/SingleField.module.less rename to sandstone/feature-custom-skin-generator/src/components/SingleField/SingleField.module.less diff --git a/sandstone/custom-skin/src/components/TripleField/TripleField.js b/sandstone/feature-custom-skin-generator/src/components/TripleField/TripleField.js similarity index 100% rename from sandstone/custom-skin/src/components/TripleField/TripleField.js rename to sandstone/feature-custom-skin-generator/src/components/TripleField/TripleField.js diff --git a/sandstone/custom-skin/src/components/TripleField/TripleField.module.less b/sandstone/feature-custom-skin-generator/src/components/TripleField/TripleField.module.less similarity index 100% rename from sandstone/custom-skin/src/components/TripleField/TripleField.module.less rename to sandstone/feature-custom-skin-generator/src/components/TripleField/TripleField.module.less diff --git a/sandstone/custom-skin/src/constants.js b/sandstone/feature-custom-skin-generator/src/constants.js similarity index 100% rename from sandstone/custom-skin/src/constants.js rename to sandstone/feature-custom-skin-generator/src/constants.js diff --git a/sandstone/custom-skin/src/index.js b/sandstone/feature-custom-skin-generator/src/index.js similarity index 100% rename from sandstone/custom-skin/src/index.js rename to sandstone/feature-custom-skin-generator/src/index.js diff --git a/sandstone/custom-skin/src/utils.js b/sandstone/feature-custom-skin-generator/src/utils.js similarity index 100% rename from sandstone/custom-skin/src/utils.js rename to sandstone/feature-custom-skin-generator/src/utils.js diff --git a/sandstone/custom-skin/src/views/MainPanel.js b/sandstone/feature-custom-skin-generator/src/views/MainPanel.js similarity index 100% rename from sandstone/custom-skin/src/views/MainPanel.js rename to sandstone/feature-custom-skin-generator/src/views/MainPanel.js diff --git a/sandstone/custom-skin/src/views/MainPanel.module.less b/sandstone/feature-custom-skin-generator/src/views/MainPanel.module.less similarity index 100% rename from sandstone/custom-skin/src/views/MainPanel.module.less rename to sandstone/feature-custom-skin-generator/src/views/MainPanel.module.less diff --git a/sandstone/pattern-ls2request-custom-colors/.gitignore b/sandstone/pattern-ls2request-custom-colors/.gitignore new file mode 100644 index 000000000..f94ea516b --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/.gitignore @@ -0,0 +1,15 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules + +# testing +coverage + +# production +build +dist + +# misc +.DS_Store +npm-debug.log diff --git a/sandstone/pattern-ls2request-custom-colors/README.md b/sandstone/pattern-ls2request-custom-colors/README.md new file mode 100644 index 000000000..3258cc0e9 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/README.md @@ -0,0 +1,20 @@ +## Custom Colors Generator + +A sample Enact application that uses dynamic color change feature to style components and create a personalized theme. + +Run `npm install` then `npm run serve` to have the app running on [http://localhost:8080](http://localhost:8080), where you can view it in your browser. + +This app will help you choose a preset theme and/or customize the Sandstone UI components for your application. +On the left side of the app, you can see all the presets and/or customizable color fields, while on the right side is the `Theme Preview` area. +Any value changes you make to the color pickers will be reflected in `Theme Preview`. + +#### Customize Themes + +The radio buttons on the first Panel allow you to choose a preset, including Sandstone default theme. +You can also choose to activate dynamic color mode which will modify the luminosity and saturation of your theme colors depending on the current time. +In addition to this, you can opt to adjust skin automatically, which means that the system will choose between Sandstone neutral and light modes according to the colors you have set. +On the second Panel you can interact with colors by clicking the colored circle which will open the basic color picker. + +#### Reset Theme + +The `Reset` button will revert all the changes to the active selected preset. diff --git a/sandstone/pattern-ls2request-custom-colors/package.json b/sandstone/pattern-ls2request-custom-colors/package.json new file mode 100644 index 000000000..c176da753 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/package.json @@ -0,0 +1,49 @@ +{ + "name": "pattern-ls2request-custom-colors", + "version": "1.0.0", + "description": "A general template for an Enact Sandstone application.", + "author": "", + "main": "src/index.js", + "scripts": { + "serve": "enact serve", + "pack": "enact pack", + "pack-p": "enact pack -p", + "watch": "enact pack --watch", + "clean": "enact clean", + "lint": "enact lint --strict .", + "license": "enact license", + "test": "enact test", + "test-watch": "enact test --watch" + }, + "license": "UNLICENSED", + "private": true, + "repository": "", + "enact": { + "theme": "sandstone" + }, + "eslintConfig": { + "extends": "enact-proxy/strict" + }, + "eslintIgnore": [ + "node_modules/*", + "build/*", + "dist/*" + ], + "dependencies": { + "@enact/core": "^4.7.5", + "@enact/i18n": "^4.7.5", + "@enact/sandstone": "^2.7.9", + "@enact/spotlight": "^4.7.5", + "@enact/ui": "^4.7.5", + "@enact/webos": "^4.7.2", + "classnames": "^2.3.2", + "ilib": "^14.18.0", + "prop-types": "^15.8.1", + "ramda": "^0.29.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "eslint-config-enact-proxy": "^1.0.6" + } +} diff --git a/sandstone/pattern-ls2request-custom-colors/resources/ilibmanifest.json b/sandstone/pattern-ls2request-custom-colors/resources/ilibmanifest.json new file mode 100644 index 000000000..b736f135b --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/resources/ilibmanifest.json @@ -0,0 +1,3 @@ +{ + "files": [] +} diff --git a/sandstone/pattern-ls2request-custom-colors/screenTypes.json b/sandstone/pattern-ls2request-custom-colors/screenTypes.json new file mode 100644 index 000000000..4a66543a8 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/screenTypes.json @@ -0,0 +1,10 @@ +[ + {"name": "pal", "pxPerRem": 12, "width": 1024, "height": 576, "aspectRatioName": "hdtv"}, + {"name": "hd", "pxPerRem": 16, "width": 1280, "height": 720, "aspectRatioName": "hdtv"}, + {"name": "fhd", "pxPerRem": 24, "width": 1920, "height": 1080, "aspectRatioName": "hdtv"}, + {"name": "uw-uxga", "pxPerRem": 24, "width": 2560, "height": 1080, "aspectRatioName": "cinema"}, + {"name": "qhd", "pxPerRem": 36, "width": 2560, "height": 1440, "aspectRatioName": "hdtv"}, + {"name": "wqhd", "pxPerRem": 32, "width": 3440, "height": 1440, "aspectRatioName": "cinema"}, + {"name": "uhd", "pxPerRem": 48, "width": 3840, "height": 2160, "aspectRatioName": "hdtv", "base": true}, + {"name": "uhd2", "pxPerRem": 96, "width": 7680, "height": 4320, "aspectRatioName": "hdtv"} +] diff --git a/sandstone/pattern-ls2request-custom-colors/src/App/App.js b/sandstone/pattern-ls2request-custom-colors/src/App/App.js new file mode 100644 index 000000000..68c0de603 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/App/App.js @@ -0,0 +1,82 @@ +import ThemeDecorator from '@enact/sandstone/ThemeDecorator'; +import LS2Request from '@enact/webos/LS2Request'; +import {useEffect, useState} from 'react'; + +import {generateStylesheet} from '../hooks/generateStylesheet'; +import MainView from '../views/MainView'; +import screenTypes from '../../screenTypes.json'; + +import {AppContext, customColorsContext} from '../constants'; + +const request = new LS2Request(); + +const defaultKeyThemeValue = JSON.stringify({ + "version": "0.1", + "activeTheme": "defaultTheme", + "dynamicColor": "off", + "handleSkin": "off", + "backgroundColor": "#000000", + "componentBackgroundColor": "#7D848C", + "focusBackgroundColor": "#E6E6E6", + "popupBackgroundColor": "#575E66", + "subtitleTextColor": "#ABAEB3", + "textColor": "#E6E6E6", + colors: generateStylesheet( + "#000000", + "#7D848C", + "#E6E6E6", + "#575E66", + "#ABAEB3", + "#E6E6E6" + ) +}); + +const App = (props) => { + const [context, setContext] = useState(customColorsContext); + const [responseStatus, setResponseStatus] = useState(false); + + useEffect(() => { + // check if app is running on webOS system + if (typeof window === 'object' && window.webOSSystem && window.webOSSystem.launchParams) { + // make a GET call to service settings to check the value of `theme` key + request.send({ + service: 'luna://com.webos.service.settings/', + method: 'getSystemSettings', + parameters: { + category: 'customUi', + keys: ['theme'] + }, + onSuccess: (res) => { + setResponseStatus(res.returnValue); + // if `theme` key is populated, update the context with key value + if (res.settings.theme !== '' && res) { + const parsedKeyData = JSON.parse(res.settings.theme); + setContext({...parsedKeyData}); + // if `theme` key is an empty string, update the context with a default value, then make a SET call to service settings and set + // `theme` key with a default value + } else if (res.settings.theme === '') { + setContext(JSON.parse(defaultKeyThemeValue)); + request.send({ + service: 'luna://com.webos.service.settings/', + method: 'setSystemSettings', + parameters: { + category: 'customUi', + settings: { + theme: defaultKeyThemeValue + } + } + }); + } + } + }); + } + }, []); + + return ( + + + + ); +}; + +export default ThemeDecorator({ri: {screenTypes}}, App); diff --git a/sandstone/pattern-ls2request-custom-colors/src/App/App.module.less b/sandstone/pattern-ls2request-custom-colors/src/App/App.module.less new file mode 100644 index 000000000..2774c5018 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/App/App.module.less @@ -0,0 +1,3 @@ +.app { + // general app styles +} diff --git a/sandstone/pattern-ls2request-custom-colors/src/App/package.json b/sandstone/pattern-ls2request-custom-colors/src/App/package.json new file mode 100644 index 000000000..441552583 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/App/package.json @@ -0,0 +1,3 @@ +{ + "main": "App.js" +} diff --git a/sandstone/pattern-ls2request-custom-colors/src/components/ColorPicker/ColorPicker.js b/sandstone/pattern-ls2request-custom-colors/src/components/ColorPicker/ColorPicker.js new file mode 100644 index 000000000..b524a1932 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/components/ColorPicker/ColorPicker.js @@ -0,0 +1,333 @@ +/** + * A Sandstone component that allows the user to choose a color. + * + * @example + * + * + * @module sandstone/ColorPicker + * @exports ColorPicker + * @exports ColorPickerBase + * @exports ColorPickerDecorator + * @private + */ + +import kind from '@enact/core/kind'; +import BodyText from '@enact/sandstone/BodyText'; +import Button, {ButtonBase} from '@enact/sandstone/Button'; +import Icon from '@enact/sandstone/Icon'; +import Item from '@enact/sandstone/Item'; +import Popup from '@enact/sandstone/Popup'; +import Skinnable from '@enact/sandstone/Skinnable'; +import Slider from '@enact/sandstone/Slider'; +import Spottable from '@enact/spotlight/Spottable'; +import {Cell, Column, Row} from '@enact/ui/Layout'; +import Toggleable from '@enact/ui/Toggleable'; +import PropTypes from 'prop-types'; +import compose from 'ramda/src/compose'; +import {useCallback, useEffect, useState} from 'react'; + +import {hexToHSL, HSLToHex} from '../../hooks/utils'; + +import componentCss from './ColorPicker.module.less'; + +const SpottableButton = Spottable(ButtonBase); + +/** + * A component that contains the content for the {@link sandstone/ColorPicker|ColorPicker} popup. + * + * @class PopupContent + * @memberof sandstone/ColorPicker + * @ui + * @private + */ +const PopupContent = ({color, colorHandler, css}) => { + const [hue, setHue] = useState(0); + const [saturation, setSaturation] = useState(0); + const [lightness, setLightness] = useState(0); + + useEffect(() => { + let {h, s, l} = hexToHSL(color); + + setHue(h); + setSaturation(s); + setLightness(l); + }, [color]); + + const changeHue = useCallback((ev) => { + setHue(ev.value); + }, []); + + const changeLightness = useCallback((ev) => { + setLightness(ev.value); + }, []); + + const changeSaturation = useCallback((ev) => { + setSaturation(ev.value); + }, []); + + const onSliderValueChange = useCallback(() => { + colorHandler(HSLToHex({h: hue, s: saturation, l: lightness})); + }, [colorHandler, hue, lightness, saturation]); + + return ( + +
+ + Hue {hue} + + Saturation {saturation}% + + Lightness {lightness}% + + +
+
+ + ); +}; + +PopupContent.propTypes = { + /** + * Indicates the color. + * + * @type {String} + * @private + */ + color: PropTypes.string, + + /** + * Called when color is modified. + * + * @type {Function} + * @private + */ + colorHandler: PropTypes.func, + + /** + * Customizes the component by mapping the supplied collection of CSS class names to the + * corresponding internal elements and states of this component. + * + * The following classes are supported: + * + * `colorPicker` - The root class name + * `coloredDiv` - A class name used for a single div + * + * @type {Object} + * @private + */ + css: PropTypes.object, + + /** + * Contains an array with a couple of possible preset colors. + * + * @type {Array} + * @private + */ + presetColors: PropTypes.array +}; + +/** + * The color picker base component which sets-up the component's structure. + * + * This component is most often not used directly but may be composed within another component as it + * is within {@link sandstone/ColorPicker|ColorPicker}. + * + * @class ColorPickerBase + * @memberof sandstone/ColorPicker + * @ui + * @private + */ +const ColorPickerBase = kind({ + name: 'ColorPicker', + + functional: true, + + propTypes: { + /** + * Indicates the color. + * + * @type {String} + * @private + */ + color: PropTypes.string, + + /** + * Called when color is modified. + * + * @type {Function} + * @private + */ + colorHandler: PropTypes.func, + + /** + * Customizes the component by mapping the supplied collection of CSS class names to the + * corresponding internal elements and states of this component. + * + * The following classes are supported: + * + * `colorPicker` - The root class name + * `colorPopup` - A class name used for the popup + * + * @type {Object} + * @private + */ + css: PropTypes.object, + + /** + * Applies the `disabled` class. + * + * When `true`, the color picker is shown as disabled. + * + * @type {Boolean} + * @default false + * @public + */ + disabled: PropTypes.bool, + + /** + * Called to open or close the color picker. + * + * @type {Function} + * @public + */ + onTogglePopup: PropTypes.func, + + /** + * Indicates if the color picker is open. + * + * When `true`, contextual popup opens. + * + * @type {Boolean} + * @default false + * @private + */ + popupOpen: PropTypes.bool, + + /** + * Contains the text that shows next to the color picker. + * + * @type {String} + * @public + */ + text: PropTypes.string + }, + + defaultProps: { + disabled: false, + popupOpen: false + }, + + handlers: { + handleClosePopup: (ev, {onTogglePopup}) => { + onTogglePopup(); + }, + handleOpenPopup: (ev, {disabled, onTogglePopup}) => { + if (!disabled) { + onTogglePopup(); + } + } + }, + + styles: { + css: componentCss, + publicClassNames: true + }, + + render: ({color, colorHandler, css, disabled, handleClosePopup, handleOpenPopup, popupOpen, text, ...rest}) => { + delete rest.onTogglePopup; + + // eslint-disable-next-line react-hooks/rules-of-hooks + const CloseIcon = useCallback((props) => , [css]); + const slotAfter = ; + + return ( + + + {text} + + + + + {text} + + + + + + + + Checkbox + Toggle + + + + {['Item 1', 'Item 2', 'Item 3']} + + + + Hello + + + + + ); +}; + +export default PreviewSection; diff --git a/sandstone/pattern-ls2request-custom-colors/src/components/PreviewSection/PreviewSection.module.less b/sandstone/pattern-ls2request-custom-colors/src/components/PreviewSection/PreviewSection.module.less new file mode 100644 index 000000000..130ee25b5 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/components/PreviewSection/PreviewSection.module.less @@ -0,0 +1,45 @@ +// PreviewSection.module.less +// +@import '~@enact/sandstone/styles/colors.less'; + +.previewSection { + background-color: @sand-bg-color; + border-radius: 12px; + margin: 24px; + padding: 0 24px; + display: flex; + justify-content: center; + + .previewTitle { + display: flex; + justify-content: center; + min-height: auto; + padding: 24px 0; + margin: 0 24px; + font-weight: 200; + } + + .previewComponents { + justify-content: space-around; + width: 100%; + + .previewButtons { + flex-wrap: wrap; + justify-content: center; + + .button { + min-width: 339px; + margin: 12px; + } + + & > * { + margin: 15px; + } + } + + .previewDropdown, + .previewPopup { + align-self: center; + } + } +} diff --git a/sandstone/pattern-ls2request-custom-colors/src/components/PreviewSection/package.json b/sandstone/pattern-ls2request-custom-colors/src/components/PreviewSection/package.json new file mode 100644 index 000000000..42f3f5add --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/components/PreviewSection/package.json @@ -0,0 +1,3 @@ +{ + "main": "PreviewSection.js" +} diff --git a/sandstone/pattern-ls2request-custom-colors/src/constants.js b/sandstone/pattern-ls2request-custom-colors/src/constants.js new file mode 100644 index 000000000..c24e78678 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/constants.js @@ -0,0 +1,27 @@ +import {createContext} from "react"; + +export const presets = { + defaultColorSet: "Default Color Set", + blueColorSet1: "Light Blue Color Set", + blueColorSet2: "Blue Color Set", + greenColorSet1: "Light Green Color Set", + greenColorSet2: "Green Color Set", + purpleColorSet1: "Light Purple Color Set", + purpleColorSet2: "Purple Color Set", + redColorSet1: "Light Red Color Set", + redColorSet2: "Red Color Set" +}; + +export const customColorsContext = { + activeTheme: 'defaultColorSet', + dynamicColor: 'off', + handleSkin: 'off', + backgroundColor: '#000000', + componentBackgroundColor: '#7D848C', + focusBackgroundColor: '#E6E6E6', + popupBackgroundColor: '#575E66', + subtitleTextColor: '#ABAEB3', + textColor: '#E6E6E6' +}; + +export const AppContext = createContext(null); diff --git a/sandstone/pattern-ls2request-custom-colors/src/hooks/generateStylesheet.js b/sandstone/pattern-ls2request-custom-colors/src/hooks/generateStylesheet.js new file mode 100644 index 000000000..91a402c54 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/hooks/generateStylesheet.js @@ -0,0 +1,535 @@ +import {hexToRGB} from './utils'; + +// Function that returns a Sandstone stylesheet based on 6 colors and a preset +export const generateStylesheet = (backgroundColor, componentBackgroundColor, focusBackgroundColor, popupBackgroundColor, subTextColor, textColor, preset) => { + const fbgRGB = hexToRGB(focusBackgroundColor).join(', '); + const pbgRGB = hexToRGB(popupBackgroundColor).join(', '); + const stRGB = hexToRGB(subTextColor).join(', '); + const tRGB = hexToRGB(textColor).join(', '); + + // This switch will return a different color combination based on preset + switch (preset) { + case 'blueColorSet1': + return `.sandstone-theme { + /* Skin Name: Blue 1; */ + --sand-bg-color: ${backgroundColor}; + --sand-text-color-rgb: ${tRGB}; + --sand-text-sub-color: ${subTextColor}; + --sand-shadow-color-rgb: 0, 0, 0; + --sand-component-text-color-rgb: ${tRGB}; + --sand-component-text-sub-color-rgb: ${stRGB}; + --sand-component-bg-color: ${componentBackgroundColor}; + --sand-component-active-indicator-bg-color: ${focusBackgroundColor}; + --sand-component-inactive-indicator-bg-color: #9DA2A7; + --sand-focus-text-color: #303030; + --sand-focus-bg-color-rgb: ${fbgRGB}; + --sand-component-focus-text-color-rgb: 51, 51, 51; + --sand-component-focus-active-indicator-bg-color: #4C5059; + --sand-component-focus-inactive-indicator-bg-color: #B8B9BB; + --sand-selected-color-rgb: ${tRGB}; + --sand-selected-text-color: #E6E6E6; + --sand-selected-bg-color: #61688E; + --sand-disabled-focus-bg-color: ${subTextColor}; + --sand-disabled-selected-color: #4C5059; + --sand-disabled-selected-bg-color: #E7E7E7; + --sand-disabled-selected-focus-color: #E7E7E7; + --sand-disabled-selected-focus-bg-color: #4C5059; + --sand-fullscreen-bg-color: #000000; + --sand-overlay-bg-color-rgb: ${pbgRGB}; + --sand-selection-color: #4C5059; + --sand-selection-bg-color: #3399FF; + --sand-toggle-off-color: #AEAEAE; + --sand-toggle-off-bg-color: #494949; + --sand-toggle-on-color: ${focusBackgroundColor}; + --sand-toggle-on-bg-color: #61688E; + --sand-progress-color-rgb: ${tRGB}; + --sand-progress-buffer-color: #6B6D73; + --sand-progress-bg-color-rgb: 55, 58, 65; + --sand-progress-highlighted-color: #FFFFFF; + --sand-progress-slider-color: #8D9298; + --sand-spinner-color-rgb: 255, 255, 255; + --sand-checkbox-color: ${focusBackgroundColor}; + --sand-item-disabled-focus-bg-color: #E6E6E6; + --sand-keyguide-bg-color-rgb: 107, 109, 115; + --sand-slider-disabled-knob-bg-color: #666666; + --sand-alert-overlay-bg-color-rgb: 202, 203, 204; + --sand-alert-overlay-text-color-rgb: 46, 50, 57; + --sand-alert-overlay-text-sub-color: #2E3239; + --sand-alert-overlay-focus-text-color: #575E66; + --sand-alert-overlay-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-disabled-selected-bg-color: #788688; + --sand-alert-overlay-disabled-selected-focus-color: ${focusBackgroundColor}; + --sand-alert-overlay-disabled-selected-focus-bg-color: #4C5059; + --sand-alert-overlay-progress-color-rgb: 107, 109, 115; + --sand-alert-overlay-progress-bg-color-rgb: 161, 161, 161; + --sand-alert-overlay-checkbox-color: #858B92; + --sand-alert-overlay-checkbox-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-formcheckboxitem-focus-text-color: #575E66; + --sand-alert-overlay-item-disabled-focus-bg-color: #989CA2; + }`; + case 'blueColorSet2': + return `.sandstone-theme { + /* Skin Name: Blue 2; */ + --sand-bg-color: ${backgroundColor}; + --sand-text-color-rgb: ${tRGB}; + --sand-text-sub-color: ${subTextColor}; + --sand-shadow-color-rgb: 0, 0, 0; + --sand-component-text-color-rgb: ${tRGB}; + --sand-component-text-sub-color-rgb: ${stRGB}; + --sand-component-bg-color: ${componentBackgroundColor}; + --sand-component-active-indicator-bg-color: ${focusBackgroundColor}; + --sand-component-inactive-indicator-bg-color: #9DA2A7; + --sand-focus-text-color: #152DAC; + --sand-focus-bg-color-rgb: ${fbgRGB}; + --sand-component-focus-text-color-rgb: 28, 49, 170; + --sand-component-focus-active-indicator-bg-color: #4C5059; + --sand-component-focus-inactive-indicator-bg-color: #B8B9BB; + --sand-selected-color-rgb: ${tRGB}; + --sand-selected-text-color: #E6E6E6; + --sand-selected-bg-color: #61688E; + --sand-disabled-focus-bg-color: ${subTextColor}; + --sand-disabled-selected-color: #4C5059; + --sand-disabled-selected-bg-color: #E7E7E7; + --sand-disabled-selected-focus-color: #E7E7E7; + --sand-disabled-selected-focus-bg-color: #4C5059; + --sand-fullscreen-bg-color: #000000; + --sand-overlay-bg-color-rgb: ${pbgRGB}; + --sand-selection-color: #4C5059; + --sand-selection-bg-color: #3399FF; + --sand-toggle-off-color: #787C90; + --sand-toggle-off-bg-color: #444C73; + --sand-toggle-on-color: ${focusBackgroundColor}; + --sand-toggle-on-bg-color: #7B84B2; + --sand-progress-color-rgb: ${tRGB}; + --sand-progress-buffer-color: #6B6D73; + --sand-progress-bg-color-rgb: 55, 58, 65; + --sand-progress-highlighted-color: #FFFFFF; + --sand-progress-slider-color: #8D9298; + --sand-spinner-color-rgb: 255, 255, 255; + --sand-checkbox-color: ${focusBackgroundColor}; + --sand-item-disabled-focus-bg-color: #E6E6E6; + --sand-keyguide-bg-color-rgb: 107, 109, 115; + --sand-slider-disabled-knob-bg-color: #666666; + --sand-alert-overlay-bg-color-rgb: 202, 203, 204; + --sand-alert-overlay-text-color-rgb: 46, 50, 57; + --sand-alert-overlay-text-sub-color: #2E3239; + --sand-alert-overlay-focus-text-color: #575E66; + --sand-alert-overlay-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-disabled-selected-bg-color: #788688; + --sand-alert-overlay-disabled-selected-focus-color: ${focusBackgroundColor}; + --sand-alert-overlay-disabled-selected-focus-bg-color: #4C5059; + --sand-alert-overlay-progress-color-rgb: 107, 109, 115; + --sand-alert-overlay-progress-bg-color-rgb: 161, 161, 161; + --sand-alert-overlay-checkbox-color: #858B92; + --sand-alert-overlay-checkbox-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-formcheckboxitem-focus-text-color: #575E66; + --sand-alert-overlay-item-disabled-focus-bg-color: #989CA2; + }`; + case 'greenColorSet1': + return `.sandstone-theme { + /* Skin Name: Green 1; */ + --sand-bg-color: ${backgroundColor}; + --sand-text-color-rgb: ${tRGB}; + --sand-text-sub-color: ${subTextColor}; + --sand-shadow-color-rgb: 0, 0, 0; + --sand-component-text-color-rgb: ${tRGB}; + --sand-component-text-sub-color-rgb: ${stRGB}; + --sand-component-bg-color: ${componentBackgroundColor}; + --sand-component-active-indicator-bg-color: ${focusBackgroundColor}; + --sand-component-inactive-indicator-bg-color: #9DA2A7; + --sand-focus-text-color: #303030; + --sand-focus-bg-color-rgb: ${fbgRGB}; + --sand-component-focus-text-color-rgb: 51, 51, 51; + --sand-component-focus-active-indicator-bg-color: #4C5059; + --sand-component-focus-inactive-indicator-bg-color: #B8B9BB; + --sand-selected-color-rgb: ${tRGB}; + --sand-selected-text-color: #E6E6E6; + --sand-selected-bg-color: #61828E; + --sand-disabled-focus-bg-color: ${subTextColor}; + --sand-disabled-selected-color: #4C5059; + --sand-disabled-selected-bg-color: #E7E7E7; + --sand-disabled-selected-focus-color: #E7E7E7; + --sand-disabled-selected-focus-bg-color: #4C5059; + --sand-fullscreen-bg-color: #000000; + --sand-overlay-bg-color-rgb: ${pbgRGB}; + --sand-selection-color: #4C5059; + --sand-selection-bg-color: #3399FF; + --sand-toggle-off-color: #AEAEAE; + --sand-toggle-off-bg-color: #494949; + --sand-toggle-on-color: ${focusBackgroundColor}; + --sand-toggle-on-bg-color: #61828E; + --sand-progress-color-rgb: ${tRGB}; + --sand-progress-buffer-color: #6B6D73; + --sand-progress-bg-color-rgb: 55, 58, 65; + --sand-progress-highlighted-color: #FFFFFF; + --sand-progress-slider-color: #8D9298; + --sand-spinner-color-rgb: 255, 255, 255; + --sand-checkbox-color: ${focusBackgroundColor}; + --sand-item-disabled-focus-bg-color: #E6E6E6; + --sand-keyguide-bg-color-rgb: 107, 109, 115; + --sand-slider-disabled-knob-bg-color: #666666; + --sand-alert-overlay-bg-color-rgb: 202, 203, 204; + --sand-alert-overlay-text-color-rgb: 46, 50, 57; + --sand-alert-overlay-text-sub-color: #2E3239; + --sand-alert-overlay-focus-text-color: #575E66; + --sand-alert-overlay-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-disabled-selected-bg-color: #788688; + --sand-alert-overlay-disabled-selected-focus-color: ${focusBackgroundColor}; + --sand-alert-overlay-disabled-selected-focus-bg-color: #4C5059; + --sand-alert-overlay-progress-color-rgb: 107, 109, 115; + --sand-alert-overlay-progress-bg-color-rgb: 161, 161, 161; + --sand-alert-overlay-checkbox-color: #858B92; + --sand-alert-overlay-checkbox-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-formcheckboxitem-focus-text-color: #575E66; + --sand-alert-overlay-item-disabled-focus-bg-color: #989CA2; + }`; + case 'greenColorSet2': + return `.sandstone-theme { + /* Skin Name: Green 2; */ + --sand-bg-color: ${backgroundColor}; + --sand-text-color-rgb: ${tRGB}; + --sand-text-sub-color: ${subTextColor}; + --sand-shadow-color-rgb: 0, 0, 0; + --sand-component-text-color-rgb: ${tRGB}; + --sand-component-text-sub-color-rgb: ${stRGB}; + --sand-component-bg-color: ${componentBackgroundColor}; + --sand-component-active-indicator-bg-color: ${focusBackgroundColor}; + --sand-component-inactive-indicator-bg-color: #9DA2A7; + --sand-focus-text-color: #02435F; + --sand-focus-bg-color-rgb: ${fbgRGB}; + --sand-component-focus-text-color-rgb: 8, 69, 95; + --sand-component-focus-active-indicator-bg-color: #4C5059; + --sand-component-focus-inactive-indicator-bg-color: #B8B9BB; + --sand-selected-color-rgb: ${tRGB}; + --sand-selected-text-color: #E6E6E6; + --sand-selected-bg-color: #61828E; + --sand-disabled-focus-bg-color: ${subTextColor}; + --sand-disabled-selected-color: #4C5059; + --sand-disabled-selected-bg-color: #E7E7E7; + --sand-disabled-selected-focus-color: #E7E7E7; + --sand-disabled-selected-focus-bg-color: #4C5059; + --sand-fullscreen-bg-color: #000000; + --sand-overlay-bg-color-rgb: ${pbgRGB}; + --sand-selection-color: #4C5059; + --sand-selection-bg-color: #3399FF; + --sand-toggle-off-color: #6F7E84; + --sand-toggle-off-bg-color: #31505B; + --sand-toggle-on-color: ${focusBackgroundColor}; + --sand-toggle-on-bg-color: #6B95A4; + --sand-progress-color-rgb: ${tRGB}; + --sand-progress-buffer-color: #6B6D73; + --sand-progress-bg-color-rgb: 55, 58, 65; + --sand-progress-highlighted-color: #FFFFFF; + --sand-progress-slider-color: #8D9298; + --sand-spinner-color-rgb: 255, 255, 255; + --sand-checkbox-color: ${focusBackgroundColor}; + --sand-item-disabled-focus-bg-color: #E6E6E6; + --sand-keyguide-bg-color-rgb: 107, 109, 115; + --sand-slider-disabled-knob-bg-color: #666666; + --sand-alert-overlay-bg-color-rgb: 202, 203, 204; + --sand-alert-overlay-text-color-rgb: 46, 50, 57; + --sand-alert-overlay-text-sub-color: #2E3239; + --sand-alert-overlay-focus-text-color: #575E66; + --sand-alert-overlay-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-disabled-selected-bg-color: #788688; + --sand-alert-overlay-disabled-selected-focus-color: ${focusBackgroundColor}; + --sand-alert-overlay-disabled-selected-focus-bg-color: #4C5059; + --sand-alert-overlay-progress-color-rgb: 107, 109, 115; + --sand-alert-overlay-progress-bg-color-rgb: 161, 161, 161; + --sand-alert-overlay-checkbox-color: #858B92; + --sand-alert-overlay-checkbox-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-formcheckboxitem-focus-text-color: #575E66; + --sand-alert-overlay-item-disabled-focus-bg-color: #989CA2; + }`; + case 'purpleColorSet1': + return `.sandstone-theme { + /* Skin Name: Purple 1; */ + --sand-bg-color: ${backgroundColor}; + --sand-text-color-rgb: ${tRGB}; + --sand-text-sub-color: ${subTextColor}; + --sand-shadow-color-rgb: 0, 0, 0; + --sand-component-text-color-rgb: ${tRGB}; + --sand-component-text-sub-color-rgb: ${stRGB}; + --sand-component-bg-color: ${componentBackgroundColor}; + --sand-component-active-indicator-bg-color: ${focusBackgroundColor}; + --sand-component-inactive-indicator-bg-color: #9DA2A7; + --sand-focus-text-color: #303030; + --sand-focus-bg-color-rgb: ${fbgRGB}; + --sand-component-focus-text-color-rgb: 51, 51, 51; + --sand-component-focus-active-indicator-bg-color: #4C5059; + --sand-component-focus-inactive-indicator-bg-color: #B8B9BB; + --sand-selected-color-rgb: ${tRGB}; + --sand-selected-text-color: #E6E6E6; + --sand-selected-bg-color: #75518E; + --sand-disabled-focus-bg-color: ${subTextColor}; + --sand-disabled-selected-color: #4C5059; + --sand-disabled-selected-bg-color: #E7E7E7; + --sand-disabled-selected-focus-color: #E7E7E7; + --sand-disabled-selected-focus-bg-color: #4C5059; + --sand-fullscreen-bg-color: #000000; + --sand-overlay-bg-color-rgb: ${pbgRGB}; + --sand-selection-color: #4C5059; + --sand-selection-bg-color: #3399FF; + --sand-toggle-off-color: #AEAEAE; + --sand-toggle-off-bg-color: #494949; + --sand-toggle-on-color: ${focusBackgroundColor}; + --sand-toggle-on-bg-color: #755183; + --sand-progress-color-rgb: ${tRGB}; + --sand-progress-buffer-color: #6B6D73; + --sand-progress-bg-color-rgb: 55, 58, 65; + --sand-progress-highlighted-color: #FFFFFF; + --sand-progress-slider-color: #8D9298; + --sand-spinner-color-rgb: 255, 255, 255; + --sand-checkbox-color: ${focusBackgroundColor}; + --sand-item-disabled-focus-bg-color: #E6E6E6; + --sand-keyguide-bg-color-rgb: 107, 109, 115; + --sand-slider-disabled-knob-bg-color: #666666; + --sand-alert-overlay-bg-color-rgb: 107, 109, 115; + --sand-alert-overlay-text-color-rgb: 46, 50, 57; + --sand-alert-overlay-text-sub-color: #2E3239; + --sand-alert-overlay-focus-text-color: #575E66; + --sand-alert-overlay-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-disabled-selected-bg-color: #788688; + --sand-alert-overlay-disabled-selected-focus-color: ${focusBackgroundColor}; + --sand-alert-overlay-disabled-selected-focus-bg-color: #4C5059; + --sand-alert-overlay-progress-color-rgb: 107, 109, 115; + --sand-alert-overlay-progress-bg-color-rgb: 161, 161, 161; + --sand-alert-overlay-checkbox-color: #858B92; + --sand-alert-overlay-checkbox-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-formcheckboxitem-focus-text-color: #575E66; + --sand-alert-overlay-item-disabled-focus-bg-color: #989CA2; + }`; + case 'purpleColorSet2': + return `.sandstone-theme { + /* Skin Name: Purple 2; */ + --sand-bg-color: ${backgroundColor}; + --sand-text-color-rgb: ${tRGB}; + --sand-text-sub-color: ${subTextColor}; + --sand-shadow-color-rgb: 0, 0, 0; + --sand-component-text-color-rgb: ${tRGB}; + --sand-component-text-sub-color-rgb: 171, 174, 179; + --sand-component-bg-color: ${componentBackgroundColor}; + --sand-component-active-indicator-bg-color: ${focusBackgroundColor}; + --sand-component-inactive-indicator-bg-color: #9DA2A7; + --sand-focus-text-color: #FFFFFF; + --sand-focus-bg-color-rgb: ${fbgRGB}; + --sand-component-focus-text-color-rgb: 77, 25, 142; + --sand-component-focus-active-indicator-bg-color: #4C5059; + --sand-component-focus-inactive-indicator-bg-color: #B8B9BB; + --sand-selected-color-rgb: ${tRGB}; + --sand-selected-text-color: #E6E6E6; + --sand-selected-bg-color: #76618E; + --sand-disabled-focus-bg-color: #ABAEB3; + --sand-disabled-selected-color: #4C5059; + --sand-disabled-selected-bg-color: #E7E7E7; + --sand-disabled-selected-focus-color: #E7E7E7; + --sand-disabled-selected-focus-bg-color: #4C5059; + --sand-fullscreen-bg-color: #000000; + --sand-overlay-bg-color-rgb: ${pbgRGB}; + --sand-selection-color: #4C5059; + --sand-selection-bg-color: #3399FF; + --sand-toggle-off-color: #80778C; + --sand-toggle-off-bg-color: #54416C; + --sand-toggle-on-color: ${focusBackgroundColor}; + --sand-toggle-on-bg-color: #8A75A2; + --sand-progress-color-rgb: ${tRGB}; + --sand-progress-buffer-color: #6B6D73; + --sand-progress-bg-color-rgb: 55, 58, 65; + --sand-progress-highlighted-color: #FFFFFF; + --sand-progress-slider-color: #8D9298; + --sand-spinner-color-rgb: 255, 255, 255; + --sand-checkbox-color: ${focusBackgroundColor}; + --sand-item-disabled-focus-bg-color: #E6E6E6; + --sand-keyguide-bg-color-rgb: 107, 109, 115; + --sand-slider-disabled-knob-bg-color: #666666; + --sand-alert-overlay-bg-color-rgb: 202, 203, 204; + --sand-alert-overlay-text-color-rgb: 46, 50, 57; + --sand-alert-overlay-text-sub-color: #2E3239; + --sand-alert-overlay-focus-text-color: #575E66; + --sand-alert-overlay-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-disabled-selected-bg-color: #788688; + --sand-alert-overlay-disabled-selected-focus-color: ${focusBackgroundColor}; + --sand-alert-overlay-disabled-selected-focus-bg-color: #4C5059; + --sand-alert-overlay-progress-color-rgb: 107, 109, 115; + --sand-alert-overlay-progress-bg-color-rgb: 161, 161, 161; + --sand-alert-overlay-checkbox-color: #858B92; + --sand-alert-overlay-checkbox-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-formcheckboxitem-focus-text-color: #575E66; + --sand-alert-overlay-item-disabled-focus-bg-color: #989CA2; + }`; + case 'redColorSet1': + return `.sandstone-theme { + /* Skin Name: Red 1; */ + --sand-bg-color: ${backgroundColor}; + --sand-text-color-rgb: ${tRGB}; + --sand-text-sub-color: ${subTextColor}; + --sand-shadow-color-rgb: 0, 0, 0; + --sand-component-text-color-rgb: ${tRGB}; + --sand-component-text-sub-color-rgb: ${stRGB}; + --sand-component-bg-color: ${componentBackgroundColor}; + --sand-component-active-indicator-bg-color: ${focusBackgroundColor}; + --sand-component-inactive-indicator-bg-color: #9DA2A7; + --sand-focus-text-color: #303030; + --sand-focus-bg-color-rgb: ${fbgRGB}; + --sand-component-focus-text-color-rgb: 51, 51, 51; + --sand-component-focus-active-indicator-bg-color: #4C5059; + --sand-component-focus-inactive-indicator-bg-color: #B8B9BB; + --sand-selected-color-rgb: ${tRGB}; + --sand-selected-text-color: #E6E6E6; + --sand-selected-bg-color: #8E6161; + --sand-disabled-focus-bg-color: ${subTextColor}; + --sand-disabled-selected-color: #4C5059; + --sand-disabled-selected-bg-color: #E7E7E7; + --sand-disabled-selected-focus-color: #E7E7E7; + --sand-disabled-selected-focus-bg-color: #4C5059; + --sand-fullscreen-bg-color: #000000; + --sand-overlay-bg-color-rgb: ${pbgRGB}; + --sand-selection-color: #4C5059; + --sand-selection-bg-color: #3399FF; + --sand-toggle-off-color: #AEAEAE; + --sand-toggle-off-bg-color: #494949; + --sand-toggle-on-color: ${focusBackgroundColor}; + --sand-toggle-on-bg-color: #8E6161; + --sand-progress-color-rgb: ${tRGB}; + --sand-progress-buffer-color: #6B6D73; + --sand-progress-bg-color-rgb: 55, 58, 65; + --sand-progress-highlighted-color: #FFFFFF; + --sand-progress-slider-color: #8D9298; + --sand-spinner-color-rgb: 255, 255, 255; + --sand-checkbox-color: ${focusBackgroundColor}; + --sand-item-disabled-focus-bg-color: #E6E6E6; + --sand-keyguide-bg-color-rgb: 107, 109, 115; + --sand-slider-disabled-knob-bg-color: #666666; + --sand-alert-overlay-bg-color-rgb: 202, 203, 204; + --sand-alert-overlay-text-color-rgb: 46, 50, 57; + --sand-alert-overlay-text-sub-color: #2E3239; + --sand-alert-overlay-focus-text-color: #575E66; + --sand-alert-overlay-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-disabled-selected-bg-color: #788688; + --sand-alert-overlay-disabled-selected-focus-color: ${focusBackgroundColor}; + --sand-alert-overlay-disabled-selected-focus-bg-color: #4C5059; + --sand-alert-overlay-progress-color-rgb: 107, 109, 115; + --sand-alert-overlay-progress-bg-color-rgb: 161, 161, 161; + --sand-alert-overlay-checkbox-color: #858B92; + --sand-alert-overlay-checkbox-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-formcheckboxitem-focus-text-color: #575E66; + --sand-alert-overlay-item-disabled-focus-bg-color: #989CA2; + }`; + case 'redColorSet2': + return `.sandstone-theme { + /* Skin Name: Red 2; */ + --sand-bg-color: ${backgroundColor}; + --sand-text-color-rgb: ${tRGB}; + --sand-text-sub-color: ${subTextColor}; + --sand-shadow-color-rgb: 0, 0, 0; + --sand-component-text-color-rgb: ${tRGB}; + --sand-component-text-sub-color-rgb: 171, 174, 179; + --sand-component-bg-color: ${componentBackgroundColor}; + --sand-component-active-indicator-bg-color: ${focusBackgroundColor}; + --sand-component-inactive-indicator-bg-color: #9DA2A7; + --sand-focus-text-color: #851919; + --sand-focus-bg-color-rgb: ${fbgRGB}; + --sand-component-focus-text-color-rgb: 132, 31, 31; + --sand-component-focus-active-indicator-bg-color: #4C5059; + --sand-component-focus-inactive-indicator-bg-color: #B8B9BB; + --sand-selected-color-rgb: ${tRGB}; + --sand-selected-text-color: #E6E6E6; + --sand-selected-bg-color: #8E6161; + --sand-disabled-focus-bg-color: #ABAEB3; + --sand-disabled-selected-color: #4C5059; + --sand-disabled-selected-bg-color: #E7E7E7; + --sand-disabled-selected-focus-color: #E7E7E7; + --sand-disabled-selected-focus-bg-color: #4C5059; + --sand-fullscreen-bg-color: #000000; + --sand-overlay-bg-color-rgb: ${pbgRGB}; + --sand-selection-color: #4C5059; + --sand-selection-bg-color: #3399FF; + --sand-toggle-off-color: #927A7A; + --sand-toggle-off-bg-color: #784747; + --sand-toggle-on-color: ${focusBackgroundColor}; + --sand-toggle-on-bg-color: #BB7D7D; + --sand-progress-color-rgb: ${tRGB}; + --sand-progress-buffer-color: #6B6D73; + --sand-progress-bg-color-rgb: 55, 58, 65; + --sand-progress-highlighted-color: #FFFFFF; + --sand-progress-slider-color: #8D9298; + --sand-spinner-color-rgb: 255, 255, 255; + --sand-checkbox-color: ${focusBackgroundColor}; + --sand-item-disabled-focus-bg-color: #E6E6E6; + --sand-keyguide-bg-color-rgb: 107, 109, 115; + --sand-slider-disabled-knob-bg-color: #666666; + --sand-alert-overlay-bg-color-rgb: 202, 203, 204; + --sand-alert-overlay-text-color-rgb: 46, 50, 57; + --sand-alert-overlay-text-sub-color: #2E3239; + --sand-alert-overlay-focus-text-color: #575E66; + --sand-alert-overlay-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-disabled-selected-bg-color: #788688; + --sand-alert-overlay-disabled-selected-focus-color: ${focusBackgroundColor}; + --sand-alert-overlay-disabled-selected-focus-bg-color: #4C5059; + --sand-alert-overlay-progress-color-rgb: 107, 109, 115; + --sand-alert-overlay-progress-bg-color-rgb: 161, 161, 161; + --sand-alert-overlay-checkbox-color: #858B92; + --sand-alert-overlay-checkbox-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-formcheckboxitem-focus-text-color: #575E66; + --sand-alert-overlay-item-disabled-focus-bg-color: #989CA2; + }`; + default: + return `.sandstone-theme { + /* Skin Name: Default; */ + --sand-bg-color: ${backgroundColor}; + --sand-text-color-rgb: ${tRGB}; + --sand-text-sub-color: ${subTextColor}; + --sand-shadow-color-rgb: 0, 0, 0; + --sand-component-text-color-rgb: ${tRGB}; + --sand-component-text-sub-color-rgb: ${stRGB}; + --sand-component-bg-color: ${componentBackgroundColor}; + --sand-component-active-indicator-bg-color: ${focusBackgroundColor}; + --sand-component-inactive-indicator-bg-color: #9DA2A7; + --sand-focus-text-color: #FFFFFF; + --sand-focus-bg-color-rgb: ${fbgRGB}; + --sand-component-focus-text-color-rgb: 76, 80, 89; + --sand-component-focus-active-indicator-bg-color: #4C5059; + --sand-component-focus-inactive-indicator-bg-color: #B8B9BB; + --sand-selected-color-rgb: ${tRGB}; + --sand-selected-text-color: #E6E6E6; + --sand-selected-bg-color: #3E454D; + --sand-disabled-focus-bg-color: ${subTextColor}; + --sand-disabled-selected-color: #4C5059; + --sand-disabled-selected-bg-color: #E6E6E6; + --sand-disabled-selected-focus-color: #E6E6E6; + --sand-disabled-selected-focus-bg-color: #4C5059; + --sand-fullscreen-bg-color: #000000; + --sand-overlay-bg-color-rgb: ${pbgRGB}; + --sand-selection-color: #4C5059; + --sand-selection-bg-color: #3399FF; + --sand-toggle-off-color: #AEAEAE; + --sand-toggle-off-bg-color: #777777; + --sand-toggle-on-color: ${focusBackgroundColor}; + --sand-toggle-on-bg-color: #30AD6B; + --sand-progress-color-rgb: ${tRGB}; + --sand-progress-buffer-color: #6B6D73; + --sand-progress-bg-color-rgb: 55, 58, 65; + --sand-progress-highlighted-color: #FFFFFF; + --sand-progress-slider-color: #8D9298; + --sand-spinner-color-rgb: 255, 255, 255; + --sand-checkbox-color: ${focusBackgroundColor}; + --sand-item-disabled-focus-bg-color: #E6E6E6; + --sand-keyguide-bg-color-rgb: 55, 58, 65; + --sand-slider-disabled-knob-bg-color: #666666; + --sand-alert-overlay-bg-color-rgb: 202, 203, 204; + --sand-alert-overlay-text-color-rgb: 46, 50, 57; + --sand-alert-overlay-text-sub-color: #2E3239; + --sand-alert-overlay-focus-text-color: #575E66; + --sand-alert-overlay-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-disabled-selected-bg-color: #788688; + --sand-alert-overlay-disabled-selected-focus-color: ${focusBackgroundColor}; + --sand-alert-overlay-disabled-selected-focus-bg-color: #4C5059; + --sand-alert-overlay-progress-color-rgb: 55, 58, 65; + --sand-alert-overlay-progress-bg-color-rgb: 161, 161, 161; + --sand-alert-overlay-checkbox-color: #858B92; + --sand-alert-overlay-checkbox-disabled-selected-color: #FFFFFF; + --sand-alert-overlay-formcheckboxitem-focus-text-color: #575E66; + --sand-alert-overlay-item-disabled-focus-bg-color: #989CA2; + }`; + } +}; diff --git a/sandstone/pattern-ls2request-custom-colors/src/hooks/package.json b/sandstone/pattern-ls2request-custom-colors/src/hooks/package.json new file mode 100644 index 000000000..0905a9472 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/hooks/package.json @@ -0,0 +1,3 @@ +{ + "main": "dynamicColor.js" +} diff --git a/sandstone/pattern-ls2request-custom-colors/src/hooks/useDynamicColor.js b/sandstone/pattern-ls2request-custom-colors/src/hooks/useDynamicColor.js new file mode 100644 index 000000000..ec6d909ba --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/hooks/useDynamicColor.js @@ -0,0 +1,100 @@ +import {useContext, useEffect, useState} from 'react'; +import {generateStylesheet} from './generateStylesheet'; +import {useLinearColor} from './useLinearColor'; +import {generateTimestamps, getIndex} from './utils'; + +import {AppContext} from '../constants'; + +let fakeIndex = 0; +let timestamps = generateTimestamps(5); + +const useLinearSkinColor = () => { + const fakeTimeEnabled = true; + const [linearSkinVariants, setLinearSkinVariants] = useState('neutral'); + const {dynamicColor: enableLinearSkin, handleSkin: skinVariants, activeTheme: preset, backgroundColor, componentBackgroundColor, focusBackgroundColor, popupBackgroundColor, subtitleTextColor, textColor, colors} = useContext(AppContext).context; + const [linearBackgroundColor, setLinearBackgroundColor] = useLinearColor(backgroundColor); + const [linearComponentBackgroundColor, setLinearComponentBackgroundColor] = useLinearColor(componentBackgroundColor); + const [linearFocusBackgroundColor, setLinearFocusBackgroundColor] = useLinearColor(focusBackgroundColor); + const [linearPopupBackgroundColor, setLinearPopupBackgroundColor] = useLinearColor(popupBackgroundColor); + const [linearSubTextColor, setLinearSubTextColor] = useLinearColor(subtitleTextColor); + const [linearTextColor, setLinearTextColor] = useLinearColor(textColor); + + useEffect(() => { + // If linear skin is not enabled we skip this useEffect's content + if (enableLinearSkin !== 'on') return; + + // Change color luminosity and saturation at a given interval (0.5s if fakeTime is enabled, 30s if it is disabled) + let changeColor = setInterval(() => { + // Get index depending on timestamp + const index = getIndex(); + if (!fakeTimeEnabled) { + if (skinVariants === 'on') { + // Set skin variant based on timestamp + if (index >= '05:00' && index < '17:00') { + setLinearSkinVariants('neutral'); + } else { + setLinearSkinVariants('light'); + } + } + + // Set colors from the generated colors array at a specific index depending on timestamp + setLinearBackgroundColor(index); + setLinearComponentBackgroundColor(index); + setLinearFocusBackgroundColor(index); + setLinearPopupBackgroundColor(index); + setLinearSubTextColor(index); + setLinearTextColor(index); + } else { + if (skinVariants === 'on') { + // Set skin variant based on timestamp + // The reason we chose the values 60 and 203 is that each increase in fakeIndex represents 5 minutes + // This way the skin changes coincides with '05:00' and '17:00' + if (60 <= fakeIndex && fakeIndex <= 203) { + setLinearSkinVariants('neutral'); + } else { + setLinearSkinVariants('light'); + } + } + + // Set colors from the generated colors array at a specific index depending on timestamp + setLinearBackgroundColor(timestamps[fakeIndex]); + setLinearComponentBackgroundColor(timestamps[fakeIndex]); + setLinearFocusBackgroundColor(timestamps[fakeIndex]); + setLinearPopupBackgroundColor(timestamps[fakeIndex]); + setLinearSubTextColor(timestamps[fakeIndex]); + setLinearTextColor(timestamps[fakeIndex]); + + // The reason we chose the value 287 is that each increase in fakeIndex represents 5 minutes + // This way from 0 to 287 we have the time interval between '00:00' to '23:55' + if (fakeIndex < 287) { + fakeIndex++; + } else { + fakeIndex = 0; + } + } + }, fakeTimeEnabled ? 500 : 30 * 1000); + return () => { + clearInterval(changeColor); + }; + }, [enableLinearSkin, fakeTimeEnabled, setLinearBackgroundColor, setLinearComponentBackgroundColor, setLinearFocusBackgroundColor, setLinearPopupBackgroundColor, setLinearSubTextColor, setLinearTextColor, skinVariants]); + + useEffect(() => { + // Appends a stylesheet containing the generated colors + if (typeof document !== 'undefined') { + document.getElementById('custom-skin')?.remove(); + const root = document.getElementById('root'); + const sheet = document.createElement('style'); + sheet.id = 'custom-skin'; + if (enableLinearSkin === 'on') { + sheet.innerHTML = generateStylesheet(linearBackgroundColor, linearComponentBackgroundColor, linearFocusBackgroundColor, linearPopupBackgroundColor, linearSubTextColor, linearTextColor, preset); + } else { + sheet.innerHTML = colors; + } + root.appendChild(sheet); + } + }, [colors, enableLinearSkin, linearBackgroundColor, linearComponentBackgroundColor, linearFocusBackgroundColor, linearPopupBackgroundColor, linearSubTextColor, linearTextColor, preset]); + + return [skinVariants === 'on', linearSkinVariants]; +}; + +export default useLinearSkinColor; diff --git a/sandstone/pattern-ls2request-custom-colors/src/hooks/useLinearColor.js b/sandstone/pattern-ls2request-custom-colors/src/hooks/useLinearColor.js new file mode 100644 index 000000000..ab9d994a2 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/hooks/useLinearColor.js @@ -0,0 +1,20 @@ +import {useCallback, useMemo, useState} from 'react'; + +import {generateColorObject, generateColors} from './utils'; + +// This hook manages a dynamic color +export const useLinearColor = (color) => { + const [linearColor, setLinearColor] = useState(color); + // Generate an array of colors from an initial selected color + const colors = useMemo(() => { + return generateColorObject(generateColors(color)); + }, [color]); + + // Change color with a different one from the generated array + const setNewColor = useCallback((index) => { + setLinearColor(colors[index]); + }, [colors]); + + // Return the current color and the setter function + return [linearColor, setNewColor]; +}; diff --git a/sandstone/pattern-ls2request-custom-colors/src/hooks/utils.js b/sandstone/pattern-ls2request-custom-colors/src/hooks/utils.js new file mode 100644 index 000000000..a3c941b08 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/hooks/utils.js @@ -0,0 +1,335 @@ +import LS2Request from '@enact/webos/LS2Request'; +import {generateStylesheet} from './generateStylesheet'; + +// set `theme` key when presets or colors are changed +export const changeSettings = (params) => { + return new Promise((resolve) => { + new LS2Request().send({ + service: 'luna://com.webos.service.settings/', + method: 'setSystemSettings', + parameters: params, + onSuccess: (res) => { + // eslint-disable-next-line no-console + console.log('setSystemSettings onSuccess', params); + resolve(res); + } + }); + }); +}; + +export const hexToHSL = (hex) => { + // Convert hex to RGB first + let r = 0, g = 0, b = 0; + if (hex.length === 4) { + r = parseInt(hex[1] + hex[1], 16); + g = parseInt(hex[2] + hex[2], 16); + b = parseInt(hex[3] + hex[3], 16); + } else if (hex.length === 7) { + r = parseInt(hex.slice(1, 3), 16); + g = parseInt(hex.slice(3, 5), 16); + b = parseInt(hex.slice(5), 16); + } + // Then convert RGB to HSL + r /= 255; + g /= 255; + b /= 255; + let cmin = Math.min(r, g, b), + cmax = Math.max(r, g, b), + delta = cmax - cmin, + h, s, l; + if (delta === 0) { + h = 0; + } else if (cmax === r) { + h = ((g - b) / delta) % 6; + } else if (cmax === g) { + h = (b - r) / delta + 2; + } else { + h = (r - g) / delta + 4; + } + h = Math.round(h * 60); + if (h < 0) { + h += 360; + } + l = (cmax + cmin) / 2; + s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)); + s = +(s * 100).toFixed(1); + l = +(l * 100).toFixed(1); + return {h: Math.round(h), s: Math.round(s), l: Math.round(l)}; +}; + +export const HSLToHex = ({h, s, l}) => { + s /= 100; + l /= 100; + let c = (1 - Math.abs(2 * l - 1)) * s, + x = c * (1 - Math.abs((h / 60) % 2 - 1)), + m = l - c / 2, + r = 0, + g = 0, + b = 0; + if (0 <= h && h < 60) { + r = c; g = x; b = 0; + } else if (60 <= h && h < 120) { + r = x; g = c; b = 0; + } else if (120 <= h && h < 180) { + r = 0; g = c; b = x; + } else if (180 <= h && h < 240) { + r = 0; g = x; b = c; + } else if (240 <= h && h < 300) { + r = x; g = 0; b = c; + } else if (300 <= h && h < 360) { + r = c; g = 0; b = x; + } + // Having obtained RGB, convert channels to hex + r = Math.round((r + m) * 255).toString(16); + g = Math.round((g + m) * 255).toString(16); + b = Math.round((b + m) * 255).toString(16); + // Prepend 0s, if necessary + if (r.length === 1) { + r = "0" + r; + } + if (g.length === 1) { + g = "0" + g; + } + if (b.length === 1) { + b = "0" + b; + } + return "#" + r + g + b; +}; + +const generateColorsDayMode = (baseColor, numColors) => { + // Create an array to hold the colors + let colors = [baseColor]; + // Calculate the step size for increasing saturation and luminosity + let step = 0.02; + // Loop through the number of colors requested + for (let i = 0; i < numColors - 1; i++) { + // Convert the base color to HSL format + const currentColor = hexToHSL(colors[i]); + // Calculate the saturation for this color + let luminosity, + saturation; + if (i % 2) { + luminosity = currentColor.l - i / 2 * step; + saturation = currentColor.s; + } else { + luminosity = currentColor.l; + saturation = currentColor.s + i / 2 * step; + } + let hslColor; + // Create the color in HSL format + if (saturation <= 100 && luminosity >= 40) { + hslColor = {h: currentColor.h, s: saturation, l: luminosity}; + } else if (saturation > 100 && luminosity >= 40) { + hslColor = {h: currentColor.h, s: 100, l: luminosity}; + } else if (saturation <= 100 && luminosity < 40) { + hslColor = {h: currentColor.h, s: saturation, l: 40}; + } else if (saturation > 100 && luminosity < 40) { + hslColor = {h: currentColor.h, s: 100, l: 40}; + } + // Convert the color back to hex format and add it to the array + let hexColor = HSLToHex(hslColor); + colors.push(hexColor); + } + return colors; +}; + +const generateColorsNightMode = (baseColor, numColors) => { + // Create an array to hold the colors + let colors = [baseColor]; + // Calculate the step size for increasing saturation and luminosity + let step = 0.03; + // Loop through the number of colors requested + for (let i = 0; i < numColors - 1; i++) { + // Convert the base color to HSL format + const currentColor = hexToHSL(colors[i]); + // Calculate the saturation for this color + let luminosity, + saturation; + if (i % 2) { + luminosity = currentColor.l + i / 2 * step; + saturation = currentColor.s; + } else { + luminosity = currentColor.l; + saturation = currentColor.s - i / 2 * step; + } + let hslColor; + // Create the color in HSL format + if (saturation >= 30 && luminosity <= 65) { + hslColor = {h: currentColor.h, s: saturation, l: luminosity}; + } else if (saturation < 30 && luminosity <= 65) { + hslColor = {h: currentColor.h, s: 30, l: luminosity}; + } else if (saturation >= 30 && luminosity > 65) { + hslColor = {h: currentColor.h, s: saturation, l: 65}; + } else if (saturation < 30 && luminosity > 65) { + hslColor = {h: currentColor.h, s: 30, l: 65}; + } + // Convert the color back to hex format and add it to the array + let hexColor = HSLToHex(hslColor); + colors.push(hexColor); + } + return colors; +}; + +export const generateTimestamps = (step) => { + // Generates an array of timestamps based on a specific step + // e.g. for (step = 5) => ['00:00', '00:05', '00:10', ..., '23:55'] + const timestamps = []; + for (let hours = 0; hours < 24; hours++) { + for (let minutes = 0; minutes < 60; minutes += step) { + const formattedHours = hours.toString().padStart(2, '0'); + const formattedMinutes = minutes.toString().padStart(2, '0'); + const timestamp = `${formattedHours}:${formattedMinutes}`; + timestamps.push(timestamp); + } + } + return timestamps; +}; + +export const generateColors = (color) => { + // Returns an array of colors, containing 144 colors for day mode and 144 for night mode + const dayColorsArray = generateColorsDayMode(color, 72); + const nightColorsArray = generateColorsNightMode(color, 72); + const array = [...nightColorsArray.reverse(), ...dayColorsArray, ...dayColorsArray.reverse(), ...nightColorsArray.reverse()]; + const offset = array.splice(0, 12); + return [...array, ...offset]; +}; + +export const generateColorObject = (colorArray) => { + // Returns an object with timestamps for keys and colors for values + // (e.g. "03:05": "#e6e6e6") + const timestamps = generateTimestamps(5); + return timestamps.map((element, index) => { + return {key: element, value: colorArray[index]}; + }).reduce((prev, curr) => { + prev[curr.key] = curr.value; + return prev; + }, {}); +}; + +export const getIndex = () => { + // Creates an index from a timestamp + let minute = parseInt(new Date().toTimeString().substring(0, 5).slice(3)); + let hour = parseInt(new Date().toTimeString().substring(0, 8)); + let index; + while (minute % 5 !== 0) minute++; + if (minute >= 60) { + minute = 0; + hour++; + } + if (hour > 24) { + hour = 1; + } + if (hour < 10) { + index = '0' + hour + ':'; + } else { + index = hour + ':'; + } + if (minute < 10) { + index = index + '0' + minute; + } else { + index = index + minute; + } + return index; +}; + +export const hexToRGB = (hex) => { + // Converts a HEX color into an RGB one + let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? [ + parseInt(result[1], 16), + parseInt(result[2], 16), + parseInt(result[3], 16) + ] : null; +}; + +export const setPreset = ({preset, context}) => { + // Changes the preset and default colors from context + const newContext = Object.assign({}, context); + newContext.activeTheme = preset; + + switch (preset) { + case 'blueColorSet2': + newContext.backgroundColor = '#181E3D'; + newContext.componentBackgroundColor = '#7D848C'; + newContext.focusBackgroundColor = '#E6E6E6'; + newContext.popupBackgroundColor = '#1E233F'; + newContext.subtitleTextColor = '#ABAEB3'; + newContext.textColor = '#E6E6E6'; + break; + case 'blueColorSet1': + newContext.backgroundColor = '#272829'; + newContext.componentBackgroundColor = '#7D848C'; + newContext.focusBackgroundColor = '#E6E6E6'; + newContext.popupBackgroundColor = '#292929'; + newContext.subtitleTextColor = '#ABAEB3'; + newContext.textColor = '#E6E6E6'; + break; + case 'greenColorSet2': + newContext.backgroundColor = '#102933'; + newContext.componentBackgroundColor = '#7D848C'; + newContext.focusBackgroundColor = '#E6E6E6'; + newContext.popupBackgroundColor = '#172D36'; + newContext.subtitleTextColor = '#ABAEB3'; + newContext.textColor = '#E6E6E6'; + break; + case 'greenColorSet1': + newContext.backgroundColor = '#272829'; + newContext.componentBackgroundColor = '#7D848C'; + newContext.focusBackgroundColor = '#E6E6E6'; + newContext.popupBackgroundColor = '#292929'; + newContext.subtitleTextColor = '#ABAEB3'; + newContext.textColor = '#E6E6E6'; + break; + case 'purpleColorSet2': + newContext.backgroundColor = '#2B1941'; + newContext.componentBackgroundColor = '#7D848C'; + newContext.focusBackgroundColor = '#E6E6E6'; + newContext.popupBackgroundColor = '#2F1F43'; + newContext.subtitleTextColor = '#848290'; + newContext.textColor = '#E6E6E6'; + break; + case 'purpleColorSet1': + newContext.backgroundColor = '#272829'; + newContext.componentBackgroundColor = '#7D848C'; + newContext.focusBackgroundColor = '#E6E6E6'; + newContext.popupBackgroundColor = '#292929'; + newContext.subtitleTextColor = '#ABAEB3'; + newContext.textColor = '#E6E6E6'; + break; + case 'redColorSet2': + newContext.backgroundColor = '#3D1A1A'; + newContext.componentBackgroundColor = '#7D848C'; + newContext.focusBackgroundColor = '#E6E6E6'; + newContext.popupBackgroundColor = '#3F2020'; + newContext.subtitleTextColor = '#807477'; + newContext.textColor = '#E6E6E6'; + break; + case 'redColorSet1': + newContext.backgroundColor = '#252424'; + newContext.componentBackgroundColor = '#7D848C'; + newContext.focusBackgroundColor = '#E6E6E6'; + newContext.popupBackgroundColor = '#292929'; + newContext.subtitleTextColor = '#ABAEB3'; + newContext.textColor = '#E6E6E6'; + break; + default: + newContext.backgroundColor = '#000000'; + newContext.componentBackgroundColor = '#7D848C'; + newContext.focusBackgroundColor = '#E6E6E6'; + newContext.popupBackgroundColor = '#575E66'; + newContext.subtitleTextColor = '#ABAEB3'; + newContext.textColor = '#E6E6E6'; + break; + } + + newContext.colors = generateStylesheet( + newContext.backgroundColor, + newContext.componentBackgroundColor, + newContext.focusBackgroundColor, + newContext.popupBackgroundColor, + newContext.subtitleTextColor, + newContext.textColor, + preset + ); + return newContext; +}; diff --git a/sandstone/pattern-ls2request-custom-colors/src/index.js b/sandstone/pattern-ls2request-custom-colors/src/index.js new file mode 100644 index 000000000..eb163ed13 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/index.js @@ -0,0 +1,19 @@ +/* global ENACT_PACK_ISOMORPHIC */ +import {createRoot, hydrateRoot} from 'react-dom/client'; + +import App from './App'; + +const appElement = (); + +// In a browser environment, render instead of exporting +if (typeof window !== 'undefined') { + const container = document.getElementById('root'); + + if (ENACT_PACK_ISOMORPHIC) { + hydrateRoot(container, appElement); + } else { + createRoot(container).render(appElement); + } +} + +export default appElement; diff --git a/sandstone/pattern-ls2request-custom-colors/src/views/CustomizePanel/CustomizePanel.js b/sandstone/pattern-ls2request-custom-colors/src/views/CustomizePanel/CustomizePanel.js new file mode 100644 index 000000000..da2efb1a1 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/views/CustomizePanel/CustomizePanel.js @@ -0,0 +1,105 @@ +import {useCallback, useContext} from 'react'; +import Button from '@enact/sandstone/Button'; +import Scroller from '@enact/sandstone/Scroller'; +import {Cell, Layout} from '@enact/ui/Layout'; + +import {setPreset, changeSettings} from '../../hooks/utils'; +import {generateStylesheet} from '../../hooks/generateStylesheet'; +import ColorPicker from '../../components/ColorPicker'; +import PreviewSection from '../../components/PreviewSection'; +import {AppContext} from '../../constants'; + +import css from './CustomizePanel.module.less'; + +const CustomizePanel = () => { + const {context, setContext} = useContext(AppContext); + const {backgroundColor, componentBackgroundColor, focusBackgroundColor, popupBackgroundColor, subtitleTextColor, textColor} = context; + + const onChangeColor = useCallback((color, newColor) => { + // a copy of the context object is created + const newContext = Object.assign({}, context); + // update the color value on the newly created object with what gets received from `event` (handleBackgroundColor) + newContext[color] = newColor; + // generate the new stylesheet based on the updated color + newContext.colors = generateStylesheet( + newContext.backgroundColor, + newContext.componentBackgroundColor, + newContext.focusBackgroundColor, + newContext.popupBackgroundColor, + newContext.subtitleTextColor, + newContext.textColor, + newContext.preset + ); + // update the app context with the new context + setContext(newContext); + + // check if app is running on webOS environment and update the `theme` + if (typeof window === 'object' && window.webOSSystem && window.webOSSystem.launchParams) { + changeSettings({ + category: 'customUi', + settings: { + theme: JSON.stringify(newContext) + } + }); + } + }, [context, setContext]); + + const handleBackgroundColor = useCallback((ev) => { + onChangeColor('backgroundColor', ev); + }, [onChangeColor]); + + const handleComponentBackgroundColor = useCallback((ev) => { + onChangeColor('componentBackgroundColor', ev); + }, [onChangeColor]); + + const handleFocusBackgroundColor = useCallback((ev) => { + onChangeColor('focusBackgroundColor', ev); + }, [onChangeColor]); + + const handlePopupBackgroundColor = useCallback((ev) => { + onChangeColor('popupBackgroundColor', ev); + }, [onChangeColor]); + + const handleSubtitleTextColor = useCallback((ev) => { + onChangeColor('subtitleTextColor', ev); + }, [onChangeColor]); + + const handleTextColor = useCallback((ev) => { + onChangeColor('textColor', ev); + }, [onChangeColor]); + + const handleResetButton = useCallback(() => { + const newContext = setPreset({preset: context.activeTheme, context}); + setContext(newContext); + + if (typeof window === 'object' && window.webOSSystem && window.webOSSystem.launchParams) { + changeSettings({ + category: 'customUi', + settings: { + theme: JSON.stringify(newContext) + } + }); + } + }, [context, setContext]); + + return ( + + + + + + + + + + + + + + + + + ); +}; + +export default CustomizePanel; diff --git a/sandstone/pattern-ls2request-custom-colors/src/views/CustomizePanel/CustomizePanel.module.less b/sandstone/pattern-ls2request-custom-colors/src/views/CustomizePanel/CustomizePanel.module.less new file mode 100644 index 000000000..01326d3e6 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/views/CustomizePanel/CustomizePanel.module.less @@ -0,0 +1,40 @@ +// CustomizePanel.module.less +// +.customizePanel { + height: 100%; + + .customizeSection { + padding: 24px; + + .scroller { + --sand-focus-bg-color-rgb: 230, 230, 230; + --sand-progress-bg-color-rgb: 55, 58, 65; + --sand-progress-color-rgb: 230, 230, 230; + + .colorPicker { + color: #E6E6E6; + --sand-component-focus-text-color-rgb: 76, 80, 89; + --sand-component-text-color-rgb: 230, 230, 230; + --sand-focus-bg-color-rgb: 230, 230, 230; + --sand-progress-color-rgb: 230, 230, 230; + --sand-selected-bg-color: #3E454D; + --sand-selected-color-rgb: 230, 230, 230; + --sand-selected-text-color-rgb: 230, 230, 230; + --sand-text-color-rgb: 230, 230, 230; + --sand-toggle-off-color: #AEAEAE; + --sand-toggle-off-bg-color: #777777; + --sand-toggle-on-color: #E6E6E6; + --sand-toggle-on-bg-color: #30AD6B; + } + } + + .resetBtn { + width: fit-content; + align-self: flex-end; + --sand-component-bg-color: #7D848C; + --sand-component-focus-text-color-rgb: 66, 75, 90; + --sand-component-text-color-rgb: 230, 230, 230; + --sand-focus-bg-color-rgb: 230, 230, 230; + } + } +} diff --git a/sandstone/pattern-ls2request-custom-colors/src/views/CustomizePanel/package.json b/sandstone/pattern-ls2request-custom-colors/src/views/CustomizePanel/package.json new file mode 100644 index 000000000..679339d0b --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/views/CustomizePanel/package.json @@ -0,0 +1,3 @@ +{ + "main": "CustomizePanel.js" +} diff --git a/sandstone/pattern-ls2request-custom-colors/src/views/MainView/MainView.js b/sandstone/pattern-ls2request-custom-colors/src/views/MainView/MainView.js new file mode 100644 index 000000000..bf03b7b51 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/views/MainView/MainView.js @@ -0,0 +1,53 @@ +import IconItem from '@enact/sandstone/IconItem'; +import {Header, Panel, Panels} from '@enact/sandstone/Panels'; +import Spinner from '@enact/sandstone/Spinner'; +import {useCallback, useState} from 'react'; + +import CustomizePanel from '../CustomizePanel'; +import PresetPanel from '../PresetPanel'; + +import useLinearSkinColor from '../../hooks/useDynamicColor'; + +import css from './MainView.module.less'; + +const MainView = ({responseStatus, ...rest}) => { + const [applySkin, skin] = useLinearSkinColor(); + const [panelIndex, setPanelIndex] = useState(0); + + const forward = useCallback(() => { + setPanelIndex(panelIndex + 1); + }, [panelIndex]); + + const backward = useCallback(() => { + setPanelIndex(panelIndex - 1); + }, [panelIndex]); + + if (!responseStatus && typeof window === 'object' && window.webOSSystem && window.webOSSystem.launchParams) { + return (Loading...); + } else { + return ( + + +
+ + + +
+ +
+ +
+ + + + ); + } +}; +export default MainView; diff --git a/sandstone/pattern-ls2request-custom-colors/src/views/MainView/MainView.module.less b/sandstone/pattern-ls2request-custom-colors/src/views/MainView/MainView.module.less new file mode 100644 index 000000000..16a8a3216 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/views/MainView/MainView.module.less @@ -0,0 +1,11 @@ +// MainView.module.less +// +.mainView { + background-color: #1A1A1A; + + .panelHeader { + --sand-focus-bg-color-rgb: 230, 230, 230; + --sand-text-color-rgb: 230, 230, 230; + --sand-text-sub-color: #ABAEB3; + } +} diff --git a/sandstone/pattern-ls2request-custom-colors/src/views/MainView/package.json b/sandstone/pattern-ls2request-custom-colors/src/views/MainView/package.json new file mode 100644 index 000000000..6035fb17d --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/views/MainView/package.json @@ -0,0 +1,3 @@ +{ + "main": "MainView.js" +} diff --git a/sandstone/pattern-ls2request-custom-colors/src/views/PresetPanel/PresetPanel.js b/sandstone/pattern-ls2request-custom-colors/src/views/PresetPanel/PresetPanel.js new file mode 100644 index 000000000..aa657c325 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/views/PresetPanel/PresetPanel.js @@ -0,0 +1,89 @@ +import RadioItem from '@enact/sandstone/RadioItem'; +import Scroller from '@enact/sandstone/Scroller'; +import SwitchItem from '@enact/sandstone/SwitchItem'; +import {Cell, Column, Layout} from '@enact/ui/Layout'; +import {useCallback, useContext} from 'react'; + +import {changeSettings, setPreset} from '../../hooks/utils'; +import PreviewSection from '../../components/PreviewSection'; +import {AppContext, presets} from '../../constants'; + +import css from './PresetPanel.module.less'; + +const PresetPanel = () => { + const {context, setContext} = useContext(AppContext); + const {activeTheme, dynamicColor, handleSkin} = context; + + // update `theme` key with the stringified version of the context object + const updateThemeKey = (newContext) => { + return changeSettings({ + category: 'customUi', + settings: { + theme: JSON.stringify(newContext) + } + }); + } + + // Toggle using dynamic color mode which will modify the luminosity and saturation of your theme colors depending on the current time + const onClickDynamicColor = useCallback(() => { + // create a copy of the context object + const newContext = Object.assign({}, context); + // update the `dynamicColor` property on the new context object + newContext.dynamicColor = context.dynamicColor === 'on' ? 'off' : 'on'; + // update app context with the new context object + setContext(newContext); + + // check if app is running in webOS environment and update `theme` key + if (typeof window === 'object' && window.webOSSystem && window.webOSSystem.launchParams) { + updateThemeKey(newContext); + } + + }, [context, setContext]); + + // Toggle adjusting skin automatically, which means that the system will choose between Sandstone neutral and light modes according to the colors you have set + const onClickHandleSkin = useCallback(() => { + // create a copy of the context object + const newContext = Object.assign({}, context); + // update the `handleSkin` property on the new context object + newContext.handleSkin = context.handleSkin === 'on' ? 'off' : 'on'; + // update app context with the new context object + setContext(newContext); + + // check if app is running in webOS environment and update `theme` key + if (typeof window === 'object' && window.webOSSystem && window.webOSSystem.launchParams) { + updateThemeKey(newContext); + } + }, [context, setContext]); + + // Choose from an existing preset theme + const onClickHandlePreset = useCallback((ev) => { + // create a copy of the app context and set the colors for the selected preset + const newContext = setPreset({preset: ev.currentTarget.id, context: context}); + // update app context with the new context object + setContext(newContext); + + // check if app is running in webOS environment and update `theme` key + if (typeof window === 'object' && window.webOSSystem && window.webOSSystem.launchParams) { + updateThemeKey(newContext); + } + }, [context, setContext]); + + return ( + + + + + {Object.entries(presets).map(([key, value]) => + {value} + )} + + Activate dynamic color mode + Adjust skin automatically + + + + + ); +}; + +export default PresetPanel; diff --git a/sandstone/pattern-ls2request-custom-colors/src/views/PresetPanel/PresetPanel.module.less b/sandstone/pattern-ls2request-custom-colors/src/views/PresetPanel/PresetPanel.module.less new file mode 100644 index 000000000..9868fda54 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/views/PresetPanel/PresetPanel.module.less @@ -0,0 +1,32 @@ +// PresetPanel.module.less +// +.presetPanel { + height: 100%; + + .customizeSection { + padding: 24px; + + .scroller { + --sand-focus-bg-color-rgb: 230, 230, 230; + --sand-progress-bg-color-rgb: 55, 58, 65; + --sand-progress-color-rgb: 230, 230, 230; + } + + .radioItem, + .switchItem { + color: #E6E6E6; + --sand-component-focus-text-color-rgb: 76, 80, 89; + --sand-component-text-color-rgb: 230, 230, 230; + --sand-focus-bg-color-rgb: 230, 230, 230; + --sand-progress-color-rgb: 230, 230, 230; + --sand-selected-bg-color: #3E454D; + --sand-selected-color-rgb: 230, 230, 230; + --sand-selected-text-color-rgb: 230, 230, 230; + --sand-text-color-rgb: 230, 230, 230; + --sand-toggle-off-color: #AEAEAE; + --sand-toggle-off-bg-color: #777777; + --sand-toggle-on-color: #E6E6E6; + --sand-toggle-on-bg-color: #30AD6B; + } + } +} diff --git a/sandstone/pattern-ls2request-custom-colors/src/views/PresetPanel/package.json b/sandstone/pattern-ls2request-custom-colors/src/views/PresetPanel/package.json new file mode 100644 index 000000000..639c6c0c6 --- /dev/null +++ b/sandstone/pattern-ls2request-custom-colors/src/views/PresetPanel/package.json @@ -0,0 +1,3 @@ +{ + "main": "PresetPanel.js" +}