@@ -149,6 +149,16 @@ def linkify(s: str) -> str:
149149 )
150150
151151
152+ def render_diff_row (typ : str , line : str ) -> str :
153+ prefix = {"ctx" : " " , "del" : "-" , "add" : "+" }[typ ]
154+ return (
155+ f' <tr class="diff-row { typ } ">'
156+ f'<td class="diff-gutter">{ prefix } </td>'
157+ f'<td class="diff-content">{ linkify (line )} </td>'
158+ f"</tr>"
159+ )
160+
161+
152162def render_diff_card (
153163 title : str , badge_class : str , badge_label : str , bibtidy_comments : list [str ], diff : list [tuple [str , str ]]
154164) -> str :
@@ -171,13 +181,14 @@ def render_diff_card(
171181 parts .append (f' <span class="diff-badge { badge_class } ">{ badge_label } </span>' )
172182 parts .append (" </div>" )
173183 parts .append (' <div class="diff-body">' )
184+ parts .append (' <table class="diff-table"><tbody>' )
174185 # bibtidy comments as added lines
175186 for comment in bibtidy_comments :
176- parts .append (f' <div class="diff-line add">+ { linkify ( comment )} </div>' )
187+ parts .append (render_diff_row ( " add", comment ))
177188 # diff lines
178189 for typ , line in diff :
179- prefix = { "ctx" : " " , "del" : "-" , "add" : "+" }[ typ ]
180- parts .append (f' <div class="diff-line { typ } "> { prefix } { linkify ( line ) } </div>' )
190+ parts . append ( render_diff_row ( typ , line ))
191+ parts .append (" </tbody></table>" )
181192 parts .append (" </div>" )
182193 parts .append ("</div>" )
183194 return "\n " .join (parts )
@@ -220,8 +231,6 @@ def build_html(cards_html: str) -> str:
220231 --badge-ok-bg: #f6f8fa;
221232 --badge-ok-text: #656d76;
222233 --badge-ok-border: #d0d7de;
223- --tab-active: #0969da;
224- --tab-hover: #f6f8fa;
225234 }}
226235
227236 @media (prefers-color-scheme: dark) {{
@@ -253,13 +262,16 @@ def build_html(cards_html: str) -> str:
253262 --badge-ok-bg: #30363d;
254263 --badge-ok-text: #8b949e;
255264 --badge-ok-border: #30363d;
256- --tab-active: #58a6ff;
257- --tab-hover: #161b22;
258265 }}
259266 }}
260267
261268 * {{ margin: 0; padding: 0; box-sizing: border-box; }}
262269
270+ html {{
271+ -webkit-text-size-adjust: 100%;
272+ text-size-adjust: 100%;
273+ }}
274+
263275 body {{
264276 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
265277 background: var(--bg);
@@ -292,33 +304,11 @@ def build_html(cards_html: str) -> str:
292304
293305 .container {{ max-width: 960px; margin: 0 auto; padding: 0 1rem 2rem; }}
294306
295- .tabs {{
296- display: flex;
297- border-bottom: 1px solid var(--border);
298- margin-bottom: 2rem;
299- }}
300-
301- .tab {{
302- padding: 0.75rem 1.25rem;
303- font-size: 0.9rem;
304- font-weight: 500;
307+ .intro {{
305308 color: var(--text-muted);
306- cursor: pointer;
307- border-bottom: 2px solid transparent;
308- margin-bottom: -1px;
309- background: none;
310- border-top: none;
311- border-left: none;
312- border-right: none;
313- font-family: inherit;
309+ margin: 2rem 0 1.5rem;
314310 }}
315311
316- .tab:hover {{ color: var(--text); background: var(--tab-hover); }}
317- .tab.active {{ color: var(--tab-active); border-bottom-color: var(--tab-active); }}
318-
319- .tab-content {{ display: none; }}
320- .tab-content.active {{ display: block; }}
321-
322312 .section-title {{
323313 font-size: 1.25rem;
324314 font-weight: 600;
@@ -329,7 +319,13 @@ def build_html(cards_html: str) -> str:
329319
330320 .section {{ margin-bottom: 2.5rem; }}
331321
332- .demo img {{ max-width: 100%; border-radius: 6px; border: 1px solid var(--border); }}
322+ .demo img {{
323+ display: block;
324+ max-width: 100%;
325+ height: auto;
326+ border-radius: 6px;
327+ border: 1px solid var(--border);
328+ }}
333329
334330 .install-step {{ margin-bottom: 1rem; }}
335331 .install-step p {{ color: var(--text-muted); font-size: 0.9rem; margin-bottom: 0.4rem; }}
@@ -339,14 +335,23 @@ def build_html(cards_html: str) -> str:
339335 border: 1px solid var(--border);
340336 border-radius: 6px;
341337 padding: 0.75rem 1rem;
342- font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
338+ font-family: ui-monospace, 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
343339 font-size: 0.85rem;
344340 display: flex;
345341 align-items: center;
346342 justify-content: space-between;
343+ gap: 0.75rem;
344+ overflow: hidden;
347345 }}
348346
349- .code-block code {{ flex: 1; user-select: all; overflow-x: auto; }}
347+ .code-block code {{
348+ flex: 1;
349+ min-width: 0;
350+ display: block;
351+ user-select: all;
352+ white-space: pre;
353+ overflow-x: auto;
354+ }}
350355
351356 .copy-btn {{
352357 background: none;
@@ -357,7 +362,6 @@ def build_html(cards_html: str) -> str:
357362 padding: 0.2rem 0.4rem;
358363 font-size: 0.75rem;
359364 font-family: inherit;
360- margin-left: 0.75rem;
361365 flex-shrink: 0;
362366 }}
363367
@@ -376,17 +380,25 @@ def build_html(cards_html: str) -> str:
376380 border-bottom: 1px solid var(--border);
377381 display: flex;
378382 align-items: center;
383+ flex-wrap: wrap;
379384 gap: 0.5rem;
380385 }}
381386
382- .diff-title {{ font-weight: 600; font-size: 0.9rem; }}
387+ .diff-title {{
388+ flex: 1 1 18rem;
389+ min-width: 0;
390+ font-weight: 600;
391+ font-size: 0.9rem;
392+ overflow-wrap: anywhere;
393+ }}
394+
395+ .diff-title a {{ overflow-wrap: anywhere; }}
383396
384397 .diff-badge {{
385398 font-size: 0.75rem;
386399 padding: 0.1rem 0.5rem;
387400 border-radius: 0.5rem;
388401 font-weight: 500;
389- margin-left: auto;
390402 }}
391403
392404 .badge-fix {{ background: var(--badge-fix-bg); color: var(--badge-fix-text); border: 1px solid var(--badge-fix-border); }}
@@ -396,23 +408,40 @@ def build_html(cards_html: str) -> str:
396408 .badge-ok {{ background: var(--badge-ok-bg); color: var(--badge-ok-text); border: 1px solid var(--badge-ok-border); }}
397409
398410 .diff-body {{
399- font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
411+ overflow-x: auto;
412+ }}
413+
414+ .diff-table {{
415+ width: max-content;
416+ min-width: 100%;
417+ border-collapse: collapse;
418+ font-family: ui-monospace, 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
400419 font-size: 0.8rem;
401420 line-height: 1.7;
402- overflow-x: auto;
421+ -webkit-text-size-adjust: none;
422+ text-size-adjust: none;
423+ -webkit-font-smoothing: antialiased;
424+ -moz-osx-font-smoothing: grayscale;
403425 }}
404426
405- .diff-hunk {{
406- background: var(--hunk-bg);
407- color: var(--hunk-text);
408- padding: 0.25rem 1rem;
409- font-size: 0.75rem;
427+ .diff-gutter,
428+ .diff-content {{
429+ white-space: pre;
430+ vertical-align: top;
431+ }}
432+
433+ .diff-gutter {{
434+ width: 2.5rem;
435+ padding: 0 0.75rem 0 1rem;
436+ user-select: none;
437+ color: var(--text-muted);
410438 }}
411439
412- .diff-line {{ padding: 0 1rem; white-space: pre; display: block; min-width: fit-content; }}
413- .diff-line.del {{ background: var(--del-bg); color: var(--del-line); }}
414- .diff-line.add {{ background: var(--add-bg); color: var(--add-line); }}
415- .diff-line.ctx {{ color: var(--text-muted); }}
440+ .diff-content {{ padding: 0 1rem 0 0; }}
441+
442+ .diff-row.del {{ background: var(--del-bg); color: var(--del-line); }}
443+ .diff-row.add {{ background: var(--add-bg); color: var(--add-line); }}
444+ .diff-row.ctx {{ color: var(--text-muted); }}
416445
417446 .stats {{ font-size: 0.8rem; color: var(--text-muted); margin-left: 0.5rem; }}
418447 .stats .add-count {{ color: var(--add-line); }}
@@ -435,18 +464,11 @@ def build_html(cards_html: str) -> str:
435464</div>
436465
437466<div class="container">
438-
439- <div class="tabs">
440- <button class="tab active" onclick="switchTab('bibtidy')">bibtidy</button>
441- </div>
442-
443- <div id="tab-bibtidy" class="tab-content active">
444-
445- <p style="color: var(--text-muted); margin-bottom: 1.5rem;">bibtidy cross-checks BibTeX entries against Google Scholar, CrossRef, and conference/journal sites. It upgrades arXiv/bioRxiv preprints to published versions (even when the title changed upon publication), corrects metadata (authors, pages, venues), and flags duplicate entries.</p>
467+ <p class="intro">bibtidy cross-checks BibTeX entries against Google Scholar, CrossRef, and conference/journal sites. It upgrades arXiv/bioRxiv preprints to published versions (even when the title changed upon publication), corrects metadata (authors, pages, venues), and flags duplicate entries.</p>
446468
447469<div class="section">
448470 <div class="demo">
449- <img src="bibtidy_demo.gif" alt="bibtidy demo">
471+ <img src="bibtidy_demo.gif" alt="bibtidy demo" width="1600" height="1200" >
450472 </div>
451473</div>
452474
@@ -457,24 +479,24 @@ def build_html(cards_html: str) -> str:
457479
458480 <div class="install-step">
459481 <p>Add the marketplace source:</p>
460- <div class="code-block"><code>/plugin marketplace add mathpluscode/bibtools</code><button class="copy-btn" onclick="copyCode(this)">Copy</button></div>
482+ <div class="code-block"><code>/plugin marketplace add mathpluscode/bibtools</code><button class="copy-btn" type="button" onclick="copyCode(this)">Copy</button></div>
461483 </div>
462484
463485 <div class="install-step">
464486 <p>Install the plugin:</p>
465- <div class="code-block"><code>/plugin install bibtools@mathpluscode-bibtools</code><button class="copy-btn" onclick="copyCode(this)">Copy</button></div>
487+ <div class="code-block"><code>/plugin install bibtools@mathpluscode-bibtools</code><button class="copy-btn" type="button" onclick="copyCode(this)">Copy</button></div>
466488 </div>
467489
468490 <div class="install-step">
469491 <p>Reload plugins:</p>
470- <div class="code-block"><code>/reload-plugins</code><button class="copy-btn" onclick="copyCode(this)">Copy</button></div>
492+ <div class="code-block"><code>/reload-plugins</code><button class="copy-btn" type="button" onclick="copyCode(this)">Copy</button></div>
471493 </div>
472494
473495 <h3 style="font-size: 1rem; font-weight: 600; margin: 1.5rem 0 0.75rem;">Codex</h3>
474496
475497 <div class="install-step">
476498 <p>Tell Codex to fetch and follow the install instructions:</p>
477- <div class="code-block"><code>Fetch and follow instructions from https://raw.githubusercontent.com/mathpluscode/bibtools/main/.codex/INSTALL.md</code><button class="copy-btn" onclick="copyCode(this)">Copy</button></div>
499+ <div class="code-block"><code>Fetch and follow instructions from https://raw.githubusercontent.com/mathpluscode/bibtools/main/.codex/INSTALL.md</code><button class="copy-btn" type="button" onclick="copyCode(this)">Copy</button></div>
478500 </div>
479501
480502</div>
@@ -488,23 +510,17 @@ def build_html(cards_html: str) -> str:
488510
489511</div>
490512
491- </div>
492-
493513<script>
494514function copyCode(btn) {{
495515 const code = btn.previousElementSibling.textContent;
496516 navigator.clipboard.writeText(code).then(() => {{
497517 btn.textContent = 'Copied!';
498518 setTimeout(() => btn.textContent = 'Copy', 1500);
519+ }}).catch(() => {{
520+ btn.textContent = 'Copy failed';
521+ setTimeout(() => btn.textContent = 'Copy', 1500);
499522 }});
500523}}
501-
502- function switchTab(name) {{
503- document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
504- document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
505- document.querySelector(`[onclick="switchTab('${{name}}')"]`).classList.add('active');
506- document.getElementById(`tab-${{name}}`).classList.add('active');
507- }}
508524</script>
509525
510526</body>
0 commit comments