diff --git a/src/components/editor/common/File.ts b/src/components/editor/common/File.ts index 66f1c7a..6d5b8e5 100644 --- a/src/components/editor/common/File.ts +++ b/src/components/editor/common/File.ts @@ -1,12 +1,12 @@ export interface FileAttributes { src: string; title: string; + alignment: string; } - +const API_URL = import.meta.env.VITE_API_KEY; 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'; + fileWrapper.className = `${attrs.alignment} mt-[30px] flex items-center justify-between p-3 border border-gray-300 shadow-sm bg-white max-w-md`; const leftDiv = document.createElement('div'); leftDiv.className = 'flex items-center space-x-2'; @@ -29,7 +29,7 @@ export const createFileNodeHTML = (attrs: FileAttributes): HTMLElement => { '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.href = `${API_URL}file/download/${attrs.src}`; downloadLink.target = '_blank'; downloadLink.rel = 'noopener noreferrer'; diff --git a/src/components/editor/common/extractPaywallData.ts b/src/components/editor/common/extractPaywallData.ts index 11722a4..ed27a5d 100644 --- a/src/components/editor/common/extractPaywallData.ts +++ b/src/components/editor/common/extractPaywallData.ts @@ -2,6 +2,7 @@ import { Editor } from '@tiptap/react'; import { JSONContent } from '@tiptap/core'; import { DOMSerializer } from '@tiptap/pm/model'; import { createFileNodeHTML, FileAttributes } from './File'; +import { createLinkNodeHTML, LinkAttributes } from './link'; interface PaywallData { isPremium: boolean; @@ -30,9 +31,22 @@ const extractPaywallData = (editor: Editor): PaywallData => { const fileWrapper = createFileNodeHTML({ src: node.attrs.src, title: node.attrs.title, + alignment: node.attrs.alignment, } as FileAttributes); tempDiv.appendChild(fileWrapper); + } else if ( + ['link', 'oglink', 'verticalLink'].includes(node.type) && + node.attrs?.url + ) { + const linkElement = createLinkNodeHTML({ + thumbnail: node.attrs.thumbnail, + title: node.attrs.title, + summary: node.attrs.summary, + url: node.attrs.url, + alignment: node.attrs.alignment, + } as LinkAttributes); + tempDiv.appendChild(linkElement); } else { const pmNode = schema.nodeFromJSON(node); const serializedNode = domSerializer.serializeNode(pmNode); diff --git a/src/components/editor/common/link.ts b/src/components/editor/common/link.ts new file mode 100644 index 0000000..5b8f4eb --- /dev/null +++ b/src/components/editor/common/link.ts @@ -0,0 +1,73 @@ +export interface LinkAttributes { + thumbnail?: string; + title: string; + summary: string; + url: string; + alignment: string; +} + +export const createLinkNodeHTML = (attrs: LinkAttributes): HTMLElement => { + const linkWrapper = document.createElement('div'); + + const alignmentClass = attrs.alignment; + linkWrapper.className = `mt-10 max-w-[490px] w-full relative border border-black/10 shadow-md ${alignmentClass}`; + + let formattedUrl = attrs.url.trim(); + if ( + !formattedUrl.startsWith('https://') && + !formattedUrl.startsWith('http://') + ) { + formattedUrl = 'https://' + formattedUrl; + } + + if (attrs.thumbnail) { + const imageLink = document.createElement('a'); + imageLink.href = formattedUrl; + imageLink.target = '_blank'; + imageLink.className = 'block decoration-none'; + + const imageContainer = document.createElement('div'); + imageContainer.className = + 'max-h-[450px] overflow-hidden block z-10 relative'; + + const imgElement = document.createElement('img'); + imgElement.src = attrs.thumbnail; + imgElement.className = 'w-full h-auto align-top'; + imgElement.alt = attrs.title || '링크 썸네일'; + + imageContainer.appendChild(imgElement); + imageLink.appendChild(imageContainer); + linkWrapper.appendChild(imageLink); + } + + const textLink = document.createElement('a'); + textLink.href = formattedUrl; + textLink.target = '_blank'; + textLink.className = 'block decoration-none'; + + const textContainer = document.createElement('div'); + textContainer.className = + 'px-[26px] pt-[21px] pb-[18px] leading-[1.4] block relative text-left box-border'; + + const titleElement = document.createElement('strong'); + titleElement.className = + 'text-[15px] text-ellipsis whitespace-nowrap overflow-hidden break-all block font-bold text-[#333]'; + titleElement.textContent = attrs.title; + + const summaryElement = document.createElement('p'); + summaryElement.className = + 'whitespace-nowrap overflow-hidden text-ellipsis break-all max-h-9 leading-[18px] mt-[7px] text-[13px] text-[#999]'; + summaryElement.textContent = attrs.summary; + + const urlElement = document.createElement('p'); + urlElement.className = 'text-[12px] text-[#a1885f] underline'; + urlElement.textContent = formattedUrl; + + textContainer.appendChild(titleElement); + textContainer.appendChild(summaryElement); + textContainer.appendChild(urlElement); + textLink.appendChild(textContainer); + linkWrapper.appendChild(textLink); + + return linkWrapper; +}; diff --git a/src/components/editor/customComponent/CustomOgLink.ts b/src/components/editor/customComponent/CustomOgLink.ts index 62a8067..01bb6a7 100644 --- a/src/components/editor/customComponent/CustomOgLink.ts +++ b/src/components/editor/customComponent/CustomOgLink.ts @@ -67,11 +67,13 @@ const CustomOgLink = Node.create({ return [ 'div', { - class: `mt-10 max-w-[450px] w-full relative ${HTMLAttributes.alignment} border border-black/10 overflow-hidden flex`, + class: `mt-10 max-w-[450px] w-full relative ${HTMLAttributes.alignment} border border-black/10 inset-0 text-inherit vertical-align-baseline`, }, [ 'div', - { class: 'se-module se-module-oglink __se-unit group' }, + { + class: 'block relative w-full bg-[#fff] decoration-none shadow-md', + }, [ 'div', { class: 'w-[110px] block relative z-10' }, @@ -86,46 +88,51 @@ const CustomOgLink = Node.create({ [ 'div', { - class: - 'absolute inset-0 w-px h-4 bg-white transform origin-center -rotate-45', + class: 'absolute inset-0 border-black/10', }, ], ], - ], - [ - 'div', - { - class: - 'px-[26px] pt-[21px] pb-[18px] leading-[1.4] block relative text-left box-border text-[0] obsolute inset-0 border border-black/10', - }, + [ 'div', - { class: 'inline-block max-w-full align-middle' }, - [ - 'strong', - { - class: - 'text-[15px] text-ellipsis whitespace-nowrap overflow-hidden break-all block font-bold text-[#333] ', - }, - HTMLAttributes.title, - ], - [ - 'p', - { - class: - 'whitespace-nowrap overflow-hidden text-ellipsis break-all max-h-9 leading-[18px] mt-[7px] text-[13px] text-[#999]', - }, - HTMLAttributes.summary, - ], + { + class: `left-[110px] absolute inset-0 px-[26px] pt-[21px] pb-[18px] leading-[1.4] block text-left box-border text-[0] before:content-[''] before:inline-block before:h-full before:align-middle`, + }, [ - 'p', - { - class: - 'whitespace-nowrap overflow-hidden text-ellipsis break-all mt-[9px] text-[#a1885f] text-[13px] no-underline', - }, - HTMLAttributes.url, + 'div', + { class: 'inline-block max-w-full align-middle' }, + [ + 'strong', + { + class: + 'text-[15px] font-bold text-[#333] break-all block mb-1 whitespace-nowrap overflow-hidden text-ellipsis', + }, + HTMLAttributes.title, + ], + [ + 'p', + { + class: + 'mt-[7px] text-[13px] leading-[1.4] text-[#999] break-all whitespace-nowrap overflow-hidden text-ellipsis', + }, + HTMLAttributes.summary, + ], + [ + 'p', + { + class: + 'mt-[9px] text-[#a1885f] text-[13px] break-all whitespace-nowrap overflow-hidden text-ellipsis no-underline', + }, + HTMLAttributes.url, + ], ], ], + [ + 'div', + { + class: 'absolute inset-0 border border-black/10', + }, + ], ], ]; }, diff --git a/src/components/editor/customComponent/CustomVerticalLink.ts b/src/components/editor/customComponent/CustomVerticalLink.ts index e756f19..08daebc 100644 --- a/src/components/editor/customComponent/CustomVerticalLink.ts +++ b/src/components/editor/customComponent/CustomVerticalLink.ts @@ -54,12 +54,12 @@ const CustomVerticalLink = Node.create({ [ 'div', { - class: `text-left border-box relative block px-[26px] pt-[21px] pb-[18px] leading-[1.4] before:content-[''] before:inline-block before:h-full before:vertical-align-middle`, + class: `text-left border-box relative block px-[26px] pt-[21px] pb-[18px] leading-[1.4] before:content-[''] before:inline-block before:h-full before:align-middle`, }, [ 'div', { - class: 'inline-block max-w-full vertical-align-middle', + class: 'inline-block max-w-full align-middle', }, [ 'strong', diff --git a/src/components/editor/customComponent/FileComponent.tsx b/src/components/editor/customComponent/FileComponent.tsx index 35e8fdb..093217c 100644 --- a/src/components/editor/customComponent/FileComponent.tsx +++ b/src/components/editor/customComponent/FileComponent.tsx @@ -11,7 +11,7 @@ const FileComponent = ({ node }: NodeViewProps) => { return (
{ thumbnail: data.hybridGraph.image || '', title: data.hybridGraph.title || '제목 없음', summary: data.hybridGraph.description || '설명 없음', + url: data.hybridGraph.url || url, }; } catch (error) { console.error('미리보기 데이터를 가져오는 중 오류 발생:', error); @@ -19,17 +20,34 @@ const AddLink = ({ editor }: { editor: Editor }) => { thumbnail: 'https://via.placeholder.com/150', title: '링크 제목', summary: '링크 요약 내용', + url: url, }; } }; + const determineLinkType = ({ + thumbnail, + url, + }: { + thumbnail: string; + url: string; + }) => { + if ( + url.includes('n.news.naver.com/mnews/article/018/') || + thumbnail.includes('imgnews.pstatic.net/image/018/') + ) { + return 'oglink'; + } + return 'link'; + }; + return (