diff --git a/crabfit-frontend/public/fonts/molot.otf b/crabfit-frontend/public/fonts/molot.otf
deleted file mode 100644
index 28c3049..0000000
Binary files a/crabfit-frontend/public/fonts/molot.otf and /dev/null differ
diff --git a/crabfit-frontend/public/fonts/molot.woff b/crabfit-frontend/public/fonts/molot.woff
new file mode 100644
index 0000000..831ef3f
Binary files /dev/null and b/crabfit-frontend/public/fonts/molot.woff differ
diff --git a/crabfit-frontend/public/fonts/molot.woff2 b/crabfit-frontend/public/fonts/molot.woff2
new file mode 100644
index 0000000..a5299b3
Binary files /dev/null and b/crabfit-frontend/public/fonts/molot.woff2 differ
diff --git a/crabfit-frontend/public/fonts/samuraibob.ttf b/crabfit-frontend/public/fonts/samuraibob.ttf
deleted file mode 100644
index 8ab735c..0000000
Binary files a/crabfit-frontend/public/fonts/samuraibob.ttf and /dev/null differ
diff --git a/crabfit-frontend/public/fonts/samuraibob.woff b/crabfit-frontend/public/fonts/samuraibob.woff
new file mode 100644
index 0000000..a0ac9b4
Binary files /dev/null and b/crabfit-frontend/public/fonts/samuraibob.woff differ
diff --git a/crabfit-frontend/public/fonts/samuraibob.woff2 b/crabfit-frontend/public/fonts/samuraibob.woff2
new file mode 100644
index 0000000..69f0a93
Binary files /dev/null and b/crabfit-frontend/public/fonts/samuraibob.woff2 differ
diff --git a/crabfit-frontend/public/index.css b/crabfit-frontend/public/index.css
index 1101eb6..952af59 100644
--- a/crabfit-frontend/public/index.css
+++ b/crabfit-frontend/public/index.css
@@ -5,13 +5,17 @@
}
@font-face {
- font-family: 'Samurai Bob';
- src: url('fonts/samuraibob.ttf') format('truetype');
- font-weight: 400;
+ font-family: 'Samurai Bob';
+ src: url('fonts/samuraibob.woff2') format('woff2'),
+ url('fonts/samuraibob.woff') format('woff');
+ font-weight: 400;
+ font-style: normal;
}
@font-face {
- font-family: 'Molot';
- src: url('fonts/molot.otf') format('opentype');
- font-weight: 400;
+ font-family: 'Molot';
+ src: url('fonts/molot.woff2') format('woff2'),
+ url('fonts/molot.woff') format('woff');
+ font-weight: 400;
+ font-style: normal;
}
diff --git a/crabfit-frontend/src/App.tsx b/crabfit-frontend/src/App.tsx
index 28cb828..74cdd38 100644
--- a/crabfit-frontend/src/App.tsx
+++ b/crabfit-frontend/src/App.tsx
@@ -6,6 +6,7 @@ import {
} from 'react-router-dom';
import { ThemeProvider, Global } from '@emotion/react';
+import { Settings } from 'components';
import {
Home,
Event,
@@ -22,7 +23,7 @@ const App = () => {
return (
- {process.env.NODE_ENV !== 'production' && }
+ {process.env.NODE_ENV !== 'production' && }
({
html: {
@@ -63,6 +64,8 @@ const App = () => {
+
+
);
diff --git a/crabfit-frontend/src/components/CalendarField/CalendarField.tsx b/crabfit-frontend/src/components/CalendarField/CalendarField.tsx
index 3f79424..dea287e 100644
--- a/crabfit-frontend/src/components/CalendarField/CalendarField.tsx
+++ b/crabfit-frontend/src/components/CalendarField/CalendarField.tsx
@@ -2,8 +2,11 @@ import { useState, useEffect, useRef } from 'react';
import dayjs from 'dayjs';
import isToday from 'dayjs/plugin/isToday';
import localeData from 'dayjs/plugin/localeData';
+import updateLocale from 'dayjs/plugin/updateLocale';
import { Button } from 'components';
+import { useSettingsStore } from 'stores';
+
import {
Wrapper,
StyledLabel,
@@ -17,12 +20,13 @@ import {
dayjs.extend(isToday);
dayjs.extend(localeData);
+dayjs.extend(updateLocale);
-const calculateMonth = (month, year) => {
+const calculateMonth = (month, year, weekStart) => {
const date = dayjs().month(month).year(year);
const daysInMonth = date.daysInMonth();
- const daysBefore = date.date(1).day();
- const daysAfter = 6 - date.date(daysInMonth).day();
+ const daysBefore = date.date(1).day() - weekStart;
+ const daysAfter = 6 - date.date(daysInMonth).day() + weekStart;
let dates = [];
let curDate = date.date(1).subtract(daysBefore, 'day');
@@ -49,7 +53,9 @@ const CalendarField = ({
register,
...props
}) => {
- const [dates, setDates] = useState(calculateMonth(dayjs().month(), dayjs().year()));
+ const weekStart = useSettingsStore(state => state.weekStart);
+
+ const [dates, setDates] = useState(calculateMonth(dayjs().month(), dayjs().year(), weekStart));
const [month, setMonth] = useState(dayjs().month());
const [year, setYear] = useState(dayjs().year());
@@ -70,8 +76,14 @@ const CalendarField = ({
};
useEffect(() => {
- setDates(calculateMonth(month, year));
- }, [month, year]);
+ if (weekStart !== dayjs.Ls.en.weekStart) {
+ dayjs.updateLocale('en', {
+ weekStart: weekStart,
+ weekdaysShort: weekStart ? 'Mon_Tue_Wed_Thu_Fri_Sat_Sun'.split('_') : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+ });
+ }
+ setDates(calculateMonth(month, year, weekStart));
+ }, [weekStart, month, year]);
return (
diff --git a/crabfit-frontend/src/components/Settings/Settings.tsx b/crabfit-frontend/src/components/Settings/Settings.tsx
new file mode 100644
index 0000000..a2ac8d2
--- /dev/null
+++ b/crabfit-frontend/src/components/Settings/Settings.tsx
@@ -0,0 +1,57 @@
+import { useState } from 'react';
+import { useTheme } from '@emotion/react';
+
+import { ToggleField } from 'components';
+
+import { useSettingsStore } from 'stores';
+
+import {
+ OpenButton,
+ Modal,
+ Heading,
+ Cover,
+} from './settingsStyle';
+
+const Settings = () => {
+ const theme = useTheme();
+ const store = useSettingsStore();
+ const [isOpen, setIsOpen] = useState(false);
+
+ return (
+ <>
+ setIsOpen(!isOpen)} title="Options"
+ >
+
+
+
+ setIsOpen(false)} />
+
+ Options
+
+ store.setWeekStart(value === 'Monday' ? 1 : 0)}
+ />
+
+ store.setTimeFormat(value)}
+ />
+
+ >
+ );
+};
+
+export default Settings;
diff --git a/crabfit-frontend/src/components/Settings/settingsStyle.ts b/crabfit-frontend/src/components/Settings/settingsStyle.ts
new file mode 100644
index 0000000..2c4fe75
--- /dev/null
+++ b/crabfit-frontend/src/components/Settings/settingsStyle.ts
@@ -0,0 +1,79 @@
+import styled from '@emotion/styled';
+
+export const OpenButton = styled.button`
+ border: 0;
+ background: none;
+ height: 50px;
+ width: 50px;
+ cursor: pointer;
+ color: inherit;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: absolute;
+ top: 12px;
+ right: 12px;
+ z-index: 200;
+ border-radius: 100%;
+ transition: background-color .15s;
+ transition: transform .15s;
+ padding: 0;
+
+ &:focus {
+ outline: 0;
+ }
+ &:focus-visible {
+ background-color: ${props => props.theme.text}22;
+ }
+
+ ${props => props.isOpen && `
+ transform: rotate(-45deg);
+ `}
+`;
+
+export const Cover = styled.div`
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 100;
+ display: none;
+
+ ${props => props.isOpen && `
+ display: block;
+ `}
+`;
+
+export const Modal = styled.div`
+ position: absolute;
+ top: 70px;
+ right: 12px;
+ background-color: ${props => props.theme.background};
+ border: 1px solid ${props => props.theme.primaryBackground};
+ z-index: 150;
+ padding: 10px 18px;
+ border-radius: 3px;
+ width: 250px;
+ box-sizing: border-box;
+ max-width: calc(100% - 20px);
+ box-shadow: 0 3px 6px 0 rgba(0,0,0,.3);
+
+ pointer-events: none;
+ opacity: 0;
+ transform: translateY(-10px);
+ transition: opacity .15s, transform .15s;
+
+ ${props => props.isOpen && `
+ pointer-events: all;
+ opacity: 1;
+ transform: translateY(0);
+ `}
+`;
+
+export const Heading = styled.span`
+ font-size: 1.5rem;
+ display: block;
+ margin: 6px 0;
+ line-height: 1em;
+`;
diff --git a/crabfit-frontend/src/components/TimeRangeField/TimeRangeField.tsx b/crabfit-frontend/src/components/TimeRangeField/TimeRangeField.tsx
index d044b4d..dfb0695 100644
--- a/crabfit-frontend/src/components/TimeRangeField/TimeRangeField.tsx
+++ b/crabfit-frontend/src/components/TimeRangeField/TimeRangeField.tsx
@@ -1,5 +1,7 @@
import { useState, useEffect, useRef } from 'react';
+import { useSettingsStore } from 'stores';
+
import {
Wrapper,
StyledLabel,
@@ -9,33 +11,62 @@ import {
Selected,
} from './timeRangeFieldStyle';
-const times = [
- '12am',
- '1am',
- '2am',
- '3am',
- '4am',
- '5am',
- '6am',
- '7am',
- '8am',
- '9am',
- '10am',
- '11am',
- '12pm',
- '1pm',
- '2pm',
- '3pm',
- '4pm',
- '5pm',
- '6pm',
- '7pm',
- '8pm',
- '9pm',
- '10pm',
- '11pm',
- '12am',
-];
+const times = {
+ '12h': [
+ '12am',
+ '1am',
+ '2am',
+ '3am',
+ '4am',
+ '5am',
+ '6am',
+ '7am',
+ '8am',
+ '9am',
+ '10am',
+ '11am',
+ '12pm',
+ '1pm',
+ '2pm',
+ '3pm',
+ '4pm',
+ '5pm',
+ '6pm',
+ '7pm',
+ '8pm',
+ '9pm',
+ '10pm',
+ '11pm',
+ '12am',
+ ],
+ '24h': [
+ '00',
+ '01',
+ '02',
+ '03',
+ '04',
+ '05',
+ '06',
+ '07',
+ '08',
+ '09',
+ '10',
+ '11',
+ '12',
+ '13',
+ '14',
+ '15',
+ '16',
+ '17',
+ '18',
+ '19',
+ '20',
+ '21',
+ '22',
+ '23',
+ '0',
+ ],
+};
const TimeRangeField = ({
label,
@@ -44,6 +75,8 @@ const TimeRangeField = ({
register,
...props
}) => {
+ const timeFormat = useSettingsStore(state => state.timeFormat);
+
const [start, setStart] = useState(9);
const [end, setEnd] = useState(17);
@@ -90,7 +123,7 @@ const TimeRangeField = ({
{start > end && end ? 0 : start} end={end} />}
{
document.addEventListener('mousemove', handleMouseMove);
isStartMoving.current = true;
@@ -112,7 +145,7 @@ const TimeRangeField = ({
/>
{
document.addEventListener('mousemove', handleMouseMove);
isEndMoving.current = true;
diff --git a/crabfit-frontend/src/components/ToggleField/ToggleField.tsx b/crabfit-frontend/src/components/ToggleField/ToggleField.tsx
new file mode 100644
index 0000000..83aa3b7
--- /dev/null
+++ b/crabfit-frontend/src/components/ToggleField/ToggleField.tsx
@@ -0,0 +1,40 @@
+import {
+ Wrapper,
+ ToggleContainer,
+ StyledLabel,
+ Option,
+ HiddenInput,
+ LabelButton,
+} from './toggleFieldStyle';
+
+const ToggleField = ({
+ label,
+ id,
+ name,
+ options = [],
+ value,
+ onChange,
+ ...props
+}) => (
+
+ {label && {label}}
+
+
+ {options.map(option =>
+
+ )}
+
+
+);
+
+export default ToggleField;
diff --git a/crabfit-frontend/src/components/ToggleField/toggleFieldStyle.ts b/crabfit-frontend/src/components/ToggleField/toggleFieldStyle.ts
new file mode 100644
index 0000000..a1e91aa
--- /dev/null
+++ b/crabfit-frontend/src/components/ToggleField/toggleFieldStyle.ts
@@ -0,0 +1,43 @@
+import styled from '@emotion/styled';
+
+export const Wrapper = styled.div`
+ margin: 10px 0;
+`;
+
+export const ToggleContainer = styled.div`
+ display: flex;
+ border: 1px solid ${props => props.theme.primary};
+ border-radius: 3px;
+ overflow: hidden;
+`;
+
+export const StyledLabel = styled.label`
+ display: block;
+ padding-bottom: 4px;
+ font-size: .9rem;
+`;
+
+export const Option = styled.div`
+ flex: 1;
+`;
+
+export const HiddenInput = styled.input`
+ height: 0;
+ width: 0;
+ position: absolute;
+ right: -1000px;
+ top: 0;
+
+ &:checked + label {
+ color: ${props => props.theme.background};
+ background-color: ${props => props.theme.primary};
+ }
+`;
+
+export const LabelButton = styled.label`
+ padding: 6px;
+ display: block;
+ text-align: center;
+ cursor: pointer;
+ user-select: none;
+`;
diff --git a/crabfit-frontend/src/components/index.ts b/crabfit-frontend/src/components/index.ts
index 3ce1ec4..2cff948 100644
--- a/crabfit-frontend/src/components/index.ts
+++ b/crabfit-frontend/src/components/index.ts
@@ -2,6 +2,7 @@ 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 ToggleField } from './ToggleField/ToggleField';
export { default as Button } from './Button/Button';
export { default as Legend } from './Legend/Legend';
@@ -11,3 +12,4 @@ export { default as Error } from './Error/Error';
export { default as Center } from './Center/Center';
export { default as Donate } from './Donate/Donate';
+export { default as Settings } from './Settings/Settings';
diff --git a/crabfit-frontend/src/pages/Home/Home.tsx b/crabfit-frontend/src/pages/Home/Home.tsx
index 97aea75..4e718a3 100644
--- a/crabfit-frontend/src/pages/Home/Home.tsx
+++ b/crabfit-frontend/src/pages/Home/Home.tsx
@@ -136,7 +136,7 @@ const Home = () => {
- Create a
+ CREATE A
CRAB FIT
About / Donate
diff --git a/crabfit-frontend/src/stores/index.ts b/crabfit-frontend/src/stores/index.ts
new file mode 100644
index 0000000..7eea586
--- /dev/null
+++ b/crabfit-frontend/src/stores/index.ts
@@ -0,0 +1,13 @@
+import create from 'zustand';
+import { persist } from 'zustand/middleware';
+
+export const useSettingsStore = create(persist(
+ set => ({
+ weekStart: 0,
+ timeFormat: '12h',
+
+ setWeekStart: weekStart => set({ weekStart }),
+ setTimeFormat: timeFormat => set({ timeFormat }),
+ }),
+ { name: 'crabfit-settings' },
+));