KIM-JINO5 před 2 měsíci
rodič
revize
729f42b5f5

+ 4 - 2
app/(auth)/approval/page.tsx

@@ -143,8 +143,10 @@ export default function Approval()
 					break;
 			}
 
-        } catch (err: any) {
-            setError(err.message);
+        } catch (err) {
+            if (err instanceof Error) {
+                setError(err.message);
+            }
         } finally {
             setLoading(false);
         }

+ 5 - 1
app/(main)/(forum)/board/_component/PermissionDenied.tsx

@@ -13,9 +13,13 @@ export default function PermissionDenied({ _board } : Props) {
     const router = useRouter();
 
     useEffect(() => {
-        document.title = '권한이 부족합니다';
+        document.title = '권한이 부족합니다.';
     }, []);
 
+    if (!_board.isActive) {
+        return null;
+    }
+
     return (
         <div className="permission-denied">
             <h1>⚠️ 권한이 부족합니다</h1>

+ 0 - 110
lib/editor_old/FileBlot.js

@@ -1,110 +0,0 @@
-import Quill from 'quill';
-
-const BlockEmbed = Quill.import('blots/block/embed');
-const Parchment = Quill.import('parchment');
-
-class FileBlot extends BlockEmbed {
-    static blotName = 'fileCard';
-    static tagName = 'div';
-    static className = 'file-card';
-	static scope = Parchment.Scope.BLOCK_BLOT;
-
-    static create(value) {
-        const node = super.create();
-		//node.setAttribute('contenteditable', 'false');
-        node.setAttribute('data-file-name', value.name);
-        node.setAttribute('data-file-size', value.size);
-		node.setAttribute('draggable', 'true');
-
-        node.innerHTML = `
-			<div class="file-card-content">
-				<div class="file-card-info">
-					<span>📄 <span class="file-name">${value.name} (${(value.size / 1024 / 1024).toFixed(2)}MB)</span></span>
-				</div>
-				<div class="file-card-actions">
-					<button data-align="start">
-						<img src="/resources/editor/align-left.svg" alt="왼쪽" />
-					</button>
-					<button data-align="center">
-						<img src="/resources/editor/align-center.svg" alt="중앙앙" />
-					</button>
-					<button data-align="end">
-						<img src="/resources/editor/align-right.svg" alt="오른쪽" />
-					</button>
-					<button class="file-card-delete">
-						<img src="/resources/editor/trash.svg" alt="삭제" />
-					</button>
-				</div>
-			</div>
-        `;
-
-		// 클릭 시 이벤트 발생
-		node.addEventListener('click', (e) => {
-			e.preventDefault();
-			e.stopPropagation();
-			
-			const quill = FileBlot.getQuillInstance();
-			if (quill) {
-				const uploader = quill?.getModule('fileUploader');
-
-				// 첨부파일 활성화 해제
-				uploader.clearActiveCards();
-
-				// 에디터 커서 표시 해제
-				quill.root.blur();
-			}
-
-			node.classList.add('active');
-		});
-
-        // 삭제 버튼
-        node.querySelector('.file-card-delete')?.addEventListener('click', () => {
-            node.remove();
-        });
-
-        // 정렬 버튼
-        node.querySelectorAll('button[data-align]').forEach(btn => {
-            btn.addEventListener('click', (e) => {
-				const target = e.currentTarget;
-                const align = target.dataset.align;
-				node.querySelectorAll('button[data-align]').forEach(el => el.classList.remove('active'));
-                node.style.justifySelf = align || 'start';
-				target.classList.add('active');
-            });
-        });
-
-		// 드래그 시작
-       node.addEventListener('dragstart', (e) => {
-            const value = {
-                name: node.getAttribute('data-file-name'),
-                size: node.getAttribute('data-file-size')
-            };
-            e.dataTransfer?.setData('text/plain', JSON.stringify(value));
-            e.dataTransfer.effectAllowed = 'move';
-            node.classList.add('dragging');
-        });
-
-        node.addEventListener('dragend', () => {
-            node.classList.remove('dragging');
-        });
-
-        return node;
-    }
-
-    static value(node) {
-        return {
-            name: node.getAttribute('data-file-name'),
-            size: node.getAttribute('data-file-size')
-        };
-    }
-
-	static getQuillInstance() {
-		return Quill.quillInstance || null;
-	}
-
-	static setQuillInstance(quill) {
-        Quill.quillInstance = quill;
-    }
-}
-
-export default FileBlot;

+ 0 - 39
lib/editor_old/FileUploader.js

@@ -1,39 +0,0 @@
-import Quill from 'quill';
-
-export default class FileUploader {
-    quill;
-
-    constructor(quill) {
-        this.quill = quill;
-    }
-
-	// 파일 추가
-    selectFile() {
-        const input = document.createElement('input');
-        input.type = 'file';
-
-        input.onchange = () => {
-            if (!input.files) {
-				return;
-			}
-
-            const file = input.files[0];
-            if (!file) {
-				return;
-			}
-
-            const range = this.quill.getSelection() || { index: 0};
-            if (range) {
-				this.quill.insertEmbed(range.index, 'fileCard', { name: file.name, size: file.size }, Quill.sources.USER);
-				this.quill.setSelection(range.index + 1);
-            }
-        };
-
-        input.click();
-    }
-
-	// 첨부 파일 활성화 삭제
-	clearActiveCards() {
-        this.quill.root.querySelectorAll('.file-card.active').forEach(el => el.classList.remove('active'));
-    }
-}

+ 0 - 197
lib/editor_old/index.tsx

@@ -1,197 +0,0 @@
-'use client';
-
-import { useEffect, useRef } from 'react';
-import { Rnd } from 'react-rnd';
-import Quill from 'quill';
-import 'quill/dist/quill.snow.css';
-import '@/styles/quill.scss';
-import ReactDOM from 'react-dom/client';
-import FileUploader from './FileUploader';
-import FileBlot from './FileBlot';
-
-const BlockEmbed = Quill.import('blots/block/embed');
-
-// --------- FileUploader ---------
-class ResizableImageBlot extends BlockEmbed {
-	static blotName = 'resizableImage';
-	static tagName = 'div';
-	static className = 'resizable-image-container';
-  
-	static create(value) {
-	  // value: { url: string, width?: number, height?: number }
-	  const node = super.create();
-	  // 저장할 이미지 정보
-	  node.setAttribute('data-url', value.url);
-	  node.setAttribute('data-width', value.width || 200);
-	  node.setAttribute('data-height', value.height || 200);
-	  // React 컴포넌트를 렌더링할 컨테이너 생성
-	  const container = document.createElement('div');
-	  container.classList.add('resizable-image-inner');
-	  node.appendChild(container);
-	  return node;
-	}
-  
-	static value(node) {
-	  // 블롯의 값을 Delta로 저장할 때 사용
-	  return {
-		url: node.getAttribute('data-url'),
-		width: node.getAttribute('data-width'),
-		height: node.getAttribute('data-height')
-	  };
-	}
-
-	renderReactComponent() {
-		const node = this.domNode as HTMLElement;
-		const container = node.querySelector('.resizable-image-inner');
-		const initialWidth = parseInt(node.getAttribute('data-width') || '200', 10);
-		const initialHeight = parseInt(node.getAttribute('data-height') || '200', 10);
-		const url = node.getAttribute('data-url') || '';
-	
-		// React 18 이상에서는 createRoot 사용
-		const root = ReactDOM.createRoot(container!);
-		root.render(
-		  <Rnd
-			default={{
-			  width: initialWidth,
-			  height: initialHeight,
-			}}
-			bounds="parent"
-			enableResizing={{
-			  top: true,
-			  right: true,
-			  bottom: true,
-			  left: true,
-			  topRight: true,
-			  bottomRight: true,
-			  bottomLeft: true,
-			  topLeft: true,
-			}}
-			onResizeStop={(e, direction, ref, delta, position) => {
-			  // 리사이즈 완료 후 새로운 크기를 data-속성에 저장
-			  node.setAttribute('data-width', String(ref.offsetWidth));
-			  node.setAttribute('data-height', String(ref.offsetHeight));
-			}}
-		  >
-			<img
-			  src={url}
-			  alt=""
-			  style={{ width: '100%', height: '100%', objectFit: 'contain' }}
-			/>
-		  </Rnd>
-		);
-	  }
-}
-
-Quill.register(ResizableImageBlot);
-Quill.register('modules/fileUploader', FileUploader);
-Quill.register(FileBlot);
-
-// --------- Quill Editor ---------
-
-// 글씨 크기 설정
-const FontSizeStyle = Quill.import('attributors/style/size') as any;
-FontSizeStyle.whitelist = ['11px', '13px', '15px', '16px', '19px', '24px', '28px', '30px', '34px', '38px'];
-Quill.register(FontSizeStyle, true);
-
-interface QuillEditorProps {
-    content: string|null|'';
-    onChange: (content: string) => void;
-}
-
-export default function Editor({ content, onChange }: QuillEditorProps) {
-    const editorRef = useRef<HTMLDivElement | null>(null);
-    const quillInstanceRef = useRef<Quill | null>(null);
-
-    useEffect(() => {
-        if (editorRef.current && !quillInstanceRef.current) {
-			const icons = Quill.import('ui/icons') as Record<string, string>;
-
-			// 파일 아이콘 생성
-			icons['file'] = '<svg viewBox="0 -0.5 17 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="si-glyph si-glyph-file-upload" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <title>1126</title> <defs> </defs> <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g transform="translate(1.000000, 1.000000)" fill="#434343"> <path d="M14,8.047 L14,12.047 L2,12.047 L2,8.047 L0,8.047 L0,15 L15.969,15 L15.969,8.047 L14,8.047 Z" class="si-glyph-fill"> </path> <path d="M7.997,0 L5,3.963 L7.016,3.984 L7.016,8.969 L8.953,8.969 L8.953,3.984 L10.953,3.984 L7.997,0 Z" class="si-glyph-fill"> </path> </g> </g> </g></svg>';
-
-            quillInstanceRef.current = new Quill(editorRef.current, {
-                theme: 'snow',
-                modules: {
-                    toolbar: {
-						container: [
-							[{ font: [] }, { size: ['11px', '13px', '15px', '16px', '19px', '24px', '28px', '30px', '34px', '38px']}],
-							['bold', 'italic', 'underline', 'strike', { color: [] }, { background: [] }],
-							[{ align: [] }, { list: 'ordered' }, { list: 'bullet' }],
-							['blockquote', 'code-block', 'clean'],
-							['link', 'image', 'video', 'file']
-						],
-						handlers: {
-							file: () => {
-                                const uploader = quillInstanceRef.current?.getModule('fileUploader') as FileUploader;
-								uploader?.selectFile();
-							}
-						},
-					},
-                    clipboard: {
-                        matchVisual: false,
-                    },
-				
-                    fileUploader: {}
-                }
-            });
-
-			quillInstanceRef.current.root.innerHTML = content || '';
-
-			// 에디터 내용 변경 시
-            quillInstanceRef.current.on('text-change', () => {
-                onChange(quillInstanceRef.current!.root.innerHTML);
-            });
-
-			// 첨부파일 클릭 시 활성화 제거
-			quillInstanceRef.current.on('selection-change', () => {
-				const uploader = quillInstanceRef.current?.getModule('fileUploader') as FileUploader;
-				if (uploader) {
-					uploader.clearActiveCards();
-				}
-			});
-
-			// FileCardBlot에 quillInstanceRef.current를 주입
-			FileBlot.setQuillInstance(quillInstanceRef.current);
-			const quillRoot = quillInstanceRef.current.root;
-			// drop 위치 처리
-			quillRoot.addEventListener('dragover', (e) => {
-				e.preventDefault();
-			});
-	
-			quillRoot.addEventListener('drop', (e) => {
-				e.preventDefault();
-				const data = e.dataTransfer?.getData('text/plain');
-				if (!data) return;
-	
-				const file = JSON.parse(data);
-	
-				// 현재 커서 위치 찾기
-				const selection = quillInstanceRef.current!.getSelection();
-				const index = selection ? selection.index : quillInstanceRef.current!.getLength();
-	
-				// 기존 dragging 된 요소 삭제
-				const draggingNode = quillRoot.querySelector('.file-card.dragging');
-				draggingNode?.remove();
-	
-				// 새로운 위치에 삽입
-				quillInstanceRef.current!.insertEmbed(index, 'fileCard', file, Quill.sources.USER);
-				quillInstanceRef.current!.setSelection(index + 1);
-			});
-        }
-    }, []);
-
-	useEffect(() => {
-		if (quillInstanceRef.current) {
-			const currentHTML = quillInstanceRef.current.root.innerHTML;
-			if (currentHTML !== (content || '')) {
-				quillInstanceRef.current.root.innerHTML = content || '';
-			}
-		}
-	}, [content]);
-
-    return (
-        <div className="w-full">
-            <div ref={editorRef} />
-        </div>
-    );
-}