Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const Editor = ({ content }: { content: JSONContent[] | null }) => {
Underline,
Highlight.configure({ multicolor: true }),
TextAlign.configure({
types: ['paragraph', 'image', 'blockquote', 'horizontal_rule'],
types: ['paragraph', 'image', 'blockquote', 'horizontal_rule', 'file'],
}),
Blockquote.configure({
HTMLAttributes: {
Expand Down
52 changes: 52 additions & 0 deletions src/components/editor/common/File.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
export interface FileAttributes {
src: string;
title: string;
}

export const createFileNodeHTML = (attrs: FileAttributes): HTMLElement => {
const fileWrapper = document.createElement('div');
fileWrapper.className =
'flex items-center justify-between p-3 border border-gray-300 rounded-lg shadow-sm bg-white max-w-md';

// 왼쪽 아이콘과 파일 제목
const leftDiv = document.createElement('div');
leftDiv.className = 'flex items-center space-x-2';

const iconSvg = `
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368">
<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" />
</svg>
`;
leftDiv.innerHTML = iconSvg;

const fileTitle = document.createElement('span');
fileTitle.className = 'text-sm font-medium text-gray-800 truncate';
fileTitle.textContent = attrs.title || 'No title';

leftDiv.appendChild(fileTitle);

// 오른쪽 다운로드 아이콘
const rightSpan = document.createElement('span');
rightSpan.className =
'flex items-center justify-center w-8 h-8 text-blue-600 rounded-full transition';

const downloadLink = document.createElement('a');
downloadLink.href = `http://43.200.90.72/file/download/${attrs.src}`;
downloadLink.target = '_blank';
downloadLink.rel = 'noopener noreferrer';

const downloadSvg = `
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor">
<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"/>
</svg>
`;
downloadLink.innerHTML = downloadSvg;

rightSpan.appendChild(downloadLink);

// 전체 구조 결합
fileWrapper.appendChild(leftDiv);
fileWrapper.appendChild(rightSpan);

return fileWrapper;
};
16 changes: 13 additions & 3 deletions src/components/editor/common/extractPaywallData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Editor } from '@tiptap/react';
import { JSONContent } from '@tiptap/core';
import { DOMSerializer } from '@tiptap/pm/model';
import { createFileNodeHTML, FileAttributes } from './File';

interface PaywallData {
isPremium: boolean;
Expand All @@ -25,9 +26,18 @@ const extractPaywallData = (editor: Editor): PaywallData => {
const tempDiv = document.createElement('div');
nodes.forEach((node) => {
try {
const pmNode = schema.nodeFromJSON(node);
const serializedNode = domSerializer.serializeNode(pmNode);
tempDiv.appendChild(serializedNode);
if (node.type === 'file' && node.attrs?.src) {
const fileWrapper = createFileNodeHTML({
src: node.attrs.src,
title: node.attrs.title,
} as FileAttributes);

tempDiv.appendChild(fileWrapper);
} else {
const pmNode = schema.nodeFromJSON(node);
const serializedNode = domSerializer.serializeNode(pmNode);
tempDiv.appendChild(serializedNode);
}
} catch (error) {
console.error('Error converting node to HTML:', error, node);
}
Expand Down
22 changes: 17 additions & 5 deletions src/components/editor/customComponent/CustomFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const CustomFile = Node.create({

group: 'block',
atom: true,

addAttributes() {
return {
src: {
Expand All @@ -18,19 +18,31 @@ const CustomFile = Node.create({
},
};
},

parseHTML() {
return [
{
tag: 'div[data-type="file"]',
},
];
},

renderHTML({ HTMLAttributes }) {
return ['div', mergeAttributes(HTMLAttributes, { 'data-type': 'file' }), ''];
return [
'div',
mergeAttributes(HTMLAttributes, { 'data-type': 'file' }),
[
'a',
{
href: HTMLAttributes.src,
target: '_blank',
rel: 'noopener noreferrer',
},
'Download File',
],
];
},

addNodeView() {
return ReactNodeViewRenderer(FileComponent); // React 컴포넌트와 연결
},
Expand Down
Loading