From a6b66667f1b9edbb299e496932690c2e364a7d3d Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 16 May 2024 19:38:34 +0300 Subject: [PATCH 001/336] feat(player): add seek action and handle seeking player state w/ debug statements Signed-off-by: Lachezar Lechev --- src/routes/Player/Player.js | 28 ++++++++++++++++++++++++++-- src/routes/Player/usePlayer.d.ts | 2 +- src/routes/Player/usePlayer.js | 15 ++++++++++++++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index 0a2efef8a..3ad5dfea2 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -34,7 +34,7 @@ const Player = ({ urlParams, queryParams }) => { return queryParams.has('forceTranscoding'); }, [queryParams]); - const [player, videoParamsChanged, timeChanged, pausedChanged, ended, nextVideo] = usePlayer(urlParams); + const [player, videoParamsChanged, timeChanged, seek, pausedChanged, ended, nextVideo] = usePlayer(urlParams); const [settings, updateSettings] = useSettings(); const streamingServer = useStreamingServer(); const statistics = useStatistics(player, streamingServer); @@ -42,6 +42,8 @@ const Player = ({ urlParams, queryParams }) => { const routeFocused = useRouteFocused(); const toast = useToast(); + const [seeking, setSeeking] = React.useState(false); + const [casting, setCasting] = React.useState(() => { return chromecast.active && chromecast.transport.getCastState() === cast.framework.CastState.CONNECTED; }); @@ -136,6 +138,8 @@ const Player = ({ urlParams, queryParams }) => { const onPlayRequested = React.useCallback(() => { video.setProp('paused', false); + setSeeking(false); + console.log(`setSeeking to (PlayRequested - Space): false`); }, []); const onPlayRequestedDebounced = React.useCallback(debounce(onPlayRequested, 200), []); @@ -159,6 +163,9 @@ const Player = ({ urlParams, queryParams }) => { const onSeekRequested = React.useCallback((time) => { video.setProp('time', time); + + setSeeking(true); + console.log(`setSeeking to (SeekRequested): true`); }, []); const onPlaybackSpeedChanged = React.useCallback((rate) => { @@ -341,11 +348,24 @@ const Player = ({ urlParams, queryParams }) => { video.setProp('extraSubtitlesOutlineColor', settings.subtitlesOutlineColor); }, [settings.subtitlesOutlineColor]); + React.useEffect(() => { + if (seeking && video.state.buffered) { + console.log(`setSeeking to (on !video.state.buffering): false`); + setSeeking(false); + } + }, [video.state.buffering]); + React.useEffect(() => { if (video.state.time !== null && !isNaN(video.state.time) && video.state.duration !== null && !isNaN(video.state.duration) && video.state.manifest !== null && typeof video.state.manifest.name === 'string') { - timeChanged(video.state.time, video.state.duration, video.state.manifest.name); + + if (seeking) { + seek(video.state.time, video.state.duration, video.state.manifest.name) + // timeChanged(video.state.time, video.state.duration, video.state.manifest.name); + } else { + timeChanged(video.state.time, video.state.duration, video.state.manifest.name); + } } }, [video.state.time, video.state.duration, video.state.manifest]); @@ -468,8 +488,12 @@ const Player = ({ urlParams, queryParams }) => { if (!menusOpen && !nextVideoPopupOpen && video.state.paused !== null) { if (video.state.paused) { onPlayRequested(); + setSeeking(false); + console.log(`setSeeking to (play requested - Space): false`); } else { onPauseRequested(); + setSeeking(false); + console.log(`setSeeking to (pause requested - Space): false`); } } diff --git a/src/routes/Player/usePlayer.d.ts b/src/routes/Player/usePlayer.d.ts index 8580583f3..0ee68cf56 100644 --- a/src/routes/Player/usePlayer.d.ts +++ b/src/routes/Player/usePlayer.d.ts @@ -1,2 +1,2 @@ -declare const usePlayer: (urlParams: UrlParams, videoParams: any) => [Player, (time: number, duration: number, device: string) => void, (paused: boolean) => void, () => void, () => void]; +declare const usePlayer: (urlParams: UrlParams, videoParams: { hash: string | null, size: number | null, filename: string | null } | null | undefined) => [Player, (videoParams: { hash: string | null, size: number | null, filename: string | null }) => void, (time: number, duration: number, device: string) => void, (time: number, duration: number, device: string) => void, (paused: boolean) => void, () => void, () => void,]; export = usePlayer; \ No newline at end of file diff --git a/src/routes/Player/usePlayer.js b/src/routes/Player/usePlayer.js index 9bbc1673d..9beb0ba06 100644 --- a/src/routes/Player/usePlayer.js +++ b/src/routes/Player/usePlayer.js @@ -81,6 +81,7 @@ const usePlayer = (urlParams) => { } }; } else { + console.warn("Player Unload triggered"); return { action: 'Unload' }; @@ -104,6 +105,17 @@ const usePlayer = (urlParams) => { } }, 'player'); }, []); + + const seek = React.useCallback((time, duration, device) => { + core.transport.dispatch({ + action: 'Player', + args: { + action: 'Seek', + args: { time, duration, device } + } + }, 'player'); + }, []); + const ended = React.useCallback(() => { core.transport.dispatch({ action: 'Player', @@ -129,8 +141,9 @@ const usePlayer = (urlParams) => { } }, 'player'); }, []); + const player = useModelState({ model: 'player', action, map }); - return [player, videoParamsChanged, timeChanged, pausedChanged, ended, nextVideo]; + return [player, videoParamsChanged, timeChanged, pausedChanged, ended, nextVideo, seek]; }; module.exports = usePlayer; From 5d5c28b1184ce0e02419703ae7203e3a0bf62ab2 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 17 May 2024 10:19:33 +0300 Subject: [PATCH 002/336] fix(player): buffering effects for seeking Signed-off-by: Lachezar Lechev --- src/routes/Player/Player.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index 3ad5dfea2..44b75c724 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -349,8 +349,8 @@ const Player = ({ urlParams, queryParams }) => { }, [settings.subtitlesOutlineColor]); React.useEffect(() => { - if (seeking && video.state.buffered) { - console.log(`setSeeking to (on !video.state.buffering): false`); + if (seeking && video.state.buffering) { + console.log(`setSeeking to (on video.state.buffering): false`); setSeeking(false); } }, [video.state.buffering]); From e66c383e23eb1840183ee0813f0d57ffdf143f14 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 17 May 2024 11:24:49 +0300 Subject: [PATCH 003/336] fix: usePlayer exports and TS definition Signed-off-by: Lachezar Lechev --- src/routes/Player/usePlayer.d.ts | 2 +- src/routes/Player/usePlayer.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Player/usePlayer.d.ts b/src/routes/Player/usePlayer.d.ts index 0ee68cf56..256424dd4 100644 --- a/src/routes/Player/usePlayer.d.ts +++ b/src/routes/Player/usePlayer.d.ts @@ -1,2 +1,2 @@ -declare const usePlayer: (urlParams: UrlParams, videoParams: { hash: string | null, size: number | null, filename: string | null } | null | undefined) => [Player, (videoParams: { hash: string | null, size: number | null, filename: string | null }) => void, (time: number, duration: number, device: string) => void, (time: number, duration: number, device: string) => void, (paused: boolean) => void, () => void, () => void,]; +declare const usePlayer: (urlParams: UrlParams) => [Player, (videoParams: { hash: string | null, size: number | null, filename: string | null }) => void, (time: number, duration: number, device: string) => void, (time: number, duration: number, device: string) => void, (paused: boolean) => void, () => void, () => void,]; export = usePlayer; \ No newline at end of file diff --git a/src/routes/Player/usePlayer.js b/src/routes/Player/usePlayer.js index 9beb0ba06..c2a2ff165 100644 --- a/src/routes/Player/usePlayer.js +++ b/src/routes/Player/usePlayer.js @@ -143,7 +143,7 @@ const usePlayer = (urlParams) => { }, []); const player = useModelState({ model: 'player', action, map }); - return [player, videoParamsChanged, timeChanged, pausedChanged, ended, nextVideo, seek]; + return [player, videoParamsChanged, timeChanged, seek, pausedChanged, ended, nextVideo]; }; module.exports = usePlayer; From 97451619990a0301155c558de73c6250ed6fe31c Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 17 May 2024 11:25:26 +0300 Subject: [PATCH 004/336] fix(player): setSeeking false right after seek instead of using video.state.buffering Signed-off-by: Lachezar Lechev --- src/routes/Player/Player.js | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index 44b75c724..521fc2387 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -348,24 +348,19 @@ const Player = ({ urlParams, queryParams }) => { video.setProp('extraSubtitlesOutlineColor', settings.subtitlesOutlineColor); }, [settings.subtitlesOutlineColor]); - React.useEffect(() => { - if (seeking && video.state.buffering) { - console.log(`setSeeking to (on video.state.buffering): false`); - setSeeking(false); - } - }, [video.state.buffering]); - React.useEffect(() => { if (video.state.time !== null && !isNaN(video.state.time) && video.state.duration !== null && !isNaN(video.state.duration) && video.state.manifest !== null && typeof video.state.manifest.name === 'string') { - if (seeking) { - seek(video.state.time, video.state.duration, video.state.manifest.name) - // timeChanged(video.state.time, video.state.duration, video.state.manifest.name); - } else { - timeChanged(video.state.time, video.state.duration, video.state.manifest.name); - } + if (seeking) { + seek(video.state.time, video.state.duration, video.state.manifest.name) + setSeeking(false); + console.log(`setSeeking to (on video.state.time change): false`); + + } else { + timeChanged(video.state.time, video.state.duration, video.state.manifest.name); + } } }, [video.state.time, video.state.duration, video.state.manifest]); From 8a79058d1cc650549aa08bcc943db5d5483a3f61 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 18 Jun 2024 12:07:34 +0200 Subject: [PATCH 005/336] feat: calendar --- src/App/routerViewsConfig.js | 4 ++ src/common/MainNavBars/MainNavBars.js | 1 + src/common/routesRegexp.js | 4 ++ src/modules.d.ts | 1 + src/routes/Calendar/Calendar.less | 61 ++++++++++++++++++ src/routes/Calendar/Calendar.tsx | 56 +++++++++++++++++ src/routes/Calendar/List/Item/Item.less | 58 +++++++++++++++++ src/routes/Calendar/List/Item/Item.tsx | 47 ++++++++++++++ src/routes/Calendar/List/List.less | 11 ++++ src/routes/Calendar/List/List.tsx | 36 +++++++++++ src/routes/Calendar/Table/Cell/Cell.less | 62 +++++++++++++++++++ src/routes/Calendar/Table/Cell/Cell.tsx | 44 +++++++++++++ src/routes/Calendar/Table/Table.less | 37 +++++++++++ src/routes/Calendar/Table/Table.tsx | 55 ++++++++++++++++ src/routes/Calendar/index.ts | 5 ++ src/routes/Calendar/useCalendar.ts | 27 ++++++++ src/routes/Calendar/useCalendarDate.ts | 34 ++++++++++ src/routes/Calendar/useSelectableInputs.ts | 35 +++++++++++ src/routes/index.js | 2 + .../KeyboardShortcuts/KeyboardShortcuts.js | 7 ++- src/types/models/Calendar.d.ts | 55 ++++++++++++++++ 21 files changed, 641 insertions(+), 1 deletion(-) create mode 100644 src/routes/Calendar/Calendar.less create mode 100644 src/routes/Calendar/Calendar.tsx create mode 100644 src/routes/Calendar/List/Item/Item.less create mode 100644 src/routes/Calendar/List/Item/Item.tsx create mode 100644 src/routes/Calendar/List/List.less create mode 100644 src/routes/Calendar/List/List.tsx create mode 100644 src/routes/Calendar/Table/Cell/Cell.less create mode 100644 src/routes/Calendar/Table/Cell/Cell.tsx create mode 100644 src/routes/Calendar/Table/Table.less create mode 100644 src/routes/Calendar/Table/Table.tsx create mode 100644 src/routes/Calendar/index.ts create mode 100644 src/routes/Calendar/useCalendar.ts create mode 100644 src/routes/Calendar/useCalendarDate.ts create mode 100644 src/routes/Calendar/useSelectableInputs.ts create mode 100644 src/types/models/Calendar.d.ts diff --git a/src/App/routerViewsConfig.js b/src/App/routerViewsConfig.js index c80da0c94..13f331728 100644 --- a/src/App/routerViewsConfig.js +++ b/src/App/routerViewsConfig.js @@ -23,6 +23,10 @@ const routerViewsConfig = [ ...routesRegexp.library, component: routes.Library }, + { + ...routesRegexp.calendar, + component: routes.Calendar + }, { ...routesRegexp.continuewatching, component: routes.Library diff --git a/src/common/MainNavBars/MainNavBars.js b/src/common/MainNavBars/MainNavBars.js index 542d68fe4..3ccf200ec 100644 --- a/src/common/MainNavBars/MainNavBars.js +++ b/src/common/MainNavBars/MainNavBars.js @@ -10,6 +10,7 @@ const TABS = [ { id: 'board', label: 'Board', icon: 'home', href: '#/' }, { id: 'discover', label: 'Discover', icon: 'discover', href: '#/discover' }, { id: 'library', label: 'Library', icon: 'library', href: '#/library' }, + { id: 'calendar', label: 'Calendar', icon: 'calendar', href: '#/calendar' }, { id: 'addons', label: 'ADDONS', icon: 'addons', href: '#/addons' }, { id: 'settings', label: 'SETTINGS', icon: 'settings', href: '#/settings' }, ]; diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index ca5efdb2c..3903da44b 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -17,6 +17,10 @@ const routesRegexp = { regexp: /^\/library(?:\/([^/]*))?$/, urlParamsNames: ['type'] }, + calendar: { + regexp: /^\/calendar(?:\/([^/]*)\/([^/]*))?$/, + urlParamsNames: ['year', 'month'] + }, continuewatching: { regexp: /^\/continuewatching(?:\/([^/]*))?$/, urlParamsNames: ['type'] diff --git a/src/modules.d.ts b/src/modules.d.ts index 70ebbd3fc..213f361f5 100644 --- a/src/modules.d.ts +++ b/src/modules.d.ts @@ -1,3 +1,4 @@ declare module '*.less'; +declare module 'stremio/services'; declare module 'stremio/common'; declare module 'stremio/common/*'; \ No newline at end of file diff --git a/src/routes/Calendar/Calendar.less b/src/routes/Calendar/Calendar.less new file mode 100644 index 000000000..7f4e5252d --- /dev/null +++ b/src/routes/Calendar/Calendar.less @@ -0,0 +1,61 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +:import('~stremio/common/PaginationInput/styles.less') { + pagination-prev-button-container: prev-button-container; + pagination-next-button-container: next-button-container; + pagination-button-icon: icon; + pagination-label: label; +} + +.calendar { + width: 100%; + height: 100%; + background-color: transparent; + + .content { + position: relative; + display: flex; + flex-direction: row; + gap: 1.5rem; + width: 100%; + height: 100%; + padding: 0 0 2rem 2rem; + + .main { + flex: auto; + position: relative; + display: flex; + flex-direction: column; + gap: 1rem; + + .inputs { + flex: none; + align-self: stretch; + display: flex; + flex-direction: row; + justify-content: center; + + .pagination-input { + flex: none; + height: 3rem; + margin-left: 1.5rem; + + .pagination-prev-button-container, .pagination-next-button-container { + width: 3rem; + height: 3rem; + + .pagination-button-icon { + width: 1rem; + height: 1rem; + } + } + + .pagination-label { + width: 9rem; + max-width: initial; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/routes/Calendar/Calendar.tsx b/src/routes/Calendar/Calendar.tsx new file mode 100644 index 000000000..c42c8c809 --- /dev/null +++ b/src/routes/Calendar/Calendar.tsx @@ -0,0 +1,56 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React, { useState } from 'react'; +import { MainNavBars, PaginationInput, useProfile, withCoreSuspender } from 'stremio/common'; +import useCalendar from './useCalendar'; +import useSelectableInputs from './useSelectableInputs'; +import Table from './Table/Table'; +import List from './List/List'; +import styles from './Calendar.less'; + +type Props = { + urlParams: UrlParams, +}; + +const Calendar = ({ urlParams }: Props) => { + const calendar = useCalendar(urlParams); + const profile = useProfile(); + + const [paginationInput] = useSelectableInputs(calendar, profile); + + const [selected, setSelected] = useState(null); + + return ( + +
+
+
+ { + paginationInput !== null ? + + : + null + } +
+ + + + + + ); +}; + +const CalendarFallback = () => ( + +); + +export default withCoreSuspender(Calendar, CalendarFallback); diff --git a/src/routes/Calendar/List/Item/Item.less b/src/routes/Calendar/List/Item/Item.less new file mode 100644 index 000000000..e0e0d0a5e --- /dev/null +++ b/src/routes/Calendar/List/Item/Item.less @@ -0,0 +1,58 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +.item { + flex: none; + position: relative; + display: flex; + flex-direction: column; + background-color: var(--overlay-color); + border-radius: var(--border-radius); + + .heading { + flex: none; + position: relative; + display: flex; + align-items: center; + height: 3.5rem; + font-size: 1rem; + font-weight: 500; + color: var(--primary-foreground-color); + padding: 0 1rem; + } + + .body { + flex: auto; + display: flex; + flex-direction: column; + + .video { + flex: none; + position: relative; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + height: 3rem; + padding: 0 1rem; + font-size: 1rem; + font-weight: 500; + color: var(--primary-foreground-color); + + &:hover { + background-color: var(--overlay-color); + } + } + } + + &:global(.current) { + .heading { + background-color: var(--primary-accent-color); + } + } + + &:global(.past) { + .body { + opacity: 0.5; + } + } +} \ No newline at end of file diff --git a/src/routes/Calendar/List/Item/Item.tsx b/src/routes/Calendar/List/Item/Item.tsx new file mode 100644 index 000000000..29ab0fdf8 --- /dev/null +++ b/src/routes/Calendar/List/Item/Item.tsx @@ -0,0 +1,47 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React from 'react'; +import classNames from 'classnames'; +import { Button } from 'stremio/common'; +import useCalendarDate from '../../useCalendarDate'; +import styles from './Item.less'; + +type Props = { + today: number | null, + date: CalendarDate, + items: CalendarContentItem[], + profile: Profile, + onClick: (date: CalendarDate) => void, +}; + +const Item = ({ today, date, items, profile, onClick }: Props) => { + const { toDayMonth } = useCalendarDate(profile); + + const onItemClick = () => { + onClick && onClick(date); + }; + + return ( +
+
+ {toDayMonth(date)} +
+
+ { + items.map(({ id, name, season, episode, deepLinks }) => ( + + )) + } +
+
+ ); +}; + +export default Item; diff --git a/src/routes/Calendar/List/List.less b/src/routes/Calendar/List/List.less new file mode 100644 index 000000000..c01168846 --- /dev/null +++ b/src/routes/Calendar/List/List.less @@ -0,0 +1,11 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +.list { + flex: none; + display: flex; + flex-direction: column; + gap: 1rem; + width: 20rem; + padding-right: 1rem; + overflow-y: auto; +} \ No newline at end of file diff --git a/src/routes/Calendar/List/List.tsx b/src/routes/Calendar/List/List.tsx new file mode 100644 index 000000000..d42bce2a3 --- /dev/null +++ b/src/routes/Calendar/List/List.tsx @@ -0,0 +1,36 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React, { useMemo } from 'react'; +import Item from './Item/Item'; +import styles from './List.less'; + +type Props = { + items: CalendarItem[], + monthInfo: CalendarMonthInfo, + profile: Profile, + onChange: (date: CalendarDate) => void, +}; + +const List = ({ items, monthInfo, profile, onChange }: Props) => { + const filteredItems = useMemo(() => { + return items.filter(({ items }) => items.length); + }, [items]); + + return ( +
+ { + filteredItems.map((item) => ( + + )) + } +
+ ); +}; + +export default List; diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less new file mode 100644 index 000000000..62cf37706 --- /dev/null +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -0,0 +1,62 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +.cell { + position: relative; + display: flex; + flex-direction: column; + justify-content: space-between; + background-color: var(--overlay-color); + + &:first-child { + border-radius: var(--border-radius) 0 0 0; + } + + &:last-child { + border-radius: 0 0 var(--border-radius) 0; + } + + &:global(.current) { + .heading { + .day { + background-color: var(--primary-accent-color); + } + } + } + + &:global(.past) { + .body { + opacity: 0.5; + } + } + + .heading { + position: relative; + padding: 1rem; + + .day { + position: relative; + display: flex; + align-items: center; + justify-content: center; + height: 2rem; + width: 2rem; + border-radius: 100%; + font-size: 1rem; + font-weight: 500; + color: var(--primary-foreground-color); + } + } + + .body { + position: relative; + display: grid; + grid-template-columns: repeat(3, 1fr); + height: 6rem; + + .poster { + height: 100%; + width: 100%; + object-fit: cover; + } + } +} \ No newline at end of file diff --git a/src/routes/Calendar/Table/Cell/Cell.tsx b/src/routes/Calendar/Table/Cell/Cell.tsx new file mode 100644 index 000000000..248067e85 --- /dev/null +++ b/src/routes/Calendar/Table/Cell/Cell.tsx @@ -0,0 +1,44 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React from 'react'; +import classNames from 'classnames'; +import { Button, Image } from 'stremio/common'; +import styles from './Cell.less'; + +type Props = { + today: number | null, + date: CalendarDate, + items: CalendarContentItem[], + onClick: (date: CalendarDate) => void, +}; + +const Cell = ({ today, date, items, onClick }: Props) => { + const onCellClick = () => { + onClick && onClick(date); + }; + + return ( +
+
+
+ {date.day} +
+
+
+ { + items.map(({ id, name, poster, deepLinks }) => ( + + )) + } +
+
+ ); +}; + +export default Cell; diff --git a/src/routes/Calendar/Table/Table.less b/src/routes/Calendar/Table/Table.less new file mode 100644 index 000000000..1d680c040 --- /dev/null +++ b/src/routes/Calendar/Table/Table.less @@ -0,0 +1,37 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +.table { + flex: auto; + position: relative; + display: flex; + flex-direction: column; + + .week { + flex: auto; + position: relative; + height: 3rem; + width: 100%; + display: grid; + grid-template-columns: repeat(7, minmax(5rem, 1fr)); + align-items: center; + + .item { + position: relative; + padding: 0.5rem; + font-size: 1rem; + font-weight: 500; + color: var(--primary-foreground-color); + } + } + + .grid { + flex: auto; + position: relative; + width: 100%; + height: 100%; + display: grid; + grid-template-columns: repeat(7, minmax(5rem, 1fr)); + gap: 1px; + border-radius: var(--border-radius); + } +} \ No newline at end of file diff --git a/src/routes/Calendar/Table/Table.tsx b/src/routes/Calendar/Table/Table.tsx new file mode 100644 index 000000000..e09366bb0 --- /dev/null +++ b/src/routes/Calendar/Table/Table.tsx @@ -0,0 +1,55 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React, { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; +import styles from './Table.less'; +import Cell from './Cell/Cell'; + +const WEEK_DAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; + +type Props = { + items: CalendarItem[], + monthInfo: CalendarMonthInfo, + onChange: (date: CalendarDate) => void, +}; + +const Table = ({ items, monthInfo, onChange }: Props) => { + const { t } = useTranslation(); + + const cellsOffset = useMemo(() => { + return Array.from(Array(monthInfo.firstWeekday).keys()); + }, [monthInfo]); + + return ( +
+
+ { + WEEK_DAYS.map((day) => ( +
+ {t(day)} +
+ )) + } +
+
+ { + cellsOffset.map((day) => ( + + )) + } + { + items.map((item) => ( + + )) + } +
+
+ ); +}; + +export default Table; diff --git a/src/routes/Calendar/index.ts b/src/routes/Calendar/index.ts new file mode 100644 index 000000000..3a1f44b68 --- /dev/null +++ b/src/routes/Calendar/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import Calendar from './Calendar'; + +export default Calendar; diff --git a/src/routes/Calendar/useCalendar.ts b/src/routes/Calendar/useCalendar.ts new file mode 100644 index 000000000..55ffc5d07 --- /dev/null +++ b/src/routes/Calendar/useCalendar.ts @@ -0,0 +1,27 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React from 'react'; +import { useModelState } from 'stremio/common'; + +const useCalendar = (urlParams: UrlParams) => { + const action = React.useMemo(() => { + const args = urlParams.year && urlParams.month ? { + year: parseInt(urlParams.year), + month: parseInt(urlParams.month), + day: urlParams.day ? parseInt(urlParams.day) : null, + } : null; + + return { + action: 'Load', + args: { + model: 'Calendar', + args, + }, + }; + }, [urlParams]); + + const calendar = useModelState({ model: 'calendar', action }) as Calendar; + return calendar; +}; + +export default useCalendar; diff --git a/src/routes/Calendar/useCalendarDate.ts b/src/routes/Calendar/useCalendarDate.ts new file mode 100644 index 000000000..2e940ce51 --- /dev/null +++ b/src/routes/Calendar/useCalendarDate.ts @@ -0,0 +1,34 @@ +const useCalendarDate = (profile: Profile) => { + const toMonthYear = (calendarDate: CalendarDate | null): string => { + if (!calendarDate) return ``; + + const date = new Date(); + date.setMonth(calendarDate.month - 1); + date.setFullYear(calendarDate.year); + + return date.toLocaleString(profile.settings.interfaceLanguage, { + month: 'long', + year: 'numeric', + }); + }; + + const toDayMonth = (calendarDate: CalendarDate | null): string => { + if (!calendarDate) return ``; + + const date = new Date(); + date.setDate(calendarDate.day); + date.setMonth(calendarDate.month - 1); + + return date.toLocaleString(profile.settings.interfaceLanguage, { + day: 'numeric', + month: 'short', + }); + }; + + return { + toMonthYear, + toDayMonth, + }; +}; + +export default useCalendarDate; \ No newline at end of file diff --git a/src/routes/Calendar/useSelectableInputs.ts b/src/routes/Calendar/useSelectableInputs.ts new file mode 100644 index 000000000..a136ab5a5 --- /dev/null +++ b/src/routes/Calendar/useSelectableInputs.ts @@ -0,0 +1,35 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React from 'react'; +import useCalendarDate from './useCalendarDate'; + +const mapSelectableInputs = (calendar: Calendar, toMonthYear: (date: CalendarDate | null) => string) => { + const paginationInput = (calendar.selectable.prev ?? calendar.selectable.next) ? + { + label: toMonthYear(calendar.selected), + onSelect: ({ value }: { value: string }) => { + if (value === 'prev' && calendar.selectable.prev) { + window.location.href = calendar.selectable.prev.deepLinks.calendar; + } + if (value === 'next' && calendar.selectable.next) { + window.location.href = calendar.selectable.next.deepLinks.calendar; + } + } + } + : + null; + + return [paginationInput]; +}; + +const useSelectableInputs = (calendar: Calendar, profile: Profile) => { + const { toMonthYear } = useCalendarDate(profile); + + const selectableInputs = React.useMemo(() => { + return mapSelectableInputs(calendar, toMonthYear); + }, [calendar]); + + return selectableInputs; +}; + +export default useSelectableInputs; diff --git a/src/routes/index.js b/src/routes/index.js index 47a2eacd8..076a2213d 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -4,6 +4,7 @@ const Addons = require('./Addons'); const Board = require('./Board'); const Discover = require('./Discover'); const Library = require('./Library'); +const Calendar = require('./Calendar').default; const MetaDetails = require('./MetaDetails'); const NotFound = require('./NotFound'); const Search = require('./Search'); @@ -16,6 +17,7 @@ module.exports = { Board, Discover, Library, + Calendar, MetaDetails, NotFound, Search, diff --git a/src/services/KeyboardShortcuts/KeyboardShortcuts.js b/src/services/KeyboardShortcuts/KeyboardShortcuts.js index 773abf23f..22ef0e41f 100644 --- a/src/services/KeyboardShortcuts/KeyboardShortcuts.js +++ b/src/services/KeyboardShortcuts/KeyboardShortcuts.js @@ -35,10 +35,15 @@ function KeyboardShortcuts() { } case 'Digit4': { event.preventDefault(); - window.location = '#/addons'; + window.location = '#/calendar'; break; } case 'Digit5': { + event.preventDefault(); + window.location = '#/addons'; + break; + } + case 'Digit6': { event.preventDefault(); window.location = '#/settings'; break; diff --git a/src/types/models/Calendar.d.ts b/src/types/models/Calendar.d.ts new file mode 100644 index 000000000..c92379a97 --- /dev/null +++ b/src/types/models/Calendar.d.ts @@ -0,0 +1,55 @@ +type CalendarDeepLinks = { + calendar: string, +}; + +type CalendarItemDeepLinks = { + metaDetailsStreams: string, +}; + +type CalendarSelectableDate = { + month: number, + year: number, + selected: boolean, + deepLinks: CalendarDeepLinks, +}; + +type CalendarSelectable = { + prev: CalendarSelectableDate, + next: CalendarSelectableDate, +}; + +type CalendarDate = { + day: number, + month: number, + year: number, +}; + +type CalendarSelected = CalendarDate | null; + +type CalendarMonthInfo = { + today: number | null, + days: number, + firstWeekday: number, +}; + +type CalendarContentItem = { + id: string, + name: string, + poster?: string, + title: string, + season?: number, + episode?: number, + deepLinks: CalendarItemDeepLinks, +}; + +type CalendarItem = { + date: CalendarDate, + items: CalendarContentItem[], +}; + +type Calendar = { + selectable: CalendarSelectable, + selected: CalendarSelected, + monthInfo: CalendarMonthInfo, + items: CalendarItem[], +}; \ No newline at end of file From 4250c9bf84c9e6a8d415f79860613b3364eaf343 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 28 Jun 2024 06:55:30 +0200 Subject: [PATCH 006/336] refactor(Calendar): improve responsiveness --- src/routes/Calendar/Calendar.less | 21 +++++++++++++++++-- src/routes/Calendar/List/Item/Item.less | 14 ++++++++++++- src/routes/Calendar/List/List.less | 14 +++++++++++++ src/routes/Calendar/Table/Cell/Cell.less | 26 +++++++++++++++++------- src/routes/Calendar/Table/Cell/Cell.tsx | 2 +- src/routes/Calendar/Table/Table.less | 9 +++++--- 6 files changed, 72 insertions(+), 14 deletions(-) diff --git a/src/routes/Calendar/Calendar.less b/src/routes/Calendar/Calendar.less index 7f4e5252d..202b2d776 100644 --- a/src/routes/Calendar/Calendar.less +++ b/src/routes/Calendar/Calendar.less @@ -1,5 +1,7 @@ // Copyright (C) 2017-2024 Smart code 203358507 +@import (reference) '~stremio/common/screen-sizes.less'; + :import('~stremio/common/PaginationInput/styles.less') { pagination-prev-button-container: prev-button-container; pagination-next-button-container: next-button-container; @@ -38,7 +40,6 @@ .pagination-input { flex: none; height: 3rem; - margin-left: 1.5rem; .pagination-prev-button-container, .pagination-next-button-container { width: 3rem; @@ -58,4 +59,20 @@ } } } -} \ No newline at end of file +} + +@media only screen and (max-width: @minimum) { + .calendar { + .content { + padding: 0; + } + } +} + +@media only screen and (max-width: @small) and (orientation: landscape) { + .calendar { + .content { + padding: 0 0 0 1rem; + } + } +} diff --git a/src/routes/Calendar/List/Item/Item.less b/src/routes/Calendar/List/Item/Item.less index e0e0d0a5e..9d4f1efe4 100644 --- a/src/routes/Calendar/List/Item/Item.less +++ b/src/routes/Calendar/List/Item/Item.less @@ -32,12 +32,24 @@ flex-direction: row; align-items: center; justify-content: space-between; + gap: 1rem; height: 3rem; padding: 0 1rem; font-size: 1rem; font-weight: 500; color: var(--primary-foreground-color); + .name { + flex: auto; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + + .info { + flex: none; + } + &:hover { background-color: var(--overlay-color); } @@ -55,4 +67,4 @@ opacity: 0.5; } } -} \ No newline at end of file +} diff --git a/src/routes/Calendar/List/List.less b/src/routes/Calendar/List/List.less index c01168846..36165bb50 100644 --- a/src/routes/Calendar/List/List.less +++ b/src/routes/Calendar/List/List.less @@ -1,5 +1,7 @@ // Copyright (C) 2017-2024 Smart code 203358507 +@import (reference) '~stremio/common/screen-sizes.less'; + .list { flex: none; display: flex; @@ -8,4 +10,16 @@ width: 20rem; padding-right: 1rem; overflow-y: auto; +} + +@media only screen and (max-width: @minimum) and (orientation: portrait) { + .list { + display: none; + } +} + +@media only screen and (max-width: @small) and (orientation: landscape) { + .list { + width: 15rem; + } } \ No newline at end of file diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less index 62cf37706..30204016f 100644 --- a/src/routes/Calendar/Table/Cell/Cell.less +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -30,6 +30,7 @@ } .heading { + flex: none; position: relative; padding: 1rem; @@ -48,15 +49,26 @@ } .body { + flex: 1 1 auto; position: relative; - display: grid; - grid-template-columns: repeat(3, 1fr); - height: 6rem; + display: flex; + flex-direction: row; + gap: 1rem; + height: 0; + padding: 1rem; + overflow-x: scroll; - .poster { + .item { + flex: none; height: 100%; - width: 100%; - object-fit: cover; + aspect-ratio: 2 / 3; + border-radius: var(--border-radius); + + .poster { + height: 100%; + width: 100%; + object-fit: cover; + } } } -} \ No newline at end of file +} diff --git a/src/routes/Calendar/Table/Cell/Cell.tsx b/src/routes/Calendar/Table/Cell/Cell.tsx index 248067e85..be003dfa1 100644 --- a/src/routes/Calendar/Table/Cell/Cell.tsx +++ b/src/routes/Calendar/Table/Cell/Cell.tsx @@ -27,7 +27,7 @@ const Cell = ({ today, date, items, onClick }: Props) => {
{ items.map(({ id, name, poster, deepLinks }) => ( -
+ + -
- - - + : + + } ); }; diff --git a/src/routes/Calendar/Placeholder/Placeholder.less b/src/routes/Calendar/Placeholder/Placeholder.less new file mode 100644 index 000000000..c57bd958e --- /dev/null +++ b/src/routes/Calendar/Placeholder/Placeholder.less @@ -0,0 +1,90 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +@import (reference) '~stremio/common/screen-sizes.less'; + +.placeholder { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + width: 100%; + overflow-y: auto; + + .title { + flex: none; + font-size: 1.75rem; + font-weight: 400; + text-align: center; + color: var(--primary-foreground-color); + margin-bottom: 1rem; + opacity: 0.5; + } + + .image { + flex: none; + height: 14rem; + margin: 1.5rem 0; + } + + .overview { + flex: none; + display: flex; + flex-direction: row; + align-items: center; + gap: 4rem; + margin-bottom: 3rem; + + .point { + display: flex; + flex-direction: row; + align-items: center; + gap: 1.5rem; + width: 18rem; + + .icon { + flex: none; + height: 3.25rem; + width: 3.25rem; + color: var(--primary-foreground-color); + opacity: 0.3; + } + + .text { + flex: auto; + font-size: 1.1rem; + font-size: 500; + color: var(--primary-foreground-color); + opacity: 0.9; + } + } + } + + .button { + flex: none; + justify-content: center; + height: 4rem; + line-height: 4rem; + padding: 0 5rem; + font-size: 1.1rem; + color: var(--primary-foreground-color); + border-radius: 3.5rem; + background-color: var(--overlay-color); + + &:hover { + outline: var(--focus-outline-size) solid var(--primary-foreground-color); + background-color: transparent; + } + } +} + +@media only screen and (max-width: @minimum) { + .placeholder { + padding: 1rem; + + .overview { + flex-direction: column; + } + } +} \ No newline at end of file diff --git a/src/routes/Calendar/Placeholder/Placeholder.tsx b/src/routes/Calendar/Placeholder/Placeholder.tsx new file mode 100644 index 000000000..b514c2295 --- /dev/null +++ b/src/routes/Calendar/Placeholder/Placeholder.tsx @@ -0,0 +1,43 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import Icon from '@stremio/stremio-icons/react'; +import { Button, Image } from 'stremio/common'; +import styles from './Placeholder.less'; + +const Placeholder = () => { + const { t } = useTranslation(); + + return ( +
+
+ {t('CALENDAR_NOT_LOGGED_IN')} +
+ +
+
+ +
+ {t('NOT_LOGGED_IN_NOTIFICATIONS')} +
+
+
+ +
+ {t('NOT_LOGGED_IN_CALENDAR')} +
+
+
+ +
+ ); +}; + +export default Placeholder; From c6ad7e971bcba4dd938506a1a373feae5d8bbda8 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 3 Jul 2024 16:25:13 +0200 Subject: [PATCH 008/336] feat(Calendar): implement selected logic --- src/routes/Calendar/Calendar.less | 2 +- src/routes/Calendar/Calendar.tsx | 2 ++ src/routes/Calendar/List/Item/Item.less | 13 ++++++-- src/routes/Calendar/List/Item/Item.tsx | 30 +++++++++++++++--- src/routes/Calendar/List/List.less | 2 +- src/routes/Calendar/List/List.tsx | 6 ++-- src/routes/Calendar/Table/Cell/Cell.less | 39 +++++++++++++++--------- src/routes/Calendar/Table/Cell/Cell.tsx | 21 ++++++++++--- src/routes/Calendar/Table/Table.tsx | 6 ++-- 9 files changed, 91 insertions(+), 30 deletions(-) diff --git a/src/routes/Calendar/Calendar.less b/src/routes/Calendar/Calendar.less index 202b2d776..cdefb4431 100644 --- a/src/routes/Calendar/Calendar.less +++ b/src/routes/Calendar/Calendar.less @@ -18,7 +18,7 @@ position: relative; display: flex; flex-direction: row; - gap: 1.5rem; + gap: 0.5rem; width: 100%; height: 100%; padding: 0 0 2rem 2rem; diff --git a/src/routes/Calendar/Calendar.tsx b/src/routes/Calendar/Calendar.tsx index d13d1fcf5..65ad50a0b 100644 --- a/src/routes/Calendar/Calendar.tsx +++ b/src/routes/Calendar/Calendar.tsx @@ -37,12 +37,14 @@ const Calendar = ({ urlParams }: Props) => {
void, }; -const Item = ({ today, date, items, profile, onClick }: Props) => { +const Item = ({ selected, monthInfo, date, items, profile, onClick }: Props) => { + const ref = useRef(null); const { toDayMonth } = useCalendarDate(profile); + const [active, today, past] = useMemo(() => { + const active = date.day === selected?.day; + const today = date.day === monthInfo.today; + const past = date.day < (monthInfo.today ?? 1); + + return [active, today, past]; + }, [selected, monthInfo, date]); + const onItemClick = () => { onClick && onClick(date); }; + useEffect(() => { + active && ref.current?.scrollIntoView({ + block: 'start', + behavior: 'smooth', + }); + }, [active]); + return ( -
+
{toDayMonth(date)}
diff --git a/src/routes/Calendar/List/List.less b/src/routes/Calendar/List/List.less index 36165bb50..dd0b63991 100644 --- a/src/routes/Calendar/List/List.less +++ b/src/routes/Calendar/List/List.less @@ -8,7 +8,7 @@ flex-direction: column; gap: 1rem; width: 20rem; - padding-right: 1rem; + padding: 0 1rem; overflow-y: auto; } diff --git a/src/routes/Calendar/List/List.tsx b/src/routes/Calendar/List/List.tsx index d42bce2a3..78e444362 100644 --- a/src/routes/Calendar/List/List.tsx +++ b/src/routes/Calendar/List/List.tsx @@ -6,12 +6,13 @@ import styles from './List.less'; type Props = { items: CalendarItem[], + selected: CalendarDate | null, monthInfo: CalendarMonthInfo, profile: Profile, onChange: (date: CalendarDate) => void, }; -const List = ({ items, monthInfo, profile, onChange }: Props) => { +const List = ({ items, selected, monthInfo, profile, onChange }: Props) => { const filteredItems = useMemo(() => { return items.filter(({ items }) => items.length); }, [items]); @@ -23,7 +24,8 @@ const List = ({ items, monthInfo, profile, onChange }: Props) => { diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less index 30204016f..a9a7117b7 100644 --- a/src/routes/Calendar/Table/Cell/Cell.less +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -6,6 +6,9 @@ flex-direction: column; justify-content: space-between; background-color: var(--overlay-color); + border: 0.15rem solid transparent; + overflow: hidden; + cursor: pointer; &:first-child { border-radius: var(--border-radius) 0 0 0; @@ -15,20 +18,6 @@ border-radius: 0 0 var(--border-radius) 0; } - &:global(.current) { - .heading { - .day { - background-color: var(--primary-accent-color); - } - } - } - - &:global(.past) { - .body { - opacity: 0.5; - } - } - .heading { flex: none; position: relative; @@ -71,4 +60,26 @@ } } } + + &.today { + .heading { + .day { + background-color: var(--primary-accent-color); + } + } + } + + &.past { + .body { + opacity: 0.5; + } + } + + &.active { + border-color: var(--primary-foreground-color); + } + + &:not(.active):hover { + border-color: var(--overlay-color); + } } diff --git a/src/routes/Calendar/Table/Cell/Cell.tsx b/src/routes/Calendar/Table/Cell/Cell.tsx index be003dfa1..d54f05e24 100644 --- a/src/routes/Calendar/Table/Cell/Cell.tsx +++ b/src/routes/Calendar/Table/Cell/Cell.tsx @@ -1,24 +1,37 @@ // Copyright (C) 2017-2024 Smart code 203358507 -import React from 'react'; +import React, { useMemo } from 'react'; import classNames from 'classnames'; import { Button, Image } from 'stremio/common'; import styles from './Cell.less'; type Props = { - today: number | null, + selected: CalendarDate | null, + monthInfo: CalendarMonthInfo, date: CalendarDate, items: CalendarContentItem[], onClick: (date: CalendarDate) => void, }; -const Cell = ({ today, date, items, onClick }: Props) => { +const Cell = ({ selected, monthInfo, date, items, onClick }: Props) => { + const [active, today, past] = useMemo(() => { + const active = date.day === selected?.day; + const today = date.day === monthInfo.today; + const past = date.day < (monthInfo.today ?? 1); + + return [active, today, past]; + }, [selected, monthInfo, date]); + const onCellClick = () => { onClick && onClick(date); }; return ( -
+
{date.day} diff --git a/src/routes/Calendar/Table/Table.tsx b/src/routes/Calendar/Table/Table.tsx index e09366bb0..b42579369 100644 --- a/src/routes/Calendar/Table/Table.tsx +++ b/src/routes/Calendar/Table/Table.tsx @@ -9,11 +9,12 @@ const WEEK_DAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Satu type Props = { items: CalendarItem[], + selected: CalendarDate | null, monthInfo: CalendarMonthInfo, onChange: (date: CalendarDate) => void, }; -const Table = ({ items, monthInfo, onChange }: Props) => { +const Table = ({ items, selected, monthInfo, onChange }: Props) => { const { t } = useTranslation(); const cellsOffset = useMemo(() => { @@ -42,7 +43,8 @@ const Table = ({ items, monthInfo, onChange }: Props) => { )) From e7ddbcf38354bdb409832fcacba8ba8b5ab2923c Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 3 Jul 2024 18:03:23 +0200 Subject: [PATCH 009/336] refactor: use shared HorizontalScroll component for Chips and Calendar --- src/common/Chips/Chips.less | 15 ------- src/common/Chips/Chips.tsx | 27 ++----------- .../HorizontalScroll/HorizontalScroll.less | 20 ++++++++++ .../HorizontalScroll/HorizontalScroll.tsx | 40 +++++++++++++++++++ src/common/HorizontalScroll/index.ts | 4 ++ src/common/index.js | 2 + src/routes/Calendar/Table/Cell/Cell.less | 1 - src/routes/Calendar/Table/Cell/Cell.tsx | 6 +-- 8 files changed, 73 insertions(+), 42 deletions(-) create mode 100644 src/common/HorizontalScroll/HorizontalScroll.less create mode 100644 src/common/HorizontalScroll/HorizontalScroll.tsx create mode 100644 src/common/HorizontalScroll/index.ts diff --git a/src/common/Chips/Chips.less b/src/common/Chips/Chips.less index cf0e85917..7d7e15d18 100644 --- a/src/common/Chips/Chips.less +++ b/src/common/Chips/Chips.less @@ -1,7 +1,5 @@ // Copyright (C) 2017-2024 Smart code 203358507 -@mask-width: 10%; - .chips { position: relative; width: 100%; @@ -9,17 +7,4 @@ align-items: center; justify-content: flex-start; gap: 1rem; - overflow-x: auto; - - &.left { - mask-image: linear-gradient(90deg, rgba(0, 0, 0, 1) calc(100% - @mask-width), rgba(0, 0, 0, 0) 100%); - } - - &.right { - mask-image: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) @mask-width); - } - - &.center { - mask-image: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) @mask-width, rgba(0, 0, 0, 1) calc(100% - @mask-width), rgba(0, 0, 0, 0) 100%); - } } \ No newline at end of file diff --git a/src/common/Chips/Chips.tsx b/src/common/Chips/Chips.tsx index 4e02c620f..e07b00e8c 100644 --- a/src/common/Chips/Chips.tsx +++ b/src/common/Chips/Chips.tsx @@ -1,7 +1,7 @@ // Copyright (C) 2017-2024 Smart code 203358507 -import React, { memo, useEffect, useRef, useState } from 'react'; -import classNames from 'classnames'; +import React, { memo } from 'react'; +import HorizontalScroll from '../HorizontalScroll'; import Chip from './Chip'; import styles from './Chips.less'; @@ -16,28 +16,9 @@ type Props = { onSelect: (value: string) => {}, }; -const SCROLL_THRESHOLD = 1; - const Chips = memo(({ options, selected, onSelect }: Props) => { - const ref = useRef(null); - const [scrollPosition, setScrollPosition] = useState('left'); - - useEffect(() => { - const onScroll = ({ target }: Event) => { - const { scrollLeft, scrollWidth, offsetWidth} = target as HTMLDivElement; - const position = - (scrollLeft - SCROLL_THRESHOLD) <= 0 ? 'left' : - (scrollLeft + offsetWidth + SCROLL_THRESHOLD) >= scrollWidth ? 'right' : - 'center'; - setScrollPosition(position); - }; - - ref.current?.addEventListener('scroll', onScroll); - return () => ref.current?.removeEventListener('scroll', onScroll); - }, []); - return ( -
+ { options.map(({ label, value }) => ( { /> )) } -
+ ); }); diff --git a/src/common/HorizontalScroll/HorizontalScroll.less b/src/common/HorizontalScroll/HorizontalScroll.less new file mode 100644 index 000000000..cb4b9be7c --- /dev/null +++ b/src/common/HorizontalScroll/HorizontalScroll.less @@ -0,0 +1,20 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +@mask-width: 10%; + +.horizontal-scroll { + position: relative; + overflow-x: auto; + + &.left { + mask-image: linear-gradient(90deg, rgba(0, 0, 0, 1) calc(100% - @mask-width), rgba(0, 0, 0, 0) 100%); + } + + &.right { + mask-image: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) @mask-width); + } + + &.center { + mask-image: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) @mask-width, rgba(0, 0, 0, 1) calc(100% - @mask-width), rgba(0, 0, 0, 0) 100%); + } +} diff --git a/src/common/HorizontalScroll/HorizontalScroll.tsx b/src/common/HorizontalScroll/HorizontalScroll.tsx new file mode 100644 index 000000000..b4c23b19b --- /dev/null +++ b/src/common/HorizontalScroll/HorizontalScroll.tsx @@ -0,0 +1,40 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React, { useRef, useEffect, useState } from 'react'; +import classNames from 'classnames'; +import styles from './HorizontalScroll.less'; + +const SCROLL_THRESHOLD = 1; + +type Props = { + className: string, + children: React.ReactNode, +}; + +const HorizontalScroll = ({ className, children }: Props) => { + const ref = useRef(null); + const [scrollPosition, setScrollPosition] = useState('left'); + + useEffect(() => { + const onScroll = ({ target }: Event) => { + const { scrollLeft, scrollWidth, offsetWidth } = target as HTMLDivElement; + + setScrollPosition(() => ( + (scrollLeft - SCROLL_THRESHOLD) <= 0 ? 'left' : + (scrollLeft + offsetWidth + SCROLL_THRESHOLD) >= scrollWidth ? 'right' : + 'center' + )); + }; + + ref.current?.addEventListener('scroll', onScroll); + return () => ref.current?.removeEventListener('scroll', onScroll); + }, []); + + return ( +
+ {children} +
+ ); +}; + +export default HorizontalScroll; diff --git a/src/common/HorizontalScroll/index.ts b/src/common/HorizontalScroll/index.ts new file mode 100644 index 000000000..4fc875461 --- /dev/null +++ b/src/common/HorizontalScroll/index.ts @@ -0,0 +1,4 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import HorizontalScroll from './HorizontalScroll'; +export default HorizontalScroll; diff --git a/src/common/index.js b/src/common/index.js index 8046dab15..fd4f838db 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -16,6 +16,7 @@ const MetaRow = require('./MetaRow'); const ModalDialog = require('./ModalDialog'); const Multiselect = require('./Multiselect'); const { HorizontalNavBar, VerticalNavBar } = require('./NavBar'); +const { default: HorizontalScroll } = require('./HorizontalScroll'); const PaginationInput = require('./PaginationInput'); const PlayIconCircleCentered = require('./PlayIconCircleCentered'); const Popup = require('./Popup'); @@ -64,6 +65,7 @@ module.exports = { ModalDialog, Multiselect, HorizontalNavBar, + HorizontalScroll, VerticalNavBar, PaginationInput, PlayIconCircleCentered, diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less index a9a7117b7..25b7b4a48 100644 --- a/src/routes/Calendar/Table/Cell/Cell.less +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -45,7 +45,6 @@ gap: 1rem; height: 0; padding: 1rem; - overflow-x: scroll; .item { flex: none; diff --git a/src/routes/Calendar/Table/Cell/Cell.tsx b/src/routes/Calendar/Table/Cell/Cell.tsx index d54f05e24..471ecc4f6 100644 --- a/src/routes/Calendar/Table/Cell/Cell.tsx +++ b/src/routes/Calendar/Table/Cell/Cell.tsx @@ -2,7 +2,7 @@ import React, { useMemo } from 'react'; import classNames from 'classnames'; -import { Button, Image } from 'stremio/common'; +import { Button, Image, HorizontalScroll } from 'stremio/common'; import styles from './Cell.less'; type Props = { @@ -37,7 +37,7 @@ const Cell = ({ selected, monthInfo, date, items, onClick }: Props) => { {date.day}
-
+ { items.map(({ id, name, poster, deepLinks }) => ( )) } -
+
); }; From a561ee0e3e948eb19304688c87c57858ec878f4f Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 4 Jul 2024 06:44:41 +0200 Subject: [PATCH 010/336] feat(Calendar): add play icons on items --- src/routes/Calendar/List/Item/Item.less | 20 ++++++++++++++ src/routes/Calendar/List/Item/Item.tsx | 2 ++ src/routes/Calendar/Table/Cell/Cell.less | 34 ++++++++++++++++++++++++ src/routes/Calendar/Table/Cell/Cell.tsx | 2 ++ 4 files changed, 58 insertions(+) diff --git a/src/routes/Calendar/List/Item/Item.less b/src/routes/Calendar/List/Item/Item.less index beb874f6b..a2e8effa7 100644 --- a/src/routes/Calendar/List/Item/Item.less +++ b/src/routes/Calendar/List/Item/Item.less @@ -49,10 +49,30 @@ .info { flex: none; + display: block; + } + + .icon { + flex: none; + display: none; + width: 2rem; + height: 2rem; + padding: 0.5rem; + border-radius: 50%; + color: var(--primary-foreground-color); + background-color: var(--secondary-accent-color); } &:hover { background-color: var(--overlay-color); + + .info { + display: none; + } + + .icon { + display: block; + } } } } diff --git a/src/routes/Calendar/List/Item/Item.tsx b/src/routes/Calendar/List/Item/Item.tsx index 64e9cc03c..cc48d5197 100644 --- a/src/routes/Calendar/List/Item/Item.tsx +++ b/src/routes/Calendar/List/Item/Item.tsx @@ -1,6 +1,7 @@ // Copyright (C) 2017-2024 Smart code 203358507 import React, { useEffect, useMemo, useRef } from 'react'; +import Icon from '@stremio/stremio-icons/react'; import classNames from 'classnames'; import { Button } from 'stremio/common'; import useCalendarDate from '../../useCalendarDate'; @@ -58,6 +59,7 @@ const Item = ({ selected, monthInfo, date, items, profile, onClick }: Props) =>
S{season}E{episode}
+ )) } diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less index 25b7b4a48..c47fc4901 100644 --- a/src/routes/Calendar/Table/Cell/Cell.less +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -48,14 +48,48 @@ .item { flex: none; + display: flex; + align-items: center; + justify-content: center; height: 100%; aspect-ratio: 2 / 3; border-radius: var(--border-radius); + .icon { + flex: none; + z-index: 1; + position: absolute; + width: 2rem; + height: 2rem; + padding: 0.5rem; + border-radius: 50%; + color: var(--primary-foreground-color); + background-color: var(--secondary-accent-color); + opacity: 0; + } + .poster { + flex: auto; + z-index: 0; + position: relative; height: 100%; width: 100%; object-fit: cover; + opacity: 1; + } + + .icon, .poster { + transition: opacity 0.1s ease-out; + } + + &:hover { + .icon { + opacity: 1; + } + + .poster { + opacity: 0.5; + } } } } diff --git a/src/routes/Calendar/Table/Cell/Cell.tsx b/src/routes/Calendar/Table/Cell/Cell.tsx index 471ecc4f6..76442a640 100644 --- a/src/routes/Calendar/Table/Cell/Cell.tsx +++ b/src/routes/Calendar/Table/Cell/Cell.tsx @@ -1,6 +1,7 @@ // Copyright (C) 2017-2024 Smart code 203358507 import React, { useMemo } from 'react'; +import Icon from '@stremio/stremio-icons/react'; import classNames from 'classnames'; import { Button, Image, HorizontalScroll } from 'stremio/common'; import styles from './Cell.less'; @@ -41,6 +42,7 @@ const Cell = ({ selected, monthInfo, date, items, onClick }: Props) => { { items.map(({ id, name, poster, deepLinks }) => (
- + { items.map(({ id, name, poster, deepLinks }) => ( ); }; From fe663f1d2bf705c9e864e5f1c9c3cb8dde39efbd Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 4 Jul 2024 21:09:08 +0300 Subject: [PATCH 015/336] feat: arrows hover effect --- src/common/PaginationInput/styles.less | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/common/PaginationInput/styles.less b/src/common/PaginationInput/styles.less index ecf6c56a4..9005fefa5 100644 --- a/src/common/PaginationInput/styles.less +++ b/src/common/PaginationInput/styles.less @@ -17,6 +17,12 @@ .icon { display: block; color: var(--primary-foreground-color); + opacity: 0.7; + transition: opacity 0.2s ease-in-out; + + &:hover { + opacity: 1; + } } } From c5efdcb74fcc6b5646e5ed8559a5c6efd35e4d78 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 4 Jul 2024 21:19:24 +0300 Subject: [PATCH 016/336] fix: chips offset --- src/common/Chips/Chip/Chip.less | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/common/Chips/Chip/Chip.less b/src/common/Chips/Chip/Chip.less index 2adbcb727..b71a7b6b6 100644 --- a/src/common/Chips/Chip/Chip.less +++ b/src/common/Chips/Chip/Chip.less @@ -20,14 +20,16 @@ background-color: transparent; user-select: none; overflow: hidden; + opacity: 0.6; &:hover { background-color: var(--overlay-color); transition: background-color 0.1s ease-out; + opacity: 1; } &.active { - font-weight: 700; + opacity: 1; background-color: var(--quaternary-accent-color); transition: background-color 0.1s ease-in; } From 13aeae0c302ca07322f7120d06e3f39abe81d80c Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 4 Jul 2024 21:44:51 +0300 Subject: [PATCH 017/336] refactor: imports --- src/routes/Calendar/Calendar.tsx | 6 +++--- src/routes/Calendar/List/Item/index.ts | 5 +++++ src/routes/Calendar/List/List.tsx | 2 +- src/routes/Calendar/List/index.ts | 5 +++++ src/routes/Calendar/Placeholder/index.ts | 5 +++++ src/routes/Calendar/Table/Cell/index.ts | 5 +++++ src/routes/Calendar/Table/index.ts | 5 +++++ 7 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/routes/Calendar/List/Item/index.ts create mode 100644 src/routes/Calendar/List/index.ts create mode 100644 src/routes/Calendar/Placeholder/index.ts create mode 100644 src/routes/Calendar/Table/Cell/index.ts create mode 100644 src/routes/Calendar/Table/index.ts diff --git a/src/routes/Calendar/Calendar.tsx b/src/routes/Calendar/Calendar.tsx index 65ad50a0b..267d6f523 100644 --- a/src/routes/Calendar/Calendar.tsx +++ b/src/routes/Calendar/Calendar.tsx @@ -2,11 +2,11 @@ import React, { useState } from 'react'; import { MainNavBars, PaginationInput, useProfile, withCoreSuspender } from 'stremio/common'; +import Table from './Table'; +import List from './List'; +import Placeholder from './Placeholder'; import useCalendar from './useCalendar'; import useSelectableInputs from './useSelectableInputs'; -import Table from './Table/Table'; -import List from './List/List'; -import Placeholder from './Placeholder/Placeholder'; import styles from './Calendar.less'; type Props = { diff --git a/src/routes/Calendar/List/Item/index.ts b/src/routes/Calendar/List/Item/index.ts new file mode 100644 index 000000000..2ad36845c --- /dev/null +++ b/src/routes/Calendar/List/Item/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import Item from './Item'; + +export default Item; \ No newline at end of file diff --git a/src/routes/Calendar/List/List.tsx b/src/routes/Calendar/List/List.tsx index 78e444362..13745e380 100644 --- a/src/routes/Calendar/List/List.tsx +++ b/src/routes/Calendar/List/List.tsx @@ -1,7 +1,7 @@ // Copyright (C) 2017-2024 Smart code 203358507 import React, { useMemo } from 'react'; -import Item from './Item/Item'; +import Item from './Item'; import styles from './List.less'; type Props = { diff --git a/src/routes/Calendar/List/index.ts b/src/routes/Calendar/List/index.ts new file mode 100644 index 000000000..60ed2cd85 --- /dev/null +++ b/src/routes/Calendar/List/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import List from './List'; + +export default List; \ No newline at end of file diff --git a/src/routes/Calendar/Placeholder/index.ts b/src/routes/Calendar/Placeholder/index.ts new file mode 100644 index 000000000..9982f89a2 --- /dev/null +++ b/src/routes/Calendar/Placeholder/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import Placeholder from './Placeholder'; + +export default Placeholder; \ No newline at end of file diff --git a/src/routes/Calendar/Table/Cell/index.ts b/src/routes/Calendar/Table/Cell/index.ts new file mode 100644 index 000000000..487e0fa63 --- /dev/null +++ b/src/routes/Calendar/Table/Cell/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import Cell from './Cell'; + +export default Cell; \ No newline at end of file diff --git a/src/routes/Calendar/Table/index.ts b/src/routes/Calendar/Table/index.ts new file mode 100644 index 000000000..1cabcf509 --- /dev/null +++ b/src/routes/Calendar/Table/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import Table from './Table'; + +export default Table; \ No newline at end of file From b6eef9a289e7ecde68a849c38785501f9337ab54 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 5 Jul 2024 06:08:10 +0200 Subject: [PATCH 018/336] fix(Calendar): cells border radius --- src/routes/Calendar/Table/Cell/Cell.less | 8 ++++++++ src/routes/Calendar/Table/Table.less | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less index c220df50f..b9cdd5507 100644 --- a/src/routes/Calendar/Table/Cell/Cell.less +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -17,6 +17,14 @@ border-radius: var(--border-radius) 0 0 0; } + &:nth-child(7) { + border-radius: 0 var(--border-radius) 0 0; + } + + &:nth-child(29) { + border-radius: 0 0 0 var(--border-radius); + } + &:last-child { border-radius: 0 0 var(--border-radius) 0; } diff --git a/src/routes/Calendar/Table/Table.less b/src/routes/Calendar/Table/Table.less index 4fa20a6fb..65a9b01e9 100644 --- a/src/routes/Calendar/Table/Table.less +++ b/src/routes/Calendar/Table/Table.less @@ -45,7 +45,6 @@ display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; - border-radius: var(--border-radius); } } From 076c1e0701447bec15530ade84a0c0071bc4583c Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 5 Jul 2024 06:12:22 +0200 Subject: [PATCH 019/336] fix(Calendar): list items border radius --- src/routes/Calendar/List/Item/Item.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/routes/Calendar/List/Item/Item.less b/src/routes/Calendar/List/Item/Item.less index a2e8effa7..cdcb708b8 100644 --- a/src/routes/Calendar/List/Item/Item.less +++ b/src/routes/Calendar/List/Item/Item.less @@ -40,6 +40,10 @@ font-weight: 500; color: var(--primary-foreground-color); + &:last-child { + border-radius: 0 0 var(--border-radius) var(--border-radius); + } + .name { flex: auto; white-space: nowrap; From 28d5252b11db5b93efb3708bc6bec185fd8111da Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Mon, 22 Jul 2024 14:06:11 +0300 Subject: [PATCH 020/336] fix: Streaming server settings - use empty string instead of null for remoteHttps Signed-off-by: Lachezar Lechev --- src/routes/Settings/useStreamingServerSettingsInputs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Settings/useStreamingServerSettingsInputs.js b/src/routes/Settings/useStreamingServerSettingsInputs.js index 32fb971a5..1d4eee066 100644 --- a/src/routes/Settings/useStreamingServerSettingsInputs.js +++ b/src/routes/Settings/useStreamingServerSettingsInputs.js @@ -70,7 +70,7 @@ const useStreamingServerSettingsInputs = (streamingServer) => { options: [ { label: t('SETTINGS_DISABLED'), - value: null, + value: '', }, ...streamingServer.networkInfo.content.availableInterfaces.map((address) => ({ label: address, From 6a5dcb9fae508fa661461a3cd3354a048f05da13 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Wed, 24 Jul 2024 16:11:41 +0300 Subject: [PATCH 021/336] feature: multiselect menu --- .../MultiselectMenu/Dropdown/Dropdown.less | 30 ++++++++++ .../MultiselectMenu/Dropdown/Dropdown.tsx | 53 ++++++++++++++++++ .../Dropdown/Option/Option.less | 30 ++++++++++ .../Dropdown/Option/Option.tsx | 42 ++++++++++++++ .../MultiselectMenu/Dropdown/Option/index.ts | 5 ++ src/common/MultiselectMenu/Dropdown/index.ts | 5 ++ .../MultiselectMenu/MultiselectMenu.less | 34 +++++++++++ .../MultiselectMenu/MultiselectMenu.tsx | 56 +++++++++++++++++++ src/common/MultiselectMenu/index.ts | 5 ++ src/common/MultiselectMenu/types.d.ts | 9 +++ src/common/index.js | 2 + .../VideosList/SeasonsBar/SeasonsBar.js | 14 ++--- 12 files changed, 278 insertions(+), 7 deletions(-) create mode 100644 src/common/MultiselectMenu/Dropdown/Dropdown.less create mode 100644 src/common/MultiselectMenu/Dropdown/Dropdown.tsx create mode 100644 src/common/MultiselectMenu/Dropdown/Option/Option.less create mode 100644 src/common/MultiselectMenu/Dropdown/Option/Option.tsx create mode 100644 src/common/MultiselectMenu/Dropdown/Option/index.ts create mode 100644 src/common/MultiselectMenu/Dropdown/index.ts create mode 100644 src/common/MultiselectMenu/MultiselectMenu.less create mode 100644 src/common/MultiselectMenu/MultiselectMenu.tsx create mode 100644 src/common/MultiselectMenu/index.ts create mode 100644 src/common/MultiselectMenu/types.d.ts diff --git a/src/common/MultiselectMenu/Dropdown/Dropdown.less b/src/common/MultiselectMenu/Dropdown/Dropdown.less new file mode 100644 index 000000000..1e15419ef --- /dev/null +++ b/src/common/MultiselectMenu/Dropdown/Dropdown.less @@ -0,0 +1,30 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +.dropdown { + background: var(--modal-background-color); + display: none; + position: absolute; + width: 100%; + top: 100%; + left: 0; + z-index: 10; + box-shadow: var(--outer-glow); + border-radius: var(--border-radius); + overflow: hidden; + + &.open { + display: block; + } + + .back-button { + display: flex; + align-items: center; + gap: 0 0.5rem; + padding: 0.75rem; + color: var(--primary-foreground-color); + + .back-button-icon { + width: 1.5rem; + } + } +} \ No newline at end of file diff --git a/src/common/MultiselectMenu/Dropdown/Dropdown.tsx b/src/common/MultiselectMenu/Dropdown/Dropdown.tsx new file mode 100644 index 000000000..1c09de925 --- /dev/null +++ b/src/common/MultiselectMenu/Dropdown/Dropdown.tsx @@ -0,0 +1,53 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React from 'react'; +import Button from 'stremio/common/Button'; +import { useTranslation } from 'react-i18next'; +import classNames from 'classnames'; +import Option from './Option'; +import Icon from '@stremio/stremio-icons/react'; +import styles from './Dropdown.less'; + +type Props = { + options: MultiselectMenuOption[]; + selectedOption?: MultiselectMenuOption | null; + menuOpen: boolean | (() => void); + level: number; + setLevel: (level: number) => void; + onSelect: (option: MultiselectMenuOption) => void; +}; + +const Dropdown = ({ level, setLevel, options, onSelect, selectedOption, menuOpen }: Props) => { + const { t } = useTranslation(); + const onBackButtonClick = () => { + setLevel(level - 1); + }; + + return ( +
+ { + level > 0 ? + + : null + } + { + options + .filter((option: MultiselectMenuOption) => !option.hidden) + .map((option: MultiselectMenuOption) => ( +
+ ); +}; + +export default Dropdown; \ No newline at end of file diff --git a/src/common/MultiselectMenu/Dropdown/Option/Option.less b/src/common/MultiselectMenu/Dropdown/Option/Option.less new file mode 100644 index 000000000..067934dfc --- /dev/null +++ b/src/common/MultiselectMenu/Dropdown/Option/Option.less @@ -0,0 +1,30 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +.option { + font-size: var(--font-size-normal); + color: var(--primary-foreground-color); + align-items: center; + display: flex; + flex-direction: row; + padding: 1rem; + + .label { + flex: 1; + color: var(--primary-foreground-color); + } + + .icon { + flex: none; + // display: none; + width: 0.5rem; + height: 0.5rem; + border-radius: 100%; + margin-left: 1rem; + background-color: var(--secondary-accent-color); + opacity: 1; + } + + &:hover { + background-color: rgba(255, 255, 255, 0.15); + } +} \ No newline at end of file diff --git a/src/common/MultiselectMenu/Dropdown/Option/Option.tsx b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx new file mode 100644 index 000000000..7ade6dfa5 --- /dev/null +++ b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx @@ -0,0 +1,42 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React, { useMemo } from 'react'; +import classNames from 'classnames'; +import Button from 'stremio/common/Button'; +import styles from './Option.less'; +import Icon from '@stremio/stremio-icons/react'; + +type Props = { + option: MultiselectMenuOption; + selectedOption?: MultiselectMenuOption | null; + onSelect: (option: MultiselectMenuOption) => void; +}; + +const Option = ({ option, selectedOption, onSelect }: Props) => { + // consider using option.id === selectedOption?.id instead + const selected = useMemo(() => option?.value === selectedOption?.value, [option, selectedOption]); + + return ( + + ); +}; + +export default Option; \ No newline at end of file diff --git a/src/common/MultiselectMenu/Dropdown/Option/index.ts b/src/common/MultiselectMenu/Dropdown/Option/index.ts new file mode 100644 index 000000000..6004f7754 --- /dev/null +++ b/src/common/MultiselectMenu/Dropdown/Option/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import Option from './Option'; + +export default Option; \ No newline at end of file diff --git a/src/common/MultiselectMenu/Dropdown/index.ts b/src/common/MultiselectMenu/Dropdown/index.ts new file mode 100644 index 000000000..ce3622a25 --- /dev/null +++ b/src/common/MultiselectMenu/Dropdown/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import Dropdown from './Dropdown'; + +export default Dropdown; \ No newline at end of file diff --git a/src/common/MultiselectMenu/MultiselectMenu.less b/src/common/MultiselectMenu/MultiselectMenu.less new file mode 100644 index 000000000..156e2035d --- /dev/null +++ b/src/common/MultiselectMenu/MultiselectMenu.less @@ -0,0 +1,34 @@ + +@border-radius: 2.75rem; + +.multiselect-menu { + background-color: var(--overlay-color); + position: relative; + min-width: 150px; + overflow: visible; + border-radius: @border-radius; + &.disabled { + pointer-events: none; + opacity: 0.3; + } + + .multiselect-button { + color: var(--primary-foreground-color); + background-color: rgba(255, 255, 255, 0.05); + padding: 0.75rem 1.5rem; + display: flex; + justify-content: space-between; + align-items: center; + gap: 0 0.5rem; + border-radius: @border-radius; + + .icon { + width: 1.5rem; + color: var(--primary-foreground-color); + + &.open { + transform: rotate(180deg); + } + } + } +} \ No newline at end of file diff --git a/src/common/MultiselectMenu/MultiselectMenu.tsx b/src/common/MultiselectMenu/MultiselectMenu.tsx new file mode 100644 index 000000000..5eb073eca --- /dev/null +++ b/src/common/MultiselectMenu/MultiselectMenu.tsx @@ -0,0 +1,56 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React from 'react'; +import Button from 'stremio/common/Button'; +import useBinaryState from 'stremio/common/useBinaryState'; +import Dropdown from './Dropdown'; +import classNames from 'classnames'; +import Icon from '@stremio/stremio-icons/react'; +import styles from './MultiselectMenu.less'; + +type Props = { + className?: string, + title?: string; + options: MultiselectMenuOption[]; + selectedOption?: MultiselectMenuOption; + onSelect: () => void; +}; + +const MultiselectMenu = ({ className, title, options, selectedOption, onSelect }: Props) => { + const [menuOpen, , closeMenu, toggleMenu] = useBinaryState(false); + const multiselectMenuRef = React.useRef(null); + const [level, setLevel] = React.useState(0); + + const onOptionSelect = (option: MultiselectMenuOption) => { + option.level ? setLevel(level + 1) : onSelect(), closeMenu(); + }; + + return ( +
+ + { + menuOpen ? + + : null + } +
+ ); +}; + +export default MultiselectMenu; \ No newline at end of file diff --git a/src/common/MultiselectMenu/index.ts b/src/common/MultiselectMenu/index.ts new file mode 100644 index 000000000..e526218cd --- /dev/null +++ b/src/common/MultiselectMenu/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import MultiselectMenu from './MultiselectMenu'; + +export default MultiselectMenu; \ No newline at end of file diff --git a/src/common/MultiselectMenu/types.d.ts b/src/common/MultiselectMenu/types.d.ts new file mode 100644 index 000000000..a1724ab9b --- /dev/null +++ b/src/common/MultiselectMenu/types.d.ts @@ -0,0 +1,9 @@ +type MultiselectMenuOption = { + id?: number; + label: string; + value: string; + destination?: string; + default?: boolean; + hidden?: boolean; + level?: MultiselectMenuOption[]; +}; \ No newline at end of file diff --git a/src/common/index.js b/src/common/index.js index 8046dab15..c582a13ca 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -15,6 +15,7 @@ const MetaPreview = require('./MetaPreview'); const MetaRow = require('./MetaRow'); const ModalDialog = require('./ModalDialog'); const Multiselect = require('./Multiselect'); +const { default: MultiselectMenu } = require('./MultiselectMenu'); const { HorizontalNavBar, VerticalNavBar } = require('./NavBar'); const PaginationInput = require('./PaginationInput'); const PlayIconCircleCentered = require('./PlayIconCircleCentered'); @@ -63,6 +64,7 @@ module.exports = { MetaRow, ModalDialog, Multiselect, + MultiselectMenu, HorizontalNavBar, VerticalNavBar, PaginationInput, diff --git a/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js index d75080d01..6ecc2c815 100644 --- a/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js +++ b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js @@ -5,9 +5,10 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const { t } = require('i18next'); const { default: Icon } = require('@stremio/stremio-icons/react'); -const { Button, Multiselect } = require('stremio/common'); +const { Button } = require('stremio/common'); const SeasonsBarPlaceholder = require('./SeasonsBarPlaceholder'); const styles = require('./styles'); +const { MultiselectMenu } = require('stremio/common'); const SeasonsBar = ({ className, seasons, season, onSelect }) => { const options = React.useMemo(() => { @@ -16,8 +17,8 @@ const SeasonsBar = ({ className, seasons, season, onSelect }) => { label: season > 0 ? `${t('SEASON')} ${season}` : t('SPECIAL') })); }, [seasons]); - const selected = React.useMemo(() => { - return [String(season)]; + const selectedSeason = React.useMemo(() => { + return { label: String(season), value: String(season) }; }, [season]); const prevNextButtonOnClick = React.useCallback((event) => { if (typeof onSelect === 'function') { @@ -61,12 +62,11 @@ const SeasonsBar = ({ className, seasons, season, onSelect }) => {
Prev
- 0 ? `${t('SEASON')} ${season}` : t('SPECIAL')} - direction={'bottom-left'} options={options} - selected={selected} + title={season > 0 ? `${t('SEASON')} ${season}` : t('SPECIAL')} + selectedOption={selectedSeason} onSelect={seasonOnSelect} /> : null diff --git a/src/common/MultiselectMenu/Dropdown/Option/Option.less b/src/common/MultiselectMenu/Dropdown/Option/Option.less index 067934dfc..a0ee1743f 100644 --- a/src/common/MultiselectMenu/Dropdown/Option/Option.less +++ b/src/common/MultiselectMenu/Dropdown/Option/Option.less @@ -15,7 +15,6 @@ .icon { flex: none; - // display: none; width: 0.5rem; height: 0.5rem; border-radius: 100%; diff --git a/src/common/MultiselectMenu/Dropdown/Option/Option.tsx b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx index 28a431b1f..4309e766e 100644 --- a/src/common/MultiselectMenu/Dropdown/Option/Option.tsx +++ b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx @@ -9,7 +9,7 @@ import Icon from '@stremio/stremio-icons/react'; type Props = { option: MultiselectMenuOption; selectedOption?: MultiselectMenuOption | null; - onSelect: (value: string) => void; + onSelect: (value: number) => void; }; const Option = ({ option, selectedOption, onSelect }: Props) => { @@ -32,7 +32,7 @@ const Option = ({ option, selectedOption, onSelect }: Props) => { } { option.level ? - + : null } diff --git a/src/common/MultiselectMenu/MultiselectMenu.less b/src/common/MultiselectMenu/MultiselectMenu.less index 58eec12dd..3c7b81b59 100644 --- a/src/common/MultiselectMenu/MultiselectMenu.less +++ b/src/common/MultiselectMenu/MultiselectMenu.less @@ -3,11 +3,11 @@ @border-radius: 2.75rem; .multiselect-menu { - background-color: var(--overlay-color); position: relative; - min-width: 150px; + min-width: 8.5rem; overflow: visible; border-radius: @border-radius; + &.disabled { pointer-events: none; opacity: 0.3; @@ -15,7 +15,6 @@ .multiselect-button { color: var(--primary-foreground-color); - background-color: rgba(255, 255, 255, 0.05); padding: 0.75rem 1.5rem; display: flex; justify-content: space-between; @@ -24,12 +23,17 @@ border-radius: @border-radius; .icon { - width: 1.5rem; + width: 1rem; color: var(--primary-foreground-color); + opacity: 0.6; &.open { transform: rotate(180deg); } } } + + &:hover { + background-color: var(--overlay-color); + } } \ No newline at end of file diff --git a/src/common/MultiselectMenu/MultiselectMenu.tsx b/src/common/MultiselectMenu/MultiselectMenu.tsx index 030b097da..2bd298752 100644 --- a/src/common/MultiselectMenu/MultiselectMenu.tsx +++ b/src/common/MultiselectMenu/MultiselectMenu.tsx @@ -14,7 +14,7 @@ type Props = { title?: string; options: MultiselectMenuOption[]; selectedOption?: MultiselectMenuOption; - onSelect: (event: any) => void; + onSelect: (value: number) => void; }; const MultiselectMenu = ({ className, title, options, selectedOption, onSelect }: Props) => { @@ -22,9 +22,8 @@ const MultiselectMenu = ({ className, title, options, selectedOption, onSelect } const multiselectMenuRef = useOutsideClick(() => closeMenu()); const [level, setLevel] = React.useState(0); - const onOptionSelect = (event: any) => { - console.log(event.value); - level ? setLevel(level + 1) : onSelect(event), closeMenu(); + const onOptionSelect = (value: number) => { + level ? setLevel(level + 1) : onSelect(value), closeMenu(); }; return ( @@ -37,7 +36,7 @@ const MultiselectMenu = ({ className, title, options, selectedOption, onSelect } aria-expanded={menuOpen} > {title} - + { menuOpen ? diff --git a/src/common/MultiselectMenu/types.d.ts b/src/common/MultiselectMenu/types.d.ts index a1724ab9b..7ed039ddd 100644 --- a/src/common/MultiselectMenu/types.d.ts +++ b/src/common/MultiselectMenu/types.d.ts @@ -1,7 +1,7 @@ type MultiselectMenuOption = { id?: number; label: string; - value: string; + value: number; destination?: string; default?: boolean; hidden?: boolean; diff --git a/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js index 6ecc2c815..71c10ce92 100644 --- a/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js +++ b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js @@ -36,8 +36,7 @@ const SeasonsBar = ({ className, seasons, season, onSelect }) => { }); } }, [season, seasons, onSelect]); - const seasonOnSelect = React.useCallback((event) => { - const value = parseFloat(event.value); + const seasonOnSelect = React.useCallback((value) => { if (typeof onSelect === 'function') { onSelect({ type: 'select', From 84ad70fc43651275d531707e6f15d9b1eeb8d940 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 25 Jul 2024 15:54:01 +0300 Subject: [PATCH 027/336] fix: Player - onSeekRequest and setting the seeking flag to true before updating the video player Signed-off-by: Lachezar Lechev --- src/routes/Player/Player.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index 521fc2387..670cd31e1 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -162,10 +162,11 @@ const Player = ({ urlParams, queryParams }) => { }, []); const onSeekRequested = React.useCallback((time) => { - video.setProp('time', time); - + // first set seeking to true and then update time! setSeeking(true); console.log(`setSeeking to (SeekRequested): true`); + + video.setProp('time', time); }, []); const onPlaybackSpeedChanged = React.useCallback((rate) => { @@ -354,11 +355,12 @@ const Player = ({ urlParams, queryParams }) => { video.state.manifest !== null && typeof video.state.manifest.name === 'string') { if (seeking) { - seek(video.state.time, video.state.duration, video.state.manifest.name) + seek(video.state.time, video.state.duration, video.state.manifest.name); setSeeking(false); console.log(`setSeeking to (on video.state.time change): false`); } else { + console.log(`time changed!`); timeChanged(video.state.time, video.state.duration, video.state.manifest.name); } } From 8d18820ca18d9d6ddac844e8b4b1bf7561a81245 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 26 Jul 2024 12:10:13 +0300 Subject: [PATCH 028/336] feat: External Players - add visionos (Vision Pro) as a platform and moonplayer url scheme Signed-off-by: Lachezar Lechev --- src/common/CONSTANTS.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/common/CONSTANTS.js b/src/common/CONSTANTS.js index aeaa51462..fef278f0b 100644 --- a/src/common/CONSTANTS.js +++ b/src/common/CONSTANTS.js @@ -44,7 +44,7 @@ const EXTERNAL_PLAYERS = [ { label: 'EXTERNAL_PLAYER_DISABLED', value: null, - platforms: ['ios', 'android', 'windows', 'linux', 'macos'], + platforms: ['ios', 'visionos', 'android', 'windows', 'linux', 'macos'], }, { label: 'EXTERNAL_PLAYER_ALLOW_CHOOSING', @@ -54,7 +54,7 @@ const EXTERNAL_PLAYERS = [ { label: 'VLC', value: 'vlc', - platforms: ['ios', 'android'], + platforms: ['ios', 'visionos', 'android'], }, { label: 'MPV', @@ -79,12 +79,17 @@ const EXTERNAL_PLAYERS = [ { label: 'Outplayer', value: 'outplayer', - platforms: ['ios'], + platforms: ['ios', 'visionos'], + }, + { + label: 'Moonplayer', + value: 'moonplayer', + platforms: ['visionos'], }, { label: 'M3U Playlist', value: 'm3u', - platforms: ['ios', 'android', 'windows', 'linux', 'macos'], + platforms: ['ios', 'visionos', 'android', 'windows', 'linux', 'macos'], }, ]; From f442df8f525ead15d171d089daf7de2a2b9905f1 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Fri, 26 Jul 2024 16:26:04 +0300 Subject: [PATCH 029/336] feat: detect vision os as a platform --- src/common/platform.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/common/platform.js b/src/common/platform.js index 1e112de6d..170967f85 100644 --- a/src/common/platform.js +++ b/src/common/platform.js @@ -1,8 +1,8 @@ -// Copyright (C) 2017-2023 Smart code 203358507 +// Copyright (C) 2017-2024 Smart code 203358507 // this detects ipad properly in safari // while bowser does not -function iOS() { +const iOS = () => { return [ 'iPad Simulator', 'iPhone Simulator', @@ -11,14 +11,20 @@ function iOS() { 'iPhone', 'iPod' ].includes(navigator.platform) - || (navigator.userAgent.includes('Mac') && 'ontouchend' in document); -} + || (navigator.userAgent.includes('Mac') && 'ontouchend' in document); +}; const Bowser = require('bowser'); const browser = Bowser.parse(window.navigator?.userAgent || ''); -const name = iOS() ? 'ios' : (browser?.os?.name || 'unknown').toLowerCase(); +const isVisionProUser = () => { + const isMacintosh = navigator.userAgent.includes('Macintosh'); + const hasFiveTouchPoints = navigator.maxTouchPoints === 5; + return isMacintosh && hasFiveTouchPoints; +}; + +const name = isVisionProUser() ? 'visionos' : (iOS() ? 'ios' : (browser?.os?.name || 'unknown').toLowerCase()); module.exports = { name, From 85b0391cbcc443591e791754909853727bf3ad84 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 26 Jul 2024 17:09:56 +0300 Subject: [PATCH 030/336] chore: stremio-core-web - use GH pages version for the feature Signed-off-by: Lachezar Lechev --- package-lock.json | 7 ++++--- package.json | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 351558728..6854816cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.47.7", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", @@ -2972,8 +2972,9 @@ }, "node_modules/@stremio/stremio-core-web": { "version": "0.47.7", - "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.47.7.tgz", - "integrity": "sha512-3hTie3Yx6198TY1rS2fdA5HKPmejqTDbE8C05+HdqM6oXor9TXVoSjY9AMPlSVUJvu40sP3oeenhe2MRBUQizw==", + "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", + "integrity": "sha512-JnnFAlSkLUc+Cl+W1KhpCqLrTnjJPmc1PpDojYF2BIVzvSmwi4VRA8FinxI5c+Nn4LQ2xS8afRBnE1p/X0PxlA==", + "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" } diff --git a/package.json b/package.json index 9c2fa37de..ed216269d 100755 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "license": "gpl-2.0", "scripts": { "start": "webpack serve --mode development", + "start-prod": "webpack serve --mode production", "build": "webpack --mode production", "test": "jest", "lint": "eslint src" @@ -15,7 +16,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.47.7", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", From fd5cad6fef54373d549b4488c4b72ca7dda2d4a7 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 26 Jul 2024 19:19:36 +0200 Subject: [PATCH 031/336] chore: update stremio-core-web --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 6854816cc..6cf8288b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2973,7 +2973,7 @@ "node_modules/@stremio/stremio-core-web": { "version": "0.47.7", "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", - "integrity": "sha512-JnnFAlSkLUc+Cl+W1KhpCqLrTnjJPmc1PpDojYF2BIVzvSmwi4VRA8FinxI5c+Nn4LQ2xS8afRBnE1p/X0PxlA==", + "integrity": "sha512-DGEgZQPqmp5Dvsbw6CTHuRmG5iEV+xWIfKqoiUUy6m8cFkYARcFseMz1TlUiOScJaYNg4yLAhHQ8YO85JU3yKA==", "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" From 8a3fb4cf17876e47c69a2b78232c096c22c85b72 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 26 Jul 2024 19:47:39 +0200 Subject: [PATCH 032/336] chore: update stremio-core-web --- package-lock.json | 7 +++---- package.json | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6cf8288b1..73ef3f20a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-player-visionos/dev/stremio-stremio-core-web-0.47.7.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", @@ -2972,9 +2972,8 @@ }, "node_modules/@stremio/stremio-core-web": { "version": "0.47.7", - "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", - "integrity": "sha512-DGEgZQPqmp5Dvsbw6CTHuRmG5iEV+xWIfKqoiUUy6m8cFkYARcFseMz1TlUiOScJaYNg4yLAhHQ8YO85JU3yKA==", - "license": "MIT", + "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-player-visionos/dev/stremio-stremio-core-web-0.47.7.tgz", + "integrity": "sha512-7ozM/pJFsjKkgGxuDpBn6MSWbHCqsXf4VDXSlBr9+TKLK7YT6cL+lEgMVzQfksK14b3d2LcXQ3BCX2b6F7AIfg==", "dependencies": { "@babel/runtime": "7.24.1" } diff --git a/package.json b/package.json index ed216269d..5aaacf3a1 100755 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-player-visionos/dev/stremio-stremio-core-web-0.47.7.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", From e8958f2c36674dd669087d0c937887cbd8b218f2 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Mon, 29 Jul 2024 12:57:21 +0300 Subject: [PATCH 033/336] refactor: rename the Moonplayer string --- src/common/CONSTANTS.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/CONSTANTS.js b/src/common/CONSTANTS.js index fef278f0b..742c138d6 100644 --- a/src/common/CONSTANTS.js +++ b/src/common/CONSTANTS.js @@ -82,7 +82,7 @@ const EXTERNAL_PLAYERS = [ platforms: ['ios', 'visionos'], }, { - label: 'Moonplayer', + label: 'Moonplayer (VisionOS)', value: 'moonplayer', platforms: ['visionos'], }, From 103fce78945ba275f9df0f75bee445ce8a22809b Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Mon, 29 Jul 2024 13:05:31 +0300 Subject: [PATCH 034/336] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5aaacf3a1..1a6afee9a 100755 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-player-visionos/dev/stremio-stremio-core-web-0.47.7.tgz", + "@stremio/stremio-core-web": "0.47.7", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", From 54728d63ce28a8ec86cd79eb0f1b509c5e5b7fad Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Mon, 29 Jul 2024 13:12:13 +0300 Subject: [PATCH 035/336] add: docs --- src/common/platform.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/platform.js b/src/common/platform.js index 170967f85..7e423489a 100644 --- a/src/common/platform.js +++ b/src/common/platform.js @@ -18,6 +18,8 @@ const Bowser = require('bowser'); const browser = Bowser.parse(window.navigator?.userAgent || ''); +// Edge case: iPad is included in this function +// Keep in mind maxTouchPoints for Vision Pro might change in the future const isVisionProUser = () => { const isMacintosh = navigator.userAgent.includes('Macintosh'); const hasFiveTouchPoints = navigator.maxTouchPoints === 5; From 60d5eb92fe30434a2b624d96945fd537f93b9c37 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Mon, 29 Jul 2024 14:25:37 +0300 Subject: [PATCH 036/336] chore: update stremio-core-web to dev. build for branch Signed-off-by: Lachezar Lechev --- package-lock.json | 7 ++++--- package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 73ef3f20a..08ed918f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-player-visionos/dev/stremio-stremio-core-web-0.47.7.tgz", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", @@ -2972,8 +2972,9 @@ }, "node_modules/@stremio/stremio-core-web": { "version": "0.47.7", - "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-player-visionos/dev/stremio-stremio-core-web-0.47.7.tgz", - "integrity": "sha512-7ozM/pJFsjKkgGxuDpBn6MSWbHCqsXf4VDXSlBr9+TKLK7YT6cL+lEgMVzQfksK14b3d2LcXQ3BCX2b6F7AIfg==", + "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", + "integrity": "sha512-VDUcbMlxk4jo0B2vG2dBAQNT502TnFOB742BGy742Qr30m9u4gFFh+zrHMIhMdm3324Du1G1upgvsjcfZTI72w==", + "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" } diff --git a/package.json b/package.json index 1a6afee9a..ed216269d 100755 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.47.7", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", From 9168df4b823ce22054e4bb0c5ed0d700e2b1562b Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Wed, 31 Jul 2024 10:52:38 +0300 Subject: [PATCH 037/336] refactor: add onKeyUp to not setSeeking to false --- src/routes/Player/Player.js | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index 62c842d45..8bf74ee9a 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -139,7 +139,6 @@ const Player = ({ urlParams, queryParams }) => { const onPlayRequested = React.useCallback(() => { video.setProp('paused', false); setSeeking(false); - console.log(`setSeeking to (PlayRequested - Space): false`); }, []); const onPlayRequestedDebounced = React.useCallback(debounce(onPlayRequested, 200), []); @@ -162,10 +161,8 @@ const Player = ({ urlParams, queryParams }) => { }, []); const onSeekRequested = React.useCallback((time) => { - // first set seeking to true and then update time! setSeeking(true); console.log(`setSeeking to (SeekRequested): true`); - video.setProp('time', time); }, []); @@ -353,16 +350,10 @@ const Player = ({ urlParams, queryParams }) => { if (video.state.time !== null && !isNaN(video.state.time) && video.state.duration !== null && !isNaN(video.state.duration) && video.state.manifest !== null && typeof video.state.manifest.name === 'string') { - - if (seeking) { - seek(video.state.time, video.state.duration, video.state.manifest.name); - setSeeking(false); - console.log(`setSeeking to (on video.state.time change): false`); - - } else { - console.log(`time changed!`); + seeking ? + seek(video.state.time, video.state.duration, video.state.manifest.name) + : timeChanged(video.state.time, video.state.duration, video.state.manifest.name); - } } }, [video.state.time, video.state.duration, video.state.manifest]); @@ -489,8 +480,6 @@ const Player = ({ urlParams, queryParams }) => { console.log(`setSeeking to (play requested - Space): false`); } else { onPauseRequested(); - setSeeking(false); - console.log(`setSeeking to (pause requested - Space): false`); } } @@ -574,6 +563,12 @@ const Player = ({ urlParams, queryParams }) => { } } }; + const onKeyUp = (event) => { + if (event.code === 'ArrowRight' || event.code === 'ArrowLeft') { + setSeeking(false); + console.log(`setSeeking to (key up - ArrowRight/ArrowLeft): false`); + } + }; const onWheel = ({ deltaY }) => { if (deltaY > 0) { if (!menusOpen && video.state.volume !== null) { @@ -587,10 +582,12 @@ const Player = ({ urlParams, queryParams }) => { }; if (routeFocused) { window.addEventListener('keydown', onKeyDown); + window.addEventListener('keyup', onKeyUp); window.addEventListener('wheel', onWheel); } return () => { window.removeEventListener('keydown', onKeyDown); + window.removeEventListener('keyup', onKeyUp); window.removeEventListener('wheel', onWheel); }; }, [player.metaItem, player.selected, streamingServer.statistics, settings.seekTimeDuration, settings.seekShortTimeDuration, routeFocused, menusOpen, nextVideoPopupOpen, video.state.paused, video.state.time, video.state.volume, video.state.audioTracks, video.state.subtitlesTracks, video.state.extraSubtitlesTracks, video.state.playbackSpeed, toggleSubtitlesMenu, toggleInfoMenu, toggleVideosMenu, toggleStatisticsMenu]); From b816a0b835fffdaa54b23d6c4b69135ea354e13c Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Mon, 19 Aug 2024 16:28:13 +0300 Subject: [PATCH 038/336] chore(stremio-core-web) - Update package with pre-release tag --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 08ed918f9..023732cd1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/stremio-core-web-v0.47.8/dev/stremio-stremio-core-web-0.47.8.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", @@ -2971,9 +2971,9 @@ "license": "MIT" }, "node_modules/@stremio/stremio-core-web": { - "version": "0.47.7", - "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", - "integrity": "sha512-VDUcbMlxk4jo0B2vG2dBAQNT502TnFOB742BGy742Qr30m9u4gFFh+zrHMIhMdm3324Du1G1upgvsjcfZTI72w==", + "version": "0.47.8", + "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/stremio-core-web-v0.47.8/dev/stremio-stremio-core-web-0.47.8.tgz", + "integrity": "sha512-qdNlsRdUXlNm999QE/smOVFXe/nJ2x28NO5OTriNqGMO1DGcp7HgCJ1V11RG4Tv/DkEDC8w4l0kkoDXspBzL3w==", "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" diff --git a/package.json b/package.json index ed216269d..f8c4b5d77 100755 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/stremio-core-web-v0.47.8/dev/stremio-stremio-core-web-0.47.8.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", From 48e44a0332a320d3297ac28ac8d6976c7b254903 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 27 Aug 2024 13:43:25 +0300 Subject: [PATCH 039/336] feature: add onDoubleClick function to scrolltop --- src/common/Button/Button.js | 4 +++- .../VerticalNavBar/NavTabButton/NavTabButton.js | 11 ++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index 9d5ef7c1e..b9afe3217 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -6,7 +6,7 @@ const classnames = require('classnames'); const styles = require('./styles'); const { useLongPress } = require('use-long-press'); -const Button = React.forwardRef(({ className, href, disabled, children, onLongPress, ...props }, ref) => { +const Button = React.forwardRef(({ className, href, disabled, children, onLongPress, onDoubleClick, ...props }, ref) => { const longPress = useLongPress(onLongPress, { detect: 'pointer' }); const onKeyDown = React.useCallback((event) => { if (typeof props.onKeyDown === 'function') { @@ -42,6 +42,7 @@ const Button = React.forwardRef(({ className, href, disabled, children, onLongPr href, onKeyDown, onMouseDown, + onDoubleClick, ...longPress() }, children @@ -58,6 +59,7 @@ Button.propTypes = { onKeyDown: PropTypes.func, onMouseDown: PropTypes.func, onLongPress: PropTypes.func, + onDoubleClick: PropTypes.func }; module.exports = Button; diff --git a/src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js b/src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js index 7ecef38c6..5372454e2 100644 --- a/src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js +++ b/src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js @@ -15,8 +15,17 @@ const NavTabButton = ({ className, logo, icon, label, href, selected, onClick }) : null ), [icon]); + const onDoubleClick = () => { + const scrollableElements = document.querySelectorAll('div'); + + scrollableElements.forEach((element) => { + if (element.scrollHeight > element.clientHeight) { + element.scrollTo(0, 0); + } + }); + }; return ( - +
+ {`S${video?.season}E${video?.episode} ${(video?.title)}`} +
+ + : + null + } + { + Object.keys(streamsByAddon).length > 1 ? + + : + null + } +
{ props.streams.length === 0 ?
@@ -109,30 +142,6 @@ const StreamsList = ({ className, video, ...props }) => { : null } -
- { - video ? - - -
- {`S${video?.season}E${video?.episode} ${(video?.title)}`} -
-
- : - null - } - { - Object.keys(streamsByAddon).length > 1 ? - - : - null - } -
{filteredStreams.map((stream, index) => ( { - return deepLinks ? - typeof deepLinks.player === 'string' ? - deepLinks.player - : - typeof deepLinks.metaDetailsStreams === 'string' ? - deepLinks.metaDetailsStreams - : - null - : - null; + const videoButtonOnClick = React.useCallback(() => { + if (deepLinks) { + if (typeof deepLinks.player === 'string') { + window.location = deepLinks.player; + } else if (typeof deepLinks.metaDetailsStreams === 'string') { + window.location.replace(deepLinks.metaDetailsStreams); + } + } }, [deepLinks]); const renderLabel = React.useMemo(() => function renderLabel({ className, id, title, thumbnail, episode, released, upcoming, watched, progress, scheduled, children, ...props }) { return ( @@ -171,7 +168,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w watched={watched} progress={progress} scheduled={scheduled} - href={href} + onClick={videoButtonOnClick} {...props} onMouseUp={popupLabelOnMouseUp} onLongPress={popupLabelOnLongPress} From b002a1c1943fd30e47356776e03496b31cb5b842 Mon Sep 17 00:00:00 2001 From: ArtificialSloth Date: Tue, 17 Sep 2024 04:41:48 -0400 Subject: [PATCH 044/336] fixed indentation --- src/routes/MetaDetails/StreamsList/StreamsList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js index 6dd4f1c6f..840664c8b 100644 --- a/src/routes/MetaDetails/StreamsList/StreamsList.js +++ b/src/routes/MetaDetails/StreamsList/StreamsList.js @@ -26,7 +26,7 @@ const StreamsList = ({ className, video, ...props }) => { `?${new URLSearchParams({'season': video.season})}` : null - )); + )); } else { window.history.back(); } From a1b94a68ff3ba428f3a31afb3de4cc411c92a18c Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Wed, 18 Sep 2024 16:30:40 +0300 Subject: [PATCH 045/336] refactor: inline function --- src/common/MultiselectMenu/Dropdown/Option/Option.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/common/MultiselectMenu/Dropdown/Option/Option.tsx b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx index 4309e766e..68884610f 100644 --- a/src/common/MultiselectMenu/Dropdown/Option/Option.tsx +++ b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx @@ -1,6 +1,6 @@ // Copyright (C) 2017-2024 Smart code 203358507 -import React, { useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import classNames from 'classnames'; import Button from 'stremio/common/Button'; import styles from './Option.less'; @@ -16,11 +16,15 @@ const Option = ({ option, selectedOption, onSelect }: Props) => { // consider using option.id === selectedOption?.id instead const selected = useMemo(() => option?.value === selectedOption?.value, [option, selectedOption]); + const handleClick = useCallback(() => { + onSelect(option.value); + }, [onSelect, option.value]); + return ( + )) + } + { + !videos.length ? +
+ No new episodes for this day +
+ : + null + } +
+ ); +}; + +export default Details; \ No newline at end of file diff --git a/src/routes/Calendar/Details/index.ts b/src/routes/Calendar/Details/index.ts new file mode 100644 index 000000000..68fcb0628 --- /dev/null +++ b/src/routes/Calendar/Details/index.ts @@ -0,0 +1,4 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import Details from './Details'; +export default Details; \ No newline at end of file diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less index b9cdd5507..78f4fc06b 100644 --- a/src/routes/Calendar/Table/Cell/Cell.less +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -105,6 +105,16 @@ } } + .more { + display: none; + flex: none; + width: 2rem; + height: 2rem; + padding: 0.5rem; + align-self: center; + color: var(--primary-foreground-color); + } + &.today { .heading { .day { @@ -128,26 +138,14 @@ } } -@media only screen and (max-height: @small) { - .cell { - gap: 1rem; - } -} - -@media only screen and (max-height: @xxsmall) { +@media only screen and (orientation: portrait) { .cell { .items { display: none; } - } -} -@media only screen and (max-width: @minimum) and (orientation: portrait) { - .cell { - .items { - .item { - border-radius: 0.25rem; - } + .more { + display: flex; } } } @@ -160,9 +158,5 @@ .heading { padding: 0; } - - .items { - display: none; - } } } diff --git a/src/routes/Calendar/Table/Cell/Cell.tsx b/src/routes/Calendar/Table/Cell/Cell.tsx index 24e6d51ec..4fc5e86c8 100644 --- a/src/routes/Calendar/Table/Cell/Cell.tsx +++ b/src/routes/Calendar/Table/Cell/Cell.tsx @@ -51,6 +51,12 @@ const Cell = ({ selected, monthInfo, date, items, onClick }: Props) => { )) } + { + items.length > 0 ? + + : + null + } ); }; From 3f8c64f36e897b802187323a2077941863c12c86 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 24 Sep 2024 03:56:14 +0200 Subject: [PATCH 054/336] fix(Calendar): remove border radius on 29nth cell --- src/routes/Calendar/Table/Cell/Cell.less | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less index 78f4fc06b..2983ae44d 100644 --- a/src/routes/Calendar/Table/Cell/Cell.less +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -21,10 +21,6 @@ border-radius: 0 var(--border-radius) 0 0; } - &:nth-child(29) { - border-radius: 0 0 0 var(--border-radius); - } - &:last-child { border-radius: 0 0 var(--border-radius) 0; } From 184f191218c9af06512c1882334c4a216a235b0b Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 24 Sep 2024 04:02:20 +0200 Subject: [PATCH 055/336] refactor(BottomSheet): style for landscape mode --- src/common/BottomSheet/BottomSheet.less | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/common/BottomSheet/BottomSheet.less b/src/common/BottomSheet/BottomSheet.less index 83c73b70b..0fef3faf1 100644 --- a/src/common/BottomSheet/BottomSheet.less +++ b/src/common/BottomSheet/BottomSheet.less @@ -9,6 +9,8 @@ bottom: 0; left: 0; right: 0; + display: flex; + justify-content: center; .backdrop { z-index: 0; @@ -87,4 +89,12 @@ .bottom-sheet { display: none; } +} + +@media only screen and (orientation: landscape) { + .bottom-sheet { + .container { + max-width: 90%; + } + } } \ No newline at end of file From 3870c6a439cc945314c5e83534dd0d0938385c2b Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 24 Sep 2024 08:56:35 +0200 Subject: [PATCH 056/336] refactor(Calendar): improve responsive layout --- src/routes/Calendar/List/List.less | 2 +- src/routes/Calendar/Table/Cell/Cell.less | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/routes/Calendar/List/List.less b/src/routes/Calendar/List/List.less index 7daae20a1..f63078680 100644 --- a/src/routes/Calendar/List/List.less +++ b/src/routes/Calendar/List/List.less @@ -32,6 +32,6 @@ @media only screen and (max-width: @xsmall) and (orientation: landscape) { .list { - width: 15rem; + display: none; } } diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less index 2983ae44d..2262de210 100644 --- a/src/routes/Calendar/Table/Cell/Cell.less +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -28,9 +28,11 @@ .heading { flex: none; position: relative; + display: flex; padding: 1rem 1rem 0 1rem; .day { + flex: none; position: relative; display: flex; align-items: center; @@ -136,6 +138,12 @@ @media only screen and (orientation: portrait) { .cell { + gap: 0; + + .heading { + justify-content: center; + } + .items { display: none; } @@ -152,7 +160,21 @@ align-items: center; .heading { - padding: 0; + padding: 0 0 0 1rem; + } + } +} + +@media only screen and (max-height: @xsmall) and (orientation: landscape) { + .cell { + gap: 0; + + .items { + display: none; + } + + .more { + display: flex; } } } From 3d4bb2ade58d71d540ace84729c55c7ae00b1a32 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 24 Sep 2024 13:00:33 +0300 Subject: [PATCH 057/336] fix: scrollTop safari content issue --- src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js b/src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js index 415f563be..fba97ed55 100644 --- a/src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js +++ b/src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js @@ -20,7 +20,7 @@ const NavTabButton = ({ className, logo, icon, label, href, selected, onClick }) scrollableElements.forEach((element) => { if (element.scrollTop > 0) { - element.scrollTop = 0; + element.scrollTo({ top: 0, behavior: 'smooth' }); } }); }; From 443e86a1adf57a3f13e84187eb935cbfdbb51c4f Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 25 Sep 2024 15:34:32 +0200 Subject: [PATCH 058/336] feat: impl openExternal for shell compatibility --- src/App/App.js | 28 ++++++------- .../AddonDetailsModal/AddonDetailsModal.js | 5 ++- src/common/Platform/Platform.tsx | 39 +++++++++++++++++++ src/common/Platform/index.ts | 5 +++ src/common/Platform/useShell.ts | 22 +++++++++++ src/common/index.js | 3 ++ src/routes/Addons/Addons.js | 5 ++- .../PasswordResetModal/PasswordResetModal.js | 5 ++- src/routes/Player/OptionsMenu/OptionsMenu.js | 5 ++- src/routes/Settings/Settings.js | 9 +++-- src/types/global.d.ts | 13 +++++++ 11 files changed, 114 insertions(+), 25 deletions(-) create mode 100644 src/common/Platform/Platform.tsx create mode 100644 src/common/Platform/index.ts create mode 100644 src/common/Platform/useShell.ts create mode 100644 src/types/global.d.ts diff --git a/src/App/App.js b/src/App/App.js index 21ba1132b..40b456cc0 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -6,7 +6,7 @@ const { useTranslation } = require('react-i18next'); const { Router } = require('stremio-router'); const { Core, Shell, Chromecast, DragAndDrop, KeyboardShortcuts, ServicesProvider } = require('stremio/services'); const { NotFound } = require('stremio/routes'); -const { ToastProvider, TooltipProvider, CONSTANTS, withCoreSuspender } = require('stremio/common'); +const { PlatformProvider, ToastProvider, TooltipProvider, CONSTANTS, withCoreSuspender } = require('stremio/common'); const ServicesToaster = require('./ServicesToaster'); const DeepLinkHandler = require('./DeepLinkHandler'); const SearchParamsHandler = require('./SearchParamsHandler'); @@ -162,18 +162,20 @@ const App = () => { services.core.error instanceof Error ? : - - - - - - - - + + + + + + + + + + :
} diff --git a/src/common/AddonDetailsModal/AddonDetailsModal.js b/src/common/AddonDetailsModal/AddonDetailsModal.js index ffe2671d0..b4ffdab71 100644 --- a/src/common/AddonDetailsModal/AddonDetailsModal.js +++ b/src/common/AddonDetailsModal/AddonDetailsModal.js @@ -3,7 +3,7 @@ const React = require('react'); const PropTypes = require('prop-types'); const ModalDialog = require('stremio/common/ModalDialog'); -const { withCoreSuspender } = require('stremio/common/CoreSuspender'); +const { usePlatform, withCoreSuspender } = require('stremio/common/CoreSuspender'); const { useServices } = require('stremio/services'); const AddonDetailsWithRemoteAndLocalAddon = withRemoteAndLocalAddon(require('./AddonDetails')); const useAddonDetails = require('./useAddonDetails'); @@ -43,6 +43,7 @@ function withRemoteAndLocalAddon(AddonDetails) { const AddonDetailsModal = ({ transportUrl, onCloseRequest }) => { const { core } = useServices(); + const platform = usePlatform(); const addonDetails = useAddonDetails(transportUrl); const modalButtons = React.useMemo(() => { const cancelButton = { @@ -68,7 +69,7 @@ const AddonDetailsModal = ({ transportUrl, onCloseRequest }) => { label: 'Configure', props: { onClick: (event) => { - window.open(transportUrl.replace('manifest.json', 'configure')); + platform.openExternal(transportUrl.replace('manifest.json', 'configure')); if (typeof onCloseRequest === 'function') { onCloseRequest({ type: 'configure', diff --git a/src/common/Platform/Platform.tsx b/src/common/Platform/Platform.tsx new file mode 100644 index 000000000..c93064d78 --- /dev/null +++ b/src/common/Platform/Platform.tsx @@ -0,0 +1,39 @@ +import React, { createContext, useContext } from 'react'; +import useShell from './useShell'; + +interface PlatformContext { + openExternal: (url: string) => void, +}; + +const PlatformContext = createContext(null); + +type Props = { + children: JSX.Element, +}; + +const PlatformProvider = ({ children }: Props) => { + const shell = useShell(); + + const openExternal = (url: string) => { + if (shell.active) { + shell.send('open-external', url); + } else { + window.open(url, '_blank'); + } + }; + + return ( + + {children} + + ); +}; + +const usePlatform = () => { + return useContext(PlatformContext); +}; + +export { + PlatformProvider, + usePlatform, +}; \ No newline at end of file diff --git a/src/common/Platform/index.ts b/src/common/Platform/index.ts new file mode 100644 index 000000000..8d2b68f12 --- /dev/null +++ b/src/common/Platform/index.ts @@ -0,0 +1,5 @@ +import { PlatformProvider, usePlatform } from './Platform'; +export { + PlatformProvider, + usePlatform, +}; \ No newline at end of file diff --git a/src/common/Platform/useShell.ts b/src/common/Platform/useShell.ts new file mode 100644 index 000000000..aaf5a028e --- /dev/null +++ b/src/common/Platform/useShell.ts @@ -0,0 +1,22 @@ +const createId = () => Math.floor(Math.random() * 9999) + 1; + +const useShell = () => { + const transport = globalThis?.qt?.webChannelTransport; + + const send = (method: string, ...args: (string | number)[]) => { + transport?.send(JSON.stringify({ + id: createId(), + type: 6, + object: 'transport', + method: 'onEvent', + args: [method, ...args], + })); + }; + + return { + active: !!transport, + send, + }; +}; + +export default useShell; \ No newline at end of file diff --git a/src/common/index.js b/src/common/index.js index c582a13ca..1188b8c61 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -18,6 +18,7 @@ const Multiselect = require('./Multiselect'); const { default: MultiselectMenu } = require('./MultiselectMenu'); const { HorizontalNavBar, VerticalNavBar } = require('./NavBar'); const PaginationInput = require('./PaginationInput'); +const { PlatformProvider, usePlatform } = require('./Platform'); const PlayIconCircleCentered = require('./PlayIconCircleCentered'); const Popup = require('./Popup'); const SearchBar = require('./SearchBar'); @@ -68,6 +69,8 @@ module.exports = { HorizontalNavBar, VerticalNavBar, PaginationInput, + PlatformProvider, + usePlatform, PlayIconCircleCentered, Popup, SearchBar, diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index c4c99173a..0de34ad4a 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -5,7 +5,7 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const { useTranslation } = require('react-i18next'); const { default: Icon } = require('@stremio/stremio-icons/react'); -const { AddonDetailsModal, Button, Image, Multiselect, MainNavBars, TextInput, SearchBar, SharePrompt, ModalDialog, useBinaryState, withCoreSuspender } = require('stremio/common'); +const { AddonDetailsModal, Button, Image, Multiselect, MainNavBars, TextInput, SearchBar, SharePrompt, ModalDialog, usePlatform, useBinaryState, withCoreSuspender } = require('stremio/common'); const Addon = require('./Addon'); const useInstalledAddons = require('./useInstalledAddons'); const useRemoteAddons = require('./useRemoteAddons'); @@ -15,6 +15,7 @@ const styles = require('./styles'); const Addons = ({ urlParams, queryParams }) => { const { t } = useTranslation(); + const platform = usePlatform(); const installedAddons = useInstalledAddons(urlParams); const remoteAddons = useRemoteAddons(urlParams); const [addonDetailsTransportUrl, setAddonDetailsTransportUrl] = useAddonDetailsTransportUrl(urlParams, queryParams); @@ -59,7 +60,7 @@ const Addons = ({ urlParams, queryParams }) => { setAddonDetailsTransportUrl(event.dataset.addon.transportUrl); }, [setAddonDetailsTransportUrl]); const onAddonConfigure = React.useCallback((event) => { - window.open(event.dataset.addon.transportUrl.replace('manifest.json', 'configure')); + platform.openExternal(event.dataset.addon.transportUrl.replace('manifest.json', 'configure')); }, []); const closeAddonDetails = React.useCallback(() => { setAddonDetailsTransportUrl(null); diff --git a/src/routes/Intro/PasswordResetModal/PasswordResetModal.js b/src/routes/Intro/PasswordResetModal/PasswordResetModal.js index 0d7bcaae4..1061f6044 100644 --- a/src/routes/Intro/PasswordResetModal/PasswordResetModal.js +++ b/src/routes/Intro/PasswordResetModal/PasswordResetModal.js @@ -3,17 +3,18 @@ const React = require('react'); const PropTypes = require('prop-types'); const { useRouteFocused } = require('stremio-router'); -const { ModalDialog } = require('stremio/common'); +const { ModalDialog, usePlatform } = require('stremio/common'); const CredentialsTextInput = require('../CredentialsTextInput'); const styles = require('./styles'); const PasswordResetModal = ({ email, onCloseRequest }) => { const routeFocused = useRouteFocused(); + const platform = usePlatform(); const [error, setError] = React.useState(''); const emailRef = React.useRef(null); const goToPasswordReset = React.useCallback(() => { emailRef.current.value.length > 0 && emailRef.current.validity.valid ? - window.open('https://www.strem.io/reset-password/' + emailRef.current.value, '_blank') + platform.openExternal('https://www.strem.io/reset-password/' + emailRef.current.value, '_blank') : setError('Invalid email'); }, []); diff --git a/src/routes/Player/OptionsMenu/OptionsMenu.js b/src/routes/Player/OptionsMenu/OptionsMenu.js index 6c50e1551..11738cb3e 100644 --- a/src/routes/Player/OptionsMenu/OptionsMenu.js +++ b/src/routes/Player/OptionsMenu/OptionsMenu.js @@ -4,7 +4,7 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const { useTranslation } = require('react-i18next'); -const { useToast } = require('stremio/common'); +const { usePlatform, useToast } = require('stremio/common'); const { useServices } = require('stremio/services'); const Option = require('./Option'); const styles = require('./styles'); @@ -12,6 +12,7 @@ const styles = require('./styles'); const OptionsMenu = ({ className, stream, playbackDevices }) => { const { t } = useTranslation(); const { core } = useServices(); + const platform = usePlatform(); const toast = useToast(); const [streamingUrl, downloadUrl] = React.useMemo(() => { return stream !== null ? @@ -48,7 +49,7 @@ const OptionsMenu = ({ className, stream, playbackDevices }) => { }, [streamingUrl, downloadUrl]); const onDownloadVideoButtonClick = React.useCallback(() => { if (streamingUrl || downloadUrl) { - window.open(streamingUrl || downloadUrl); + platform.openExternal(streamingUrl || downloadUrl); } }, [streamingUrl, downloadUrl]); const onExternalDeviceRequested = React.useCallback((deviceId) => { diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 071f14d0e..5c5d51774 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -7,7 +7,7 @@ const { useTranslation } = require('react-i18next'); const { default: Icon } = require('@stremio/stremio-icons/react'); const { useRouteFocused } = require('stremio-router'); const { useServices } = require('stremio/services'); -const { Button, Checkbox, MainNavBars, Multiselect, ColorInput, TextInput, ModalDialog, useProfile, useStreamingServer, useBinaryState, withCoreSuspender, useToast } = require('stremio/common'); +const { Button, Checkbox, MainNavBars, Multiselect, ColorInput, TextInput, ModalDialog, useProfile, usePlatform, useStreamingServer, useBinaryState, withCoreSuspender, useToast } = require('stremio/common'); const useProfileSettingsInputs = require('./useProfileSettingsInputs'); const useStreamingServerSettingsInputs = require('./useStreamingServerSettingsInputs'); const useDataExport = require('./useDataExport'); @@ -25,6 +25,7 @@ const Settings = () => { const profile = useProfile(); const [dataExport, loadDataExport] = useDataExport(); const streamingServer = useStreamingServer(); + const platform = usePlatform(); const toast = useToast(); const { interfaceLanguageSelect, @@ -90,7 +91,7 @@ const Settings = () => { }, []); const toggleTraktOnClick = React.useCallback(() => { if (!isTraktAuthenticated && profile.auth !== null && profile.auth.user !== null && typeof profile.auth.user._id === 'string') { - window.open(`https://www.strem.io/trakt/auth/${profile.auth.user._id}`); + platform.openExternal(`https://www.strem.io/trakt/auth/${profile.auth.user._id}`); setTraktAuthStarted(true); } else { core.transport.dispatch({ @@ -103,7 +104,7 @@ const Settings = () => { }, [isTraktAuthenticated, profile.auth]); const subscribeCalendarOnClick = React.useCallback(() => { const url = `webcal://www.strem.io/calendar/${profile.auth.user._id}.ics`; - window.open(url); + platform.openExternal(url); toast.show({ type: 'success', title: 'Calendar has been added to your default caldendar app', @@ -181,7 +182,7 @@ const Settings = () => { }, [isTraktAuthenticated, traktAuthStarted]); React.useEffect(() => { if (dataExport.exportUrl !== null && typeof dataExport.exportUrl === 'string') { - window.open(dataExport.exportUrl); + platform.openExternal(dataExport.exportUrl); } }, [dataExport.exportUrl]); React.useLayoutEffect(() => { diff --git a/src/types/global.d.ts b/src/types/global.d.ts new file mode 100644 index 000000000..97da1d705 --- /dev/null +++ b/src/types/global.d.ts @@ -0,0 +1,13 @@ +interface QtTransport { + send: (message: string) => void, +} + +interface Qt { + webChannelTransport: QtTransport, +} + +declare global { + var qt: Qt | undefined; +} + +export { }; \ No newline at end of file From c5b20800c0870feb68b82feb300c2091d845ee8d Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 25 Sep 2024 15:43:04 +0200 Subject: [PATCH 059/336] fix(App): lint --- src/App/App.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/App/App.js b/src/App/App.js index 40b456cc0..730e75f28 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -165,14 +165,14 @@ const App = () => { - - - - + + + + From 4173fca28cb6f3d2c95aa635a77e1e4fd88c4c4e Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 26 Sep 2024 12:28:48 +0300 Subject: [PATCH 060/336] feature: check if url is whitelisted --- src/common/CONSTANTS.js | 3 +++ src/common/Platform/Platform.tsx | 19 ++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/common/CONSTANTS.js b/src/common/CONSTANTS.js index 742c138d6..c64c84bcd 100644 --- a/src/common/CONSTANTS.js +++ b/src/common/CONSTANTS.js @@ -93,6 +93,8 @@ const EXTERNAL_PLAYERS = [ }, ]; +const WHITELISTED_HOSTS = ['www.stremio.com', 'blog.stremio.com', 'web.stremio.com', 'web.strem.io', 'stremio.zendesk.com', 'www.google.com', 'www.youtube.com', 'www.twitch.tv', 'twitter.com', 'www.netflix.com', 'www.adex.network', 'www.amazon.com', 'docs.google.com', 'blog.stremio.com', 'forms.gle']; + module.exports = { CHROMECAST_RECEIVER_APP_ID, SUBTITLES_SIZES, @@ -110,4 +112,5 @@ module.exports = { TYPE_PRIORITIES, ICON_FOR_TYPE, EXTERNAL_PLAYERS, + WHITELISTED_HOSTS, }; diff --git a/src/common/Platform/Platform.tsx b/src/common/Platform/Platform.tsx index c93064d78..0804d512b 100644 --- a/src/common/Platform/Platform.tsx +++ b/src/common/Platform/Platform.tsx @@ -1,5 +1,6 @@ import React, { createContext, useContext } from 'react'; import useShell from './useShell'; +import { WHITELISTED_HOSTS } from 'stremio/common/CONSTANTS'; interface PlatformContext { openExternal: (url: string) => void, @@ -15,10 +16,22 @@ const PlatformProvider = ({ children }: Props) => { const shell = useShell(); const openExternal = (url: string) => { + let finalUrl = url; + try { + const parsedUrl = new URL(url); + const hostname = parsedUrl.hostname; + const isWhitelisted = WHITELISTED_HOSTS.some((host: string) => hostname === host || hostname.endsWith('.' + host)); + if (!isWhitelisted) { + finalUrl = 'https://www.stremio.com/warning#' + encodeURIComponent(url); + } + } catch (e) { + finalUrl = 'https://www.stremio.com/warning#' + encodeURIComponent(url); + } + if (shell.active) { - shell.send('open-external', url); + shell.send('open-external', finalUrl); } else { - window.open(url, '_blank'); + window.open(finalUrl, '_blank'); } }; @@ -36,4 +49,4 @@ const usePlatform = () => { export { PlatformProvider, usePlatform, -}; \ No newline at end of file +}; From 94cbd8d26812f6c0e2e3279bb84d09697da8d5a0 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 26 Sep 2024 11:51:45 +0200 Subject: [PATCH 061/336] fix(Settings): remove data export link if not logged in --- src/routes/Settings/Settings.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 071f14d0e..ce37d83ba 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -261,9 +261,14 @@ const Settings = () => {
- + { + profile.auth ? + + : + null + }
{ profile.auth !== null && profile.auth.user !== null && typeof profile.auth.user._id === 'string' ? From 50b93014babbe80b3b53f943be2a911936cb8154 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 26 Sep 2024 13:06:57 +0300 Subject: [PATCH 062/336] refactor: wrap everything in try catch --- src/common/Platform/Platform.tsx | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/common/Platform/Platform.tsx b/src/common/Platform/Platform.tsx index 0804d512b..13e8592ad 100644 --- a/src/common/Platform/Platform.tsx +++ b/src/common/Platform/Platform.tsx @@ -16,23 +16,19 @@ const PlatformProvider = ({ children }: Props) => { const shell = useShell(); const openExternal = (url: string) => { - let finalUrl = url; try { - const parsedUrl = new URL(url); - const hostname = parsedUrl.hostname; - const isWhitelisted = WHITELISTED_HOSTS.some((host: string) => hostname === host || hostname.endsWith('.' + host)); - if (!isWhitelisted) { - finalUrl = 'https://www.stremio.com/warning#' + encodeURIComponent(url); + const { hostname } = new URL(url); + const isWhitelisted = WHITELISTED_HOSTS.some((host: string) => hostname.endsWith(host)); + const finalUrl = !isWhitelisted ? 'https://www.stremio.com/warning#' + encodeURIComponent(url) : url; + + if (shell.active) { + shell.send('open-external', finalUrl); + } else { + window.open(finalUrl, '_blank'); } } catch (e) { - finalUrl = 'https://www.stremio.com/warning#' + encodeURIComponent(url); - } - - if (shell.active) { - shell.send('open-external', finalUrl); - } else { - window.open(finalUrl, '_blank'); - } + console.error('Failed to parse external url:', e); + } }; return ( From c1b9a057309215e97f4949331ea2f0b931b3721d Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 26 Sep 2024 13:09:08 +0300 Subject: [PATCH 063/336] refactor: whitelisted hosts list --- src/common/CONSTANTS.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/CONSTANTS.js b/src/common/CONSTANTS.js index c64c84bcd..c08cf471d 100644 --- a/src/common/CONSTANTS.js +++ b/src/common/CONSTANTS.js @@ -93,7 +93,7 @@ const EXTERNAL_PLAYERS = [ }, ]; -const WHITELISTED_HOSTS = ['www.stremio.com', 'blog.stremio.com', 'web.stremio.com', 'web.strem.io', 'stremio.zendesk.com', 'www.google.com', 'www.youtube.com', 'www.twitch.tv', 'twitter.com', 'www.netflix.com', 'www.adex.network', 'www.amazon.com', 'docs.google.com', 'blog.stremio.com', 'forms.gle']; +const WHITELISTED_HOSTS = ['stremio.com', 'strem.io', 'stremio.zendesk.com', 'google.com', 'youtube.com', 'twitch.tv', 'twitter.com', 'netflix.com', 'adex.network', 'amazon.com', 'forms.gle']; module.exports = { CHROMECAST_RECEIVER_APP_ID, From bd1305927919c9260195901c5327afccd4c5e610 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 26 Sep 2024 14:51:12 +0300 Subject: [PATCH 064/336] refactor: turn button into a link --- src/routes/Settings/Settings.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 5c5d51774..ab69d26f6 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -11,6 +11,7 @@ const { Button, Checkbox, MainNavBars, Multiselect, ColorInput, TextInput, Modal const useProfileSettingsInputs = require('./useProfileSettingsInputs'); const useStreamingServerSettingsInputs = require('./useStreamingServerSettingsInputs'); const useDataExport = require('./useDataExport'); +const { name: platformName } = require('stremio/common/platform'); const styles = require('./styles'); const GENERAL_SECTION = 'general'; @@ -102,16 +103,20 @@ const Settings = () => { }); } }, [isTraktAuthenticated, profile.auth]); + const protocol = platformName === 'ios' ? 'webcal' : 'http'; + const calendarUrl = `${protocol}://www.strem.io/calendar/${profile.auth.user._id}.ics`; + const calendarFileName = `${profile.auth.user._id}.ics`; const subscribeCalendarOnClick = React.useCallback(() => { - const url = `webcal://www.strem.io/calendar/${profile.auth.user._id}.ics`; - platform.openExternal(url); + platform.openExternal(calendarUrl); toast.show({ type: 'success', - title: 'Calendar has been added to your default caldendar app', + title: platformName === 'android' ? + 'Calendar has been downloaded. Please open it in your calendar app.' : + 'Calendar has been added to your default calendar app.', timeout: 25000 }); - //Stremio 4 emits not documented event subscribeCalendar - }, []); + // Stremio 4 emits not documented event subscribeCalendar + }, [platformName, profile.auth.user._id, platform, toast]); const exportDataOnClick = React.useCallback(() => { loadDataExport(); }, []); @@ -269,7 +274,7 @@ const Settings = () => { { profile.auth !== null && profile.auth.user !== null && typeof profile.auth.user._id === 'string' ?
-
From 0ee4b6d396417d43c9caafd3f1884998d97229c6 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 26 Sep 2024 14:55:43 +0300 Subject: [PATCH 065/336] remove: download file name --- src/routes/Settings/Settings.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index ab69d26f6..7b1afe620 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -103,9 +103,8 @@ const Settings = () => { }); } }, [isTraktAuthenticated, profile.auth]); - const protocol = platformName === 'ios' ? 'webcal' : 'http'; + const protocol = platformName === 'ios' ? 'webcal' : 'https'; const calendarUrl = `${protocol}://www.strem.io/calendar/${profile.auth.user._id}.ics`; - const calendarFileName = `${profile.auth.user._id}.ics`; const subscribeCalendarOnClick = React.useCallback(() => { platform.openExternal(calendarUrl); toast.show({ @@ -274,7 +273,7 @@ const Settings = () => { { profile.auth !== null && profile.auth.user !== null && typeof profile.auth.user._id === 'string' ?
-
From 9b160a0c6b60a85011705dfbf3a0e41ea4393412 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 26 Sep 2024 14:57:40 +0300 Subject: [PATCH 066/336] remove: href and target on button --- src/routes/Settings/Settings.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 7b1afe620..3b2846305 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -103,10 +103,10 @@ const Settings = () => { }); } }, [isTraktAuthenticated, profile.auth]); - const protocol = platformName === 'ios' ? 'webcal' : 'https'; - const calendarUrl = `${protocol}://www.strem.io/calendar/${profile.auth.user._id}.ics`; const subscribeCalendarOnClick = React.useCallback(() => { - platform.openExternal(calendarUrl); + const protocol = platformName === 'ios' ? 'webcal' : 'https'; + const url = `${protocol}://www.strem.io/calendar/${profile.auth.user._id}.ics`; + platform.openExternal(url); toast.show({ type: 'success', title: platformName === 'android' ? @@ -273,7 +273,7 @@ const Settings = () => { { profile.auth !== null && profile.auth.user !== null && typeof profile.auth.user._id === 'string' ?
-
From 0ebdf83c7f3988502e6282cd3733bbe5071233ff Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 26 Sep 2024 14:59:32 +0300 Subject: [PATCH 067/336] refactor: dependencies on useCallback --- src/routes/Settings/Settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 3b2846305..fb97d7386 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -115,7 +115,7 @@ const Settings = () => { timeout: 25000 }); // Stremio 4 emits not documented event subscribeCalendar - }, [platformName, profile.auth.user._id, platform, toast]); + }, [profile.auth.user._id]); const exportDataOnClick = React.useCallback(() => { loadDataExport(); }, []); From dab0169038cf537430958d91d3512d641321cae1 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 26 Sep 2024 15:02:50 +0300 Subject: [PATCH 068/336] refactor: add translations --- src/routes/Settings/Settings.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index fb97d7386..92ad44763 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -109,9 +109,7 @@ const Settings = () => { platform.openExternal(url); toast.show({ type: 'success', - title: platformName === 'android' ? - 'Calendar has been downloaded. Please open it in your calendar app.' : - 'Calendar has been added to your default calendar app.', + title: platformName === 'ios' ? t('SETTINGS_SUBSCRIBE_CALENDAR_IOS') : t('SETTINGS_SUBSCRIBE_CALENDAR'), timeout: 25000 }); // Stremio 4 emits not documented event subscribeCalendar From f84bc813f9c71b0759cedea082d05f0ca399ffbb Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 26 Sep 2024 15:08:47 +0300 Subject: [PATCH 069/336] refactor: translations strings --- src/routes/Settings/Settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 92ad44763..3e0c4cf8e 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -109,7 +109,7 @@ const Settings = () => { platform.openExternal(url); toast.show({ type: 'success', - title: platformName === 'ios' ? t('SETTINGS_SUBSCRIBE_CALENDAR_IOS') : t('SETTINGS_SUBSCRIBE_CALENDAR'), + title: platformName === 'ios' ? t('SETTINGS_SUBSCRIBE_CALENDAR_IOS_TOAST') : t('SETTINGS_SUBSCRIBE_CALENDAR_TOAST'), timeout: 25000 }); // Stremio 4 emits not documented event subscribeCalendar From 8e2da823eaf041435ad7d9782570a599aba13d8e Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 26 Sep 2024 16:00:55 +0300 Subject: [PATCH 070/336] chore: update translations pkg --- package-lock.json | 9 ++++----- package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5775eb1a9..31a0fdda8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ "react-i18next": "^12.1.1", "react-is": "18.2.0", "spatial-navigation-polyfill": "github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6", - "stremio-translations": "github:Stremio/stremio-translations#b13b3e2653bd0dcf644d2a20ffa32074fe6532dd", + "stremio-translations": "github:Stremio/stremio-translations#378218c9617f3e763ba5f6755e4d39c1c158747d", "url": "0.11.0", "use-long-press": "^3.1.5" }, @@ -12470,10 +12470,9 @@ } }, "node_modules/stremio-translations": { - "version": "1.44.7", - "resolved": "git+ssh://git@github.com/Stremio/stremio-translations.git#b13b3e2653bd0dcf644d2a20ffa32074fe6532dd", - "integrity": "sha512-OtRAM3j9ie89llgI379p4utCbgnNMswE+LtL/lyLRVLfm5B+jpBLp4ozpU25iQg0O4tvN+OHBjXZ870CCHtZMA==", - "license": "MIT" + "version": "1.44.9", + "resolved": "git+ssh://git@github.com/Stremio/stremio-translations.git#378218c9617f3e763ba5f6755e4d39c1c158747d", + "integrity": "sha512-3GboN8JS2LgrdIVK/gW+n6r1kLrGG+D/tWkRv8PJo2mZLzh49HTzS2u7XXUSkNmA4AGUyEf8QRjyBhlOg8JNTQ==" }, "node_modules/string_decoder": { "version": "1.1.1", diff --git a/package.json b/package.json index 6610395a6..1339ba710 100755 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "react-i18next": "^12.1.1", "react-is": "18.2.0", "spatial-navigation-polyfill": "github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6", - "stremio-translations": "github:Stremio/stremio-translations#b13b3e2653bd0dcf644d2a20ffa32074fe6532dd", + "stremio-translations": "github:Stremio/stremio-translations#378218c9617f3e763ba5f6755e4d39c1c158747d", "url": "0.11.0", "use-long-press": "^3.1.5" }, From d474ec60ca86e791c1f6f1d0d37bef7a8942b131 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 26 Sep 2024 17:06:27 +0300 Subject: [PATCH 071/336] refactor: logic unite --- src/common/Platform/Platform.tsx | 66 ++++++++++++++++++++++++++------ src/common/platform.js | 36 ----------------- src/routes/Settings/Settings.js | 5 +-- 3 files changed, 57 insertions(+), 50 deletions(-) delete mode 100644 src/common/platform.js diff --git a/src/common/Platform/Platform.tsx b/src/common/Platform/Platform.tsx index 13e8592ad..2dee98bff 100644 --- a/src/common/Platform/Platform.tsx +++ b/src/common/Platform/Platform.tsx @@ -1,26 +1,70 @@ import React, { createContext, useContext } from 'react'; -import useShell from './useShell'; import { WHITELISTED_HOSTS } from 'stremio/common/CONSTANTS'; +import useShell from './useShell'; +import Bowser from 'bowser'; interface PlatformContext { - openExternal: (url: string) => void, -}; + name: string; + isMobile: () => boolean; + openExternal: (url: string) => void; +} const PlatformContext = createContext(null); type Props = { - children: JSX.Element, + children: JSX.Element; }; const PlatformProvider = ({ children }: Props) => { const shell = useShell(); + // this detects ipad properly in safari + // while bowser does not + const iOS = () => { + return ( + [ + 'iPad Simulator', + 'iPhone Simulator', + 'iPod Simulator', + 'iPad', + 'iPhone', + 'iPod', + ].includes(navigator.platform) || + (navigator.userAgent.includes('Mac') && 'ontouchend' in document) + ); + }; + + // Edge case: iPad is included in this function + // Keep in mind maxTouchPoints for Vision Pro might change in the future + const isVisionProUser = () => { + const isMacintosh = navigator.userAgent.includes('Macintosh'); + const hasFiveTouchPoints = navigator.maxTouchPoints === 5; + return isMacintosh && hasFiveTouchPoints; + }; + + const browser = Bowser.getParser(window.navigator?.userAgent || ''); + const osName = browser.getOSName().toLowerCase(); + + const name = isVisionProUser() + ? 'visionos' + : iOS() + ? 'ios' + : osName || 'unknown'; + + const isMobile = () => { + return name === 'ios' || name === 'android'; + }; + const openExternal = (url: string) => { try { const { hostname } = new URL(url); - const isWhitelisted = WHITELISTED_HOSTS.some((host: string) => hostname.endsWith(host)); - const finalUrl = !isWhitelisted ? 'https://www.stremio.com/warning#' + encodeURIComponent(url) : url; - + const isWhitelisted = WHITELISTED_HOSTS.some((host: string) => + hostname.endsWith(host) + ); + const finalUrl = !isWhitelisted + ? 'https://www.stremio.com/warning#' + encodeURIComponent(url) + : url; + if (shell.active) { shell.send('open-external', finalUrl); } else { @@ -28,11 +72,11 @@ const PlatformProvider = ({ children }: Props) => { } } catch (e) { console.error('Failed to parse external url:', e); - } + } }; return ( - + {children} ); @@ -42,7 +86,7 @@ const usePlatform = () => { return useContext(PlatformContext); }; -export { +export { PlatformProvider, - usePlatform, + usePlatform }; diff --git a/src/common/platform.js b/src/common/platform.js deleted file mode 100644 index 7e423489a..000000000 --- a/src/common/platform.js +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2017-2024 Smart code 203358507 - -// this detects ipad properly in safari -// while bowser does not -const iOS = () => { - return [ - 'iPad Simulator', - 'iPhone Simulator', - 'iPod Simulator', - 'iPad', - 'iPhone', - 'iPod' - ].includes(navigator.platform) - || (navigator.userAgent.includes('Mac') && 'ontouchend' in document); -}; - -const Bowser = require('bowser'); - -const browser = Bowser.parse(window.navigator?.userAgent || ''); - -// Edge case: iPad is included in this function -// Keep in mind maxTouchPoints for Vision Pro might change in the future -const isVisionProUser = () => { - const isMacintosh = navigator.userAgent.includes('Macintosh'); - const hasFiveTouchPoints = navigator.maxTouchPoints === 5; - return isMacintosh && hasFiveTouchPoints; -}; - -const name = isVisionProUser() ? 'visionos' : (iOS() ? 'ios' : (browser?.os?.name || 'unknown').toLowerCase()); - -module.exports = { - name, - isMobile: () => { - return name === 'ios' || name === 'android'; - } -}; diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 3e0c4cf8e..0d9199225 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -11,7 +11,6 @@ const { Button, Checkbox, MainNavBars, Multiselect, ColorInput, TextInput, Modal const useProfileSettingsInputs = require('./useProfileSettingsInputs'); const useStreamingServerSettingsInputs = require('./useStreamingServerSettingsInputs'); const useDataExport = require('./useDataExport'); -const { name: platformName } = require('stremio/common/platform'); const styles = require('./styles'); const GENERAL_SECTION = 'general'; @@ -104,12 +103,12 @@ const Settings = () => { } }, [isTraktAuthenticated, profile.auth]); const subscribeCalendarOnClick = React.useCallback(() => { - const protocol = platformName === 'ios' ? 'webcal' : 'https'; + const protocol = platform.name === 'ios' ? 'webcal' : 'https'; const url = `${protocol}://www.strem.io/calendar/${profile.auth.user._id}.ics`; platform.openExternal(url); toast.show({ type: 'success', - title: platformName === 'ios' ? t('SETTINGS_SUBSCRIBE_CALENDAR_IOS_TOAST') : t('SETTINGS_SUBSCRIBE_CALENDAR_TOAST'), + title: platform.name === 'ios' ? t('SETTINGS_SUBSCRIBE_CALENDAR_IOS_TOAST') : t('SETTINGS_SUBSCRIBE_CALENDAR_TOAST'), timeout: 25000 }); // Stremio 4 emits not documented event subscribeCalendar From ff662d087282bf6665885e4daaa4535a4b52b369 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 27 Sep 2024 09:05:02 +0200 Subject: [PATCH 072/336] refactor: platform device logic --- src/common/Platform/Platform.tsx | 49 +++----------------------------- src/common/Platform/device.ts | 31 ++++++++++++++++++++ src/common/index.js | 2 -- 3 files changed, 35 insertions(+), 47 deletions(-) create mode 100644 src/common/Platform/device.ts diff --git a/src/common/Platform/Platform.tsx b/src/common/Platform/Platform.tsx index 2dee98bff..69ff3e8c3 100644 --- a/src/common/Platform/Platform.tsx +++ b/src/common/Platform/Platform.tsx @@ -1,11 +1,11 @@ import React, { createContext, useContext } from 'react'; import { WHITELISTED_HOSTS } from 'stremio/common/CONSTANTS'; import useShell from './useShell'; -import Bowser from 'bowser'; +import { name, isMobile } from './device'; interface PlatformContext { name: string; - isMobile: () => boolean; + isMobile: boolean; openExternal: (url: string) => void; } @@ -18,52 +18,11 @@ type Props = { const PlatformProvider = ({ children }: Props) => { const shell = useShell(); - // this detects ipad properly in safari - // while bowser does not - const iOS = () => { - return ( - [ - 'iPad Simulator', - 'iPhone Simulator', - 'iPod Simulator', - 'iPad', - 'iPhone', - 'iPod', - ].includes(navigator.platform) || - (navigator.userAgent.includes('Mac') && 'ontouchend' in document) - ); - }; - - // Edge case: iPad is included in this function - // Keep in mind maxTouchPoints for Vision Pro might change in the future - const isVisionProUser = () => { - const isMacintosh = navigator.userAgent.includes('Macintosh'); - const hasFiveTouchPoints = navigator.maxTouchPoints === 5; - return isMacintosh && hasFiveTouchPoints; - }; - - const browser = Bowser.getParser(window.navigator?.userAgent || ''); - const osName = browser.getOSName().toLowerCase(); - - const name = isVisionProUser() - ? 'visionos' - : iOS() - ? 'ios' - : osName || 'unknown'; - - const isMobile = () => { - return name === 'ios' || name === 'android'; - }; - const openExternal = (url: string) => { try { const { hostname } = new URL(url); - const isWhitelisted = WHITELISTED_HOSTS.some((host: string) => - hostname.endsWith(host) - ); - const finalUrl = !isWhitelisted - ? 'https://www.stremio.com/warning#' + encodeURIComponent(url) - : url; + const isWhitelisted = WHITELISTED_HOSTS.some((host: string) => hostname.endsWith(host)); + const finalUrl = !isWhitelisted ? `https://www.stremio.com/warning#${encodeURIComponent(url)}` : url; if (shell.active) { shell.send('open-external', finalUrl); diff --git a/src/common/Platform/device.ts b/src/common/Platform/device.ts new file mode 100644 index 000000000..68ca72b32 --- /dev/null +++ b/src/common/Platform/device.ts @@ -0,0 +1,31 @@ +import Bowser from 'bowser'; + +const APPLE_MOBILE_DEVICES = [ + 'iPad Simulator', + 'iPhone Simulator', + 'iPod Simulator', + 'iPad', + 'iPhone', + 'iPod', +]; + +const { userAgent, platform, maxTouchPoints } = globalThis.navigator; + +// this detects ipad properly in safari +// while bowser does not +const isIOS = APPLE_MOBILE_DEVICES.includes(platform) || (userAgent.includes('Mac') && 'ontouchend' in document); + +// Edge case: iPad is included in this function +// Keep in mind maxTouchPoints for Vision Pro might change in the future +const isVisionOS = userAgent.includes('Macintosh') || maxTouchPoints === 5; + +const bowser = Bowser.getParser(userAgent); +const os = bowser.getOSName().toLowerCase(); + +const name = isVisionOS ? 'visionos' : isIOS ? 'ios' : os || 'unknown'; +const isMobile = ['ios', 'android'].includes(name); + +export { + name, + isMobile, +}; \ No newline at end of file diff --git a/src/common/index.js b/src/common/index.js index 1188b8c61..5adef3e60 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -46,7 +46,6 @@ const useProfile = require('./useProfile'); const useStreamingServer = require('./useStreamingServer'); const useTorrent = require('./useTorrent'); const useTranslate = require('./useTranslate'); -const platform = require('./platform'); const EventModal = require('./EventModal'); module.exports = { @@ -101,6 +100,5 @@ module.exports = { useStreamingServer, useTorrent, useTranslate, - platform, EventModal, }; From 3c517f6a32a2b29e8b789e23771378916096cc45 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 27 Sep 2024 10:59:48 +0200 Subject: [PATCH 073/336] fix: replace platform by usePlatform --- src/routes/MetaDetails/StreamsList/Stream/Stream.js | 3 ++- src/routes/Settings/useProfileSettingsInputs.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 40ccb2f07..e4829ece0 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -5,7 +5,7 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const { default: Icon } = require('@stremio/stremio-icons/react'); const { t } = require('i18next'); -const { Button, Image, useProfile, platform, useToast, Popup, useBinaryState } = require('stremio/common'); +const { Button, Image, useProfile, usePlatform, useToast, Popup, useBinaryState } = require('stremio/common'); const { useServices } = require('stremio/services'); const { useRouteFocused } = require('stremio-router'); const StreamPlaceholder = require('./StreamPlaceholder'); @@ -14,6 +14,7 @@ const styles = require('./styles'); const Stream = ({ className, videoId, videoReleased, addonName, name, description, thumbnail, progress, deepLinks, ...props }) => { const profile = useProfile(); const toast = useToast(); + const platform = usePlatform(); const { core } = useServices(); const routeFocused = useRouteFocused(); diff --git a/src/routes/Settings/useProfileSettingsInputs.js b/src/routes/Settings/useProfileSettingsInputs.js index 939e5e7cf..a90d0d483 100644 --- a/src/routes/Settings/useProfileSettingsInputs.js +++ b/src/routes/Settings/useProfileSettingsInputs.js @@ -3,11 +3,12 @@ const React = require('react'); const { useTranslation } = require('react-i18next'); const { useServices } = require('stremio/services'); -const { CONSTANTS, interfaceLanguages, languageNames, platform } = require('stremio/common'); +const { CONSTANTS, usePlatform, interfaceLanguages, languageNames } = require('stremio/common'); const useProfileSettingsInputs = (profile) => { const { t } = useTranslation(); const { core } = useServices(); + const platform = usePlatform(); // TODO combine those useMemo in one const interfaceLanguageSelect = React.useMemo(() => ({ options: interfaceLanguages.map(({ name, codes }) => ({ From 0a2ad7b6aa4331f20ae48b8c82f43b60405366d9 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 27 Sep 2024 11:20:57 +0200 Subject: [PATCH 074/336] fix(Settings): check for profile.auth in subscribeCalendarOnClick --- src/routes/Settings/Settings.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 0d9199225..ed4f45e16 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -103,6 +103,8 @@ const Settings = () => { } }, [isTraktAuthenticated, profile.auth]); const subscribeCalendarOnClick = React.useCallback(() => { + if (!profile.auth) return; + const protocol = platform.name === 'ios' ? 'webcal' : 'https'; const url = `${protocol}://www.strem.io/calendar/${profile.auth.user._id}.ics`; platform.openExternal(url); @@ -112,7 +114,7 @@ const Settings = () => { timeout: 25000 }); // Stremio 4 emits not documented event subscribeCalendar - }, [profile.auth.user._id]); + }, [profile.auth]); const exportDataOnClick = React.useCallback(() => { loadDataExport(); }, []); From 67aeed6005d97ed49d5dfe78260031bc22ad8f14 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 1 Oct 2024 12:25:46 +0300 Subject: [PATCH 075/336] fix: dropdown scroll --- src/common/MultiselectMenu/Dropdown/Dropdown.less | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/MultiselectMenu/Dropdown/Dropdown.less b/src/common/MultiselectMenu/Dropdown/Dropdown.less index 1e15419ef..17aeedef9 100644 --- a/src/common/MultiselectMenu/Dropdown/Dropdown.less +++ b/src/common/MultiselectMenu/Dropdown/Dropdown.less @@ -14,6 +14,8 @@ &.open { display: block; + max-height: 50vh; + overflow: scroll; } .back-button { From 3da58916671279060afdc40ca5fdfd61845310f0 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Wed, 2 Oct 2024 17:08:17 +0300 Subject: [PATCH 076/336] refactor: dropdown styles --- src/common/MultiselectMenu/Dropdown/Dropdown.less | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/common/MultiselectMenu/Dropdown/Dropdown.less b/src/common/MultiselectMenu/Dropdown/Dropdown.less index 17aeedef9..57840ca22 100644 --- a/src/common/MultiselectMenu/Dropdown/Dropdown.less +++ b/src/common/MultiselectMenu/Dropdown/Dropdown.less @@ -1,5 +1,7 @@ // Copyright (C) 2017-2024 Smart code 203358507 +@import (reference) '~stremio/common/screen-sizes.less'; + .dropdown { background: var(--modal-background-color); display: none; @@ -14,8 +16,8 @@ &.open { display: block; - max-height: 50vh; - overflow: scroll; + max-height: calc(3.2rem * 10); + overflow: auto; } .back-button { @@ -29,4 +31,12 @@ width: 1.5rem; } } +} + +@media only screen and (max-width: @minimum) { + .dropdown { + &.open { + max-height: calc(3.2rem * 7); + } + } } \ No newline at end of file From 5e1b808b4bdc476dac3188725ff3e5f1e1d0c30e Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 2 Oct 2024 16:14:30 +0200 Subject: [PATCH 077/336] 5.0.0-beta.10 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 31a0fdda8..6f767069b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "stremio", - "version": "5.0.0-beta.9", + "version": "5.0.0-beta.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "stremio", - "version": "5.0.0-beta.9", + "version": "5.0.0-beta.10", "license": "gpl-2.0", "dependencies": { "@babel/runtime": "7.16.0", diff --git a/package.json b/package.json index 1339ba710..73f27d28e 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "stremio", "displayName": "Stremio", - "version": "5.0.0-beta.9", + "version": "5.0.0-beta.10", "author": "Smart Code OOD", "private": true, "license": "gpl-2.0", From 2d9f3fa6ac2c924830d72bd9acf076a2e71c5575 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 3 Oct 2024 08:56:20 +0200 Subject: [PATCH 078/336] refactor(Calendar): improve placeholder responsiveness on mobile --- src/routes/Calendar/Placeholder/Placeholder.less | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/routes/Calendar/Placeholder/Placeholder.less b/src/routes/Calendar/Placeholder/Placeholder.less index c57bd958e..a509ff79e 100644 --- a/src/routes/Calendar/Placeholder/Placeholder.less +++ b/src/routes/Calendar/Placeholder/Placeholder.less @@ -69,6 +69,7 @@ padding: 0 5rem; font-size: 1.1rem; color: var(--primary-foreground-color); + text-align: center; border-radius: 3.5rem; background-color: var(--overlay-color); @@ -81,10 +82,18 @@ @media only screen and (max-width: @minimum) { .placeholder { - padding: 1rem; + padding: 1rem 2rem; + + .image { + height: 10rem; + } .overview { flex-direction: column; } + + .button { + width: 100%; + } } } \ No newline at end of file From 59d490c87951a1904f2d77f314082fa72df201d2 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 3 Oct 2024 08:56:52 +0200 Subject: [PATCH 079/336] refactor(Calendar): make placeholder login button go to the login form --- src/routes/Calendar/Placeholder/Placeholder.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Calendar/Placeholder/Placeholder.tsx b/src/routes/Calendar/Placeholder/Placeholder.tsx index b514c2295..feb236221 100644 --- a/src/routes/Calendar/Placeholder/Placeholder.tsx +++ b/src/routes/Calendar/Placeholder/Placeholder.tsx @@ -33,7 +33,7 @@ const Placeholder = () => {
- From 53174981a901ffa53d5a8da96dee57bb12a5466c Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 3 Oct 2024 15:52:25 +0200 Subject: [PATCH 080/336] refactor(Intro): make fb login compatible with shell --- package-lock.json | 17 +++++++- package.json | 3 +- src/routes/Intro/Intro.js | 14 ++++--- src/routes/Intro/useFacebookLogin.ts | 63 ++++++++++++++++++++++++++++ src/routes/Intro/useFacebookToken.js | 51 ---------------------- 5 files changed, 88 insertions(+), 60 deletions(-) create mode 100644 src/routes/Intro/useFacebookLogin.ts delete mode 100644 src/routes/Intro/useFacebookToken.js diff --git a/package-lock.json b/package-lock.json index 6f767069b..f2404dd17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "classnames": "2.3.1", "eventemitter3": "4.0.7", "filter-invalid-dom-props": "2.1.0", - "hat": "0.0.3", + "hat": "^0.0.3", "i18next": "^22.4.3", "langs": "^2.0.0", "lodash.debounce": "4.0.8", @@ -46,6 +46,7 @@ "@babel/plugin-proposal-object-rest-spread": "7.16.0", "@babel/preset-env": "7.16.0", "@babel/preset-react": "7.16.0", + "@types/hat": "^0.0.4", "@types/react": "^18.2.9", "babel-loader": "8.2.3", "clean-webpack-plugin": "4.0.0", @@ -3181,6 +3182,13 @@ "@types/node": "*" } }, + "node_modules/@types/hat": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@types/hat/-/hat-0.0.4.tgz", + "integrity": "sha512-HsNPoA1/v8x1d1jztZNI/RJNv7gvFsy2QVx9TEJyZ7S2aqJEDyRPiEYjr246tujQ6Br5ouH1VWIv8tXHYKlZUw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/html-minifier-terser": { "version": "6.0.0", "dev": true, @@ -6887,7 +6895,12 @@ }, "node_modules/hat": { "version": "0.0.3", - "license": "MIT/X11" + "resolved": "https://registry.npmjs.org/hat/-/hat-0.0.3.tgz", + "integrity": "sha512-zpImx2GoKXy42fVDSEad2BPKuSQdLcqsCYa48K3zHSzM/ugWuYjLDr8IXxpVuL7uCLHw56eaiLxCRthhOzf5ug==", + "license": "MIT/X11", + "engines": { + "node": "*" + } }, "node_modules/he": { "version": "1.2.0", diff --git a/package.json b/package.json index 73f27d28e..725c75658 100755 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "classnames": "2.3.1", "eventemitter3": "4.0.7", "filter-invalid-dom-props": "2.1.0", - "hat": "0.0.3", + "hat": "^0.0.3", "i18next": "^22.4.3", "langs": "^2.0.0", "lodash.debounce": "4.0.8", @@ -50,6 +50,7 @@ "@babel/plugin-proposal-object-rest-spread": "7.16.0", "@babel/preset-env": "7.16.0", "@babel/preset-react": "7.16.0", + "@types/hat": "^0.0.4", "@types/react": "^18.2.9", "babel-loader": "8.2.3", "clean-webpack-plugin": "4.0.0", diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index cde07bc96..c1fd82d74 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -10,7 +10,7 @@ const { Button, Image, useBinaryState } = require('stremio/common'); const CredentialsTextInput = require('./CredentialsTextInput'); const ConsentCheckbox = require('./ConsentCheckbox'); const PasswordResetModal = require('./PasswordResetModal'); -const useFacebookToken = require('./useFacebookToken'); +const useFacebookLogin = require('./useFacebookLogin'); const styles = require('./styles'); const SIGNUP_FORM = 'signup'; @@ -19,7 +19,7 @@ const LOGIN_FORM = 'login'; const Intro = ({ queryParams }) => { const { core } = useServices(); const routeFocused = useRouteFocused(); - const getFacebookToken = useFacebookToken(); + const startFacebookLogin = useFacebookLogin(); const emailRef = React.useRef(null); const passwordRef = React.useRef(null); const confirmPasswordRef = React.useRef(null); @@ -80,15 +80,17 @@ const Intro = ({ queryParams }) => { ); const loginWithFacebook = React.useCallback(() => { openLoaderModal(); - getFacebookToken() - .then((accessToken) => { + startFacebookLogin() + .then(({ email, password }) => { core.transport.dispatch({ action: 'Ctx', args: { action: 'Authenticate', args: { - type: 'Facebook', - token: accessToken, + type: 'Login', + email, + password, + facebook: true } } }); diff --git a/src/routes/Intro/useFacebookLogin.ts b/src/routes/Intro/useFacebookLogin.ts new file mode 100644 index 000000000..a1097111b --- /dev/null +++ b/src/routes/Intro/useFacebookLogin.ts @@ -0,0 +1,63 @@ +// Copyright (C) 2017-2023 Smart code 203358507 + +import { useCallback, useEffect, useRef } from 'react'; +import hat from 'hat'; +import { usePlatform } from 'stremio/common'; + +const STREMIO_URL = 'https://www.strem.io'; +const MAX_TRIES = 10; + +const getCredentials = async (state: string) => { + try { + const response = await fetch(`${STREMIO_URL}/login-fb-get-acc/${state}`); + const { user } = await response.json(); + + return Promise.resolve({ + email: user.email, + password: user.fbLoginToken, + }); + } catch (e) { + console.error('Failed to get credentials from facebook auth', e); + return Promise.reject(e); + } +}; + +const useFacebookLogin = () => { + const platform = usePlatform(); + const timeout = useRef(null); + + const startFacebookLogin = useCallback(() => { + return new Promise((resolve, reject) => { + const state = hat(128); + let tries = 0; + + platform.openExternal(`${STREMIO_URL}/login-fb/${state}`); + + const waitForCredentials = () => { + timeout.current && clearTimeout(timeout.current); + timeout.current = setTimeout(() => { + if (tries >= MAX_TRIES) + return reject(new Error('Failed to authenticate with facebook')); + + tries++; + + getCredentials(state) + .then(resolve) + .catch(waitForCredentials); + }, 1000); + }; + + waitForCredentials(); + }); + }, []); + + useEffect(() => { + return () => { + timeout.current && clearTimeout(timeout.current); + }; + }, []); + + return startFacebookLogin; +}; + +module.exports = useFacebookLogin; diff --git a/src/routes/Intro/useFacebookToken.js b/src/routes/Intro/useFacebookToken.js deleted file mode 100644 index 8f978e248..000000000 --- a/src/routes/Intro/useFacebookToken.js +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const React = require('react'); - -const useFacebookToken = () => { - const getToken = React.useCallback(() => { - return new Promise((resolve, reject) => { - if (typeof FB === 'undefined') { - reject(new Error('Failed to connect to Facebook')); - return; - } - - FB.getLoginStatus((resp) => { - if (resp && resp.authResponse && typeof resp.authResponse.accessToken === 'string') { - resolve(resp.authResponse.accessToken); - return; - } - - FB.login((resp) => { - if (!resp || !resp.authResponse || typeof resp.authResponse.accessToken !== 'string') { - reject(new Error('Failed to get token from Facebook')); - return; - } - - resolve(resp.authResponse.accessToken); - }); - }); - }); - }, []); - React.useEffect(() => { - window.fbAsyncInit = function() { - FB.init({ - appId: '1537119779906825', - status: true, - xfbml: false, - version: 'v2.7' - }); - }; - const sdkScriptElement = document.createElement('script'); - sdkScriptElement.src = 'https://connect.facebook.net/en_US/sdk.js'; - sdkScriptElement.async = true; - sdkScriptElement.defer = true; - document.body.appendChild(sdkScriptElement); - return () => { - document.body.removeChild(sdkScriptElement); - }; - }, []); - return getToken; -}; - -module.exports = useFacebookToken; From 6305743c1afc1fe8fbec68d71c7a4aef2878f583 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 3 Oct 2024 16:25:30 +0200 Subject: [PATCH 081/336] feat(Intro): add cancel button to facebook modal --- src/routes/Intro/Intro.js | 11 ++++++++++- src/routes/Intro/styles.less | 25 +++++++++++++++++++++++-- src/routes/Intro/useFacebookLogin.ts | 17 +++++++++++------ 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index c1fd82d74..bcdd74aff 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -1,6 +1,7 @@ // Copyright (C) 2017-2023 Smart code 203358507 const React = require('react'); +const { useTranslation } = require('react-i18next'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const { default: Icon } = require('@stremio/stremio-icons/react'); @@ -18,8 +19,9 @@ const LOGIN_FORM = 'login'; const Intro = ({ queryParams }) => { const { core } = useServices(); + const { t } = useTranslation(); const routeFocused = useRouteFocused(); - const startFacebookLogin = useFacebookLogin(); + const [startFacebookLogin, stopFacebookLogin] = useFacebookLogin(); const emailRef = React.useRef(null); const passwordRef = React.useRef(null); const confirmPasswordRef = React.useRef(null); @@ -100,6 +102,10 @@ const Intro = ({ queryParams }) => { dispatch({ type: 'error', error: error.message }); }); }, []); + const cancelLoginWithFacebook = React.useCallback(() => { + stopFacebookLogin(); + closeLoaderModal(); + }, []); const loginWithEmail = React.useCallback(() => { if (typeof state.email !== 'string' || state.email.length === 0 || !emailRef.current.validity.valid) { dispatch({ type: 'error', error: 'Invalid email' }); @@ -385,6 +391,9 @@ const Intro = ({ queryParams }) => {
Authenticating...
+
: diff --git a/src/routes/Intro/styles.less b/src/routes/Intro/styles.less index 1b1200a7c..61a62aff1 100644 --- a/src/routes/Intro/styles.less +++ b/src/routes/Intro/styles.less @@ -200,7 +200,8 @@ flex-direction: column; align-items: center; justify-content: center; - padding: 2rem; + gap: 1rem; + padding: 2.5rem; border-radius: var(--border-radius); background-color: var(--modal-background-color); @@ -218,7 +219,6 @@ flex: none; width: 5rem; height: 5rem; - margin-bottom: 1rem; color: var(--primary-foreground-color); animation: 1s linear infinite alternate flash; } @@ -228,6 +228,27 @@ color: var(--primary-foreground-color); animation: 1s linear infinite alternate flash; } + + .button { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + height: 3.5rem; + width: 100%; + border-radius: 3.5rem; + padding: 0 1rem; + margin-top: 2rem; + font-size: 1.1rem; + font-weight: 700; + color: var(--primary-foreground-color); + outline: var(--focus-outline-size) solid var(--primary-foreground-color); + + &:hover { + color: var(--secondary-foreground-color); + background-color: var(--primary-foreground-color); + } + } } } diff --git a/src/routes/Intro/useFacebookLogin.ts b/src/routes/Intro/useFacebookLogin.ts index a1097111b..c59f6e275 100644 --- a/src/routes/Intro/useFacebookLogin.ts +++ b/src/routes/Intro/useFacebookLogin.ts @@ -26,7 +26,7 @@ const useFacebookLogin = () => { const platform = usePlatform(); const timeout = useRef(null); - const startFacebookLogin = useCallback(() => { + const start = useCallback(() => { return new Promise((resolve, reject) => { const state = hat(128); let tries = 0; @@ -51,13 +51,18 @@ const useFacebookLogin = () => { }); }, []); - useEffect(() => { - return () => { - timeout.current && clearTimeout(timeout.current); - }; + const stop = useCallback(() => { + timeout.current && clearTimeout(timeout.current); }, []); - return startFacebookLogin; + useEffect(() => { + return () => stop(); + }, []); + + return [ + start, + stop, + ]; }; module.exports = useFacebookLogin; From c3f0c91ea88d80559d0cc6d5019a3cbb2ab1b85d Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 3 Oct 2024 16:29:39 +0200 Subject: [PATCH 082/336] refactor(Intro): increase waitFroCredentials max tries --- src/routes/Intro/useFacebookLogin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Intro/useFacebookLogin.ts b/src/routes/Intro/useFacebookLogin.ts index c59f6e275..f447079ec 100644 --- a/src/routes/Intro/useFacebookLogin.ts +++ b/src/routes/Intro/useFacebookLogin.ts @@ -5,7 +5,7 @@ import hat from 'hat'; import { usePlatform } from 'stremio/common'; const STREMIO_URL = 'https://www.strem.io'; -const MAX_TRIES = 10; +const MAX_TRIES = 25; const getCredentials = async (state: string) => { try { From a95458f99552c9850be083f7064d40db7ba229de Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 3 Oct 2024 16:49:48 +0200 Subject: [PATCH 083/336] fix(useFacebookLogin): requests were made after cancelling --- src/routes/Intro/useFacebookLogin.ts | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/routes/Intro/useFacebookLogin.ts b/src/routes/Intro/useFacebookLogin.ts index f447079ec..992c6501a 100644 --- a/src/routes/Intro/useFacebookLogin.ts +++ b/src/routes/Intro/useFacebookLogin.ts @@ -1,6 +1,6 @@ // Copyright (C) 2017-2023 Smart code 203358507 -import { useCallback, useEffect, useRef } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import hat from 'hat'; import { usePlatform } from 'stremio/common'; @@ -24,16 +24,18 @@ const getCredentials = async (state: string) => { const useFacebookLogin = () => { const platform = usePlatform(); + const started = useRef(false); const timeout = useRef(null); - const start = useCallback(() => { - return new Promise((resolve, reject) => { - const state = hat(128); - let tries = 0; + const start = useCallback(() => new Promise((resolve, reject) => { + started.current = true; + const state = hat(128); + let tries = 0; - platform.openExternal(`${STREMIO_URL}/login-fb/${state}`); + platform.openExternal(`${STREMIO_URL}/login-fb/${state}`); - const waitForCredentials = () => { + const waitForCredentials = () => { + if (started.current) { timeout.current && clearTimeout(timeout.current); timeout.current = setTimeout(() => { if (tries >= MAX_TRIES) @@ -45,13 +47,14 @@ const useFacebookLogin = () => { .then(resolve) .catch(waitForCredentials); }, 1000); - }; + } + }; - waitForCredentials(); - }); - }, []); + waitForCredentials(); + }), []); const stop = useCallback(() => { + started.current = false; timeout.current && clearTimeout(timeout.current); }, []); From bb5866955e65e38cdac3fa367c7abba7c74147c5 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 3 Oct 2024 17:00:22 +0200 Subject: [PATCH 084/336] refactor(useFacebookLogin): remove unused import --- src/routes/Intro/useFacebookLogin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Intro/useFacebookLogin.ts b/src/routes/Intro/useFacebookLogin.ts index 992c6501a..901ca9495 100644 --- a/src/routes/Intro/useFacebookLogin.ts +++ b/src/routes/Intro/useFacebookLogin.ts @@ -1,6 +1,6 @@ // Copyright (C) 2017-2023 Smart code 203358507 -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef } from 'react'; import hat from 'hat'; import { usePlatform } from 'stremio/common'; From 13ef4d86aad8e37c7d33dc687c74418371739772 Mon Sep 17 00:00:00 2001 From: Tim Date: Sun, 6 Oct 2024 10:01:15 +0200 Subject: [PATCH 085/336] fix(AddonsDetailsModal): import error --- src/common/AddonDetailsModal/AddonDetailsModal.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/AddonDetailsModal/AddonDetailsModal.js b/src/common/AddonDetailsModal/AddonDetailsModal.js index b4ffdab71..1ebbb2e60 100644 --- a/src/common/AddonDetailsModal/AddonDetailsModal.js +++ b/src/common/AddonDetailsModal/AddonDetailsModal.js @@ -3,7 +3,8 @@ const React = require('react'); const PropTypes = require('prop-types'); const ModalDialog = require('stremio/common/ModalDialog'); -const { usePlatform, withCoreSuspender } = require('stremio/common/CoreSuspender'); +const { withCoreSuspender } = require('stremio/common/CoreSuspender'); +const { usePlatform } = require('stremio/common/Platform'); const { useServices } = require('stremio/services'); const AddonDetailsWithRemoteAndLocalAddon = withRemoteAndLocalAddon(require('./AddonDetails')); const useAddonDetails = require('./useAddonDetails'); From 5ca9d3a70196161c5919d9c70b99804eedd5cb84 Mon Sep 17 00:00:00 2001 From: Tim Date: Sun, 6 Oct 2024 19:23:04 +0200 Subject: [PATCH 086/336] chore: fix js imports resolution --- src/common/Platform/Platform.tsx | 2 +- src/common/useBinaryState.d.ts | 8 ++++++++ src/modules.d.ts | 9 ++++++--- tsconfig.json | 9 +++++---- 4 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 src/common/useBinaryState.d.ts diff --git a/src/common/Platform/Platform.tsx b/src/common/Platform/Platform.tsx index 69ff3e8c3..057e60703 100644 --- a/src/common/Platform/Platform.tsx +++ b/src/common/Platform/Platform.tsx @@ -9,7 +9,7 @@ interface PlatformContext { openExternal: (url: string) => void; } -const PlatformContext = createContext(null); +const PlatformContext = createContext({} as PlatformContext); type Props = { children: JSX.Element; diff --git a/src/common/useBinaryState.d.ts b/src/common/useBinaryState.d.ts new file mode 100644 index 000000000..c61a28712 --- /dev/null +++ b/src/common/useBinaryState.d.ts @@ -0,0 +1,8 @@ +declare const useBinaryState: (initialValue?: boolean) => [ + boolean, + () => void, + () => void, + () => void, +]; + +export = useBinaryState; \ No newline at end of file diff --git a/src/modules.d.ts b/src/modules.d.ts index 70ebbd3fc..73d4eec32 100644 --- a/src/modules.d.ts +++ b/src/modules.d.ts @@ -1,3 +1,6 @@ -declare module '*.less'; -declare module 'stremio/common'; -declare module 'stremio/common/*'; \ No newline at end of file +declare module '*.less' { + const resource: { [key: string]: string }; + export = resource; +} + +declare module 'stremio/common/Button'; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 896a7d197..fd930dbcf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,10 +2,11 @@ "compilerOptions": { "lib": ["DOM", "DOM.Iterable"], "jsx": "react", - "baseUrl": "src", + "baseUrl": "./src", + "outDir": "./dist", "moduleResolution": "node", "paths": { - "stremio/*": ["src/*"], + "stremio/*": ["*"], }, "resolveJsonModule": true, "esModuleInterop": true, @@ -15,6 +16,6 @@ "strict": true, }, "include": [ - "src", - ], + "src/", + ] } From e51e6f415e4a39e23e1fab074a8db93bafb0e994 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 7 Oct 2024 12:17:33 +0200 Subject: [PATCH 087/336] chore: update eslint --- .eslintrc | 99 - eslint.config.mjs | 100 + package-lock.json | 2418 +++++++++++++---- package.json | 9 +- src/common/Chips/Chip/Chip.tsx | 2 +- src/common/Chips/Chip/index.ts | 2 +- src/common/Chips/Chips.tsx | 2 +- src/common/Chips/index.ts | 2 +- src/common/CoreSuspender.js | 1 + src/common/DelayedRenderer/DelayedRenderer.js | 3 +- .../MultiselectMenu/Dropdown/Dropdown.tsx | 5 +- .../Dropdown/Option/Option.tsx | 2 +- .../MultiselectMenu/Dropdown/Option/index.ts | 2 +- src/common/MultiselectMenu/Dropdown/index.ts | 2 +- .../MultiselectMenu/MultiselectMenu.tsx | 6 +- src/common/MultiselectMenu/index.ts | 2 +- src/common/MultiselectMenu/types.d.ts | 2 +- .../SearchBar/useLocalSearch.d.ts | 2 +- .../SearchBar/useSearchHistory.d.ts | 2 +- src/common/Platform/Platform.tsx | 2 +- src/common/Platform/device.ts | 2 +- src/common/Platform/index.ts | 2 +- src/common/Platform/useShell.ts | 2 +- src/common/Toast/ToastContext.js | 2 + src/common/useNotifications.d.ts | 2 +- src/common/useOutsideClick.ts | 2 +- src/common/useProfile.d.ts | 2 +- src/common/useStreamingServer.d.ts | 2 +- src/modules.d.ts | 2 +- src/routes/Addons/useInstalledAddons.d.ts | 2 +- src/routes/Addons/useRemoteAddons.d.ts | 2 +- src/routes/Board/useBoard.d.ts | 2 +- src/routes/Discover/useDiscover.d.ts | 2 +- src/routes/Library/useLibrary.d.ts | 2 +- src/routes/MetaDetails/useMetaDetails.d.ts | 2 +- src/routes/Player/usePlayer.d.ts | 2 +- src/routes/Player/useSettings.d.ts | 2 +- src/routes/Search/useSearch.d.ts | 2 +- src/services/Core/Core.d.ts | 2 +- src/services/Core/CoreTransport.d.ts | 2 +- src/services/Core/globals.d.ts | 2 +- src/services/Core/types.d.ts | 2 +- src/services/DragAndDrop/DragAndDrop.js | 2 +- src/services/ServicesContext/types.d.ts | 2 +- src/services/ServicesContext/useServices.d.ts | 2 +- src/services/Shell/ShellTransport.js | 1 + src/types/Addon.d.ts | 2 +- src/types/LibraryItem.d.ts | 2 +- src/types/MetaItem.d.ts | 2 +- src/types/Selectable.d.ts | 2 +- src/types/Stream.d.ts | 2 +- src/types/Video.d.ts | 2 +- src/types/global.d.ts | 4 +- src/types/models/Board.d.ts | 2 +- src/types/models/CatalogsWithExtra.d.ts | 2 +- src/types/models/Ctx.d.ts | 2 +- src/types/models/Discover.d.ts | 2 +- src/types/models/InstalledAddons.d.ts | 2 +- src/types/models/Library.d.ts | 2 +- src/types/models/LocalSearch.d.ts | 2 +- src/types/models/MetaDetails.d.ts | 2 +- src/types/models/Player.d.ts | 2 +- src/types/models/RemoteAddons.d.ts | 2 +- src/types/models/Search.d.ts | 2 +- src/types/models/StremingServer.d.ts | 2 +- src/types/types.d.ts | 4 +- webpack.config.js | 2 +- 67 files changed, 2090 insertions(+), 672 deletions(-) delete mode 100644 .eslintrc create mode 100644 eslint.config.mjs diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 88fa22404..000000000 --- a/.eslintrc +++ /dev/null @@ -1,99 +0,0 @@ -{ - "extends": [ - "eslint:recommended", - "plugin:react/recommended" - ], - "settings": { - "react": { - "version": "detect" - } - }, - "globals": { - "YT": "readonly", - "FB": "readonly", - "cast": "readonly", - "chrome": "readonly" - }, - "env": { - "node": true, - "commonjs": true, - "browser": true, - "es6": true - }, - "parserOptions": { - "ecmaVersion": 11, - "ecmaFeatures": { - "jsx": true - } - }, - "ignorePatterns": [ - "/*", - "!/src" - ], - "rules": { - "arrow-parens": "error", - "arrow-spacing": "error", - "block-spacing": "error", - "comma-spacing": "error", - "eol-last": "error", - "eqeqeq": "error", - "func-call-spacing": "error", - "indent": [ - "error", - 4, - { - "SwitchCase": 1 - } - ], - "no-console": [ - "error", - { - "allow": [ - "warn", - "error" - ] - } - ], - "no-extra-semi": "error", - "no-eq-null": "error", - "no-multi-spaces": "error", - "no-multiple-empty-lines": [ - "error", - { - "max": 1 - } - ], - "no-prototype-builtins": "off", - "no-template-curly-in-string": "error", - "no-trailing-spaces": "error", - "no-useless-concat": "error", - "no-unreachable": "error", - "no-unused-vars": [ - "error", - { - "varsIgnorePattern": "_" - } - ], - "prefer-const": "error", - "quotes": [ - "error", - "single" - ], - "quote-props": [ - "error", - "as-needed", - { - "unnecessary": false - } - ], - "semi": "error", - "semi-spacing": "error", - "space-before-blocks": "error", - "valid-typeof": [ - "error", - { - "requireStringLiterals": true - } - ] - } -} \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..acb2014cd --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,100 @@ +import globals from 'globals'; +import pluginJs from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import pluginReact from 'eslint-plugin-react'; +import stylistic from '@stylistic/eslint-plugin' + +export default [ + pluginJs.configs.recommended, + ...tseslint.configs.recommended, + ...tseslint.configs.stylistic, + pluginReact.configs.flat.recommended, + { + plugins: { + '@stylistic': stylistic + }, + }, + { + files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'] + }, + { + files: ['**/*.js'], + languageOptions: { + sourceType: 'commonjs', + ecmaVersion: 'latest', + } + }, + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + YT: 'readonly', + FB: 'readonly', + cast: 'readonly', + chrome: 'readonly', + } + } + }, + { + settings: { + react: { + version: 'detect', + }, + }, + }, + { + rules: { + 'no-redeclare': 'off', + 'eol-last': 'error', + 'eqeqeq': 'error', + 'no-console': ['error', { + allow: [ + 'warn', + 'error' + ] + }], + } + }, + { + rules: { + '@typescript-eslint/no-redeclare': 'off', + '@typescript-eslint/no-require-imports': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-empty-object-type': 'off', + '@typescript-eslint/no-unused-expressions': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-unused-vars': [ + 'error', + { + 'varsIgnorePattern': '_', + 'caughtErrorsIgnorePattern': '_', + } + ], + } + }, + { + rules: { + '@stylistic/arrow-parens': 'error', + '@stylistic/arrow-spacing': 'error', + '@stylistic/block-spacing': 'error', + '@stylistic/comma-spacing': 'error', + '@stylistic/semi-spacing': 'error', + '@stylistic/space-before-blocks': 'error', + '@stylistic/no-trailing-spaces': 'error', + '@stylistic/func-call-spacing': 'error', + '@stylistic/eol-last': 'error', + '@stylistic/no-multi-spaces': 'error', + '@stylistic/no-multiple-empty-lines': ['error', { + max: 1 + }], + '@stylistic/indent': ['error', 4], + '@stylistic/quotes': ['error', 'single'], + } + }, + { + rules: { + 'react/display-name': 'off', + } + } +]; diff --git a/package-lock.json b/package-lock.json index f2404dd17..e48fb0f8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,9 @@ "@babel/plugin-proposal-object-rest-spread": "7.16.0", "@babel/preset-env": "7.16.0", "@babel/preset-react": "7.16.0", + "@eslint/js": "^9.12.0", + "@stylistic/eslint-plugin": "^2.9.0", + "@stylistic/eslint-plugin-jsx": "^2.9.0", "@types/hat": "^0.0.4", "@types/react": "^18.2.9", "babel-loader": "8.2.3", @@ -54,8 +57,9 @@ "css-loader": "6.5.0", "cssnano": "5.0.8", "cssnano-preset-advanced": "5.1.4", - "eslint": "7.32.0", - "eslint-plugin-react": "7.26.1", + "eslint": "^9.12.0", + "eslint-plugin-react": "^7.37.1", + "globals": "^15.10.0", "html-webpack-plugin": "5.5.0", "jest": "27.3.1", "less": "4.1.2", @@ -66,6 +70,7 @@ "terser-webpack-plugin": "5.2.4", "ts-loader": "^9.5.1", "typescript": "^5.4.2", + "typescript-eslint": "^8.8.0", "webpack": "5.61.0", "webpack-cli": "4.9.1", "webpack-dev-server": "^4.7.4", @@ -1012,6 +1017,16 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.16.0", "dev": true, @@ -1630,6 +1645,16 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/types": { "version": "7.18.7", "dev": true, @@ -1655,64 +1680,198 @@ "node": ">=10.0.0" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", + "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "0.4.3", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.12.0", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/js": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", + "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", + "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "levn": "^0.4.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.0", + "node_modules/@humanfs/core": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", + "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", "dev": true, - "license": "BSD-3-Clause" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", + "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.0", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -3018,6 +3177,117 @@ "vtt.js": "github:jaruba/vtt.js#e4f5f5603730866bacb174a93f51b734c9f29e6a" } }, + "node_modules/@stylistic/eslint-plugin": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.9.0.tgz", + "integrity": "sha512-OrDyFAYjBT61122MIY1a3SfEgy3YCMgt2vL4eoPmvTwDBwyQhAXurxNQznlRD/jESNfYWfID8Ej+31LljvF7Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.8.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.9.0.tgz", + "integrity": "sha512-eP7fPtuwDcuF0RvvYPCemW2VbEE4vj9e9mK04w8lTWLC2/yMqhs+tQCJqA1vDSNg/y3sHEw1uYRrSZuCF8Q4wg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "dev": true, @@ -3224,7 +3494,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.9", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, @@ -3352,6 +3624,235 @@ "dev": true, "license": "MIT" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.0.tgz", + "integrity": "sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/type-utils": "8.8.0", + "@typescript-eslint/utils": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.0.tgz", + "integrity": "sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/typescript-estree": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.0.tgz", + "integrity": "sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.0.tgz", + "integrity": "sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.8.0", + "@typescript-eslint/utils": "8.8.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.0.tgz", + "integrity": "sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.0.tgz", + "integrity": "sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.0.tgz", + "integrity": "sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/typescript-estree": "8.8.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.0.tgz", + "integrity": "sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.8.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", "dev": true, @@ -3570,7 +4071,9 @@ } }, "node_modules/acorn": { - "version": "8.7.1", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "license": "MIT", "bin": { @@ -3610,6 +4113,8 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -3711,14 +4216,6 @@ "dev": true, "license": "MIT" }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "dev": true, @@ -3799,20 +4296,40 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "2.1.2", "dev": true, "license": "MIT" }, "node_modules/array-includes": { - "version": "3.1.4", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" }, "engines": { @@ -3841,14 +4358,19 @@ "node": ">=0.10.0" } }, - "node_modules/array.prototype.flatmap": { + "node_modules/array.prototype.findlast": { "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -3857,12 +4379,63 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/astral-regex": { - "version": "2.0.0", + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/async": { @@ -3912,6 +4485,22 @@ "postcss": "^8.1.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/babel-jest": { "version": "27.3.1", "dev": true, @@ -4376,12 +4965,20 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5214,12 +5811,68 @@ "node": ">=10" } }, - "node_modules/debug": { - "version": "4.3.2", + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -5284,6 +5937,24 @@ "node": ">= 10" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "dev": true, @@ -5293,14 +5964,21 @@ } }, "node_modules/define-properties": { - "version": "1.1.3", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "license": "MIT", "dependencies": { - "object-keys": "^1.0.12" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/del": { @@ -5399,17 +6077,6 @@ "buffer-indexof": "^1.0.0" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dom-converter": { "version": "0.2.0", "dev": true, @@ -5574,17 +6241,6 @@ "node": ">=10.13.0" } }, - "node_modules/enquirer": { - "version": "2.3.6", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/entities": { "version": "2.2.0", "dev": true, @@ -5625,30 +6281,58 @@ } }, "node_modules/es-abstract": { - "version": "1.19.1", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -5657,13 +6341,102 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "0.9.3", "dev": true, "license": "MIT" }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + } + }, "node_modules/es-to-primitive": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "license": "MIT", "dependencies": { @@ -5784,86 +6557,97 @@ } }, "node_modules/eslint": { - "version": "7.32.0", + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz", + "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.6.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.12.0", + "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.5", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", + "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^8.1.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3", + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-plugin-react": { - "version": "7.26.1", + "version": "7.37.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.1.tgz", + "integrity": "sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==", "dev": true, "license": "MIT", "dependencies": { - "array-includes": "^3.1.3", - "array.prototype.flatmap": "^1.2.4", + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "estraverse": "^5.2.0", + "es-iterator-helpers": "^1.0.19", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.0.4", - "object.entries": "^1.1.4", - "object.fromentries": "^2.0.4", - "object.hasown": "^1.0.0", - "object.values": "^1.1.4", - "prop-types": "^15.7.2", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.5" + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "node_modules/eslint-plugin-react/node_modules/doctrine": { @@ -5885,13 +6669,38 @@ "node": ">=4.0" } }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.3", + "node_modules/eslint-plugin-react/node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5909,43 +6718,25 @@ "node": ">=8.0.0" } }, - "node_modules/eslint-utils": { - "version": "2.1.0", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", + "node_modules/eslint/node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/@babel/code-frame": { - "version": "7.12.11", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.10.4" - } + "license": "MIT" }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", @@ -6003,26 +6794,58 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "5.1.2", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", + "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", "dev": true, - "license": "ISC", + "license": "BSD-2-Clause", "dependencies": { - "is-glob": "^4.0.1" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">= 6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.12.0", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { - "type-fest": "^0.20.2" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6036,26 +6859,52 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/eslint/node_modules/semver": { - "version": "7.3.5", - "dev": true, - "license": "ISC", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "p-locate": "^5.0.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint/node_modules/supports-color": { @@ -6070,35 +6919,34 @@ } }, "node_modules/espree": { - "version": "7.3.1", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", + "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.1.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/acorn": { - "version": "7.4.1", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "engines": { - "node": ">=0.4.0" + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", "dev": true, "license": "Apache-2.0", "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -6114,7 +6962,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -6335,7 +7185,9 @@ "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.2.7", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "license": "MIT", "dependencies": { @@ -6346,7 +7198,7 @@ "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, "node_modules/fast-glob/node_modules/glob-parent": { @@ -6403,14 +7255,16 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/file-type": { @@ -6533,33 +7387,23 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.2.2", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true, "license": "ISC" }, @@ -6596,6 +7440,16 @@ } } }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/form-data": { "version": "3.0.1", "dev": true, @@ -6670,14 +7524,43 @@ "license": "ISC" }, "node_modules/function-bind": { - "version": "1.1.1", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "license": "MIT" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/gensync": { "version": "1.0.0-beta.2", @@ -6696,13 +7579,20 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.1", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6733,12 +7623,15 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" }, "engines": { "node": ">= 0.4" @@ -6801,11 +7694,33 @@ } }, "node_modules/globals": { - "version": "11.12.0", + "version": "15.10.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.10.0.tgz", + "integrity": "sha512-tqFIbz83w4Y5TCbtgjZjApohbuh7K9BxGYFm7ifwDR240tvdb7P9x+/9VvUKlmkPoiknoJtanI8UOrqxS3a7lQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/globby": { @@ -6831,29 +7746,40 @@ "node": ">=0.10.0" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.8", "dev": true, "license": "ISC" }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, "node_modules/handle-thing": { "version": "2.0.1", "dev": true, "license": "MIT" }, - "node_modules/has": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { - "version": "1.0.1", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, "license": "MIT", "funding": { @@ -6868,8 +7794,36 @@ "node": ">=4" } }, - "node_modules/has-symbols": { + "node_modules/has-property-descriptors": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, "license": "MIT", "engines": { @@ -6880,11 +7834,13 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -6893,6 +7849,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hat": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/hat/-/hat-0.0.3.tgz", @@ -7215,7 +8184,9 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.1.8", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -7308,12 +8279,14 @@ "license": "ISC" }, "node_modules/internal-slot": { - "version": "1.0.3", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "hasown": "^2.0.0", "side-channel": "^1.0.4" }, "engines": { @@ -7364,13 +8337,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "dev": true, "license": "MIT" }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-bigint": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, "license": "MIT", "dependencies": { @@ -7393,6 +8401,8 @@ }, "node_modules/is-boolean-object": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, "license": "MIT", "dependencies": { @@ -7407,7 +8417,9 @@ } }, "node_modules/is-callable": { - "version": "1.2.4", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "license": "MIT", "engines": { @@ -7418,11 +8430,32 @@ } }, "node_modules/is-core-module": { - "version": "2.8.0", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "license": "MIT", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7464,6 +8497,19 @@ "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "dev": true, @@ -7485,6 +8531,22 @@ "node": ">=6" } }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "dev": true, @@ -7496,13 +8558,28 @@ "node": ">=0.10.0" } }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-module": { "version": "1.0.0", "dev": true, "license": "MIT" }, "node_modules/is-negative-zero": { - "version": "2.0.1", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "license": "MIT", "engines": { @@ -7521,7 +8598,9 @@ } }, "node_modules/is-number-object": { - "version": "1.0.6", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7626,10 +8705,31 @@ "dev": true, "license": "ISC" }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7661,6 +8761,8 @@ }, "node_modules/is-symbol": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, "license": "MIT", "dependencies": { @@ -7673,17 +8775,65 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "dev": true, "license": "MIT" }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { - "version": "1.0.1", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.0" + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7809,6 +8959,20 @@ "node": ">=8" } }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, "node_modules/jake": { "version": "10.8.5", "dev": true, @@ -9553,6 +10717,13 @@ "node": ">=4" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, "node_modules/json-parse-better-errors": { "version": "1.0.2", "dev": true, @@ -9631,6 +10802,16 @@ "node": ">=4.0" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kind-of": { "version": "6.0.3", "dev": true, @@ -9870,11 +11051,6 @@ "version": "4.1.1", "license": "MIT" }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.uniq": { "version": "4.5.0", "dev": true, @@ -10114,7 +11290,9 @@ "license": "ISC" }, "node_modules/minimatch": { - "version": "3.0.4", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { @@ -10141,7 +11319,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -10324,9 +11504,14 @@ } }, "node_modules/object-inspect": { - "version": "1.11.0", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -10355,13 +11540,15 @@ } }, "node_modules/object.assign": { - "version": "4.1.2", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, "engines": { @@ -10372,26 +11559,31 @@ } }, "node_modules/object.entries": { - "version": "1.1.5", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/object.fromentries": { - "version": "2.0.5", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -10400,26 +11592,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.hasown": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object.values": { - "version": "1.1.5", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -10496,7 +11678,9 @@ } }, "node_modules/optionator": { - "version": "0.9.1", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "dependencies": { @@ -10505,7 +11689,7 @@ "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -10839,6 +12023,16 @@ "ms": "^2.1.1" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { "version": "8.3.11", "dev": true, @@ -11477,14 +12671,6 @@ "dev": true, "license": "MIT" }, - "node_modules/progress": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/prompts": { "version": "2.4.2", "dev": true, @@ -11745,6 +12931,28 @@ "node": ">= 0.10" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regenerate": { "version": "1.4.2", "dev": true, @@ -11774,12 +12982,16 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.3.1", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -11788,17 +13000,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/regexpu-core": { "version": "4.8.0", "dev": true, @@ -12044,11 +13245,55 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.1.2", "dev": true, "license": "MIT" }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "dev": true, @@ -12111,7 +13356,9 @@ } }, "node_modules/semver": { - "version": "6.3.0", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -12154,11 +13401,6 @@ "dev": true, "license": "MIT" }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "dev": true, - "license": "MIT" - }, "node_modules/serialize-javascript": { "version": "6.0.0", "dev": true, @@ -12235,6 +13477,40 @@ "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "dev": true, @@ -12271,13 +13547,19 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12312,52 +13594,6 @@ "node": ">=8" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, "node_modules/sockjs": { "version": "0.3.24", "dev": true, @@ -12521,42 +13757,90 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.6", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.3.1", - "side-channel": "^1.0.4" + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimend": { - "version": "1.0.4", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.4", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12612,6 +13896,8 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", "engines": { @@ -12694,6 +13980,19 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/svgo": { "version": "2.7.0", "dev": true, @@ -12719,42 +14018,6 @@ "dev": true, "license": "MIT" }, - "node_modules/table": { - "version": "6.7.2", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/tapable": { "version": "2.2.1", "dev": true, @@ -13053,6 +14316,19 @@ "node": ">=6" } }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/ts-loader": { "version": "9.5.1", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", @@ -13190,17 +14466,6 @@ "node": ">=4" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "1.6.18", "dev": true, @@ -13213,6 +14478,83 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "dev": true, @@ -13234,14 +14576,40 @@ "node": ">=14.17" } }, - "node_modules/unbox-primitive": { - "version": "1.0.1", + "node_modules/typescript-eslint": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.8.0.tgz", + "integrity": "sha512-BjIT/VwJ8+0rVO01ZQ2ZVnjE1svFBiRczcpr1t1Yxt7sT25VSbPfrJtDsQ8uQTy2pilX5nI9gwxhUyLULNentw==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "@typescript-eslint/eslint-plugin": "8.8.0", + "@typescript-eslint/parser": "8.8.0", + "@typescript-eslint/utils": "8.8.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" }, "funding": { @@ -13462,11 +14830,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "dev": true, - "license": "MIT" - }, "node_modules/v8-to-istanbul": { "version": "8.1.0", "dev": true, @@ -13853,32 +15216,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-dev-server/node_modules/fast-glob": { - "version": "3.2.11", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/webpack-dev-server/node_modules/glob-parent": { - "version": "5.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/webpack-dev-server/node_modules/globby": { "version": "11.1.0", "dev": true, @@ -13898,14 +15235,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-dev-server/node_modules/ignore": { - "version": "5.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/webpack-dev-server/node_modules/is-path-inside": { "version": "3.0.3", "dev": true, @@ -14123,6 +15452,8 @@ }, "node_modules/which-boxed-primitive": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, "license": "MIT", "dependencies": { @@ -14136,13 +15467,88 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-builtin-type": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "dev": true, + "license": "MIT", + "dependencies": { + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wildcard": { "version": "2.0.0", "dev": true, "license": "MIT" }, "node_modules/word-wrap": { - "version": "1.2.3", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index 725c75658..910f236a7 100755 --- a/package.json +++ b/package.json @@ -50,6 +50,9 @@ "@babel/plugin-proposal-object-rest-spread": "7.16.0", "@babel/preset-env": "7.16.0", "@babel/preset-react": "7.16.0", + "@eslint/js": "^9.12.0", + "@stylistic/eslint-plugin": "^2.9.0", + "@stylistic/eslint-plugin-jsx": "^2.9.0", "@types/hat": "^0.0.4", "@types/react": "^18.2.9", "babel-loader": "8.2.3", @@ -58,8 +61,9 @@ "css-loader": "6.5.0", "cssnano": "5.0.8", "cssnano-preset-advanced": "5.1.4", - "eslint": "7.32.0", - "eslint-plugin-react": "7.26.1", + "eslint": "^9.12.0", + "eslint-plugin-react": "^7.37.1", + "globals": "^15.10.0", "html-webpack-plugin": "5.5.0", "jest": "27.3.1", "less": "4.1.2", @@ -70,6 +74,7 @@ "terser-webpack-plugin": "5.2.4", "ts-loader": "^9.5.1", "typescript": "^5.4.2", + "typescript-eslint": "^8.8.0", "webpack": "5.61.0", "webpack-cli": "4.9.1", "webpack-dev-server": "^4.7.4", diff --git a/src/common/Chips/Chip/Chip.tsx b/src/common/Chips/Chip/Chip.tsx index 403d198af..e3a7fa849 100644 --- a/src/common/Chips/Chip/Chip.tsx +++ b/src/common/Chips/Chip/Chip.tsx @@ -42,4 +42,4 @@ const Chip = memo(({ label, value, active, onSelect }: Props) => { ); }); -export default Chip; \ No newline at end of file +export default Chip; diff --git a/src/common/Chips/Chip/index.ts b/src/common/Chips/Chip/index.ts index 9713aecaa..f540cf064 100644 --- a/src/common/Chips/Chip/index.ts +++ b/src/common/Chips/Chip/index.ts @@ -1,4 +1,4 @@ // Copyright (C) 2017-2024 Smart code 203358507 import Chip from './Chip'; -export default Chip; \ No newline at end of file +export default Chip; diff --git a/src/common/Chips/Chips.tsx b/src/common/Chips/Chips.tsx index 4e02c620f..8804775b0 100644 --- a/src/common/Chips/Chips.tsx +++ b/src/common/Chips/Chips.tsx @@ -53,4 +53,4 @@ const Chips = memo(({ options, selected, onSelect }: Props) => { ); }); -export default Chips; \ No newline at end of file +export default Chips; diff --git a/src/common/Chips/index.ts b/src/common/Chips/index.ts index 883af30d1..b92e80c79 100644 --- a/src/common/Chips/index.ts +++ b/src/common/Chips/index.ts @@ -1,4 +1,4 @@ // Copyright (C) 2017-2024 Smart code 203358507 import Chips from './Chips'; -export default Chips; \ No newline at end of file +export default Chips; diff --git a/src/common/CoreSuspender.js b/src/common/CoreSuspender.js index a9e666b58..d225d5411 100644 --- a/src/common/CoreSuspender.js +++ b/src/common/CoreSuspender.js @@ -37,6 +37,7 @@ const useCoreSuspender = () => { return React.useContext(CoreSuspenderContext); }; +// eslint-disable-next-line @typescript-eslint/no-empty-function const withCoreSuspender = (Component, Fallback = () => { }) => { return function withCoreSuspender(props) { const { core } = useServices(); diff --git a/src/common/DelayedRenderer/DelayedRenderer.js b/src/common/DelayedRenderer/DelayedRenderer.js index cbf976ddb..940bc96bd 100644 --- a/src/common/DelayedRenderer/DelayedRenderer.js +++ b/src/common/DelayedRenderer/DelayedRenderer.js @@ -17,7 +17,8 @@ const DelayedRenderer = ({ children, delay }) => { }; DelayedRenderer.propTypes = { - children: PropTypes.node + children: PropTypes.node, + delay: PropTypes.number, }; module.exports = DelayedRenderer; diff --git a/src/common/MultiselectMenu/Dropdown/Dropdown.tsx b/src/common/MultiselectMenu/Dropdown/Dropdown.tsx index 9f82106d1..cb7de76c2 100644 --- a/src/common/MultiselectMenu/Dropdown/Dropdown.tsx +++ b/src/common/MultiselectMenu/Dropdown/Dropdown.tsx @@ -32,7 +32,7 @@ const Dropdown = ({ level, setLevel, options, onSelect, selectedOption, menuOpen {t('BACK')} - : null + : null } { options @@ -46,10 +46,9 @@ const Dropdown = ({ level, setLevel, options, onSelect, selectedOption, menuOpen /> )) - } ); }; -export default Dropdown; \ No newline at end of file +export default Dropdown; diff --git a/src/common/MultiselectMenu/Dropdown/Option/Option.tsx b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx index c7dbb4ebb..13ea37bd5 100644 --- a/src/common/MultiselectMenu/Dropdown/Option/Option.tsx +++ b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx @@ -43,4 +43,4 @@ const Option = ({ option, selectedOption, onSelect }: Props) => { ); }; -export default Option; \ No newline at end of file +export default Option; diff --git a/src/common/MultiselectMenu/Dropdown/Option/index.ts b/src/common/MultiselectMenu/Dropdown/Option/index.ts index 6004f7754..fee9da7be 100644 --- a/src/common/MultiselectMenu/Dropdown/Option/index.ts +++ b/src/common/MultiselectMenu/Dropdown/Option/index.ts @@ -2,4 +2,4 @@ import Option from './Option'; -export default Option; \ No newline at end of file +export default Option; diff --git a/src/common/MultiselectMenu/Dropdown/index.ts b/src/common/MultiselectMenu/Dropdown/index.ts index ce3622a25..52d853721 100644 --- a/src/common/MultiselectMenu/Dropdown/index.ts +++ b/src/common/MultiselectMenu/Dropdown/index.ts @@ -2,4 +2,4 @@ import Dropdown from './Dropdown'; -export default Dropdown; \ No newline at end of file +export default Dropdown; diff --git a/src/common/MultiselectMenu/MultiselectMenu.tsx b/src/common/MultiselectMenu/MultiselectMenu.tsx index 2bd298752..df4208c4c 100644 --- a/src/common/MultiselectMenu/MultiselectMenu.tsx +++ b/src/common/MultiselectMenu/MultiselectMenu.tsx @@ -25,7 +25,7 @@ const MultiselectMenu = ({ className, title, options, selectedOption, onSelect } const onOptionSelect = (value: number) => { level ? setLevel(level + 1) : onSelect(value), closeMenu(); }; - + return (
); }; -export default MultiselectMenu; \ No newline at end of file +export default MultiselectMenu; diff --git a/src/common/MultiselectMenu/index.ts b/src/common/MultiselectMenu/index.ts index e526218cd..0d7c60413 100644 --- a/src/common/MultiselectMenu/index.ts +++ b/src/common/MultiselectMenu/index.ts @@ -2,4 +2,4 @@ import MultiselectMenu from './MultiselectMenu'; -export default MultiselectMenu; \ No newline at end of file +export default MultiselectMenu; diff --git a/src/common/MultiselectMenu/types.d.ts b/src/common/MultiselectMenu/types.d.ts index 7ed039ddd..b59d699b6 100644 --- a/src/common/MultiselectMenu/types.d.ts +++ b/src/common/MultiselectMenu/types.d.ts @@ -6,4 +6,4 @@ type MultiselectMenuOption = { default?: boolean; hidden?: boolean; level?: MultiselectMenuOption[]; -}; \ No newline at end of file +}; diff --git a/src/common/NavBar/HorizontalNavBar/SearchBar/useLocalSearch.d.ts b/src/common/NavBar/HorizontalNavBar/SearchBar/useLocalSearch.d.ts index 1812b96f9..c86a2a6b8 100644 --- a/src/common/NavBar/HorizontalNavBar/SearchBar/useLocalSearch.d.ts +++ b/src/common/NavBar/HorizontalNavBar/SearchBar/useLocalSearch.d.ts @@ -1,2 +1,2 @@ declare const useLocalSearch: () => { items: LocalSearchItem[], search: (query: string) => void }; -export = useLocalSearch; \ No newline at end of file +export = useLocalSearch; diff --git a/src/common/NavBar/HorizontalNavBar/SearchBar/useSearchHistory.d.ts b/src/common/NavBar/HorizontalNavBar/SearchBar/useSearchHistory.d.ts index 6beedfc66..def3eb255 100644 --- a/src/common/NavBar/HorizontalNavBar/SearchBar/useSearchHistory.d.ts +++ b/src/common/NavBar/HorizontalNavBar/SearchBar/useSearchHistory.d.ts @@ -1,2 +1,2 @@ declare const useSearchHistory: () => { items: SearchHistory, clear: () => void }; -export = useSearchHistory; \ No newline at end of file +export = useSearchHistory; diff --git a/src/common/Platform/Platform.tsx b/src/common/Platform/Platform.tsx index 69ff3e8c3..2cd1932c5 100644 --- a/src/common/Platform/Platform.tsx +++ b/src/common/Platform/Platform.tsx @@ -45,7 +45,7 @@ const usePlatform = () => { return useContext(PlatformContext); }; -export { +export { PlatformProvider, usePlatform }; diff --git a/src/common/Platform/device.ts b/src/common/Platform/device.ts index 68ca72b32..dda45f795 100644 --- a/src/common/Platform/device.ts +++ b/src/common/Platform/device.ts @@ -28,4 +28,4 @@ const isMobile = ['ios', 'android'].includes(name); export { name, isMobile, -}; \ No newline at end of file +}; diff --git a/src/common/Platform/index.ts b/src/common/Platform/index.ts index 8d2b68f12..f6cb22c9c 100644 --- a/src/common/Platform/index.ts +++ b/src/common/Platform/index.ts @@ -2,4 +2,4 @@ import { PlatformProvider, usePlatform } from './Platform'; export { PlatformProvider, usePlatform, -}; \ No newline at end of file +}; diff --git a/src/common/Platform/useShell.ts b/src/common/Platform/useShell.ts index aaf5a028e..5e61bfe84 100644 --- a/src/common/Platform/useShell.ts +++ b/src/common/Platform/useShell.ts @@ -19,4 +19,4 @@ const useShell = () => { }; }; -export default useShell; \ No newline at end of file +export default useShell; diff --git a/src/common/Toast/ToastContext.js b/src/common/Toast/ToastContext.js index 152cbf675..6a5ede356 100644 --- a/src/common/Toast/ToastContext.js +++ b/src/common/Toast/ToastContext.js @@ -1,5 +1,7 @@ // Copyright (C) 2017-2023 Smart code 203358507 +/* eslint-disable @typescript-eslint/no-empty-function */ + const React = require('react'); const ToastContext = React.createContext({ diff --git a/src/common/useNotifications.d.ts b/src/common/useNotifications.d.ts index 7a6943654..e3cae5b81 100644 --- a/src/common/useNotifications.d.ts +++ b/src/common/useNotifications.d.ts @@ -1,2 +1,2 @@ declare const useNotifcations: () => Notifications; -export = useNotifcations; \ No newline at end of file +export = useNotifcations; diff --git a/src/common/useOutsideClick.ts b/src/common/useOutsideClick.ts index 815132924..182cf8e37 100644 --- a/src/common/useOutsideClick.ts +++ b/src/common/useOutsideClick.ts @@ -24,4 +24,4 @@ const useOutsideClick = (callback: () => void) => { return ref; }; -export default useOutsideClick; \ No newline at end of file +export default useOutsideClick; diff --git a/src/common/useProfile.d.ts b/src/common/useProfile.d.ts index be5aed774..9cdea8a00 100644 --- a/src/common/useProfile.d.ts +++ b/src/common/useProfile.d.ts @@ -1,2 +1,2 @@ declare const useProfile: () => Profile; -export = useProfile; \ No newline at end of file +export = useProfile; diff --git a/src/common/useStreamingServer.d.ts b/src/common/useStreamingServer.d.ts index 76d3167de..146c1500b 100644 --- a/src/common/useStreamingServer.d.ts +++ b/src/common/useStreamingServer.d.ts @@ -1,2 +1,2 @@ declare const useStreamingServer: () => StreamingServer; -export = useStreamingServer; \ No newline at end of file +export = useStreamingServer; diff --git a/src/modules.d.ts b/src/modules.d.ts index 70ebbd3fc..d2e09c121 100644 --- a/src/modules.d.ts +++ b/src/modules.d.ts @@ -1,3 +1,3 @@ declare module '*.less'; declare module 'stremio/common'; -declare module 'stremio/common/*'; \ No newline at end of file +declare module 'stremio/common/*'; diff --git a/src/routes/Addons/useInstalledAddons.d.ts b/src/routes/Addons/useInstalledAddons.d.ts index 72120dad4..7298b9895 100644 --- a/src/routes/Addons/useInstalledAddons.d.ts +++ b/src/routes/Addons/useInstalledAddons.d.ts @@ -1,2 +1,2 @@ declare const useInstalledAddons: (urlParams: UrlParams) => InstalledAddons; -export = useInstalledAddons; \ No newline at end of file +export = useInstalledAddons; diff --git a/src/routes/Addons/useRemoteAddons.d.ts b/src/routes/Addons/useRemoteAddons.d.ts index 520f53d60..854edcf15 100644 --- a/src/routes/Addons/useRemoteAddons.d.ts +++ b/src/routes/Addons/useRemoteAddons.d.ts @@ -1,2 +1,2 @@ declare const useRemoteAddons: (urlParams: UrlParams) => RemoteAddons; -export = useRemoteAddons; \ No newline at end of file +export = useRemoteAddons; diff --git a/src/routes/Board/useBoard.d.ts b/src/routes/Board/useBoard.d.ts index c0fe06d3c..e15070dd9 100644 --- a/src/routes/Board/useBoard.d.ts +++ b/src/routes/Board/useBoard.d.ts @@ -1,2 +1,2 @@ declare const useBoard: () => [Board, ({ start, end }: { start: number, end: number }) => void]; -export = useBoard; \ No newline at end of file +export = useBoard; diff --git a/src/routes/Discover/useDiscover.d.ts b/src/routes/Discover/useDiscover.d.ts index 3fbd7a512..0748c8d27 100644 --- a/src/routes/Discover/useDiscover.d.ts +++ b/src/routes/Discover/useDiscover.d.ts @@ -1,2 +1,2 @@ declare const useDiscover: (urlParams: UrlParams, searchParams: URLSearchParams) => [Discover, () => void]; -export = useDiscover; \ No newline at end of file +export = useDiscover; diff --git a/src/routes/Library/useLibrary.d.ts b/src/routes/Library/useLibrary.d.ts index f197b0820..dd440918e 100644 --- a/src/routes/Library/useLibrary.d.ts +++ b/src/routes/Library/useLibrary.d.ts @@ -1,2 +1,2 @@ declare const useLibrary: (model: string, urlParams: UrlParams, searchParams: URLSearchParams) => Library; -export = useLibrary; \ No newline at end of file +export = useLibrary; diff --git a/src/routes/MetaDetails/useMetaDetails.d.ts b/src/routes/MetaDetails/useMetaDetails.d.ts index 5146bed99..e2215194c 100644 --- a/src/routes/MetaDetails/useMetaDetails.d.ts +++ b/src/routes/MetaDetails/useMetaDetails.d.ts @@ -1,2 +1,2 @@ declare const useMetaDetails: (urlParams: UrlParams) => MetaDetails; -export = useMetaDetails; \ No newline at end of file +export = useMetaDetails; diff --git a/src/routes/Player/usePlayer.d.ts b/src/routes/Player/usePlayer.d.ts index 8580583f3..28beeeabd 100644 --- a/src/routes/Player/usePlayer.d.ts +++ b/src/routes/Player/usePlayer.d.ts @@ -1,2 +1,2 @@ declare const usePlayer: (urlParams: UrlParams, videoParams: any) => [Player, (time: number, duration: number, device: string) => void, (paused: boolean) => void, () => void, () => void]; -export = usePlayer; \ No newline at end of file +export = usePlayer; diff --git a/src/routes/Player/useSettings.d.ts b/src/routes/Player/useSettings.d.ts index 688445b1f..e3daf32cd 100644 --- a/src/routes/Player/useSettings.d.ts +++ b/src/routes/Player/useSettings.d.ts @@ -1,2 +1,2 @@ declare const useSettings: () => [Settings, (settings: any) => void]; -export = useSettings; \ No newline at end of file +export = useSettings; diff --git a/src/routes/Search/useSearch.d.ts b/src/routes/Search/useSearch.d.ts index 156cacbbf..dd8e77ef6 100644 --- a/src/routes/Search/useSearch.d.ts +++ b/src/routes/Search/useSearch.d.ts @@ -1,2 +1,2 @@ declare const useSearch: (searchParams: URLSearchParams) => [Search, (range: number) => void]; -export = useSearch; \ No newline at end of file +export = useSearch; diff --git a/src/services/Core/Core.d.ts b/src/services/Core/Core.d.ts index e9cfdef5b..ab03f3b1d 100644 --- a/src/services/Core/Core.d.ts +++ b/src/services/Core/Core.d.ts @@ -1,2 +1,2 @@ declare function Core(): Core; -export = Core; \ No newline at end of file +export = Core; diff --git a/src/services/Core/CoreTransport.d.ts b/src/services/Core/CoreTransport.d.ts index ef9b606ca..8a58f7451 100644 --- a/src/services/Core/CoreTransport.d.ts +++ b/src/services/Core/CoreTransport.d.ts @@ -1,2 +1,2 @@ declare function CoreTransport(): CoreTransport; -export = CoreTransport; \ No newline at end of file +export = CoreTransport; diff --git a/src/services/Core/globals.d.ts b/src/services/Core/globals.d.ts index ca2680a0e..dd7e39e4b 100644 --- a/src/services/Core/globals.d.ts +++ b/src/services/Core/globals.d.ts @@ -9,4 +9,4 @@ declare global { } } -export {}; \ No newline at end of file +export {}; diff --git a/src/services/Core/types.d.ts b/src/services/Core/types.d.ts index 73875adf9..7e4249ac8 100644 --- a/src/services/Core/types.d.ts +++ b/src/services/Core/types.d.ts @@ -25,4 +25,4 @@ interface CoreTransport { interface Core { active: boolean, transport: CoreTransport, -} \ No newline at end of file +} diff --git a/src/services/DragAndDrop/DragAndDrop.js b/src/services/DragAndDrop/DragAndDrop.js index 477362bb5..bc54e2f35 100644 --- a/src/services/DragAndDrop/DragAndDrop.js +++ b/src/services/DragAndDrop/DragAndDrop.js @@ -25,7 +25,7 @@ function DragAndDrop({ core }) { args: Array.from(new Uint8Array(torrent)) } }); - } catch (error) { + } catch (_error) { events.emit('error', { message: 'Failed to process file', file: { diff --git a/src/services/ServicesContext/types.d.ts b/src/services/ServicesContext/types.d.ts index 48a599ea2..432155719 100644 --- a/src/services/ServicesContext/types.d.ts +++ b/src/services/ServicesContext/types.d.ts @@ -4,4 +4,4 @@ type ServicesContext = { chromecast: any, keyboardShortcuts: any, dragAndDrop: any, -}; \ No newline at end of file +}; diff --git a/src/services/ServicesContext/useServices.d.ts b/src/services/ServicesContext/useServices.d.ts index bd4199743..710be6d01 100644 --- a/src/services/ServicesContext/useServices.d.ts +++ b/src/services/ServicesContext/useServices.d.ts @@ -1,2 +1,2 @@ declare const useService: () => ServicesContext; -export = useService; \ No newline at end of file +export = useService; diff --git a/src/services/Shell/ShellTransport.js b/src/services/Shell/ShellTransport.js index 4fba3ac08..c70e28008 100644 --- a/src/services/Shell/ShellTransport.js +++ b/src/services/Shell/ShellTransport.js @@ -45,6 +45,7 @@ function ShellTransport() { this.props = {}; + // eslint-disable-next-line @typescript-eslint/no-this-alias const shell = this; initialize() .then(() => { diff --git a/src/types/Addon.d.ts b/src/types/Addon.d.ts index 880ff2ca8..9274dd8b7 100644 --- a/src/types/Addon.d.ts +++ b/src/types/Addon.d.ts @@ -17,4 +17,4 @@ type Addon = { type AddonsDeepLinks = { addons: string, -}; \ No newline at end of file +}; diff --git a/src/types/LibraryItem.d.ts b/src/types/LibraryItem.d.ts index 69a42c8a4..4981e1191 100644 --- a/src/types/LibraryItem.d.ts +++ b/src/types/LibraryItem.d.ts @@ -31,4 +31,4 @@ type LibraryItemDeepLinks = { metaDetailsStreams: string | null, player: string | null, externalPlayer: ExternalPlayerLinks | null, -}; \ No newline at end of file +}; diff --git a/src/types/MetaItem.d.ts b/src/types/MetaItem.d.ts index ae7e2fe55..1eac35151 100644 --- a/src/types/MetaItem.d.ts +++ b/src/types/MetaItem.d.ts @@ -29,4 +29,4 @@ type MetaItemDeepLinks = { metaDetailsVideos: string | null, metaDetailsStreams: string | null, player: string | null, -}; \ No newline at end of file +}; diff --git a/src/types/Selectable.d.ts b/src/types/Selectable.d.ts index 36d4be598..cbabdd697 100644 --- a/src/types/Selectable.d.ts +++ b/src/types/Selectable.d.ts @@ -24,4 +24,4 @@ type SelectableCatalog = { name: string, selected: boolean, deepLinks: T, -}; \ No newline at end of file +}; diff --git a/src/types/Stream.d.ts b/src/types/Stream.d.ts index 9d9cdebf3..2400c9725 100644 --- a/src/types/Stream.d.ts +++ b/src/types/Stream.d.ts @@ -15,4 +15,4 @@ type Stream = { player: string, externalPlayer: ExternalPlayerLinks, }, -}; \ No newline at end of file +}; diff --git a/src/types/Video.d.ts b/src/types/Video.d.ts index 645fa2a4c..92bc704f5 100644 --- a/src/types/Video.d.ts +++ b/src/types/Video.d.ts @@ -14,4 +14,4 @@ type Video = { episode?: number, streams: Stream[], trailerStreams: TrailerStream[], -}; \ No newline at end of file +}; diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 97da1d705..5effeffd4 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -1,3 +1,5 @@ +/* eslint-disable no-var */ + interface QtTransport { send: (message: string) => void, } @@ -10,4 +12,4 @@ declare global { var qt: Qt | undefined; } -export { }; \ No newline at end of file +export { }; diff --git a/src/types/models/Board.d.ts b/src/types/models/Board.d.ts index f03046102..4c9445e3a 100644 --- a/src/types/models/Board.d.ts +++ b/src/types/models/Board.d.ts @@ -1 +1 @@ -type Board = CatalogsWithExtra; \ No newline at end of file +type Board = CatalogsWithExtra; diff --git a/src/types/models/CatalogsWithExtra.d.ts b/src/types/models/CatalogsWithExtra.d.ts index 7a8a4efad..7931dc4b7 100644 --- a/src/types/models/CatalogsWithExtra.d.ts +++ b/src/types/models/CatalogsWithExtra.d.ts @@ -8,4 +8,4 @@ type CatalogsWithExtra = { type: string | null, extra: [string, string][] } | null, -}; \ No newline at end of file +}; diff --git a/src/types/models/Ctx.d.ts b/src/types/models/Ctx.d.ts index 74f770698..33da9f366 100644 --- a/src/types/models/Ctx.d.ts +++ b/src/types/models/Ctx.d.ts @@ -71,4 +71,4 @@ type Ctx = { profile: Profile, notifications: Notifications, searchHistory: SearchHistory, -}; \ No newline at end of file +}; diff --git a/src/types/models/Discover.d.ts b/src/types/models/Discover.d.ts index 7c7d8d614..5f34c124e 100644 --- a/src/types/models/Discover.d.ts +++ b/src/types/models/Discover.d.ts @@ -23,4 +23,4 @@ type Discover = { selected: { request: ResourceRequest, } | null, -}; \ No newline at end of file +}; diff --git a/src/types/models/InstalledAddons.d.ts b/src/types/models/InstalledAddons.d.ts index 0bce5cff8..d31f70829 100644 --- a/src/types/models/InstalledAddons.d.ts +++ b/src/types/models/InstalledAddons.d.ts @@ -9,4 +9,4 @@ type InstalledAddons = { type: string, } } | null, -}; \ No newline at end of file +}; diff --git a/src/types/models/Library.d.ts b/src/types/models/Library.d.ts index 6599c2ccf..ffb693824 100644 --- a/src/types/models/Library.d.ts +++ b/src/types/models/Library.d.ts @@ -26,4 +26,4 @@ type Library = { type: string | null, } } | null, -}; \ No newline at end of file +}; diff --git a/src/types/models/LocalSearch.d.ts b/src/types/models/LocalSearch.d.ts index 9862ebcd6..720173c0c 100644 --- a/src/types/models/LocalSearch.d.ts +++ b/src/types/models/LocalSearch.d.ts @@ -7,4 +7,4 @@ type LocalSearchItem = { type LocalSearch = { items: LocalSearchItem[], -}; \ No newline at end of file +}; diff --git a/src/types/models/MetaDetails.d.ts b/src/types/models/MetaDetails.d.ts index efa7efc33..c7eeafb1b 100644 --- a/src/types/models/MetaDetails.d.ts +++ b/src/types/models/MetaDetails.d.ts @@ -24,4 +24,4 @@ type MetaDetails = { content: Loadable }[], title: string | null, -}; \ No newline at end of file +}; diff --git a/src/types/models/Player.d.ts b/src/types/models/Player.d.ts index 3dff6e3ec..6664e83f5 100644 --- a/src/types/models/Player.d.ts +++ b/src/types/models/Player.d.ts @@ -42,4 +42,4 @@ type Player = { } | null, subtitles: Subtitle[], title: string | null, -}; \ No newline at end of file +}; diff --git a/src/types/models/RemoteAddons.d.ts b/src/types/models/RemoteAddons.d.ts index 9c046e885..d745a5f15 100644 --- a/src/types/models/RemoteAddons.d.ts +++ b/src/types/models/RemoteAddons.d.ts @@ -7,4 +7,4 @@ type RemoteAddons = { selected: { request: ResourceRequest, } | null, -}; \ No newline at end of file +}; diff --git a/src/types/models/Search.d.ts b/src/types/models/Search.d.ts index b9c91ba67..5859b1633 100644 --- a/src/types/models/Search.d.ts +++ b/src/types/models/Search.d.ts @@ -1 +1 @@ -type Search = CatalogsWithExtra; \ No newline at end of file +type Search = CatalogsWithExtra; diff --git a/src/types/models/StremingServer.d.ts b/src/types/models/StremingServer.d.ts index f44563d9b..68b7d6d42 100644 --- a/src/types/models/StremingServer.d.ts +++ b/src/types/models/StremingServer.d.ts @@ -115,4 +115,4 @@ type StreamingServer = { torrent: [string, Loadable] | null, statistics: Loadable | null, playbackDevices: Loadable | null, -}; \ No newline at end of file +}; diff --git a/src/types/types.d.ts b/src/types/types.d.ts index 18c769a07..8b7a627b6 100644 --- a/src/types/types.d.ts +++ b/src/types/types.d.ts @@ -51,7 +51,7 @@ type BehaviorHints = { hasScheduledVideos: boolean, }; -type PosterShape = 'square' | 'landscape' | 'poster' | null; +type PosterShape = 'square' | 'landscape' | 'poster' | null; type Catalog = { label?: string, @@ -60,4 +60,4 @@ type Catalog = { content: T, installed?: boolean, deepLinks?: D, -}; \ No newline at end of file +}; diff --git a/webpack.config.js b/webpack.config.js index 8f62fa021..8e6cac439 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -194,7 +194,7 @@ module.exports = (env, argv) => ({ new CleanWebpackPlugin({ cleanOnceBeforeBuildPatterns: ['*'] }), - argv.mode === 'production' && + argv.mode === 'production' && new WorkboxPlugin.GenerateSW({ maximumFileSizeToCacheInBytes: 20000000, clientsClaim: true, From 401911dd5b07d7cae3aa8e5fcc567633dcef5372 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 7 Oct 2024 13:43:53 +0200 Subject: [PATCH 088/336] fix: lint --- src/common/useBinaryState.d.ts | 2 +- src/modules.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/useBinaryState.d.ts b/src/common/useBinaryState.d.ts index c61a28712..7a0185109 100644 --- a/src/common/useBinaryState.d.ts +++ b/src/common/useBinaryState.d.ts @@ -5,4 +5,4 @@ declare const useBinaryState: (initialValue?: boolean) => [ () => void, ]; -export = useBinaryState; \ No newline at end of file +export = useBinaryState; diff --git a/src/modules.d.ts b/src/modules.d.ts index 9b680c72c..66f93be4c 100644 --- a/src/modules.d.ts +++ b/src/modules.d.ts @@ -1,5 +1,5 @@ declare module '*.less' { - const resource: { [key: string]: string }; + const resource: Record; export = resource; } From 59ec8326036346e620ed5205cb60adb36f09b4b9 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 7 Oct 2024 14:21:55 +0200 Subject: [PATCH 089/336] 5.0.0-beta.12 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e48fb0f8c..46eb25c54 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "stremio", - "version": "5.0.0-beta.10", + "version": "5.0.0-beta.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "stremio", - "version": "5.0.0-beta.10", + "version": "5.0.0-beta.12", "license": "gpl-2.0", "dependencies": { "@babel/runtime": "7.16.0", diff --git a/package.json b/package.json index 910f236a7..b3e1e8086 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "stremio", "displayName": "Stremio", - "version": "5.0.0-beta.10", + "version": "5.0.0-beta.12", "author": "Smart Code OOD", "private": true, "license": "gpl-2.0", From 5f9b4ab0e24de085fb4a4dafac107d5bf11570b7 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 8 Oct 2024 14:32:23 +0200 Subject: [PATCH 090/336] fix(Platform): macos detection --- src/common/Platform/device.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/Platform/device.ts b/src/common/Platform/device.ts index dda45f795..dfb5aa690 100644 --- a/src/common/Platform/device.ts +++ b/src/common/Platform/device.ts @@ -17,7 +17,7 @@ const isIOS = APPLE_MOBILE_DEVICES.includes(platform) || (userAgent.includes('Ma // Edge case: iPad is included in this function // Keep in mind maxTouchPoints for Vision Pro might change in the future -const isVisionOS = userAgent.includes('Macintosh') || maxTouchPoints === 5; +const isVisionOS = userAgent.includes('Macintosh') && maxTouchPoints === 5; const bowser = Bowser.getParser(userAgent); const os = bowser.getOSName().toLowerCase(); From 1d0cb4dfa022db7fc1653e2c4d8a705d7b9f7332 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 9 Oct 2024 10:56:52 +0200 Subject: [PATCH 091/336] refactor(BottomSheet): make container follow to size of content --- src/common/BottomSheet/BottomSheet.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/BottomSheet/BottomSheet.less b/src/common/BottomSheet/BottomSheet.less index 0fef3faf1..b159242d0 100644 --- a/src/common/BottomSheet/BottomSheet.less +++ b/src/common/BottomSheet/BottomSheet.less @@ -28,8 +28,8 @@ .container { z-index: 1; position: absolute; - top: var(--horizontal-nav-bar-size); - height: 100%; + bottom: 0; + max-height: calc(100% - var(--horizontal-nav-bar-size)); width: 100%; display: flex; flex-direction: column; From 19085da76b700b97e6eaa0553e84600295ad3957 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 9 Oct 2024 11:02:12 +0200 Subject: [PATCH 092/336] refactor(BottomSheet): remove unnecessary useCallback --- src/common/BottomSheet/BottomSheet.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/BottomSheet/BottomSheet.tsx b/src/common/BottomSheet/BottomSheet.tsx index 98df5c00e..e767f1847 100644 --- a/src/common/BottomSheet/BottomSheet.tsx +++ b/src/common/BottomSheet/BottomSheet.tsx @@ -40,10 +40,10 @@ const BottomSheet = ({ children, title, show }: Props) => { setOffset(Math.max(0, clientY - startOffset)); }, [startOffset]); - const onTouchEnd = useCallback(() => { + const onTouchEnd = () => { setOffset((offset) => offset > CLOSE_THRESHOLD ? containerHeight() : 0); setStartOffset(0); - }, []); + }; const onTransitionEnd = useCallback(() => { (offset === containerHeight()) && close(); From b23204aa34bb1e2c33208227c7a19f14c8bfdc51 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Wed, 9 Oct 2024 14:11:34 +0300 Subject: [PATCH 093/336] add: logs --- src/routes/Settings/Settings.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 2ed0a1ab7..0fe3094ef 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -7,7 +7,7 @@ const { useTranslation } = require('react-i18next'); const { default: Icon } = require('@stremio/stremio-icons/react'); const { useRouteFocused } = require('stremio-router'); const { useServices } = require('stremio/services'); -const { Button, Checkbox, MainNavBars, Multiselect, ColorInput, TextInput, ModalDialog, useProfile, usePlatform, useStreamingServer, useBinaryState, withCoreSuspender, useToast } = require('stremio/common'); +const { Button, Checkbox, MainNavBars, Multiselect, ColorInput, TextInput, ModalDialog, useProfile, usePlatform, useStreamingServer, useBinaryState, withCoreSuspender, useToast, useModelState } = require('stremio/common'); const useProfileSettingsInputs = require('./useProfileSettingsInputs'); const useStreamingServerSettingsInputs = require('./useStreamingServerSettingsInputs'); const useDataExport = require('./useDataExport'); @@ -194,6 +194,9 @@ const Settings = () => { } closeConfigureServerUrlModal(); }, [routeFocused]); + const ctx = useModelState({ model: 'ctx' }); + console.log(profile); // eslint-disable-line no-console + console.log(ctx); // eslint-disable-line no-console return (
From d12766ecad4f668f89357d7b0614007a38b90e2a Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Mon, 21 Oct 2024 17:13:46 +0300 Subject: [PATCH 094/336] feat: Support Multiple Server URLs in the settings --- src/common/Checkbox/Checkbox.less | 92 +++++++++ src/common/Checkbox/Checkbox.tsx | 86 ++++++++ src/common/Checkbox/index.js | 5 - src/common/Checkbox/index.ts | 5 + .../HorizontalNavBar/SearchBar/SearchBar.js | 2 +- src/common/SearchBar/SearchBar.js | 2 +- src/common/SharePrompt/SharePrompt.js | 2 +- src/common/TextInput/TextInput.js | 43 ---- src/common/TextInput/TextInput.tsx | 49 +++++ src/common/TextInput/index.js | 5 - src/common/TextInput/index.ts | 5 + .../Checkbox.js => Toggle/Toggle.js} | 10 +- src/common/Toggle/index.js | 5 + src/common/{Checkbox => Toggle}/styles.less | 2 +- src/common/index.js | 8 +- src/common/useStreamingServerUrls.js | 96 +++++++++ src/routes/Intro/ConsentCheckbox/index.js | 5 - .../ConsentToggle.js} | 16 +- src/routes/Intro/ConsentToggle/index.js | 5 + .../styles.less | 4 +- .../CredentialsTextInput.js | 2 +- src/routes/Intro/Intro.js | 22 +- .../MetaDetails/VideosList/VideosList.js | 6 +- src/routes/MetaDetails/VideosList/styles.less | 2 +- src/routes/Settings/Settings.js | 97 +++------ .../Settings/URLsManager/Item/Item.less | 194 ++++++++++++++++++ src/routes/Settings/URLsManager/Item/Item.tsx | 148 +++++++++++++ src/routes/Settings/URLsManager/Item/index.ts | 5 + .../Settings/URLsManager/URLsManager.less | 81 ++++++++ .../Settings/URLsManager/URLsManager.tsx | 61 ++++++ src/routes/Settings/URLsManager/index.ts | 5 + src/routes/Settings/styles.less | 2 +- .../Settings/useProfileSettingsInputs.js | 36 +--- src/types/models/Ctx.d.ts | 8 + 34 files changed, 925 insertions(+), 191 deletions(-) create mode 100644 src/common/Checkbox/Checkbox.less create mode 100644 src/common/Checkbox/Checkbox.tsx delete mode 100644 src/common/Checkbox/index.js create mode 100644 src/common/Checkbox/index.ts delete mode 100644 src/common/TextInput/TextInput.js create mode 100644 src/common/TextInput/TextInput.tsx delete mode 100644 src/common/TextInput/index.js create mode 100644 src/common/TextInput/index.ts rename src/common/{Checkbox/Checkbox.js => Toggle/Toggle.js} (68%) create mode 100644 src/common/Toggle/index.js rename src/common/{Checkbox => Toggle}/styles.less (98%) create mode 100644 src/common/useStreamingServerUrls.js delete mode 100644 src/routes/Intro/ConsentCheckbox/index.js rename src/routes/Intro/{ConsentCheckbox/ConsentCheckbox.js => ConsentToggle/ConsentToggle.js} (74%) create mode 100644 src/routes/Intro/ConsentToggle/index.js rename src/routes/Intro/{ConsentCheckbox => ConsentToggle}/styles.less (90%) create mode 100644 src/routes/Settings/URLsManager/Item/Item.less create mode 100644 src/routes/Settings/URLsManager/Item/Item.tsx create mode 100644 src/routes/Settings/URLsManager/Item/index.ts create mode 100644 src/routes/Settings/URLsManager/URLsManager.less create mode 100644 src/routes/Settings/URLsManager/URLsManager.tsx create mode 100644 src/routes/Settings/URLsManager/index.ts diff --git a/src/common/Checkbox/Checkbox.less b/src/common/Checkbox/Checkbox.less new file mode 100644 index 000000000..8dea5fd1d --- /dev/null +++ b/src/common/Checkbox/Checkbox.less @@ -0,0 +1,92 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +.checkbox { + display: flex; + align-items: center; +} + +.checkbox label { + display: flex; + align-items: center; + cursor: pointer; +} + +.checkbox-container { + position: relative; + width: 1.25rem; + height: 1.25rem; + border: 2px solid var(--primary-accent-color); + border-radius: 0.25rem; + background-color: transparent; + display: flex; + align-items: center; + justify-content: center; + transition: background-color 0.2s, border-color 0.2s; + cursor: pointer; + outline: none; + user-select: none; + + &:focus { + outline: var(--focus-outline-size) solid var(--primary-accent-color); + outline-offset: 2px; + } + + &:hover { + background-color: var(--overlay-color); + } +} + +.checkbox-container input[type='checkbox'] { + opacity: 0; + width: 0; + height: 0; + position: absolute; +} + +.checkbox-icon { + color: var(--primary-foreground-color); + width: 1rem; +} + +.checkbox-label { + margin-left: 0.75rem; + color: var(--primary-foreground-color); + font-size: 1rem; +} + +.checkbox-checked .checkbox-container { + background-color: var(--primary-accent-color); + border-color: var(--primary-accent-color); +} + +.checkbox-checked .checkbox-icon { + color: var(--secondary-foreground-color); +} + +.checkbox-unchecked .checkbox-container { + background-color: transparent; + border-color: var(--primary-accent-color); +} + +.checkbox-disabled { + cursor: not-allowed; + opacity: 0.6; +} + +.checkbox-disabled .checkbox-container { + background-color: var(--overlay-color); + border-color: var(--overlay-color); +} + +.checkbox-disabled .checkbox-label { + color: var(--primary-foreground-color); + opacity: 0.6; +} + +.checkbox-error .checkbox-container { + border-color: var(--color-reddit); +} + +.checkbox-error .checkbox-label { + color: var(--color-reddit); +} diff --git a/src/common/Checkbox/Checkbox.tsx b/src/common/Checkbox/Checkbox.tsx new file mode 100644 index 000000000..2148e0dd9 --- /dev/null +++ b/src/common/Checkbox/Checkbox.tsx @@ -0,0 +1,86 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React, { useState, useEffect, DetailedHTMLProps, HTMLAttributes } from 'react'; +import classNames from 'classnames'; +import styles from './Checkbox.less'; +import Icon from '@stremio/stremio-icons/react'; + +type Props = { + disabled?: boolean; + value?: boolean; + className?: string; + onChange?: (checked: boolean) => void; + ariaLabel?: string; + error?: string; +}; + +const Checkbox = ({ disabled, value, className, onChange, ariaLabel, error }: Props) => { + const [isChecked, setIsChecked] = useState(false); + const [isError, setIsError] = useState(false); + const [isDisabled, setIsDisabled] = useState(disabled); + + const handleChangeCheckbox = () => { + if (disabled) { + return; + } + + setIsChecked(!isChecked); + onChange && onChange(!isChecked); + }; + + const handleEnterPress = (event: DetailedHTMLProps, HTMLDivElement>) => { + if ((event.key === 'Enter' || event.key === ' ') && !disabled) { + setIsChecked(!isChecked); + onChange && onChange(!isChecked); + } + }; + + useEffect(() => setIsDisabled(disabled), [disabled]); + + useEffect(() => setIsError(!!error), [error]); + + useEffect(() => { + const checked = typeof value === 'boolean' ? value : false; + setIsChecked(checked); + }, [value]); + + return ( + <> +
+ +
+ + ); +}; + +export default Checkbox; diff --git a/src/common/Checkbox/index.js b/src/common/Checkbox/index.js deleted file mode 100644 index b185f6cbc..000000000 --- a/src/common/Checkbox/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const Checkbox = require('./Checkbox'); - -module.exports = Checkbox; diff --git a/src/common/Checkbox/index.ts b/src/common/Checkbox/index.ts new file mode 100644 index 000000000..40b9097d9 --- /dev/null +++ b/src/common/Checkbox/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import Checkbox from './Checkbox'; + +export default Checkbox; diff --git a/src/common/NavBar/HorizontalNavBar/SearchBar/SearchBar.js b/src/common/NavBar/HorizontalNavBar/SearchBar/SearchBar.js index 5db06f1d0..40cfbed06 100644 --- a/src/common/NavBar/HorizontalNavBar/SearchBar/SearchBar.js +++ b/src/common/NavBar/HorizontalNavBar/SearchBar/SearchBar.js @@ -8,13 +8,13 @@ const { useTranslation } = require('react-i18next'); const { default: Icon } = require('@stremio/stremio-icons/react'); const { useRouteFocused } = require('stremio-router'); const Button = require('stremio/common/Button'); -const TextInput = require('stremio/common/TextInput'); const useTorrent = require('stremio/common/useTorrent'); const { withCoreSuspender } = require('stremio/common/CoreSuspender'); const useSearchHistory = require('./useSearchHistory'); const useLocalSearch = require('./useLocalSearch'); const styles = require('./styles'); const useBinaryState = require('stremio/common/useBinaryState'); +const { default: TextInput } = require('stremio/common/TextInput'); const SearchBar = React.memo(({ className, query, active }) => { const { t } = useTranslation(); diff --git a/src/common/SearchBar/SearchBar.js b/src/common/SearchBar/SearchBar.js index 3b7013aa0..23ad327e0 100644 --- a/src/common/SearchBar/SearchBar.js +++ b/src/common/SearchBar/SearchBar.js @@ -4,7 +4,7 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const { default: Icon } = require('@stremio/stremio-icons/react'); -const TextInput = require('stremio/common/TextInput'); +const { default: TextInput } = require('../TextInput'); const SearchBarPlaceholder = require('./SearchBarPlaceholder'); const styles = require('./styles'); diff --git a/src/common/SharePrompt/SharePrompt.js b/src/common/SharePrompt/SharePrompt.js index 2d25682e4..4d49087c8 100644 --- a/src/common/SharePrompt/SharePrompt.js +++ b/src/common/SharePrompt/SharePrompt.js @@ -8,8 +8,8 @@ const { default: Icon } = require('@stremio/stremio-icons/react'); const { useRouteFocused } = require('stremio-router'); const { useServices } = require('stremio/services'); const useToast = require('stremio/common/Toast/useToast'); +const { default: TextInput } = require('../TextInput'); const Button = require('stremio/common/Button'); -const TextInput = require('stremio/common/TextInput'); const styles = require('./styles'); const SharePrompt = ({ className, url }) => { diff --git a/src/common/TextInput/TextInput.js b/src/common/TextInput/TextInput.js deleted file mode 100644 index 742e87dfc..000000000 --- a/src/common/TextInput/TextInput.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const React = require('react'); -const PropTypes = require('prop-types'); -const classnames = require('classnames'); -const styles = require('./styles'); - -const TextInput = React.forwardRef((props, ref) => { - const onKeyDown = React.useCallback((event) => { - if (typeof props.onKeyDown === 'function') { - props.onKeyDown(event); - } - - if (event.key === 'Enter' && !event.nativeEvent.submitPrevented && typeof props.onSubmit === 'function') { - props.onSubmit(event); - } - }, [props.onKeyDown, props.onSubmit]); - return ( - - ); -}); - -TextInput.displayName = 'TextInput'; - -TextInput.propTypes = { - className: PropTypes.string, - disabled: PropTypes.bool, - onKeyDown: PropTypes.func, - onSubmit: PropTypes.func -}; - -module.exports = TextInput; diff --git a/src/common/TextInput/TextInput.tsx b/src/common/TextInput/TextInput.tsx new file mode 100644 index 000000000..b409f229c --- /dev/null +++ b/src/common/TextInput/TextInput.tsx @@ -0,0 +1,49 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React from 'react'; +import classnames from 'classnames'; +import styles from './styles.less'; + +type Props = React.InputHTMLAttributes & { + className?: string; + disabled?: boolean; + onKeyDown?: (event: React.KeyboardEvent) => void; + onSubmit?: (event: React.KeyboardEvent) => void; +}; + +const TextInput = React.forwardRef((props, ref) => { + const { onSubmit, className, disabled, ...rest } = props; + + const onKeyDown = React.useCallback((event: React.KeyboardEvent) => { + if (typeof props.onKeyDown === 'function') { + props.onKeyDown(event); + } + + if ( + event.key === 'Enter' && + !(event.nativeEvent as any).submitPrevented && + typeof onSubmit === 'function' + ) { + onSubmit(event); + } + }, [props.onKeyDown, onSubmit]); + + return ( + + ); +}); + +TextInput.displayName = 'TextInput'; + +export default TextInput; diff --git a/src/common/TextInput/index.js b/src/common/TextInput/index.js deleted file mode 100644 index a61d9ca79..000000000 --- a/src/common/TextInput/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const TextInput = require('./TextInput'); - -module.exports = TextInput; diff --git a/src/common/TextInput/index.ts b/src/common/TextInput/index.ts new file mode 100644 index 000000000..60cbf8e67 --- /dev/null +++ b/src/common/TextInput/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import TextInput from './TextInput'; + +export default TextInput; diff --git a/src/common/Checkbox/Checkbox.js b/src/common/Toggle/Toggle.js similarity index 68% rename from src/common/Checkbox/Checkbox.js rename to src/common/Toggle/Toggle.js index a823ce488..837944747 100644 --- a/src/common/Checkbox/Checkbox.js +++ b/src/common/Toggle/Toggle.js @@ -6,21 +6,21 @@ const classnames = require('classnames'); const Button = require('stremio/common/Button'); const styles = require('./styles'); -const Checkbox = React.forwardRef(({ className, checked, children, ...props }, ref) => { +const Toggle = React.forwardRef(({ className, checked, children, ...props }, ref) => { return ( - ); }); -Checkbox.displayName = 'Checkbox'; +Toggle.displayName = 'Toggle'; -Checkbox.propTypes = { +Toggle.propTypes = { className: PropTypes.string, checked: PropTypes.bool, children: PropTypes.node }; -module.exports = Checkbox; +module.exports = Toggle; diff --git a/src/common/Toggle/index.js b/src/common/Toggle/index.js new file mode 100644 index 000000000..ae6c69d8a --- /dev/null +++ b/src/common/Toggle/index.js @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2023 Smart code 203358507 + +const Toggle = require('./Toggle'); + +module.exports = Toggle; diff --git a/src/common/Checkbox/styles.less b/src/common/Toggle/styles.less similarity index 98% rename from src/common/Checkbox/styles.less rename to src/common/Toggle/styles.less index d8224db53..e1c2e9d0a 100644 --- a/src/common/Checkbox/styles.less +++ b/src/common/Toggle/styles.less @@ -8,7 +8,7 @@ @thumb-size: calc(@height - @thumb-margin); -.checkbox-container { +.toggle-container { position: relative; .toggle { diff --git a/src/common/index.js b/src/common/index.js index 5adef3e60..6387821f0 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -2,7 +2,7 @@ const AddonDetailsModal = require('./AddonDetailsModal'); const Button = require('./Button'); -const Checkbox = require('./Checkbox'); +const Toggle = require('./Toggle'); const { default: Chips } = require('./Chips'); const ColorInput = require('./ColorInput'); const ContinueWatchingItem = require('./ContinueWatchingItem'); @@ -25,7 +25,7 @@ const SearchBar = require('./SearchBar'); const StreamingServerWarning = require('./StreamingServerWarning'); const SharePrompt = require('./SharePrompt'); const Slider = require('./Slider'); -const TextInput = require('./TextInput'); +const { default: TextInput } = require('./TextInput'); const { ToastProvider, useToast } = require('./Toast'); const { TooltipProvider, Tooltip } = require('./Tooltips'); const comparatorWithPriorities = require('./comparatorWithPriorities'); @@ -47,11 +47,12 @@ const useStreamingServer = require('./useStreamingServer'); const useTorrent = require('./useTorrent'); const useTranslate = require('./useTranslate'); const EventModal = require('./EventModal'); +const { default: Checkbox } = require('./Checkbox'); module.exports = { AddonDetailsModal, Button, - Checkbox, + Toggle, Chips, ColorInput, ContinueWatchingItem, @@ -77,6 +78,7 @@ module.exports = { SharePrompt, Slider, TextInput, + Checkbox, ToastProvider, useToast, TooltipProvider, diff --git a/src/common/useStreamingServerUrls.js b/src/common/useStreamingServerUrls.js new file mode 100644 index 000000000..36c8f8b9e --- /dev/null +++ b/src/common/useStreamingServerUrls.js @@ -0,0 +1,96 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import { useCallback } from 'react'; +import { useServices } from 'stremio/services'; +import { useToast } from './Toast'; +import useModelState from './useModelState'; +import useProfile from './useProfile'; + +const useStreamingServerUrls = () => { + const { core } = useServices(); + const profile = useProfile(); + const toast = useToast(); + const ctx = useModelState({ model: 'ctx' }); + + const streamingServerUrls = ctx.streamingServerUrls.sort((a, b) => { + const dateA = new Date(a._mtime).getTime(); + const dateB = new Date(b._mtime).getTime(); + return dateA - dateB; + }) + + const onAdd = useCallback((url) => { + const isValidUrl = (url) => { + try { + new URL(url); + return true; + } catch (_) { + return false; + } + }; + + if (isValidUrl(url)) { + toast.show({ + type: 'success', + title: 'New URL added', + message: 'The new URL has been added successfully', + timeout: 4000 + }); + + core.transport.dispatch({ + action: 'Ctx', + args: { + action: 'AddServerUrl', + args: url, + } + }); + } else { + toast.show({ + type: 'error', + title: 'Invalid URL', + message: 'Please provide a valid URL', + timeout: 4000 + }); + } + }, []); + + const onDelete = useCallback((url) => { + core.transport.dispatch({ + action: 'Ctx', + args: { + action: 'DeleteServerUrl', + args: url, + } + }); + }, []); + const onSelect = useCallback((url) => { + core.transport.dispatch({ + action: 'Ctx', + args: { + action: 'UpdateSettings', + args: { + ...profile.settings, + streamingServerUrl: url + } + } + }); + }, []); + const onReload = useCallback(() => { + core.transport.dispatch({ + action: 'StreamingServer', + args: { + action: 'Reload' + } + }); + }, []); + + const actions = { + onAdd, + onDelete, + onSelect, + onReload + } + + return { streamingServerUrls, actions }; +}; + +export default useStreamingServerUrls; diff --git a/src/routes/Intro/ConsentCheckbox/index.js b/src/routes/Intro/ConsentCheckbox/index.js deleted file mode 100644 index 85376bae3..000000000 --- a/src/routes/Intro/ConsentCheckbox/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const ConsentCheckbox = require('./ConsentCheckbox'); - -module.exports = ConsentCheckbox; diff --git a/src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js b/src/routes/Intro/ConsentToggle/ConsentToggle.js similarity index 74% rename from src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js rename to src/routes/Intro/ConsentToggle/ConsentToggle.js index cdb5dd189..9940a817f 100644 --- a/src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js +++ b/src/routes/Intro/ConsentToggle/ConsentToggle.js @@ -3,11 +3,11 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); -const { Button, Checkbox } = require('stremio/common'); +const { Button, Toggle } = require('stremio/common'); const styles = require('./styles'); -const ConsentCheckbox = React.forwardRef(({ className, label, link, href, onToggle, ...props }, ref) => { - const checkboxOnClick = React.useCallback((event) => { +const ConsentToggle = React.forwardRef(({ className, label, link, href, onToggle, ...props }, ref) => { + const toggleOnClick = React.useCallback((event) => { if (typeof props.onClick === 'function') { props.onClick(event); } @@ -24,7 +24,7 @@ const ConsentCheckbox = React.forwardRef(({ className, label, link, href, onTogg event.nativeEvent.togglePrevented = true; }, []); return ( - +
{label} {' '} @@ -37,13 +37,13 @@ const ConsentCheckbox = React.forwardRef(({ className, label, link, href, onTogg null }
-
+ ); }); -ConsentCheckbox.displayName = 'ConsentCheckbox'; +ConsentToggle.displayName = 'ConsentToggle'; -ConsentCheckbox.propTypes = { +ConsentToggle.propTypes = { className: PropTypes.string, checked: PropTypes.bool, label: PropTypes.string, @@ -53,4 +53,4 @@ ConsentCheckbox.propTypes = { onClick: PropTypes.func }; -module.exports = ConsentCheckbox; +module.exports = ConsentToggle; diff --git a/src/routes/Intro/ConsentToggle/index.js b/src/routes/Intro/ConsentToggle/index.js new file mode 100644 index 000000000..8edfe4a27 --- /dev/null +++ b/src/routes/Intro/ConsentToggle/index.js @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2023 Smart code 203358507 + +const ConsentToggle = require('./ConsentToggle'); + +module.exports = ConsentToggle; diff --git a/src/routes/Intro/ConsentCheckbox/styles.less b/src/routes/Intro/ConsentToggle/styles.less similarity index 90% rename from src/routes/Intro/ConsentCheckbox/styles.less rename to src/routes/Intro/ConsentToggle/styles.less index 2bf136924..494c9cc35 100644 --- a/src/routes/Intro/ConsentCheckbox/styles.less +++ b/src/routes/Intro/ConsentToggle/styles.less @@ -2,11 +2,11 @@ @import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; -:import('~stremio/common/Checkbox/styles.less') { +:import('~stremio/common/Toggle/styles.less') { checkbox-icon: icon; } -.consent-checkbox-container { +.consent-toogle-container { display: flex; flex-direction: row; align-items: center; diff --git a/src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js b/src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js index 61c558cb0..36d26e880 100644 --- a/src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js +++ b/src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js @@ -2,7 +2,7 @@ const React = require('react'); const PropTypes = require('prop-types'); -const { TextInput } = require('stremio/common'); +const { default: TextInput } = require('stremio/common/TextInput'); const CredentialsTextInput = React.forwardRef((props, ref) => { const onKeyDown = React.useCallback((event) => { diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index bcdd74aff..35397c0ab 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -9,7 +9,7 @@ const { Modal, useRouteFocused } = require('stremio-router'); const { useServices } = require('stremio/services'); const { Button, Image, useBinaryState } = require('stremio/common'); const CredentialsTextInput = require('./CredentialsTextInput'); -const ConsentCheckbox = require('./ConsentCheckbox'); +const ConsentToggle = require('./ConsentToggle'); const PasswordResetModal = require('./PasswordResetModal'); const useFacebookLogin = require('./useFacebookLogin'); const styles = require('./styles'); @@ -54,7 +54,7 @@ const Intro = ({ queryParams }) => { error: '', [action.name]: action.value }; - case 'toggle-checkbox': + case 'toogle-checkbox': return { ...state, error: '', @@ -210,13 +210,13 @@ const Intro = ({ queryParams }) => { termsRef.current.focus(); }, []); const toggleTermsAccepted = React.useCallback(() => { - dispatch({ type: 'toggle-checkbox', name: 'termsAccepted' }); + dispatch({ type: 'toogle-checkbox', name: 'termsAccepted' }); }, []); const togglePrivacyPolicyAccepted = React.useCallback(() => { - dispatch({ type: 'toggle-checkbox', name: 'privacyPolicyAccepted' }); + dispatch({ type: 'toogle-checkbox', name: 'privacyPolicyAccepted' }); }, []); const toggleMarketingAccepted = React.useCallback(() => { - dispatch({ type: 'toggle-checkbox', name: 'marketingAccepted' }); + dispatch({ type: 'toogle-checkbox', name: 'marketingAccepted' }); }, []); const switchFormOnClick = React.useCallback(() => { const queryParams = new URLSearchParams([['form', state.form === SIGNUP_FORM ? LOGIN_FORM : SIGNUP_FORM]]); @@ -307,27 +307,27 @@ const Intro = ({ queryParams }) => { onChange={confirmPasswordOnChange} onSubmit={confirmPasswordOnSubmit} /> - - - { showNotificationsToggle && libraryItem ? - + {t('DETAIL_RECEIVE_NOTIF_SERIES')} - + : null } diff --git a/src/routes/MetaDetails/VideosList/styles.less b/src/routes/MetaDetails/VideosList/styles.less index e1b2215ae..9f9a7edee 100644 --- a/src/routes/MetaDetails/VideosList/styles.less +++ b/src/routes/MetaDetails/VideosList/styles.less @@ -36,7 +36,7 @@ } } - .notifications-checkbox { + .notifications-toggle { flex: none; display: flex; flex-direction: row; diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 0fe3094ef..5d1b024ff 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -7,11 +7,12 @@ const { useTranslation } = require('react-i18next'); const { default: Icon } = require('@stremio/stremio-icons/react'); const { useRouteFocused } = require('stremio-router'); const { useServices } = require('stremio/services'); -const { Button, Checkbox, MainNavBars, Multiselect, ColorInput, TextInput, ModalDialog, useProfile, usePlatform, useStreamingServer, useBinaryState, withCoreSuspender, useToast, useModelState } = require('stremio/common'); +const { Button, Toggle, MainNavBars, Multiselect, ColorInput, useProfile, usePlatform, useStreamingServer, withCoreSuspender, useToast } = require('stremio/common'); const useProfileSettingsInputs = require('./useProfileSettingsInputs'); const useStreamingServerSettingsInputs = require('./useStreamingServerSettingsInputs'); const useDataExport = require('./useDataExport'); const styles = require('./styles'); +const { default: URLsManager } = require('./URLsManager/URLsManager'); const GENERAL_SECTION = 'general'; const PLAYER_SECTION = 'player'; @@ -35,16 +36,15 @@ const Settings = () => { subtitlesBackgroundColorInput, subtitlesOutlineColorInput, audioLanguageSelect, - surroundSoundCheckbox, + surroundSoundToggle, seekTimeDurationSelect, seekShortTimeDurationSelect, - escExitFullscreenCheckbox, + escExitFullscreenToggle, playInExternalPlayerSelect, nextVideoPopupDurationSelect, - bingeWatchingCheckbox, - playInBackgroundCheckbox, - hardwareDecodingCheckbox, - streamingServerUrlInput + bingeWatchingToggle, + playInBackgroundToggle, + hardwareDecodingToggle, } = useProfileSettingsInputs(profile); const { streamingServerRemoteUrlInput, @@ -53,34 +53,11 @@ const Settings = () => { torrentProfileSelect, transcodingProfileSelect, } = useStreamingServerSettingsInputs(streamingServer); - const [configureServerUrlModalOpen, openConfigureServerUrlModal, closeConfigureServerUrlModal] = useBinaryState(false); - const configureServerUrlInputRef = React.useRef(null); - const configureServerUrlOnSubmit = React.useCallback(() => { - streamingServerUrlInput.onChange(configureServerUrlInputRef.current.value); - closeConfigureServerUrlModal(); - }, [streamingServerUrlInput]); const [traktAuthStarted, setTraktAuthStarted] = React.useState(false); const isTraktAuthenticated = React.useMemo(() => { return profile.auth !== null && profile.auth.user !== null && profile.auth.user.trakt !== null && (Date.now() / 1000) < (profile.auth.user.trakt.created_at + profile.auth.user.trakt.expires_in); }, [profile.auth]); - const configureServerUrlModalButtons = React.useMemo(() => { - return [ - { - className: styles['cancel-button'], - label: 'Cancel', - props: { - onClick: closeConfigureServerUrlModal - } - }, - { - label: 'Submit', - props: { - onClick: configureServerUrlOnSubmit, - } - } - ]; - }, [configureServerUrlOnSubmit]); const logoutButtonOnClick = React.useCallback(() => { core.transport.dispatch({ action: 'Ctx', @@ -118,14 +95,6 @@ const Settings = () => { const exportDataOnClick = React.useCallback(() => { loadDataExport(); }, []); - const reloadStreamingServer = React.useCallback(() => { - core.transport.dispatch({ - action: 'StreamingServer', - args: { - action: 'Reload' - } - }); - }, []); const onCopyRemoteUrlClick = React.useCallback(() => { if (streamingServer.remoteUrl) { navigator.clipboard.writeText(streamingServer.remoteUrl); @@ -192,11 +161,7 @@ const Settings = () => { if (routeFocused) { updateSelectedSectionId(); } - closeConfigureServerUrlModal(); }, [routeFocused]); - const ctx = useModelState({ model: 'ctx' }); - console.log(profile); // eslint-disable-line no-console - console.log(ctx); // eslint-disable-line no-console return (
@@ -372,9 +337,9 @@ const Settings = () => {
{ t('SETTINGS_FULLSCREEN_EXIT') }
-
: @@ -435,10 +400,10 @@ const Settings = () => {
{ t('SETTINGS_SURROUND_SOUND') }
-
@@ -469,11 +434,11 @@ const Settings = () => {
{ t('SETTINGS_PLAY_IN_BACKGROUND') }
- @@ -486,9 +451,9 @@ const Settings = () => {
{ t('AUTO_PLAY') }
-
@@ -520,22 +485,18 @@ const Settings = () => {
{ t('SETTINGS_HWDEC') }
-
{ t('SETTINGS_NAV_STREAMING') }
-
- -
-
+ + {/*
{ t('STATUS') }
@@ -555,8 +516,8 @@ const Settings = () => { }
-
-
+
*/} + {/*
Url
@@ -566,7 +527,7 @@ const Settings = () => {
- + */} { streamingServerRemoteUrlInput.value !== null ?
@@ -782,7 +743,7 @@ const Settings = () => {
- { + {/* { configureServerUrlModalOpen ? { : null - } + } */}
); }; diff --git a/src/routes/Settings/URLsManager/Item/Item.less b/src/routes/Settings/URLsManager/Item/Item.less new file mode 100644 index 000000000..8ef93763e --- /dev/null +++ b/src/routes/Settings/URLsManager/Item/Item.less @@ -0,0 +1,194 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +@import (reference) '~stremio/common/screen-sizes.less'; + +.item { + display: flex; + padding: 1rem 1.5rem; + border-radius: var(--border-radius); + transition: 0.3s all ease-in-out; + background-color: transparent; + border: 2px solid transparent; + justify-content: space-between; + position: relative; + + .content { + display: flex; + gap: 1rem; + align-items: center; + justify-content: center; + + .checkbox { + + } + + .label { + color: var(--primary-foreground-color); + } + } + + .actions { + display: flex; + gap: 1rem; + margin-right: 5rem; + + .status { + display: flex; + gap: 0.5rem; + align-items: center; + justify-content: center; + + .icon { + width: 0.75rem; + height: 0.75rem; + border-radius: 1rem; + + &.ready { + background-color: var(--secondary-accent-color); + } + + &.error { + background-color: var(--color-trakt); + } + } + + .label { + font-size: 1rem; + color: var(--primary-foreground-color); + } + } + + .delete { + position: absolute; + right: 1.5rem; + top: 50%; + display: none; + gap: 0.5rem; + padding: 0.25rem; + align-items: center; + justify-content: center; + background-color: transparent; + transition: 0.3s all ease-in-out; + border-radius: var(--border-radius); + transform: translateY(-50%); + width: 3rem; + opacity: 0.6; + + .icon { + width: 2rem; + height: 2rem; + color: var(--primary-foreground-color); + } + + &:hover { + background-color: var(--overlay-color); + opacity: 1; + + .icon { + color: var(--color-trakt); + } + } + } + } + + &.add { + padding: 0.5rem 1.5rem; + gap: 1rem; + + .input { + background-color: var(--overlay-color); + border-radius: var(--border-radius); + color: var(--primary-foreground-color); + padding: 0.5rem 0.75rem; + border: 1px solid transparent; + width: 70%; + + &:focus { + border: 1px solid var(--primary-foreground-color); + } + } + + .actions { + display: flex; + gap: 0.25rem; + margin-right: 0; + + .add, .cancel { + display: flex; + gap: 0.5rem; + padding: 0.25rem; + align-items: center; + justify-content: center; + background-color: transparent; + transition: 0.3s all ease-in-out; + border-radius: var(--border-radius); + width: 3rem; + opacity: 0.6; + + .icon { + width: 2rem; + height: 2rem; + color: var(--primary-foreground-color); + } + + &:hover { + opacity: 1; + background-color: var(--overlay-color); + } + } + + .add { + .icon { + width: 1.8rem; + height: 1.8rem; + } + &:hover { + .icon { + color: var(--secondary-accent-color); + } + } + } + + .cancel { + &:hover { + .icon { + color: var(--color-trakt); + } + } + } + } + &:hover { + border: 2px solid transparent; + background-color: var(--overlay-color); + } + } + + + &:hover { + background-color: var(--overlay-color); + + .actions { + .delete { + display: flex; + } + } + } +} + +@media only screen and (max-width: @minimum) { + .item { + padding: 1rem 0.5rem; + + .actions { + margin-right: 4rem; + + .delete { + right: 0.5rem; + } + } + + &.add { + padding: 0.5rem; + } + } +} \ No newline at end of file diff --git a/src/routes/Settings/URLsManager/Item/Item.tsx b/src/routes/Settings/URLsManager/Item/Item.tsx new file mode 100644 index 000000000..9858a3a81 --- /dev/null +++ b/src/routes/Settings/URLsManager/Item/Item.tsx @@ -0,0 +1,148 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React, { useState, useCallback, ChangeEvent } from 'react'; +import { useProfile } from 'stremio/common'; +import Button from 'stremio/common/Button'; +import useStreamingServer from 'stremio/common/useStreamingServer'; +import TextInput from 'stremio/common/TextInput'; +import Icon from '@stremio/stremio-icons/react'; +import styles from './Item.less'; +import classNames from 'classnames'; +import { useTranslation } from 'react-i18next'; +import Checkbox from 'stremio/common/Checkbox'; + +type ViewModeProps = { + url: string; + onDelete?: (url: string) => void; + onSelect?: (url: string) => void; +} + +const ViewMode = ({ url, onDelete, onSelect }: ViewModeProps) => { + const { t } = useTranslation(); + const streamingServer = useStreamingServer(); + const profile = useProfile(); + const selected = profile.settings.streamingServerUrl === url; + + const handleDelete = () => { + onDelete?.(url); + }; + + const handleSelect = () => { + onSelect?.(url); + }; + + return ( + <> +
+ +
{url}
+
+
+ { + selected ? +
+
+
+ { + streamingServer.settings === null ? + 'NotLoaded' + : + streamingServer.settings.type === 'Ready' ? + t('SETTINGS_SERVER_STATUS_ONLINE') + : + streamingServer.settings.type === 'Err' ? + t('SETTINGS_SERVER_STATUS_ERROR') + : + streamingServer.settings.type + } +
+
+ : null + } + +
+ + ); +}; + +type AddModeProps = { + inputValue: string; + handleValueChange: (event: ChangeEvent) => void; + onAdd?: (url: string) => void; + onCancel?: () => void; +} + +const AddMode = ({ inputValue, handleValueChange, onAdd, onCancel }: AddModeProps) => { + const handleAdd = () => { + if (inputValue.trim()) { + onAdd?.(inputValue); + } + }; + + return ( + <> + +
+ + +
+ + ); +}; + +type Props = + | { + mode: 'add'; + onAdd?: (url: string) => void; + onCancel?: () => void; + } + | { + mode: 'view'; + url: string; + onDelete?: (url: string) => void; + onSelect?: (url: string) => void; + }; + +const Item = (props: Props) => { + if (props.mode === 'add') { + const { onAdd, onCancel } = props; + + const [inputValue, setInputValue] = useState(''); + + const handleValueChange = useCallback((event: ChangeEvent) => { + setInputValue(event.target.value); + }, []); + + return ( +
+ +
+ ); + } else if (props.mode === 'view') { + const { url, onDelete, onSelect } = props; + + return ( +
+ +
+ ); + } +}; + +export default Item; + diff --git a/src/routes/Settings/URLsManager/Item/index.ts b/src/routes/Settings/URLsManager/Item/index.ts new file mode 100644 index 000000000..87c19a210 --- /dev/null +++ b/src/routes/Settings/URLsManager/Item/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import Item from './Item' + +export default Item; diff --git a/src/routes/Settings/URLsManager/URLsManager.less b/src/routes/Settings/URLsManager/URLsManager.less new file mode 100644 index 000000000..a68660681 --- /dev/null +++ b/src/routes/Settings/URLsManager/URLsManager.less @@ -0,0 +1,81 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +.wrapper { + display: flex; + flex-direction: column; + max-width: 35rem; + margin-bottom: 2rem; + + .header { + display: flex; + justify-content: space-around; + align-items: center; + + .label { + font-size: 1rem; + color: var(--primary-foreground-color); + font-weight: 400; + opacity: 0.6; + } + } + + .content { + display: flex; + flex-direction: column; + gap: 1rem; + padding: 1.5rem 0; + } + + .footer { + display: flex; + justify-content: space-between; + + .add-url { + display: flex; + gap: 0.5rem; + align-items: center; + justify-content: center; + padding: 0.5rem 1.5rem; + background-color: var(--secondary-accent-color); + transition: 0.3s all ease-in-out; + border-radius: 1.5rem; + color: var(--primary-foreground-color); + border: 2px solid transparent; + + .icon { + width: 1rem; + height: 1rem; + color: var(--primary-foreground-color); + } + + &:hover { + background-color: transparent; + border: 2px solid var(--primary-foreground-color); + } + } + + .reload { + display: flex; + gap: 0.5rem; + align-items: center; + justify-content: center; + padding: 0.5rem 1.5rem; + background-color: var(--overlay-color); + border-radius: 1.5rem; + transition: 0.3s all ease-in-out; + color: var(--primary-foreground-color); + border: 2px solid transparent; + + .icon { + width: 1rem; + height: 1rem; + color: var(--primary-foreground-color); + } + + &:hover { + background-color: transparent; + border: 2px solid var(--primary-foreground-color); + } + } + } +} \ No newline at end of file diff --git a/src/routes/Settings/URLsManager/URLsManager.tsx b/src/routes/Settings/URLsManager/URLsManager.tsx new file mode 100644 index 000000000..82578e346 --- /dev/null +++ b/src/routes/Settings/URLsManager/URLsManager.tsx @@ -0,0 +1,61 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React, { useCallback, useState } from 'react' +import { useTranslation } from 'react-i18next'; +import styles from './URLsManager.less'; +import Button from 'stremio/common/Button'; +import Item from './Item'; +import Icon from '@stremio/stremio-icons/react'; +import useStreamingServerUrls from 'stremio/common/useStreamingServerUrls'; + +const URLsManager = () => { + const { t } = useTranslation(); + const [addMode, setAddMode] = useState(false); + const { streamingServerUrls, actions } = useStreamingServerUrls(); + + const onAdd = () => { + setAddMode(true); + } + + const onCancel = () => { + setAddMode(false); + }; + + const handleAddUrl = useCallback((url: string) => { + actions.onAdd(url); + setAddMode(false); + }, []); + + return ( +
+
+
URL
+
{ t('STATUS') }
+
+
+ { + streamingServerUrls.map((url: StreamingServerUrl, index: number) => ( + + )) + } + { + addMode ? + + : null + } +
+
+ + +
+
+ ); +}; + +export default URLsManager; diff --git a/src/routes/Settings/URLsManager/index.ts b/src/routes/Settings/URLsManager/index.ts new file mode 100644 index 000000000..c8874c0a4 --- /dev/null +++ b/src/routes/Settings/URLsManager/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import URLsManager from './URLsManager'; + +export default URLsManager; diff --git a/src/routes/Settings/styles.less b/src/routes/Settings/styles.less index 7c9444509..5480db8b5 100644 --- a/src/routes/Settings/styles.less +++ b/src/routes/Settings/styles.less @@ -3,7 +3,7 @@ @import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; @import (reference) '~stremio/common/screen-sizes.less'; -:import('~stremio/common/Checkbox/styles.less') { +:import('~stremio/common/Toggle/styles.less') { checkbox-icon: icon; } diff --git a/src/routes/Settings/useProfileSettingsInputs.js b/src/routes/Settings/useProfileSettingsInputs.js index a90d0d483..d36b169f9 100644 --- a/src/routes/Settings/useProfileSettingsInputs.js +++ b/src/routes/Settings/useProfileSettingsInputs.js @@ -136,7 +136,7 @@ const useProfileSettingsInputs = (profile) => { }); } }), [profile.settings]); - const surroundSoundCheckbox = React.useMemo(() => ({ + const surroundSoundToggle = React.useMemo(() => ({ checked: profile.settings.surroundSound, onClick: () => { core.transport.dispatch({ @@ -151,7 +151,7 @@ const useProfileSettingsInputs = (profile) => { }); } }), [profile.settings]); - const escExitFullscreenCheckbox = React.useMemo(() => ({ + const escExitFullscreenToggle = React.useMemo(() => ({ checked: profile.settings.escExitFullscreen, onClick: () => { core.transport.dispatch({ @@ -261,7 +261,7 @@ const useProfileSettingsInputs = (profile) => { }); } }), [profile.settings]); - const bingeWatchingCheckbox = React.useMemo(() => ({ + const bingeWatchingToggle = React.useMemo(() => ({ checked: profile.settings.bingeWatching, onClick: () => { core.transport.dispatch({ @@ -276,7 +276,7 @@ const useProfileSettingsInputs = (profile) => { }); } }), [profile.settings]); - const playInBackgroundCheckbox = React.useMemo(() => ({ + const playInBackgroundToggle = React.useMemo(() => ({ checked: profile.settings.playInBackground, onClick: () => { core.transport.dispatch({ @@ -291,7 +291,7 @@ const useProfileSettingsInputs = (profile) => { }); } }), [profile.settings]); - const hardwareDecodingCheckbox = React.useMemo(() => ({ + const hardwareDecodingToggle = React.useMemo(() => ({ checked: profile.settings.hardwareDecoding, onClick: () => { core.transport.dispatch({ @@ -306,21 +306,6 @@ const useProfileSettingsInputs = (profile) => { }); } }), [profile.settings]); - const streamingServerUrlInput = React.useMemo(() => ({ - value: profile.settings.streamingServerUrl, - onChange: (value) => { - core.transport.dispatch({ - action: 'Ctx', - args: { - action: 'UpdateSettings', - args: { - ...profile.settings, - streamingServerUrl: value - } - } - }); - } - }), [profile.settings]); return { interfaceLanguageSelect, subtitlesLanguageSelect, @@ -329,16 +314,15 @@ const useProfileSettingsInputs = (profile) => { subtitlesBackgroundColorInput, subtitlesOutlineColorInput, audioLanguageSelect, - surroundSoundCheckbox, - escExitFullscreenCheckbox, + surroundSoundToggle, + escExitFullscreenToggle, seekTimeDurationSelect, seekShortTimeDurationSelect, playInExternalPlayerSelect, nextVideoPopupDurationSelect, - bingeWatchingCheckbox, - playInBackgroundCheckbox, - hardwareDecodingCheckbox, - streamingServerUrlInput + bingeWatchingToggle, + playInBackgroundToggle, + hardwareDecodingToggle, }; }; diff --git a/src/types/models/Ctx.d.ts b/src/types/models/Ctx.d.ts index 33da9f366..9619a0e89 100644 --- a/src/types/models/Ctx.d.ts +++ b/src/types/models/Ctx.d.ts @@ -67,8 +67,16 @@ type SearchHistoryItem = { type SearchHistory = SearchHistoryItem[]; +type StreamingServerUrl = { + url: string, + _mtime: Date, +}; + +type StreamingServerUrls = StreamingServerUrl[]; + type Ctx = { profile: Profile, notifications: Notifications, searchHistory: SearchHistory, + streamingServerUrls: StreamingServerUrls, }; From 14d5fc3da7d9748af349bbec7fd173a3b6586b1f Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 22 Oct 2024 10:25:29 +0300 Subject: [PATCH 095/336] refactor: handle edge cases correctly --- src/common/CONSTANTS.js | 2 ++ src/common/Checkbox/Checkbox.less | 3 +-- src/routes/Settings/URLsManager/Item/Item.tsx | 17 ++++++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/common/CONSTANTS.js b/src/common/CONSTANTS.js index c08cf471d..fe6ece826 100644 --- a/src/common/CONSTANTS.js +++ b/src/common/CONSTANTS.js @@ -1,6 +1,7 @@ // Copyright (C) 2017-2023 Smart code 203358507 const CHROMECAST_RECEIVER_APP_ID = '1634F54B'; +const DEFAULT_STREAMING_SERVER_URL = 'http://127.0.0.1:11470/'; const SUBTITLES_SIZES = [75, 100, 125, 150, 175, 200, 250]; const SUBTITLES_FONTS = ['PlusJakartaSans', 'Arial', 'Halvetica', 'Times New Roman', 'Verdana', 'Courier', 'Lucida Console', 'sans-serif', 'serif', 'monospace']; const SEEK_TIME_DURATIONS = [3000, 5000, 10000, 15000, 20000, 30000]; @@ -97,6 +98,7 @@ const WHITELISTED_HOSTS = ['stremio.com', 'strem.io', 'stremio.zendesk.com', 'go module.exports = { CHROMECAST_RECEIVER_APP_ID, + DEFAULT_STREAMING_SERVER_URL, SUBTITLES_SIZES, SUBTITLES_FONTS, SEEK_TIME_DURATIONS, diff --git a/src/common/Checkbox/Checkbox.less b/src/common/Checkbox/Checkbox.less index 8dea5fd1d..ef158f5e2 100644 --- a/src/common/Checkbox/Checkbox.less +++ b/src/common/Checkbox/Checkbox.less @@ -70,12 +70,11 @@ .checkbox-disabled { cursor: not-allowed; - opacity: 0.6; } .checkbox-disabled .checkbox-container { - background-color: var(--overlay-color); border-color: var(--overlay-color); + cursor: not-allowed; } .checkbox-disabled .checkbox-label { diff --git a/src/routes/Settings/URLsManager/Item/Item.tsx b/src/routes/Settings/URLsManager/Item/Item.tsx index 9858a3a81..8292f262b 100644 --- a/src/routes/Settings/URLsManager/Item/Item.tsx +++ b/src/routes/Settings/URLsManager/Item/Item.tsx @@ -2,13 +2,14 @@ import React, { useState, useCallback, ChangeEvent } from 'react'; import { useProfile } from 'stremio/common'; +import { DEFAULT_STREAMING_SERVER_URL } from 'stremio/common/CONSTANTS'; +import { useTranslation } from 'react-i18next'; import Button from 'stremio/common/Button'; import useStreamingServer from 'stremio/common/useStreamingServer'; import TextInput from 'stremio/common/TextInput'; import Icon from '@stremio/stremio-icons/react'; import styles from './Item.less'; import classNames from 'classnames'; -import { useTranslation } from 'react-i18next'; import Checkbox from 'stremio/common/Checkbox'; type ViewModeProps = { @@ -22,9 +23,11 @@ const ViewMode = ({ url, onDelete, onSelect }: ViewModeProps) => { const streamingServer = useStreamingServer(); const profile = useProfile(); const selected = profile.settings.streamingServerUrl === url; + const defaultUrl = url === DEFAULT_STREAMING_SERVER_URL; const handleDelete = () => { onDelete?.(url); + onSelect?.(DEFAULT_STREAMING_SERVER_URL); }; const handleSelect = () => { @@ -34,7 +37,7 @@ const ViewMode = ({ url, onDelete, onSelect }: ViewModeProps) => { return ( <>
- +
{url}
@@ -59,9 +62,13 @@ const ViewMode = ({ url, onDelete, onSelect }: ViewModeProps) => {
: null } - + { + !defaultUrl ? + + : null + }
); From fd88b18cdd6a7f15960f6597d374c144269fabc9 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 22 Oct 2024 11:50:59 +0300 Subject: [PATCH 096/336] fix: Item and checkbox styles --- src/common/Checkbox/Checkbox.less | 2 +- src/common/Checkbox/Checkbox.tsx | 3 +-- src/routes/Settings/URLsManager/Item/Item.less | 11 +++++++++-- src/routes/Settings/URLsManager/Item/Item.tsx | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/common/Checkbox/Checkbox.less b/src/common/Checkbox/Checkbox.less index ef158f5e2..876deb26d 100644 --- a/src/common/Checkbox/Checkbox.less +++ b/src/common/Checkbox/Checkbox.less @@ -21,7 +21,7 @@ display: flex; align-items: center; justify-content: center; - transition: background-color 0.2s, border-color 0.2s; + transition: all 0.2s ease-in-out; cursor: pointer; outline: none; user-select: none; diff --git a/src/common/Checkbox/Checkbox.tsx b/src/common/Checkbox/Checkbox.tsx index 2148e0dd9..85a7b9c17 100644 --- a/src/common/Checkbox/Checkbox.tsx +++ b/src/common/Checkbox/Checkbox.tsx @@ -46,11 +46,10 @@ const Checkbox = ({ disabled, value, className, onChange, ariaLabel, error }: Pr return ( <> -
+
{ + const { toMonth } = useCalendarDate(profile); + + const [prev, next] = useMemo(() => ( + [selectable.prev, selectable.next] + ), [selectable]); + + const onPrev = useCallback(() => { + window.location.href = prev.deepLinks.calendar; + }, [prev]); + + const onNext = useCallback(() => { + window.location.href = next.deepLinks.calendar; + }, [next]); + + return ( +
+ +
+
+ {selected?.year} +
+
+ {toMonth(selected, 'long')} +
+
+ +
+ ); +}; + +export default Selector; diff --git a/src/routes/Calendar/Selector/index.ts b/src/routes/Calendar/Selector/index.ts new file mode 100644 index 000000000..be7f5bd13 --- /dev/null +++ b/src/routes/Calendar/Selector/index.ts @@ -0,0 +1,2 @@ +import Selector from './Selector'; +export default Selector; diff --git a/src/routes/Calendar/useCalendarDate.ts b/src/routes/Calendar/useCalendarDate.ts index b92c72266..082098380 100644 --- a/src/routes/Calendar/useCalendarDate.ts +++ b/src/routes/Calendar/useCalendarDate.ts @@ -1,6 +1,18 @@ import { useCallback } from 'react'; const useCalendarDate = (profile: Profile) => { + const toMonth = useCallback((calendarDate: CalendarDate | CalendarSelectableDate | null, format: 'short' | 'long'): string => { + if (!calendarDate) return ''; + + const date = new Date(); + date.setDate(1); + date.setMonth(calendarDate.month - 1); + + return date.toLocaleString(profile.settings.interfaceLanguage, { + month: format, + }); + }, [profile.settings]); + const toMonthYear = useCallback((calendarDate: CalendarDate | null): string => { if (!calendarDate) return ''; @@ -29,6 +41,7 @@ const useCalendarDate = (profile: Profile) => { }, [profile.settings]); return { + toMonth, toMonthYear, toDayMonth, }; diff --git a/src/routes/Calendar/useSelectableInputs.ts b/src/routes/Calendar/useSelectableInputs.ts deleted file mode 100644 index bfe51743a..000000000 --- a/src/routes/Calendar/useSelectableInputs.ts +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2017-2024 Smart code 203358507 - -import React from 'react'; -import useCalendarDate from './useCalendarDate'; - -const mapSelectableInputs = (calendar: Calendar, toMonthYear: (date: CalendarDate | null) => string) => { - const paginationInput = (calendar.selectable.prev ?? calendar.selectable.next) ? - { - label: toMonthYear(calendar.selected), - onSelect: ({ value }: { value: string }) => { - if (value === 'prev' && calendar.selectable.prev) { - window.location.href = calendar.selectable.prev.deepLinks.calendar; - } - if (value === 'next' && calendar.selectable.next) { - window.location.href = calendar.selectable.next.deepLinks.calendar; - } - } - } - : - null; - - return [paginationInput]; -}; - -const useSelectableInputs = (calendar: Calendar, profile: Profile) => { - const { toMonthYear } = useCalendarDate(profile); - - const selectableInputs = React.useMemo(() => { - return mapSelectableInputs(calendar, toMonthYear); - }, [calendar, toMonthYear]); - - return selectableInputs; -}; - -export default useSelectableInputs; diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less index 1d8bca9cb..3af4ddce9 100644 --- a/src/routes/Discover/styles.less +++ b/src/routes/Discover/styles.less @@ -11,13 +11,6 @@ multiselect-label: label; } -:import('~stremio/common/PaginationInput/styles.less') { - pagination-prev-button-container: prev-button-container; - pagination-next-button-container: next-button-container; - pagination-button-icon: icon; - pagination-label: label; -} - :import('~stremio/common/ModalDialog/styles.less') { selectable-inputs-modal-container: modal-dialog-container; selectable-inputs-modal-content: modal-dialog-content; From 192bd535373b354796e2949efcdcec4d6ad365f8 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 28 Nov 2024 12:35:30 +0200 Subject: [PATCH 156/336] remove(stream): max-height on addon-name Co-authored-by: Tim --- src/routes/MetaDetails/StreamsList/Stream/styles.less | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/styles.less b/src/routes/MetaDetails/StreamsList/Stream/styles.less index e4af802f4..22b2abc61 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/styles.less +++ b/src/routes/MetaDetails/StreamsList/Stream/styles.less @@ -58,7 +58,6 @@ .addon-name { width: 7rem; - max-height:4em; font-size: 1.1rem; text-align: left; color: var(--primary-foreground-color); From 320bca2e350e108bbf9e28de4e7debd2767a743f Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 28 Nov 2024 11:45:26 +0100 Subject: [PATCH 157/336] fix(Calendar): copyright headers --- src/routes/Calendar/Selector/Selector.less | 2 ++ src/routes/Calendar/Selector/Selector.tsx | 2 ++ src/routes/Calendar/Selector/index.ts | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/routes/Calendar/Selector/Selector.less b/src/routes/Calendar/Selector/Selector.less index 129ee8fd2..ef18f9a7e 100644 --- a/src/routes/Calendar/Selector/Selector.less +++ b/src/routes/Calendar/Selector/Selector.less @@ -1,3 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + @import (reference) '~stremio/common/screen-sizes.less'; .selector { diff --git a/src/routes/Calendar/Selector/Selector.tsx b/src/routes/Calendar/Selector/Selector.tsx index 1c2fb0e20..d6aa23336 100644 --- a/src/routes/Calendar/Selector/Selector.tsx +++ b/src/routes/Calendar/Selector/Selector.tsx @@ -1,3 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + import React, { useCallback, useMemo } from 'react'; import Icon from '@stremio/stremio-icons/react'; import { Button } from 'stremio/common'; diff --git a/src/routes/Calendar/Selector/index.ts b/src/routes/Calendar/Selector/index.ts index be7f5bd13..f8baa472a 100644 --- a/src/routes/Calendar/Selector/index.ts +++ b/src/routes/Calendar/Selector/index.ts @@ -1,2 +1,4 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + import Selector from './Selector'; export default Selector; From 73ab4adf4aa15ccca19541b41e8b95941fda18b9 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 28 Nov 2024 13:36:15 +0100 Subject: [PATCH 158/336] refactor(Calendar): use fixed widths for selector --- src/routes/Calendar/Selector/Selector.less | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/routes/Calendar/Selector/Selector.less b/src/routes/Calendar/Selector/Selector.less index ef18f9a7e..b5cefbf06 100644 --- a/src/routes/Calendar/Selector/Selector.less +++ b/src/routes/Calendar/Selector/Selector.less @@ -6,17 +6,17 @@ flex: none; position: relative; display: flex; - gap: 3rem; + gap: 1rem; align-items: center; justify-content: center; .prev, .next { position: relative; height: 3rem; + width: 6rem; display: flex; flex-direction: row; align-items: center; - justify-content: space-between; gap: 0.5rem; border-radius: 0.5rem; transition: background-color 0.1s ease-out; @@ -30,6 +30,9 @@ .label { font-size: 1rem; font-weight: 500; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; } .icon { @@ -46,22 +49,21 @@ } .prev { + justify-content: start; padding-left: 0.5rem; padding-right: 1rem; } .next { + justify-content: end; padding-left: 1rem; padding-right: 0.5rem; } .selected { position: relative; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - overflow: hidden; + width: 8.5rem; + text-align: center; .year { font-size: 1rem; @@ -75,7 +77,9 @@ font-size: 1.5rem; font-weight: 500; color: var(--primary-foreground-color); + text-overflow: ellipsis; white-space: nowrap; + overflow: hidden; } } } From c5ab6b61126c94b0917fe5f91378570948b194b0 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 28 Nov 2024 14:55:55 +0200 Subject: [PATCH 159/336] fix: navbar item label was cut --- src/common/NavBar/VerticalNavBar/styles.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/NavBar/VerticalNavBar/styles.less b/src/common/NavBar/VerticalNavBar/styles.less index 88f5e45a3..3a6ae76d8 100644 --- a/src/common/NavBar/VerticalNavBar/styles.less +++ b/src/common/NavBar/VerticalNavBar/styles.less @@ -19,8 +19,8 @@ } .nav-tab-button { - width: calc(var(--vertical-nav-bar-size) - 1.5rem); - height: calc(var(--vertical-nav-bar-size) - 1.5rem); + width: calc(var(--vertical-nav-bar-size) - 1.2rem); + height: calc(var(--vertical-nav-bar-size) - 1.2rem); } } From 03a29c59031e969456526e5af9c9ee643acdd06c Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 28 Nov 2024 14:06:46 +0100 Subject: [PATCH 160/336] refactor(Calendar): simplify mobile media query --- src/routes/Calendar/Selector/Selector.less | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/routes/Calendar/Selector/Selector.less b/src/routes/Calendar/Selector/Selector.less index b5cefbf06..8a4eb2407 100644 --- a/src/routes/Calendar/Selector/Selector.less +++ b/src/routes/Calendar/Selector/Selector.less @@ -9,6 +9,7 @@ gap: 1rem; align-items: center; justify-content: center; + padding: 0 1rem; .prev, .next { position: relative; @@ -86,16 +87,6 @@ @media only screen and (max-width: @small) { .selector { - .prev, .next { - position: absolute; - } - - .prev { - left: 1rem; - } - - .next { - right: 1rem; - } + justify-content: space-between; } } \ No newline at end of file From 1f7cf89d940790da03c9ca2a5c7e7426595457c4 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 28 Nov 2024 14:11:23 +0100 Subject: [PATCH 161/336] refactor(Calendar): remove chrome mobile highlight on buttons --- src/routes/Calendar/Details/Details.less | 1 + src/routes/Calendar/Selector/Selector.less | 1 + src/routes/Calendar/Table/Cell/Cell.less | 1 + 3 files changed, 3 insertions(+) diff --git a/src/routes/Calendar/Details/Details.less b/src/routes/Calendar/Details/Details.less index db11acc78..2e78ca703 100644 --- a/src/routes/Calendar/Details/Details.less +++ b/src/routes/Calendar/Details/Details.less @@ -16,6 +16,7 @@ font-size: 1rem; font-weight: 500; color: var(--primary-foreground-color); + -webkit-tap-highlight-color: transparent; .name { flex: auto; diff --git a/src/routes/Calendar/Selector/Selector.less b/src/routes/Calendar/Selector/Selector.less index 8a4eb2407..1f70aa149 100644 --- a/src/routes/Calendar/Selector/Selector.less +++ b/src/routes/Calendar/Selector/Selector.less @@ -21,6 +21,7 @@ gap: 0.5rem; border-radius: 0.5rem; transition: background-color 0.1s ease-out; + -webkit-tap-highlight-color: transparent; .label, .icon { color: var(--primary-foreground-color); diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less index 3ecb32d15..285117119 100644 --- a/src/routes/Calendar/Table/Cell/Cell.less +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -13,6 +13,7 @@ overflow: hidden; cursor: pointer; transition: border-color 0.1s ease-out; + -webkit-tap-highlight-color: transparent; &:first-child { border-radius: var(--border-radius) 0 0 0; From 83c5c5ab0fc997bff7e99b11cc1bbd0e752e894f Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 28 Nov 2024 14:29:04 +0100 Subject: [PATCH 162/336] refactor(Calendar): month selector style --- src/routes/Calendar/Selector/Selector.less | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/routes/Calendar/Selector/Selector.less b/src/routes/Calendar/Selector/Selector.less index 1f70aa149..6683697be 100644 --- a/src/routes/Calendar/Selector/Selector.less +++ b/src/routes/Calendar/Selector/Selector.less @@ -18,6 +18,7 @@ display: flex; flex-direction: row; align-items: center; + justify-content: space-between; gap: 0.5rem; border-radius: 0.5rem; transition: background-color 0.1s ease-out; @@ -51,14 +52,12 @@ } .prev { - justify-content: start; padding-left: 0.5rem; - padding-right: 1rem; + padding-right: 1.25rem; } .next { - justify-content: end; - padding-left: 1rem; + padding-left: 1.25rem; padding-right: 0.5rem; } From c3611c61c3d42fdd122a605b66390647f61a50ca Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Thu, 28 Nov 2024 15:49:56 +0200 Subject: [PATCH 163/336] chore(fix): pkg.lock.json --- package-lock.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2af6603ae..5316adf69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,8 +12,8 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.47.8", - "@stremio/stremio-icons": "5.2.0", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/streming-server-urls-bucket/dev/stremio-stremio-core-web-0.47.8.tgz", + "@stremio/stremio-icons": "5.4.0", "@stremio/stremio-video": "0.0.46", "a-color-picker": "1.2.1", "bowser": "2.11.0", @@ -3132,8 +3132,8 @@ }, "node_modules/@stremio/stremio-core-web": { "version": "0.47.8", - "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.47.8.tgz", - "integrity": "sha512-X5yKSCm5DXR7U6oIO+2kaI1q3TnaWP6df/HFa1RBi/uw+8IYk+FB8GWpryxXyisJTFiUfQgcJDIlHROauaBQkg==", + "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/streming-server-urls-bucket/dev/stremio-stremio-core-web-0.47.8.tgz", + "integrity": "sha512-Y9o1ax6TJuYB9GYeXuRjMgyt9bpORLhzgzU2+ie2b1nIa9+5IS+jCWhgJFud35Io479GZJNVUeP83KxVktbuNg==", "dependencies": { "@babel/runtime": "7.24.1" } From 7b877151533cd927d340fad7600e90bb53032f3f Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 28 Nov 2024 15:07:39 +0100 Subject: [PATCH 164/336] refactor(Calendar): remove past items styling --- src/routes/Calendar/List/Item/Item.less | 6 ------ src/routes/Calendar/List/Item/Item.tsx | 13 +++++-------- src/routes/Calendar/Table/Cell/Cell.less | 6 ------ src/routes/Calendar/Table/Cell/Cell.tsx | 13 +++++-------- 4 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/routes/Calendar/List/Item/Item.less b/src/routes/Calendar/List/Item/Item.less index 4ce981807..aba6bba09 100644 --- a/src/routes/Calendar/List/Item/Item.less +++ b/src/routes/Calendar/List/Item/Item.less @@ -88,12 +88,6 @@ } } - &.past { - .body { - opacity: 0.5; - } - } - &.active { border-color: var(--primary-foreground-color); } diff --git a/src/routes/Calendar/List/Item/Item.tsx b/src/routes/Calendar/List/Item/Item.tsx index cc48d5197..70010b0f5 100644 --- a/src/routes/Calendar/List/Item/Item.tsx +++ b/src/routes/Calendar/List/Item/Item.tsx @@ -20,13 +20,10 @@ const Item = ({ selected, monthInfo, date, items, profile, onClick }: Props) => const ref = useRef(null); const { toDayMonth } = useCalendarDate(profile); - const [active, today, past] = useMemo(() => { - const active = date.day === selected?.day; - const today = date.day === monthInfo.today; - const past = date.day < (monthInfo.today ?? 1); - - return [active, today, past]; - }, [selected, monthInfo, date]); + const [active, today] = useMemo(() => [ + date.day === selected?.day, + date.day === monthInfo.today, + ], [selected, monthInfo, date]); const onItemClick = () => { onClick && onClick(date); @@ -42,7 +39,7 @@ const Item = ({ selected, monthInfo, date, items, profile, onClick }: Props) => return (
diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less index 285117119..1d54855bc 100644 --- a/src/routes/Calendar/Table/Cell/Cell.less +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -124,12 +124,6 @@ } } - &.past { - .items { - opacity: 0.5; - } - } - &.active { border-color: var(--primary-foreground-color); } diff --git a/src/routes/Calendar/Table/Cell/Cell.tsx b/src/routes/Calendar/Table/Cell/Cell.tsx index 4fc5e86c8..b5e78464c 100644 --- a/src/routes/Calendar/Table/Cell/Cell.tsx +++ b/src/routes/Calendar/Table/Cell/Cell.tsx @@ -15,13 +15,10 @@ type Props = { }; const Cell = ({ selected, monthInfo, date, items, onClick }: Props) => { - const [active, today, past] = useMemo(() => { - const active = date.day === selected?.day; - const today = date.day === monthInfo.today; - const past = date.day < (monthInfo.today ?? 1); - - return [active, today, past]; - }, [selected, monthInfo, date]); + const [active, today] = useMemo(() => [ + date.day === selected?.day, + date.day === monthInfo.today, + ], [selected, monthInfo, date]); const onCellClick = () => { onClick && onClick(date); @@ -29,7 +26,7 @@ const Cell = ({ selected, monthInfo, date, items, onClick }: Props) => { return (
diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index d82512a87..f393f986d 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -338,7 +338,7 @@ const Settings = () => {
{ t('SETTINGS_FULLSCREEN_EXIT') }
@@ -401,7 +401,7 @@ const Settings = () => {
{ t('SETTINGS_SURROUND_SOUND') }
@@ -435,7 +435,7 @@ const Settings = () => {
{ t('SETTINGS_PLAY_IN_BACKGROUND') }
{
{ t('AUTO_PLAY') }
@@ -486,7 +486,7 @@ const Settings = () => {
{ t('SETTINGS_HWDEC') }
Date: Fri, 29 Nov 2024 12:22:20 +0200 Subject: [PATCH 166/336] refactor: checkbox component --- src/common/Checkbox/Checkbox.tsx | 52 ++++++------------- src/routes/Settings/URLsManager/Item/Item.tsx | 2 +- 2 files changed, 18 insertions(+), 36 deletions(-) diff --git a/src/common/Checkbox/Checkbox.tsx b/src/common/Checkbox/Checkbox.tsx index 0b11c93b2..770654837 100644 --- a/src/common/Checkbox/Checkbox.tsx +++ b/src/common/Checkbox/Checkbox.tsx @@ -1,65 +1,47 @@ // Copyright (C) 2017-2024 Smart code 203358507 -import React, { useState, useEffect, useCallback, DetailedHTMLProps, HTMLAttributes } from 'react'; +import React, { useCallback, DetailedHTMLProps, HTMLAttributes, ChangeEvent } from 'react'; import classNames from 'classnames'; import styles from './Checkbox.less'; import Icon from '@stremio/stremio-icons/react'; type Props = { disabled?: boolean; - value?: boolean; + checked?: boolean; className?: string; onChange?: (checked: boolean) => void; ariaLabel?: string; error?: string; }; -const Checkbox = ({ disabled, value, className, onChange, ariaLabel, error }: Props) => { - const [isChecked, setIsChecked] = useState(false); - const [isError, setIsError] = useState(false); - const [isDisabled, setIsDisabled] = useState(disabled); +const Checkbox = ({ disabled, checked, className, onChange, ariaLabel, error }: Props) => { - const handleChangeCheckbox = useCallback(() => { - if (disabled) { - return; + const handleChangeCheckbox = useCallback(({ target }: ChangeEvent) => { + onChange && onChange(target.checked); + }, [onChange]); + + const onKeyDown = useCallback(({ key }: DetailedHTMLProps, HTMLDivElement>) => { + if ((key === 'Enter' || key === ' ') && !disabled) { + onChange && onChange(!checked); } - - setIsChecked(!isChecked); - onChange && onChange(!isChecked); - }, [disabled]); - - const handleEnterPress = useCallback((event: DetailedHTMLProps, HTMLDivElement>) => { - if ((event.key === 'Enter' || event.key === ' ') && !disabled) { - setIsChecked(!isChecked); - onChange && onChange(!isChecked); - } - }, [disabled]); - - useEffect(() => setIsDisabled(disabled), [disabled]); - - useEffect(() => setIsError(!!error), [error]); - - useEffect(() => { - const checked = typeof value === 'boolean' ? value : false; - setIsChecked(checked); - }, [value]); + }, [disabled, checked, onChange]); return (