@@ -9170,12 +9170,14 @@ MDHEAD
91709170 body {
91719171 max-width: 980px;
91729172 margin: 0 auto;
9173- padding: 45px 45px 80px ;
9173+ padding: 0 ;
91749174 background: #ffffff;
9175+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
91759176 }
91769177 .markdown-body {
91779178 min-width: 200px;
91789179 max-width: 980px;
9180+ padding: 24px 45px 80px;
91799181 }
91809182 @media (prefers-color-scheme: dark) {
91819183 body { background: #0d1117; }
@@ -9185,15 +9187,95 @@ MDHEAD
91859187 }
91869188 }
91879189 @media (max-width: 767px) {
9188- body { padding: 15px 15px 60px; }
9190+ .markdown- body { padding: 15px 15px 60px; }
91899191 }
91909192 @media print {
91919193 body { max-width: none; padding: 0; }
9194+ #md-toolbar { display: none; }
9195+ }
9196+ /* Toolbar */
9197+ #md-toolbar {
9198+ position: sticky; top: 0; z-index: 100;
9199+ display: flex; justify-content: space-between; align-items: center;
9200+ padding: 8px 16px;
9201+ background: #f6f8fa; border-bottom: 1px solid #d0d7de;
9202+ font-size: 14px;
9203+ }
9204+ #md-filename { font-weight: 600; color: #57606a; }
9205+ #md-toolbar button {
9206+ padding: 5px 16px; font-size: 14px; border-radius: 6px;
9207+ border: 1px solid rgba(27,31,36,0.15); cursor: pointer; margin-left: 8px;
9208+ font-weight: 500;
9209+ }
9210+ .btn-primary { background: #2ea44f !important; color: #fff !important; border-color: rgba(27,31,36,0.15) !important; }
9211+ .btn-primary:hover { background: #2c974b !important; }
9212+ .btn-default { background: #f6f8fa; color: #24292f; }
9213+ .btn-default:hover { background: #e1e4e8; }
9214+ @media (prefers-color-scheme: dark) {
9215+ #md-toolbar { background: #161b22; border-bottom-color: #30363d; }
9216+ #md-filename { color: #8b949e; }
9217+ .btn-default { background: #21262d; color: #c9d1d9; border-color: #30363d; }
9218+ .btn-default:hover { background: #30363d; }
9219+ }
9220+ /* Edit mode layout */
9221+ body.edit-mode { max-width: none; }
9222+ body.edit-mode #md-container { display: flex; height: calc(100vh - 45px); }
9223+ body.edit-mode #md-editor { display: flex !important; flex: 1; min-width: 0; border-right: 1px solid #d0d7de; }
9224+ body.edit-mode .markdown-body { flex: 1; min-width: 0; overflow-y: auto; padding: 24px 45px 80px; max-width: none; }
9225+ #md-source {
9226+ width: 100%; height: 100%; border: none; outline: none; resize: none;
9227+ padding: 24px; font-family: "SFMono-Regular",Consolas,"Liberation Mono",Menlo,monospace;
9228+ font-size: 14px; line-height: 1.6; background: #fff; color: #24292f; tab-size: 4;
9229+ }
9230+ @media (prefers-color-scheme: dark) {
9231+ body.edit-mode #md-editor { border-right-color: #30363d; }
9232+ #md-source { background: #0d1117; color: #e6edf3; }
9233+ }
9234+ /* Diff highlights */
9235+ .diff-added {
9236+ background: rgba(46,160,67,0.15); border-left: 3px solid #2ea44f;
9237+ padding-left: 8px; margin-left: -11px;
9238+ }
9239+ .diff-changed {
9240+ background: rgba(210,153,34,0.15); border-left: 3px solid #d29922;
9241+ padding-left: 8px; margin-left: -11px;
9242+ }
9243+ @media (prefers-color-scheme: dark) {
9244+ .diff-added { background: rgba(46,160,67,0.1); }
9245+ .diff-changed { background: rgba(210,153,34,0.1); }
9246+ }
9247+ /* Diff legend */
9248+ #diff-legend {
9249+ display: none; padding: 8px 16px; font-size: 12px; color: #57606a;
9250+ border-bottom: 1px solid #d0d7de; background: #f6f8fa;
9251+ }
9252+ #diff-legend.visible { display: flex; gap: 16px; align-items: center; }
9253+ #diff-legend span { display: inline-flex; align-items: center; gap: 4px; }
9254+ #diff-legend .swatch { width: 12px; height: 12px; border-radius: 2px; display: inline-block; }
9255+ @media (prefers-color-scheme: dark) {
9256+ #diff-legend { background: #161b22; border-bottom-color: #30363d; color: #8b949e; }
91929257 }
91939258 </style>
91949259</head>
91959260<body>
9196- <article class="markdown-body"></article>
9261+ <div id="md-toolbar">
9262+ <span id="md-filename"></span>
9263+ <div>
9264+ <button id="btn-edit" class="btn-primary" title="Edit markdown">Edit</button>
9265+ <button id="btn-save" class="btn-primary" style="display:none" title="Download edited file">Save</button>
9266+ <button id="btn-cancel" class="btn-default" style="display:none" title="Exit edit mode">Cancel</button>
9267+ </div>
9268+ </div>
9269+ <div id="diff-legend">
9270+ <span><span class="swatch" style="background:#d29922"></span> Changed</span>
9271+ <span><span class="swatch" style="background:#2ea44f"></span> Added</span>
9272+ </div>
9273+ <div id="md-container">
9274+ <article class="markdown-body" id="md-preview"></article>
9275+ <div id="md-editor" style="display:none">
9276+ <textarea id="md-source" spellcheck="false"></textarea>
9277+ </div>
9278+ </div>
91979279 <script>
91989280MDCSS
91999281 cat " $MD_ASSETS_DIR /marked.min.js"
@@ -9214,9 +9296,121 @@ MDCSS
92149296 var bytes=new Uint8Array(bin.length);
92159297 for(var i=0;i<bin.length;i++)bytes[i]=bin.charCodeAt(i);
92169298 var src=new TextDecoder('utf-8').decode(bytes);
9217- document.querySelector('.markdown-body').innerHTML=marked.parse(src);
9218- document.querySelectorAll('pre code').forEach(function(b){hljs.highlightElement(b);});
9299+ window.__originalMd=src;
9300+ window.__currentMd=src;
9301+ document.getElementById('md-preview').innerHTML=marked.parse(src);
9302+ document.querySelectorAll('#md-preview pre code').forEach(function(b){hljs.highlightElement(b);});
9303+ document.getElementById('md-filename').textContent=document.title;
92199304MDSCRIPT
9305+ echo " </script>"
9306+ echo " <script>"
9307+ cat << 'MDEDITJS '
9308+ (function(){
9309+ var preview=document.getElementById('md-preview');
9310+ var editor=document.getElementById('md-editor');
9311+ var source=document.getElementById('md-source');
9312+ var btnEdit=document.getElementById('btn-edit');
9313+ var btnSave=document.getElementById('btn-save');
9314+ var btnCancel=document.getElementById('btn-cancel');
9315+ var legend=document.getElementById('diff-legend');
9316+
9317+ function renderPreview(md,showDiff){
9318+ preview.innerHTML=marked.parse(md);
9319+ document.querySelectorAll('#md-preview pre code').forEach(function(b){hljs.highlightElement(b);});
9320+ if(showDiff) applyDiffHighlights();
9321+ }
9322+
9323+ function splitBlocks(text){
9324+ return text.split(/\n{2,}/).filter(function(b){return b.trim().length>0;});
9325+ }
9326+
9327+ function applyDiffHighlights(){
9328+ var origBlocks=splitBlocks(window.__originalMd);
9329+ var currBlocks=splitBlocks(window.__currentMd);
9330+ var children=preview.children;
9331+ var hasChanges=false;
9332+ // Walk through rendered children and mark changed/added blocks
9333+ var ci=0;
9334+ for(var i=0;i<children.length&&ci<Math.max(origBlocks.length,currBlocks.length);i++){
9335+ // Skip non-element nodes
9336+ if(children[i].nodeType!==1)continue;
9337+ if(ci>=origBlocks.length){
9338+ children[i].classList.add('diff-added');
9339+ hasChanges=true;
9340+ }else if(ci<currBlocks.length&&origBlocks[ci].trim()!==currBlocks[ci].trim()){
9341+ children[i].classList.add('diff-changed');
9342+ hasChanges=true;
9343+ }
9344+ ci++;
9345+ }
9346+ legend.className=hasChanges?'visible':'';
9347+ }
9348+
9349+ function enterEditMode(){
9350+ document.body.classList.add('edit-mode');
9351+ source.value=window.__currentMd;
9352+ btnEdit.style.display='none';
9353+ btnSave.style.display='';
9354+ btnCancel.style.display='';
9355+ legend.className='';
9356+ // Clear diff highlights for split view
9357+ Array.from(preview.children).forEach(function(el){
9358+ el.classList.remove('diff-added','diff-changed');
9359+ });
9360+ source.focus();
9361+ }
9362+
9363+ function exitEditMode(){
9364+ document.body.classList.remove('edit-mode');
9365+ btnEdit.style.display='';
9366+ btnSave.style.display='none';
9367+ btnCancel.style.display='none';
9368+ var hasChanges=window.__currentMd!==window.__originalMd;
9369+ renderPreview(window.__currentMd,hasChanges);
9370+ }
9371+
9372+ btnEdit.addEventListener('click',enterEditMode);
9373+ btnCancel.addEventListener('click',exitEditMode);
9374+
9375+ // Live preview with debounce
9376+ var timer;
9377+ source.addEventListener('input',function(){
9378+ clearTimeout(timer);
9379+ timer=setTimeout(function(){
9380+ window.__currentMd=source.value;
9381+ renderPreview(window.__currentMd,true);
9382+ },150);
9383+ });
9384+
9385+ // Save/download
9386+ btnSave.addEventListener('click',function(){
9387+ var content=window.__currentMd;
9388+ var blob=new Blob([content],{type:'text/markdown;charset=utf-8'});
9389+ var url=URL.createObjectURL(blob);
9390+ var a=document.createElement('a');
9391+ var origName=document.title.replace(/\.[^.]+$/,'');
9392+ a.href=url;
9393+ a.download=origName+'.edited.md';
9394+ document.body.appendChild(a);
9395+ a.click();
9396+ document.body.removeChild(a);
9397+ URL.revokeObjectURL(url);
9398+ });
9399+
9400+ // Keyboard shortcuts
9401+ document.addEventListener('keydown',function(e){
9402+ if((e.metaKey||e.ctrlKey)&&e.key==='s'){
9403+ if(document.body.classList.contains('edit-mode')){
9404+ e.preventDefault();
9405+ btnSave.click();
9406+ }
9407+ }
9408+ if(e.key==='Escape'&&document.body.classList.contains('edit-mode')){
9409+ exitEditMode();
9410+ }
9411+ });
9412+ })();
9413+ MDEDITJS
92209414 echo " </script>"
92219415 echo " </body>"
92229416 echo " </html>"
0 commit comments