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
31 changes: 20 additions & 11 deletions src/api/article.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
import { AddArticleData } from '../types/article';
import { apiClient } from './axiosInstance';

interface AddArticleData {
title: string;
authorName: string;
categoryName: string;
type: string;
isPremium: boolean;
imageLink: string;
paywallUp: string;
paywallDown: string;
}

export const saveArticle = async (articleData: AddArticleData) => {
try {
const token = localStorage.getItem('token');
Expand All @@ -29,3 +19,22 @@ export const saveArticle = async (articleData: AddArticleData) => {
throw new Error('api Error');
}
};

export const uploadImage = async (imageUrl: string) => {
try {
const response = await apiClient.post(
'/articles/image',
new URLSearchParams({ src: imageUrl }),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
},
);

return response.data;
} catch (error) {
console.error('이미지 업로드 실패:', error);
throw new Error('api Error');
}
};
84 changes: 57 additions & 27 deletions src/components/editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import extractPaywallData from './common/extractPaywallData';
import { authors, types, categories } from '../../types/options';
import SelectComponent from './SelectComponent';
import CustomToolbar from './toolbar/CustomToolbar';
import { saveArticle } from '../../api/article';
import { saveArticle, uploadImage } from '../../api/article';
import { DOMParser as ProseMirrorDOMParser } from 'prosemirror-model';

import Bold from '@tiptap/extension-bold';
Expand All @@ -25,7 +25,6 @@ import TextStyle from '@tiptap/extension-text-style';
import Focus from '@tiptap/extension-focus';
import Table from '@tiptap/extension-table';
import TableHeader from '@tiptap/extension-table-header';
import TableCell from '@tiptap/extension-table-cell';
import TableRow from '@tiptap/extension-table-row';
import ListItem from '@tiptap/extension-list-item';
import BulletList from '@tiptap/extension-bullet-list';
Expand All @@ -51,6 +50,7 @@ import CustomPhotoGroup from './customComponent/CustomPhotoGroup';
import CustomBlockLink from './customComponent/CustomBlockLink';
import CustomHighlight from './extension/CustomHighlight';
import CustomTextLink from './extension/CustomTextLink';
import { CustomTableCell } from './customComponent/CustomTableCell';

const Editor = ({ content }: { content: JSONContent[] | null }) => {
const [articleData, setArticleData] = useState({
Expand Down Expand Up @@ -120,12 +120,7 @@ const Editor = ({ content }: { content: JSONContent[] | null }) => {
class: 'h-10',
},
}),
TableCell.configure({
HTMLAttributes: {
class:
'border border-[rgba(61,37,20,0.12)] box-border min-w-[1em] px-2 py-1 relative align-middle',
},
}),
CustomTableCell,

CustomBlock,
CustomParagraph,
Expand Down Expand Up @@ -180,36 +175,71 @@ const Editor = ({ content }: { content: JSONContent[] | null }) => {
controlBarElement.remove();
});

body.querySelectorAll('table').forEach((tableElement) => {
tableElement.querySelectorAll('tr').forEach((trElement, index) => {
if (index === 0) {
trElement.querySelectorAll('td').forEach((tdElement) => {
const thElement = document.createElement('th');
thElement.innerHTML = tdElement.innerHTML;
trElement.replaceChild(thElement, tdElement);
});
}
});
});
// body.querySelectorAll('table').forEach((tableElement) => {
// tableElement.querySelectorAll('tr').forEach((trElement, index) => {
// if (index === 0) {
// trElement.querySelectorAll('td').forEach((tdElement) => {
// const thElement = document.createElement('th');
// thElement.innerHTML = tdElement.innerHTML;
// trElement.replaceChild(thElement, tdElement);
// });
// }
// });
// });

body
.querySelectorAll('.se-cell-context-menu')
.forEach((controlBarElement) => {
controlBarElement.remove();
});

const fragment = ProseMirrorDOMParser.fromSchema(
view.state.schema,
).parse(body);
uploadAllImages(body).then(() => {
const fragment = ProseMirrorDOMParser.fromSchema(
view.state.schema,
).parse(body);
const transaction = view.state.tr.replaceSelectionWith(fragment);
view.dispatch(transaction);
});

const transaction = view.state.tr.replaceSelectionWith(fragment);
view.dispatch(transaction);
return true;
}
return false;
},
},
});

const uploadAllImages = async (body: HTMLElement) => {
const imageContainers = body.querySelectorAll(
'.se-section-image, .se-section-imageStrip, .se-section-imageGroup',
);

for (const element of imageContainers) {
await uploadImagesInElement(element as HTMLElement);
}
};

const uploadImagesInElement = async (element: HTMLElement) => {
if (!element) return;

const imageElements = element.querySelectorAll('img.se-image-resource');

for (const img of imageElements) {
const src = img.getAttribute('src') || '';

if (!src || src.startsWith('https://scs-phinf.pstatic.net/')) continue;

try {
console.log(`Uploading image: ${src}`);
const uploadedUrl = await uploadImage(src);

console.log(`Uploaded URL: ${uploadedUrl}`);
img.setAttribute('src', uploadedUrl);
} catch (error) {
console.error('이미지 업로드 실패:', error);
}
}
};

useEffect(() => {
if (content && editor?.commands) {
editor?.commands.setContent(content);
Expand Down Expand Up @@ -305,12 +335,12 @@ const Editor = ({ content }: { content: JSONContent[] | null }) => {
</button>
)}
</div>
<div className="border-2 w-full overflow-y-auto flex flex-col">
<div className="border-2 w-full flex flex-col h-screen">
<CustomToolbar editor={editor} />
<ToolBar editor={editor} />
<div className="overflow-y-auto">
<div className="flex-1 overflow-y-auto min-h-0 h-0">
<div className="px-6 max-w-[1000px] mx-auto">
<div className="pt-10 pb-[435px]">
<div className="py-10">
<div className="px-6">
<h1 className="p-4">
<input
Expand Down
2 changes: 1 addition & 1 deletion src/components/editor/customComponent/CustomPhoto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const CustomPhoto = Node.create({
const src =
imgElement?.getAttribute('data-src')?.trim() ||
imgElement?.getAttribute('src')?.trim();
console.log('Extracted src:', src);

const alt = imgElement?.getAttribute('alt') || '';
const width = imgElement?.getAttribute('width') || '680';

Expand Down
66 changes: 66 additions & 0 deletions src/components/editor/customComponent/CustomTableCell.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { TableCell } from '@tiptap/extension-table-cell';
import { mergeAttributes } from '@tiptap/core';

export const CustomTableCell = TableCell.extend({
name: 'tableCell',

addOptions() {
return {
HTMLAttributes: {},
};
},

addAttributes() {
return {
colspan: {
default: 1,
parseHTML: (element) =>
parseInt(element.getAttribute('colspan') ?? '1', 10),
renderHTML: (attributes) =>
attributes.colspan > 1 ? { colspan: attributes.colspan } : {},
},
rowspan: {
default: 1,
parseHTML: (element) =>
parseInt(element.getAttribute('rowspan') ?? '1', 10),
renderHTML: (attributes) =>
attributes.rowspan > 1 ? { rowspan: attributes.rowspan } : {},
},
style: {
default: '',
parseHTML: (element) => element.getAttribute('style') || '',
renderHTML: (attributes) =>
attributes.style ? { style: attributes.style } : {},
},
class: {
default:
'border border-gray-300 border-r border-b bg-white p-2 align-middle box-border',
parseHTML: () => {
return 'border border-gray-300 border-r border-b bg-white p-2 align-middle box-border';
},
renderHTML: (attributes) => ({ class: attributes.class }),
},
};
},

parseHTML() {
return [
{
tag: 'td.se-cell',
getAttrs: (element) => {
return {
colspan: parseInt(element.getAttribute('colspan') ?? '1', 10),
rowspan: parseInt(element.getAttribute('rowspan') ?? '1', 10),
style: element.getAttribute('style') ?? '',
class:
'border border-gray-300 border-r border-b bg-white p-2 align-middle box-border',
};
},
},
];
},

renderHTML({ HTMLAttributes }) {
return ['td', mergeAttributes(HTMLAttributes), 0];
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const CustomVerticalLink = Node.create({
const summary =
ogLinkElement.querySelector('.se-oglink-summary')?.textContent ||
'';
const whiteSpace = 'whitespace-normal max-h-[58px] leading-[20px]';
const whiteSpace = 'whitespace-nowrap max-h-[58px] leading-[20px]';
const url =
ogLinkElement.querySelector('.se-oglink-url')?.textContent || '';

Expand Down
Loading