markdownr 0.3.3 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3218025cb46f3cb61158188eeea5957b3d797abb2c63970a9fa2c873b39da870
4
- data.tar.gz: 36df70282be17b496d6e6706e568fc5c585adba12bba091cf534176ea56182a2
3
+ metadata.gz: a6f6186e83f09bb4239d8ca1fd5cca349fbbe17ccea6565a5579c11920e7ce2e
4
+ data.tar.gz: 1eb3bc2813a2748ad37b63271e3e6844b4f927dc638f0c0bd1d0a7d65f940e28
5
5
  SHA512:
6
- metadata.gz: 90edee3edf4003ebcf4605e0488db495e8d460964595944aa478e8be5a72d6b9c7dc0e276b855f0148c4113a2cf9360dc8ab6ea01f823b1061b3718bab76a67c
7
- data.tar.gz: ad890bdaa976d1eb179fd9945656b27238103a93974cbf232950567ce08eaa87da2100e910bd33d9cbda0db8e67252275937fe8ff780f4abd0e34f2569e9cb15
6
+ metadata.gz: c249628b120b2af78fe64e9690362aa2978896cf098fc9aec04f7225f685661203f3d5dd59bde5b8ddf3bb6c959ac92a4c09f5b46483f121a9355bdf7675e68c
7
+ data.tar.gz: 80774310a8da3df52c41ef1e7ea811040a85392d5b6d02e149e1b3be0d12bc63d1f4bab5b7972f0a173da2a118f44aaf932df4c6e11487a62ffc7fe5fd47b548
@@ -192,7 +192,27 @@ module MarkdownServer
192
192
  def render_frontmatter_value(value)
193
193
  case value
194
194
  when Array
195
- value.map { |v| %(<span class="tag">#{h(v)}</span>) }.join(" ")
195
+ value.map { |v|
196
+ str = v.to_s
197
+ if str =~ /\A\[\[([^\]]+)\]\]\z/
198
+ raw = $1
199
+ target, display = raw.include?("|") ? raw.split("|", 2) : [raw, nil]
200
+ label = display || target
201
+ if target.start_with?("#")
202
+ anchor = target[1..].downcase.gsub(/\s+/, "-").gsub(/[^\w-]/, "")
203
+ %(<a class="wiki-link" href="##{h(anchor)}">#{h(label)}</a>)
204
+ else
205
+ resolved = resolve_wiki_link(target)
206
+ if resolved
207
+ %(<a class="wiki-link" href="/browse/#{encode_path_component(resolved).gsub('%2F', '/')}">#{h(label)}</a>)
208
+ else
209
+ %(<span class="wiki-link broken">#{h(label)}</span>)
210
+ end
211
+ end
212
+ else
213
+ %(<span class="tag">#{h(str)}</span>)
214
+ end
215
+ }.join(" ")
196
216
  when String
197
217
  if value =~ /\Ahttps?:\/\//
198
218
  %(<a href="#{h(value)}" target="_blank" rel="noopener">#{h(value)}</a>)
@@ -219,7 +239,7 @@ module MarkdownServer
219
239
  def extract_toc(html)
220
240
  headings = []
221
241
  html.scan(/<h([1-6])\s[^>]*id="([^"]*)"[^>]*>(.*?)<\/h\1>/mi) do |level, id, text|
222
- clean_text = text.gsub(/<[^>]+>/, "").strip
242
+ clean_text = text.gsub(/<sup[^>]*id="fnref:[^"]*"[^>]*>.*?<\/sup>/i, "").gsub(/<[^>]+>/, "").strip
223
243
  headings << { level: level.to_i, id: id, text: clean_text }
224
244
  end
225
245
  headings
@@ -1,3 +1,3 @@
1
1
  module MarkdownServer
2
- VERSION = "0.3.3"
2
+ VERSION = "0.3.5"
3
3
  end
data/views/layout.erb CHANGED
@@ -113,14 +113,13 @@
113
113
  }
114
114
 
115
115
  /* Frontmatter */
116
- details.frontmatter {
116
+ div.frontmatter {
117
117
  margin-bottom: 1.5rem;
118
118
  border: 1px solid #e0d8c8;
119
119
  border-radius: 6px;
120
120
  background: #fdfcf9;
121
121
  }
122
- details.frontmatter summary {
123
- cursor: pointer;
122
+ .frontmatter-heading {
124
123
  padding: 0.6rem 1rem;
125
124
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
126
125
  font-size: 0.85rem;
@@ -128,9 +127,6 @@
128
127
  color: #8b6914;
129
128
  background: #f5f0e4;
130
129
  border-radius: 6px 6px 0 0;
131
- user-select: none;
132
- }
133
- details.frontmatter[open] summary {
134
130
  border-bottom: 1px solid #e0d8c8;
135
131
  }
136
132
  .meta-table {
@@ -403,40 +399,6 @@
403
399
  min-width: 0;
404
400
  }
405
401
 
406
- /* Mobile TOC (replaces sidebar) */
407
- .toc-mobile {
408
- display: none;
409
- margin-bottom: 1rem;
410
- border: 1px solid #e0d8c8;
411
- border-radius: 6px;
412
- background: #fdfcf9;
413
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
414
- font-size: 0.82rem;
415
- }
416
- .toc-mobile summary {
417
- cursor: pointer;
418
- padding: 0.5rem 0.8rem;
419
- font-weight: 600;
420
- color: #8b6914;
421
- font-size: 0.8rem;
422
- user-select: none;
423
- }
424
- .toc-mobile ul {
425
- list-style: none;
426
- padding: 0 0.8rem 0.5rem;
427
- margin: 0;
428
- }
429
- .toc-mobile li { margin-bottom: 0.2rem; }
430
- .toc-mobile a {
431
- color: #666;
432
- text-decoration: none;
433
- padding: 0.2rem 0;
434
- display: block;
435
- }
436
- .toc-mobile a:hover { color: #8b6914; }
437
- .toc-mobile .toc-h3 { padding-left: 0.8rem; }
438
- .toc-mobile .toc-h4 { padding-left: 1.4rem; }
439
-
440
402
  /* TOC drawer (swipe-to-reveal on mobile) */
441
403
  .toc-overlay {
442
404
  display: none;
@@ -731,15 +693,15 @@
731
693
  max-width: 350px;
732
694
  width: max-content;
733
695
  z-index: 150;
734
- pointer-events: none;
735
696
  box-shadow: 0 2px 8px rgba(0,0,0,0.25);
736
697
  margin-bottom: 6px;
737
698
  }
699
+ .footnote-tooltip { cursor: pointer; }
738
700
  .footnote-tooltip::after {
739
701
  content: '';
740
702
  position: absolute;
741
703
  top: 100%;
742
- left: 50%;
704
+ left: calc(50% + var(--arrow-offset, 0px));
743
705
  transform: translateX(-50%);
744
706
  border: 5px solid transparent;
745
707
  border-top-color: #2d2d2d;
@@ -768,7 +730,6 @@
768
730
 
769
731
  .page-with-toc { display: block; }
770
732
  .toc-sidebar { display: none; }
771
- .toc-mobile { display: block; }
772
733
 
773
734
  .meta-table th, .meta-table td {
774
735
  display: block;
@@ -1093,12 +1054,75 @@
1093
1054
  var tooltip = document.createElement('span');
1094
1055
  tooltip.className = 'footnote-tooltip';
1095
1056
  tooltip.innerHTML = html;
1057
+ var fnHref = link.getAttribute('href');
1096
1058
 
1097
- sup.addEventListener('mouseenter', function() {
1059
+ function showTooltip() {
1098
1060
  sup.appendChild(tooltip);
1099
- });
1100
- sup.addEventListener('mouseleave', function() {
1061
+ // Reset any previous adjustment
1062
+ tooltip.style.left = '50%';
1063
+ tooltip.style.transform = 'translateX(-50%)';
1064
+ tooltip.style.removeProperty('--arrow-offset');
1065
+ // Clamp tooltip to viewport.
1066
+ // document.documentElement.clientWidth is more reliable than window.innerWidth
1067
+ // on Android browsers (e.g. EinkBro) which may return a pre-scaled layout
1068
+ // viewport width for window.innerWidth rather than the CSS viewport width.
1069
+ var viewportWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);
1070
+ var rect = tooltip.getBoundingClientRect();
1071
+ var shift = 0;
1072
+ if (rect.left < 8) {
1073
+ shift = 8 - rect.left;
1074
+ } else if (rect.right > viewportWidth - 8) {
1075
+ shift = (viewportWidth - 8) - rect.right;
1076
+ }
1077
+ if (shift !== 0) {
1078
+ tooltip.style.transform = 'translateX(calc(-50% + ' + shift + 'px))';
1079
+ tooltip.style.setProperty('--arrow-offset', (-shift) + 'px');
1080
+ }
1081
+ }
1082
+
1083
+ function hideTooltip() {
1101
1084
  if (tooltip.parentNode === sup) sup.removeChild(tooltip);
1085
+ }
1086
+
1087
+ // Hover devices: show/hide on mouseenter/mouseleave
1088
+ sup.addEventListener('mouseenter', showTooltip);
1089
+ sup.addEventListener('mouseleave', hideTooltip);
1090
+
1091
+ // Touch: first tap shows tooltip, second tap navigates
1092
+ // Using touchend instead of click so no hover media query check is needed —
1093
+ // touchend only fires on real touch, regardless of what (hover:none) reports.
1094
+ var linkTouchMoved = false;
1095
+ link.addEventListener('touchstart', function() { linkTouchMoved = false; }, { passive: true });
1096
+ link.addEventListener('touchmove', function() { linkTouchMoved = true; }, { passive: true });
1097
+ link.addEventListener('touchend', function(e) {
1098
+ if (linkTouchMoved) return; // scroll, not a tap
1099
+ if (tooltip.parentNode === sup) {
1100
+ // Tooltip already showing — let the link navigate
1101
+ return;
1102
+ }
1103
+ e.preventDefault();
1104
+ // Dismiss any other open tooltip
1105
+ document.querySelectorAll('.footnote-tooltip').forEach(function(t) {
1106
+ if (t.parentNode) t.parentNode.removeChild(t);
1107
+ });
1108
+ showTooltip();
1109
+ });
1110
+
1111
+ var tooltipTouchMoved = false;
1112
+ tooltip.addEventListener('touchstart', function() { tooltipTouchMoved = false; }, { passive: true });
1113
+ tooltip.addEventListener('touchmove', function() { tooltipTouchMoved = true; }, { passive: true });
1114
+ tooltip.addEventListener('touchend', function(e) {
1115
+ if (tooltipTouchMoved) return;
1116
+ e.stopPropagation();
1117
+ hideTooltip();
1118
+ window.location.hash = fnHref;
1119
+ });
1120
+
1121
+ // Dismiss tooltip when tapping elsewhere
1122
+ document.addEventListener('click', function(e) {
1123
+ if (tooltip.parentNode === sup && !sup.contains(e.target)) {
1124
+ hideTooltip();
1125
+ }
1102
1126
  });
1103
1127
  });
1104
1128
  })();
data/views/markdown.erb CHANGED
@@ -11,17 +11,6 @@
11
11
  </div>
12
12
 
13
13
  <% if @has_toc %>
14
- <details class="toc-mobile">
15
- <summary>Table of Contents</summary>
16
- <ul>
17
- <% @toc.each do |entry| %>
18
- <li class="toc-h<%= entry[:level] %>">
19
- <a href="#<%= h(entry[:id]) %>"><%= h(entry[:text]) %></a>
20
- </li>
21
- <% end %>
22
- </ul>
23
- </details>
24
-
25
14
  <button class="toc-fab" id="toc-fab" aria-label="Table of Contents">&#9776;</button>
26
15
  <div class="toc-overlay" id="toc-overlay"></div>
27
16
  <nav class="toc-drawer" id="toc-drawer">
@@ -55,8 +44,8 @@
55
44
 
56
45
  <div class="page-main">
57
46
  <% if @meta && !@meta.empty? %>
58
- <details class="frontmatter" open>
59
- <summary>Metadata</summary>
47
+ <div class="frontmatter">
48
+ <div class="frontmatter-heading">Frontmatter</div>
60
49
  <table class="meta-table">
61
50
  <% @meta.each do |key, value| %>
62
51
  <tr>
@@ -65,7 +54,7 @@
65
54
  </tr>
66
55
  <% end %>
67
56
  </table>
68
- </details>
57
+ </div>
69
58
  <% end %>
70
59
 
71
60
  <div class="md-content" data-file="<%= h(@title) %>">
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markdownr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Dunn