diff --git a/frontend/reply-module/.storybook/main.js b/frontend/reply-module/.storybook/main.js index 26dfeaf66..82a742044 100644 --- a/frontend/reply-module/.storybook/main.js +++ b/frontend/reply-module/.storybook/main.js @@ -1,10 +1,4 @@ module.exports = { - "stories": [ - "../src/**/*.stories.mdx", - "../src/**/*.stories.@(js|jsx|ts|tsx)" - ], - "addons": [ - "@storybook/addon-links", - "@storybook/addon-essentials" - ] -} \ No newline at end of file + stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"], + addons: ["@storybook/addon-links", "@storybook/addon-essentials"] +}; diff --git a/frontend/reply-module/.storybook/preview.css b/frontend/reply-module/.storybook/preview.css new file mode 100644 index 000000000..ec23d958f --- /dev/null +++ b/frontend/reply-module/.storybook/preview.css @@ -0,0 +1,4 @@ +#root { + width: 100%; + max-width: 1080px; +} diff --git a/frontend/reply-module/.storybook/preview.js b/frontend/reply-module/.storybook/preview.js index 48afd568a..02afa7473 100644 --- a/frontend/reply-module/.storybook/preview.js +++ b/frontend/reply-module/.storybook/preview.js @@ -1,9 +1,23 @@ +import { configure, addDecorator } from "@storybook/react"; +import GlobalStyles from "../src/styles/GlobalStyles"; +import "./preview.css"; + export const parameters = { actions: { argTypesRegex: "^on[A-Z].*" }, + layout: "centered", controls: { matchers: { color: /(background|color)$/i, - date: /Date$/, - }, - }, -} \ No newline at end of file + date: /Date$/ + } + } +}; + +addDecorator(style => ( + <> + + <>{style()} + +)); + +configure(require.context("../src", true, /\.stories\.js?$/), module); diff --git a/frontend/reply-module/src/App.tsx b/frontend/reply-module/src/App.tsx index a5e22d64a..49837e41c 100644 --- a/frontend/reply-module/src/App.tsx +++ b/frontend/reply-module/src/App.tsx @@ -1,5 +1,5 @@ const App = () => { - return <>Hello World; + return null; }; export default App; diff --git a/frontend/reply-module/src/assets/svg/three-dots.svg b/frontend/reply-module/src/assets/svg/three-dots.svg new file mode 100644 index 000000000..bd4058aaa --- /dev/null +++ b/frontend/reply-module/src/assets/svg/three-dots.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/reply-module/src/components/atoms/Avatar/Avatar.stories.tsx b/frontend/reply-module/src/components/atoms/Avatar/Avatar.stories.tsx new file mode 100644 index 000000000..cc19a8f65 --- /dev/null +++ b/frontend/reply-module/src/components/atoms/Avatar/Avatar.stories.tsx @@ -0,0 +1,16 @@ +import { Story } from "@storybook/react"; +import Avatar, { Props } from "."; + +export default { + title: "atoms/Avatar", + component: Avatar, + argTypes: { children: { control: "text" } } +}; + +const Template: Story = args => ; + +export const Default = Template.bind({}); + +Default.args = { + imageURL: "data:image/jpeg;base64,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" +}; diff --git a/frontend/reply-module/src/components/atoms/Avatar/index.tsx b/frontend/reply-module/src/components/atoms/Avatar/index.tsx new file mode 100644 index 000000000..37402cf45 --- /dev/null +++ b/frontend/reply-module/src/components/atoms/Avatar/index.tsx @@ -0,0 +1,14 @@ +import { Container } from "./styles"; + +export type Size = "SM" | "MD" | "LG"; + +export interface Props { + imageURL: string; + size?: Size; +} + +const Avatar = ({ imageURL, size = "MD" }: Props) => { + return ; +}; + +export default Avatar; diff --git a/frontend/reply-module/src/components/atoms/Avatar/styles.ts b/frontend/reply-module/src/components/atoms/Avatar/styles.ts new file mode 100644 index 000000000..286d2c87e --- /dev/null +++ b/frontend/reply-module/src/components/atoms/Avatar/styles.ts @@ -0,0 +1,17 @@ +import styled from "styled-components"; + +import { Size } from "."; + +const avatarSizeBySize = { + SM: 30, + MD: 40, + LG: 90 +}; + +const Container = styled.img<{ size: Size }>` + border-radius: 50%; + width: ${props => `${avatarSizeBySize[props.size]}px`}; + height: ${props => `${avatarSizeBySize[props.size]}px`}; +`; + +export { Container }; diff --git a/frontend/reply-module/src/components/atoms/CommentOption/CommentOption.stories.tsx b/frontend/reply-module/src/components/atoms/CommentOption/CommentOption.stories.tsx new file mode 100644 index 000000000..8e127a394 --- /dev/null +++ b/frontend/reply-module/src/components/atoms/CommentOption/CommentOption.stories.tsx @@ -0,0 +1,14 @@ +import { Story } from "@storybook/react"; +import CommentOption, { Props } from "."; + +export default { + title: "atoms/CommentOption", + component: CommentOption, + argTypes: { children: { control: "text" } } +}; + +const Template: Story = args => ; + +export const Default = Template.bind({}); + +Default.args = {}; diff --git a/frontend/reply-module/src/components/atoms/CommentOption/index.tsx b/frontend/reply-module/src/components/atoms/CommentOption/index.tsx new file mode 100644 index 000000000..d352943e3 --- /dev/null +++ b/frontend/reply-module/src/components/atoms/CommentOption/index.tsx @@ -0,0 +1,29 @@ +import { useState } from "react"; +import threeDots from "../../../assets/svg/three-dots.svg"; +import { Container, DeleteButton, EditButton, OptionContainer, OptionIcon } from "./styles"; + +export interface Props { + onEdit?: () => void; + onDelete?: () => void; +} + +const CommentOption = ({ onEdit, onDelete }: Props) => { + const [isShowOptionBox, setShowOptionBox] = useState(false); + const onShowOptionBox = () => { + setShowOptionBox(state => !state); + }; + + return ( + + + {isShowOptionBox && ( + + 수정 + 삭제 + + )} + + ); +}; + +export default CommentOption; diff --git a/frontend/reply-module/src/components/atoms/CommentOption/styles.ts b/frontend/reply-module/src/components/atoms/CommentOption/styles.ts new file mode 100644 index 000000000..5fe7d3414 --- /dev/null +++ b/frontend/reply-module/src/components/atoms/CommentOption/styles.ts @@ -0,0 +1,63 @@ +import styled from "styled-components"; +import { PALETTE } from "../../../styles/palette"; + +const Container = styled.div` + position: absolute; +`; + +const OptionIcon = styled.img` + cursor: pointer; +`; + +const OptionContainer = styled.div` + position: absolute; + right: -5px; + width: 6rem; + box-shadow: 1.04082px 1.04082px 6.24491px rgba(0, 0, 0, 0.25); + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: center; + background-color: ${PALETTE.WHITE}; + + ::before { + content: ""; + position: absolute; + top: -5px; + right: 8px; + + border-bottom: 10px solid ${PALETTE.WHITE}; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + } + + & > button { + width: 100%; + border: none; + outline: none; + background-color: ${PALETTE.WHITE}; + cursor: pointer; + font-weight: 600; + margin-bottom: 0.3rem; + + :first-child { + padding-top: 0.5rem; + border-radius: 10px 10px 0 0; + } + + :last-child { + margin-bottom: 0; + padding-bottom: 0.5rem; + border-radius: 0 0 10px 10px; + } + } +`; + +const EditButton = styled.button` + color: ${PALETTE.BLACK_700}; +`; +const DeleteButton = styled.button` + color: ${PALETTE.RED_600}; +`; + +export { Container, OptionIcon, OptionContainer, EditButton, DeleteButton }; diff --git a/frontend/reply-module/src/components/atoms/CommentTextBox/CommentTextBox.stories.tsx b/frontend/reply-module/src/components/atoms/CommentTextBox/CommentTextBox.stories.tsx new file mode 100644 index 000000000..d653da56b --- /dev/null +++ b/frontend/reply-module/src/components/atoms/CommentTextBox/CommentTextBox.stories.tsx @@ -0,0 +1,17 @@ +import { Story } from "@storybook/react"; +import CommentTextBox, { Props } from "."; + +export default { + title: "atoms/CommentTextBox", + component: CommentTextBox, + argTypes: { children: { control: "text" } } +}; + +const Template: Story = args => ; + +export const Default = Template.bind({}); + +Default.args = { + name: "곤이", + contentEditable: true +}; diff --git a/frontend/reply-module/src/components/atoms/CommentTextBox/index.tsx b/frontend/reply-module/src/components/atoms/CommentTextBox/index.tsx new file mode 100644 index 000000000..185c730c3 --- /dev/null +++ b/frontend/reply-module/src/components/atoms/CommentTextBox/index.tsx @@ -0,0 +1,18 @@ +import { Container, Name, Text } from "./styles"; + +export interface Props { + name: string; + children: string; + contentEditable?: boolean; +} + +const CommentTextBox = ({ name, children, contentEditable = false }: Props) => { + return ( + + {name} + {children} + + ); +}; + +export default CommentTextBox; diff --git a/frontend/reply-module/src/components/atoms/CommentTextBox/styles.ts b/frontend/reply-module/src/components/atoms/CommentTextBox/styles.ts new file mode 100644 index 000000000..920d837ee --- /dev/null +++ b/frontend/reply-module/src/components/atoms/CommentTextBox/styles.ts @@ -0,0 +1,27 @@ +import styled from "styled-components"; +import { PALETTE } from "../../../styles/palette"; + +const Container = styled.div` + width: 100%; + background-color: ${PALETTE.GRAY_200}; + border-radius: 10px; + padding: 0.8rem 1rem; + display: flex; + flex-direction: column; +`; + +const Name = styled.span` + font-weight: 700; + font-size: 1.4rem; + margin-bottom: 0.7rem; +`; + +const Text = styled.div` + outline-color: ${PALETTE.BLACK_700}; + background-color: ${props => (props.contentEditable ? PALETTE.WHITE : PALETTE.GRAY_200)}; + border-radius: 10px; + min-width: 10rem; + max-width: 20rem; +`; + +export { Container, Name, Text }; diff --git a/frontend/reply-module/src/components/atoms/SubmitButton/SubmitButton.stories.tsx b/frontend/reply-module/src/components/atoms/SubmitButton/SubmitButton.stories.tsx new file mode 100644 index 000000000..a6ba8f1db --- /dev/null +++ b/frontend/reply-module/src/components/atoms/SubmitButton/SubmitButton.stories.tsx @@ -0,0 +1,14 @@ +import { Story } from "@storybook/react"; +import SubmitButton, { Props } from "."; + +export default { + title: "atoms/SubmitButton", + component: SubmitButton, + argTypes: { children: { control: "text" } } +}; + +const Template: Story = args => ; + +export const Default = Template.bind({}); + +Default.args = {}; diff --git a/frontend/reply-module/src/components/atoms/SubmitButton/index.tsx b/frontend/reply-module/src/components/atoms/SubmitButton/index.tsx new file mode 100644 index 000000000..7e56e3894 --- /dev/null +++ b/frontend/reply-module/src/components/atoms/SubmitButton/index.tsx @@ -0,0 +1,12 @@ +import { Button } from "./styles"; + +export interface Props { + children: string; + onClick: () => void; +} + +const SubmitButton = ({ children, onClick }: Props) => { + return ; +}; + +export default SubmitButton; diff --git a/frontend/reply-module/src/components/atoms/SubmitButton/styles.ts b/frontend/reply-module/src/components/atoms/SubmitButton/styles.ts new file mode 100644 index 000000000..41cf756b3 --- /dev/null +++ b/frontend/reply-module/src/components/atoms/SubmitButton/styles.ts @@ -0,0 +1,15 @@ +import { PALETTE } from "./../../../styles/palette"; +import styled from "styled-components"; + +const Button = styled.button` + width: 6rem; + height: 3.6rem; + background-color: ${PALETTE.PRIMARY}; + color: ${PALETTE.WHITE}; + font-size: 1.6rem; + font-weight: 500; + border: none; + border-radius: 10px; +`; + +export { Button }; diff --git a/frontend/reply-module/src/components/molecules/Comment/Comment.stories.tsx b/frontend/reply-module/src/components/molecules/Comment/Comment.stories.tsx new file mode 100644 index 000000000..355a594b4 --- /dev/null +++ b/frontend/reply-module/src/components/molecules/Comment/Comment.stories.tsx @@ -0,0 +1,28 @@ +import { Story } from "@storybook/react"; +import Comment, { Props } from "."; + +export default { + title: "molecules/Comment", + component: Comment, + argTypes: { children: { control: "text" } } +}; + +const Template: Story = args => ; + +export const Default = Template.bind({}); + +Default.args = { + comment: { + id: 1, + content: "Donec accumsan neque enim sodales. Neque eget vulputate viverra convallis pharetra.", + user: { + id: 1, + imageURL: + "https://static.independent.co.uk/s3fs-public/thumbnails/image/2015/06/06/15/Chris-Pratt.jpg?width=982&height=726&auto=webp&quality=75", + nickName: "Robert Hill", + type: "Authorized" + }, + createdAt: "1시간 전" + }, + shouldShowOption: true +}; diff --git a/frontend/reply-module/src/components/molecules/Comment/index.tsx b/frontend/reply-module/src/components/molecules/Comment/index.tsx new file mode 100644 index 000000000..539f80af6 --- /dev/null +++ b/frontend/reply-module/src/components/molecules/Comment/index.tsx @@ -0,0 +1,33 @@ +import { Comment as CommentType } from "../../../types"; +import Avatar from "../../atoms/Avatar"; +import CommentOption from "../../atoms/CommentOption"; +import CommentTextBox from "../../atoms/CommentTextBox"; +import { Container, CommentTextBoxWrapper, Time, CommentOptionWrapper } from "./styles"; + +export interface Props { + comment: CommentType; + align?: "left" | "right"; + + shouldShowOption?: boolean; + onEdit?: () => void; + onDelete?: () => void; +} + +const Comment = ({ comment, align = "left", shouldShowOption, onEdit, onDelete }: Props) => { + return ( + + + + {comment.content} + + {shouldShowOption && ( + + + + )} + + + ); +}; + +export default Comment; diff --git a/frontend/reply-module/src/components/molecules/Comment/styles.ts b/frontend/reply-module/src/components/molecules/Comment/styles.ts new file mode 100644 index 000000000..af2340a0d --- /dev/null +++ b/frontend/reply-module/src/components/molecules/Comment/styles.ts @@ -0,0 +1,27 @@ +import styled from "styled-components"; + +const Container = styled.div<{ align: "left" | "right" }>` + display: flex; + flex-direction: ${props => (props.align === "left" ? "row" : "row-reverse")}; +`; + +const CommentTextBoxWrapper = styled.div<{ align: "left" | "right" }>` + position: relative; + display: flex; + flex-direction: column; + align-items: ${props => (props.align === "left" ? "flex-start" : "flex-end")}; + margin: ${props => (props.align === "left" ? "0 0 0 0.6rem" : "0 0.6rem 0 0")}; +`; + +const Time = styled.span` + margin: 0 1rem; + margin-top: 0.3rem; +`; + +const CommentOptionWrapper = styled.div` + position: absolute; + right: 30px; + top: 8px; +`; + +export { Container, CommentTextBoxWrapper, Time, CommentOptionWrapper }; diff --git a/frontend/reply-module/src/components/organisms/CommentInput/CommentInput.stories.tsx b/frontend/reply-module/src/components/organisms/CommentInput/CommentInput.stories.tsx new file mode 100644 index 000000000..07836f452 --- /dev/null +++ b/frontend/reply-module/src/components/organisms/CommentInput/CommentInput.stories.tsx @@ -0,0 +1,14 @@ +import { Story } from "@storybook/react"; +import CommentInput, { Props } from "."; + +export default { + title: "organisms/CommentInput", + component: CommentInput, + argTypes: { children: { control: "text" } } +}; + +const Template: Story = args => ; + +export const Default = Template.bind({}); + +Default.args = {}; diff --git a/frontend/reply-module/src/components/organisms/CommentInput/index.tsx b/frontend/reply-module/src/components/organisms/CommentInput/index.tsx new file mode 100644 index 000000000..862d3fdf5 --- /dev/null +++ b/frontend/reply-module/src/components/organisms/CommentInput/index.tsx @@ -0,0 +1,27 @@ +import SubmitButton from "../../atoms/SubmitButton"; +import { Container, TextArea, Wrapper, GuestInfo } from "./styles"; + +export interface Props {} + +const CommentInput = () => { + const isGuest = true; + + return ( + +