diff --git a/renderer/src/styles/ui/bdsettings.css b/renderer/src/styles/ui/bdsettings.css index 7662523c..15ca8320 100644 --- a/renderer/src/styles/ui/bdsettings.css +++ b/renderer/src/styles/ui/bdsettings.css @@ -48,6 +48,11 @@ transition: 150ms ease border-color; } +.bd-select.bd-select-disabled { + cursor: not-allowed; + opacity: 0.5; +} + .bd-select:hover, .bd-select.menu-open { border-color: var(--background-tertiary); @@ -123,7 +128,7 @@ .bd-setting-header label { font-weight: 500; - cursor: pointer; + /* cursor: pointer; */ overflow: hidden; word-wrap: break-word; font-size: 16px; diff --git a/renderer/src/styles/ui/colorpicker.css b/renderer/src/styles/ui/colorpicker.css index 24f240c0..b0b46aa2 100644 --- a/renderer/src/styles/ui/colorpicker.css +++ b/renderer/src/styles/ui/colorpicker.css @@ -2,6 +2,16 @@ display: flex; } +.bd-color-picker-container.bd-color-picker-disabled { + cursor: not-allowed; + opacity: 0.5; +} + +.bd-color-picker-container.bd-color-picker-disabled > .bd-color-picker-controls, +.bd-color-picker-container.bd-color-picker-disabled > .bd-color-picker-swatch { + pointer-events: none; +} + .bd-color-picker-controls { padding-left: 1px; padding-top: 2px; diff --git a/renderer/src/styles/ui/keybind.css b/renderer/src/styles/ui/keybind.css index 89a630a5..ae019e19 100644 --- a/renderer/src/styles/ui/keybind.css +++ b/renderer/src/styles/ui/keybind.css @@ -10,6 +10,15 @@ cursor: pointer; } +.bd-keybind-wrap.bd-keybind-disabled { + cursor: not-allowed; + opacity: 0.5; +} + +.bd-keybind-wrap.bd-keybind-disabled .bd-keybind-controls { + pointer-events: none; +} + .bd-keybind-wrap input { outline: none; border: none; diff --git a/renderer/src/styles/ui/number.css b/renderer/src/styles/ui/number.css index 60ca1f1a..6559deeb 100644 --- a/renderer/src/styles/ui/number.css +++ b/renderer/src/styles/ui/number.css @@ -1,16 +1,21 @@ -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - opacity: 0.5; -} - -.bd-number-input { - display: flex; - background-color: var(--deprecated-text-input-bg); - border: 1px solid var(--deprecated-text-input-border); - color: var(--text-normal); - font-size: 14px; - padding: 5px; - margin: 0; - border-radius: 3px; - width: 70px; +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + opacity: 0.5; +} + +.bd-number-input { + display: flex; + background-color: var(--deprecated-text-input-bg); + border: 1px solid var(--deprecated-text-input-border); + color: var(--text-normal); + font-size: 14px; + padding: 5px; + margin: 0; + border-radius: 3px; + width: 70px; +} + +.bd-number-input:disabled { + cursor: not-allowed; + opacity: 0.5; } \ No newline at end of file diff --git a/renderer/src/styles/ui/radio.css b/renderer/src/styles/ui/radio.css index bf23b332..6bfc2c6f 100644 --- a/renderer/src/styles/ui/radio.css +++ b/renderer/src/styles/ui/radio.css @@ -1,55 +1,64 @@ -.bd-radio-group { - min-width: 300px; -} - -.bd-radio-option { - display: flex; - align-items: center; - padding: 10px; - margin-bottom: 8px; - cursor: pointer; - user-select: none; - background-color: var(--background-secondary); - border-radius: 3px; - color: var(--interactive-normal); -} - -.bd-radio-option:hover { - background-color: var(--background-modifier-hover); -} - -.bd-radio-option.bd-radio-selected { - background-color: var(--background-modifier-selected); - color: var(--interactive-active); -} - -.bd-radio-option input { - position: absolute; - opacity: 0; - cursor: pointer; - height: 0; - width: 0; -} - -.bd-radio-icon { - margin-right: 10px; -} - -.bd-radio-label-wrap { - display: flex; - flex-direction: column; -} - -.bd-radio-label { - font-family: var(--font-primary); - font-size: 16px; - line-height: 20px; - font-weight: 500; -} - -.bd-radio-description { - font-family: var(--font-primary); - font-size: 14px; - line-height: 18px; - font-weight: 400; +.bd-radio-group { + min-width: 300px; +} + +.bd-radio-option { + display: flex; + align-items: center; + padding: 10px; + margin-bottom: 8px; + cursor: pointer; + user-select: none; + background-color: var(--background-secondary); + border-radius: 3px; + color: var(--interactive-normal); +} + +.bd-radio-group.bd-radio-disabled { + cursor: not-allowed; + opacity: 0.5; +} + +.bd-radio-group.bd-radio-disabled .bd-radio-option { + pointer-events: none; +} + +.bd-radio-option:hover { + background-color: var(--background-modifier-hover); +} + +.bd-radio-option.bd-radio-selected { + background-color: var(--background-modifier-selected); + color: var(--interactive-active); +} + +.bd-radio-option input { + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; + width: 0; +} + +.bd-radio-icon { + margin-right: 10px; +} + +.bd-radio-label-wrap { + display: flex; + flex-direction: column; +} + +.bd-radio-label { + font-family: var(--font-primary); + font-size: 16px; + line-height: 20px; + font-weight: 500; +} + +.bd-radio-description { + font-family: var(--font-primary); + font-size: 14px; + line-height: 18px; + font-weight: 400; } \ No newline at end of file diff --git a/renderer/src/styles/ui/slider.css b/renderer/src/styles/ui/slider.css index 90c8e4c2..99e1baaf 100644 --- a/renderer/src/styles/ui/slider.css +++ b/renderer/src/styles/ui/slider.css @@ -1,42 +1,51 @@ -.bd-slider-wrap { - display: flex; - color: var(--text-normal); - align-items: center; - } - - .bd-slider-label { - background: var(--brand-experiment); - font-weight: 700; - padding: 5px; - margin-right: 10px; - border-radius: 5px; - } - - .bd-slider-input { - /* -webkit-appearance: none; */ - height: 8px; - border-radius: 4px; - appearance: none; - min-width: 350px; - border-radius: 5px; - background: hsl(217,calc(var(--saturation-factor, 1)*7.6%),33.5%); - outline: none; - transition: opacity .2s; - background-image: linear-gradient(var(--brand-experiment), var(--brand-experiment)); - background-size: 70% 100%; - background-repeat: no-repeat; - } - - /* The slider handle (use -webkit- (Chrome, Opera, Safari, Edge) and -moz- (Firefox) to override default look) */ - .bd-slider-input::-webkit-slider-thumb { - appearance: none; - width: 10px; - height: 24px; - top: 50%; - border-radius: 3px; - background-color: hsl(0,calc(var(--saturation-factor, 1)*0%),100%); - border: 1px solid hsl(210,calc(var(--saturation-factor, 1)*2.9%),86.7%); - -webkit-box-shadow: 0 3px 1px 0 hsla(0,calc(var(--saturation-factor, 1)*0%),0%,.05),0 2px 2px 0 hsla(0,calc(var(--saturation-factor, 1)*0%),0%,.1),0 3px 3px 0 hsla(0,calc(var(--saturation-factor, 1)*0%),0%,.05); - box-shadow: 0 3px 1px 0 hsla(0,calc(var(--saturation-factor, 1)*0%),0%,.05),0 2px 2px 0 hsla(0,calc(var(--saturation-factor, 1)*0%),0%,.1),0 3px 3px 0 hsla(0,calc(var(--saturation-factor, 1)*0%),0%,.05); - cursor: ew-resize; +.bd-slider-wrap { + display: flex; + color: var(--text-normal); + align-items: center; +} + +.bd-slider-wrap.bd-slider-disabled { + cursor: not-allowed; + opacity: 0.5; +} + +.bd-slider-wrap.bd-slider-disabled .bd-slider-input { + pointer-events: none; +} + + .bd-slider-label { + background: var(--brand-experiment); + font-weight: 700; + padding: 5px; + margin-right: 10px; + border-radius: 5px; + } + + .bd-slider-input { + /* -webkit-appearance: none; */ + height: 8px; + border-radius: 4px; + appearance: none; + min-width: 350px; + border-radius: 5px; + background: hsl(217,calc(var(--saturation-factor, 1)*7.6%),33.5%); + outline: none; + transition: opacity .2s; + background-image: linear-gradient(var(--brand-experiment), var(--brand-experiment)); + background-size: 70% 100%; + background-repeat: no-repeat; + } + + /* The slider handle (use -webkit- (Chrome, Opera, Safari, Edge) and -moz- (Firefox) to override default look) */ + .bd-slider-input::-webkit-slider-thumb { + appearance: none; + width: 10px; + height: 24px; + top: 50%; + border-radius: 3px; + background-color: hsl(0,calc(var(--saturation-factor, 1)*0%),100%); + border: 1px solid hsl(210,calc(var(--saturation-factor, 1)*2.9%),86.7%); + -webkit-box-shadow: 0 3px 1px 0 hsla(0,calc(var(--saturation-factor, 1)*0%),0%,.05),0 2px 2px 0 hsla(0,calc(var(--saturation-factor, 1)*0%),0%,.1),0 3px 3px 0 hsla(0,calc(var(--saturation-factor, 1)*0%),0%,.05); + box-shadow: 0 3px 1px 0 hsla(0,calc(var(--saturation-factor, 1)*0%),0%,.05),0 2px 2px 0 hsla(0,calc(var(--saturation-factor, 1)*0%),0%,.1),0 3px 3px 0 hsla(0,calc(var(--saturation-factor, 1)*0%),0%,.05); + cursor: ew-resize; } \ No newline at end of file diff --git a/renderer/src/styles/ui/textbox.css b/renderer/src/styles/ui/textbox.css index a277a2e3..38266adf 100644 --- a/renderer/src/styles/ui/textbox.css +++ b/renderer/src/styles/ui/textbox.css @@ -1,11 +1,16 @@ -.bd-text-input { - min-width: 250px; - font-size: 16px; - box-sizing: border-box; - border-radius: 3px; - color: var(--text-normal); - background-color: var(--input-background); - border: none; - padding: 10px; - height: 40px; - } \ No newline at end of file +.bd-text-input { + min-width: 250px; + font-size: 16px; + box-sizing: border-box; + border-radius: 3px; + color: var(--text-normal); + background-color: var(--input-background); + border: none; + padding: 10px; + height: 40px; +} + +.bd-text-input:disabled { + cursor: not-allowed; + opacity: 0.5; +} \ No newline at end of file diff --git a/renderer/src/ui/settings/components/color.jsx b/renderer/src/ui/settings/components/color.jsx index b8e2418e..b655b9d7 100644 --- a/renderer/src/ui/settings/components/color.jsx +++ b/renderer/src/ui/settings/components/color.jsx @@ -57,15 +57,16 @@ const getContrastColor = (color) => { }; -export default function Color({value: initialValue, onChange, colors = defaultColors, defaultValue}) { +export default function Color({value: initialValue, onChange, colors = defaultColors, defaultValue, disabled}) { const [value, setValue] = useState(initialValue); const change = useCallback((e) => { + if (disabled) return; onChange?.(resolveColor(e.target.value)); setValue(e.target.value); - }, [onChange]); + }, [onChange, disabled]); const intValue = resolveColor(value, false); - return
+ return
{props => ( @@ -81,7 +82,7 @@ export default function Color({value: initialValue, onChange, colors = defaultCo {props => (
- +
)}
diff --git a/renderer/src/ui/settings/components/dropdown.jsx b/renderer/src/ui/settings/components/dropdown.jsx index 34ebad58..15d9e9eb 100644 --- a/renderer/src/ui/settings/components/dropdown.jsx +++ b/renderer/src/ui/settings/components/dropdown.jsx @@ -1,48 +1,51 @@ -import React from "@modules/react"; - -import Arrow from "@ui/icons/downarrow"; - -const {useState, useCallback} = React; - - -export default function Select({value: initialValue, options, style, onChange}) { - const [value, setValue] = useState(initialValue ?? options[0].value); - const change = useCallback((val) => { - onChange?.(val); - setValue(val); - }, [onChange]); - - - const hideMenu = useCallback(() => { - setOpen(false); - document.removeEventListener("click", hideMenu); - }, []); - - const [open, setOpen] = useState(false); - const showMenu = useCallback((event) => { - event.preventDefault(); - event.stopPropagation(); - - const next = !open; - setOpen(next); - if (!next) return; - document.addEventListener("click", hideMenu); - }, [hideMenu, open]); - - - // ?? options[0] provides a double failsafe - const selected = options.find(o => o.value == value) ?? options[0]; - const optionComponents =
- {options.map(opt => -
change(opt.value)}>{opt.label}
- )} -
; - - const styleClass = style == "transparent" ? " bd-select-transparent" : ""; - const isOpen = open ? " menu-open" : ""; - return
-
{selected.label}
- - {open && optionComponents} -
; +import React from "@modules/react"; + +import Arrow from "@ui/icons/downarrow"; + +const {useState, useCallback} = React; + + +export default function Select({value: initialValue, options, style, onChange, disabled}) { + const [value, setValue] = useState(initialValue ?? options[0].value); + const change = useCallback((val) => { + onChange?.(val); + setValue(val); + }, [onChange]); + + + const hideMenu = useCallback(() => { + setOpen(false); + document.removeEventListener("click", hideMenu); + }, []); + + const [open, setOpen] = useState(false); + const showMenu = useCallback((event) => { + event.preventDefault(); + event.stopPropagation(); + + if (disabled) return; + + const next = !open; + setOpen(next); + if (!next) return; + document.addEventListener("click", hideMenu); + }, [hideMenu, open, disabled]); + + + // ?? options[0] provides a double failsafe + const selected = options.find(o => o.value == value) ?? options[0]; + const optionComponents =
+ {options.map(opt => +
change(opt.value)}>{opt.label}
+ )} +
; + + const styleClass = style == "transparent" ? " bd-select-transparent" : ""; + const isOpen = open ? " menu-open" : ""; + const isDisabled = disabled ? " bd-select-disabled" : ""; + return
+
{selected.label}
+ + {open && optionComponents} +
; } \ No newline at end of file diff --git a/renderer/src/ui/settings/components/keybind.jsx b/renderer/src/ui/settings/components/keybind.jsx index f6a04602..de0f8a72 100644 --- a/renderer/src/ui/settings/components/keybind.jsx +++ b/renderer/src/ui/settings/components/keybind.jsx @@ -7,7 +7,7 @@ import Close from "@ui/icons/close"; const {useState, useCallback, useEffect} = React; -export default function Keybind({value: initialValue, onChange, max = 2, clearable = true}) { +export default function Keybind({value: initialValue, onChange, max = 2, clearable = true, disabled}) { const [state, setState] = useState({value: initialValue, isRecording: false, accum: []}); useEffect(() => { @@ -32,19 +32,21 @@ export default function Keybind({value: initialValue, onChange, max = 2, clearab const clearKeybind = useCallback((event) => { event.stopPropagation(); event.preventDefault(); + if (disabled) return; if (onChange) onChange([]); setState({...state, isRecording: false, value: [], accum: []}); - }, [onChange, state]); + }, [onChange, state, disabled]); const onClick = useCallback((e) => { + if (disabled) return; if (e.target?.className?.includes?.("bd-keybind-clear") || e.target?.closest(".bd-button")?.className?.includes("bd-keybind-clear")) return clearKeybind(e); setState({...state, isRecording: !state.isRecording}); - }, [state, clearKeybind]); + }, [state, clearKeybind, disabled]); const displayValue = state.isRecording ? "Recording..." : !state.value.length ? "N/A" : state.value.join(" + "); - return
- + return
+
{clearable && } diff --git a/renderer/src/ui/settings/components/number.jsx b/renderer/src/ui/settings/components/number.jsx index 01180e8e..25b6c8fc 100644 --- a/renderer/src/ui/settings/components/number.jsx +++ b/renderer/src/ui/settings/components/number.jsx @@ -1,14 +1,14 @@ -import React from "@modules/react"; - -const {useState, useCallback} = React; - - -export default function Number({value: initialValue, min, max, step, onChange}) { - const [value, setValue] = useState(initialValue); - const change = useCallback((e) => { - onChange?.(e.target.value); - setValue(e.target.value); - }, [onChange]); - - return ; +import React from "@modules/react"; + +const {useState, useCallback} = React; + + +export default function Number({value: initialValue, min, max, step, onChange, disabled}) { + const [value, setValue] = useState(initialValue); + const change = useCallback((e) => { + onChange?.(e.target.value); + setValue(e.target.value); + }, [onChange]); + + return ; } \ No newline at end of file diff --git a/renderer/src/ui/settings/components/radio.jsx b/renderer/src/ui/settings/components/radio.jsx index ea293de0..6ec87205 100644 --- a/renderer/src/ui/settings/components/radio.jsx +++ b/renderer/src/ui/settings/components/radio.jsx @@ -1,31 +1,32 @@ -import React from "@modules/react"; - -import RadioIcon from "@ui/icons/radio"; - -const {useState, useCallback} = React; - - -export default function Radio({name, value, options, onChange}) { - const [index, setIndex] = useState(options.findIndex(o => o.value === value)); - const change = useCallback((e) => { - const newIndex = parseInt(e.target.value); - const newValue = options[newIndex].value; - onChange?.(newValue); - setIndex(newIndex); - }, [options, onChange]); - - function renderOption(opt, i) { - const isSelected = index === i; - return ; - } - - return
{options.map(renderOption)}
; +import React from "@modules/react"; + +import RadioIcon from "@ui/icons/radio"; + +const {useState, useCallback} = React; + + +export default function Radio({name, value, options, onChange, disabled}) { + const [index, setIndex] = useState(options.findIndex(o => o.value === value)); + const change = useCallback((e) => { + if (disabled) return; + const newIndex = parseInt(e.target.value); + const newValue = options[newIndex].value; + onChange?.(newValue); + setIndex(newIndex); + }, [options, onChange, disabled]); + + function renderOption(opt, i) { + const isSelected = index === i; + return ; + } + + return
{options.map(renderOption)}
; } \ No newline at end of file diff --git a/renderer/src/ui/settings/components/slider.jsx b/renderer/src/ui/settings/components/slider.jsx index 3483d535..9655447d 100644 --- a/renderer/src/ui/settings/components/slider.jsx +++ b/renderer/src/ui/settings/components/slider.jsx @@ -1,16 +1,17 @@ -import React from "@modules/react"; - -const {useState, useCallback} = React; - - -export default function Slider({value: initialValue, min, max, step, onChange}) { - const [value, setValue] = useState(initialValue); - const change = useCallback((e) => { - onChange?.(e.target.value); - setValue(e.target.value); - }, [onChange]); - - return
-
{value}
-
; +import React from "@modules/react"; + +const {useState, useCallback} = React; + + +export default function Slider({value: initialValue, min, max, step, onChange, disabled}) { + const [value, setValue] = useState(initialValue); + const change = useCallback((e) => { + if (disabled) return; + onChange?.(e.target.value); + setValue(e.target.value); + }, [onChange, disabled]); + + return
+
{value}
+
; } \ No newline at end of file diff --git a/renderer/src/ui/settings/components/textbox.jsx b/renderer/src/ui/settings/components/textbox.jsx index 60bf97ad..93815694 100644 --- a/renderer/src/ui/settings/components/textbox.jsx +++ b/renderer/src/ui/settings/components/textbox.jsx @@ -1,14 +1,15 @@ -import React from "@modules/react"; - -const {useState, useCallback} = React; - - -export default function Textbox({value: initialValue, maxLength, placeholder, onKeyDown, onChange}) { - const [value, setValue] = useState(initialValue); - const change = useCallback((e) => { - onChange?.(e.target.value); - setValue(e.target.value); - }, [onChange]); - - return ; +import React from "@modules/react"; + +const {useState, useCallback} = React; + + +export default function Textbox({value: initialValue, maxLength, placeholder, onKeyDown, onChange, disabled}) { + const [value, setValue] = useState(initialValue); + const change = useCallback((e) => { + if (disabled) return; + onChange?.(e.target.value); + setValue(e.target.value); + }, [onChange, disabled]); + + return ; } \ No newline at end of file