From 8a79058d1cc650549aa08bcc943db5d5483a3f61 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 18 Jun 2024 12:07:34 +0200 Subject: [PATCH 01/42] 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 02/42] 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 04/42] 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 05/42] 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 06/42] 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 11/42] 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 12/42] 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 13/42] 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 14/42] 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 15/42] 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 0b70f67dd92915c5f182a61c8c35ab6e7f450ca4 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 23 Sep 2024 14:28:06 +0200 Subject: [PATCH 16/42] feat: add BottomSheet to calendar for mobile --- package-lock.json | 10 +++ package.json | 1 + src/App/styles.less | 1 + src/common/BottomSheet/BottomSheet.less | 90 ++++++++++++++++++++++++ src/common/BottomSheet/BottomSheet.tsx | 83 ++++++++++++++++++++++ src/common/BottomSheet/index.ts | 4 ++ src/common/animations.less | 19 +++++ src/common/index.js | 2 + src/common/useBinaryState.d.ts | 8 +++ src/routes/Calendar/Calendar.tsx | 17 ++++- src/routes/Calendar/Details/Details.less | 59 ++++++++++++++++ src/routes/Calendar/Details/Details.tsx | 45 ++++++++++++ src/routes/Calendar/Details/index.ts | 4 ++ src/routes/Calendar/Table/Cell/Cell.less | 32 ++++----- src/routes/Calendar/Table/Cell/Cell.tsx | 6 ++ 15 files changed, 359 insertions(+), 22 deletions(-) create mode 100644 src/common/BottomSheet/BottomSheet.less create mode 100644 src/common/BottomSheet/BottomSheet.tsx create mode 100644 src/common/BottomSheet/index.ts create mode 100644 src/common/useBinaryState.d.ts create mode 100644 src/routes/Calendar/Details/Details.less create mode 100644 src/routes/Calendar/Details/Details.tsx create mode 100644 src/routes/Calendar/Details/index.ts diff --git a/package-lock.json b/package-lock.json index 76db0e04a..b61d56a26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,7 @@ "@babel/preset-env": "7.16.0", "@babel/preset-react": "7.16.0", "@types/react": "^18.2.9", + "@types/react-dom": "^18.3.0", "babel-loader": "8.2.3", "clean-webpack-plugin": "4.0.0", "copy-webpack-plugin": "9.0.1", @@ -3270,6 +3271,15 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "dev": true, diff --git a/package.json b/package.json index bf4b1bd10..0b4fe4723 100755 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "@babel/preset-env": "7.16.0", "@babel/preset-react": "7.16.0", "@types/react": "^18.2.9", + "@types/react-dom": "^18.3.0", "babel-loader": "8.2.3", "clean-webpack-plugin": "4.0.0", "copy-webpack-plugin": "9.0.1", diff --git a/src/App/styles.less b/src/App/styles.less index be0c26480..6210a8bdf 100644 --- a/src/App/styles.less +++ b/src/App/styles.less @@ -91,6 +91,7 @@ html { min-height: 480px; font-family: 'PlusJakartaSans', 'sans-serif'; overflow: auto; + overscroll-behavior: none; body { width: 100%; diff --git a/src/common/BottomSheet/BottomSheet.less b/src/common/BottomSheet/BottomSheet.less new file mode 100644 index 000000000..83c73b70b --- /dev/null +++ b/src/common/BottomSheet/BottomSheet.less @@ -0,0 +1,90 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +@import (reference) '~stremio/common/screen-sizes.less'; + +.bottom-sheet { + z-index: 99; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + + .backdrop { + z-index: 0; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: var(--primary-background-color); + opacity: 0.8; + transition: opacity 0.1s ease-out; + cursor: pointer; + } + + .container { + z-index: 1; + position: absolute; + top: var(--horizontal-nav-bar-size); + height: 100%; + width: 100%; + display: flex; + flex-direction: column; + gap: 1.5rem; + border-radius: 2rem 2rem 0 0; + background-color: var(--modal-background-color); + box-shadow: var(--outer-glow); + overflow: hidden; + + &:not(.dragging) { + transition: transform 0.1s ease-out; + } + + .heading { + position: relative; + + .handle { + position: relative; + height: 2.5rem; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + + &::after { + content: ""; + height: 0.3rem; + width: 3rem; + border-radius: 1rem; + background-color: var(--primary-foreground-color); + opacity: 0.3; + } + } + + .title { + position: relative; + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 1rem; + padding-left: 1.5rem; + font-size: 1.25rem; + font-weight: 600; + color: var(--primary-foreground-color); + } + } + + .content { + position: relative; + overflow-y: auto; + } + } +} + +@media only screen and (min-width: @xsmall) { + .bottom-sheet { + display: none; + } +} \ No newline at end of file diff --git a/src/common/BottomSheet/BottomSheet.tsx b/src/common/BottomSheet/BottomSheet.tsx new file mode 100644 index 000000000..eed990670 --- /dev/null +++ b/src/common/BottomSheet/BottomSheet.tsx @@ -0,0 +1,83 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { createPortal } from 'react-dom'; +import classNames from 'classnames'; +import useBinaryState from 'stremio/common/useBinaryState'; +import styles from './BottomSheet.less'; + +const CLOSE_THRESHOLD = 100; + +type Props = { + children: JSX.Element, + title: string, + show?: boolean, + onClose: () => void, +}; + +const BottomSheet = ({ children, title, show }: Props) => { + const containerRef = useRef(null); + const [startOffset, setStartOffset] = useState(0); + const [offset, setOffset] = useState(0); + + const [opened, open, close] = useBinaryState(); + + const containerStyle = useMemo(() => ({ + transform: `translateY(${offset}px)` + }), [offset]); + + const containerHeight = () => containerRef.current?.offsetHeight ?? 0; + + const onClose = () => setOffset(containerHeight()); + + const onTouchStart = ({ touches }: React.TouchEvent) => { + const { clientY } = touches[0]; + setStartOffset(clientY); + }; + + const onTouchMove = useCallback(({ touches }: React.TouchEvent) => { + const { clientY } = touches[0]; + setOffset(Math.max(0, clientY - startOffset)); + }, [startOffset]); + + const onTouchEnd = useCallback(() => { + setOffset((offset) => offset > CLOSE_THRESHOLD ? containerHeight() : 0); + setStartOffset(0); + }, []); + + const onTransitionEnd = useCallback(() => { + (offset === containerHeight()) && close(); + }, [offset]); + + useEffect(() => { + setOffset(0); + show ? open() : close(); + }, [show]); + + return opened && createPortal(( +
+
+
+
+
+
+ {title} +
+
+
+ {children} +
+
+
+ ), document.body); +}; + +export default BottomSheet; \ No newline at end of file diff --git a/src/common/BottomSheet/index.ts b/src/common/BottomSheet/index.ts new file mode 100644 index 000000000..411a57f22 --- /dev/null +++ b/src/common/BottomSheet/index.ts @@ -0,0 +1,4 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import BottomSheet from './BottomSheet'; +export default BottomSheet; \ No newline at end of file diff --git a/src/common/animations.less b/src/common/animations.less index 8a7fc2b9e..4b0776d16 100644 --- a/src/common/animations.less +++ b/src/common/animations.less @@ -19,4 +19,23 @@ opacity: 1; transform: translateY(0); } +} + +:global(.animation-slide-up) { + :local { + animation-name: slide-up; + } + + animation-timing-function: ease-out; + animation-duration: 0.1s; +} + +@keyframes slide-up { + 0% { + transform: translateY(100%); + } + + 100% { + transform: translateY(0%); + } } \ No newline at end of file diff --git a/src/common/index.js b/src/common/index.js index fd4f838db..cccae3513 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -1,6 +1,7 @@ // Copyright (C) 2017-2023 Smart code 203358507 const AddonDetailsModal = require('./AddonDetailsModal'); +const { default: BottomSheet } = require('./BottomSheet'); const Button = require('./Button'); const Checkbox = require('./Checkbox'); const { default: Chips } = require('./Chips'); @@ -50,6 +51,7 @@ const EventModal = require('./EventModal'); module.exports = { AddonDetailsModal, + BottomSheet, Button, Checkbox, Chips, diff --git a/src/common/useBinaryState.d.ts b/src/common/useBinaryState.d.ts new file mode 100644 index 000000000..cc1f5fccb --- /dev/null +++ b/src/common/useBinaryState.d.ts @@ -0,0 +1,8 @@ +declare const useBinaryState: () => [ + boolean, + () => void, + () => void, + () => void, +]; + +export = useBinaryState; \ No newline at end of file diff --git a/src/routes/Calendar/Calendar.tsx b/src/routes/Calendar/Calendar.tsx index 267d6f523..d51de4785 100644 --- a/src/routes/Calendar/Calendar.tsx +++ b/src/routes/Calendar/Calendar.tsx @@ -1,11 +1,13 @@ // Copyright (C) 2017-2024 Smart code 203358507 -import React, { useState } from 'react'; -import { MainNavBars, PaginationInput, useProfile, withCoreSuspender } from 'stremio/common'; +import React, { useMemo, useState } from 'react'; +import { MainNavBars, PaginationInput, BottomSheet, useProfile, withCoreSuspender } from 'stremio/common'; import Table from './Table'; import List from './List'; +import Details from './Details'; import Placeholder from './Placeholder'; import useCalendar from './useCalendar'; +import useCalendarDate from './useCalendarDate'; import useSelectableInputs from './useSelectableInputs'; import styles from './Calendar.less'; @@ -16,11 +18,14 @@ type Props = { const Calendar = ({ urlParams }: Props) => { const calendar = useCalendar(urlParams); const profile = useProfile(); - + const [paginationInput] = useSelectableInputs(calendar, profile); + const { toDayMonth } = useCalendarDate(profile); const [selected, setSelected] = useState(null); + const detailsTitle = useMemo(() => toDayMonth(selected), [selected]); + return ( { @@ -49,6 +54,12 @@ const Calendar = ({ urlParams }: Props) => { profile={profile} onChange={setSelected} /> + +
+
: diff --git a/src/routes/Calendar/Details/Details.less b/src/routes/Calendar/Details/Details.less new file mode 100644 index 000000000..db11acc78 --- /dev/null +++ b/src/routes/Calendar/Details/Details.less @@ -0,0 +1,59 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +.details { + position: relative; + + .video { + flex: none; + position: relative; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 0 1.5rem; + height: 4rem; + 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; + display: block; + } + + .icon { + flex: none; + width: 2rem; + height: 2rem; + padding: 0.5rem; + border-radius: 50%; + color: var(--primary-foreground-color); + } + + &:hover, &:active { + background-color: var(--overlay-color); + + .icon { + display: block; + background-color: var(--secondary-accent-color); + } + } + } + + .placeholder { + display: flex; + align-items: center; + justify-content: center; + height: 10rem; + font-size: 1rem; + color: var(--primary-foreground-color); + } +} \ No newline at end of file diff --git a/src/routes/Calendar/Details/Details.tsx b/src/routes/Calendar/Details/Details.tsx new file mode 100644 index 000000000..0f48b8800 --- /dev/null +++ b/src/routes/Calendar/Details/Details.tsx @@ -0,0 +1,45 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React, { useMemo } from 'react'; +import Icon from '@stremio/stremio-icons/react'; +import Button from 'stremio/common/Button'; +import styles from './Details.less'; + +type Props = { + selected: CalendarDate | null, + items: CalendarItem[], +}; + +const Details = ({ selected, items }: Props) => { + const videos = useMemo(() => { + return items.find(({ date }) => date.day === selected?.day)?.items ?? []; + }, [selected, items]); + + return ( +
+ { + videos.map(({ id, name, season, episode, deepLinks }) => ( + + )) + } + { + !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 17/42] 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 18/42] 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 19/42] 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 2d9f3fa6ac2c924830d72bd9acf076a2e71c5575 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 3 Oct 2024 08:56:20 +0200 Subject: [PATCH 20/42] 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 21/42] 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 1d0cb4dfa022db7fc1653e2c4d8a705d7b9f7332 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 9 Oct 2024 10:56:52 +0200 Subject: [PATCH 22/42] 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 23/42] 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 820f7eaf8154d915bd82fd7376bf351ecdadbb11 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 29 Oct 2024 08:39:29 +0100 Subject: [PATCH 24/42] fix(Calendar): use useCallback for useCalendarDate functions --- src/routes/Calendar/Calendar.tsx | 2 +- src/routes/Calendar/useCalendarDate.ts | 10 ++++++---- src/routes/Calendar/useSelectableInputs.ts | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/routes/Calendar/Calendar.tsx b/src/routes/Calendar/Calendar.tsx index 7a4e8163d..4df5e4bf2 100644 --- a/src/routes/Calendar/Calendar.tsx +++ b/src/routes/Calendar/Calendar.tsx @@ -24,7 +24,7 @@ const Calendar = ({ urlParams }: Props) => { const [selected, setSelected] = useState(null); - const detailsTitle = useMemo(() => toDayMonth(selected), [selected]); + const detailsTitle = useMemo(() => toDayMonth(selected), [selected, toDayMonth]); return ( diff --git a/src/routes/Calendar/useCalendarDate.ts b/src/routes/Calendar/useCalendarDate.ts index d3cb5b869..b2dd70d75 100644 --- a/src/routes/Calendar/useCalendarDate.ts +++ b/src/routes/Calendar/useCalendarDate.ts @@ -1,5 +1,7 @@ +import { useCallback } from "react"; + const useCalendarDate = (profile: Profile) => { - const toMonthYear = (calendarDate: CalendarDate | null): string => { + const toMonthYear = useCallback((calendarDate: CalendarDate | null): string => { if (!calendarDate) return ''; const date = new Date(); @@ -10,9 +12,9 @@ const useCalendarDate = (profile: Profile) => { month: 'long', year: 'numeric', }); - }; + }, [profile.settings]); - const toDayMonth = (calendarDate: CalendarDate | null): string => { + const toDayMonth = useCallback((calendarDate: CalendarDate | null): string => { if (!calendarDate) return ''; const date = new Date(); @@ -23,7 +25,7 @@ const useCalendarDate = (profile: Profile) => { day: 'numeric', month: 'short', }); - }; + }, [profile.settings]); return { toMonthYear, diff --git a/src/routes/Calendar/useSelectableInputs.ts b/src/routes/Calendar/useSelectableInputs.ts index a136ab5a5..bfe51743a 100644 --- a/src/routes/Calendar/useSelectableInputs.ts +++ b/src/routes/Calendar/useSelectableInputs.ts @@ -27,7 +27,7 @@ const useSelectableInputs = (calendar: Calendar, profile: Profile) => { const selectableInputs = React.useMemo(() => { return mapSelectableInputs(calendar, toMonthYear); - }, [calendar]); + }, [calendar, toMonthYear]); return selectableInputs; }; From d9b82acc4a5d6d6ee0bed063c571e1a04fbb69b3 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 29 Oct 2024 08:40:06 +0100 Subject: [PATCH 25/42] fix(Calendar): lint --- src/routes/Calendar/useCalendarDate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Calendar/useCalendarDate.ts b/src/routes/Calendar/useCalendarDate.ts index b2dd70d75..5143fe6da 100644 --- a/src/routes/Calendar/useCalendarDate.ts +++ b/src/routes/Calendar/useCalendarDate.ts @@ -1,4 +1,4 @@ -import { useCallback } from "react"; +import { useCallback } from 'react'; const useCalendarDate = (profile: Profile) => { const toMonthYear = useCallback((calendarDate: CalendarDate | null): string => { From ea933fe5c33eb1dc444644cee52735717a5ca22b Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 29 Oct 2024 08:46:28 +0100 Subject: [PATCH 26/42] refactor(PaginationInput): transition when hovering the button --- src/common/PaginationInput/styles.less | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/common/PaginationInput/styles.less b/src/common/PaginationInput/styles.less index 9005fefa5..5590d2a7f 100644 --- a/src/common/PaginationInput/styles.less +++ b/src/common/PaginationInput/styles.less @@ -18,9 +18,11 @@ display: block; color: var(--primary-foreground-color); opacity: 0.7; - transition: opacity 0.2s ease-in-out; + transition: opacity 0.1s ease-in; + } - &:hover { + &:hover { + .icon { opacity: 1; } } From ac0190837473b6062d690915bb54d8288d50d1e7 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 29 Oct 2024 08:54:21 +0100 Subject: [PATCH 27/42] fix(Calendar): deselect day when closing details --- src/common/BottomSheet/BottomSheet.tsx | 12 ++++++++---- src/routes/Calendar/Calendar.tsx | 6 +++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/common/BottomSheet/BottomSheet.tsx b/src/common/BottomSheet/BottomSheet.tsx index e767f1847..d362aa02e 100644 --- a/src/common/BottomSheet/BottomSheet.tsx +++ b/src/common/BottomSheet/BottomSheet.tsx @@ -15,7 +15,7 @@ type Props = { onClose: () => void, }; -const BottomSheet = ({ children, title, show }: Props) => { +const BottomSheet = ({ children, title, show, onClose }: Props) => { const containerRef = useRef(null); const [startOffset, setStartOffset] = useState(0); const [offset, setOffset] = useState(0); @@ -28,7 +28,7 @@ const BottomSheet = ({ children, title, show }: Props) => { const containerHeight = () => containerRef.current?.offsetHeight ?? 0; - const onClose = () => setOffset(containerHeight()); + const onCloseRequest = () => setOffset(containerHeight()); const onTouchStart = ({ touches }: React.TouchEvent) => { const { clientY } = touches[0]; @@ -54,9 +54,13 @@ const BottomSheet = ({ children, title, show }: Props) => { show ? open() : close(); }, [show]); + useEffect(() => { + !opened && onClose(); + }, [opened]); + return opened && createPortal((
-
+
{ {title}
-
+
{children}
diff --git a/src/routes/Calendar/Calendar.tsx b/src/routes/Calendar/Calendar.tsx index 4df5e4bf2..f27ef12b6 100644 --- a/src/routes/Calendar/Calendar.tsx +++ b/src/routes/Calendar/Calendar.tsx @@ -26,6 +26,10 @@ const Calendar = ({ urlParams }: Props) => { const detailsTitle = useMemo(() => toDayMonth(selected), [selected, toDayMonth]); + const onDetailsClose = () => { + setSelected(null); + }; + return ( { @@ -54,7 +58,7 @@ const Calendar = ({ urlParams }: Props) => { profile={profile} onChange={setSelected} /> - +
Date: Tue, 29 Oct 2024 08:58:17 +0100 Subject: [PATCH 28/42] feat(Calendar): add transition to border of items --- src/routes/Calendar/List/Item/Item.less | 1 + src/routes/Calendar/Table/Cell/Cell.less | 1 + 2 files changed, 2 insertions(+) diff --git a/src/routes/Calendar/List/Item/Item.less b/src/routes/Calendar/List/Item/Item.less index cdcb708b8..4ce981807 100644 --- a/src/routes/Calendar/List/Item/Item.less +++ b/src/routes/Calendar/List/Item/Item.less @@ -8,6 +8,7 @@ background-color: var(--overlay-color); border-radius: var(--border-radius); border: 0.15rem solid transparent; + transition: border-color 0.1s ease-out; .heading { flex: none; diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less index 2262de210..6e0a5aa99 100644 --- a/src/routes/Calendar/Table/Cell/Cell.less +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -12,6 +12,7 @@ border: 0.15rem solid transparent; overflow: hidden; cursor: pointer; + transition: border-color 0.1s ease-out; &:first-child { border-radius: var(--border-radius) 0 0 0; From a98d38fa25eaac7ec2c8b87c7cb870546f2aac16 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 30 Oct 2024 10:23:21 +0100 Subject: [PATCH 29/42] fix(BottomSheet): remove chrome mobile highlight color for backdrop --- src/common/BottomSheet/BottomSheet.less | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/BottomSheet/BottomSheet.less b/src/common/BottomSheet/BottomSheet.less index b159242d0..3a67cba33 100644 --- a/src/common/BottomSheet/BottomSheet.less +++ b/src/common/BottomSheet/BottomSheet.less @@ -23,6 +23,7 @@ opacity: 0.8; transition: opacity 0.1s ease-out; cursor: pointer; + -webkit-tap-highlight-color: transparent; } .container { From 57fc3bc263917ba310662daf20b324a63bb01236 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 30 Oct 2024 10:23:40 +0100 Subject: [PATCH 30/42] fix(BottomSheet): add bottom padding to container --- src/common/BottomSheet/BottomSheet.less | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/BottomSheet/BottomSheet.less b/src/common/BottomSheet/BottomSheet.less index 3a67cba33..e0d756477 100644 --- a/src/common/BottomSheet/BottomSheet.less +++ b/src/common/BottomSheet/BottomSheet.less @@ -35,6 +35,7 @@ display: flex; flex-direction: column; gap: 1.5rem; + padding-bottom: 1rem; border-radius: 2rem 2rem 0 0; background-color: var(--modal-background-color); box-shadow: var(--outer-glow); From 79cde15ade0800bffabb3cdf6cf285519a0dbdbc Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 31 Oct 2024 15:09:28 +0100 Subject: [PATCH 31/42] fix(Calendar): toMonthYear returned incorrect month depending on the day --- src/routes/Calendar/useCalendarDate.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/Calendar/useCalendarDate.ts b/src/routes/Calendar/useCalendarDate.ts index 5143fe6da..b92c72266 100644 --- a/src/routes/Calendar/useCalendarDate.ts +++ b/src/routes/Calendar/useCalendarDate.ts @@ -5,6 +5,7 @@ const useCalendarDate = (profile: Profile) => { if (!calendarDate) return ''; const date = new Date(); + date.setDate(1); date.setMonth(calendarDate.month - 1); date.setFullYear(calendarDate.year); From 7874062156e73059be85db77e0d4d81e4abeca88 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 31 Oct 2024 15:10:16 +0100 Subject: [PATCH 32/42] chore: use dev build of core-web --- package-lock.json | 11 +++++++---- package.json | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4b10d3e62..cfd8c960f 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.8", + "@stremio/stremio-core-web": "http://stremio.github.io/stremio-core/stremio-core-web/development/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", @@ -3133,8 +3133,9 @@ }, "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": "http://stremio.github.io/stremio-core/stremio-core-web/development/stremio-stremio-core-web-0.47.8.tgz", + "integrity": "sha512-TulKl3gUdMxIUa6xJpoVzyLWRLq0RRLmD3b0GuA5hx9MZC0zF8abeWzCV38Y/jWRIXSxnku+x6KR3E9ODFPS8Q==", + "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" } @@ -3143,6 +3144,7 @@ "version": "7.24.1", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -3153,7 +3155,8 @@ "node_modules/@stremio/stremio-core-web/node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" }, "node_modules/@stremio/stremio-icons": { "version": "5.2.0", diff --git a/package.json b/package.json index 30613b0a9..3cb7cc1e8 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.8", + "@stremio/stremio-core-web": "http://stremio.github.io/stremio-core/stremio-core-web/development/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 9df9a4e1a116edb902b96c0444f73af6fdb167bb Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 4 Nov 2024 15:31:00 +0100 Subject: [PATCH 33/42] fix(Calendar): layout issue for small viewports --- src/routes/Calendar/Table/Cell/Cell.less | 25 ++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/routes/Calendar/Table/Cell/Cell.less b/src/routes/Calendar/Table/Cell/Cell.less index 6e0a5aa99..3ecb32d15 100644 --- a/src/routes/Calendar/Table/Cell/Cell.less +++ b/src/routes/Calendar/Table/Cell/Cell.less @@ -7,7 +7,7 @@ display: flex; flex-direction: column; justify-content: space-between; - gap: 2rem; + gap: 0.5rem; background-color: var(--overlay-color); border: 0.15rem solid transparent; overflow: hidden; @@ -29,8 +29,10 @@ .heading { flex: none; position: relative; + height: 3rem; display: flex; - padding: 1rem 1rem 0 1rem; + align-items: center; + padding: 0 1rem; .day { flex: none; @@ -48,12 +50,11 @@ } .items { - flex: 1 1 auto; + flex: 0 1 10rem; position: relative; display: flex; flex-direction: row; gap: 1rem; - height: 0; padding: 0 1rem 1rem 1rem; .item { @@ -139,8 +140,6 @@ @media only screen and (orientation: portrait) { .cell { - gap: 0; - .heading { justify-content: center; } @@ -155,21 +154,23 @@ } } -@media only screen and (max-width: @xsmall) and (orientation: landscape) { +@media only screen and (max-width: @small) and (orientation: landscape) { .cell { flex-direction: row; align-items: center; - .heading { - padding: 0 0 0 1rem; + .items { + display: none; + } + + .more { + display: flex; } } } -@media only screen and (max-height: @xsmall) and (orientation: landscape) { +@media only screen and (max-height: @xxsmall) and (orientation: landscape) { .cell { - gap: 0; - .items { display: none; } From 941e3795d8b5adf2def917b9ec7556b97f84bd9e Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 20 Nov 2024 15:37:45 +0100 Subject: [PATCH 34/42] chore: update stremio-core-web --- 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 cfd8c960f..65057bf18 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": "http://stremio.github.io/stremio-core/stremio-core-web/development/stremio-stremio-core-web-0.47.8.tgz", + "@stremio/stremio-core-web": "0.48.0", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", @@ -3132,9 +3132,9 @@ "license": "MIT" }, "node_modules/@stremio/stremio-core-web": { - "version": "0.47.8", - "resolved": "http://stremio.github.io/stremio-core/stremio-core-web/development/stremio-stremio-core-web-0.47.8.tgz", - "integrity": "sha512-TulKl3gUdMxIUa6xJpoVzyLWRLq0RRLmD3b0GuA5hx9MZC0zF8abeWzCV38Y/jWRIXSxnku+x6KR3E9ODFPS8Q==", + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.48.0.tgz", + "integrity": "sha512-UEVxb5weAIZ22Hz0iNKM8O1QkALcLShG9AyCe1P2WhZhyiridbwE7MtP5itBtLcLm9f/D6UeRrpUWMCS01n18Q==", "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" diff --git a/package.json b/package.json index 3cb7cc1e8..6be38fa66 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": "http://stremio.github.io/stremio-core/stremio-core-web/development/stremio-stremio-core-web-0.47.8.tgz", + "@stremio/stremio-core-web": "0.48.0", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", From e5e67d547a13a6c964810c68b6de6fc79c1ab06c Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 28 Nov 2024 11:31:27 +0100 Subject: [PATCH 35/42] feat(Calendar): implement selector --- src/common/PaginationInput/PaginationInput.js | 44 --------- src/common/PaginationInput/index.js | 5 - src/common/PaginationInput/styles.less | 50 ---------- src/common/index.js | 2 - src/routes/Calendar/Calendar.less | 35 ------- src/routes/Calendar/Calendar.tsx | 18 ++-- src/routes/Calendar/Selector/Selector.less | 95 +++++++++++++++++++ src/routes/Calendar/Selector/Selector.tsx | 60 ++++++++++++ src/routes/Calendar/Selector/index.ts | 2 + src/routes/Calendar/useCalendarDate.ts | 13 +++ src/routes/Calendar/useSelectableInputs.ts | 35 ------- src/routes/Discover/styles.less | 7 -- 12 files changed, 177 insertions(+), 189 deletions(-) delete mode 100644 src/common/PaginationInput/PaginationInput.js delete mode 100644 src/common/PaginationInput/index.js delete mode 100644 src/common/PaginationInput/styles.less create mode 100644 src/routes/Calendar/Selector/Selector.less create mode 100644 src/routes/Calendar/Selector/Selector.tsx create mode 100644 src/routes/Calendar/Selector/index.ts delete mode 100644 src/routes/Calendar/useSelectableInputs.ts diff --git a/src/common/PaginationInput/PaginationInput.js b/src/common/PaginationInput/PaginationInput.js deleted file mode 100644 index 41d740b3f..000000000 --- a/src/common/PaginationInput/PaginationInput.js +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const React = require('react'); -const PropTypes = require('prop-types'); -const classnames = require('classnames'); -const { default: Icon } = require('@stremio/stremio-icons/react'); -const Button = require('stremio/common/Button'); -const styles = require('./styles'); - -const PaginationInput = ({ className, label, dataset, onSelect, ...props }) => { - const prevNextButtonOnClick = React.useCallback((event) => { - if (typeof onSelect === 'function') { - onSelect({ - type: 'change-page', - value: event.currentTarget.dataset.value, - dataset: dataset, - reactEvent: event, - nativeEvent: event.nativeEvent - }); - } - }, [dataset, onSelect]); - return ( -
- -
-
{label}
-
- -
- ); -}; - -PaginationInput.propTypes = { - className: PropTypes.string, - label: PropTypes.string, - dataset: PropTypes.object, - onSelect: PropTypes.func -}; - -module.exports = PaginationInput; diff --git a/src/common/PaginationInput/index.js b/src/common/PaginationInput/index.js deleted file mode 100644 index da139e27d..000000000 --- a/src/common/PaginationInput/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const PaginationInput = require('./PaginationInput'); - -module.exports = PaginationInput; diff --git a/src/common/PaginationInput/styles.less b/src/common/PaginationInput/styles.less deleted file mode 100644 index 5590d2a7f..000000000 --- a/src/common/PaginationInput/styles.less +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -@import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; - -.pagination-input-container { - display: flex; - flex-direction: row; - border-radius: var(--border-radius); - - .prev-button-container, .next-button-container { - flex: none; - display: flex; - align-items: center; - justify-content: center; - background-color: var(--overlay-color); - - .icon { - display: block; - color: var(--primary-foreground-color); - opacity: 0.7; - transition: opacity 0.1s ease-in; - } - - &:hover { - .icon { - opacity: 1; - } - } - } - - .label-container { - flex: 1; - align-self: stretch; - display: flex; - align-items: center; - justify-content: center; - background-color: var(--overlay-color); - - .label { - flex: none; - min-width: 1.2rem; - max-width: 3rem; - white-space: nowrap; - text-overflow: ellipsis; - text-align: center; - font-weight: 500; - color: var(--primary-foreground-color); - } - } -} \ No newline at end of file diff --git a/src/common/index.js b/src/common/index.js index b82a47839..8deae04fe 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -19,7 +19,6 @@ const Multiselect = require('./Multiselect'); const { default: MultiselectMenu } = require('./MultiselectMenu'); const { HorizontalNavBar, VerticalNavBar } = require('./NavBar'); const { default: HorizontalScroll } = require('./HorizontalScroll'); -const PaginationInput = require('./PaginationInput'); const { PlatformProvider, usePlatform } = require('./Platform'); const PlayIconCircleCentered = require('./PlayIconCircleCentered'); const Popup = require('./Popup'); @@ -71,7 +70,6 @@ module.exports = { HorizontalNavBar, HorizontalScroll, VerticalNavBar, - PaginationInput, PlatformProvider, usePlatform, PlayIconCircleCentered, diff --git a/src/routes/Calendar/Calendar.less b/src/routes/Calendar/Calendar.less index cdefb4431..7f7925bf5 100644 --- a/src/routes/Calendar/Calendar.less +++ b/src/routes/Calendar/Calendar.less @@ -2,13 +2,6 @@ @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; - pagination-button-icon: icon; - pagination-label: label; -} - .calendar { width: 100%; height: 100%; @@ -29,34 +22,6 @@ 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; - - .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; - } - } - } } } } diff --git a/src/routes/Calendar/Calendar.tsx b/src/routes/Calendar/Calendar.tsx index f27ef12b6..2ff1da70a 100644 --- a/src/routes/Calendar/Calendar.tsx +++ b/src/routes/Calendar/Calendar.tsx @@ -1,14 +1,14 @@ // Copyright (C) 2017-2024 Smart code 203358507 import React, { useMemo, useState } from 'react'; -import { MainNavBars, PaginationInput, BottomSheet, useProfile, withCoreSuspender } from 'stremio/common'; +import { MainNavBars, BottomSheet, useProfile, withCoreSuspender } from 'stremio/common'; +import Selector from './Selector'; import Table from './Table'; import List from './List'; import Details from './Details'; import Placeholder from './Placeholder'; import useCalendar from './useCalendar'; import useCalendarDate from './useCalendarDate'; -import useSelectableInputs from './useSelectableInputs'; import styles from './Calendar.less'; type Props = { @@ -19,7 +19,6 @@ const Calendar = ({ urlParams }: Props) => { const calendar = useCalendar(urlParams); const profile = useProfile(); - const [paginationInput] = useSelectableInputs(calendar, profile); const { toDayMonth } = useCalendarDate(profile); const [selected, setSelected] = useState(null); @@ -36,14 +35,11 @@ const Calendar = ({ urlParams }: Props) => { profile.auth !== null ?
-
- { - paginationInput !== null ? - - : - null - } -
+
{ + 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 320bca2e350e108bbf9e28de4e7debd2767a743f Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 28 Nov 2024 11:45:26 +0100 Subject: [PATCH 36/42] 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 37/42] 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 38/42] 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 39/42] 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 40/42] 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 41/42] 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 7b877151533cd927d340fad7600e90bb53032f3f Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 28 Nov 2024 15:07:39 +0100 Subject: [PATCH 42/42] 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 (