From 1b2fe2104458a42c376c457e0014b5b5c6a08e86 Mon Sep 17 00:00:00 2001 From: Botzy Date: Thu, 13 Feb 2025 13:05:14 +0200 Subject: [PATCH 1/7] feat(Checkbox): added Checkbox component --- src/components/Checkbox/Checkbox.less | 95 +++++++++++++++++++++++++++ src/components/Checkbox/Checkbox.tsx | 87 ++++++++++++++++++++++++ src/components/Checkbox/index.ts | 5 ++ src/components/index.ts | 2 + 4 files changed, 189 insertions(+) create mode 100644 src/components/Checkbox/Checkbox.less create mode 100644 src/components/Checkbox/Checkbox.tsx create mode 100644 src/components/Checkbox/index.ts diff --git a/src/components/Checkbox/Checkbox.less b/src/components/Checkbox/Checkbox.less new file mode 100644 index 000000000..7d43947ed --- /dev/null +++ b/src/components/Checkbox/Checkbox.less @@ -0,0 +1,95 @@ +// Copyright (C) 2017-2025 Smart code 203358507 + +.checkbox { + display: flex; + align-items: center; + overflow: visible; + + .label { + display: flex; + flex-direction: row; + align-items: center; + padding: 0.5rem 0; + + span { + font-size: 0.9rem; + color: var(--primary-foreground-color); + opacity: 0.6; + } + .link { + font-size: 0.9rem; + color: var(--primary-accent-color); + + &:hover { + text-decoration: underline; + } + } + } + + .checkbox-container { + position: relative; + width: 1.75rem; + height: 1.75rem; + border: 0.2rem solid var(--color-placeholder); + border-radius: 0.5rem; + background-color: transparent; + display: flex; + flex: none; + margin-right: 1rem; + align-items: center; + justify-content: center; + transition: all 0.2s ease-in-out; + cursor: pointer; + outline: none; + user-select: none; + + input[type='checkbox'] { + opacity: 0; + width: 0; + height: 0; + position: absolute; + cursor: pointer; + } + + .checkmark { + position: absolute; + top: 0; + left: 0; + width: 1.5rem; + height: 1.5rem; + transition: opacity 0.2s ease-in-out; + background-color: transparent; + opacity: 0; + + &:after { + content: ""; + position: absolute; + left: 0.45rem; + top: 0.2rem; + width: 0.2rem; + height: 0.5rem; + border: solid var(--primary-foreground-color); + border-width: 0 0.2rem 0.2rem 0; + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); + } + } + + &.disabled { + cursor: not-allowed; + } + + &.error { + border-color: var(--color-trakt); + } + + &.checked { + border: 3px solid var(--secondary-accent-color); + background-color: var(--secondary-accent-color); + .checkmark { + opacity: 1; + } + } + } +} diff --git a/src/components/Checkbox/Checkbox.tsx b/src/components/Checkbox/Checkbox.tsx new file mode 100644 index 000000000..b5c0b0e7c --- /dev/null +++ b/src/components/Checkbox/Checkbox.tsx @@ -0,0 +1,87 @@ +// Copyright (C) 2017-2025 Smart code 203358507 + +import React, { useCallback, ChangeEvent, KeyboardEvent, RefCallback } from 'react'; +import classNames from 'classnames'; +import styles from './Checkbox.less'; +import Button from '../Button'; + +type Props = { + ref?: RefCallback; + name: string; + disabled?: boolean; + checked?: boolean; + className?: string; + label?: string; + link?: string; + href?: string; + onChange?: (props: any) => void; + error?: string; +}; + +const Checkbox = React.forwardRef(({ name, disabled, className, label, href, link, onChange, error, checked }, ref) => { + + const handleSelect = useCallback((event: ChangeEvent) => { + if (!disabled && onChange) { + onChange({ + type: 'select', + checked: event.target.checked, + reactEvent: event, + nativeEvent: event.nativeEvent, + }); + } + }, [disabled, onChange]); + + const onKeyDown = useCallback((event: KeyboardEvent) => { + if ((event.key === 'Enter' || event.key === ' ') && !disabled) { + onChange && onChange({ + type: 'select', + checked: event.target.checked, + reactEvent: event, + nativeEvent: event.nativeEvent, + }); + } + }, [disabled, checked, onChange]); + + return ( +
+ +
+ ); +}); + +export default Checkbox; diff --git a/src/components/Checkbox/index.ts b/src/components/Checkbox/index.ts new file mode 100644 index 000000000..fa5739580 --- /dev/null +++ b/src/components/Checkbox/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2025 Smart code 203358507 + +import Checkbox from './Checkbox'; + +export default Checkbox; diff --git a/src/components/index.ts b/src/components/index.ts index f65d66f81..7ef75f888 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,6 +1,7 @@ import AddonDetailsModal from './AddonDetailsModal'; import BottomSheet from './BottomSheet'; import Button from './Button'; +import Checkbox from './Checkbox'; import Chips from './Chips'; import ColorInput from './ColorInput'; import ContinueWatchingItem from './ContinueWatchingItem'; @@ -31,6 +32,7 @@ export { AddonDetailsModal, BottomSheet, Button, + Checkbox, Chips, ColorInput, ContinueWatchingItem, From e3fda56a11f3a7081d44d6c2a5f5d7e826fc954e Mon Sep 17 00:00:00 2001 From: Botzy Date: Thu, 13 Feb 2025 13:06:05 +0200 Subject: [PATCH 2/7] refactor(Intro): reuse Checkbox component for consent items --- src/routes/Intro/Intro.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index fc98fe5cf..989e6febd 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -8,9 +8,8 @@ const { default: Icon } = require('@stremio/stremio-icons/react'); const { Modal, useRouteFocused } = require('stremio-router'); const { useServices } = require('stremio/services'); const { useBinaryState } = require('stremio/common'); -const { Button, Image } = require('stremio/components'); +const { Button, Image, Checkbox } = require('stremio/components'); const CredentialsTextInput = require('./CredentialsTextInput'); -const ConsentToggle = require('./ConsentToggle'); const PasswordResetModal = require('./PasswordResetModal'); const useFacebookLogin = require('./useFacebookLogin'); const styles = require('./styles'); @@ -308,30 +307,27 @@ const Intro = ({ queryParams }) => { onChange={confirmPasswordOnChange} onSubmit={confirmPasswordOnSubmit} /> - - - : From 71bd470d31d2645ffb5a5d6dbcb3273846b503c9 Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 17 Feb 2025 14:02:15 +0200 Subject: [PATCH 3/7] fix(Checkbox): use checkmark icon instead of styles and make bg color the primary accent one --- src/components/Checkbox/Checkbox.less | 35 +++++---------------------- src/components/Checkbox/Checkbox.tsx | 7 +++++- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/src/components/Checkbox/Checkbox.less b/src/components/Checkbox/Checkbox.less index 7d43947ed..5890ce52e 100644 --- a/src/components/Checkbox/Checkbox.less +++ b/src/components/Checkbox/Checkbox.less @@ -30,9 +30,10 @@ position: relative; width: 1.75rem; height: 1.75rem; - border: 0.2rem solid var(--color-placeholder); + border: 0.2rem solid var(--primary-accent-color); border-radius: 0.5rem; background-color: transparent; + padding: 0.1rem; display: flex; flex: none; margin-right: 1rem; @@ -51,29 +52,9 @@ cursor: pointer; } - .checkmark { - position: absolute; - top: 0; - left: 0; - width: 1.5rem; - height: 1.5rem; - transition: opacity 0.2s ease-in-out; - background-color: transparent; - opacity: 0; - - &:after { - content: ""; - position: absolute; - left: 0.45rem; - top: 0.2rem; - width: 0.2rem; - height: 0.5rem; - border: solid var(--primary-foreground-color); - border-width: 0 0.2rem 0.2rem 0; - -webkit-transform: rotate(45deg); - -ms-transform: rotate(45deg); - transform: rotate(45deg); - } + .checkbox-icon { + width: 100%; + height: 100%; } &.disabled { @@ -85,11 +66,7 @@ } &.checked { - border: 3px solid var(--secondary-accent-color); - background-color: var(--secondary-accent-color); - .checkmark { - opacity: 1; - } + background-color: var(--primary-accent-color); } } } diff --git a/src/components/Checkbox/Checkbox.tsx b/src/components/Checkbox/Checkbox.tsx index b5c0b0e7c..8180ddd84 100644 --- a/src/components/Checkbox/Checkbox.tsx +++ b/src/components/Checkbox/Checkbox.tsx @@ -4,6 +4,7 @@ import React, { useCallback, ChangeEvent, KeyboardEvent, RefCallback } from 'rea import classNames from 'classnames'; import styles from './Checkbox.less'; import Button from '../Button'; +import Icon from '@stremio/stremio-icons/react'; type Props = { ref?: RefCallback; @@ -66,7 +67,11 @@ const Checkbox = React.forwardRef(({ name, disabled, cl onChange={handleSelect} className={styles['input']} /> - + { + checked ? + + : null + }
{label} From 72e7b7051ef55d8567482a063d5b7a75231ff0db Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 17 Feb 2025 17:46:13 +0200 Subject: [PATCH 4/7] fix(Button): add missing target prop to type --- src/components/Button/Button.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index f4b059bd3..f97e1ba82 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -8,6 +8,7 @@ import styles from './Button.less'; type Props = { className?: string, href?: string, + target?: string title?: string, disabled?: boolean, tabIndex?: number, From f5ef7d653d50003e24b98ea8f08ee1edf029f9e1 Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 17 Feb 2025 18:09:17 +0200 Subject: [PATCH 5/7] fix(Checkbox): improve typings and styles to follow mockups --- src/components/Checkbox/Checkbox.less | 24 +++++++++++++++++------- src/components/Checkbox/Checkbox.tsx | 13 +++++++++---- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/components/Checkbox/Checkbox.less b/src/components/Checkbox/Checkbox.less index 5890ce52e..742506cc0 100644 --- a/src/components/Checkbox/Checkbox.less +++ b/src/components/Checkbox/Checkbox.less @@ -1,5 +1,7 @@ // Copyright (C) 2017-2025 Smart code 203358507 +@import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; + .checkbox { display: flex; align-items: center; @@ -10,6 +12,7 @@ flex-direction: row; align-items: center; padding: 0.5rem 0; + cursor: pointer; span { font-size: 0.9rem; @@ -28,21 +31,23 @@ .checkbox-container { position: relative; - width: 1.75rem; - height: 1.75rem; - border: 0.2rem solid var(--primary-accent-color); - border-radius: 0.5rem; - background-color: transparent; + width: 1.5rem; + height: 1.5rem; + border-radius: 0.3rem; + background-color: var(--overlay-color); padding: 0.1rem; display: flex; flex: none; - margin-right: 1rem; + margin: 0 1rem 0 0.3rem; align-items: center; justify-content: center; transition: all 0.2s ease-in-out; cursor: pointer; outline: none; user-select: none; + outline-width: var(--focus-outline-size); + outline-color: @color-surface-light5; + outline-offset: 2px; input[type='checkbox'] { opacity: 0; @@ -54,7 +59,8 @@ .checkbox-icon { width: 100%; - height: 100%; + height: 100%; + color: var(--primary-foreground-color); } &.disabled { @@ -68,5 +74,9 @@ &.checked { background-color: var(--primary-accent-color); } + + &:hover, &:focus { + outline-style: solid; + } } } diff --git a/src/components/Checkbox/Checkbox.tsx b/src/components/Checkbox/Checkbox.tsx index 8180ddd84..da4ae33eb 100644 --- a/src/components/Checkbox/Checkbox.tsx +++ b/src/components/Checkbox/Checkbox.tsx @@ -15,7 +15,12 @@ type Props = { label?: string; link?: string; href?: string; - onChange?: (props: any) => void; + onChange?: (props: { + type: string; + checked: boolean; + reactEvent: KeyboardEvent | ChangeEvent; + nativeEvent: Event; + }) => void; error?: string; }; @@ -32,12 +37,12 @@ const Checkbox = React.forwardRef(({ name, disabled, cl } }, [disabled, onChange]); - const onKeyDown = useCallback((event: KeyboardEvent) => { + const onKeyDown = useCallback((event: KeyboardEvent) => { if ((event.key === 'Enter' || event.key === ' ') && !disabled) { onChange && onChange({ type: 'select', - checked: event.target.checked, - reactEvent: event, + checked: !checked, + reactEvent: event as KeyboardEvent, nativeEvent: event.nativeEvent, }); } From e60cf6501e977259da4cdbef2fc6a362e8a2d19f Mon Sep 17 00:00:00 2001 From: Botsy Date: Mon, 17 Feb 2025 18:10:48 +0200 Subject: [PATCH 6/7] Update src/components/Checkbox/Checkbox.less Co-authored-by: Timothy Z. --- src/components/Checkbox/Checkbox.less | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Checkbox/Checkbox.less b/src/components/Checkbox/Checkbox.less index 742506cc0..718a7b129 100644 --- a/src/components/Checkbox/Checkbox.less +++ b/src/components/Checkbox/Checkbox.less @@ -19,6 +19,7 @@ color: var(--primary-foreground-color); opacity: 0.6; } + .link { font-size: 0.9rem; color: var(--primary-accent-color); From 14927942e8f37b2135e378e9612cd367159143bf Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 17 Feb 2025 18:25:21 +0200 Subject: [PATCH 7/7] fix(ConsentToggle): remove unused ConsentToggle component --- .../Intro/ConsentToggle/ConsentToggle.js | 56 ------------------- src/routes/Intro/ConsentToggle/index.js | 5 -- src/routes/Intro/ConsentToggle/styles.less | 43 -------------- 3 files changed, 104 deletions(-) delete mode 100644 src/routes/Intro/ConsentToggle/ConsentToggle.js delete mode 100644 src/routes/Intro/ConsentToggle/index.js delete mode 100644 src/routes/Intro/ConsentToggle/styles.less diff --git a/src/routes/Intro/ConsentToggle/ConsentToggle.js b/src/routes/Intro/ConsentToggle/ConsentToggle.js deleted file mode 100644 index 9a0210607..000000000 --- a/src/routes/Intro/ConsentToggle/ConsentToggle.js +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const React = require('react'); -const PropTypes = require('prop-types'); -const classnames = require('classnames'); -const { Button, Toggle } = require('stremio/components'); -const styles = require('./styles'); - -const ConsentToggle = React.forwardRef(({ className, label, link, href, onToggle, ...props }, ref) => { - const toggleOnClick = React.useCallback((event) => { - if (typeof props.onClick === 'function') { - props.onClick(event); - } - - if (!event.nativeEvent.togglePrevented && typeof onToggle === 'function') { - onToggle({ - type: 'toggle', - reactEvent: event, - nativeEvent: event.nativeEvent - }); - } - }, [onToggle, props.onClick]); - const linkOnClick = React.useCallback((event) => { - event.nativeEvent.togglePrevented = true; - }, []); - return ( - -
- {label} - {' '} - { - typeof link === 'string' && link.length > 0 && typeof href === 'string' && href.length > 0 ? - - : - null - } -
-
- ); -}); - -ConsentToggle.displayName = 'ConsentToggle'; - -ConsentToggle.propTypes = { - className: PropTypes.string, - checked: PropTypes.bool, - label: PropTypes.string, - link: PropTypes.string, - href: PropTypes.string, - onToggle: PropTypes.func, - onClick: PropTypes.func -}; - -module.exports = ConsentToggle; diff --git a/src/routes/Intro/ConsentToggle/index.js b/src/routes/Intro/ConsentToggle/index.js deleted file mode 100644 index 8edfe4a27..000000000 --- a/src/routes/Intro/ConsentToggle/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const ConsentToggle = require('./ConsentToggle'); - -module.exports = ConsentToggle; diff --git a/src/routes/Intro/ConsentToggle/styles.less b/src/routes/Intro/ConsentToggle/styles.less deleted file mode 100644 index e8229e244..000000000 --- a/src/routes/Intro/ConsentToggle/styles.less +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -@import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; - -:import('~stremio/components/Toggle/styles.less') { - checkbox-icon: icon; -} - -.consent-toggle-container { - display: flex; - flex-direction: row; - align-items: center; - padding: 0.5rem 0; - border-radius: var(--border-radius); - - &:focus { - outline: none; - background-color: var(--overlay-color); - } - - &:global(.checked) { - .label { - opacity: 1; - } - } - - .label { - flex: 1; - margin-left: 1rem; - font-size: 0.9rem; - color: var(--primary-foreground-color); - opacity: 0.6; - - .link { - font-size: 0.9rem; - color: var(--primary-accent-color); - - &:hover { - text-decoration: underline; - } - } - } -} \ No newline at end of file