@tipp/ui-quill-editor 1.3.34 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -111,6 +111,7 @@ function ReadCard(props) {
111
111
  ref.current.style.height = "initial";
112
112
  }
113
113
  },
114
+ size: "small",
114
115
  variant: "outline",
115
116
  children: [
116
117
  "\uBA54\uBAA8 \uD3BC\uCE58\uAE30",
@@ -137,38 +138,62 @@ function ReadCard(props) {
137
138
  return null;
138
139
  };
139
140
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.Card, { size: "2", children: [
140
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.Flex, { align: "center", gap: "2", justify: "between", children: [
141
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.Flex, { align: "center", gap: "4", children: [
142
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Heading, { variant: "heading5", weight: "regular", children: title }),
143
- writer ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Badge, { color: "neutral", size: "small", children: `\uC791\uC131\uC790 : ${writer}` }) : null
144
- ] }),
145
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.Flex, { align: "center", gap: "4", children: [
146
- createAt ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Typo, { children: `\uB4F1\uB85D\uC77C\uC790: ${createAt.toLocaleDateString()} ` }) : null,
147
- optionItems.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.DropdownMenu.Root, { children: [
148
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.DropdownMenu.Trigger, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.IconButton, { variant: "ghost", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.DotsVerticalIcon, {}) }) }),
149
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.DropdownMenu.Content, { children: optionItems.map((item) => {
150
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.DropdownMenu.Item, { onClick: item.onClick, children: [
151
- item.icon,
152
- item.title
153
- ] }, item.title);
154
- }) })
155
- ] }) : null
156
- ] }),
157
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
158
- import_ui.AlertDialog.Root,
141
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.Grid, { columns: "1fr auto", width: "100%", children: [
142
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
143
+ import_ui.Grid,
159
144
  {
160
- onOpenChange: setDeleteDialogOpen,
161
- open: deleteDialogOpen,
162
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.AlertDialog.Content, { children: [
163
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.AlertDialog.Title, { children: "\uB178\uD2B8\uB97C \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?" }),
164
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.AlertDialog.Description, { children: "\uC0AD\uC81C\uB41C \uB178\uD2B8\uB294 \uBCF5\uAD6C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?" }),
165
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.Flex, { gap: "3", justify: "end", children: [
166
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.AlertDialog.Cancel, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Button, { color: "gray", variant: "outline", children: "\uCDE8\uC18C" }) }),
167
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.AlertDialog.Action, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Button, { color: "tomato", onClick: propsOnClickDelete, children: "\uC0AD\uC81C" }) })
168
- ] })
169
- ] })
145
+ align: "center",
146
+ columns: { initial: "1", sm: "auto 1fr" },
147
+ gap: "2",
148
+ width: "100%",
149
+ children: [
150
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Heading, { variant: "heading5", weight: "regular", children: title }),
151
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
152
+ import_ui.Flex,
153
+ {
154
+ align: "center",
155
+ gap: "4",
156
+ justify: { initial: "start", sm: "between" },
157
+ width: "100%",
158
+ children: [
159
+ writer ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Badge, { color: "neutral", size: "small", children: `\uC791\uC131\uC790 : ${writer}` }) : null,
160
+ createAt ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
161
+ import_ui.Typo,
162
+ {
163
+ style: { whiteSpace: "nowrap" },
164
+ children: `\uB4F1\uB85D ${createAt.getFullYear()}.${createAt.getMonth() + 1}.${createAt.getDate()} `
165
+ }
166
+ ) : null
167
+ ]
168
+ }
169
+ ),
170
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
171
+ import_ui.AlertDialog.Root,
172
+ {
173
+ onOpenChange: setDeleteDialogOpen,
174
+ open: deleteDialogOpen,
175
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.AlertDialog.Content, { children: [
176
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.AlertDialog.Title, { children: "\uB178\uD2B8\uB97C \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?" }),
177
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.AlertDialog.Description, { children: "\uC0AD\uC81C\uB41C \uB178\uD2B8\uB294 \uBCF5\uAD6C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?" }),
178
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.Flex, { gap: "3", justify: "end", children: [
179
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.AlertDialog.Cancel, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Button, { color: "gray", variant: "outline", children: "\uCDE8\uC18C" }) }),
180
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.AlertDialog.Action, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Button, { color: "tomato", onClick: propsOnClickDelete, children: "\uC0AD\uC81C" }) })
181
+ ] })
182
+ ] })
183
+ }
184
+ )
185
+ ]
170
186
  }
171
- )
187
+ ),
188
+ optionItems.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.DropdownMenu.Root, { children: [
189
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.DropdownMenu.Trigger, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.IconButton, { ml: "2", mt: "1", variant: "ghost", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.DotsVerticalIcon, {}) }) }),
190
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.DropdownMenu.Content, { children: optionItems.map((item) => {
191
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.DropdownMenu.Item, { onClick: item.onClick, children: [
192
+ item.icon,
193
+ item.title
194
+ ] }, item.title);
195
+ }) })
196
+ ] }) : null
172
197
  ] }),
173
198
  Boolean(files == null ? void 0 : files.length) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Flex, { direction: "column", gap: "1", children: files == null ? void 0 : files.map((file) => {
174
199
  var _a;
@@ -182,16 +207,17 @@ function ReadCard(props) {
182
207
  {
183
208
  mt: "3",
184
209
  size: "4",
185
- style: { width: 400, height: 56 },
210
+ style: { width: "100%", height: 56 },
186
211
  variant: "soft",
187
212
  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.Flex, { gap: "3", pl: "4", width: "100%", children: [
188
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Typo, { color: "gray", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.FileIcon, { height: 20, width: 20 }) }),
213
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Typo, { color: "gray", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.FileIcon, { height: 16, width: 16 }) }),
189
214
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
190
215
  import_ui.Typo,
191
216
  {
192
217
  as: "p",
193
218
  color: "gray",
194
219
  style: { width: "100%", textAlign: "left" },
220
+ variant: "caption",
195
221
  children: file.fileName
196
222
  }
197
223
  )
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/read-card.tsx","../src/html-container.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport Dompurify from 'dompurify';\nimport {\n AlertDialog,\n Badge,\n FileIcon,\n Button,\n Card,\n ChevronDownIcon,\n ChevronUpIcon,\n DotsVerticalIcon,\n Flex,\n Heading,\n IconButton,\n Link,\n Typo,\n Separator,\n DropdownMenu,\n Pencil1Icon,\n TrashIcon,\n} from '@tipp/ui';\nimport QuillHtmlOutputContainer from './html-container';\nimport type { Attachment } from './type';\n\ninterface ReadCardProps {\n onClickDelete?: () => void;\n onClickEdit?: () => void;\n content?: string;\n title?: string;\n writer?: string;\n createAt?: Date;\n files?: Attachment[];\n}\n\nexport function ReadCard(props: ReadCardProps): React.ReactNode {\n const {\n onClickDelete: propsOnClickDelete,\n onClickEdit: propsOnClickEdit,\n content = '',\n title = '',\n writer,\n createAt,\n files,\n } = props;\n const ref = useRef<HTMLDivElement>(null);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n\n const safeContent = useMemo(() => {\n return Dompurify.sanitize(content || '');\n }, [content]);\n\n interface OptionItem {\n title: string;\n icon: React.ReactNode;\n onClick: () => void;\n }\n const optionItems = useMemo<OptionItem[]>(() => {\n const result: OptionItem[] = [];\n if (propsOnClickEdit) {\n result.push({\n title: '수정하기',\n icon: <Pencil1Icon />,\n onClick: propsOnClickEdit,\n });\n }\n\n if (propsOnClickDelete) {\n result.push({\n title: '삭제하기',\n onClick: () => {\n setDeleteDialogOpen(true);\n },\n icon: <TrashIcon />,\n });\n }\n\n return result;\n }, [propsOnClickDelete, propsOnClickEdit]);\n\n const [className, setClassName] = useState<undefined | 'closed'>('closed');\n const [openBtnVisible, setOpenBtnVisible] = useState(false);\n\n useEffect(() => {\n if (!ref.current) return;\n setOpenBtnVisible(ref.current.clientHeight < ref.current.scrollHeight);\n ref.current.style.height = `${ref.current.clientHeight}px`;\n }, [ref, content]);\n\n const renderOpenBtns = (): React.ReactNode => {\n if (openBtnVisible) {\n if (className) {\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName(undefined);\n if (ref.current) {\n ref.current.style.height = 'initial';\n }\n }}\n variant=\"outline\"\n >\n 메모 펼치기\n <ChevronDownIcon />\n </Button>\n );\n }\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName('closed');\n }}\n variant=\"outline\"\n >\n 메모 접기\n <ChevronUpIcon />\n </Button>\n );\n }\n return null;\n };\n\n return (\n <Card size=\"2\">\n <Flex align=\"center\" gap=\"2\" justify=\"between\">\n <Flex align=\"center\" gap=\"4\">\n <Heading variant=\"heading5\" weight=\"regular\">\n {title}\n </Heading>\n {writer ? (\n <Badge color=\"neutral\" size=\"small\">{`작성자 : ${writer}`}</Badge>\n ) : null}\n </Flex>\n\n <Flex align=\"center\" gap=\"4\">\n {createAt ? (\n <Typo>{`등록일자: ${createAt.toLocaleDateString()} `}</Typo>\n ) : null}\n\n {optionItems.length ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton variant=\"ghost\">\n <DotsVerticalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n {optionItems.map((item) => {\n return (\n <DropdownMenu.Item key={item.title} onClick={item.onClick}>\n {item.icon}\n {item.title}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : null}\n </Flex>\n\n <AlertDialog.Root\n onOpenChange={setDeleteDialogOpen}\n open={deleteDialogOpen}\n >\n <AlertDialog.Content>\n <AlertDialog.Title>노트를 삭제하시겠습니까?</AlertDialog.Title>\n <AlertDialog.Description>\n 삭제된 노트는 복구할 수 없습니다. 삭제하시겠습니까?\n </AlertDialog.Description>\n <Flex gap=\"3\" justify=\"end\">\n <AlertDialog.Cancel>\n <Button color=\"gray\" variant=\"outline\">\n 취소\n </Button>\n </AlertDialog.Cancel>\n <AlertDialog.Action>\n <Button color=\"tomato\" onClick={propsOnClickDelete}>\n 삭제\n </Button>\n </AlertDialog.Action>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n </Flex>\n\n {Boolean(files?.length) && (\n <Flex direction=\"column\" gap=\"1\">\n {files?.map((file) => {\n return (\n <Link\n download={file.fileName}\n href={file.url}\n key={file.createdAt?.valueOf() + file.fileName}\n >\n <IconButton\n mt=\"3\"\n size=\"4\"\n style={{ width: 400, height: 56 }}\n variant=\"soft\"\n >\n <Flex gap=\"3\" pl=\"4\" width=\"100%\">\n <Typo color=\"gray\">\n <FileIcon height={20} width={20} />\n </Typo>\n <Typo\n as=\"p\"\n color=\"gray\"\n style={{ width: '100%', textAlign: 'left' }}\n >\n {file.fileName}\n </Typo>\n </Flex>\n </IconButton>\n </Link>\n );\n })}\n </Flex>\n )}\n\n {content ? (\n <>\n <Separator mb=\"4\" mt=\"4\" style={{ width: '100%' }} />\n\n <Flex align=\"center\" direction=\"column\" gap=\"3\">\n <QuillHtmlOutputContainer\n className={className}\n html={safeContent}\n ref={ref}\n />\n {renderOpenBtns()}\n </Flex>\n </>\n ) : null}\n </Card>\n );\n}\n","import React, { forwardRef } from 'react';\n\ninterface QuillHtmlOutputContainerProps {\n html: string;\n className?: string;\n}\n\nconst QuillHtmlOutputContainer = forwardRef<\n HTMLDivElement,\n QuillHtmlOutputContainerProps\n>(({ html, className }, ref): React.ReactNode => {\n return (\n <div className=\"ql-snow ql-container read-mode\">\n <div\n className={`ql-editor ${className || ''}`}\n dangerouslySetInnerHTML={{ __html: html }}\n ref={ref}\n />\n </div>\n );\n});\n\nQuillHtmlOutputContainer.displayName = 'QuillHtmlOutputContainer';\n\nexport default QuillHtmlOutputContainer;\n"],"mappings":"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","names":["import_react","import_jsx_runtime","Dompurify"]}
1
+ {"version":3,"sources":["../src/read-card.tsx","../src/html-container.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport Dompurify from 'dompurify';\nimport {\n AlertDialog,\n Badge,\n FileIcon,\n Button,\n Card,\n ChevronDownIcon,\n ChevronUpIcon,\n DotsVerticalIcon,\n Flex,\n Heading,\n IconButton,\n Link,\n Typo,\n Separator,\n DropdownMenu,\n Pencil1Icon,\n TrashIcon,\n Grid,\n} from '@tipp/ui';\nimport QuillHtmlOutputContainer from './html-container';\nimport type { Attachment } from './type';\n\ninterface ReadCardProps {\n onClickDelete?: () => void;\n onClickEdit?: () => void;\n content?: string;\n title?: string;\n writer?: string;\n createAt?: Date;\n files?: Attachment[];\n}\n\nexport function ReadCard(props: ReadCardProps): React.ReactNode {\n const {\n onClickDelete: propsOnClickDelete,\n onClickEdit: propsOnClickEdit,\n content = '',\n title = '',\n writer,\n createAt,\n files,\n } = props;\n const ref = useRef<HTMLDivElement>(null);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n\n const safeContent = useMemo(() => {\n return Dompurify.sanitize(content || '');\n }, [content]);\n\n interface OptionItem {\n title: string;\n icon: React.ReactNode;\n onClick: () => void;\n }\n const optionItems = useMemo<OptionItem[]>(() => {\n const result: OptionItem[] = [];\n if (propsOnClickEdit) {\n result.push({\n title: '수정하기',\n icon: <Pencil1Icon />,\n onClick: propsOnClickEdit,\n });\n }\n\n if (propsOnClickDelete) {\n result.push({\n title: '삭제하기',\n onClick: () => {\n setDeleteDialogOpen(true);\n },\n icon: <TrashIcon />,\n });\n }\n\n return result;\n }, [propsOnClickDelete, propsOnClickEdit]);\n\n const [className, setClassName] = useState<undefined | 'closed'>('closed');\n const [openBtnVisible, setOpenBtnVisible] = useState(false);\n\n useEffect(() => {\n if (!ref.current) return;\n setOpenBtnVisible(ref.current.clientHeight < ref.current.scrollHeight);\n ref.current.style.height = `${ref.current.clientHeight}px`;\n }, [ref, content]);\n\n const renderOpenBtns = (): React.ReactNode => {\n if (openBtnVisible) {\n if (className) {\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName(undefined);\n if (ref.current) {\n ref.current.style.height = 'initial';\n }\n }}\n size=\"small\"\n variant=\"outline\"\n >\n 메모 펼치기\n <ChevronDownIcon />\n </Button>\n );\n }\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName('closed');\n }}\n variant=\"outline\"\n >\n 메모 접기\n <ChevronUpIcon />\n </Button>\n );\n }\n return null;\n };\n\n return (\n <Card size=\"2\">\n <Grid columns=\"1fr auto\" width=\"100%\">\n <Grid\n align=\"center\"\n columns={{ initial: '1', sm: 'auto 1fr' }}\n gap=\"2\"\n width=\"100%\"\n >\n <Heading variant=\"heading5\" weight=\"regular\">\n {title}\n </Heading>\n\n <Flex\n align=\"center\"\n gap=\"4\"\n justify={{ initial: 'start', sm: 'between' }}\n width=\"100%\"\n >\n {writer ? (\n <Badge color=\"neutral\" size=\"small\">{`작성자 : ${writer}`}</Badge>\n ) : null}\n {createAt ? (\n <Typo\n style={{ whiteSpace: 'nowrap' }}\n >{`등록 ${createAt.getFullYear()}.${createAt.getMonth() + 1}.${createAt.getDate()} `}</Typo>\n ) : null}\n </Flex>\n\n <AlertDialog.Root\n onOpenChange={setDeleteDialogOpen}\n open={deleteDialogOpen}\n >\n <AlertDialog.Content>\n <AlertDialog.Title>노트를 삭제하시겠습니까?</AlertDialog.Title>\n <AlertDialog.Description>\n 삭제된 노트는 복구할 수 없습니다. 삭제하시겠습니까?\n </AlertDialog.Description>\n <Flex gap=\"3\" justify=\"end\">\n <AlertDialog.Cancel>\n <Button color=\"gray\" variant=\"outline\">\n 취소\n </Button>\n </AlertDialog.Cancel>\n <AlertDialog.Action>\n <Button color=\"tomato\" onClick={propsOnClickDelete}>\n 삭제\n </Button>\n </AlertDialog.Action>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n </Grid>\n\n {/* ... 옵션 버튼 */}\n {optionItems.length ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton ml=\"2\" mt=\"1\" variant=\"ghost\">\n <DotsVerticalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n {optionItems.map((item) => {\n return (\n <DropdownMenu.Item key={item.title} onClick={item.onClick}>\n {item.icon}\n {item.title}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : null}\n </Grid>\n\n {Boolean(files?.length) && (\n <Flex direction=\"column\" gap=\"1\">\n {files?.map((file) => {\n return (\n <Link\n download={file.fileName}\n href={file.url}\n key={file.createdAt?.valueOf() + file.fileName}\n >\n <IconButton\n mt=\"3\"\n size=\"4\"\n style={{ width: '100%', height: 56 }}\n variant=\"soft\"\n >\n <Flex gap=\"3\" pl=\"4\" width=\"100%\">\n <Typo color=\"gray\">\n <FileIcon height={16} width={16} />\n </Typo>\n <Typo\n as=\"p\"\n color=\"gray\"\n style={{ width: '100%', textAlign: 'left' }}\n variant=\"caption\"\n >\n {file.fileName}\n </Typo>\n </Flex>\n </IconButton>\n </Link>\n );\n })}\n </Flex>\n )}\n\n {content ? (\n <>\n <Separator mb=\"4\" mt=\"4\" style={{ width: '100%' }} />\n\n <Flex align=\"center\" direction=\"column\" gap=\"3\">\n <QuillHtmlOutputContainer\n className={className}\n html={safeContent}\n ref={ref}\n />\n {renderOpenBtns()}\n </Flex>\n </>\n ) : null}\n </Card>\n );\n}\n","import React, { forwardRef } from 'react';\n\ninterface QuillHtmlOutputContainerProps {\n html: string;\n className?: string;\n}\n\nconst QuillHtmlOutputContainer = forwardRef<\n HTMLDivElement,\n QuillHtmlOutputContainerProps\n>(({ html, className }, ref): React.ReactNode => {\n return (\n <div className=\"ql-snow ql-container read-mode\">\n <div\n className={`ql-editor ${className || ''}`}\n dangerouslySetInnerHTML={{ __html: html }}\n ref={ref}\n />\n </div>\n );\n});\n\nQuillHtmlOutputContainer.displayName = 'QuillHtmlOutputContainer';\n\nexport default QuillHtmlOutputContainer;\n"],"mappings":"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","names":["import_react","import_jsx_runtime","Dompurify"]}
package/dist/read-card.js CHANGED
@@ -23,7 +23,8 @@ import {
23
23
  Separator,
24
24
  DropdownMenu,
25
25
  Pencil1Icon,
26
- TrashIcon
26
+ TrashIcon,
27
+ Grid
27
28
  } from "@tipp/ui";
28
29
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
29
30
  function ReadCard(props) {
@@ -82,6 +83,7 @@ function ReadCard(props) {
82
83
  ref.current.style.height = "initial";
83
84
  }
84
85
  },
86
+ size: "small",
85
87
  variant: "outline",
86
88
  children: [
87
89
  "\uBA54\uBAA8 \uD3BC\uCE58\uAE30",
@@ -108,38 +110,62 @@ function ReadCard(props) {
108
110
  return null;
109
111
  };
110
112
  return /* @__PURE__ */ jsxs(Card, { size: "2", children: [
111
- /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "2", justify: "between", children: [
112
- /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "4", children: [
113
- /* @__PURE__ */ jsx(Heading, { variant: "heading5", weight: "regular", children: title }),
114
- writer ? /* @__PURE__ */ jsx(Badge, { color: "neutral", size: "small", children: `\uC791\uC131\uC790 : ${writer}` }) : null
115
- ] }),
116
- /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "4", children: [
117
- createAt ? /* @__PURE__ */ jsx(Typo, { children: `\uB4F1\uB85D\uC77C\uC790: ${createAt.toLocaleDateString()} ` }) : null,
118
- optionItems.length ? /* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [
119
- /* @__PURE__ */ jsx(DropdownMenu.Trigger, { children: /* @__PURE__ */ jsx(IconButton, { variant: "ghost", children: /* @__PURE__ */ jsx(DotsVerticalIcon, {}) }) }),
120
- /* @__PURE__ */ jsx(DropdownMenu.Content, { children: optionItems.map((item) => {
121
- return /* @__PURE__ */ jsxs(DropdownMenu.Item, { onClick: item.onClick, children: [
122
- item.icon,
123
- item.title
124
- ] }, item.title);
125
- }) })
126
- ] }) : null
127
- ] }),
128
- /* @__PURE__ */ jsx(
129
- AlertDialog.Root,
113
+ /* @__PURE__ */ jsxs(Grid, { columns: "1fr auto", width: "100%", children: [
114
+ /* @__PURE__ */ jsxs(
115
+ Grid,
130
116
  {
131
- onOpenChange: setDeleteDialogOpen,
132
- open: deleteDialogOpen,
133
- children: /* @__PURE__ */ jsxs(AlertDialog.Content, { children: [
134
- /* @__PURE__ */ jsx(AlertDialog.Title, { children: "\uB178\uD2B8\uB97C \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?" }),
135
- /* @__PURE__ */ jsx(AlertDialog.Description, { children: "\uC0AD\uC81C\uB41C \uB178\uD2B8\uB294 \uBCF5\uAD6C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?" }),
136
- /* @__PURE__ */ jsxs(Flex, { gap: "3", justify: "end", children: [
137
- /* @__PURE__ */ jsx(AlertDialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { color: "gray", variant: "outline", children: "\uCDE8\uC18C" }) }),
138
- /* @__PURE__ */ jsx(AlertDialog.Action, { children: /* @__PURE__ */ jsx(Button, { color: "tomato", onClick: propsOnClickDelete, children: "\uC0AD\uC81C" }) })
139
- ] })
140
- ] })
117
+ align: "center",
118
+ columns: { initial: "1", sm: "auto 1fr" },
119
+ gap: "2",
120
+ width: "100%",
121
+ children: [
122
+ /* @__PURE__ */ jsx(Heading, { variant: "heading5", weight: "regular", children: title }),
123
+ /* @__PURE__ */ jsxs(
124
+ Flex,
125
+ {
126
+ align: "center",
127
+ gap: "4",
128
+ justify: { initial: "start", sm: "between" },
129
+ width: "100%",
130
+ children: [
131
+ writer ? /* @__PURE__ */ jsx(Badge, { color: "neutral", size: "small", children: `\uC791\uC131\uC790 : ${writer}` }) : null,
132
+ createAt ? /* @__PURE__ */ jsx(
133
+ Typo,
134
+ {
135
+ style: { whiteSpace: "nowrap" },
136
+ children: `\uB4F1\uB85D ${createAt.getFullYear()}.${createAt.getMonth() + 1}.${createAt.getDate()} `
137
+ }
138
+ ) : null
139
+ ]
140
+ }
141
+ ),
142
+ /* @__PURE__ */ jsx(
143
+ AlertDialog.Root,
144
+ {
145
+ onOpenChange: setDeleteDialogOpen,
146
+ open: deleteDialogOpen,
147
+ children: /* @__PURE__ */ jsxs(AlertDialog.Content, { children: [
148
+ /* @__PURE__ */ jsx(AlertDialog.Title, { children: "\uB178\uD2B8\uB97C \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?" }),
149
+ /* @__PURE__ */ jsx(AlertDialog.Description, { children: "\uC0AD\uC81C\uB41C \uB178\uD2B8\uB294 \uBCF5\uAD6C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?" }),
150
+ /* @__PURE__ */ jsxs(Flex, { gap: "3", justify: "end", children: [
151
+ /* @__PURE__ */ jsx(AlertDialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { color: "gray", variant: "outline", children: "\uCDE8\uC18C" }) }),
152
+ /* @__PURE__ */ jsx(AlertDialog.Action, { children: /* @__PURE__ */ jsx(Button, { color: "tomato", onClick: propsOnClickDelete, children: "\uC0AD\uC81C" }) })
153
+ ] })
154
+ ] })
155
+ }
156
+ )
157
+ ]
141
158
  }
142
- )
159
+ ),
160
+ optionItems.length ? /* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [
161
+ /* @__PURE__ */ jsx(DropdownMenu.Trigger, { children: /* @__PURE__ */ jsx(IconButton, { ml: "2", mt: "1", variant: "ghost", children: /* @__PURE__ */ jsx(DotsVerticalIcon, {}) }) }),
162
+ /* @__PURE__ */ jsx(DropdownMenu.Content, { children: optionItems.map((item) => {
163
+ return /* @__PURE__ */ jsxs(DropdownMenu.Item, { onClick: item.onClick, children: [
164
+ item.icon,
165
+ item.title
166
+ ] }, item.title);
167
+ }) })
168
+ ] }) : null
143
169
  ] }),
144
170
  Boolean(files == null ? void 0 : files.length) && /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "1", children: files == null ? void 0 : files.map((file) => {
145
171
  var _a;
@@ -153,16 +179,17 @@ function ReadCard(props) {
153
179
  {
154
180
  mt: "3",
155
181
  size: "4",
156
- style: { width: 400, height: 56 },
182
+ style: { width: "100%", height: 56 },
157
183
  variant: "soft",
158
184
  children: /* @__PURE__ */ jsxs(Flex, { gap: "3", pl: "4", width: "100%", children: [
159
- /* @__PURE__ */ jsx(Typo, { color: "gray", children: /* @__PURE__ */ jsx(FileIcon, { height: 20, width: 20 }) }),
185
+ /* @__PURE__ */ jsx(Typo, { color: "gray", children: /* @__PURE__ */ jsx(FileIcon, { height: 16, width: 16 }) }),
160
186
  /* @__PURE__ */ jsx(
161
187
  Typo,
162
188
  {
163
189
  as: "p",
164
190
  color: "gray",
165
191
  style: { width: "100%", textAlign: "left" },
192
+ variant: "caption",
166
193
  children: file.fileName
167
194
  }
168
195
  )
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/read-card.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport Dompurify from 'dompurify';\nimport {\n AlertDialog,\n Badge,\n FileIcon,\n Button,\n Card,\n ChevronDownIcon,\n ChevronUpIcon,\n DotsVerticalIcon,\n Flex,\n Heading,\n IconButton,\n Link,\n Typo,\n Separator,\n DropdownMenu,\n Pencil1Icon,\n TrashIcon,\n} from '@tipp/ui';\nimport QuillHtmlOutputContainer from './html-container';\nimport type { Attachment } from './type';\n\ninterface ReadCardProps {\n onClickDelete?: () => void;\n onClickEdit?: () => void;\n content?: string;\n title?: string;\n writer?: string;\n createAt?: Date;\n files?: Attachment[];\n}\n\nexport function ReadCard(props: ReadCardProps): React.ReactNode {\n const {\n onClickDelete: propsOnClickDelete,\n onClickEdit: propsOnClickEdit,\n content = '',\n title = '',\n writer,\n createAt,\n files,\n } = props;\n const ref = useRef<HTMLDivElement>(null);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n\n const safeContent = useMemo(() => {\n return Dompurify.sanitize(content || '');\n }, [content]);\n\n interface OptionItem {\n title: string;\n icon: React.ReactNode;\n onClick: () => void;\n }\n const optionItems = useMemo<OptionItem[]>(() => {\n const result: OptionItem[] = [];\n if (propsOnClickEdit) {\n result.push({\n title: '수정하기',\n icon: <Pencil1Icon />,\n onClick: propsOnClickEdit,\n });\n }\n\n if (propsOnClickDelete) {\n result.push({\n title: '삭제하기',\n onClick: () => {\n setDeleteDialogOpen(true);\n },\n icon: <TrashIcon />,\n });\n }\n\n return result;\n }, [propsOnClickDelete, propsOnClickEdit]);\n\n const [className, setClassName] = useState<undefined | 'closed'>('closed');\n const [openBtnVisible, setOpenBtnVisible] = useState(false);\n\n useEffect(() => {\n if (!ref.current) return;\n setOpenBtnVisible(ref.current.clientHeight < ref.current.scrollHeight);\n ref.current.style.height = `${ref.current.clientHeight}px`;\n }, [ref, content]);\n\n const renderOpenBtns = (): React.ReactNode => {\n if (openBtnVisible) {\n if (className) {\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName(undefined);\n if (ref.current) {\n ref.current.style.height = 'initial';\n }\n }}\n variant=\"outline\"\n >\n 메모 펼치기\n <ChevronDownIcon />\n </Button>\n );\n }\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName('closed');\n }}\n variant=\"outline\"\n >\n 메모 접기\n <ChevronUpIcon />\n </Button>\n );\n }\n return null;\n };\n\n return (\n <Card size=\"2\">\n <Flex align=\"center\" gap=\"2\" justify=\"between\">\n <Flex align=\"center\" gap=\"4\">\n <Heading variant=\"heading5\" weight=\"regular\">\n {title}\n </Heading>\n {writer ? (\n <Badge color=\"neutral\" size=\"small\">{`작성자 : ${writer}`}</Badge>\n ) : null}\n </Flex>\n\n <Flex align=\"center\" gap=\"4\">\n {createAt ? (\n <Typo>{`등록일자: ${createAt.toLocaleDateString()} `}</Typo>\n ) : null}\n\n {optionItems.length ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton variant=\"ghost\">\n <DotsVerticalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n {optionItems.map((item) => {\n return (\n <DropdownMenu.Item key={item.title} onClick={item.onClick}>\n {item.icon}\n {item.title}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : null}\n </Flex>\n\n <AlertDialog.Root\n onOpenChange={setDeleteDialogOpen}\n open={deleteDialogOpen}\n >\n <AlertDialog.Content>\n <AlertDialog.Title>노트를 삭제하시겠습니까?</AlertDialog.Title>\n <AlertDialog.Description>\n 삭제된 노트는 복구할 수 없습니다. 삭제하시겠습니까?\n </AlertDialog.Description>\n <Flex gap=\"3\" justify=\"end\">\n <AlertDialog.Cancel>\n <Button color=\"gray\" variant=\"outline\">\n 취소\n </Button>\n </AlertDialog.Cancel>\n <AlertDialog.Action>\n <Button color=\"tomato\" onClick={propsOnClickDelete}>\n 삭제\n </Button>\n </AlertDialog.Action>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n </Flex>\n\n {Boolean(files?.length) && (\n <Flex direction=\"column\" gap=\"1\">\n {files?.map((file) => {\n return (\n <Link\n download={file.fileName}\n href={file.url}\n key={file.createdAt?.valueOf() + file.fileName}\n >\n <IconButton\n mt=\"3\"\n size=\"4\"\n style={{ width: 400, height: 56 }}\n variant=\"soft\"\n >\n <Flex gap=\"3\" pl=\"4\" width=\"100%\">\n <Typo color=\"gray\">\n <FileIcon height={20} width={20} />\n </Typo>\n <Typo\n as=\"p\"\n color=\"gray\"\n style={{ width: '100%', textAlign: 'left' }}\n >\n {file.fileName}\n </Typo>\n </Flex>\n </IconButton>\n </Link>\n );\n })}\n </Flex>\n )}\n\n {content ? (\n <>\n <Separator mb=\"4\" mt=\"4\" style={{ width: '100%' }} />\n\n <Flex align=\"center\" direction=\"column\" gap=\"3\">\n <QuillHtmlOutputContainer\n className={className}\n html={safeContent}\n ref={ref}\n />\n {renderOpenBtns()}\n </Flex>\n </>\n ) : null}\n </Card>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/read-card.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport Dompurify from 'dompurify';\nimport {\n AlertDialog,\n Badge,\n FileIcon,\n Button,\n Card,\n ChevronDownIcon,\n ChevronUpIcon,\n DotsVerticalIcon,\n Flex,\n Heading,\n IconButton,\n Link,\n Typo,\n Separator,\n DropdownMenu,\n Pencil1Icon,\n TrashIcon,\n Grid,\n} from '@tipp/ui';\nimport QuillHtmlOutputContainer from './html-container';\nimport type { Attachment } from './type';\n\ninterface ReadCardProps {\n onClickDelete?: () => void;\n onClickEdit?: () => void;\n content?: string;\n title?: string;\n writer?: string;\n createAt?: Date;\n files?: Attachment[];\n}\n\nexport function ReadCard(props: ReadCardProps): React.ReactNode {\n const {\n onClickDelete: propsOnClickDelete,\n onClickEdit: propsOnClickEdit,\n content = '',\n title = '',\n writer,\n createAt,\n files,\n } = props;\n const ref = useRef<HTMLDivElement>(null);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n\n const safeContent = useMemo(() => {\n return Dompurify.sanitize(content || '');\n }, [content]);\n\n interface OptionItem {\n title: string;\n icon: React.ReactNode;\n onClick: () => void;\n }\n const optionItems = useMemo<OptionItem[]>(() => {\n const result: OptionItem[] = [];\n if (propsOnClickEdit) {\n result.push({\n title: '수정하기',\n icon: <Pencil1Icon />,\n onClick: propsOnClickEdit,\n });\n }\n\n if (propsOnClickDelete) {\n result.push({\n title: '삭제하기',\n onClick: () => {\n setDeleteDialogOpen(true);\n },\n icon: <TrashIcon />,\n });\n }\n\n return result;\n }, [propsOnClickDelete, propsOnClickEdit]);\n\n const [className, setClassName] = useState<undefined | 'closed'>('closed');\n const [openBtnVisible, setOpenBtnVisible] = useState(false);\n\n useEffect(() => {\n if (!ref.current) return;\n setOpenBtnVisible(ref.current.clientHeight < ref.current.scrollHeight);\n ref.current.style.height = `${ref.current.clientHeight}px`;\n }, [ref, content]);\n\n const renderOpenBtns = (): React.ReactNode => {\n if (openBtnVisible) {\n if (className) {\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName(undefined);\n if (ref.current) {\n ref.current.style.height = 'initial';\n }\n }}\n size=\"small\"\n variant=\"outline\"\n >\n 메모 펼치기\n <ChevronDownIcon />\n </Button>\n );\n }\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName('closed');\n }}\n variant=\"outline\"\n >\n 메모 접기\n <ChevronUpIcon />\n </Button>\n );\n }\n return null;\n };\n\n return (\n <Card size=\"2\">\n <Grid columns=\"1fr auto\" width=\"100%\">\n <Grid\n align=\"center\"\n columns={{ initial: '1', sm: 'auto 1fr' }}\n gap=\"2\"\n width=\"100%\"\n >\n <Heading variant=\"heading5\" weight=\"regular\">\n {title}\n </Heading>\n\n <Flex\n align=\"center\"\n gap=\"4\"\n justify={{ initial: 'start', sm: 'between' }}\n width=\"100%\"\n >\n {writer ? (\n <Badge color=\"neutral\" size=\"small\">{`작성자 : ${writer}`}</Badge>\n ) : null}\n {createAt ? (\n <Typo\n style={{ whiteSpace: 'nowrap' }}\n >{`등록 ${createAt.getFullYear()}.${createAt.getMonth() + 1}.${createAt.getDate()} `}</Typo>\n ) : null}\n </Flex>\n\n <AlertDialog.Root\n onOpenChange={setDeleteDialogOpen}\n open={deleteDialogOpen}\n >\n <AlertDialog.Content>\n <AlertDialog.Title>노트를 삭제하시겠습니까?</AlertDialog.Title>\n <AlertDialog.Description>\n 삭제된 노트는 복구할 수 없습니다. 삭제하시겠습니까?\n </AlertDialog.Description>\n <Flex gap=\"3\" justify=\"end\">\n <AlertDialog.Cancel>\n <Button color=\"gray\" variant=\"outline\">\n 취소\n </Button>\n </AlertDialog.Cancel>\n <AlertDialog.Action>\n <Button color=\"tomato\" onClick={propsOnClickDelete}>\n 삭제\n </Button>\n </AlertDialog.Action>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n </Grid>\n\n {/* ... 옵션 버튼 */}\n {optionItems.length ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton ml=\"2\" mt=\"1\" variant=\"ghost\">\n <DotsVerticalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n {optionItems.map((item) => {\n return (\n <DropdownMenu.Item key={item.title} onClick={item.onClick}>\n {item.icon}\n {item.title}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : null}\n </Grid>\n\n {Boolean(files?.length) && (\n <Flex direction=\"column\" gap=\"1\">\n {files?.map((file) => {\n return (\n <Link\n download={file.fileName}\n href={file.url}\n key={file.createdAt?.valueOf() + file.fileName}\n >\n <IconButton\n mt=\"3\"\n size=\"4\"\n style={{ width: '100%', height: 56 }}\n variant=\"soft\"\n >\n <Flex gap=\"3\" pl=\"4\" width=\"100%\">\n <Typo color=\"gray\">\n <FileIcon height={16} width={16} />\n </Typo>\n <Typo\n as=\"p\"\n color=\"gray\"\n style={{ width: '100%', textAlign: 'left' }}\n variant=\"caption\"\n >\n {file.fileName}\n </Typo>\n </Flex>\n </IconButton>\n </Link>\n );\n })}\n </Flex>\n )}\n\n {content ? (\n <>\n <Separator mb=\"4\" mt=\"4\" style={{ width: '100%' }} />\n\n <Flex align=\"center\" direction=\"column\" gap=\"3\">\n <QuillHtmlOutputContainer\n className={className}\n html={safeContent}\n ref={ref}\n />\n {renderOpenBtns()}\n </Flex>\n </>\n ) : null}\n </Card>\n );\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tipp/ui-quill-editor",
3
- "version": "1.3.34",
3
+ "version": "1.4.0",
4
4
  "private": false,
5
5
  "description": "tipp 디자인 시스템이 적용된 quillEditor 패키지, quillEditor의 사이즈가 커서 별도 패키지로 분리했습니다.",
6
6
  "sideEffects": false,
@@ -40,7 +40,7 @@
40
40
  "react": "^18.3.1",
41
41
  "react-dom": "^18.3.1",
42
42
  "react-quill": "^2.0.0",
43
- "@tipp/ui": "1.4.26"
43
+ "@tipp/ui": "1.5.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/dompurify": "^3.0.5",
@@ -58,8 +58,8 @@
58
58
  "postcss-nesting": "12.0.2",
59
59
  "tsup": "^8.0.2",
60
60
  "typescript": "^5.3.3",
61
- "@tipp/eslint-config": "1.0.0",
62
- "@tipp/typescript-config": "1.0.0"
61
+ "@tipp/typescript-config": "1.0.1",
62
+ "@tipp/eslint-config": "1.0.1"
63
63
  },
64
64
  "scripts": {
65
65
  "build": "pnpm run build:js && pnpm run build:css",
package/src/read-card.tsx CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  DropdownMenu,
19
19
  Pencil1Icon,
20
20
  TrashIcon,
21
+ Grid,
21
22
  } from '@tipp/ui';
22
23
  import QuillHtmlOutputContainer from './html-container';
23
24
  import type { Attachment } from './type';
@@ -98,6 +99,7 @@ export function ReadCard(props: ReadCardProps): React.ReactNode {
98
99
  ref.current.style.height = 'initial';
99
100
  }
100
101
  }}
102
+ size="small"
101
103
  variant="outline"
102
104
  >
103
105
  메모 펼치기
@@ -123,66 +125,79 @@ export function ReadCard(props: ReadCardProps): React.ReactNode {
123
125
 
124
126
  return (
125
127
  <Card size="2">
126
- <Flex align="center" gap="2" justify="between">
127
- <Flex align="center" gap="4">
128
+ <Grid columns="1fr auto" width="100%">
129
+ <Grid
130
+ align="center"
131
+ columns={{ initial: '1', sm: 'auto 1fr' }}
132
+ gap="2"
133
+ width="100%"
134
+ >
128
135
  <Heading variant="heading5" weight="regular">
129
136
  {title}
130
137
  </Heading>
131
- {writer ? (
132
- <Badge color="neutral" size="small">{`작성자 : ${writer}`}</Badge>
133
- ) : null}
134
- </Flex>
135
-
136
- <Flex align="center" gap="4">
137
- {createAt ? (
138
- <Typo>{`등록일자: ${createAt.toLocaleDateString()} `}</Typo>
139
- ) : null}
140
138
 
141
- {optionItems.length ? (
142
- <DropdownMenu.Root>
143
- <DropdownMenu.Trigger>
144
- <IconButton variant="ghost">
145
- <DotsVerticalIcon />
146
- </IconButton>
147
- </DropdownMenu.Trigger>
148
- <DropdownMenu.Content>
149
- {optionItems.map((item) => {
150
- return (
151
- <DropdownMenu.Item key={item.title} onClick={item.onClick}>
152
- {item.icon}
153
- {item.title}
154
- </DropdownMenu.Item>
155
- );
156
- })}
157
- </DropdownMenu.Content>
158
- </DropdownMenu.Root>
159
- ) : null}
160
- </Flex>
139
+ <Flex
140
+ align="center"
141
+ gap="4"
142
+ justify={{ initial: 'start', sm: 'between' }}
143
+ width="100%"
144
+ >
145
+ {writer ? (
146
+ <Badge color="neutral" size="small">{`작성자 : ${writer}`}</Badge>
147
+ ) : null}
148
+ {createAt ? (
149
+ <Typo
150
+ style={{ whiteSpace: 'nowrap' }}
151
+ >{`등록 ${createAt.getFullYear()}.${createAt.getMonth() + 1}.${createAt.getDate()} `}</Typo>
152
+ ) : null}
153
+ </Flex>
161
154
 
162
- <AlertDialog.Root
163
- onOpenChange={setDeleteDialogOpen}
164
- open={deleteDialogOpen}
165
- >
166
- <AlertDialog.Content>
167
- <AlertDialog.Title>노트를 삭제하시겠습니까?</AlertDialog.Title>
168
- <AlertDialog.Description>
169
- 삭제된 노트는 복구할 수 없습니다. 삭제하시겠습니까?
170
- </AlertDialog.Description>
171
- <Flex gap="3" justify="end">
172
- <AlertDialog.Cancel>
173
- <Button color="gray" variant="outline">
174
- 취소
175
- </Button>
176
- </AlertDialog.Cancel>
177
- <AlertDialog.Action>
178
- <Button color="tomato" onClick={propsOnClickDelete}>
179
- 삭제
180
- </Button>
181
- </AlertDialog.Action>
182
- </Flex>
183
- </AlertDialog.Content>
184
- </AlertDialog.Root>
185
- </Flex>
155
+ <AlertDialog.Root
156
+ onOpenChange={setDeleteDialogOpen}
157
+ open={deleteDialogOpen}
158
+ >
159
+ <AlertDialog.Content>
160
+ <AlertDialog.Title>노트를 삭제하시겠습니까?</AlertDialog.Title>
161
+ <AlertDialog.Description>
162
+ 삭제된 노트는 복구할 수 없습니다. 삭제하시겠습니까?
163
+ </AlertDialog.Description>
164
+ <Flex gap="3" justify="end">
165
+ <AlertDialog.Cancel>
166
+ <Button color="gray" variant="outline">
167
+ 취소
168
+ </Button>
169
+ </AlertDialog.Cancel>
170
+ <AlertDialog.Action>
171
+ <Button color="tomato" onClick={propsOnClickDelete}>
172
+ 삭제
173
+ </Button>
174
+ </AlertDialog.Action>
175
+ </Flex>
176
+ </AlertDialog.Content>
177
+ </AlertDialog.Root>
178
+ </Grid>
179
+
180
+ {/* ... 옵션 버튼 */}
181
+ {optionItems.length ? (
182
+ <DropdownMenu.Root>
183
+ <DropdownMenu.Trigger>
184
+ <IconButton ml="2" mt="1" variant="ghost">
185
+ <DotsVerticalIcon />
186
+ </IconButton>
187
+ </DropdownMenu.Trigger>
188
+ <DropdownMenu.Content>
189
+ {optionItems.map((item) => {
190
+ return (
191
+ <DropdownMenu.Item key={item.title} onClick={item.onClick}>
192
+ {item.icon}
193
+ {item.title}
194
+ </DropdownMenu.Item>
195
+ );
196
+ })}
197
+ </DropdownMenu.Content>
198
+ </DropdownMenu.Root>
199
+ ) : null}
200
+ </Grid>
186
201
 
187
202
  {Boolean(files?.length) && (
188
203
  <Flex direction="column" gap="1">
@@ -196,17 +211,18 @@ export function ReadCard(props: ReadCardProps): React.ReactNode {
196
211
  <IconButton
197
212
  mt="3"
198
213
  size="4"
199
- style={{ width: 400, height: 56 }}
214
+ style={{ width: '100%', height: 56 }}
200
215
  variant="soft"
201
216
  >
202
217
  <Flex gap="3" pl="4" width="100%">
203
218
  <Typo color="gray">
204
- <FileIcon height={20} width={20} />
219
+ <FileIcon height={16} width={16} />
205
220
  </Typo>
206
221
  <Typo
207
222
  as="p"
208
223
  color="gray"
209
224
  style={{ width: '100%', textAlign: 'left' }}
225
+ variant="caption"
210
226
  >
211
227
  {file.fileName}
212
228
  </Typo>