Skip to content

Commit 92aad33

Browse files
authored
Merge pull request #7 from Moaguide-develop/feat/editor
feat: 파일 HTML 변환 추가
2 parents 4b322fb + 2040218 commit 92aad33

File tree

4 files changed

+83
-9
lines changed

4 files changed

+83
-9
lines changed

src/components/editor/Editor.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ const Editor = ({ content }: { content: JSONContent[] | null }) => {
9797
Underline,
9898
Highlight.configure({ multicolor: true }),
9999
TextAlign.configure({
100-
types: ['paragraph', 'image', 'blockquote', 'horizontal_rule'],
100+
types: ['paragraph', 'image', 'blockquote', 'horizontal_rule', 'file'],
101101
}),
102102
Blockquote.configure({
103103
HTMLAttributes: {
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
export interface FileAttributes {
2+
src: string;
3+
title: string;
4+
}
5+
6+
export const createFileNodeHTML = (attrs: FileAttributes): HTMLElement => {
7+
const fileWrapper = document.createElement('div');
8+
fileWrapper.className =
9+
'flex items-center justify-between p-3 border border-gray-300 rounded-lg shadow-sm bg-white max-w-md';
10+
11+
// 왼쪽 아이콘과 파일 제목
12+
const leftDiv = document.createElement('div');
13+
leftDiv.className = 'flex items-center space-x-2';
14+
15+
const iconSvg = `
16+
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368">
17+
<path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640v400q0 33-23.5 56.5T800-160H160Zm0-80h640v-400H447l-80-80H160v480Zm0 0v-480 480Z" />
18+
</svg>
19+
`;
20+
leftDiv.innerHTML = iconSvg;
21+
22+
const fileTitle = document.createElement('span');
23+
fileTitle.className = 'text-sm font-medium text-gray-800 truncate';
24+
fileTitle.textContent = attrs.title || 'No title';
25+
26+
leftDiv.appendChild(fileTitle);
27+
28+
// 오른쪽 다운로드 아이콘
29+
const rightSpan = document.createElement('span');
30+
rightSpan.className =
31+
'flex items-center justify-center w-8 h-8 text-blue-600 rounded-full transition';
32+
33+
const downloadLink = document.createElement('a');
34+
downloadLink.href = `http://43.200.90.72/file/download/${attrs.src}`;
35+
downloadLink.target = '_blank';
36+
downloadLink.rel = 'noopener noreferrer';
37+
38+
const downloadSvg = `
39+
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor">
40+
<path d="M480-320 280-520l56-58 104 104v-326h80v326l104-104 56 58-200 200ZM240-160q-33 0-56.5-23.5T160-240v-120h80v120h480v-120h80v120q0 33-23.5 56.5T720-160H240Z"/>
41+
</svg>
42+
`;
43+
downloadLink.innerHTML = downloadSvg;
44+
45+
rightSpan.appendChild(downloadLink);
46+
47+
// 전체 구조 결합
48+
fileWrapper.appendChild(leftDiv);
49+
fileWrapper.appendChild(rightSpan);
50+
51+
return fileWrapper;
52+
};

src/components/editor/common/extractPaywallData.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Editor } from '@tiptap/react';
22
import { JSONContent } from '@tiptap/core';
33
import { DOMSerializer } from '@tiptap/pm/model';
4+
import { createFileNodeHTML, FileAttributes } from './File';
45

56
interface PaywallData {
67
isPremium: boolean;
@@ -25,9 +26,18 @@ const extractPaywallData = (editor: Editor): PaywallData => {
2526
const tempDiv = document.createElement('div');
2627
nodes.forEach((node) => {
2728
try {
28-
const pmNode = schema.nodeFromJSON(node);
29-
const serializedNode = domSerializer.serializeNode(pmNode);
30-
tempDiv.appendChild(serializedNode);
29+
if (node.type === 'file' && node.attrs?.src) {
30+
const fileWrapper = createFileNodeHTML({
31+
src: node.attrs.src,
32+
title: node.attrs.title,
33+
} as FileAttributes);
34+
35+
tempDiv.appendChild(fileWrapper);
36+
} else {
37+
const pmNode = schema.nodeFromJSON(node);
38+
const serializedNode = domSerializer.serializeNode(pmNode);
39+
tempDiv.appendChild(serializedNode);
40+
}
3141
} catch (error) {
3242
console.error('Error converting node to HTML:', error, node);
3343
}

src/components/editor/customComponent/CustomFile.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const CustomFile = Node.create({
77

88
group: 'block',
99
atom: true,
10-
10+
1111
addAttributes() {
1212
return {
1313
src: {
@@ -18,19 +18,31 @@ const CustomFile = Node.create({
1818
},
1919
};
2020
},
21-
21+
2222
parseHTML() {
2323
return [
2424
{
2525
tag: 'div[data-type="file"]',
2626
},
2727
];
2828
},
29-
29+
3030
renderHTML({ HTMLAttributes }) {
31-
return ['div', mergeAttributes(HTMLAttributes, { 'data-type': 'file' }), ''];
31+
return [
32+
'div',
33+
mergeAttributes(HTMLAttributes, { 'data-type': 'file' }),
34+
[
35+
'a',
36+
{
37+
href: HTMLAttributes.src,
38+
target: '_blank',
39+
rel: 'noopener noreferrer',
40+
},
41+
'Download File',
42+
],
43+
];
3244
},
33-
45+
3446
addNodeView() {
3547
return ReactNodeViewRenderer(FileComponent); // React 컴포넌트와 연결
3648
},

0 commit comments

Comments
 (0)