Timezones, mobile calendar support

This commit is contained in:
Ben Grant 2021-03-02 22:21:39 +11:00
parent 0dde47109f
commit 89fd659f5c
15 changed files with 789 additions and 76 deletions

View file

@ -26,6 +26,7 @@ export const Top = styled.button`
width: var(--btn-width);
position: absolute;
top: -4px;
left: 0;
user-select: none;
transition: top .15s;
outline: none;

View file

@ -8,6 +8,7 @@ import {
StyledLabel,
StyledSubLabel,
CalendarHeader,
CalendarDays,
CalendarBody,
Date,
Day,
@ -141,10 +142,12 @@ const CalendarField = ({
>&gt;</Button>
</CalendarHeader>
<CalendarBody>
<CalendarDays>
{days.map((name, i) =>
<Day key={i}>{name}</Day>
)}
</CalendarDays>
<CalendarBody>
{dates.length > 0 && dates.map((dateRow, y) =>
dateRow.map((date, x) =>
<Date
@ -155,12 +158,13 @@ const CalendarField = ({
selected={selectedDates.includes(date.format('DDMMYYYY'))}
selecting={selectingDates.includes(date)}
mode={mode}
onMouseDown={() => {
onPointerDown={(e) => {
startPos.current = {x, y};
setMode(selectedDates.includes(date.format('DDMMYYYY')) ? 'remove' : 'add');
setSelectingDates([date]);
e.currentTarget.releasePointerCapture(e.pointerId);
document.addEventListener('mouseup', () => {
document.addEventListener('pointerup', () => {
if (staticMode.current === 'add') {
setSelectedDates([...selectedDates, ...staticSelectingDates.current.map(d => d.format('DDMMYYYY'))]);
} else if (staticMode.current === 'remove') {
@ -170,7 +174,7 @@ const CalendarField = ({
setMode(null);
}, { once: true });
}}
onMouseEnter={() => {
onPointerEnter={() => {
if (staticMode.current) {
let found = [];
for (let cy = Math.min(startPos.current.y, y); cy < Math.max(startPos.current.y, y)+1; cy++) {

View file

@ -27,21 +27,40 @@ export const CalendarHeader = styled.div`
font-weight: bold;
`;
export const CalendarBody = styled.div`
export const CalendarDays = styled.div`
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-gap: 2px;
`;
export const CalendarBody = styled.div`
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-gap: 2px;
& div:first-child {
border-top-left-radius: 3px;
}
& div:nth-child(7) {
border-top-right-radius: 3px;
}
& div:nth-last-child(7) {
border-bottom-left-radius: 3px;
}
& div:last-child {
border-bottom-right-radius: 3px;
}
`;
export const Date = styled.div`
background-color: ${props => props.theme.primary}22;
background-color: ${props => props.theme.primaryBackground};
border: 1px solid ${props => props.theme.primaryLight};
display: flex;
align-items: center;
justify-content: center;
padding: 10px 0;
border-radius: 3px;
user-select: none;
touch-action: none;
${props => props.otherMonth && `
color: ${props.theme.primaryLight};
@ -49,6 +68,7 @@ export const Date = styled.div`
${props => props.isToday && `
font-weight: 900;
color: ${props.theme.primaryDark};
text-decoration: underline;
`}
${props => (props.selected || (props.mode === 'add' && props.selecting)) && `
color: ${props.otherMonth ? 'rgba(255,255,255,.5)' : '#FFF'};
@ -56,7 +76,7 @@ export const Date = styled.div`
border-color: ${props.theme.primary};
`}
${props => props.mode === 'remove' && props.selecting && `
background-color: ${props.theme.primary}22;
background-color: ${props.theme.primaryBackground};
border: 1px solid ${props.theme.primaryLight};
color: ${props.isToday ? props.theme.primaryDark : (props.otherMonth ? props.theme.primaryLight : 'inherit')};
`}

View file

@ -0,0 +1,7 @@
import styled from '@emotion/styled';
const Center = styled.div`
text-align: center;
`;
export default Center;

View file

@ -0,0 +1,33 @@
import {
Wrapper,
StyledLabel,
StyledSubLabel,
StyledSelect,
} from './selectFieldStyle';
const SelectField = ({
label,
subLabel,
id,
options = [],
register,
...props
}) => (
<Wrapper>
{label && <StyledLabel htmlFor={id}>{label}</StyledLabel>}
{subLabel && <StyledSubLabel htmlFor={id}>{subLabel}</StyledSubLabel>}
<StyledSelect
id={id}
ref={register}
{...props}
>
<option value="">Select...</option>
{options.map((value, i) =>
<option key={i} value={value}>{value}</option>
)}
</StyledSelect>
</Wrapper>
);
export default SelectField;

View file

@ -0,0 +1,37 @@
import styled from '@emotion/styled';
export const Wrapper = styled.div`
margin: 30px 0;
`;
export const StyledLabel = styled.label`
display: block;
padding-bottom: 4px;
font-size: 18px;
`;
export const StyledSubLabel = styled.label`
display: block;
padding-bottom: 6px;
font-size: 13px;
opacity: .6;
`;
export const StyledSelect = styled.select`
width: 100%;
box-sizing: border-box;
font: inherit;
background: ${props => props.theme.primaryBackground};
color: inherit;
padding: 10px 14px;
border: 1px solid ${props => props.theme.primaryLight};
box-shadow: inset 0 0 0 0 ${props => props.theme.primaryLight};
border-radius: 3px;
outline: none;
transition: border-color .15s, box-shadow .15s;
&:focus {
border: 1px solid ${props => props.theme.primary};
box-shadow: inset 0 -3px 0 0 ${props => props.theme.primary};
}
`;

View file

@ -21,7 +21,7 @@ export const StyledInput = styled.input`
width: 100%;
box-sizing: border-box;
font: inherit;
background: ${props => props.theme.primary}22;
background: ${props => props.theme.primaryBackground};
color: inherit;
padding: 10px 14px;
border: 1px solid ${props => props.theme.primaryLight};

View file

@ -19,7 +19,7 @@ export const StyledSubLabel = styled.label`
export const Range = styled.div`
user-select: none;
background-color: ${props => props.theme.primary}22;
background-color: ${props => props.theme.primaryBackground};
border: 1px solid ${props => props.theme.primaryLight};
border-radius: 3px;
height: 50px;
@ -37,6 +37,7 @@ export const Handle = styled.div`
top: -10px;
left: calc(${props => props.value * 4.1666666666666666}% - 11px);
cursor: ew-resize;
touch-action: none;
&:after {
content: '|||';

View file

@ -1,4 +1,6 @@
export { default as TextField } from './TextField/TextField';
export { default as SelectField } from './SelectField/SelectField';
export { default as CalendarField } from './CalendarField/CalendarField';
export { default as TimeRangeField } from './TimeRangeField/TimeRangeField';
export { default as Button } from './Button/Button';
export { default as Center } from './Center/Center';