diff --git a/public/css/styles.css b/public/css/styles.css index cf0672f..99b3fdb 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -439,7 +439,7 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(-- .shadess-flag-btn{font-size:11px;padding:2px 6px;} /* Settings page */ -.settings-page{display:flex;flex-direction:column;gap:0;max-width:800px;} +.settings-page{display:flex;flex-direction:column;gap:0;} .settings-page .settings-section{padding:20px;margin-bottom:12px;border-radius:var(--radius);} .settings-page .settings-section h3{font-size:16px;font-weight:700;color:var(--g800);margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid var(--g100);display:flex;align-items:center;gap:8px;} .settings-page .settings-section p{font-size:13px;color:var(--g600);margin-bottom:12px;line-height:1.6;} @@ -548,10 +548,7 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(-- .lh-quiz-option input[type="radio"]{accent-color:var(--blue);width:18px;height:18px;flex-shrink:0;} .lh-quiz-option span{flex:1;} .lh-opt-correct{border-color:var(--green) !important;background:var(--green-light) !important;box-shadow:0 0 0 2px rgba(16,185,129,0.2) !important;} -.lh-opt-correct::after{content:'\\2713';position:absolute;right:14px;color:var(--green);font-weight:700;font-size:18px;} -.lh-quiz-option.lh-opt-correct,.lh-quiz-option.lh-opt-wrong{position:relative;} .lh-opt-wrong{border-color:var(--red) !important;background:var(--red-light) !important;box-shadow:0 0 0 2px rgba(239,68,68,0.2) !important;} -.lh-opt-wrong::after{content:'\\2717';position:absolute;right:14px;color:var(--red);font-weight:700;font-size:18px;} /* Quiz results */ .lh-result-item{margin-bottom:14px;padding-bottom:14px;border-bottom:1px solid var(--g100);} diff --git a/public/js/app.js b/public/js/app.js index 9265564..9a49c47 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -223,6 +223,18 @@ document.addEventListener('DOMContentLoaded', function() { // GLOBAL FUNCTIONS (must be outside DOMContentLoaded) // ============================================================ +// ── Set formatted text on output/contenteditable elements ── +// Converts \n to
so line breaks survive in contenteditable divs +// and are preserved when copying with innerText +function setOutputText(el, text) { + if (!el) return; + if (typeof el === 'string') el = document.getElementById(el); + if (!el) return; + // Escape HTML, then convert newlines to
+ var safe = String(text || '').replace(/&/g, '&').replace(//g, '>'); + el.innerHTML = safe.replace(/\n/g, '
'); +} + // ── Announcement banner ──────────────────────────────────── function loadAnnouncement() { fetch('/api/admin/config/announcement', { headers: getAuthHeaders() }) @@ -457,7 +469,7 @@ function refineDocument(outputElementId, inputElementId) { .then(function(r) { return r.json(); }) .then(function(data) { hideLoading(); - if (data.success) { doc.textContent = data.refined; input.value = ''; showToast('Refined!', 'success'); } + if (data.success) { setOutputText(doc, data.refined); input.value = ''; showToast('Refined!', 'success'); } else showToast(data.error || 'Failed', 'error'); }) .catch(function(err) { hideLoading(); showToast(err.message, 'error'); }); @@ -476,7 +488,7 @@ function shortenDocument(outputElementId) { .then(function(r) { return r.json(); }) .then(function(data) { hideLoading(); - if (data.success) { doc.textContent = data.shortened; showToast('Shortened!', 'success'); } + if (data.success) { setOutputText(doc, data.shortened); showToast('Shortened!', 'success'); } else showToast(data.error || 'Failed', 'error'); }) .catch(function(err) { hideLoading(); showToast(err.message, 'error'); }); diff --git a/public/js/chartReview.js b/public/js/chartReview.js index 21b0f8d..bbaab75 100644 --- a/public/js/chartReview.js +++ b/public/js/chartReview.js @@ -141,7 +141,7 @@ .then(function(data) { hideLoading(); if (data.success) { - reviewText.textContent = data.review; + setOutputText(reviewText, data.review); modelTag.textContent = (data.model || '').split('/').pop(); outputCard.classList.remove('hidden'); outputCard.scrollIntoView({ behavior: 'smooth' }); diff --git a/public/js/hospitalCourse.js b/public/js/hospitalCourse.js index 1eaf8ec..5e8bee9 100644 --- a/public/js/hospitalCourse.js +++ b/public/js/hospitalCourse.js @@ -152,7 +152,7 @@ .then(function(data) { hideLoading(); if (data.success) { - courseText.textContent = data.hospitalCourse; + setOutputText(courseText, data.hospitalCourse); formatTag.textContent = data.format || ''; modelTag.textContent = (data.model || '').split('/').pop(); outputCard.classList.remove('hidden'); @@ -183,7 +183,7 @@ .then(function(data) { hideLoading(); if (data.success) { - clarifyOutput.textContent = data.questions; + setOutputText(clarifyOutput, data.questions); clarifyOutput.classList.remove('hidden'); showToast('Review missing information below', 'info'); } diff --git a/public/js/liveEncounter.js b/public/js/liveEncounter.js index ce0a1bc..1d21875 100644 --- a/public/js/liveEncounter.js +++ b/public/js/liveEncounter.js @@ -125,7 +125,7 @@ .then(function(data) { hideLoading(); if (data.success) { - hpiText.textContent = data.hpi; + setOutputText(hpiText, data.hpi); modelTag.textContent = (data.model || '').split('/').pop(); outputCard.classList.remove('hidden'); outputCard.scrollIntoView({ behavior: 'smooth' }); diff --git a/public/js/milestones.js b/public/js/milestones.js index 7ba5f50..274c8ae 100644 --- a/public/js/milestones.js +++ b/public/js/milestones.js @@ -130,7 +130,7 @@ .then(function(data) { hideLoading(); if (data.success) { - narrativeText.textContent = data.narrative; + setOutputText(narrativeText, data.narrative); modelTag.textContent = (data.model || '').split('/').pop(); if (data.summary) { summaryBar.innerHTML = '
Achieved: ' + data.summary.achieved + '
' + @@ -172,7 +172,7 @@ btn.disabled = false; btn.innerHTML = ' Regenerate Summary'; if (data.success) { - document.getElementById('ms-summary-text').textContent = data.summary; + setOutputText('ms-summary-text', data.summary); document.getElementById('ms-quick-summary').classList.remove('hidden'); showToast('Summary generated!', 'success'); } diff --git a/public/js/shadess.js b/public/js/shadess.js index 5cc9c97..0b4a47b 100644 --- a/public/js/shadess.js +++ b/public/js/shadess.js @@ -366,7 +366,7 @@ var out = document.getElementById('shadess-result-text'); var outCard = document.getElementById('shadess-output'); var tag = document.getElementById('shadess-model-tag'); - if (out) out.textContent = data.assessment; + if (out) setOutputText(out, data.assessment); if (tag) tag.textContent = (data.model || '').split('/').pop(); if (outCard) { outCard.classList.remove('hidden'); outCard.scrollIntoView({ behavior: 'smooth' }); } showToast('SSHADESS assessment generated', 'success'); @@ -861,7 +861,7 @@ var noteEl = document.getElementById('wv-note-text'); var outCard = document.getElementById('wv-note-output'); var tag = document.getElementById('wv-note-model-tag'); - if (noteEl) noteEl.textContent = data.note; + if (noteEl) setOutputText(noteEl, data.note); if (tag) tag.textContent = (data.model || '').split('/').pop(); if (outCard) { outCard.classList.remove('hidden'); outCard.scrollIntoView({ behavior: 'smooth' }); } showToast('Well visit note generated!', 'success'); diff --git a/public/js/sickVisit.js b/public/js/sickVisit.js index f4c6aa4..a046f82 100644 --- a/public/js/sickVisit.js +++ b/public/js/sickVisit.js @@ -322,7 +322,7 @@ var noteEl = document.getElementById('sick-note-text'); var outCard = document.getElementById('sick-note-output'); var tag = document.getElementById('sick-note-model-tag'); - if (noteEl) noteEl.textContent = data.note; + if (noteEl) setOutputText(noteEl, data.note); if (tag) tag.textContent = (data.model || '').split('/').pop(); if (outCard) { outCard.classList.remove('hidden'); outCard.scrollIntoView({ behavior: 'smooth' }); } showToast('Sick visit note generated!', 'success'); diff --git a/public/js/soap.js b/public/js/soap.js index 4de26f7..bdd3b4b 100644 --- a/public/js/soap.js +++ b/public/js/soap.js @@ -82,7 +82,7 @@ .then(function(data) { hideLoading(); if (data.success) { - soapText.textContent = data.soap; + setOutputText(soapText, data.soap); modelTag.textContent = (data.model || '').split('/').pop(); outputCard.classList.remove('hidden'); outputCard.scrollIntoView({ behavior: 'smooth' }); diff --git a/public/js/voiceDictation.js b/public/js/voiceDictation.js index f0f4616..124ae05 100644 --- a/public/js/voiceDictation.js +++ b/public/js/voiceDictation.js @@ -137,7 +137,7 @@ .then(function(data) { hideLoading(); if (data.success) { - hpiText.textContent = data.hpi || data.soap; + setOutputText(hpiText, data.hpi || data.soap); modelTag.textContent = (data.model || '').split('/').pop(); outputCard.classList.remove('hidden'); outputCard.scrollIntoView({ behavior: 'smooth' });