Timezones, mobile calendar support
This commit is contained in:
parent
0dde47109f
commit
89fd659f5c
15 changed files with 789 additions and 76 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
StyledLabel,
|
||||
StyledSubLabel,
|
||||
CalendarHeader,
|
||||
CalendarDays,
|
||||
CalendarBody,
|
||||
Date,
|
||||
Day,
|
||||
|
|
@ -141,10 +142,12 @@ const CalendarField = ({
|
|||
>></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++) {
|
||||
|
|
|
|||
|
|
@ -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')};
|
||||
`}
|
||||
|
|
|
|||
7
crabfit-frontend/src/components/Center/Center.ts
Normal file
7
crabfit-frontend/src/components/Center/Center.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import styled from '@emotion/styled';
|
||||
|
||||
const Center = styled.div`
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
export default Center;
|
||||
33
crabfit-frontend/src/components/SelectField/SelectField.tsx
Normal file
33
crabfit-frontend/src/components/SelectField/SelectField.tsx
Normal 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;
|
||||
|
|
@ -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};
|
||||
}
|
||||
`;
|
||||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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: '|||';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue