-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
Feature/#94 기초 마크다운 에디터 구현
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
//# sourceMappingURL=Crdt.d.ts.map |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
//# sourceMappingURL=Interfaces.d.ts.map |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
//# sourceMappingURL=LinkedList.d.ts.map |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
//# sourceMappingURL=Node.d.ts.map |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"program":{"fileNames":["../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.scripthost.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib/lib.es2021.full.d.ts","../crdt.ts","../interfaces.ts","../linkedlist.ts","../node.ts"],"fileInfos":[{"version":"f33e5332b24c3773e930e212cbb8b6867c8ba3ec4492064ea78e55a524d57450","affectsGlobalScope":true},"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","26f2f787e82c4222710f3b676b4d83eb5ad0a72fa7b746f03449e7a026ce5073","9a68c0c07ae2fa71b44384a839b7b8d81662a236d4b9ac30916718f7510b1b2d","5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569",{"version":"21e41a76098aa7a191028256e52a726baafd45a925ea5cf0222eb430c96c1d83","affectsGlobalScope":true},{"version":"35299ae4a62086698444a5aaee27fc7aa377c68cbb90b441c9ace246ffd05c97","affectsGlobalScope":true},{"version":"80e18897e5884b6723488d4f5652167e7bb5024f946743134ecc4aa4ee731f89","affectsGlobalScope":true},{"version":"cd034f499c6cdca722b60c04b5b1b78e058487a7085a8e0d6fb50809947ee573","affectsGlobalScope":true},{"version":"138fb588d26538783b78d1e3b2c2cc12d55840b97bf5e08bca7f7a174fbe2f17","affectsGlobalScope":true},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true},{"version":"4443e68b35f3332f753eacc66a04ac1d2053b8b035a0e0ac1d455392b5e243b3","affectsGlobalScope":true},{"version":"bc47685641087c015972a3f072480889f0d6c65515f12bd85222f49a98952ed7","affectsGlobalScope":true},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true},{"version":"93495ff27b8746f55d19fcbcdbaccc99fd95f19d057aed1bd2c0cafe1335fbf0","affectsGlobalScope":true},{"version":"6fc23bb8c3965964be8c597310a2878b53a0306edb71d4b5a4dfe760186bcc01","affectsGlobalScope":true},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true},{"version":"bb42a7797d996412ecdc5b2787720de477103a0b2e53058569069a0e2bae6c7e","affectsGlobalScope":true},{"version":"4738f2420687fd85629c9efb470793bb753709c2379e5f85bc1815d875ceadcd","affectsGlobalScope":true},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true},{"version":"9fc46429fbe091ac5ad2608c657201eb68b6f1b8341bd6d670047d32ed0a88fa","affectsGlobalScope":true},{"version":"61c37c1de663cf4171e1192466e52c7a382afa58da01b1dc75058f032ddf0839","affectsGlobalScope":true},{"version":"b541a838a13f9234aba650a825393ffc2292dc0fc87681a5d81ef0c96d281e7a","affectsGlobalScope":true},{"version":"e0275cd0e42990dc3a16f0b7c8bca3efe87f1c8ad404f80c6db1c7c0b828c59f","affectsGlobalScope":true},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true},{"version":"49ed889be54031e1044af0ad2c603d627b8bda8b50c1a68435fe85583901d072","affectsGlobalScope":true},{"version":"e93d098658ce4f0c8a0779e6cab91d0259efb88a318137f686ad76f8410ca270","affectsGlobalScope":true},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true},{"version":"bf14a426dbbf1022d11bd08d6b8e709a2e9d246f0c6c1032f3b2edb9a902adbe","affectsGlobalScope":true},{"version":"ec0104fee478075cb5171e5f4e3f23add8e02d845ae0165bfa3f1099241fa2aa","affectsGlobalScope":true},{"version":"2b72d528b2e2fe3c57889ca7baef5e13a56c957b946906d03767c642f386bbc3","affectsGlobalScope":true},{"version":"acae90d417bee324b1372813b5a00829d31c7eb670d299cd7f8f9a648ac05688","affectsGlobalScope":true},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true},{"version":"51e547984877a62227042850456de71a5c45e7fe86b7c975c6e68896c86fa23b","affectsGlobalScope":true},{"version":"62a4966981264d1f04c44eb0f4b5bdc3d81c1a54725608861e44755aa24ad6a5","affectsGlobalScope":true},{"version":"33358442698bb565130f52ba79bfd3d4d484ac85fe33f3cb1759c54d18201393","affectsGlobalScope":true},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true},"c1e8d979afc15d66e2bd5a58c732d5a2ba3ccaae41ac7d5a2c539e6de66a8e51","e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"],"root":[[54,57]],"options":{"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"declarationMap":true,"emitDecoratorMetadata":true,"experimentalDecorators":true,"module":99,"outDir":"./","removeComments":true,"rootDir":"..","skipLibCheck":true,"sourceMap":true,"strict":true,"target":8},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[54,55,56,57,51,52,9,10,14,13,2,15,16,17,18,19,20,21,22,3,4,23,27,24,25,26,28,29,30,5,31,32,33,34,6,38,35,36,37,39,7,40,45,46,41,42,43,44,8,53,50,47,48,49,1,12,11],"latestChangedDtsFile":"./Node.d.ts"},"version":"5.3.3"} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { cva } from "@styled-system/css"; | ||
|
||
// 기본 블록 스타일 | ||
const baseBlockStyle = { | ||
textStyle: "display-medium16", | ||
outline: "none", | ||
borderRadius: "radii.xs", | ||
width: "full", | ||
minHeight: "spacing.lg", | ||
margin: "spacing.sm 0", | ||
padding: "spacing.sm", | ||
color: "gray.900", | ||
backgroundColor: "transparent", | ||
"&:empty::before": { | ||
content: "attr(data-placeholder)", // data-placeholder 속성의 값을 표시 | ||
color: "gray.300", | ||
position: "absolute", | ||
pointerEvents: "none", // 텍스트 선택이나 클릭 방지 | ||
}, | ||
}; | ||
|
||
// 블록 타입별 스타일 variants | ||
export const blockContainerStyle = cva({ | ||
base: baseBlockStyle, | ||
variants: { | ||
type: { | ||
p: { | ||
textStyle: "display-medium16", | ||
fontWeight: "bold", | ||
}, | ||
h1: { | ||
textStyle: "display-medium24", | ||
fontWeight: "bold", | ||
}, | ||
h2: { | ||
textStyle: "display-medium20", | ||
fontWeight: "bold", | ||
}, | ||
h3: { | ||
textStyle: "display-medium16", | ||
fontWeight: "bold", | ||
}, | ||
ul: { | ||
display: "block", | ||
listStyleType: "disc", | ||
listStylePosition: "outside", | ||
}, | ||
ol: { | ||
display: "block", | ||
listStyleType: "decimal", | ||
listStylePosition: "outside", | ||
}, | ||
li: { | ||
textStyle: "display-medium16", | ||
display: "list-item", | ||
outline: "none", | ||
margin: "0", | ||
padding: "0 0 0 16px", | ||
}, | ||
blockquote: { | ||
borderLeft: "4px solid token(colors.gray.300)", | ||
paddingLeft: "spacing.md", | ||
color: "gray.500", | ||
fontStyle: "italic", | ||
}, | ||
checkbox: {}, | ||
}, | ||
isActive: { | ||
true: { | ||
opacity: 0.9, | ||
}, | ||
false: { | ||
backgroundColor: "transparent", | ||
}, | ||
}, | ||
}, | ||
defaultVariants: { | ||
type: "p", | ||
isActive: false, | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import React, { memo } from "react"; | ||
import { EditorNode } from "../../types/markdown"; | ||
import { blockContainerStyle } from "./Block.style"; | ||
|
||
interface BlockProps { | ||
node: EditorNode; | ||
isActive: boolean; | ||
contentRef?: React.RefObject<HTMLDivElement>; | ||
onKeyDown: (e: React.KeyboardEvent) => void; | ||
onCompositionStart: () => void; | ||
onCompositionEnd: () => void; | ||
onInput: (e: React.KeyboardEvent) => void; | ||
onClick: (nodeId: string) => void; | ||
currentNodeId: string; | ||
} | ||
|
||
export const Block: React.FC<BlockProps> = memo( | ||
({ | ||
node, | ||
isActive, | ||
contentRef, | ||
onKeyDown, | ||
onCompositionStart, | ||
onCompositionEnd, | ||
onInput, | ||
onClick, | ||
}: BlockProps) => { | ||
const handleClick = (e: React.MouseEvent) => { | ||
e.preventDefault(); | ||
onClick(node.id); | ||
}; | ||
|
||
const getPlaceholder = (type: string) => { | ||
switch (type) { | ||
case "p": | ||
return "텍스트를 입력하세요 ..."; | ||
case "h1": | ||
return "제목 1"; | ||
case "h2": | ||
return "제목 2"; | ||
case "h3": | ||
return "제목 3"; | ||
case "li": | ||
return "리스트 항목"; | ||
case "blockquote": | ||
return "인용구를 입력하세요"; | ||
default: | ||
return "텍스트를 입력하세요"; | ||
} | ||
}; | ||
|
||
const nodeType = node.type === "checkbox" ? "p" : node.type; | ||
|
||
const commonProps = { | ||
"data-node-id": node.id, | ||
"data-depth": node.depth, | ||
"data-placeholder": getPlaceholder(node.type), | ||
onKeyDown, | ||
onInput, | ||
onCompositionStart, | ||
onCompositionEnd, | ||
onClick: handleClick, | ||
ref: isActive ? contentRef : undefined, | ||
contentEditable: true, | ||
suppressContentEditableWarning: true, | ||
dangerouslySetInnerHTML: { __html: node.content }, | ||
className: blockContainerStyle({ | ||
type: node.type, | ||
isActive, | ||
}), | ||
}; | ||
|
||
return React.createElement(nodeType, commonProps); | ||
}, | ||
); | ||
|
||
// 메모이제이션을 위한 displayName 설정 | ||
Block.displayName = "Block"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { css } from "@styled-system/css"; | ||
|
||
export const editorContainer = css({ | ||
width: "full", | ||
height: "full", // 부모 컴포넌트의 header(60px)를 제외한 높이 | ||
margin: "spacing.lg", // 16px margin | ||
padding: "24px", // 24px padding | ||
overflowY: "auto", // 내용이 많을 경우 스크롤 | ||
_focus: { | ||
outline: "none", | ||
}, | ||
}); | ||
|
||
export const editorTitleContainer = css({ | ||
width: "full", | ||
marginBottom: "30px", | ||
padding: "spacing.sm", | ||
}); | ||
|
||
export const editorTitle = css({ | ||
textStyle: "display-medium28", | ||
outline: "none", | ||
border: "none", | ||
width: "full", | ||
color: "gray.700", | ||
"&::placeholder": { | ||
color: "gray.300", | ||
}, | ||
}); | ||
|
||
export const checkboxContainer = css({ | ||
display: "flex", | ||
gap: "spacing.sm", | ||
flexDirection: "row", | ||
alignItems: "center", | ||
}); | ||
|
||
export const checkbox = css({ | ||
border: "1px solid", | ||
borderColor: "gray.300", | ||
borderRadius: "4px", | ||
width: "16px", | ||
height: "16px", | ||
margin: "0 8px 0 0", | ||
cursor: "pointer", | ||
"&:checked": { | ||
borderColor: "blue.500", | ||
backgroundColor: "blue.500", | ||
}, | ||
}); |