feat: add attachment button and mobile UI enhancements (v2.1)

This commit is contained in:
leeyj
2026-04-19 23:22:35 +09:00
parent 3d3709371d
commit ff9d75c26f
9 changed files with 97 additions and 41 deletions
+1
View File
@@ -104,6 +104,7 @@
}
.action-btn:hover { background: rgba(184, 59, 94, 0.8); }
.btn-label { display: none; }
.ai-btn:hover { background: var(--ai-accent); color: white; }
/* Memo Footer Metadata Styling */
+1
View File
@@ -33,6 +33,7 @@
.memo-actions { opacity: 1 !important; bottom: 8px; right: 8px; }
.action-btn { padding: 8px 12px; font-size: 1rem; min-width: 44px; min-height: 44px; display: flex; align-items: center; justify-content: center; }
.btn-label { display: inline; margin-left: 5px; font-size: 0.9rem; font-weight: bold; }
.modal-content { width: 95%; max-height: 90vh; border-radius: 12px; }
.tag-badge, .group-badge { padding: 4px 10px; font-size: 0.85rem; }
+15 -1
View File
@@ -28,7 +28,9 @@ export const ComposerManager = {
foldBtn: document.getElementById('foldBtn'),
discardBtn: document.getElementById('discardBtn'),
deleteBtn: document.getElementById('deleteMemoBtn'), // NEW
categoryBar: document.getElementById('composerCategoryBar')
categoryBar: document.getElementById('composerCategoryBar'),
attachBtn: document.getElementById('attachBtn'),
fileInput: document.getElementById('composerFileInput')
};
if (!this.DOM.composer || !this.DOM.trigger) return;
@@ -71,6 +73,18 @@ export const ComposerManager = {
this.DOM.encryptionToggle.onclick = () => this.toggleEncryption();
this.initShortcutHint();
// 💡 파일 첨부 버튼 연동
if (this.DOM.attachBtn && this.DOM.fileInput) {
this.DOM.attachBtn.onclick = () => this.DOM.fileInput.click();
this.DOM.fileInput.onchange = (e) => {
const files = e.target.files;
if (files.length > 0) {
EditorManager.handleFiles(files);
e.target.value = ''; // 같은 파일 다시 올릴 수 있게 초기화
}
};
}
// 2. 자동 임시저장 및 키보드 리스너 등록
this.draftTimer = setInterval(() => this.saveDraft(), 3000);
ComposerDraft.checkRestore((draft) => this.restoreDraft(draft));
+36 -27
View File
@@ -147,37 +147,46 @@ export const EditorManager = {
if (!files || files.length === 0) return;
// 에디터가 닫혀있다면 상위에서 열어줘야 함
onDropComplete(true);
if (onDropComplete) onDropComplete(true);
for (let file of files) {
try {
const data = await API.uploadFile(file);
if (data.url) {
const filename = data.url.split('/').pop();
const isImg = ['png','jpg','jpeg','gif','webp','svg'].includes(data.ext?.toLowerCase());
const name = data.name || 'file';
// Ensure editor is focused before inserting
this.editor.focus();
if (isImg) {
this.editor.exec('addImage', { altText: name, imageUrl: data.url });
}
// 공통: 첨부 파일 목록에 추가 및 UI 갱신
this.attachedFiles.push({
filename: filename,
original_name: name,
file_type: file.type
});
this.sessionFiles.add(filename); // 세션 트래킹 추가
this.refreshAttachmentUI();
}
} catch (err) { console.error(err); }
}
await this.handleFiles(files);
});
},
/**
* 다중 파일을 처리(업로드 및 UI 반영)함
*/
async handleFiles(files) {
if (!files || files.length === 0) return;
for (let file of files) {
try {
const data = await API.uploadFile(file);
if (data.url) {
const filename = data.url.split('/').pop();
const isImg = ['png','jpg','jpeg','gif','webp','svg'].includes(data.ext?.toLowerCase());
const name = data.name || 'file';
// Ensure editor is focused before inserting
this.editor.focus();
if (isImg) {
this.editor.exec('addImage', { altText: name, imageUrl: data.url });
}
// 공통: 첨부 파일 목록에 추가 및 UI 갱신
this.attachedFiles.push({
filename: filename,
original_name: name,
file_type: file.type
});
this.sessionFiles.add(filename); // 세션 트래킹 추가
this.refreshAttachmentUI();
}
} catch (err) { console.error('[Editor] File process error:', err); }
}
},
getAttachedFilenames() {
return this.attachedFiles.map(f => f.filename);
},
+2
View File
@@ -23,6 +23,8 @@
"composer_save": "메모 저장",
"composer_discard": "취소 (삭제)",
"composer_encrypt": "암호화",
"composer_attach_file": "파일 첨부",
"composer_attach_label": "파일추가",
"composer_password": "비밀번호",
"tooltip_fold": "창 접기 (내용 보존)",