diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 431efeb5..0232927b 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -13,7 +13,7 @@
"styled-components": "^6.0.3"
},
"devDependencies": {
- "@types/react": "^18.2.14",
+ "@types/react": "^18.2.15",
"@types/react-dom": "^18.2.6",
"@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.61.0",
@@ -2439,9 +2439,9 @@
"dev": true
},
"node_modules/@types/react": {
- "version": "18.2.14",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.14.tgz",
- "integrity": "sha512-A0zjq+QN/O0Kpe30hA1GidzyFjatVvrpIvWLxD+xv67Vt91TWWgco9IvrJBkeyHm1trGaFS/FSGqPlhyeZRm0g==",
+ "version": "18.2.15",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.15.tgz",
+ "integrity": "sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA==",
"dev": true,
"dependencies": {
"@types/prop-types": "*",
diff --git a/frontend/package.json b/frontend/package.json
index 7ab39954..ba728c64 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -15,7 +15,7 @@
"styled-components": "^6.0.3"
},
"devDependencies": {
- "@types/react": "^18.2.14",
+ "@types/react": "^18.2.15",
"@types/react-dom": "^18.2.6",
"@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.61.0",
diff --git a/frontend/public/close-danger.svg b/frontend/public/close-danger.svg
deleted file mode 100644
index 7cf85cf5..00000000
--- a/frontend/public/close-danger.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/frontend/public/close.svg b/frontend/public/close.svg
deleted file mode 100644
index ca2c5a76..00000000
--- a/frontend/public/close.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/frontend/public/edit.svg b/frontend/public/edit.svg
deleted file mode 100644
index b203a52a..00000000
--- a/frontend/public/edit.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/frontend/public/log.svg b/frontend/public/log.svg
deleted file mode 100644
index 27b83ecc..00000000
--- a/frontend/public/log.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/frontend/public/plus.svg b/frontend/public/plus.svg
deleted file mode 100644
index 532a8a18..00000000
--- a/frontend/public/plus.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index e58f464b..0947a6d4 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,72 +1,27 @@
-import { useState, useRef } from "react";
-import styled, { ThemeProvider } from "styled-components";
-import Board from "./components/Board";
-import HistoryBtn from "./components/HistoryBtn";
-import Logo from "./components/Logo";
-import Modal from "./components/Modal";
-import Header from "./components/landmark/Header";
-import Main from "./components/landmark/Main";
-import CommonStyle from "./styles/CommonStyle";
-import { theme } from "./theme";
-import { TTheme } from "./types/theme";
-
-export default function App() {
- const [isUserLogOpened, setIsUserLogOpened] = useState(false);
- const [message, setMessage] = useState("");
- const callbackTemp = useRef<() => void | undefined>();
-
- function clearMessage() {
- setMessage("");
- }
-
- function dummyAction() {
- clearMessage();
- if (callbackTemp.current) {
- callbackTemp.current();
- }
- }
-
- function openConfirmModal(content: string, callback: () => void) {
- setMessage(content);
- callbackTemp.current = callback;
- }
-
- function toggleActiveUserLog() {
- setIsUserLogOpened((bool) => !bool);
+import { useState } from "react";
+import Header from "./components/Header";
+import Main from "./components/main/Main";
+import Alert from "./components/common/Alert";
+import Container from "./styles/Container";
+import Aside from "./components/aside/Aside";
+
+const App: React.FC = () => {
+ const [isHistoryOpen, setIsHistoryOpen] = useState(false);
+
+ function toggleHistory() {
+ setIsHistoryOpen((bool) => !bool);
}
return (
-
-
-
-
-
-
-
-
- {/* */}
-
-
- {" "}
-
+ <>
+
+
+
+ {/* */}
+
+
+ >
);
-}
-
-const AppStyledDiv = styled.div<{ theme: TTheme }>`
- position: relative;
- width: 100vw;
- height: 100vh;
- top: 0;
- left: 0;
- background-color: ${(props) => props.theme.color.surface.alt};
-`;
+};
-const Container = styled.div`
- display: flex;
- padding: calc(2.29rem - 4px) calc(5.8rem - 4px);
-`;
+export default App;
diff --git a/frontend/src/components/Board.tsx b/frontend/src/components/Board.tsx
deleted file mode 100644
index ecb144ee..00000000
--- a/frontend/src/components/Board.tsx
+++ /dev/null
@@ -1,281 +0,0 @@
-import { styled } from "styled-components";
-import { TTheme } from "../types/theme";
-import CloseDanger from "/close-danger.svg";
-import Close from "/close.svg";
-import Edit from "/edit.svg";
-import Plus from "/plus.svg";
-
-type data = {
- title: string;
- text: string;
-};
-
-const dummy = [
- {
- name: "해야할 일",
- data: [
- {
- title: "Github 공부하기",
- text: "add, commit, push",
- },
- ],
- },
- {
- name: "하고 있는 일",
- data: [
- {
- title: "Github 공부하기",
- text: "add, commit, push",
- },
- ],
- },
- {
- name: "완료한 일",
- data: [
- {
- title: "Github 공부하기",
- text: "add, commit, push",
- },
- ],
- },
-];
-
-function Board({ handleDeleteButtonClick }: { handleDeleteButtonClick: (content: string, callback: () => void) => void }) {
- return (
-
- {dummy.map((item, index) => {
- const changeItem = (newData: data[]) => {
- console.log(item.data, newData);
- item.data = newData;
- };
-
- return (
-
-
-
- );
- })}
-
- );
-}
-
-const BoardStyledUl = styled.ul`
- display: flex;
- overflow: auto;
- box-sizing: border-box;
- gap: 24px;
- padding: 4px;
- &::-webkit-scrollbar {
- height: 0;
- }
-`;
-
-function Column({
- name,
- data,
- handleDeleteButtonClick,
- changeItem,
-}: {
- name: string;
- data: data[];
- handleDeleteButtonClick: (content: string, callback: () => void) => void;
- changeItem: (newData: data[]) => void;
-}) {
- return (
-
-
- {name}
-
-
-
- {data.map((d, index, data) => {
- const deleteCurrCard = () => {
- const newData = data.filter((item) => item !== d);
- console.log(newData)
- changeItem(newData);
- };
-
- return (
-
- handleDeleteButtonClick("선택한 카드를 삭제할까요?", deleteCurrCard)} />
-
- );
- })}
-
-
- );
-}
-
-const ColumnStyledUl = styled.ul`
- display: flex;
- flex-direction: column;
- gap: 10px;
-`;
-
-function ColumnControl() {
- return (
-
- {[
- { icon: Plus, alt: "추가" },
- { icon: Close, alt: "삭제" },
- ].map(ColumnControlBtn)}
-
- );
-}
-
-function ColumnControlBtn({ icon, alt }: { icon: string; alt: string }, index: number) {
- return (
-
-
-
- );
-}
-
-const ColumnControlBtnStyledLi = styled.li`
- & button {
- display: block;
- background-color: transparent;
- border: 0;
- padding: 0;
- & img {
- display: block;
-
- &.add {
- padding: 4px;
- }
-
- &.del {
- padding: 5px;
- }
- }
- }
-`;
-
-const ColumnControlStyledUl = styled.ul`
- display: inline-flex;
- gap: 8px;
-`;
-
-const ColumnStyledArticle = styled.li<{ theme: TTheme }>`
- min-width: 300px;
-`;
-
-const ColumnTitleStyledDiv = styled.div<{ theme: TTheme }>`
- display: flex;
- justify-content: space-between;
- margin-bottom: 10px;
- padding: 0 16px;
- box-sizing: border-box;
- h3 {
- font: ${(props) => props.theme.font.display.bold16};
- display: flex;
- align-items: center;
- &::after {
- content: attr(data-badge);
- margin-left: 8px;
- height: 24px;
- min-width: 24px;
- padding: 4px;
- box-sizing: border-box;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- border-radius: 8px;
- font: ${(props) => props.theme.font.display.medium12};
- color: ${(props) => props.theme.color.text.weak};
- border: 1px solid ${(props) => props.theme.color.border.default};
- }
- }
-`;
-
-function Card({ title, text, handleDeleteButtonClick }: { title: string; text: string; handleDeleteButtonClick: () => void }) {
- return (
-
- 카드
-
-
{title}
-
{text}
-
author by web
-
-
-
- );
-}
-
-const CardStyledArticle = styled.article<{ theme: TTheme }>`
- padding: 16px;
- border-radius: 8px;
- background-color: ${(props) => props.theme.color.surface.default};
- box-shadow: 0px 1px 4px rgba(110, 128, 145, 0.24);
- display: flex;
- align-items: flex-start;
- gap: 16px;
-
- h4 {
- font: ${(props) => props.theme.font.display.bold14};
- color: ${(props) => props.theme.color.text.strong};
- margin-bottom: 8px;
- }
-
- pre {
- font: ${(props) => props.theme.font.display.medium14};
- color: ${(props) => props.theme.color.text.default};
- margin-bottom: 16px;
- }
-
- p {
- font: ${(props) => props.theme.font.display.medium12};
- color: ${(props) => props.theme.color.text.weak};
- }
-
- .inner {
- flex-grow: 1;
- }
-
- ul {
- flex-shrink: 0;
- button {
- display: block;
- background-color: transparent;
- border: 0;
- padding: 0;
- cursor: pointer;
- &.del {
- padding: 5px;
- img:first-child {
- display: block;
- }
- img:last-child {
- display: none;
- }
- &:hover {
- img:first-child {
- display: none;
- }
- img:last-child {
- display: block;
- }
- }
- }
- &.edit {
- padding: 4px;
- }
- }
- }
-`;
-
-export default Board;
diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx
new file mode 100644
index 00000000..b9168b03
--- /dev/null
+++ b/frontend/src/components/Header.tsx
@@ -0,0 +1,41 @@
+import styled, { css } from "styled-components";
+import { TTheme } from "../types/TTheme";
+import Buttons from "./common/Buttons";
+
+const Header = styled(({ className }: { className?: string }) => {
+ return (
+
+ );
+})<{ theme: TTheme }>`
+ padding: 2.29rem 5.8rem;
+ height: 64px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+
+ ${({ theme }) => {
+ const { font, color } = theme;
+ return css`
+ .logo {
+ font: ${font.display.bold24};
+ text-decoration: none;
+ color: ${color.text.strong};
+ }
+ `;
+ }}
+`;
+
+export default Header;
diff --git a/frontend/src/components/HistoryBtn.tsx b/frontend/src/components/HistoryBtn.tsx
deleted file mode 100644
index 38ffc878..00000000
--- a/frontend/src/components/HistoryBtn.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { styled } from "styled-components";
-import Log from "/log.svg";
-
-export default function HistoryBtn({ toggleActiveUserLog }: { toggleActiveUserLog: () => void }) {
- return (
- toggleActiveUserLog()}>
-
-
- );
-}
-
-const HistoryBtnStyledButton = styled.button`
- background-color: transparent;
- border: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- padding: 0;
-
- & img {
- padding: 4px;
- }
-`
\ No newline at end of file
diff --git a/frontend/src/components/Logo.tsx b/frontend/src/components/Logo.tsx
deleted file mode 100644
index 06457899..00000000
--- a/frontend/src/components/Logo.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import styled from "styled-components";
-import { TTheme } from "../types/theme";
-
-const LogoStyledA = styled.a<{theme: TTheme}>`
- font: ${(props) => props.theme.font.display.bold24};
- text-decoration: none;
- color: ${(props) => props.theme.color.text.strong};
-`;
-
-export default function Logo() {
- return TODO LIST;
-}
diff --git a/frontend/src/components/Modal.tsx b/frontend/src/components/Modal.tsx
deleted file mode 100644
index 2c870d3b..00000000
--- a/frontend/src/components/Modal.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import React from "react";
-import { styled } from "styled-components";
-import { TTheme } from "../types/theme";
-
-export default function Modal({ message, action }: { message: string; action: () => void }) {
-
- function closeHandler(e: React.SyntheticEvent) {
- const dialog = e.target as HTMLDialogElement;
-
- console.log(dialog.returnValue);
- action();
- }
-
- return (
- <>
- {!!message && }
-
- >
- );
-}
-
-const Dim = styled.div`
- width: 100%;
- height: 100%;
- position: absolute;
- left: 0;
- top: 0;
- background-color: rgba(20, 33, 43, 0.3);
-`;
-
-const Dialog = styled.dialog<{theme: TTheme}>`
- width: 320px;
- border: none;
- border-radius: 8px;
- padding: 24px;
- margin: auto;
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- box-shadow: 0 2px 8px rgba(110, 128, 145, 0.16);
-
- p {
- margin-bottom: 24px;
- font: ${props => props.theme.font.display.medium16};
- color: ${props => props.theme.color.text.default};
- }
- form {
- display: block;
- }
-
- menu {
- display: flex;
- gap: 8px;
-
- li {
- flex: 1;
- }
-
- button {
- border: none;
- border-radius: 8px;
- width: 100%;
- padding: 8px 0;
- background-color: transparent;
- font: ${props => props.theme.font.display.bold14};
-
- &[value="cancel"] {
- color: ${props => props.theme.color.text.default};
- background-color: ${props => props.theme.color.surface.alt};
- }
-
- &[value="ok"] {
- color: ${props => props.theme.color.text.white.default};
- background-color: ${props => props.theme.color.surface.danger};
- }
- }
- }
-`;
diff --git a/frontend/src/components/aside/Aside.tsx b/frontend/src/components/aside/Aside.tsx
new file mode 100644
index 00000000..c35078c3
--- /dev/null
+++ b/frontend/src/components/aside/Aside.tsx
@@ -0,0 +1,15 @@
+import { styled } from "styled-components";
+import { UserActionLogList } from "./actionHistory/UserActionLogList";
+
+const Aside = styled(({ className }: { className?: string }) => {
+ return (
+
+ );
+})`
+ overflow: hidden;
+`;
+
+export default Aside;
diff --git a/frontend/src/components/UserActionLog.tsx b/frontend/src/components/aside/actionHistory/UserActionLog.tsx
similarity index 100%
rename from frontend/src/components/UserActionLog.tsx
rename to frontend/src/components/aside/actionHistory/UserActionLog.tsx
diff --git a/frontend/src/components/UserActionLogList.tsx b/frontend/src/components/aside/actionHistory/UserActionLogList.tsx
similarity index 84%
rename from frontend/src/components/UserActionLogList.tsx
rename to frontend/src/components/aside/actionHistory/UserActionLogList.tsx
index 68281bbb..046151f9 100644
--- a/frontend/src/components/UserActionLogList.tsx
+++ b/frontend/src/components/aside/actionHistory/UserActionLogList.tsx
@@ -1,3 +1,4 @@
+import React from "react";
import { UserActionLog } from "./UserActionLog";
const logDummy = [
@@ -13,7 +14,7 @@ const logDummy = [
},
];
-function UserActionLogList() {
+export const UserActionLogList: React.FC = () => {
return (
사용자 활동기록 목록
@@ -26,6 +27,4 @@ function UserActionLogList() {
);
-}
-
-export default UserActionLogList;
\ No newline at end of file
+};
diff --git a/frontend/src/components/common/Alert.tsx b/frontend/src/components/common/Alert.tsx
new file mode 100644
index 00000000..8fb04a69
--- /dev/null
+++ b/frontend/src/components/common/Alert.tsx
@@ -0,0 +1,112 @@
+import { css, styled } from "styled-components";
+import { TTheme } from "../../types/TTheme";
+import Dim from "../../styles/Dim";
+import { useEffect, useState } from "react";
+import { useAlert } from "../../hooks/useAlert";
+import { TAlertState } from "../../types/TAlertState";
+import Buttons from "./Buttons";
+
+const Alert = styled(({ className }: { className?: string }) => {
+ const [alertState, setAlertState] = useState(null);
+
+ useEffect(() => {
+ useAlert.register(setAlertState);
+ }, []);
+
+ function closeHandler(e: React.SyntheticEvent) {
+ const dialog = e.target as HTMLDialogElement;
+
+ if (dialog.returnValue === "ok") {
+ alertState!.action();
+ }
+ setAlertState(null);
+ }
+
+ return (
+ <>
+ {alertState && }
+
+ >
+ );
+})<{ theme: TTheme }>`
+ width: 320px;
+ border: none;
+ padding: 24px;
+ margin: auto;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ box-shadow: 0 2px 8px rgba(110, 128, 145, 0.16);
+ form {
+ display: block;
+ }
+
+ menu {
+ display: flex;
+ gap: 8px;
+
+ li {
+ flex: 1;
+ }
+ }
+ button {
+ width: 100%;
+ }
+
+ ${({ theme }) => {
+ const { font, color, border, boxShadow } = theme;
+
+ return css`
+ box-shadow: ${boxShadow.up};
+ border-radius: ${border.radius.round8};
+ p {
+ margin-bottom: 24px;
+ font: ${font.display.medium16};
+ color: ${color.text.default};
+ }
+
+ .cancel button {
+ background-color: ${color.surface.alt};
+ color: ${color.text.default};
+ }
+
+ .ok button {
+ background-color: ${color.surface.danger};
+ color: ${color.text.white.default};
+ }
+ `;
+ }}
+`;
+
+export default Alert;
diff --git a/frontend/src/components/common/Badge.tsx b/frontend/src/components/common/Badge.tsx
new file mode 100644
index 00000000..9ef693f5
--- /dev/null
+++ b/frontend/src/components/common/Badge.tsx
@@ -0,0 +1,45 @@
+import { css, styled } from "styled-components";
+import { TTheme } from "../../types/TTheme";
+
+export const Badge = styled(
+ ({ className, digit }: { className?: string; digit: number }) => {
+ return (
+
+ {digit}
+
+ );
+ }
+)<{ theme: TTheme; $2DigitPlus: boolean }>`
+ height: 24px;
+ padding: 4px;
+ box-sizing: border-box;
+ display: inline-flex;
+ ${({ theme }) => {
+ const { color, font, border } = theme;
+ return css`
+ border: 1px solid ${color.border.default};
+ font: ${font.display.medium12};
+ border-radius: ${border.radius.round8};
+ `;
+ }}
+
+ .text-label {
+ padding: 0 4px;
+ }
+
+ ${({ $2DigitPlus }) =>
+ $2DigitPlus
+ ? css`
+ .text-label {
+ display: none;
+ }
+ &::after {
+ content: "99+";
+ }
+ `
+ : css`
+ .text-label {
+ display: inline-block;
+ }
+ `}
+`;
diff --git a/frontend/src/components/common/Buttons.tsx b/frontend/src/components/common/Buttons.tsx
new file mode 100644
index 00000000..c4d59bed
--- /dev/null
+++ b/frontend/src/components/common/Buttons.tsx
@@ -0,0 +1,128 @@
+import { styled } from "styled-components";
+import { IconRouter } from "./Icon";
+import { TTheme } from "../../types/TTheme";
+
+const Buttons = styled(
+ ({
+ className,
+ icon,
+ text,
+ value,
+ type,
+ onClick,
+ }: {
+ className?: string;
+ icon?: string;
+ text?: string;
+ value?: string;
+ type?: "button" | "reset" | "submit";
+ onClick?: () => void;
+ }) => {
+ return (
+
+ );
+ }
+)<{
+ theme: TTheme;
+ $Flexible: "Fixed" | "";
+ $Type: "Contained" | "Ghost";
+ $ElementPattern: "Icon Only" | "Text Only" | "Icon + Text";
+ $States: "Enable" | "Hover" | "Disabled";
+}>`
+ padding: 8px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border: 0;
+ .container {
+ display: block;
+ }
+ svg {
+ display: block;
+ }
+
+ ${({ theme, $Flexible, $Type, $ElementPattern, $States }) => {
+ const { font, border } = theme;
+ let styleRules = `
+ font: ${font.display.bold14};
+ border-radius: ${border.radius.round8};
+ `;
+
+ switch ($Flexible) {
+ case "Fixed":
+ styleRules += `
+ height: 32px;
+ width: auto !important;
+ `;
+ break;
+ case "":
+ styleRules += ``;
+ break;
+ }
+
+ switch ($Type) {
+ case "Contained":
+ styleRules += ``;
+ break;
+ case "Ghost":
+ styleRules += `
+ background: transparent !important;
+ `;
+ break;
+ }
+
+ switch ($ElementPattern) {
+ case "Icon Only":
+ styleRules += `
+ `;
+ break;
+ case "Text Only":
+ styleRules += `
+ .text-label {
+ padding: 0 4px;
+ }
+ `;
+ break;
+ case "Icon + Text":
+ styleRules += `
+ .text-label {
+ padding: 0 4px;
+ }
+ `;
+ break;
+ }
+
+ switch ($States) {
+ case "Enable":
+ styleRules += `
+ opacity: 1;
+ `;
+ break;
+ case "Hover":
+ styleRules += `
+ opacity: .8;
+ `;
+ break;
+ case "Disabled":
+ styleRules += `
+ opacity: .3;
+ `;
+ break;
+ }
+
+ return styleRules;
+ }}
+`;
+
+export default Buttons;
diff --git a/frontend/src/components/common/Fab.tsx b/frontend/src/components/common/Fab.tsx
new file mode 100644
index 00000000..64701aa6
--- /dev/null
+++ b/frontend/src/components/common/Fab.tsx
@@ -0,0 +1,14 @@
+import { css, styled } from "styled-components";
+import { IconRouter } from "./Icon";
+import { TTheme } from "../../types/TTheme";
+export const Fab = styled(({ className }: { className: string }) => {
+ return ;
+})<{ theme: TTheme }>`
+ ${({ theme }) => {
+ const { color } = theme;
+ return css`
+ background: ${color.accent.blue};
+ border-radius: 50%;
+ `;
+ }}
+`;
diff --git a/frontend/src/components/common/Icon.tsx b/frontend/src/components/common/Icon.tsx
new file mode 100644
index 00000000..2855afbc
--- /dev/null
+++ b/frontend/src/components/common/Icon.tsx
@@ -0,0 +1,104 @@
+import React from "react";
+
+export function IconRouter(name: string) {
+ switch (name) {
+ case "Plus":
+ return ;
+ case "Close":
+ return ;
+ case "CloseSmall":
+ return ;
+ case "History":
+ return ;
+ case "Edit":
+ return ;
+ }
+}
+
+export const Plus: React.FC = () => {
+ return (
+
+ );
+};
+
+export const Close: React.FC = () => {
+ return (
+
+ );
+};
+
+export const CloseSmall: React.FC = () => {
+ return (
+
+ );
+};
+
+export const History: React.FC = () => {
+ return (
+
+ );
+};
+
+export const Edit: React.FC = () => {
+ return (
+
+ );
+};
diff --git a/frontend/src/components/landmark/Header.tsx b/frontend/src/components/landmark/Header.tsx
deleted file mode 100644
index 8599c00f..00000000
--- a/frontend/src/components/landmark/Header.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from "react";
-import styled from "styled-components"
-
-export default function Header({ children }: { children: React.ReactNode }) {
- return (
-
- );
-}
-
-const Style = styled.header`
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 1.2rem 5.8rem;
- margin: auto;
-`
\ No newline at end of file
diff --git a/frontend/src/components/landmark/Main.tsx b/frontend/src/components/landmark/Main.tsx
deleted file mode 100644
index 5e05561b..00000000
--- a/frontend/src/components/landmark/Main.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { ReactNode } from "react";
-import { styled } from "styled-components";
-
-export default function Main({ children }: { children: ReactNode }) {
- return (
-
- 메인
- {children}
-
- );
-}
-
-const MainStyledMain = styled.main`
- overflow: hidden;
-`;
diff --git a/frontend/src/components/landmark/landmark.tsx b/frontend/src/components/landmark/landmark.tsx
deleted file mode 100644
index a4d7a012..00000000
--- a/frontend/src/components/landmark/landmark.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import { ReactNode } from "react";
-
-export default function Aside({ children }: { children: ReactNode }) {
- return (
-
- );
-}
-
diff --git a/frontend/src/components/main/Main.tsx b/frontend/src/components/main/Main.tsx
new file mode 100644
index 00000000..add24794
--- /dev/null
+++ b/frontend/src/components/main/Main.tsx
@@ -0,0 +1,15 @@
+import { styled } from "styled-components";
+import Board from "./board/Board";
+
+const Main = styled(({ className }: { className?: string }) => {
+ return (
+
+ 메인
+
+
+ );
+})`
+ overflow: hidden;
+`;
+
+export default Main;
diff --git a/frontend/src/components/main/board/Board.tsx b/frontend/src/components/main/board/Board.tsx
new file mode 100644
index 00000000..2b7a6589
--- /dev/null
+++ b/frontend/src/components/main/board/Board.tsx
@@ -0,0 +1,75 @@
+import { styled } from "styled-components";
+import Column from "./column/Column";
+import { useState } from "react";
+import TCard from "../../../types/TCard";
+import TColumn from "../../../types/TColumn";
+import { TTheme } from "../../../types/TTheme";
+
+const Board = styled(({ className }: { className?: string }) => {
+ const [columns, setColumns] = useState(dummy);
+
+ function deleteCardFromColumn(columnIndex: number) {
+ return (card: TCard) => {
+ setColumns((columns) => {
+ const newColumns = [...columns];
+ const cards = newColumns[columnIndex].cards;
+ newColumns[columnIndex].cards = cards.filter((_card) => _card !== card);
+ return newColumns;
+ });
+ };
+ }
+
+ return (
+
+ {columns.map((column, index) => {
+ const deleteCard = deleteCardFromColumn(index);
+ return (
+ -
+
+
+ );
+ })}
+
+ );
+})<{ theme: TTheme }>`
+ display: flex;
+ overflow: auto;
+ box-sizing: border-box;
+ gap: 24px;
+ padding: 4px;
+ &::-webkit-scrollbar {
+ height: 0;
+ }
+`;
+
+const dummy: TColumn[] = [
+ {
+ name: "해야할 일",
+ cards: [
+ {
+ title: "Github 공부하기",
+ text: "add, commit, push",
+ },
+ ],
+ },
+ {
+ name: "하고 있는 일",
+ cards: [
+ {
+ title: "Github 공부하기",
+ text: "add, commit, push",
+ },
+ ],
+ },
+ {
+ name: "완료한 일",
+ cards: [
+ {
+ title: "Github 공부하기",
+ text: "add, commit, push",
+ },
+ ],
+ },
+];
+
+export default Board;
diff --git a/frontend/src/components/main/board/column/Column.tsx b/frontend/src/components/main/board/column/Column.tsx
new file mode 100644
index 00000000..48ea15ef
--- /dev/null
+++ b/frontend/src/components/main/board/column/Column.tsx
@@ -0,0 +1,43 @@
+import { styled } from "styled-components";
+
+import Card from "./card/Card";
+import ColumnTitle from "./ColumnTitle";
+import TCard from "../../../../types/TCard";
+import { TTheme } from "../../../../types/TTheme";
+
+const Column = styled(
+ ({
+ className,
+ name,
+ cards,
+ deleteCard,
+ }: {
+ className?: string;
+ name: string;
+ cards: TCard[];
+ deleteCard: (card: TCard) => void;
+ }) => {
+ return (
+
+
+
+ {cards.map((card, index) => (
+ -
+ deleteCard(card)} />
+
+ ))}
+
+
+ );
+ }
+)<{ theme: TTheme }>`
+ min-width: 300px;
+
+ .card-list {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ }
+`;
+
+export default Column;
diff --git a/frontend/src/components/main/board/column/ColumnControl.tsx b/frontend/src/components/main/board/column/ColumnControl.tsx
new file mode 100644
index 00000000..3b7e4e09
--- /dev/null
+++ b/frontend/src/components/main/board/column/ColumnControl.tsx
@@ -0,0 +1,38 @@
+import { styled } from "styled-components";
+import Buttons from "../../../common/Buttons";
+import { TTheme } from "../../../../types/TTheme";
+
+const ColumnControl = styled(({ className }: { className?: string }) => {
+ return (
+
+ {["Plus", "Close"].map((IconName, index) => {
+ return (
+ -
+ console.log("컬럼버튼")}
+ />
+
+ );
+ })}
+
+ );
+})<{ theme: TTheme }>`
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+
+ button {
+ background-color: transparent;
+ display: block;
+ border: 0;
+ margin: 0;
+ padding: 0;
+ }
+`;
+
+export default ColumnControl;
diff --git a/frontend/src/components/main/board/column/ColumnTitle.tsx b/frontend/src/components/main/board/column/ColumnTitle.tsx
new file mode 100644
index 00000000..53e284df
--- /dev/null
+++ b/frontend/src/components/main/board/column/ColumnTitle.tsx
@@ -0,0 +1,46 @@
+import { css, styled } from "styled-components";
+import ColumnControl from "./ColumnControl";
+import { Badge } from "../../../common/Badge";
+import { TTheme } from "../../../../types/TTheme";
+
+const ColumnTitle = styled(
+ ({
+ className,
+ title,
+ count,
+ }: {
+ className?: string;
+ title: string;
+ count: number;
+ }) => {
+ return (
+
+
+ {title}
+ 99} digit={count} />
+
+
+
+ );
+ }
+)<{ theme: TTheme }>`
+ width: 300px;
+ padding: 0 16px;
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ .text-aria {
+ display: inline-flex;
+ gap: 8px;
+ align-items: center;
+ }
+
+ ${({ theme }) => {
+ const { font } = theme;
+ return css`
+ font: ${font.display.bold16};
+ `;
+ }}
+`;
+
+export default ColumnTitle;
diff --git a/frontend/src/components/main/board/column/card/Card.tsx b/frontend/src/components/main/board/column/card/Card.tsx
new file mode 100644
index 00000000..67ce0046
--- /dev/null
+++ b/frontend/src/components/main/board/column/card/Card.tsx
@@ -0,0 +1,184 @@
+import { css, styled } from "styled-components";
+import { FormEvent, useState } from "react";
+import Buttons from "../../../../common/Buttons";
+import { useAlert } from "../../../../../hooks/useAlert";
+import { TTheme } from "../../../../../types/TTheme";
+
+const Card = styled(
+ ({
+ className,
+ title,
+ text,
+ onDelete,
+ }: {
+ className?: string;
+ title: string;
+ text: string;
+ onDelete: () => void;
+ }) => {
+ const [mode, setMode] = useState<"default" | "Add/Edit" | "Drag" | "Place">(
+ "default"
+ );
+
+ function editFormSubmitHandler(event: FormEvent): void {
+ event.preventDefault();
+ console.log(event.target);
+ }
+
+ return (
+
+ 카드
+ {mode !== "Add/Edit" && (
+
+
+
{title}
+
{text}
+
author by web
+
+
+
+ )}
+ {mode === "Add/Edit" && (
+
+ )}
+
+ );
+ }
+)<{ theme: TTheme }>`
+ ${({ theme }) => {
+ const { color, font } = theme;
+ return css`
+ padding: 16px;
+ border-radius: 8px;
+ background-color: ${color.surface.default};
+ box-shadow: 0px 1px 4px rgba(110, 128, 145, 0.24);
+ & > .container {
+ display: flex;
+ align-items: flex-start;
+ gap: 16px;
+ }
+
+ h4 {
+ font: ${font.display.bold14};
+ color: ${color.text.strong};
+ margin-bottom: 8px;
+ }
+
+ pre {
+ font: ${font.display.medium14};
+ color: ${color.text.default};
+ }
+
+ p {
+ font: ${font.display.medium12};
+ margin-top: 16px;
+ color: ${color.text.weak};
+ }
+
+ form {
+ input {
+ background: transparent;
+ border: 0;
+ margin-top: -1px;
+ margin-left: -2px;
+ }
+ input[name="title"] {
+ font: ${font.display.bold14};
+ color: ${color.text.strong};
+ margin-bottom: 7px;
+ }
+ input[name="body"] {
+ font: ${font.display.medium14};
+ color: ${color.text.default};
+ margin-bottom: 6px;
+ }
+ }
+
+ .inner {
+ flex-grow: 1;
+ }
+
+ .control {
+ button {
+ display: block;
+ background-color: transparent;
+ border: 0;
+ padding: 0;
+ cursor: pointer;
+ }
+ }
+ .edit-menu {
+ display: flex;
+ gap: 8px;
+ li {
+ width: 100%;
+ &.register button {
+ color: ${color.text.default};
+ }
+ &.register button {
+ background-color: ${color.surface.brand};
+ color: ${color.text.white.default};
+ }
+ }
+ button {
+ width: 100%;
+ }
+ }
+ `;
+ }}
+`;
+
+export default Card;
diff --git a/frontend/src/hooks/useAlert.ts b/frontend/src/hooks/useAlert.ts
new file mode 100644
index 00000000..26143eda
--- /dev/null
+++ b/frontend/src/hooks/useAlert.ts
@@ -0,0 +1,23 @@
+import { TAlertState } from "../types/TAlertState";
+
+export const useAlert = (function () {
+ const state: {
+ set: React.Dispatch> | null;
+ } = {
+ set: null,
+ };
+
+ return {
+ register: (
+ set: React.Dispatch>
+ ) => {
+ state.set = set;
+ },
+ use: (message: string, action: () => void) => {
+ if (!state.set) {
+ return;
+ }
+ state.set({ message, action });
+ },
+ };
+})();
diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx
index e63eef4a..57236b4a 100644
--- a/frontend/src/main.tsx
+++ b/frontend/src/main.tsx
@@ -1,9 +1,15 @@
-import React from 'react'
-import ReactDOM from 'react-dom/client'
-import App from './App.tsx'
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App.tsx";
+import { ThemeProvider } from "styled-components";
+import { theme } from "./theme.ts";
+import CommonStyle from "./styles/CommonStyle.tsx";
-ReactDOM.createRoot(document.getElementById('root')!).render(
+ReactDOM.createRoot(document.getElementById("root")!).render(
-
- ,
-)
+
+
+
+
+
+);
diff --git a/frontend/src/styles/CommonStyle.tsx b/frontend/src/styles/CommonStyle.tsx
index 17d02a32..e73d9458 100644
--- a/frontend/src/styles/CommonStyle.tsx
+++ b/frontend/src/styles/CommonStyle.tsx
@@ -1,7 +1,15 @@
import { createGlobalStyle } from "styled-components";
+import { TTheme } from "../types/TTheme";
-const CommonStyle = createGlobalStyle`
-
+const CommonStyle = createGlobalStyle<{ theme: TTheme }>`
+ body {
+ position: relative;
+ width: 100vw;
+ height: 100vh;
+ top: 0;
+ left: 0;
+ background-color: ${({ theme }) => theme.color.surface.alt};
+ }
.blind {
width: 1px;
height: 1px;
diff --git a/frontend/src/styles/Container.tsx b/frontend/src/styles/Container.tsx
new file mode 100644
index 00000000..06ea25b0
--- /dev/null
+++ b/frontend/src/styles/Container.tsx
@@ -0,0 +1,8 @@
+import { styled } from "styled-components";
+
+const Container = styled.div`
+ display: flex;
+ padding: calc(2.29rem - 4px) calc(5.8rem - 4px);
+`;
+
+export default Container;
diff --git a/frontend/src/styles/Dim.tsx b/frontend/src/styles/Dim.tsx
index e69de29b..71509b25 100644
--- a/frontend/src/styles/Dim.tsx
+++ b/frontend/src/styles/Dim.tsx
@@ -0,0 +1,12 @@
+import { styled } from "styled-components";
+
+const Dim = styled.div`
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ left: 0;
+ top: 0;
+ background-color: rgba(20, 33, 43, 0.3);
+`;
+
+export default Dim;
diff --git a/frontend/src/theme.ts b/frontend/src/theme.ts
index 5a769e46..38b46424 100644
--- a/frontend/src/theme.ts
+++ b/frontend/src/theme.ts
@@ -1,6 +1,7 @@
-import { TTheme } from "./types/theme";
+import { TTheme } from "./types/TTheme";
-const fontFamily = '"Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif'
+const fontFamily =
+ '"Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif';
export const theme: TTheme = {
font: {
@@ -57,8 +58,8 @@ export const theme: TTheme = {
default: "#6E7191",
weak: "#A0A3BD",
white: {
- default:"#FEFEFE",
- weak: "#F7F7FC"
+ default: "#FEFEFE",
+ weak: "#F7F7FC",
},
brand: "#007AFF",
danger: "#FF3B30",
@@ -67,10 +68,23 @@ export const theme: TTheme = {
default: "#FEFEFE",
alt: "#F7F7FC",
brand: "#007AFF",
- danger:"#FF3B30"
+ danger: "#FF3B30",
+ },
+ border: {
+ default: "#EFF0F6",
},
- border: {
- default: "#EFF0F6"
- }
},
-};
\ No newline at end of file
+ border: {
+ radius: {
+ round8: "8px",
+ round16: "8px",
+ circle: "50%",
+ },
+ },
+ boxShadow: {
+ normal: "0px 1px 4px rgba(110, 128, 145, 0.24)",
+ up: "0px 2px 8px rgba(110, 128, 145, 0.32)",
+ floating:
+ "0px 0px 4px rgba(110, 128, 145, 0.08), 0px 16px 16px rgba(110, 128, 145, 0.24)",
+ },
+};
diff --git a/frontend/src/types/TAlertState.ts b/frontend/src/types/TAlertState.ts
new file mode 100644
index 00000000..6a23c90f
--- /dev/null
+++ b/frontend/src/types/TAlertState.ts
@@ -0,0 +1,4 @@
+export type TAlertState = {
+ message: string;
+ action: () => void;
+}
\ No newline at end of file
diff --git a/frontend/src/types/TCard.ts b/frontend/src/types/TCard.ts
new file mode 100644
index 00000000..a44b5d3c
--- /dev/null
+++ b/frontend/src/types/TCard.ts
@@ -0,0 +1,6 @@
+type TCard = {
+ title: string;
+ text: string;
+};
+
+export default TCard;
diff --git a/frontend/src/types/TColumn.ts b/frontend/src/types/TColumn.ts
new file mode 100644
index 00000000..ca65062f
--- /dev/null
+++ b/frontend/src/types/TColumn.ts
@@ -0,0 +1,8 @@
+import TCard from "./TCard";
+
+type TColumn = {
+ name: string;
+ cards: TCard[];
+};
+
+export default TColumn;
diff --git a/frontend/src/types/theme.ts b/frontend/src/types/TTheme.ts
similarity index 83%
rename from frontend/src/types/theme.ts
rename to frontend/src/types/TTheme.ts
index 85e6e175..5bbefc0e 100644
--- a/frontend/src/types/theme.ts
+++ b/frontend/src/types/TTheme.ts
@@ -1,12 +1,11 @@
// theme.ts
-
export type TTheme = {
font: {
bold: {
L: string;
M: string;
- R: string;
+ R: string;
S: string;
};
medium: {
@@ -63,4 +62,17 @@ export type TTheme = {
default: string;
};
};
+
+ border: {
+ radius: {
+ round8: string;
+ round16: string;
+ circle: string;
+ };
+ };
+ boxShadow: {
+ normal: string;
+ up: string;
+ floating: string;
+ };
};
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..ed282966
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6 @@
+{
+ "name": "todo-max",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {}
+}