feat(Calendar): implement selector

This commit is contained in:
Tim 2024-11-28 11:31:27 +01:00
parent 941e3795d8
commit e5e67d547a
12 changed files with 177 additions and 189 deletions

View file

@ -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 (
<div {...props} className={classnames(className, styles['pagination-input-container'])} >
<Button className={styles['prev-button-container']} title={'Previous page'} data-value={'prev'} onClick={prevNextButtonOnClick}>
<Icon className={styles['icon']} name={'chevron-back'} />
</Button>
<div className={styles['label-container']} title={label}>
<div className={styles['label']}>{label}</div>
</div>
<Button className={styles['next-button-container']} title={'Next page'} data-value={'next'} onClick={prevNextButtonOnClick}>
<Icon className={styles['icon']} name={'chevron-forward'} />
</Button>
</div>
);
};
PaginationInput.propTypes = {
className: PropTypes.string,
label: PropTypes.string,
dataset: PropTypes.object,
onSelect: PropTypes.func
};
module.exports = PaginationInput;

View file

@ -1,5 +0,0 @@
// Copyright (C) 2017-2023 Smart code 203358507
const PaginationInput = require('./PaginationInput');
module.exports = PaginationInput;

View file

@ -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);
}
}
}

View file

@ -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,

View file

@ -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;
}
}
}
}
}
}

View file

@ -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<CalendarDate | null>(null);
@ -36,14 +35,11 @@ const Calendar = ({ urlParams }: Props) => {
profile.auth !== null ?
<div className={styles['content']}>
<div className={styles['main']}>
<div className={styles['inputs']}>
{
paginationInput !== null ?
<PaginationInput {...paginationInput} className={styles['pagination-input']} />
:
null
}
</div>
<Selector
selected={calendar.selected}
selectable={calendar.selectable}
profile={profile}
/>
<Table
items={calendar.items}
selected={selected}

View file

@ -0,0 +1,95 @@
@import (reference) '~stremio/common/screen-sizes.less';
.selector {
flex: none;
position: relative;
display: flex;
gap: 3rem;
align-items: center;
justify-content: center;
.prev, .next {
position: relative;
height: 3rem;
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;
.label, .icon {
color: var(--primary-foreground-color);
opacity: 0.5;
transition: opacity 0.1s ease-out;
}
.label {
font-size: 1rem;
font-weight: 500;
}
.icon {
height: 1.5rem;
}
&:hover {
.label, .icon {
opacity: 1;
}
background-color: var(--overlay-color);
}
}
.prev {
padding-left: 0.5rem;
padding-right: 1rem;
}
.next {
padding-left: 1rem;
padding-right: 0.5rem;
}
.selected {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
.year {
font-size: 1rem;
font-weight: 500;
line-height: 100%;
color: var(--primary-foreground-color);
opacity: 0.5;
}
.month {
font-size: 1.5rem;
font-weight: 500;
color: var(--primary-foreground-color);
white-space: nowrap;
}
}
}
@media only screen and (max-width: @small) {
.selector {
.prev, .next {
position: absolute;
}
.prev {
left: 1rem;
}
.next {
right: 1rem;
}
}
}

View file

@ -0,0 +1,60 @@
import React, { useCallback, useMemo } from 'react';
import Icon from '@stremio/stremio-icons/react';
import { Button } from 'stremio/common';
import useCalendarDate from '../useCalendarDate';
import styles from './Selector.less';
type Props = {
selected: CalendarSelected,
selectable: CalendarSelectable,
profile: Profile,
};
const Selector = ({ selected, selectable, profile }: Props) => {
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 (
<div className={styles['selector']}>
<Button className={styles['prev']} onClick={onPrev}>
<Icon
className={styles['icon']}
name={'chevron-back'}
/>
<div className={styles['label']}>
{toMonth(prev, 'short')}
</div>
</Button>
<div className={styles['selected']}>
<div className={styles['year']}>
{selected?.year}
</div>
<div className={styles['month']}>
{toMonth(selected, 'long')}
</div>
</div>
<Button className={styles['next']} onClick={onNext}>
<div className={styles['label']}>
{toMonth(next, 'short')}
</div>
<Icon
className={styles['icon']}
name={'chevron-forward'}
/>
</Button>
</div>
);
};
export default Selector;

View file

@ -0,0 +1,2 @@
import Selector from './Selector';
export default Selector;

View file

@ -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,
};

View file

@ -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;

View file

@ -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;