reviw 0.14.5 → 0.15.0

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.
Files changed (2) hide show
  1. package/cli.cjs +33 -6
  2. package/package.json +1 -1
package/cli.cjs CHANGED
@@ -29,21 +29,25 @@ const allowedTags = new Set([
29
29
  'ul', 'ol', 'li',
30
30
  'blockquote', 'pre', 'code',
31
31
  'em', 'strong', 'del', 's',
32
- 'a', 'img',
32
+ 'a', 'img', 'video',
33
33
  'table', 'thead', 'tbody', 'tr', 'th', 'td',
34
34
  'div', 'span', // Markdown拡張用
35
+ 'details', 'summary', // 折りたたみ用
35
36
  ]);
36
37
 
37
38
  // 許可属性リスト(タグごとに定義)
38
39
  const allowedAttributes = {
39
40
  'a': ['href', 'title', 'target', 'rel'],
40
41
  'img': ['src', 'alt', 'title', 'width', 'height'],
42
+ 'video': ['src', 'controls', 'width', 'height', 'poster', 'preload', 'muted', 'loop'],
41
43
  'code': ['class'], // 言語ハイライト用
42
44
  'pre': ['class'],
43
45
  'div': ['class'],
44
46
  'span': ['class'],
45
47
  'th': ['align'],
46
48
  'td': ['align'],
49
+ 'details': ['open'],
50
+ 'summary': [],
47
51
  };
48
52
 
49
53
  // HTMLエスケープ関数(XSS対策用)
@@ -149,12 +153,13 @@ marked.use({
149
153
  }
150
154
  var titleAttr = title ? ' title="' + escapeHtmlForXss(title) + '"' : "";
151
155
  var altAttr = text ? ' alt="' + escapeHtmlForXss(text) + '"' : "";
152
- // Check if this is a video file - wrap in <a> tag for video player functionality
156
+ // Check if this is a video file - render as video element with thumbnail
153
157
  var videoExtensions = /\.(mp4|mov|webm|avi|mkv|m4v|ogv)$/i;
154
158
  if (videoExtensions.test(href)) {
155
- // For videos, return a clickable link with video icon
159
+ // For videos, render as video element with controls and thumbnail preview
156
160
  var displayText = text || href.split('/').pop();
157
- return '<a href="' + escapeHtmlForXss(href) + '"' + titleAttr + ' class="video-link">📹' + escapeHtmlForXss(displayText) + '</a>';
161
+ return '<video src="' + escapeHtmlForXss(href) + '" controls preload="metadata" class="video-preview"' + titleAttr + '>' +
162
+ '<a href="' + escapeHtmlForXss(href) + '">📹' + escapeHtmlForXss(displayText) + '</a></video>';
158
163
  }
159
164
  return '<img src="' + escapeHtmlForXss(href) + '"' + altAttr + titleAttr + '>';
160
165
  }
@@ -719,8 +724,28 @@ function loadMarkdown(filePath) {
719
724
  }
720
725
 
721
726
  // Parse markdown content (without frontmatter)
722
- const contentText = lines.slice(contentStart).join("\n");
723
- const preview = frontmatterHtml + marked.parse(contentText, { breaks: true });
727
+ let contentText = lines.slice(contentStart).join("\n");
728
+
729
+ // Preprocess <details> blocks to preserve their content
730
+ // marked splits HTML blocks on blank lines, so we need to handle details specially
731
+ const detailsBlocks = [];
732
+ contentText = contentText.replace(/<details>([\s\S]*?)<\/details>/gi, function(match, inner) {
733
+ const placeholder = `<!--DETAILS_PLACEHOLDER_${detailsBlocks.length}-->`;
734
+ // Parse the inner content as markdown, preserving the details structure
735
+ const summaryMatch = inner.match(/<summary>([\s\S]*?)<\/summary>/i);
736
+ const summary = summaryMatch ? summaryMatch[1] : '';
737
+ const content = summaryMatch ? inner.replace(/<summary>[\s\S]*?<\/summary>/i, '').trim() : inner.trim();
738
+ const parsedContent = marked.parse(content, { breaks: true });
739
+ detailsBlocks.push(`<details><summary>${summary}</summary>${parsedContent}</details>`);
740
+ return placeholder;
741
+ });
742
+
743
+ let preview = frontmatterHtml + marked.parse(contentText, { breaks: true });
744
+
745
+ // Restore details blocks
746
+ detailsBlocks.forEach((block, i) => {
747
+ preview = preview.replace(`<!--DETAILS_PLACEHOLDER_${i}-->`, block);
748
+ });
724
749
 
725
750
  return {
726
751
  rows: lines.map((line) => [line]),
@@ -2224,6 +2249,8 @@ function htmlTemplate(dataRows, cols, projectRoot, relativePath, mode, previewHt
2224
2249
  }
2225
2250
  .md-preview p { margin: 0.3em 0; line-height: 1.5; }
2226
2251
  .md-preview img { max-width: 100%; height: auto; border-radius: 8px; }
2252
+ .md-preview video.video-preview { max-width: 100%; height: auto; border-radius: 8px; background: #000; }
2253
+ .md-preview table video.video-preview { max-width: 300px; }
2227
2254
  .md-preview code { background: rgba(255,255,255,0.08); padding: 2px 4px; border-radius: 4px; }
2228
2255
  .md-preview pre {
2229
2256
  background: var(--code-bg);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reviw",
3
- "version": "0.14.5",
3
+ "version": "0.15.0",
4
4
  "description": "Lightweight file reviewer with in-browser comments for CSV, TSV, Markdown, and Git diffs.",
5
5
  "type": "module",
6
6
  "bin": {