diff --git a/apps/web/components.json b/apps/web/components.json new file mode 100644 index 0000000..f9a8534 --- /dev/null +++ b/apps/web/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/App.css", + "baseColor": "neutral", + "cssVariables": false + }, + "aliases": { + "components": "./src/components", + "utils": "./src/lib/utils", + "ui": "./src/components/ui" + } +} diff --git a/apps/web/src/App.css b/apps/web/src/App.css index 8363bb1..2e17660 100644 --- a/apps/web/src/App.css +++ b/apps/web/src/App.css @@ -2,6 +2,86 @@ @tailwind components; @tailwind utilities; +@layer base { + html, + body, + #root { + min-height: 100%; + } + + body { + margin: 0; + } + + ::selection { + background: #0a0a0a; + color: #fff; + } +} + +.monochrome-shell { + font-family: 'Avenir Next', 'Century Gothic', sans-serif; +} + +.monochrome-shell > div > section, +.monochrome-shell > div > main { + animation: focus-rise 420ms ease-out both; +} + +.monochrome-shell > div > section:nth-of-type(2) { + animation-delay: 80ms; +} + +.monochrome-shell > div > main { + animation-delay: 140ms; +} + +.monochrome-shell header .dropdown > .btn, +.monochrome-shell header .btn-circle { + min-height: 2.25rem; + height: 2.25rem; + width: 2.25rem; + border-radius: 0; + background: transparent; + color: #0a0a0a; +} + +.monochrome-shell header .dropdown-content { + border: 1px solid #171717; + border-radius: 0; + background: #fff; + color: #171717; +} + +.monochrome-log-editor { + background-image: repeating-linear-gradient( + to bottom, + transparent 0, + transparent 27px, + rgb(0 0 0 / 7%) 27px, + rgb(0 0 0 / 7%) 28px + ); + background-position-y: 15px; +} + +@keyframes focus-rise { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@media (prefers-reduced-motion: reduce) { + .monochrome-shell > div > section, + .monochrome-shell > div > main { + animation: none; + } +} + @keyframes shake { 0% { transform: translateX(0); diff --git a/apps/web/src/components/charts/AvailableRestTimeChart/chart.tsx b/apps/web/src/components/charts/AvailableRestTimeChart/chart.tsx index bf4e2dd..8d8915e 100644 --- a/apps/web/src/components/charts/AvailableRestTimeChart/chart.tsx +++ b/apps/web/src/components/charts/AvailableRestTimeChart/chart.tsx @@ -2,6 +2,7 @@ import { Area, AreaChart, CartesianGrid, + ReferenceLine, ResponsiveContainer, Tooltip, XAxis, @@ -31,46 +32,78 @@ export const AvailableRestTimeChart = ({ const gradientId = 'availableRestTimeSplitColor'; + if (data.length < 2) { + return ( +
+ 기록을 두 개 이상 추가하면 시간 잔고가 표시됩니다 +
+ ); + } + return ( - + - + `${value}`} /> [`${value}분`, '초과 휴식']} + formatter={(value: number | string) => [`${value}분`, '소비 − 생산']} + contentStyle={{ + border: '1px solid #171717', + borderRadius: 0, + boxShadow: 'none', + fontSize: 11, + }} /> + - - + + {getPoints(data)} diff --git a/apps/web/src/components/charts/AvailableRestTimeChart/points.tsx b/apps/web/src/components/charts/AvailableRestTimeChart/points.tsx index 0016284..05290f2 100644 --- a/apps/web/src/components/charts/AvailableRestTimeChart/points.tsx +++ b/apps/web/src/components/charts/AvailableRestTimeChart/points.tsx @@ -11,7 +11,7 @@ export const getPoints = (data: ChartDataPoint[]) => { const points: ReactElement[] = []; if (highPoint) { - const color = highPoint.need >= 0 ? 'red' : 'green'; + const color = highPoint.need >= 0 ? '#171717' : '#737373'; points.push( { } if (lowPoint) { - const color = lowPoint.need >= 0 ? 'red' : 'green'; + const color = lowPoint.need >= 0 ? '#171717' : '#737373'; points.push( = 0 ? 'red' : 'green'; + const color = currPoint.need >= 0 ? '#171717' : '#737373'; const position = currPoint.need >= 0 ? 'top' : 'bottom'; return { point: currPoint, shouldShow, color, position }; diff --git a/apps/web/src/components/charts/DayRatioBar.tsx b/apps/web/src/components/charts/DayRatioBar.tsx index 4812d71..807f43d 100644 --- a/apps/web/src/components/charts/DayRatioBar.tsx +++ b/apps/web/src/components/charts/DayRatioBar.tsx @@ -8,7 +8,7 @@ export const DayRatioBar = ({ logs }: { logs: Log[] }) => { if (isEmpty || totalDuration <= 0) { return ( -
+
); } @@ -36,14 +36,14 @@ export const DayRatioBar = ({ logs }: { logs: Log[] }) => { return (
{blocks.map((block, idx) => (
{ + if (data.length < 2) { + return ( +
+ 기록을 두 개 이상 추가하면 페이스가 표시됩니다 +
+ ); + } + return ( - + - + - - o.pace} unit="min/h" - stroke="darkgreen" - fill="green" + stroke="#171717" + strokeWidth={1.5} + fill="#d4d4d4" /> diff --git a/apps/web/src/components/days/DayNavigator.tsx b/apps/web/src/components/days/DayNavigator.tsx index ecb1d13..23bcc39 100644 --- a/apps/web/src/components/days/DayNavigator.tsx +++ b/apps/web/src/components/days/DayNavigator.tsx @@ -1,6 +1,7 @@ import { useDispatch } from 'react-redux'; import { goToNextDate, goToPrevDate, goToToday } from '../../store/logs'; +import { Button } from '../ui/button'; const PREV_DAY_BUTTON_TEXT = '←'; const TODAY_BUTTON_TEXT = '오늘'; @@ -13,19 +14,33 @@ export const DayNavigator = () => { const handleTomorrowButton = () => dispatch(goToNextDate()); return ( -
- - + - + {TODAY_BUTTON_TEXT} + +
); }; diff --git a/apps/web/src/components/texts/ProductiveToggle.tsx b/apps/web/src/components/texts/ProductiveToggle.tsx index b1c9016..72cbf89 100644 --- a/apps/web/src/components/texts/ProductiveToggle.tsx +++ b/apps/web/src/components/texts/ProductiveToggle.tsx @@ -14,10 +14,10 @@ export const ProductiveToggle = ({ onKeyDown, checkboxRef, }: ProductiveToggleProps) => ( -