각 소스 설명을 "적합 주제" 중심으로 재작성하고, 임상=PubMed / 보건정책·경제=OpenAlex+Semantic / 자연어문장=Semantic / vs 빼기 힌트 줄을 추가. ptitle "PubMed 논문 검색" → "논문 검색". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XZX9JHFSLZRuK9rR4sCVBs
824 lines
55 KiB
HTML
824 lines
55 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ko">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>📊 슬라이드 제작</title>
|
||
<style>
|
||
:root{
|
||
--bg:#0f1117;--panel:#1a1d27;--panel2:#22263a;--line:#2e3250;
|
||
--text:#e2e8f0;--muted:#94a3b8;--brand:#6366f1;--brand2:#818cf8;
|
||
--green:#22c55e;--red:#ef4444;--yellow:#f59e0b;--r:10px;
|
||
}
|
||
body.theme-light{
|
||
--bg:#eef1f8;--panel:#ffffff;--panel2:#f0f3fb;--line:#cdd3e8;
|
||
--text:#1e2337;--muted:#5a6480;--brand:#4f52cc;--brand2:#6366f1;
|
||
--green:#15803d;--red:#dc2626;--yellow:#b45309;
|
||
}
|
||
body.theme-warm{
|
||
--bg:#f5f0e8;--panel:#fffdf7;--panel2:#ede8dc;--line:#d6ccbb;
|
||
--text:#2c2318;--muted:#7a6e5e;--brand:#7c5c2e;--brand2:#a07840;
|
||
--green:#15803d;--red:#dc2626;--yellow:#b45309;
|
||
}
|
||
.theme-btn{background:none;border:1.5px solid var(--line);border-radius:6px;padding:4px 10px;font-size:12px;color:var(--muted);cursor:pointer;transition:.15s;}
|
||
.theme-btn:hover,.theme-btn.active{border-color:var(--brand);color:var(--brand2);background:rgba(99,102,241,.08);}
|
||
.src-chk{display:flex;align-items:flex-start;gap:6px;font-size:12px;font-weight:600;color:var(--muted);cursor:pointer;border:1.5px solid var(--line);border-radius:8px;padding:8px 11px;transition:.15s;user-select:none;width:168px;flex-shrink:0;box-sizing:border-box;}
|
||
.src-chk input{width:13px;height:13px;cursor:pointer;margin-top:2px;flex-shrink:0;}
|
||
.src-chk-desc{display:block;font-size:10px;font-weight:400;color:var(--muted);margin-top:4px;line-height:1.5;}
|
||
#src-pubmed{background:rgba(239,68,68,.07);}
|
||
#src-pubmed:has(input:checked){background:rgba(239,68,68,.18);border-color:#f87171;color:#fca5a5;}
|
||
#src-pubmed input{accent-color:#ef4444;}
|
||
#src-openalex{background:rgba(34,197,94,.07);}
|
||
#src-openalex:has(input:checked){background:rgba(34,197,94,.18);border-color:var(--green);color:#86efac;}
|
||
#src-openalex input{accent-color:#22c55e;}
|
||
#src-semantic{background:rgba(251,191,36,.07);}
|
||
#src-semantic:has(input:checked){background:rgba(251,191,36,.18);border-color:#fbbf24;color:#fde68a;}
|
||
#src-semantic input{accent-color:#f59e0b;}
|
||
#src-europepmc{background:rgba(96,165,250,.07);}
|
||
#src-europepmc:has(input:checked){background:rgba(96,165,250,.18);border-color:#60a5fa;color:#bfdbfe;}
|
||
#src-europepmc input{accent-color:#3b82f6;}
|
||
*{margin:0;padding:0;box-sizing:border-box;}
|
||
body{background:var(--bg);color:var(--text);font-family:'Segoe UI',system-ui,sans-serif;height:100vh;display:flex;flex-direction:column;overflow:hidden;font-size:14px;}
|
||
|
||
.header{display:flex;align-items:center;gap:10px;padding:10px 18px;background:var(--panel);border-bottom:1px solid var(--line);flex-shrink:0;}
|
||
.header h1{font-size:16px;font-weight:700;}
|
||
.steps{display:flex;gap:2px;margin-left:auto;align-items:center;}
|
||
.step-hint{font-size:10px;color:var(--muted);margin-right:6px;}
|
||
.sdot{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted);padding:5px 12px;border-radius:6px;cursor:pointer;transition:.15s;user-select:none;}
|
||
.sdot.active{color:var(--brand2);background:rgba(99,102,241,.15);font-weight:700;}
|
||
.sdot.done{color:var(--green);}
|
||
.sdot .n{width:20px;height:20px;border-radius:50%;border:1.5px solid currentColor;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;flex-shrink:0;}
|
||
|
||
.body{display:flex;flex:1;min-height:0;}
|
||
.sv{display:none;flex-direction:column;flex:1;min-height:0;}
|
||
.sv.active{display:flex;}
|
||
.ptitle{font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;padding:11px 16px 8px;border-bottom:1px solid var(--line);flex-shrink:0;}
|
||
.scroll{flex:1;overflow-y:auto;padding:14px 16px;}
|
||
|
||
/* Buttons */
|
||
.btn{padding:8px 16px;border:none;border-radius:var(--r);font-size:13px;font-weight:600;cursor:pointer;transition:.15s;white-space:nowrap;}
|
||
.btn:disabled{opacity:.4;cursor:not-allowed;}
|
||
.bp{background:var(--brand);color:#fff;}.bp:not(:disabled):hover{background:var(--brand2);}
|
||
.bg{background:var(--panel2);color:var(--text);border:1px solid var(--line);}.bg:not(:disabled):hover{background:var(--line);}
|
||
.bgreen{background:#166534;color:#86efac;border:1px solid #166534;}.bgreen:not(:disabled):hover{background:#15803d;}
|
||
.bred{background:#7f1d1d;color:#fca5a5;border:1px solid #7f1d1d;}
|
||
|
||
/* Search */
|
||
.srow{display:flex;gap:8px;margin-bottom:12px;}
|
||
.srow input{flex:1;background:var(--panel2);border:1px solid var(--line);border-radius:var(--r);padding:8px 12px;font-size:13px;color:var(--text);outline:none;}
|
||
.srow input:focus{border-color:var(--brand);}
|
||
.srow .yin{width:52px;flex:none;padding:8px 4px;text-align:center;}
|
||
.srow .yin::-webkit-inner-spin-button,.srow .yin::-webkit-outer-spin-button{-webkit-appearance:none;}
|
||
.srow .yin{-moz-appearance:textfield;}
|
||
|
||
/* Paper cards */
|
||
.pcard{background:var(--panel2);border:1px solid var(--line);border-radius:var(--r);padding:11px 13px;margin-bottom:8px;display:flex;gap:10px;align-items:flex-start;transition:.15s;}
|
||
.pcard.sel{border-color:var(--brand);background:rgba(99,102,241,.07);}
|
||
.pcard input[type=checkbox]{margin-top:3px;flex-shrink:0;accent-color:var(--brand);width:15px;height:15px;cursor:pointer;}
|
||
.pmeta{flex:1;min-width:0;}
|
||
.ptitle2{font-size:13px;font-weight:600;line-height:1.45;margin-bottom:4px;}
|
||
.psub{font-size:11px;color:var(--muted);}
|
||
.badge{display:inline-block;font-size:10px;padding:2px 6px;border-radius:3px;margin-right:3px;font-weight:700;}
|
||
.bpmc{background:rgba(34,197,94,.15);color:var(--green);}
|
||
.byear{background:rgba(99,102,241,.15);color:var(--brand2);}
|
||
.btype{background:rgba(245,158,11,.1);color:var(--yellow);}
|
||
.bnopmc{background:rgba(239,68,68,.1);color:var(--red);}
|
||
.bupload{background:rgba(99,102,241,.15);color:var(--brand2);}
|
||
.dropzone{border:2px dashed var(--line);border-radius:10px;padding:18px 14px;text-align:center;cursor:pointer;transition:.15s;color:var(--muted);font-size:12px;margin-bottom:6px;}
|
||
.dropzone:hover,.dropzone.drag{border-color:var(--brand);color:var(--brand2);background:rgba(99,102,241,.05);}
|
||
.dropzone input[type=file]{display:none;}
|
||
.pbtns{display:flex;gap:5px;margin-top:6px;}
|
||
|
||
/* Prep */
|
||
.prog{padding:8px 10px;border-bottom:1px solid var(--line);font-size:13px;border-radius:6px;transition:background .2s;}
|
||
.prog.active{background:rgba(99,102,241,.08);border-left:3px solid var(--brand2);padding-left:8px;}
|
||
.psp{display:inline-block;padding:2px 9px;border-radius:10px;font-size:11px;font-weight:600;white-space:nowrap;}
|
||
.psp-wait{background:var(--line);color:var(--muted);}
|
||
.psp-run{background:rgba(99,102,241,.2);color:var(--brand2);}
|
||
.psp-done{background:rgba(34,197,94,.15);color:var(--green);}
|
||
.psp-fail{background:rgba(239,68,68,.15);color:var(--red);}
|
||
.psp-skip{background:var(--line);color:var(--muted);}
|
||
@keyframes blink{0%,100%{opacity:1}50%{opacity:.4}}
|
||
.psp-run{animation:blink 1.2s ease-in-out infinite;}
|
||
.prog:last-child{border-bottom:none;}
|
||
.pstat{width:16px;flex-shrink:0;margin-top:1px;}
|
||
|
||
/* Img grid */
|
||
.igrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:8px;}
|
||
.icard{position:relative;border:1.5px solid var(--line);border-radius:7px;overflow:hidden;cursor:pointer;aspect-ratio:4/3;background:var(--panel2);transition:.15s;}
|
||
.icard:hover{border-color:var(--brand);}
|
||
.icard img{width:100%;height:100%;object-fit:cover;}
|
||
.ilabel{position:absolute;bottom:0;left:0;right:0;background:rgba(0,0,0,.65);color:#fff;font-size:9px;padding:2px 5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
||
|
||
/* Slide cards */
|
||
/* slide editor */
|
||
.slide-eg{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:10px;padding-bottom:8px;}
|
||
.scard{background:var(--panel2);border:1.5px solid var(--line);border-radius:10px;overflow:hidden;transition:.15s;}
|
||
.scard.open{border-color:var(--brand);}
|
||
.scard-hd{display:flex;align-items:center;gap:6px;padding:7px 10px;cursor:pointer;background:var(--panel);user-select:none;}
|
||
.scard-hd:hover{background:var(--line);}
|
||
.slide-mini{aspect-ratio:16/9;padding:8% 9%;position:relative;overflow:hidden;cursor:pointer;box-sizing:border-box;}
|
||
.slide-mini-title{font-weight:700;line-height:1.3;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;word-break:keep-all;overflow-wrap:break-word;}
|
||
.slide-mini-bullets{margin-top:5px;opacity:.75;}
|
||
.slide-mini-img{position:absolute;right:5%;top:15%;width:38%;height:70%;object-fit:cover;border-radius:3px;opacity:.88;}
|
||
.slide-edit-area{padding:12px;border-top:1px solid var(--line);}
|
||
.slide-edit-row{display:flex;gap:8px;flex-wrap:wrap;align-items:flex-end;margin-top:8px;}
|
||
.sbul-ta{width:100%;background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:6px 8px;font-size:12px;color:var(--text);resize:vertical;outline:none;line-height:1.5;min-height:60px;font-family:monospace;}
|
||
.sbul-ta:focus{border-color:var(--brand);}
|
||
.elabel{font-size:10px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;display:block;margin-bottom:3px;}
|
||
/* translation modal */
|
||
.txlmodal{width:min(680px,94vw);max-height:86vh;}
|
||
.txlmodal-hd{padding:14px 18px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:10px;flex-shrink:0;}
|
||
.txlmodal-body{flex:1;overflow-y:auto;padding:18px 20px;font-size:13px;line-height:1.85;white-space:pre-wrap;color:var(--text);}
|
||
.txlmodal-ft{padding:10px 14px;border-top:1px solid var(--line);display:flex;gap:8px;justify-content:flex-end;flex-shrink:0;}
|
||
.snum{width:22px;height:22px;border-radius:50%;background:var(--brand);color:#fff;font-size:10px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
|
||
.stype-tag{font-size:10px;color:var(--muted);background:var(--panel);padding:2px 6px;border-radius:3px;}
|
||
.sin{background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:6px 9px;font-size:13px;color:var(--text);width:100%;outline:none;}
|
||
.sin:focus{border-color:var(--brand);}
|
||
.sbul textarea{width:100%;background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:6px 9px;font-size:12px;color:var(--text);font-family:'IBM Plex Mono',monospace;resize:vertical;outline:none;margin-top:5px;line-height:1.5;}
|
||
.sbul textarea:focus{border-color:var(--brand);}
|
||
.simg-row{display:flex;align-items:center;gap:8px;margin-top:7px;}
|
||
.sthumb{width:52px;height:40px;border-radius:5px;object-fit:cover;border:1px solid var(--line);}
|
||
.sno-img{width:52px;height:40px;border-radius:5px;border:1px dashed var(--line);display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:14px;flex-shrink:0;}
|
||
.pickbtn{font-size:11px;padding:3px 9px;border-radius:5px;background:var(--panel);border:1px solid var(--line);color:var(--muted);cursor:pointer;}
|
||
.pickbtn:hover{border-color:var(--brand);color:var(--brand2);}
|
||
|
||
/* Skin picker */
|
||
.skin-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:5px;margin-top:5px;}
|
||
.skin-sw{width:100%;aspect-ratio:1;border-radius:5px;cursor:pointer;border:2px solid transparent;transition:.15s;}
|
||
.skin-sw.active{border-color:var(--brand);box-shadow:0 0 0 2px var(--brand);transform:scale(1.12);}
|
||
.skin-sw:hover{transform:scale(1.08);}
|
||
|
||
/* Preview grid */
|
||
.preview-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px;}
|
||
.preview-card{position:relative;background:var(--panel2);border:1px solid var(--line);border-radius:var(--r);overflow:hidden;transition:.15s;}
|
||
.preview-card:hover{border-color:var(--brand);}
|
||
.preview-card img{width:100%;display:block;}
|
||
.prev-edit-btn{position:absolute;top:6px;right:6px;opacity:0;transition:.15s;z-index:2;background:rgba(30,30,40,.75);color:#fff;border:none;border-radius:5px;padding:3px 9px;font-size:11px;cursor:pointer;backdrop-filter:blur(4px);}
|
||
.preview-card:hover .prev-edit-btn{opacity:1;}
|
||
.prev-edit-btn:hover{background:var(--brand)!important;opacity:1!important;}
|
||
.preview-card[data-edited]::after{content:'● 수정됨';position:absolute;top:6px;left:6px;background:rgba(99,102,241,.85);color:#fff;font-size:10px;padding:2px 7px;border-radius:10px;pointer-events:none;z-index:3;}
|
||
.preview-label{font-size:11px;padding:6px 10px;color:var(--muted);text-align:center;}
|
||
|
||
/* Settings sidebar — LEFT */
|
||
.sidebar{width:230px;flex-shrink:0;border-right:1px solid var(--line);background:var(--panel);display:flex;flex-direction:column;overflow:hidden;order:-1;}
|
||
.sidebar .scroll{padding:12px;}
|
||
.field{margin-bottom:12px;}
|
||
.flabel{display:block;font-size:10px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:5px;}
|
||
.field select,.field input[type=text],.field input[type=number]{width:100%;background:var(--panel2);border:1px solid var(--line);border-radius:7px;padding:6px 8px;font-size:12px;color:var(--text);outline:none;}
|
||
.field select:focus,.field input:focus{border-color:var(--brand);}
|
||
|
||
/* Bottom bar */
|
||
.bbar{padding:9px 14px;border-top:1px solid var(--line);background:var(--panel);flex-shrink:0;display:flex;gap:7px;align-items:center;}
|
||
.bbar .sp{flex:1;}
|
||
.smsg{font-size:12px;color:var(--muted);}
|
||
.smsg.running{animation:blink 1.2s ease-in-out infinite;}
|
||
|
||
/* Modals */
|
||
.mbg{display:none;position:fixed;inset:0;background:rgba(0,0,0,.8);z-index:200;align-items:center;justify-content:center;}
|
||
.mbg.open{display:flex;}
|
||
.modal{background:var(--panel);border:1px solid var(--line);border-radius:14px;display:flex;flex-direction:column;gap:0;}
|
||
|
||
/* Abstract modal */
|
||
.amodal{width:min(740px,94vw);max-height:88vh;}
|
||
.amodal-hd{padding:16px 20px;border-bottom:1px solid var(--line);flex-shrink:0;}
|
||
.amodal-title{font-size:15px;font-weight:700;line-height:1.4;margin-bottom:5px;}
|
||
.amodal-meta{font-size:12px;color:var(--muted);}
|
||
.atabs{display:flex;gap:2px;padding:8px 16px;border-bottom:1px solid var(--line);flex-shrink:0;}
|
||
.atab{padding:5px 14px;border-radius:6px;font-size:12px;font-weight:600;cursor:pointer;color:var(--muted);background:none;border:none;}
|
||
.atab.active{color:var(--brand2);background:rgba(99,102,241,.15);}
|
||
.amodal-body{flex:1;overflow-y:auto;padding:18px 20px;font-size:14px;line-height:1.85;white-space:pre-wrap;color:var(--text);}
|
||
.amodal-ft{padding:12px 18px;border-top:1px solid var(--line);flex-shrink:0;display:flex;gap:8px;justify-content:flex-end;align-items:center;}
|
||
|
||
/* Image picker modal */
|
||
.imodal{width:min(680px,94vw);max-height:82vh;}
|
||
.imodal-hd{padding:14px 18px;border-bottom:1px solid var(--line);font-size:14px;font-weight:700;flex-shrink:0;}
|
||
.imodal-body{flex:1;overflow-y:auto;padding:14px;}
|
||
.imodal-ft{padding:10px 16px;border-top:1px solid var(--line);flex-shrink:0;display:flex;justify-content:flex-end;}
|
||
/* PDF capture modal */
|
||
.pdfmodal{width:min(900px,96vw);max-height:94vh;height:94vh;}
|
||
.pdfmodal-hd{padding:10px 16px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:10px;flex-shrink:0;}
|
||
.pdfmodal-body{flex:1;overflow:hidden;display:flex;flex-direction:column;align-items:center;background:#111;position:relative;}
|
||
.pdfmodal-ft{padding:8px 14px;border-top:1px solid var(--line);display:flex;gap:8px;align-items:center;flex-shrink:0;}
|
||
#pdf-canvas-wrap{overflow:auto;flex:1;width:100%;display:flex;justify-content:flex-start;align-items:flex-start;background:#111;}
|
||
#pdf-main-canvas{display:block;cursor:crosshair;}
|
||
|
||
/* Slideshow overlay */
|
||
#slideshow{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column;align-items:center;justify-content:center;}
|
||
#slideshow.open{display:flex;}
|
||
.ss-img-wrap{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;width:100%;padding:16px 80px;}
|
||
#ss-img{max-width:100%;max-height:100%;object-fit:contain;border-radius:4px;}
|
||
.ss-bar{width:100%;padding:14px 20px;display:flex;align-items:center;gap:12px;background:rgba(0,0,0,.6);flex-shrink:0;}
|
||
.ss-btn{background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.2);color:#fff;border-radius:8px;padding:8px 18px;font-size:14px;cursor:pointer;transition:.15s;}
|
||
.ss-btn:hover{background:rgba(255,255,255,.22);}
|
||
.ss-counter{color:#fff;font-size:14px;font-weight:600;min-width:60px;text-align:center;}
|
||
.ss-title{color:rgba(255,255,255,.7);font-size:13px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
||
.ss-nav{position:absolute;top:50%;transform:translateY(-50%);background:rgba(0,0,0,.4);border:none;color:#fff;font-size:28px;width:52px;height:52px;border-radius:50%;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:.2s;}
|
||
.ss-nav:hover{background:rgba(99,102,241,.6);}
|
||
#ss-prev{left:12px;}
|
||
#ss-nav-next{right:12px;}
|
||
|
||
/* ── Slide Editor Modal ─────────────────────────────────────────────────── */
|
||
.sedmodal{width:1200px;height:90vh;max-width:98vw;max-height:98vh;border-radius:10px;position:fixed;box-shadow:0 8px 40px rgba(0,0,0,.6);cursor:default;overflow:hidden;left:50%;top:50%;transform:translate(-50%,-50%);}
|
||
.sed-hd{cursor:move;user-select:none;}
|
||
.sed-hd{display:flex;align-items:center;gap:8px;padding:10px 18px;border-bottom:1px solid var(--line);flex-shrink:0;}
|
||
.sed-body{display:flex;flex:1;min-height:0;overflow:hidden;}
|
||
.sed-ctrl{width:340px;flex-shrink:0;border-right:1px solid var(--line);overflow-y:auto;padding:16px 18px;display:flex;flex-direction:column;gap:16px;}
|
||
.sed-stage{flex:1;background:#080b12;display:flex;align-items:center;justify-content:center;padding:28px;min-width:0;position:relative;}
|
||
.sed-preview{position:relative;border-radius:6px;box-shadow:0 8px 48px rgba(0,0,0,.7);overflow:hidden;transition:background .2s;}
|
||
.sed-section-lbl{font-size:12px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:8px;display:block;}
|
||
.sed-hint{display:flex;gap:10px;font-size:10px;color:var(--muted);margin-top:3px;margin-bottom:4px;opacity:.7}
|
||
.sed-hint span{background:var(--panel2);padding:1px 6px;border-radius:4px}
|
||
.layout-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:5px;}
|
||
.layout-btn{background:var(--panel2);border:1.5px solid var(--line);border-radius:7px;padding:8px 4px 6px;cursor:pointer;text-align:center;transition:.15s;user-select:none;}
|
||
.layout-btn:hover{border-color:var(--brand);background:rgba(99,102,241,.08);}
|
||
.layout-btn.active{border-color:var(--brand);background:rgba(99,102,241,.15);color:var(--brand2);}
|
||
.layout-btn .li{font-size:13px;display:block;margin-bottom:3px;letter-spacing:.5px;font-family:monospace;}
|
||
.layout-btn .lt{font-size:11px;color:var(--muted);}
|
||
.layout-btn.active .lt{color:var(--brand2);font-weight:700;}
|
||
.sed-inp{width:100%;background:var(--panel);border:1px solid var(--line);border-radius:7px;padding:9px 12px;font-size:16px;color:var(--text);outline:none;font-family:inherit;resize:none;line-height:1.5;min-height:46px;}
|
||
.sed-inp:focus{border-color:var(--brand);}
|
||
.sed-ta{width:100%;background:var(--panel);border:1px solid var(--line);border-radius:7px;padding:9px 12px;font-size:15px;color:var(--text);font-family:'IBM Plex Mono',monospace;resize:vertical;outline:none;line-height:1.65;min-height:110px;}
|
||
.sed-ta:focus{border-color:var(--brand);}
|
||
.sed-row{display:flex;align-items:center;gap:8px;margin-top:6px;}
|
||
.sed-range{flex:1;accent-color:var(--brand);}
|
||
.sed-val{font-size:13px;font-weight:700;color:var(--brand2);min-width:40px;text-align:right;}
|
||
.sed-skin-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:4px;margin-top:5px;}
|
||
.sed-skin-sw{aspect-ratio:1;border-radius:5px;cursor:pointer;border:2px solid transparent;transition:.15s;}
|
||
.sed-skin-sw.active{border-color:var(--brand);box-shadow:0 0 0 2px var(--brand);transform:scale(1.15);}
|
||
.sed-skin-sw:hover{transform:scale(1.1);}
|
||
.fx-btn{font-size:11px;padding:3px 8px;border-radius:5px;background:var(--panel);border:1px solid var(--line);color:var(--muted);cursor:pointer;transition:.12s;}
|
||
.fx-btn:hover{border-color:var(--brand);color:var(--brand2);}
|
||
.fx-btn.active{background:var(--brand);border-color:var(--brand);color:#fff;}
|
||
.clr-row{display:flex;align-items:center;gap:6px;margin-top:5px;}
|
||
.clr-row label{font-size:11px;color:var(--muted);min-width:36px;}
|
||
.clr-row input[type=color]{width:28px;height:22px;border:1px solid var(--line);border-radius:4px;padding:0 2px;background:var(--panel);cursor:pointer;}
|
||
.clr-row .clr-reset{font-size:10px;color:var(--muted);cursor:pointer;padding:2px 5px;border:1px solid var(--line);border-radius:4px;background:var(--panel);}
|
||
.clr-row .clr-reset:hover{color:var(--red);border-color:var(--red);}
|
||
.sed-img-thumb{width:100%;height:100px;border-radius:6px;background:var(--panel) center/cover no-repeat;border:1px solid var(--line);display:flex;align-items:center;justify-content:center;font-size:28px;color:var(--muted);cursor:pointer;transition:.15s;}
|
||
.sed-img-thumb:hover{border-color:var(--brand);}
|
||
.sed-nav-info{font-size:12px;color:var(--muted);text-align:center;flex:1;}
|
||
|
||
/* ── mob-tab (inline, styles.css not loaded) ── */
|
||
.mob-tab{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;border:none;background:transparent;color:var(--muted);font-family:inherit;font-size:10px;font-weight:700;letter-spacing:.04em;cursor:pointer;padding:6px 4px;border-top:2px solid transparent;transition:color .15s,border-color .15s;-webkit-tap-highlight-color:transparent;}
|
||
.mob-tab.active{color:var(--brand);border-top-color:var(--brand);}
|
||
|
||
/* ── Mobile ── */
|
||
@media(max-width:1024px){
|
||
/* Header: compact */
|
||
.header{flex-wrap:wrap;padding:7px 12px;gap:6px;}
|
||
.header h1{font-size:13px;}
|
||
.header > div:has(.theme-btn){display:none;}
|
||
/* step dots: hide text labels, keep numbers */
|
||
.sdot{padding:5px 8px;font-size:0;}
|
||
.sdot .n{font-size:10px;}
|
||
.step-hint{display:none;}
|
||
.steps{gap:0;margin-left:auto;}
|
||
|
||
/* Sidebar: left overlay */
|
||
.sidebar{
|
||
position:fixed;top:0;left:0;bottom:52px;z-index:500;
|
||
width:82vw;max-width:310px;
|
||
transform:translateX(-100%);transition:transform .25s ease;
|
||
box-shadow:4px 0 28px rgba(0,0,0,.5);
|
||
order:0;
|
||
}
|
||
.sidebar.mob-open{transform:translateX(0);}
|
||
.sidebar-mob-theme{display:flex !important;}
|
||
|
||
#mob-backdrop{display:none;position:fixed;inset:0 0 52px 0;background:rgba(0,0,0,.55);z-index:499;}
|
||
#mob-backdrop.show{display:block;}
|
||
#mob-tabbar{display:flex !important;position:fixed;bottom:0;left:0;right:0;z-index:600;background:var(--bg);border-top:1px solid var(--line);height:52px;}
|
||
|
||
/* bottom padding for tabbar */
|
||
.body{padding-bottom:52px;}
|
||
.sv .scroll{padding-bottom:16px;}
|
||
|
||
/* Search row: wrap */
|
||
.srow{flex-wrap:wrap;}
|
||
.srow input{min-width:0;}
|
||
|
||
/* Source checkboxes: narrower */
|
||
.src-chk{width:calc(50% - 4px);min-width:0;}
|
||
|
||
/* Step 2: stack layout */
|
||
#step-2 .scroll > div[style*="flex:2"],
|
||
#step-2 .scroll > div[style*="flex:1"]{flex:1 1 100%;}
|
||
#step-2 .scroll{flex-wrap:wrap;}
|
||
|
||
/* Slide editor modal: full screen */
|
||
.sedmodal{width:100vw !important;height:100dvh !important;max-width:100vw;max-height:100dvh;border-radius:0;left:0;top:0;transform:none;}
|
||
.sed-body{flex-direction:column;}
|
||
.sed-ctrl{width:100%;max-height:40vh;border-right:none;border-bottom:1px solid var(--line);}
|
||
|
||
/* iOS zoom prevention */
|
||
input,textarea,select{font-size:16px !important;}
|
||
}
|
||
@media(min-width:1025px){
|
||
#mob-backdrop{display:none !important;}
|
||
#mob-tabbar{display:none !important;}
|
||
.sidebar-mob-theme{display:none !important;}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="header">
|
||
<span style="font-size:18px">📊</span>
|
||
<h1>슬라이드 제작 마법사</h1>
|
||
<div style="display:flex;gap:4px;margin-left:14px">
|
||
<button class="theme-btn active" id="tbtn-dark" onclick="setTheme('dark')">🌙 다크</button>
|
||
<button class="theme-btn" id="tbtn-light" onclick="setTheme('light')">☀️ 라이트</button>
|
||
<button class="theme-btn" id="tbtn-warm" onclick="setTheme('warm')">🌿 웜</button>
|
||
</div>
|
||
<div class="steps">
|
||
<span class="step-hint">← 번호 클릭으로 이동</span>
|
||
<div class="sdot active" id="sd1" onclick="goStep(1)"><div class="n">1</div>논문 검색</div>
|
||
<div class="sdot" id="sd2" onclick="goStep(2)"><div class="n">2</div>준비</div>
|
||
<div class="sdot" id="sd3" onclick="goStep(3)"><div class="n">3</div>아웃라인</div>
|
||
<div class="sdot" id="sd4" onclick="goStep(4)"><div class="n">4</div>프리뷰</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="mob-backdrop" onclick="mobCloseAll()"></div>
|
||
<div id="mob-tabbar" style="display:none">
|
||
<button class="mob-tab" id="mobtab-settings" onclick="mobToggle('settings')"><span style="font-size:18px">⚙</span>설정</button>
|
||
<button class="mob-tab active" id="mobtab-work" onclick="mobCloseAll()"><span style="font-size:18px">📊</span>작업</button>
|
||
</div>
|
||
|
||
<div class="body">
|
||
|
||
<!-- ── STEP 1 ── -->
|
||
<div class="sv active" id="step-1">
|
||
<div class="ptitle">논문 검색</div>
|
||
<div class="scroll">
|
||
<div style="display:flex;gap:6px;margin-bottom:6px;align-items:flex-start;flex-wrap:wrap">
|
||
<span style="font-size:11px;font-weight:700;color:var(--muted);margin-top:7px">검색 소스:</span>
|
||
<label class="src-chk" id="src-pubmed">
|
||
<input type="checkbox" checked onchange="updSrcState()">
|
||
<span>🔬 PubMed<span class="src-chk-desc"><b>임상·약물·생명과학.</b> NIH/NLM 공식 색인 — AHRQ·CDC 등 美 보건당국 지원 연구 포함. PMC 전문 PDF.</span></span>
|
||
</label>
|
||
<label class="src-chk" id="src-openalex">
|
||
<input type="checkbox" onchange="updSrcState()">
|
||
<span>🌐 OpenAlex<span class="src-chk-desc"><b>전 분야 2억+.</b> 보건정책·의료경제·사회과학까지. Nature·Science 포함, OA PDF.</span></span>
|
||
</label>
|
||
<label class="src-chk" id="src-semantic">
|
||
<input type="checkbox" onchange="updSrcState()">
|
||
<span>🧠 Semantic<span class="src-chk-desc"><b>자연어 문장 검색에 강함.</b> AI·CS·학제간, 인용 영향력 지수 제공.</span></span>
|
||
</label>
|
||
<label class="src-chk" id="src-europepmc">
|
||
<input type="checkbox" onchange="updSrcState()">
|
||
<span>🇪🇺 Europe PMC<span class="src-chk-desc"><b>생명과학, PubMed보다 넓음.</b> 유럽 저널·전임상 강세, PMC 전문 포함.</span></span>
|
||
</label>
|
||
</div>
|
||
<div style="font-size:10.5px;color:var(--muted);line-height:1.6;margin-bottom:8px;padding:6px 9px;background:rgba(99,102,241,.06);border-radius:7px">
|
||
💡 임상·약물·질병은 <b>PubMed</b> · 보건정책/의료경제/비교연구는 <b>OpenAlex + Semantic</b> · 자연어 문장으로 검색하면 <b>Semantic</b> · <b>“vs / versus”는 빼고</b> 키워드만 넣으세요.
|
||
</div>
|
||
<div class="srow">
|
||
<input id="qi" placeholder="예: sinus lift augmentation" onkeydown="if(event.key==='Enter')doSearch()">
|
||
<input class="yin" id="qy" type="number" placeholder="연도" min="1990" max="2030" value="2017">
|
||
<span style="font-size:11px;color:var(--muted);white-space:nowrap">이후 (선택)</span>
|
||
<select id="cfg-sort" style="background:var(--panel2);border:1px solid var(--line);border-radius:var(--r);padding:7px 9px;font-size:13px;color:var(--text);flex-shrink:0">
|
||
<option value="relevance">관련도순</option>
|
||
<option value="date">최신순</option>
|
||
</select>
|
||
<button id="pmc-filter-btn" class="btn bg" onclick="togglePmcFilter()" title="PMC 전문 있는 논문만 표시 (PDF 다운로드 가능)" style="flex-shrink:0;font-size:13px;padding:7px 11px;opacity:.6">PMC <span style="font-size:10px">PDF</span></button>
|
||
<button class="btn bp" onclick="doSearch()" id="sbtn" style="font-size:13px;padding:7px 14px">🔍 검색</button>
|
||
</div>
|
||
<div id="search-legend" style="display:none;padding:7px 12px;background:rgba(99,102,241,.07);border-radius:7px;margin-bottom:6px;font-size:11px;color:var(--muted);line-height:1.7">
|
||
<span style="color:var(--green);font-weight:700">■ PMC등재</span> — PubMed Central에 전문(PDF) 있음. 체크박스로 선택해 PPTX에 활용 가능.<br>
|
||
<span style="color:var(--red);font-weight:700">■ PMC미등재</span> — PMC에 전문 없음. 초록 보기 가능, PDF 다운로드 불가.<br>
|
||
<span style="color:var(--brand2);font-weight:700">■ 연도</span> — 출판 연도 | <span style="color:#fcd34d;font-weight:700">■ 유형</span> — 논문 종류 (RCT, Review 등)
|
||
</div>
|
||
<div id="results"></div>
|
||
<div style="padding:8px 0 2px;display:flex;align-items:center;gap:8px;color:var(--muted);font-size:11px">
|
||
<div style="flex:1;height:1px;background:var(--line)"></div>또는 PDF 직접 업로드<div style="flex:1;height:1px;background:var(--line)"></div>
|
||
</div>
|
||
<div class="dropzone" id="pdf-dropzone"
|
||
onclick="document.getElementById('pdf-file-input').click()"
|
||
ondragover="event.preventDefault();this.classList.add('drag')"
|
||
ondragleave="this.classList.remove('drag')"
|
||
ondrop="this.classList.remove('drag');handlePdfDrop(event)">
|
||
<input type="file" id="pdf-file-input" accept=".pdf" multiple onchange="handlePdfFileInput(this)">
|
||
📄 PDF 파일을 드래그하거나 클릭해서 선택<br>
|
||
<span style="font-size:10px">여러 파일 동시 업로드 가능</span>
|
||
</div>
|
||
<div id="upload-list"></div>
|
||
</div>
|
||
<div class="bbar">
|
||
<span class="smsg" id="s1msg"></span><div class="sp"></div>
|
||
<button class="btn bp" id="s1next" onclick="goStep(2)" disabled>▶ PDF 준비 →</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── STEP 2 ── -->
|
||
<div class="sv" id="step-2">
|
||
<div class="ptitle">PDF 다운로드</div>
|
||
<div class="scroll" style="display:flex;gap:14px">
|
||
<div style="flex:1;min-width:0">
|
||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
|
||
<span style="font-size:10px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.04em">진행 상황</span>
|
||
<span id="s2-overall" style="display:none;font-size:11px;color:var(--brand2);font-weight:700"></span>
|
||
</div>
|
||
<div id="proglist"></div>
|
||
<div id="img-search-section" style="margin-top:14px;border-top:1px solid var(--line);padding-top:10px">
|
||
<div style="font-size:10px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.04em;margin-bottom:6px">🔍 이미지 검색</div>
|
||
<div style="display:flex;gap:6px">
|
||
<input id="img-search-input" type="text" placeholder="예: 구강 해부도, TMJ X-ray"
|
||
style="flex:1;font-size:12px;padding:4px 8px;background:var(--panel2);border:1px solid var(--line);border-radius:5px;color:var(--fg);outline:none"
|
||
onkeydown="if(event.key==='Enter')doImgSearch()">
|
||
<button class="btn bg" style="font-size:11px;padding:3px 10px;flex-shrink:0" onclick="doImgSearch()">검색</button>
|
||
</div>
|
||
<div id="img-search-results" style="margin-top:8px;max-height:260px;overflow-y:auto"></div>
|
||
</div>
|
||
</div>
|
||
<div style="flex:2;min-width:0">
|
||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
|
||
<span style="font-size:10px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.04em">캡처 이미지 <span id="imgcnt"></span></span>
|
||
<button id="btn-analyze-imgs" onclick="analyzeImages()" style="font-size:11px;color:#10b981;background:rgba(16,185,129,.1);border:1px solid #10b981;border-radius:5px;padding:2px 8px;cursor:pointer;flex-shrink:0" title="미분석 이미지를 mistral vision으로 재분석 (준비 실행 시 자동 처리됨)">🔍 재분석</button>
|
||
<button onclick="downloadAllImgs()" style="font-size:11px;color:#60a5fa;background:rgba(96,165,250,.1);border:1px solid #60a5fa;border-radius:5px;padding:2px 8px;cursor:pointer;flex-shrink:0" title="전체 이미지 다운로드">⬇ 전체</button>
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:11px;color:var(--brand2);background:rgba(99,102,241,.1);border:1px solid var(--brand);border-radius:5px;padding:2px 8px;cursor:pointer;flex-shrink:0" title="이미지 파일 업로드">
|
||
<input type="file" id="img-upload-input" accept="image/*" multiple style="display:none" onchange="handleImgUpload(this.files)">
|
||
+ 이미지 업로드
|
||
</label>
|
||
</div>
|
||
<div id="img-dropzone"
|
||
style="border:2px dashed var(--line);border-radius:7px;padding:6px 10px;text-align:center;font-size:11px;color:var(--muted);margin-bottom:7px;cursor:pointer;transition:.15s"
|
||
onclick="document.getElementById('img-upload-input').click()"
|
||
ondragover="event.preventDefault();this.style.borderColor='var(--brand)';this.style.color='var(--brand2)'"
|
||
ondragleave="this.style.borderColor='';this.style.color=''"
|
||
ondrop="event.preventDefault();this.style.borderColor='';this.style.color='';handleImgUpload(event.dataTransfer.files)">
|
||
이미지 파일을 여기에 드래그하거나 클릭
|
||
</div>
|
||
<div class="igrid" id="imgrid"></div>
|
||
</div>
|
||
</div>
|
||
<div class="bbar">
|
||
<span class="smsg" id="s2msg"></span><div class="sp"></div>
|
||
<button class="btn bp" id="s2start" onclick="startPrep()">▶ 시작</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── STEP 3 ── -->
|
||
<div class="sv" id="step-3">
|
||
<div class="ptitle">슬라이드 아웃라인 편집</div>
|
||
<div class="scroll" id="outline-scroll">
|
||
<div id="outline-cards" style="padding-bottom:8px">
|
||
<div style="color:var(--muted);font-size:12px;text-align:center;padding:24px 0">준비 단계 완료 후 아웃라인이 자동 생성됩니다</div>
|
||
</div>
|
||
</div>
|
||
<div class="bbar">
|
||
<span class="smsg" id="s3msg"></span><div class="sp"></div>
|
||
<button class="btn bgreen" id="s3create" onclick="createPptx()" disabled>✅ PPTX 생성 →</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── STEP 4 ── -->
|
||
<div class="sv" id="step-4">
|
||
<div class="ptitle">슬라이드 프리뷰</div>
|
||
<div class="scroll">
|
||
<div id="preview-hint" style="display:none;padding:7px 14px;background:rgba(99,102,241,.07);border-radius:7px;margin-bottom:8px;font-size:12px;color:var(--muted);line-height:1.6">
|
||
카드에 마우스를 올리면 <strong>✏ 편집</strong> 버튼이 나타납니다. 편집 후 <strong>🔄 PPTX 재생성</strong>으로 업데이트하세요. | 카드 이미지를 클릭하면 슬라이드 쇼를 시작합니다.
|
||
</div>
|
||
<div id="preview-grid" class="preview-grid">
|
||
<div style="color:var(--muted);font-size:12px;text-align:center;padding:24px 0;grid-column:1/-1">PPTX 생성 후 프리뷰가 표시됩니다</div>
|
||
</div>
|
||
<div style="margin-top:14px;padding:8px 12px;border-top:1px solid var(--line);font-size:11px;color:var(--muted);line-height:1.7">
|
||
↑ 상단 <strong>1 · 2 · 3</strong> 단계 버튼을 클릭하면 이전 단계로 돌아갈 수 있습니다. 
|
||
논문 추가·변경 → <strong>1단계</strong>, PDF 처리 재실행 → <strong>2단계</strong>, 아웃라인 수정 → <strong>3단계</strong>.
|
||
</div>
|
||
</div>
|
||
<div class="bbar">
|
||
<span class="smsg" id="s4msg"></span><div class="sp"></div>
|
||
<button class="btn bg" onclick="reloadPreview()">↺ 새로고침</button>
|
||
<button class="btn bg" id="ss-launch" onclick="ssStart()" disabled>▶ 슬라이드 쇼</button>
|
||
<button class="btn bgreen" id="s4-regen" onclick="s4Regen()" style="display:none">🔄 PPTX 재생성</button>
|
||
<a id="dl-btn" class="btn bgreen" style="text-decoration:none;display:none" download>⬇ 다운로드</a>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── SETTINGS SIDEBAR ── -->
|
||
<div class="sidebar">
|
||
<div class="ptitle" style="display:flex;align-items:center;justify-content:space-between">
|
||
<span>설정</span>
|
||
<div class="sidebar-mob-theme" style="display:none;gap:4px;align-items:center">
|
||
<button class="theme-btn" id="tbtn-dark2" onclick="setTheme('dark')" style="padding:2px 8px;font-size:11px">🌙</button>
|
||
<button class="theme-btn" id="tbtn-light2" onclick="setTheme('light')" style="padding:2px 8px;font-size:11px">☀️</button>
|
||
<button class="theme-btn" id="tbtn-warm2" onclick="setTheme('warm')" style="padding:2px 8px;font-size:11px">🌿</button>
|
||
<button onclick="mobCloseAll()" style="background:none;border:none;color:var(--muted);cursor:pointer;font-size:16px;padding:0 4px;line-height:1">✕</button>
|
||
</div>
|
||
</div>
|
||
<div class="scroll">
|
||
<div class="field">
|
||
<button class="btn bgreen" style="width:100%;font-size:12px;padding:7px 0" onclick="newProject()">+ 새 프로젝트</button>
|
||
</div>
|
||
<div class="field">
|
||
<label class="flabel">기존 프로젝트 열기</label>
|
||
<div style="display:flex;gap:5px">
|
||
<select id="cfg-open-proj" style="flex:1;background:var(--panel2);border:1px solid var(--line);border-radius:7px;padding:4px 6px;font-size:12px;color:var(--text);outline:none" onchange="onOpenProjChange(this.value)">
|
||
<option value="">— 선택 —</option>
|
||
</select>
|
||
<button class="btn bg" style="font-size:11px;padding:4px 8px;flex-shrink:0" onclick="loadProjList()" title="목록 새로고침">↺</button>
|
||
<button class="btn bred" style="font-size:11px;padding:4px 8px;flex-shrink:0" onclick="deleteSelectedProject()" title="선택한 프로젝트 폴더 삭제">🗑</button>
|
||
</div>
|
||
</div>
|
||
<div class="field">
|
||
<label class="flabel">모델 요청</label>
|
||
<textarea id="cfg-topic" placeholder="예: 상악동 거상술 최신 동향에 대해 치과의사 대상 학회 발표 자료를 만들어주세요. 임상 적용 위주로 구성하고 핵심 수치를 강조해주세요." style="width:100%;background:var(--panel2);border:1px solid var(--line);border-radius:7px;padding:7px 9px;font-size:12px;color:var(--text);resize:vertical;outline:none;line-height:1.6;min-height:72px;font-family:inherit" onfocus="this.style.borderColor='var(--brand)'" onblur="this.style.borderColor='var(--line)'"></textarea>
|
||
</div>
|
||
<div class="field">
|
||
<label class="flabel">프로젝트 폴더명</label>
|
||
<input type="text" id="cfg-project" placeholder="자동 (아웃라인 생성 후 채워짐)" style="width:100%;background:var(--panel2);border:1px solid var(--line);border-radius:7px;padding:5px 8px;font-size:12px;color:var(--text);outline:none;font-family:inherit" onfocus="this.style.borderColor='var(--brand)'" onblur="this.style.borderColor='var(--line)'">
|
||
</div>
|
||
<div class="field">
|
||
<label class="flabel">슬라이드 수</label>
|
||
<input type="number" id="cfg-slides" min="5" max="30" value="12">
|
||
</div>
|
||
<div class="field">
|
||
<label class="flabel">템플릿 <span id="tmpl-lbl" style="font-weight:400;text-transform:none;font-size:11px;margin-left:4px;color:var(--text)">creative</span></label>
|
||
<input type="hidden" id="cfg-tmpl" value="creative">
|
||
<div class="skin-grid" id="tmpl-grid" style="grid-template-columns:repeat(6,1fr)"></div>
|
||
</div>
|
||
<div class="field">
|
||
<label class="flabel">배경 스킨 <span id="skin-name-lbl" style="font-weight:400;text-transform:none;margin-left:4px"></span></label>
|
||
<div class="skin-grid" id="skin-grid"></div>
|
||
</div>
|
||
<div class="field">
|
||
<label class="flabel">PDF 이미지 자동 추출</label>
|
||
<label style="display:flex;align-items:flex-start;gap:8px;font-size:12px;color:var(--text);cursor:pointer;line-height:1.5">
|
||
<input type="checkbox" id="cfg-auto-img" checked onchange="onAutoImgToggle()" style="accent-color:var(--brand);width:15px;height:15px;cursor:pointer;margin-top:1px;flex-shrink:0">
|
||
<span id="cfg-auto-img-lbl"></span>
|
||
</label>
|
||
</div>
|
||
<div class="field">
|
||
<label class="flabel">PDF 본문 텍스트 추출</label>
|
||
<label style="display:flex;align-items:flex-start;gap:8px;font-size:12px;color:var(--text);cursor:pointer;line-height:1.5">
|
||
<input type="checkbox" id="cfg-extract-txt" checked onchange="onExtractTxtToggle()" style="accent-color:var(--brand);width:15px;height:15px;cursor:pointer;margin-top:1px;flex-shrink:0">
|
||
<span id="cfg-extract-txt-lbl"></span>
|
||
</label>
|
||
</div>
|
||
<div class="field">
|
||
<label class="flabel">본문 자동 번역</label>
|
||
<label style="display:flex;align-items:flex-start;gap:8px;font-size:12px;color:var(--text);cursor:pointer;line-height:1.5">
|
||
<input type="checkbox" id="cfg-auto-txl" checked onchange="onAutoTxlToggle()" style="accent-color:var(--brand);width:15px;height:15px;cursor:pointer;margin-top:1px;flex-shrink:0">
|
||
<span id="cfg-auto-txl-lbl"></span>
|
||
</label>
|
||
</div>
|
||
<div class="field" style="margin-top:14px;border-top:1px solid var(--line);padding-top:12px">
|
||
<label class="flabel">선택된 논문</label>
|
||
<div id="sel-summary" style="font-size:10px;color:var(--muted)">없음</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Abstract modal -->
|
||
<div class="mbg" id="abg">
|
||
<div class="modal amodal">
|
||
<div class="amodal-hd">
|
||
<div class="amodal-title" id="am-title"></div>
|
||
<div class="amodal-meta" id="am-meta"></div>
|
||
</div>
|
||
<div class="atabs">
|
||
<button class="atab active" id="at-en" onclick="switchAbTab('en')">영문</button>
|
||
<button class="atab" id="at-ko" onclick="switchAbTab('ko')">한국어 번역</button>
|
||
</div>
|
||
<div class="amodal-body" id="am-body">로딩 중...</div>
|
||
<div class="amodal-ft">
|
||
<button class="btn bg" id="am-translate-btn" onclick="translateAbstract()">🌐 번역</button>
|
||
<button class="btn bg" onclick="closeAbModal()">닫기</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Slideshow overlay -->
|
||
<div id="slideshow">
|
||
<button class="ss-nav" id="ss-prev" onclick="ssPrev()">‹</button>
|
||
<button class="ss-nav" id="ss-nav-next" onclick="ssNext()">›</button>
|
||
<div class="ss-img-wrap"><img id="ss-img" src="" alt=""></div>
|
||
<div class="ss-bar">
|
||
<button class="ss-btn" onclick="ssPrev()">← 이전</button>
|
||
<span class="ss-counter" id="ss-counter">1 / 1</span>
|
||
<button class="ss-btn" onclick="ssNext()">다음 →</button>
|
||
<span class="ss-title" id="ss-title"></span>
|
||
<button class="ss-btn" onclick="ssToggleAuto()" id="ss-auto-btn">⏵ 자동</button>
|
||
<button class="ss-btn" onclick="ssClose()" style="margin-left:auto">✕ 닫기</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Image picker modal -->
|
||
<div class="mbg" id="ibg" style="z-index:600">
|
||
<div class="modal imodal">
|
||
<div class="imodal-hd">이미지 선택</div>
|
||
<div class="imodal-body"><div class="igrid" id="imodal-grid"></div></div>
|
||
<div class="imodal-ft">
|
||
<button class="btn bg" onclick="closeIModal()">취소</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- PDF Translation modal -->
|
||
<div class="mbg" id="txlbg" onclick="if(event.target===this)closeTxlModal()">
|
||
<div class="modal txlmodal" onclick="event.stopPropagation()">
|
||
<div class="txlmodal-hd">
|
||
<span style="font-size:14px">📄</span>
|
||
<span id="txl-title" style="font-size:13px;font-weight:700;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">전문</span>
|
||
<button class="btn bg" style="padding:3px 10px;font-size:11px" id="txl-tab-en" onclick="switchTxlTab('en')">원문</button>
|
||
<button class="btn bg" style="padding:3px 10px;font-size:11px" id="txl-tab-ko" onclick="switchTxlTab('ko')">번역</button>
|
||
<button class="btn bg" style="padding:3px 10px;font-size:11px" onclick="copyTxlText()">복사</button>
|
||
<button class="btn bg" style="padding:3px 10px;font-size:11px" onclick="downloadTxlText()">⬇ 다운로드</button>
|
||
<button class="btn bg" style="padding:3px 10px;font-size:11px" onclick="closeTxlModal()">✕</button>
|
||
</div>
|
||
<div class="txlmodal-body" id="txl-body"></div>
|
||
<div class="txlmodal-ft">
|
||
<span id="txl-status" style="font-size:11px;color:var(--muted);flex:1"></span>
|
||
<button class="btn bg" onclick="closeTxlModal()">닫기</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Image lightbox -->
|
||
<div class="mbg" id="lbg" onclick="closeImgPreview()" style="z-index:400">
|
||
<div style="position:relative;max-width:90vw;max-height:90vh;display:flex;flex-direction:column;gap:8px" onclick="event.stopPropagation()">
|
||
<div style="display:flex;justify-content:space-between;align-items:center">
|
||
<span id="lb-label" style="color:rgba(255,255,255,.7);font-size:12px;max-width:80vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></span>
|
||
<button onclick="closeImgPreview()" style="background:rgba(255,255,255,.15);border:none;color:#fff;border-radius:6px;padding:4px 10px;cursor:pointer;font-size:13px;margin-left:12px">✕</button>
|
||
</div>
|
||
<img id="lb-img" src="" style="max-width:88vw;max-height:82vh;border-radius:8px;display:block;box-shadow:0 8px 32px rgba(0,0,0,.6)">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Slide Editor Modal -->
|
||
<div class="mbg" id="sedbg" onclick="if(event.target===this)closeSed()" style="padding:0;align-items:center;justify-content:center">
|
||
<div class="modal sedmodal" onclick="event.stopPropagation()">
|
||
<div class="sed-hd">
|
||
<div class="snum" id="sed-num">1</div>
|
||
<span class="stype-tag" id="sed-type"></span>
|
||
<span id="sed-title-lbl" style="flex:1;font-size:14px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin:0 10px;color:var(--text)"></span>
|
||
<span class="sed-nav-info"><span id="sed-cur">1</span> / <span id="sed-total">1</span></span>
|
||
<button class="btn bg" style="padding:5px 12px" onclick="sedNav(-1)">← 이전</button>
|
||
<button class="btn bg" style="padding:5px 12px" onclick="sedNav(1)">다음 →</button>
|
||
<button class="btn bg" style="padding:5px 12px" onclick="closeSed()">✕ 닫기</button>
|
||
</div>
|
||
<div class="sed-body">
|
||
<!-- Controls -->
|
||
<div class="sed-ctrl">
|
||
<!-- Layout -->
|
||
<div id="sed-layout-sec">
|
||
<span class="sed-section-lbl">레이아웃</span>
|
||
<div class="layout-grid">
|
||
<div class="layout-btn" data-layout="split-right" onclick="sedSetLayout('split-right')"><span class="li">T|I</span><span class="lt">텍스트+이미지</span></div>
|
||
<div class="layout-btn" data-layout="split-left" onclick="sedSetLayout('split-left')"><span class="li">I|T</span><span class="lt">이미지+텍스트</span></div>
|
||
<div class="layout-btn" data-layout="text" onclick="sedSetLayout('text')"><span class="li">T</span><span class="lt">텍스트만</span></div>
|
||
<div class="layout-btn" data-layout="fullscreen" onclick="sedSetLayout('fullscreen')"><span class="li">[I]</span><span class="lt">전체이미지</span></div>
|
||
<div class="layout-btn" data-layout="compare" onclick="sedSetLayout('compare')"><span class="li">||</span><span class="lt">2단비교</span></div>
|
||
</div>
|
||
</div>
|
||
<!-- Title -->
|
||
<div>
|
||
<span class="sed-section-lbl">제목</span>
|
||
<textarea class="sed-inp" id="sed-title-inp" oninput="sedChange()" onkeydown="setTimeout(sedRenderPreview,0)" placeholder="슬라이드 제목" rows="2"></textarea>
|
||
<div class="sed-row">
|
||
<span style="font-size:11px;color:var(--muted)">제목 크기</span>
|
||
<input type="range" class="sed-range" id="sed-title-size" min="14" max="52" step="1" oninput="sedChange()">
|
||
<span class="sed-val" id="sed-title-size-val">28pt</span>
|
||
</div>
|
||
</div>
|
||
<!-- Subtitle (title-type only) -->
|
||
<div id="sed-subtitle-sec">
|
||
<span class="sed-section-lbl">부제목</span>
|
||
<textarea class="sed-inp" id="sed-subtitle-inp" oninput="sedChange()" onkeydown="setTimeout(sedRenderPreview,0)" placeholder="부제목" rows="2"></textarea>
|
||
</div>
|
||
<!-- Bullets -->
|
||
<div id="sed-bullets-sec">
|
||
<span class="sed-section-lbl">내용</span>
|
||
<textarea class="sed-ta" id="sed-bullets-ta" oninput="sedChange()" onkeydown="setTimeout(sedRenderPreview,0)"></textarea>
|
||
<div class="sed-hint">
|
||
<span>Enter = 같은 항목 줄바꿈</span>
|
||
<span>빈 줄 = 새 항목 ●</span>
|
||
<span>- 시작 = 하위 항목 –</span>
|
||
</div>
|
||
<div class="sed-row">
|
||
<span style="font-size:11px;color:var(--muted)">본문 크기</span>
|
||
<input type="range" class="sed-range" id="sed-body-size" min="10" max="36" step="1" oninput="sedChange()">
|
||
<span class="sed-val" id="sed-body-size-val">18pt</span>
|
||
</div>
|
||
</div>
|
||
<!-- Image -->
|
||
<div id="sed-img-sec">
|
||
<span class="sed-section-lbl">이미지</span>
|
||
<div class="sed-img-thumb" id="sed-img-thumb" onclick="sedPickImg()">🖼</div>
|
||
<input type="text" class="sed-inp" id="sed-img-url-inp" placeholder="URL 직접 붙여넣기" style="margin-top:5px;font-size:11px" oninput="sedImgUrlInput()">
|
||
<div style="display:flex;gap:6px;margin-top:5px">
|
||
<button class="btn bg" style="flex:1;font-size:12px" onclick="sedPickImg()">🖼 선택</button>
|
||
<button class="btn bp" style="flex:1;font-size:12px" onclick="sedAutoExtract()">📷 자동추출</button>
|
||
<button class="btn bg" style="font-size:12px;color:var(--red)" onclick="sedClearImg()">✕</button>
|
||
</div>
|
||
<button class="btn bg" style="width:100%;font-size:11px;margin-top:4px;color:var(--muted)" onclick="sedOpenPdfPicker()">✂ 수동 캡처 (PDF 드래그)</button>
|
||
<div class="sed-row" style="margin-top:8px">
|
||
<span style="font-size:11px;color:var(--muted)">이미지 크기</span>
|
||
<input type="range" class="sed-range" id="sed-img-scale" min="20" max="80" step="5" oninput="sedChange()">
|
||
<span class="sed-val" id="sed-img-scale-val">50%</span>
|
||
</div>
|
||
</div>
|
||
<!-- Font -->
|
||
<div>
|
||
<span class="sed-section-lbl">폰트</span>
|
||
<div class="sed-row" style="margin-top:2px">
|
||
<span style="font-size:11px;color:var(--muted);min-width:36px">패밀리</span>
|
||
<select id="sed-font-family" style="flex:1;background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:3px 6px;font-size:12px;color:var(--text)" onchange="sedChange()">
|
||
<option value="">기본 (Calibri/맑은고딕)</option>
|
||
<option value="Malgun Gothic">맑은 고딕</option>
|
||
<option value="NanumGothic">나눔고딕</option>
|
||
<option value="Arial">Arial</option>
|
||
<option value="Calibri">Calibri</option>
|
||
<option value="Georgia">Georgia</option>
|
||
<option value="Times New Roman">Times New Roman</option>
|
||
</select>
|
||
</div>
|
||
<div class="clr-row">
|
||
<label>제목색</label>
|
||
<input type="color" id="sed-title-color" value="#1a1a2e" oninput="sedChange()">
|
||
<button class="clr-reset" onclick="sedResetColor('title')">초기화</button>
|
||
</div>
|
||
<div class="clr-row">
|
||
<label>본문색</label>
|
||
<input type="color" id="sed-body-color" value="#2d3748" oninput="sedChange()">
|
||
<button class="clr-reset" onclick="sedResetColor('body')">초기화</button>
|
||
</div>
|
||
</div>
|
||
<!-- Image FX -->
|
||
<div id="sed-img-fx-sec">
|
||
<span class="sed-section-lbl">이미지 효과</span>
|
||
<div style="display:flex;gap:4px;flex-wrap:wrap;margin-top:4px">
|
||
<button class="fx-btn active" data-fx="" onclick="sedSetFx('')">원본</button>
|
||
<button class="fx-btn" data-fx="blur" onclick="sedSetFx('blur')">흐리게</button>
|
||
<button class="fx-btn" data-fx="grayscale" onclick="sedSetFx('grayscale')">흑백</button>
|
||
<button class="fx-btn" data-fx="contrast" onclick="sedSetFx('contrast')">대비↑</button>
|
||
<button class="fx-btn" data-fx="bright" onclick="sedSetFx('bright')">밝기↑</button>
|
||
<button class="fx-btn" data-fx="round" onclick="sedSetFx('round')">모서리</button>
|
||
</div>
|
||
<div id="sed-fx-blur-row" class="sed-row" style="display:none;margin-top:6px">
|
||
<span style="font-size:11px;color:var(--muted)">강도</span>
|
||
<input type="range" class="sed-range" id="sed-fx-blur" min="1" max="20" value="5" oninput="sedFxSlider()">
|
||
<span class="sed-val" id="sed-fx-blur-val">5</span>
|
||
</div>
|
||
<div id="sed-fx-round-row" class="sed-row" style="display:none;margin-top:6px">
|
||
<span style="font-size:11px;color:var(--muted)">반경</span>
|
||
<input type="range" class="sed-range" id="sed-fx-radius" min="5" max="50" value="15" oninput="sedFxSlider()">
|
||
<span class="sed-val" id="sed-fx-radius-val">15%</span>
|
||
</div>
|
||
</div>
|
||
<!-- Background -->
|
||
<div>
|
||
<span class="sed-section-lbl">배경 <span id="sed-skin-lbl" style="font-weight:400;text-transform:none;font-size:11px;margin-left:4px;color:var(--text)"></span></span>
|
||
<div class="sed-skin-grid" id="sed-skin-grid"></div>
|
||
<div style="display:flex;gap:5px;align-items:center;margin-top:6px">
|
||
<div id="sed-bg-img-thumb" style="width:38px;height:26px;border:1px solid var(--line);border-radius:3px;background-size:cover;background-position:center;flex-shrink:0;font-size:10px;display:flex;align-items:center;justify-content:center;color:var(--muted)">🖼</div>
|
||
<button class="pickbtn" style="font-size:11px;padding:3px 8px" onclick="sedPickBgImg()">이미지 배경</button>
|
||
<button class="pickbtn" id="sed-bg-img-clear" style="font-size:11px;padding:3px 8px;color:var(--red);display:none" onclick="sedClearBgImg()">✕</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Preview Stage -->
|
||
<div class="sed-stage" id="sed-stage">
|
||
<div class="sed-preview" id="sed-preview"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- PDF Capture modal -->
|
||
<div class="mbg" id="pdfbg" onclick="if(event.target===this)closePdfModal()">
|
||
<div class="modal pdfmodal" onclick="event.stopPropagation()">
|
||
<div class="pdfmodal-hd">
|
||
<span style="font-size:13px;font-weight:700">📄 PDF 캡처</span>
|
||
<span id="pdf-modal-name" style="font-size:11px;color:var(--muted);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></span>
|
||
<button class="btn bg" style="padding:4px 10px;font-size:11px" onclick="pdfPrevPage()">◀</button>
|
||
<span id="pdf-page-lbl" style="font-size:12px;color:var(--muted);min-width:60px;text-align:center">1 / 1</span>
|
||
<button class="btn bg" style="padding:4px 10px;font-size:11px" onclick="pdfNextPage()">▶</button>
|
||
<button class="btn bg" style="padding:4px 10px;font-size:11px" onclick="pdfZoomStep(-1)">-</button>
|
||
<span id="pdf-zoom-lbl" style="font-size:12px;color:var(--muted);min-width:42px;text-align:center;cursor:pointer" title="클릭하여 초기화" onclick="pdfZoomReset()">100%</span>
|
||
<button class="btn bg" style="padding:4px 10px;font-size:11px" onclick="pdfZoomStep(1)">+</button>
|
||
<button class="btn bg" style="padding:4px 10px;font-size:11px" onclick="closePdfModal()">✕</button>
|
||
</div>
|
||
<div class="pdfmodal-body" id="pdfmodal-body">
|
||
<div id="pdf-canvas-wrap">
|
||
<canvas id="pdf-main-canvas"></canvas>
|
||
</div>
|
||
<div id="pdf-load-msg" style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#aaa;font-size:14px">페이지 로딩 중...</div>
|
||
</div>
|
||
<div class="pdfmodal-ft">
|
||
<span style="font-size:11px;color:var(--muted)">드래그로 영역 선택 → 캡처</span>
|
||
<div style="flex:1"></div>
|
||
<span id="pdf-sel-info" style="font-size:11px;color:var(--brand2);margin-right:8px"></span>
|
||
<button class="btn bg" id="pdf-capture-btn" onclick="pdfCapture()" disabled>📷 캡처</button>
|
||
<button class="btn bg" onclick="pdfClearSel()">✕ 선택 해제</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="/js/pptx/pptx-wizard.js"></script>
|
||
</body>
|
||
</html>
|