diff --git a/crabfit-frontend/.gcloudignore b/crabfit-frontend/.gcloudignore deleted file mode 100644 index d3a7b16..0000000 --- a/crabfit-frontend/.gcloudignore +++ /dev/null @@ -1,6 +0,0 @@ -.gcloudignore - -.git -.gitignore - -node_modules/ diff --git a/crabfit-frontend/app.yaml b/crabfit-frontend/example-app.yaml similarity index 100% rename from crabfit-frontend/app.yaml rename to crabfit-frontend/example-app.yaml diff --git a/crabfit-frontend/jsconfig.json b/crabfit-frontend/jsconfig.json deleted file mode 100644 index 5875dc5..0000000 --- a/crabfit-frontend/jsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": "src" - }, - "include": ["src"] -} diff --git a/crabfit-frontend/package.json b/crabfit-frontend/package.json index 072dd0d..90739d6 100644 --- a/crabfit-frontend/package.json +++ b/crabfit-frontend/package.json @@ -8,10 +8,17 @@ "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", + "@types/jest": "^26.0.20", + "@types/node": "^14.14.31", + "@types/react": "^17.0.2", + "@types/react-dom": "^17.0.1", + "dayjs": "^1.10.4", "react": "^17.0.1", "react-dom": "^17.0.1", + "react-hook-form": "^6.15.4", "react-router-dom": "^5.2.0", "react-scripts": "4.0.3", + "typescript": "^4.2.2", "web-vitals": "^1.0.1", "zustand": "^3.3.2" }, diff --git a/crabfit-frontend/public/fonts/karla-italic-variable.ttf b/crabfit-frontend/public/fonts/karla-italic-variable.ttf new file mode 100644 index 0000000..aecc468 Binary files /dev/null and b/crabfit-frontend/public/fonts/karla-italic-variable.ttf differ diff --git a/crabfit-frontend/public/fonts/karla-variable.ttf b/crabfit-frontend/public/fonts/karla-variable.ttf new file mode 100644 index 0000000..172b500 Binary files /dev/null and b/crabfit-frontend/public/fonts/karla-variable.ttf differ diff --git a/crabfit-frontend/public/index.css b/crabfit-frontend/public/index.css new file mode 100644 index 0000000..749c6cd --- /dev/null +++ b/crabfit-frontend/public/index.css @@ -0,0 +1,5 @@ +@font-face { + font-family: Karla; + src: url('fonts/karla-variable.ttf') format('truetype'); + font-weight: 1 999; +} diff --git a/crabfit-frontend/public/index.html b/crabfit-frontend/public/index.html index 523055d..11686e0 100644 --- a/crabfit-frontend/public/index.html +++ b/crabfit-frontend/public/index.html @@ -12,6 +12,8 @@ + + Crab Fit diff --git a/crabfit-frontend/src/App.js b/crabfit-frontend/src/App.js deleted file mode 100644 index 06a90b3..0000000 --- a/crabfit-frontend/src/App.js +++ /dev/null @@ -1,25 +0,0 @@ -import { - BrowserRouter, - Switch, - Route, - Redirect, - useLocation, -} from 'react-router-dom'; - -import { - Home, - Event, -} from 'pages'; - -const App = () => { - return ( - - - - - - - ); -} - -export default App; diff --git a/crabfit-frontend/src/App.test.js b/crabfit-frontend/src/App.test.ts similarity index 100% rename from crabfit-frontend/src/App.test.js rename to crabfit-frontend/src/App.test.ts diff --git a/crabfit-frontend/src/App.tsx b/crabfit-frontend/src/App.tsx new file mode 100644 index 0000000..c7c7be2 --- /dev/null +++ b/crabfit-frontend/src/App.tsx @@ -0,0 +1,49 @@ +import { useState } from 'react'; +import { + BrowserRouter, + Switch, + Route, +} from 'react-router-dom'; +import { ThemeProvider, Global } from '@emotion/react'; + +import { + Home, + Event, +} from 'pages'; + +import theme from 'theme'; + +const App = () => { + const darkQuery = window.matchMedia('(prefers-color-scheme: dark)'); + const [isDark, setIsDark] = useState(darkQuery.matches); + + darkQuery.addListener(e => setIsDark(e.matches)); + + return ( + + + + ({ + body: { + backgroundColor: theme.background, + color: theme.text, + fontFamily: `'Karla', sans-serif`, + fontWeight: 600, + margin: 0, + }, + a: { + color: theme.primary, + }, + })} + /> + + + + + + + ); +} + +export default App; diff --git a/crabfit-frontend/src/components/Button/Button.tsx b/crabfit-frontend/src/components/Button/Button.tsx new file mode 100644 index 0000000..5e90449 --- /dev/null +++ b/crabfit-frontend/src/components/Button/Button.tsx @@ -0,0 +1,14 @@ +import { Wrapper, Top, Bottom } from './buttonStyle'; + +const Button = ({ + buttonHeight, + buttonWidth, + ...props +}) => ( + + + + +); + +export default Button; diff --git a/crabfit-frontend/src/components/Button/buttonStyle.ts b/crabfit-frontend/src/components/Button/buttonStyle.ts new file mode 100644 index 0000000..b46842e --- /dev/null +++ b/crabfit-frontend/src/components/Button/buttonStyle.ts @@ -0,0 +1,47 @@ +import styled from '@emotion/styled'; + +export const Wrapper = styled.div` + display: inline-block; + position: relative; + + --btn-height: ${props => props.buttonHeight || '40px'}; + --btn-width: ${props => props.buttonWidth || '100px'}; + + height: var(--btn-height); + width: var(--btn-width); +`; + +export const Top = styled.button` + border: 0; + cursor: pointer; + font: inherit; + box-sizing: border-box; + background: ${props => props.theme.primary}; + color: #FFF; + font-weight: 600; + text-shadow: 0 -1.5px .5px ${props => props.theme.primaryDark}; + padding: ${props => props.padding || '10px 14px'}; + border-radius: 3px; + height: var(--btn-height); + width: var(--btn-width); + position: absolute; + top: -4px; + user-select: none; + transition: top .15s; + outline: none; + + &:active { + top: 0; + } + &:focus-visible { + filter: brightness(1.2); + } +`; + +export const Bottom = styled.div` + box-sizing: border-box; + background: ${props => props.theme.primaryDark}; + border-radius: 3px; + height: var(--btn-height); + width: var(--btn-width); +`; diff --git a/crabfit-frontend/src/components/CalendarField/CalendarField.tsx b/crabfit-frontend/src/components/CalendarField/CalendarField.tsx new file mode 100644 index 0000000..8636276 --- /dev/null +++ b/crabfit-frontend/src/components/CalendarField/CalendarField.tsx @@ -0,0 +1,192 @@ +import { useState, useEffect, useRef } from 'react'; +import dayjs from 'dayjs'; +import isToday from 'dayjs/plugin/isToday'; + +import { Button } from 'components'; +import { + Wrapper, + StyledLabel, + StyledSubLabel, + CalendarHeader, + CalendarBody, + Date, + Day, +} from './calendarFieldStyle'; + +dayjs.extend(isToday); + +const days = [ + 'Sun', + 'Mon', + 'Tue', + 'Wed', + 'Thu', + 'Fri', + 'Sat', +]; + +const months = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', +]; + +const calculateMonth = (month, year) => { + const date = dayjs().month(month).year(year); + const daysInMonth = date.daysInMonth(); + const daysBefore = date.date(1).day(); + const daysAfter = 6 - date.date(daysInMonth).day(); + + let dates = []; + let curDate = date.date(1).subtract(daysBefore, 'day'); + let y = 0; + let x = 0; + for (let i = 0; i < daysBefore + daysInMonth + daysAfter; i++) { + if (x === 0) dates[y] = []; + dates[y][x] = curDate.clone(); + curDate = curDate.add(1, 'day'); + x++; + if (x > 6) { + x = 0; + y++; + } + } + + return dates; +}; + +const CalendarField = ({ + label, + subLabel, + id, + register, + ...props +}) => { + const [dates, setDates] = useState(calculateMonth(dayjs().month(), dayjs().year())); + const [month, setMonth] = useState(dayjs().month()); + const [year, setYear] = useState(dayjs().year()); + + const [selectedDates, setSelectedDates] = useState([]); + const [selectingDates, _setSelectingDates] = useState([]); + const staticSelectingDates = useRef([]); + const setSelectingDates = newDates => { + staticSelectingDates.current = newDates; + _setSelectingDates(newDates); + }; + + const startPos = useRef({}); + const staticMode = useRef(null); + const [mode, _setMode] = useState(staticMode.current); + const setMode = newMode => { + staticMode.current = newMode; + _setMode(newMode); + }; + + useEffect(() => { + setDates(calculateMonth(month, year)); + }, [month, year]); + + return ( + + {label && {label}} + {subLabel && {subLabel}} + + + + + {months[month]} {year} + + + + + {days.map((name, i) => + {name} + )} + {dates.length > 0 && dates.map((dateRow, y) => + dateRow.map((date, x) => + { + startPos.current = {x, y}; + setMode(selectedDates.includes(date.format('DDMMYYYY')) ? 'remove' : 'add'); + setSelectingDates([date]); + + document.addEventListener('mouseup', () => { + if (staticMode.current === 'add') { + setSelectedDates([...selectedDates, ...staticSelectingDates.current.map(d => d.format('DDMMYYYY'))]); + } else if (staticMode.current === 'remove') { + const toRemove = staticSelectingDates.current.map(d => d.format('DDMMYYYY')); + setSelectedDates(selectedDates.filter(d => !toRemove.includes(d))); + } + setMode(null); + }, { once: true }); + }} + onMouseEnter={() => { + if (staticMode.current) { + let found = []; + for (let cy = Math.min(startPos.current.y, y); cy < Math.max(startPos.current.y, y)+1; cy++) { + for (let cx = Math.min(startPos.current.x, x); cx < Math.max(startPos.current.x, x)+1; cx++) { + found.push({y: cy, x: cx}); + } + } + setSelectingDates(found.map(d => dates[d.y][d.x])); + } + }} + >{date.date()} + ) + )} + + + ); +}; + +export default CalendarField; diff --git a/crabfit-frontend/src/components/CalendarField/calendarFieldStyle.ts b/crabfit-frontend/src/components/CalendarField/calendarFieldStyle.ts new file mode 100644 index 0000000..32d3cbc --- /dev/null +++ b/crabfit-frontend/src/components/CalendarField/calendarFieldStyle.ts @@ -0,0 +1,73 @@ +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 CalendarHeader = styled.div` + display: flex; + align-items: center; + justify-content: space-between; + user-select: none; + padding: 6px 0; + font-size: 1.2em; + font-weight: bold; +`; + +export const CalendarBody = styled.div` + display: grid; + grid-template-columns: repeat(7, 1fr); + grid-gap: 2px; +`; + +export const Date = styled.div` + background-color: ${props => props.theme.primary}22; + border: 1px solid ${props => props.theme.primaryLight}; + display: flex; + align-items: center; + justify-content: center; + padding: 10px 0; + border-radius: 3px; + user-select: none; + + ${props => props.otherMonth && ` + color: ${props.theme.primaryLight}; + `} + ${props => props.isToday && ` + font-weight: 900; + color: ${props.theme.primaryDark}; + `} + ${props => (props.selected || (props.mode === 'add' && props.selecting)) && ` + color: ${props.otherMonth ? 'rgba(255,255,255,.5)' : '#FFF'}; + background-color: ${props.theme.primary}; + border-color: ${props.theme.primary}; + `} + ${props => props.mode === 'remove' && props.selecting && ` + background-color: ${props.theme.primary}22; + border: 1px solid ${props.theme.primaryLight}; + color: ${props.isToday ? props.theme.primaryDark : (props.otherMonth ? props.theme.primaryLight : 'inherit')}; + `} +`; + +export const Day = styled.div` + display: flex; + align-items: center; + justify-content: center; + padding: 3px 10px; + font-weight: bold; + user-select: none; + opacity: .7; +`; diff --git a/crabfit-frontend/src/components/TextField/TextField.tsx b/crabfit-frontend/src/components/TextField/TextField.tsx new file mode 100644 index 0000000..0a91061 --- /dev/null +++ b/crabfit-frontend/src/components/TextField/TextField.tsx @@ -0,0 +1,22 @@ +import { + Wrapper, + StyledLabel, + StyledSubLabel, + StyledInput, +} from './textFieldStyle'; + +const TextField = ({ + label, + subLabel, + id, + register, + ...props +}) => ( + + {label && {label}} + {subLabel && {subLabel}} + + +); + +export default TextField; diff --git a/crabfit-frontend/src/components/TextField/textFieldStyle.ts b/crabfit-frontend/src/components/TextField/textFieldStyle.ts new file mode 100644 index 0000000..ac37df0 --- /dev/null +++ b/crabfit-frontend/src/components/TextField/textFieldStyle.ts @@ -0,0 +1,38 @@ +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 StyledInput = styled.input` + width: 100%; + box-sizing: border-box; + font: inherit; + background: ${props => props.theme.primary}22; + 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; + font-size: 18px; + 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}; + } +`; diff --git a/crabfit-frontend/src/components/TimeRangeField/TimeRangeField.tsx b/crabfit-frontend/src/components/TimeRangeField/TimeRangeField.tsx new file mode 100644 index 0000000..fb5fce3 --- /dev/null +++ b/crabfit-frontend/src/components/TimeRangeField/TimeRangeField.tsx @@ -0,0 +1,139 @@ +import { useState, useEffect, useRef } from 'react'; + +import { + Wrapper, + StyledLabel, + StyledSubLabel, + Range, + Handle, + 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 TimeRangeField = ({ + label, + subLabel, + id, + register, + ...props +}) => { + const [start, setStart] = useState(9); + const [end, setEnd] = useState(17); + + const isStartMoving = useRef(false); + const isEndMoving = useRef(false); + const rangeRef = useRef(); + const rangeRect = useRef(); + + useEffect(() => { + if (rangeRef.current) { + rangeRect.current = rangeRef.current.getBoundingClientRect(); + } + }, [rangeRef]); + + const handleMouseMove = e => { + if (isStartMoving.current || isEndMoving.current) { + let step = Math.round(((e.pageX - rangeRect.current.left) / rangeRect.current.width) * 24); + if (step < 0) step = 0; + if (step > 24) step = 24; + step = Math.abs(step); + + if (isStartMoving.current) { + setStart(step); + } else if (isEndMoving.current) { + setEnd(step); + } + } + }; + + return ( + + {label && {label}} + {subLabel && {subLabel}} + end ? {start: end, end: start} : {start, end})} + {...props} + /> + + + end ? end : start} end={start > end ? start : end} /> + { + document.addEventListener('mousemove', handleMouseMove); + isStartMoving.current = true; + + document.addEventListener('mouseup', () => { + isStartMoving.current = false; + document.removeEventListener('mousemove', handleMouseMove); + }, { once: true }); + }} + onTouchMove={(e) => { + const touch = e.targetTouches[0]; + + let step = Math.round(((touch.pageX - rangeRect.current.left) / rangeRect.current.width) * 24); + if (step < 0) step = 0; + if (step > 24) step = 24; + step = Math.abs(step); + setStart(step); + }} + /> + { + document.addEventListener('mousemove', handleMouseMove); + isEndMoving.current = true; + + document.addEventListener('mouseup', () => { + isEndMoving.current = false; + document.removeEventListener('mousemove', handleMouseMove); + }, { once: true }); + }} + onTouchMove={(e) => { + const touch = e.targetTouches[0]; + + let step = Math.round(((touch.pageX - rangeRect.current.left) / rangeRect.current.width) * 24); + if (step < 0) step = 0; + if (step > 24) step = 24; + step = Math.abs(step); + setEnd(step); + }} + /> + + + ); +}; + +export default TimeRangeField; diff --git a/crabfit-frontend/src/components/TimeRangeField/timeRangeFieldStyle.ts b/crabfit-frontend/src/components/TimeRangeField/timeRangeFieldStyle.ts new file mode 100644 index 0000000..ddaefb3 --- /dev/null +++ b/crabfit-frontend/src/components/TimeRangeField/timeRangeFieldStyle.ts @@ -0,0 +1,72 @@ +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 Range = styled.div` + user-select: none; + background-color: ${props => props.theme.primary}22; + border: 1px solid ${props => props.theme.primaryLight}; + border-radius: 3px; + height: 50px; + position: relative; + margin: 38px 6px 18px; +`; + +export const Handle = styled.div` + height: calc(100% + 20px); + width: 20px; + border: 1px solid ${props => props.theme.primary}; + background-color: ${props => props.theme.primaryLight}; + border-radius: 3px; + position: absolute; + top: -10px; + left: calc(${props => props.value * 4.1666666666666666}% - 11px); + cursor: ew-resize; + + &:after { + content: '|||'; + font-size: 8px; + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + color: ${props => props.theme.primaryDark}; + } + + &:before { + content: '${props => props.label}'; + position: absolute; + bottom: calc(100% + 8px); + text-align: center; + left: 50%; + transform: translateX(-50%); + } +`; + +export const Selected = styled.div` + position: absolute; + height: 100%; + left: ${props => props.start * 4.1666666666666666}%; + right: calc(100% - ${props => props.end * 4.1666666666666666}%); + top: 0; + background-color: ${props => props.theme.primary}; +`; diff --git a/crabfit-frontend/src/components/index.ts b/crabfit-frontend/src/components/index.ts new file mode 100644 index 0000000..0146924 --- /dev/null +++ b/crabfit-frontend/src/components/index.ts @@ -0,0 +1,4 @@ +export { default as TextField } from './TextField/TextField'; +export { default as CalendarField } from './CalendarField/CalendarField'; +export { default as TimeRangeField } from './TimeRangeField/TimeRangeField'; +export { default as Button } from './Button/Button'; diff --git a/crabfit-frontend/src/index.css b/crabfit-frontend/src/index.css deleted file mode 100644 index ec2585e..0000000 --- a/crabfit-frontend/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/crabfit-frontend/src/index.js b/crabfit-frontend/src/index.tsx similarity index 95% rename from crabfit-frontend/src/index.js rename to crabfit-frontend/src/index.tsx index ef2edf8..7998135 100644 --- a/crabfit-frontend/src/index.js +++ b/crabfit-frontend/src/index.tsx @@ -1,6 +1,5 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; diff --git a/crabfit-frontend/src/pages/Event/Event.js b/crabfit-frontend/src/pages/Event/Event.tsx similarity index 100% rename from crabfit-frontend/src/pages/Event/Event.js rename to crabfit-frontend/src/pages/Event/Event.tsx diff --git a/crabfit-frontend/src/pages/Home/Home.js b/crabfit-frontend/src/pages/Home/Home.js deleted file mode 100644 index c60398a..0000000 --- a/crabfit-frontend/src/pages/Home/Home.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Link } from 'react-router-dom'; - -const Home = () => { - return ( -
-
Home
- Test -
- ); -}; - -export default Home; diff --git a/crabfit-frontend/src/pages/Home/Home.tsx b/crabfit-frontend/src/pages/Home/Home.tsx new file mode 100644 index 0000000..b57eda4 --- /dev/null +++ b/crabfit-frontend/src/pages/Home/Home.tsx @@ -0,0 +1,59 @@ +import { useForm } from 'react-hook-form'; + +import { + TextField, + CalendarField, + TimeRangeField, + Button, +} from 'components'; + +import { + StyledMain, + CreateForm, + TitleSmall, + TitleLarge, +} from './homeStyle'; + +const Home = () => { + const { register, handleSubmit } = useForm(); + + const onSubmit = data => console.log('submit', data); + + return ( + + Create a + CRAB FIT + + + + + + + + + + + + ); +}; + +export default Home; diff --git a/crabfit-frontend/src/pages/Home/homeStyle.ts b/crabfit-frontend/src/pages/Home/homeStyle.ts new file mode 100644 index 0000000..c9a75be --- /dev/null +++ b/crabfit-frontend/src/pages/Home/homeStyle.ts @@ -0,0 +1,32 @@ +import styled from '@emotion/styled'; + +export const StyledMain = styled.main` + width: 600px; + margin: 30px auto; + max-width: calc(100% - 30px); +`; + +export const CreateForm = styled.form` +`; + +export const TitleSmall = styled.span` + display: block; + margin: 20px 0 0; + font-size: 3rem; + text-align: center; + font-family: 'CF Samurai Bob'; + font-weight: 400; + color: ${props => props.theme.primaryDark}; + line-height: 1em; +`; + +export const TitleLarge = styled.h1` + margin: 0 0 40px; + font-size: 4rem; + text-align: center; + color: ${props => props.theme.primary}; + font-family: 'Molot'; + font-weight: 400; + text-shadow: 0 4px 0 ${props => props.theme.primaryDark}; + line-height: 1em; +`; diff --git a/crabfit-frontend/src/pages/index.js b/crabfit-frontend/src/pages/index.ts similarity index 100% rename from crabfit-frontend/src/pages/index.js rename to crabfit-frontend/src/pages/index.ts diff --git a/crabfit-frontend/src/react-app-env.d.ts b/crabfit-frontend/src/react-app-env.d.ts new file mode 100644 index 0000000..6431bc5 --- /dev/null +++ b/crabfit-frontend/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/crabfit-frontend/src/res/create_banner.svg b/crabfit-frontend/src/res/create_banner.svg new file mode 100644 index 0000000..c4c1aff --- /dev/null +++ b/crabfit-frontend/src/res/create_banner.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/crabfit-frontend/src/theme/index.ts b/crabfit-frontend/src/theme/index.ts new file mode 100644 index 0000000..c6063e2 --- /dev/null +++ b/crabfit-frontend/src/theme/index.ts @@ -0,0 +1,20 @@ +const theme = { + light: { + mode: 'light', + background: '#FFFFFF', + text: '#000000', + primary: '#F79E00', + primaryDark: '#F48600', + primaryLight: '#F4BB60', + }, + dark: { + mode: 'dark', + background: '#111', + text: '#DDDDDD', + primary: '#F79E00', + primaryDark: '#F4BB60', + primaryLight: '#F48600', + }, +}; + +export default theme; diff --git a/crabfit-frontend/tsconfig.json b/crabfit-frontend/tsconfig.json new file mode 100644 index 0000000..425d574 --- /dev/null +++ b/crabfit-frontend/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "baseUrl": "src" + }, + "include": [ + "src" + ] +} diff --git a/crabfit-frontend/yarn.lock b/crabfit-frontend/yarn.lock index 4ab31ff..d1ce37f 100644 --- a/crabfit-frontend/yarn.lock +++ b/crabfit-frontend/yarn.lock @@ -1834,7 +1834,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@*": +"@types/jest@*", "@types/jest@^26.0.20": version "26.0.20" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.20.tgz#cd2f2702ecf69e86b586e1f5223a60e454056307" integrity sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA== @@ -1857,7 +1857,7 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== -"@types/node@*": +"@types/node@*", "@types/node@^14.14.31": version "14.14.31" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.31.tgz#72286bd33d137aa0d152d47ec7c1762563d34055" integrity sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g== @@ -1877,11 +1877,31 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.2.1.tgz#374e31645d58cb18a07b3ecd8e9dede4deb2cccd" integrity sha512-DxZZbyMAM9GWEzXL+BMZROWz9oo6A9EilwwOMET2UVu2uZTqMWS5S69KVtuVKaRjCUpcrOXRalet86/OpG4kqw== +"@types/prop-types@*": + version "15.7.3" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" + integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== + "@types/q@^1.5.1": version "1.5.4" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug== +"@types/react-dom@^17.0.1": + version "17.0.1" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.1.tgz#d92d77d020bfb083e07cc8e0ac9f933599a4d56a" + integrity sha512-yIVyopxQb8IDZ7SOHeTovurFq+fXiPICa+GV3gp0Xedsl+MwQlMLKmvrnEjFbQxjliH5YVAEWFh975eVNmKj7Q== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^17.0.2": + version "17.0.2" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.2.tgz#3de24c4efef902dd9795a49c75f760cbe4f7a5a8" + integrity sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + "@types/resolve@0.0.8": version "0.0.8" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" @@ -3951,6 +3971,11 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +dayjs@^1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.4.tgz#8e544a9b8683f61783f570980a8a80eaf54ab1e2" + integrity sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw== + debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -9106,6 +9131,11 @@ react-error-overlay@^6.0.9: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew== +react-hook-form@^6.15.4: + version "6.15.4" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-6.15.4.tgz#328003e1ccc096cd158899ffe7e3b33735a9b024" + integrity sha512-K+Sw33DtTMengs8OdqFJI3glzNl1wBzSefD/ksQw/hJf9CnOHQAU6qy82eOrh0IRNt2G53sjr7qnnw1JDjvx1w== + react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -10828,6 +10858,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.2.tgz#1450f020618f872db0ea17317d16d8da8ddb8c4c" + integrity sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ== + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"