marksites 0.2.3 → 0.2.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.
- package/README.md +3 -1
- package/dist/cli.js +0 -0
- package/dist/features/annotations/index.js +24 -6
- package/dist/features/file-tree/index.js +20 -5
- package/dist/features/header/index.js +2 -2
- package/dist/template/styles.d.ts +1 -1
- package/dist/template/styles.js +16 -10
- package/dist/utils/icons.d.ts +1 -0
- package/dist/utils/icons.js +3 -0
- package/package.json +1 -1
- package/dist/features/annotations.d.ts +0 -9
- package/dist/features/annotations.js +0 -78
- package/dist/features/code-blocks.d.ts +0 -5
- package/dist/features/code-blocks.js +0 -89
- package/dist/features/file-tree.d.ts +0 -7
- package/dist/features/file-tree.js +0 -325
- package/dist/features/header.d.ts +0 -6
- package/dist/features/header.js +0 -47
- package/dist/features/sidebar.d.ts +0 -13
- package/dist/features/sidebar.js +0 -55
- package/dist/features/table-of-contents.d.ts +0 -16
- package/dist/features/table-of-contents.js +0 -91
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ const html = markdownToHtml(markdown, {
|
|
|
25
25
|
});
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
見出しレベル2から6までの目次と、GitHub互換の見出しアンカーが自動生成されます。ファイルツリーはGitHubのFiles
|
|
28
|
+
見出しレベル2から6までの目次と、GitHub互換の見出しアンカーが自動生成されます。ファイルツリーはGitHubのFilesペインと同様、画面左端へ接する全高のサイドバーとして常時表示し、本文を中央、`目次`とコメントを画面右側へ配置します。ファイル一覧は階層ツリーと更新順を切り替えられます。更新順ではMarkdownのローカルファイル更新日時(mtime)を新しい順に日付でまとめ、連続した縦線からインデントした位置に通常ウェイトのファイル名を表示します。親ディレクトリと更新日時は通常時には隠し、ファイルへホバーすると変換ルートを`/`、配下を`/src/`とする明色の吹き出しでファイル名の右側へ直ちに表示します。日付見出しではファイル件数を確認でき、クリックで折り畳めます。初期状態では最新日と現在ファイルを含む日を開き、検索中は一致する日を一時的に展開します。左サイドバーはヘッダーの四角いペインアイコンで折り畳むことができ、閉じると本文が左へ広がります。閉じた場合はページ上部に同形の復帰アイコンと、従来どおりポップオーバーでファイル一覧を開く`ファイル`ボタンを並べます。サイドバーの閉状態は`file-sidebar=closed`、ポップオーバーは`marksites-files=open`、更新順表示は`file-view=recent`、開いたフォルダは短縮IDを値とする`open` GETパラメータでページ間に引き継がれます。ファイルパス直後のアイコンでパスをコピーできます。Markdownの更新日時は本文カード上部で、ブラウザのローカルタイムゾーンを使った`YYYY-MM-DD HH:mm:ss`形式にして表示します。タイムゾーン名やUTCオフセットは表示しません。JavaScript実行前はUTCの日時を同じ形式で表示します。現在位置に対応する見出しもハイライトされます。狭い画面では右サイドバーを本文上部、ファイルサイドバーを必要なときだけ開く固定オーバーレイとして表示します。
|
|
29
29
|
|
|
30
30
|
左ファイルサイドバーは幅280pxとし、開閉アイコンは枠線なしで表示します。更新日時はヘッダーのファイルパス右隣へ細い縦線で区切って表示し、狭い画面では省略します。
|
|
31
31
|
|
|
@@ -99,6 +99,8 @@ npx marksites docs
|
|
|
99
99
|
|
|
100
100
|
軽量ローカルサーバーの起動中だけ、本文の選択範囲へコメントを追加・編集・削除できます。
|
|
101
101
|
|
|
102
|
+
本文で文字列を選択すると、コピー操作の隣に`文字列置換`が表示されます。選択文字列を変換元として画面中央の管理ポップアップへ置換後の文字列を入力すると、表示中の本文にある同じ文字列をすべてブラウザ上で一時的に置換でき、アクセストークンなどを当てはめてからコピーできます。本文カード右上の`置換`ボタンから選択なしで新しいルールを追加することもでき、複数ルールを一覧で管理して個別にクリアできます。ポップアップは閉じるアイコンまたは範囲外のクリックで閉じます。置換箇所は枠付きでハイライトされます。置換値自体は管理ボタンへ表示しません。元のMarkdownと生成HTMLは変更されず、ページを再読み込みしても元に戻ります。
|
|
103
|
+
|
|
102
104
|
右サイドバーでは目次と現在ページのコメント一覧をタブで切り替えられます。タブにはコメント件数が表示され、コメントを選ぶと本文の対象箇所へ移動します。一覧先頭の追加ボタンから、範囲を選択しない文書全体へのコメントも作成できます。ヘッダーは固定され、各パネルは独立してスクロールします。
|
|
103
105
|
|
|
104
106
|
```sh
|
package/dist/cli.js
CHANGED
|
File without changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { countActiveAnnotations, } from "../../annotations/model.js";
|
|
2
|
-
import { renderAddIcon, renderArchiveIcon, renderCopyIcon, renderDeleteIcon, renderEditIcon, renderRestoreIcon, } from "../../utils/icons.js";
|
|
2
|
+
import { renderAddIcon, renderArchiveIcon, renderCloseIcon, renderCopyIcon, renderDeleteIcon, renderEditIcon, renderRestoreIcon, } from "../../utils/icons.js";
|
|
3
3
|
function safeJson(value) {
|
|
4
4
|
return JSON.stringify(value)
|
|
5
5
|
.replace(/</g, "\\u003c")
|
|
@@ -12,9 +12,19 @@ export function createAnnotationsFeature(data) {
|
|
|
12
12
|
const markup = `<script id="marksites-annotations-data" type="application/json">${safeJson(data)}</script>
|
|
13
13
|
<div class="selection-actions" id="selection-actions" hidden role="toolbar" aria-label="選択範囲の操作">
|
|
14
14
|
<button type="button" data-selection-action="copy" data-tooltip="選択範囲をコピー">${renderCopyIcon()}<span data-copy-label>コピー</span></button>
|
|
15
|
+
<button type="button" data-selection-action="replace" data-tooltip="文書内の同じ文字列を置換">${renderEditIcon()}<span>文字列置換</span></button>
|
|
15
16
|
<button type="button" data-selection-action="ai" data-tooltip="AI向けの形式でコピー">${renderCopyIcon()}<span data-copy-label>AI向けコピー</span></button>
|
|
16
17
|
<button type="button" data-selection-action="comment" data-tooltip="選択範囲にコメントを追加" disabled title="コメントを追加するにはmarksites serveを起動してください">${renderAddIcon()}<span>コメント</span></button>
|
|
17
|
-
</div
|
|
18
|
+
</div>
|
|
19
|
+
<form class="text-replace-alert" id="text-replace-alert" hidden role="alert" aria-live="polite">
|
|
20
|
+
<div class="text-replace-alert-heading"><strong>文字列置換</strong><button type="button" data-cancel-replace aria-label="置換リストを閉じる">${renderCloseIcon()}</button></div>
|
|
21
|
+
<div class="text-replacement-list" data-replacement-list></div>
|
|
22
|
+
<label><span>置換する文字列</span><input type="text" name="search" autocomplete="off" required></label>
|
|
23
|
+
<label><span>置換後の文字列</span><input type="text" name="replacement" autocomplete="off"></label>
|
|
24
|
+
<p class="text-replace-error" data-replacement-error role="alert" hidden></p>
|
|
25
|
+
<div class="text-replace-alert-actions"><button type="submit">置換</button><button type="button" data-cancel-replace>キャンセル</button></div>
|
|
26
|
+
</form>
|
|
27
|
+
<button type="button" class="document-replacement-menu" data-replacement-menu aria-expanded="false" title="この文書の文字列置換を管理" aria-label="この文書の文字列置換を管理">${renderEditIcon()}<span>置換</span><span class="text-replacement-count" data-replacement-count hidden>0</span></button>`;
|
|
18
28
|
const panel = `<section class="annotations-panel sidebar-panel" id="sidebar-panel-comments" role="tabpanel" aria-labelledby="sidebar-tab-comments" hidden>
|
|
19
29
|
<div class="annotations-actions"><button type="button" class="annotation-action-add" data-add-document-comment data-tooltip="文書全体にコメントを追加" disabled title="コメントを追加するにはmarksites serveを起動してください">${renderAddIcon()}<span>追加</span></button><button type="button" class="annotation-action-copy" data-copy-all-comments data-tooltip="有効なコメントだけをコピー" aria-label="有効なコメントをコピー">${renderCopyIcon()}<span data-copy-comments-label>コピー</span></button></div>
|
|
20
30
|
<p class="annotations-status" id="annotations-status" role="status"></p>
|
|
@@ -24,10 +34,11 @@ export function createAnnotationsFeature(data) {
|
|
|
24
34
|
</section>`;
|
|
25
35
|
const styles = `
|
|
26
36
|
.selection-actions{position:fixed;z-index:20;display:flex;gap:4px;padding:6px;background:#24292f;border:1px solid #57606a;border-radius:6px;box-shadow:0 8px 24px #140f0f26}
|
|
27
|
-
.selection-actions[hidden],#annotation-form[hidden],.annotations-empty[hidden]{display:none}
|
|
37
|
+
.selection-actions[hidden],.text-replace-alert[hidden],.text-replacement-count[hidden],#annotation-form[hidden],.annotations-empty[hidden]{display:none}
|
|
28
38
|
.selection-actions button{display:inline-flex;align-items:center;justify-content:center;gap:5px;border:0;border-radius:4px;padding:5px 9px;color:#fff;background:transparent;font:12px/1 system-ui;cursor:pointer}
|
|
29
39
|
.selection-actions button:hover:not(:disabled){background:#57606a}.selection-actions button:disabled{color:#8c959f;cursor:not-allowed}
|
|
30
40
|
.selection-actions [data-tooltip],.annotations-panel [data-tooltip]{position:relative}.selection-actions [data-tooltip]::after,.annotations-panel [data-tooltip]::after{position:absolute;z-index:30;top:calc(100% + 6px);right:0;width:max-content;max-width:220px;padding:5px 7px;color:#fff;font-size:.6875rem;font-weight:400;line-height:1.3;white-space:normal;background:#24292f;border-radius:4px;box-shadow:0 3px 10px rgba(31,35,40,.2);content:attr(data-tooltip);opacity:0;pointer-events:none;transform:translateY(-2px);transition:opacity 120ms ease,transform 120ms ease}.selection-actions [data-tooltip]:hover::after,.selection-actions [data-tooltip]:focus-visible::after,.annotations-panel [data-tooltip]:hover::after,.annotations-panel [data-tooltip]:focus-visible::after{opacity:1;transform:translateY(0)}
|
|
41
|
+
.markdown-content{position:relative}.document-replacement-menu{position:absolute;top:12px;right:12px;display:inline-flex;height:32px;align-items:center;justify-content:center;gap:6px;padding:0 9px;color:var(--fgColor-muted,#59636e);font:inherit;font-size:.75rem;font-weight:600;background:var(--button-default-bgColor-rest,#f6f8fa);border:1px solid var(--borderColor-default,#d0d7de);border-radius:6px;cursor:pointer}.document-replacement-menu:hover{color:var(--fgColor-default,#1f2328);background:var(--button-default-bgColor-hover,#eaeef2)}.document-replacement-menu:focus-visible{outline:2px solid var(--focus-outlineColor,#0969da);outline-offset:2px}.document-replacement-menu svg{width:16px;height:16px;flex:none;fill:none;stroke:currentColor;stroke-width:1.25;stroke-linecap:round;stroke-linejoin:round}.document-replacement-menu>span:not(.text-replacement-count){line-height:16px}.text-replace-alert{position:fixed;z-index:45;top:50%;left:50%;box-sizing:border-box;display:grid;width:min(440px,calc(100vw - 24px));max-height:calc(100vh - 24px);grid-template-columns:1fr 1fr;gap:10px;padding:12px;overflow-y:auto;color:var(--fgColor-default,#1f2328);background:var(--bgColor-default,#fff);border:1px solid var(--borderColor-default,#d0d7de);border-radius:6px;box-shadow:0 8px 24px rgba(31,35,40,.2);transform:translate(-50%,-50%)}.text-replace-alert-heading,.text-replacement-list{grid-column:1/-1}.text-replace-alert-heading{display:flex;align-items:center;justify-content:space-between}.text-replace-alert label{display:block;min-width:0}.text-replace-alert label span{display:block;margin-bottom:5px;color:var(--fgColor-muted,#59636e);font-size:.75rem;font-weight:600}.text-replace-alert input{box-sizing:border-box;width:100%;height:34px;padding:5px 8px;color:var(--fgColor-default,#1f2328);font:inherit;background:var(--bgColor-default,#fff);border:1px solid var(--borderColor-default,#d0d7de);border-radius:6px}.text-replace-alert input:focus{border-color:var(--borderColor-accent-emphasis,#0969da);outline:2px solid var(--bgColor-accent-muted,#ddf4ff)}.text-replace-error{grid-column:1/-1;margin:0;color:var(--fgColor-danger,#d1242f);font-size:.75rem}.text-replace-error[hidden]{display:none}.text-replace-alert-actions{display:flex;grid-column:1/-1;justify-content:flex-end;gap:6px}.text-replace-alert button{height:34px;padding:0 10px;color:var(--fgColor-default,#1f2328);font:inherit;font-size:.8125rem;font-weight:600;background:var(--button-default-bgColor-rest,#f6f8fa);border:1px solid var(--borderColor-default,#d0d7de);border-radius:6px;cursor:pointer}.text-replace-alert button[type=submit]{color:#fff;background:var(--button-primary-bgColor-rest,#1f883d);border-color:transparent}.text-replace-alert .text-replace-alert-heading button{display:inline-flex;width:28px;height:28px;align-items:center;justify-content:center;padding:0;color:var(--fgColor-muted,#59636e);background:transparent;border:0;border-radius:4px}.text-replace-alert .text-replace-alert-heading button:hover{color:var(--fgColor-default,#1f2328);background:var(--button-default-bgColor-hover,#eaeef2)}.text-replace-alert .text-replace-alert-heading button:focus-visible{color:var(--fgColor-default,#1f2328);background:var(--button-default-bgColor-hover,#eaeef2);outline:2px solid var(--focus-outlineColor,#0969da);outline-offset:1px}.text-replace-alert-heading button svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round}.text-replacement-list:empty{display:none}.text-replacement-rule{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr) auto;align-items:center;gap:8px;padding:8px 0;border-bottom:1px solid var(--borderColor-muted,#d8dee4);font-size:.75rem}.text-replacement-rule code{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-replacement-rule button{height:28px;padding:0 8px}.text-replacement{padding:1px 2px;background:var(--bgColor-accent-muted,#ddf4ff);border:1px solid var(--borderColor-accent-emphasis,#0969da);border-radius:3px;box-decoration-break:clone;-webkit-box-decoration-break:clone}.text-replacement-count{display:inline-flex;min-width:16px;height:16px;align-items:center;justify-content:center;margin-left:3px;padding:0 3px;color:#fff;font-size:.6875rem;line-height:16px;background:var(--fgColor-accent,#0969da);border-radius:999px}
|
|
31
42
|
.annotations-panel{color:var(--fgColor-default,#1f2328)}
|
|
32
43
|
.annotations-actions{position:sticky;z-index:1;top:-12px;display:flex;gap:8px;margin:-12px -12px 0;padding:10px 12px;background:var(--bgColor-default,#fff);border-bottom:1px solid var(--borderColor-muted,#d8dee4)}.annotations-panel button{padding:6px 10px;color:var(--fgColor-default,#1f2328);font:inherit;font-size:.8125rem;font-weight:600;background:var(--button-default-bgColor-rest,#f6f8fa);border:1px solid var(--borderColor-default,#d0d7de);border-radius:6px;cursor:pointer}.annotations-panel button:hover:not(:disabled){background:var(--button-default-bgColor-hover,#eaeef2)}.annotations-panel button:focus-visible{outline:2px solid var(--focus-outlineColor,#0969da);outline-offset:2px}.annotations-panel button:disabled{color:var(--fgColor-muted,#818b98);cursor:not-allowed}.annotations-actions button{display:inline-flex;min-width:0;flex:1;align-items:center;justify-content:center;gap:5px}.annotations-panel .annotation-action-add:not(:disabled){color:#fff;background:var(--button-primary-bgColor-rest,#1f883d);border-color:var(--button-primary-borderColor-rest,#1f232826)}.annotations-panel .annotation-action-add:hover:not(:disabled){background:var(--button-primary-bgColor-hover,#1a7f37)}.annotations-panel .annotation-action-copy{color:var(--fgColor-muted,#59636e);background:transparent;border-color:var(--borderColor-muted,#d8dee4)}
|
|
33
44
|
.annotations-empty{margin:0;padding:28px 12px 20px;color:var(--fgColor-muted,#59636e);font-size:.8125rem;line-height:1.6;text-align:center}
|
|
@@ -40,8 +51,8 @@ export function createAnnotationsFeature(data) {
|
|
|
40
51
|
`;
|
|
41
52
|
const script = `<script>(()=>{
|
|
42
53
|
const dataElement=document.getElementById('marksites-annotations-data');if(!dataElement)return;
|
|
43
|
-
let state=JSON.parse(dataElement.textContent||'{}'),editable=false,pendingSelection=null,editingId=null;
|
|
44
|
-
const content=document.querySelector('.markdown-content'),toolbar=document.getElementById('selection-actions'),addDocumentComment=document.querySelector('[data-add-document-comment]'),copyAllComments=document.querySelector('[data-copy-all-comments]'),list=document.getElementById('annotations-list'),empty=document.getElementById('annotations-empty'),count=document.getElementById('annotation-count'),panelStatus=document.getElementById('annotations-status'),form=document.getElementById('annotation-form'),formHome=document.createComment('annotation-form-home');form.before(formHome);
|
|
54
|
+
let state=JSON.parse(dataElement.textContent||'{}'),editable=false,pendingSelection=null,editingId=null,replacementSequence=0,replacementRules=[];
|
|
55
|
+
const content=document.querySelector('.markdown-content'),toolbar=document.getElementById('selection-actions'),replaceAlert=document.getElementById('text-replace-alert'),replacementError=document.querySelector('[data-replacement-error]'),replacementMenu=document.querySelector('[data-replacement-menu]'),replacementList=document.querySelector('[data-replacement-list]'),addDocumentComment=document.querySelector('[data-add-document-comment]'),copyAllComments=document.querySelector('[data-copy-all-comments]'),list=document.getElementById('annotations-list'),empty=document.getElementById('annotations-empty'),count=document.getElementById('annotation-count'),panelStatus=document.getElementById('annotations-status'),form=document.getElementById('annotation-form'),formHome=document.createComment('annotation-form-home');form.before(formHome);content.prepend(replacementMenu);
|
|
45
56
|
const excluded='button,textarea,input,.selection-actions,.annotations-panel,.file-tree,.table-of-contents,.code-block-actions';
|
|
46
57
|
const groupParameter='comments',groupDefinitions=[['comments',''],['archived','アーカイブ']],validGroups=new Set(['archived']),openGroups=new Set((new URL(location.href).searchParams.get(groupParameter)||'').split(',').filter(key=>validGroups.has(key)));
|
|
47
58
|
function syncGroupState(){const updateUrl=url=>{url.searchParams.delete(groupParameter);if(openGroups.size)url.searchParams.set(groupParameter,groupDefinitions.map(([key])=>key).filter(key=>openGroups.has(key)).join(','));return url};history.replaceState(null,'',updateUrl(new URL(location.href)));for(const link of document.querySelectorAll('a[href]')){const raw=link.getAttribute('href');if(!raw||raw.startsWith('#'))continue;const url=new URL(raw,location.href);if(url.protocol===location.protocol&&url.host===location.host&&url.pathname.endsWith('.html'))link.href=updateUrl(url).href}}
|
|
@@ -54,8 +65,15 @@ function annotationMetadata(a,title='コメント'){const documentComment=a.sele
|
|
|
54
65
|
function allCommentsMetadata(){const annotations=sortedAnnotations().filter(a=>a.status==='open');return annotations.length?annotations.map((a,index)=>annotationMetadata(a,'コメント '+(index+1))).join('\\n\\n'):['# コメント','文書: '+state.document,'','有効なコメントはありません。'].join('\\n')}
|
|
55
66
|
function headingFor(node){if(!node)return null;const el=node.nodeType===1?node:node.parentElement,direct=el&&el.closest('h1,h2,h3,h4,h5,h6');if(direct)return direct.id;let previous=null;for(const heading of content.querySelectorAll('h1,h2,h3,h4,h5,h6')){if(heading.compareDocumentPosition(node)&Node.DOCUMENT_POSITION_FOLLOWING)previous=heading;else break}return previous?previous.id:null}
|
|
56
67
|
function selectionData(){const selection=getSelection();if(!selection||selection.rangeCount!==1||selection.isCollapsed)return null;const range=selection.getRangeAt(0);if(!content.contains(range.commonAncestorContainer)||(range.commonAncestorContainer.parentElement&&range.commonAncestorContainer.parentElement.closest(excluded)))return null;const exact=selection.toString().trim();if(!exact)return null;const all=content.innerText,index=all.indexOf(exact);return{exact,prefix:index<0?'':all.slice(Math.max(0,index-40),index),suffix:index<0?'':all.slice(index+exact.length,index+exact.length+40),headingId:headingFor(range.startContainer),startOffset:Math.max(0,index),endOffset:Math.max(0,index)+exact.length}}
|
|
68
|
+
function renderReplacementRules(){replacementList.textContent='';for(const rule of replacementRules){const row=document.createElement('div');row.className='text-replacement-rule';const search=document.createElement('code'),arrow=document.createElement('span'),replacement=document.createElement('code'),clear=document.createElement('button');search.textContent=rule.search;arrow.textContent='→';replacement.textContent=rule.replacement;clear.type='button';clear.textContent='クリア';clear.dataset.clearReplacement=String(rule.id);row.append(search,arrow,replacement,clear);replacementList.append(row)}const count=replacementRules.length,countElement=replacementMenu.querySelector('[data-replacement-count]');countElement.hidden=count===0;countElement.textContent=String(count)}
|
|
69
|
+
function setReplacementError(message=''){replacementError.textContent=message;replacementError.hidden=!message}
|
|
70
|
+
function openReplacementMenu(search=''){replaceAlert.hidden=false;replacementMenu.setAttribute('aria-expanded','true');replaceAlert.search.value=search;replaceAlert.replacement.value='';setReplacementError();replaceAlert.search.focus();if(search)replaceAlert.replacement.focus()}
|
|
71
|
+
function closeReplacementMenu(){replaceAlert.hidden=true;replacementMenu.setAttribute('aria-expanded','false')}
|
|
72
|
+
function replaceText(search,replacement){const id=++replacementSequence,walker=document.createTreeWalker(content,NodeFilter.SHOW_TEXT,{acceptNode:node=>node.parentElement?.closest(excluded+',.text-replacement')?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT}),nodes=[];let node,total=0;while(node=walker.nextNode())nodes.push(node);for(const text of nodes){const parts=text.data.split(search);if(parts.length===1)continue;const fragment=document.createDocumentFragment();parts.forEach((part,index)=>{fragment.append(document.createTextNode(part));if(index<parts.length-1){const mark=document.createElement('span');mark.className='text-replacement';mark.dataset.replacementId=String(id);mark.textContent=replacement;fragment.append(mark);total++}});text.replaceWith(fragment)}if(total)replacementRules.push({id,search,replacement,total});renderReplacementRules()}
|
|
57
73
|
document.addEventListener('selectionchange',()=>{clearTimeout(window.__marksitesSelectionTimer);window.__marksitesSelectionTimer=setTimeout(()=>{const next=selectionData();if(!next){toolbar.hidden=true;return}pendingSelection=next;const r=getSelection().getRangeAt(0).getBoundingClientRect();toolbar.style.left=Math.max(8,Math.min(innerWidth-toolbar.offsetWidth-8,r.left))+'px';toolbar.style.top=Math.max(8,r.top-44)+'px';toolbar.hidden=false},80)});
|
|
58
|
-
toolbar.addEventListener('mousedown',e=>e.preventDefault());toolbar.addEventListener('click',async e=>{const button=e.target.closest('button');if(!button||!pendingSelection)return;const label=button.querySelector('[data-copy-label]');try{if(button.dataset.selectionAction==='copy')await copy(pendingSelection.exact);if(button.dataset.selectionAction==='ai')await copy('文書: '+state.document+'\\n見出し: '+(pendingSelection.headingId||'なし')+'\\n\\n> '+pendingSelection.exact.replace(/\\n/g,'\\n> '));if(button.dataset.selectionAction==='comment'&&editable){editingId=null;dispatchEvent(new Event('marksites:show-comments'));openForm()}if(label){label.textContent='コピーしました';setTimeout(()=>label.textContent=button.dataset.selectionAction==='ai'?'AI向けコピー':'コピー',1000)}}catch{if(label)label.textContent='コピー失敗'}});
|
|
74
|
+
toolbar.addEventListener('mousedown',e=>e.preventDefault());toolbar.addEventListener('click',async e=>{const button=e.target.closest('button');if(!button||!pendingSelection)return;const label=button.querySelector('[data-copy-label]');try{if(button.dataset.selectionAction==='copy')await copy(pendingSelection.exact);if(button.dataset.selectionAction==='replace'){openReplacementMenu(pendingSelection.exact);toolbar.hidden=true}if(button.dataset.selectionAction==='ai')await copy('文書: '+state.document+'\\n見出し: '+(pendingSelection.headingId||'なし')+'\\n\\n> '+pendingSelection.exact.replace(/\\n/g,'\\n> '));if(button.dataset.selectionAction==='comment'&&editable){editingId=null;dispatchEvent(new Event('marksites:show-comments'));openForm()}if(label){label.textContent='コピーしました';setTimeout(()=>label.textContent=button.dataset.selectionAction==='ai'?'AI向けコピー':'コピー',1000)}}catch{if(label)label.textContent='コピー失敗'}});
|
|
75
|
+
replaceAlert.addEventListener('submit',e=>{e.preventDefault();const search=replaceAlert.search.value,replacement=replaceAlert.replacement.value;if(!search){setReplacementError('置換する文字列を入力してください。');replaceAlert.search.focus();return}if(!replacement){setReplacementError('置換後の文字列を入力してください。');replaceAlert.replacement.focus();return}const before=replacementRules.length;replaceText(search,replacement);if(replacementRules.length===before){setReplacementError('置換する文字列が本文内に見つかりません。');replaceAlert.search.focus();return}setReplacementError();replaceAlert.search.value='';replaceAlert.replacement.value='';replaceAlert.search.focus();getSelection()?.removeAllRanges()});replaceAlert.addEventListener('input',()=>setReplacementError());replaceAlert.querySelectorAll('[data-cancel-replace]').forEach(button=>button.addEventListener('click',closeReplacementMenu));replacementMenu.addEventListener('click',()=>{if(replaceAlert.hidden)openReplacementMenu();else closeReplacementMenu()});replacementList.addEventListener('click',e=>{const button=e.target.closest('[data-clear-replacement]');if(!button)return;const id=Number(button.dataset.clearReplacement),rule=replacementRules.find(item=>item.id===id);if(!rule)return;for(const mark of content.querySelectorAll('.text-replacement[data-replacement-id="'+id+'"]'))mark.replaceWith(document.createTextNode(rule.search));replacementRules=replacementRules.filter(item=>item.id!==id);renderReplacementRules()});
|
|
76
|
+
document.addEventListener('click',e=>{if(replaceAlert.hidden||replaceAlert.contains(e.target)||replacementMenu.contains(e.target)||e.target.closest('[data-selection-action=replace]'))return;closeReplacementMenu()});
|
|
59
77
|
addDocumentComment.addEventListener('click',()=>{if(!editable)return;editingId=null;pendingSelection={exact:'',prefix:'',suffix:'',headingId:null,startOffset:0,endOffset:0};openForm()});
|
|
60
78
|
copyAllComments.addEventListener('click',async()=>{const label=copyAllComments.querySelector('[data-copy-comments-label]');try{await copy(allCommentsMetadata());label.textContent='コピーしました';setTimeout(()=>label.textContent='コピー',1000)}catch{label.textContent='コピー失敗'}});
|
|
61
79
|
function locate(a){const preferred=a.selection.headingId?document.getElementById(a.selection.headingId):null,roots=preferred&&preferred!==content?[preferred,content]:[content];for(const root of roots){const walker=document.createTreeWalker(root,NodeFilter.SHOW_TEXT);let node,text='',nodes=[];while(node=walker.nextNode()){nodes.push([node,text.length]);text+=node.data}let index=text.indexOf(a.selection.exact);if(index<0)continue;const matches=[];while(index>=0){matches.push(index);index=text.indexOf(a.selection.exact,index+1)}if(matches.length>1){const contextual=matches.find(i=>text.slice(Math.max(0,i-a.selection.prefix.length),i)===a.selection.prefix&&text.slice(i+a.selection.exact.length,i+a.selection.exact.length+a.selection.suffix.length)===a.selection.suffix);index=contextual??matches.reduce((best,current)=>Math.abs(current-a.selection.startOffset)<Math.abs(best-a.selection.startOffset)?current:best)}else index=matches[0];let start,end,so=0,eo=0;for(const [n,offset] of nodes){if(!start&&offset+n.data.length>=index){start=n;so=index-offset}if(offset+n.data.length>=index+a.selection.exact.length){end=n;eo=index+a.selection.exact.length-offset;break}}if(!start||!end)continue;const range=document.createRange();range.setStart(start,so);range.setEnd(end,eo);return range}return null}
|
|
@@ -122,7 +122,7 @@ function renderRecentFiles(nodes) {
|
|
|
122
122
|
const groupId = grouped ? `recent-${groupNumber++}` : "";
|
|
123
123
|
const directoryLabel = directory ? `/${directory}` : "/";
|
|
124
124
|
if (grouped)
|
|
125
|
-
output.push(` <li class="file-tree-directory-group" data-recent-group="${groupId}"
|
|
125
|
+
output.push(` <li class="file-tree-directory-group" data-recent-group="${groupId}" aria-hidden="true">${renderFolderIcon()}<span>${escapeHtml(directoryLabel)}</span></li>`);
|
|
126
126
|
for (; index < end; index++) {
|
|
127
127
|
const file = files[index];
|
|
128
128
|
const current = file.current ? ' aria-current="page"' : "";
|
|
@@ -130,7 +130,8 @@ function renderRecentFiles(nodes) {
|
|
|
130
130
|
? `<span class="file-tree-comment-count" aria-label="コメント${file.commentCount}件">${file.commentCount}</span>`
|
|
131
131
|
: "";
|
|
132
132
|
const time = file.modifiedAt.slice(11, 16);
|
|
133
|
-
|
|
133
|
+
const tooltipDate = `${file.modifiedAt.slice(0, 10)} ${time}`;
|
|
134
|
+
output.push(` <li class="file-tree-recent-file${grouped ? " is-grouped" : ""}" data-file-path="${escapeHtml(file.path)}" data-directory="${escapeHtml(directory)}" data-modified-at="${file.modifiedAt}"${grouped ? ` data-recent-group="${groupId}"` : ""}><a href="${escapeHtml(file.href)}"${current}><span class="file-tree-recent-label"><span class="file-tree-name"><span class="file-tree-name-text">${escapeHtml(file.name)}</span></span></span>${count}<span class="file-tree-directory-tooltip" aria-hidden="true"><span class="file-tree-directory-tooltip-path">${renderFolderIcon()}<span>${escapeHtml(directoryLabel)}</span></span><time datetime="${file.modifiedAt}">${tooltipDate}</time></span></a></li>`);
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
137
|
return output.join("\n");
|
|
@@ -202,6 +203,20 @@ export function renderFileTreeScript(enabled) {
|
|
|
202
203
|
const ignoredToggles = new WeakSet();
|
|
203
204
|
const initialOpenState = new Map();
|
|
204
205
|
|
|
206
|
+
const positionDirectoryTooltip = (link) => {
|
|
207
|
+
const name = link.querySelector('.file-tree-name-text');
|
|
208
|
+
const tooltip = link.querySelector('.file-tree-directory-tooltip');
|
|
209
|
+
if (!name || !tooltip) return;
|
|
210
|
+
const nameRect = name.getBoundingClientRect();
|
|
211
|
+
tooltip.style.left = Math.min(nameRect.right + 8, innerWidth - tooltip.offsetWidth - 8) + 'px';
|
|
212
|
+
tooltip.style.top = Math.max(8 + tooltip.offsetHeight / 2, Math.min(nameRect.top + nameRect.height / 2, innerHeight - 8 - tooltip.offsetHeight / 2)) + 'px';
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
for (const link of document.querySelectorAll('.file-tree-recent-file > a')) {
|
|
216
|
+
link.addEventListener('pointerenter', () => positionDirectoryTooltip(link));
|
|
217
|
+
link.addEventListener('focus', () => positionDirectoryTooltip(link));
|
|
218
|
+
}
|
|
219
|
+
|
|
205
220
|
for (const directory of directories) {
|
|
206
221
|
const details = directory.querySelector(':scope > details');
|
|
207
222
|
details.open = openPaths.has(details.dataset.folderId);
|
|
@@ -339,8 +354,8 @@ export function renderFileTreeScript(enabled) {
|
|
|
339
354
|
group.className = 'file-tree-directory-group';
|
|
340
355
|
group.dataset.recentGroup = groupId;
|
|
341
356
|
group.dataset.localDate = dateKey;
|
|
357
|
+
group.setAttribute('aria-hidden', 'true');
|
|
342
358
|
const directoryLabel = first.dataset.directory ? '/'+first.dataset.directory : '/';
|
|
343
|
-
group.title = directoryLabel;
|
|
344
359
|
group.innerHTML = ${JSON.stringify(renderFolderIcon())};
|
|
345
360
|
const name = document.createElement('span');
|
|
346
361
|
name.textContent = directoryLabel;
|
|
@@ -351,8 +366,8 @@ export function renderFileTreeScript(enabled) {
|
|
|
351
366
|
const file = files[index];
|
|
352
367
|
const date = new Date(file.dataset.modifiedAt);
|
|
353
368
|
file.dataset.localDate = dateKey;
|
|
354
|
-
const
|
|
355
|
-
|
|
369
|
+
const tooltipTime = file.querySelector('.file-tree-directory-tooltip time');
|
|
370
|
+
tooltipTime.textContent = date.getFullYear()+'-'+pad(date.getMonth()+1)+'-'+pad(date.getDate())+' '+pad(date.getHours())+':'+pad(date.getMinutes());
|
|
356
371
|
if (grouped) {
|
|
357
372
|
file.classList.add('is-grouped');
|
|
358
373
|
file.dataset.recentGroup = groupId;
|
|
@@ -27,12 +27,12 @@ const languageParameter='lang',themeParameter='theme',pageUrl=new URL(location.h
|
|
|
27
27
|
const english=new Map(${JSON.stringify([
|
|
28
28
|
["目次", "Outline"], ["コメント", "Comments"], ["ファイル", "Files"], ["アーカイブ", "Archived"],
|
|
29
29
|
["追加", "Add"], ["コピー", "Copy"], ["コメントを追加", "Add comment"], ["コメントをすべてコピー", "Copy all comments"], ["コメントはありません。", "No comments."], ["このページにコメントはありません。", "No comments on this page."],
|
|
30
|
-
["コピー", "Copy"], ["AI向けコピー", "Copy for AI"], ["折り返す", "Wrap"], ["コピーしました", "Copied"], ["保存", "Save"], ["キャンセル", "Cancel"],
|
|
30
|
+
["コピー", "Copy"], ["文字列置換", "Replace text"], ["置換", "Replace"], ["置換する文字列", "Text to replace"], ["置換後の文字列", "Replacement text"], ["置換する文字列を入力してください。", "Enter text to replace."], ["置換後の文字列を入力してください。", "Enter replacement text."], ["置換する文字列が本文内に見つかりません。", "Text to replace was not found in the document."], ["この文書の文字列置換を管理", "Manage replacements in this document"], ["置換リストを閉じる", "Close replacement list"], ["クリア", "Clear"], ["AI向けコピー", "Copy for AI"], ["折り返す", "Wrap"], ["コピーしました", "Copied"], ["保存", "Save"], ["キャンセル", "Cancel"],
|
|
31
31
|
["引用", "Quote"], ["引用先なし", "Quote unavailable"], ["文書全体", "Whole document"],
|
|
32
32
|
["ファイルを検索", "Filter files"], ["一致するファイルはありません", "No matching files"], ["ファイル表示", "File view"], ["ツリー", "Tree"], ["更新順", "Recently updated"], ["更新日時のあるファイルはありません", "No files with update times"],
|
|
33
33
|
["ファイルサイドバーを開く", "Open file sidebar"], ["ファイルサイドバーを閉じる", "Close file sidebar"], ["ファイルを開く", "Open files"], ["ファイルを閉じる", "Close files"],
|
|
34
34
|
["ファイル名で検索", "Filter files by name"], ["ファイルパスをコピー", "Copy file path"], ["ファイルパスをコピーしました", "File path copied"], ["ファイルパスをコピーできませんでした", "Could not copy file path"],
|
|
35
|
-
["選択範囲の操作", "Selection actions"], ["選択範囲をコピー", "Copy selection"], ["AI向けの形式でコピー", "Copy for AI"], ["選択範囲にコメントを追加", "Add comment to selection"], ["文書全体にコメントを追加", "Add comment to document"],
|
|
35
|
+
["選択範囲の操作", "Selection actions"], ["選択範囲をコピー", "Copy selection"], ["文書内の同じ文字列を置換", "Replace matching text in document"], ["AI向けの形式でコピー", "Copy for AI"], ["選択範囲にコメントを追加", "Add comment to selection"], ["文書全体にコメントを追加", "Add comment to document"],
|
|
36
36
|
["コメントをコピー", "Copy comment"], ["コメントを編集", "Edit comment"], ["コメントをアーカイブ", "Archive comment"], ["コメントを復元", "Restore comment"], ["コメントを削除", "Delete comment"],
|
|
37
37
|
["アーカイブを開く", "Open archive"], ["アーカイブを閉じる", "Close archive"], ["コメントを保存", "Save comment"], ["編集をキャンセル", "Cancel editing"],
|
|
38
38
|
["有効なコメントをすべてコピー", "Copy all active comments"], ["有効なコメントだけをコピー", "Copy active comments only"], ["有効なコメントをコピー", "Copy active comments"], ["コメントをコピーしました", "Comment copied"], ["コピー失敗", "Copy failed"], ["コピーに失敗しました", "Copy failed"], ["保存中…", "Saving…"], ["保存に失敗しました", "Save failed"], ["このコメントを削除しますか?", "Delete this comment?"],
|
|
@@ -2,4 +2,4 @@ export declare const githubMarkdownCss: string;
|
|
|
2
2
|
export declare const highlightCss: string;
|
|
3
3
|
export declare const highlightThemeStyles = "body[data-theme=\"dark\"] .hljs{color:var(--codeBlock-fgColor);background:var(--codeBlock-bgColor)}\nbody[data-theme=\"dark\"] :is(.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_){color:var(--color-prettylights-syntax-keyword)}\nbody[data-theme=\"dark\"] :is(.hljs-title,.hljs-title.class_,.hljs-title.function_){color:var(--color-prettylights-syntax-entity)}\nbody[data-theme=\"dark\"] :is(.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id){color:var(--color-prettylights-syntax-constant)}\nbody[data-theme=\"dark\"] :is(.hljs-regexp,.hljs-string,.hljs-meta .hljs-string){color:var(--color-prettylights-syntax-string)}\nbody[data-theme=\"dark\"] :is(.hljs-built_in,.hljs-symbol){color:var(--color-prettylights-syntax-variable)}\nbody[data-theme=\"dark\"] :is(.hljs-comment,.hljs-code,.hljs-formula){color:var(--color-prettylights-syntax-comment)}\nbody[data-theme=\"dark\"] :is(.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo){color:var(--color-prettylights-syntax-entity-tag)}";
|
|
4
4
|
export declare const documentStyles = " body.markdown-body { box-sizing: border-box; min-width: 200px; width: calc(100% - 64px); max-width: none; margin: 0 32px; padding: 32px 0 0; display: grid; grid-template-columns: minmax(0, 1fr) 300px; grid-template-areas: \"content toc\"; column-gap: 32px; align-items: start; }\n .markdown-content, .document-sidebar { box-sizing: border-box; }\n .markdown-content { grid-area: content; min-width: 0; margin-bottom: 72px; padding: clamp(28px, 3vw, 52px); border: 1px solid var(--borderColor-muted, #d8dee4); border-radius: 8px; box-shadow: 0 1px 2px rgba(31, 35, 40, 0.04); }\n .markdown-content :is(h1, h2, h3, h4, h5, h6) { scroll-margin-top: 32px; }\n .code-block { margin-bottom: 16px; overflow: hidden; border: 1px solid var(--borderColor-muted, #d8dee4); border-radius: 8px; }\n .code-toolbar { display: flex; min-height: 38px; align-items: center; justify-content: space-between; padding: 0 8px 0 14px; color: var(--fgColor-muted, #59636e); background: var(--bgColor-muted, #f6f8fa); border-bottom: 1px solid var(--borderColor-muted, #d8dee4); }\n .code-language { font-size: 0.75rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }\n .code-tools { display: flex; gap: 2px; }\n .code-tool { display: inline-flex; min-height: 30px; align-items: center; justify-content: center; gap: 5px; padding: 4px 8px; color: inherit; font: inherit; font-size: 0.75rem; line-height: 1; background: transparent; border: 0; border-radius: 5px; cursor: pointer; }\n .code-tool-label, [data-copy-label] { display: inline-flex; align-items: center; line-height: 1; }\n .code-tool:hover { color: var(--fgColor-default, #1f2328); background: var(--button-default-bgColor-hover, #eaeef2); }\n .code-tool:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: -2px; }\n .code-tool[aria-pressed=\"true\"] { color: var(--fgColor-accent, #0969da); background: var(--bgColor-accent-muted, #ddf4ff); }\n .code-block pre { margin: 0; border-radius: 0; }\n .code-block pre, .code-block pre code { color: var(--codeBlock-fgColor, #24292f); background: var(--codeBlock-bgColor, #fff); }\n .code-block pre code { display: block; }\n .code-block.is-wrapped pre code { white-space: pre-wrap; overflow-wrap: anywhere; }\n .panel-toggle-icon { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; transition: transform 120ms ease; }\n .action-icon { display: block; width: 14px; height: 14px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; }\n .table-of-contents ul { margin: 0; padding: 0; list-style: none; }\n .table-of-contents li { margin: 2px 0 2px calc(var(--toc-level) * 12px); }\n .table-of-contents a { position: relative; display: block; padding: 6px 10px; color: var(--fgColor-muted, #59636e); font-size: 0.875rem; line-height: 1.4; overflow-wrap: anywhere; text-decoration: none; border-radius: 0 6px 6px 0; transition: color 120ms ease, background-color 120ms ease; }\n .table-of-contents a::before { position: absolute; top: 0; bottom: 0; left: 0; width: 2px; background: transparent; content: \"\"; }\n .table-of-contents a:hover { color: var(--fgColor-default, #1f2328); background: var(--bgColor-muted, #f6f8fa); text-decoration: none; }\n .table-of-contents a:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: -2px; }\n .table-of-contents a[aria-current=\"location\"] { color: var(--fgColor-accent, #0969da); font-weight: 600; background: linear-gradient(90deg, var(--bgColor-accent-muted, #ddf4ff), transparent); }\n .table-of-contents a[aria-current=\"location\"]::before { background: var(--borderColor-accent-emphasis, #0969da); }\n @media (max-width: 900px) {\n body.markdown-body { width: calc(100% - 24px); max-width: none; margin: 0 12px; padding: 12px 0 0; grid-template-columns: minmax(0, 1fr); grid-template-areas: \"toc\" \"content\"; gap: 16px; }\n .markdown-content { margin-bottom: 32px; }\n }\n @media (max-width: 600px) { .markdown-content { padding: 24px 20px; border-radius: 6px; } }\n @media (prefers-reduced-motion: reduce) { .table-of-contents a, .panel-toggle-icon { transition: none; } }";
|
|
5
|
-
export declare const fileTreeStyles = " body.markdown-body.has-file-tree { width: 100%; margin: 0; padding: 32px 32px 0 0; grid-template-columns: 280px minmax(0, 1fr) 300px; grid-template-areas: \"files content toc\"; column-gap: 32px; }\n body.markdown-body.has-file-tree.file-sidebar-collapsed { width: calc(100% - 64px); margin: 0 32px; padding: 32px 0 0; grid-template-columns: minmax(0, 1fr) 300px; grid-template-areas: \"content toc\"; }\n .file-sidebar { grid-area: files; position: fixed; z-index: 45; top: 0; bottom: 0; left: 0; box-sizing: border-box; display: flex; width: 280px; min-height: 0; flex-direction: column; color: var(--fgColor-default, #1f2328); background: var(--bgColor-default, #fff); border: 0; border-right: 1px solid var(--borderColor-muted, #d8dee4); border-radius: 0; overflow: hidden; }\n .file-sidebar-header { display: flex; min-height: 52px; flex: none; align-items: center; gap: 9px; padding: 0 12px; font-size: 0.875rem; font-weight: 700; border-bottom: 1px solid var(--borderColor-muted, #d8dee4); }\n .file-sidebar-header > span { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .file-sidebar[hidden], .file-sidebar-open[hidden], .file-sidebar-close[hidden] { display: none; }\n .file-sidebar-close { position: fixed; z-index: 50; top: 13px; left: 12px; display: inline-flex; width: 30px; height: 30px; flex: none; align-items: center; justify-content: center; padding: 0; color: var(--fgColor-muted, #59636e); background: transparent; border: 0; border-radius: 6px; cursor: pointer; }\n .file-sidebar-close:hover { color: var(--fgColor-default, #1f2328); background: var(--button-default-bgColor-hover, #eaeef2); }\n .file-sidebar-close:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: -2px; }\n .file-breadcrumbs { display: flex; align-items: center; gap: 8px; margin: 0; padding-bottom: 14px; border-bottom: 1px solid var(--borderColor-muted, #d8dee4); }\n .file-breadcrumbs ol { display: flex; min-width: 0; min-height: 28px; flex: 0 1 auto; flex-wrap: wrap; align-items: baseline; gap: 6px; margin: 0; padding: 0; list-style: none; }\n .file-breadcrumbs li { display: inline-block; min-width: 0; height: 28px; color: var(--fgColor-muted, #59636e); font-size: 0.875rem; line-height: 28px; }\n .file-breadcrumbs li + li::before { margin-right: 6px; color: var(--fgColor-muted, #818b98); content: \"/\"; }\n .file-breadcrumb-separator { height: 28px; margin-right: -2px; color: var(--fgColor-muted, #818b98); font-size: 0.875rem; line-height: 28px; }\n .file-breadcrumbs a { display: inline-block; height: 28px; color: var(--fgColor-accent, #0969da); font-weight: 500; line-height: 28px; text-decoration: none; vertical-align: baseline; }\n .file-breadcrumbs a:hover { text-decoration: underline; }\n .file-breadcrumbs [aria-current=\"page\"] { color: var(--fgColor-default, #1f2328); font-weight: 600; white-space: nowrap; }\n .file-sidebar-open { position: fixed; z-index: 50; top: 13px; left: 12px; display: inline-flex; width: 30px; height: 30px; flex: none; align-items: center; justify-content: center; padding: 0; color: var(--fgColor-muted, #59636e); background: transparent; border: 0; border-radius: 6px; cursor: pointer; }\n .file-tree-popover-toggle { position: relative; top: 1px; display: inline-flex; height: 28px; min-width: 0; flex: none; align-items: center; justify-content: center; gap: 3px; padding: 0; color: var(--fgColor-accent, #0969da); font: inherit; font-size: 0.875rem; font-weight: 600; line-height: 28px; background: transparent; border: 0; border-radius: 4px; cursor: pointer; }\n .file-tree-popover-toggle span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .file-sidebar-toggle-icon { display: block; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.2; stroke-linecap: round; stroke-linejoin: round; }\n .file-sidebar-open:hover { color: var(--fgColor-default, #1f2328); background: var(--button-default-bgColor-hover, #eaeef2); }\n .file-sidebar-open:focus-visible, .file-tree-popover-toggle:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: 2px; }\n .file-tree-popover-toggle:hover { color: var(--fgColor-accent, #0969da); text-decoration: underline; background: transparent; }\n .file-tree-popover-toggle:disabled { color: var(--fgColor-default, #1f2328); text-decoration: none; cursor: default; }\n .file-tree-popover-toggle:disabled .panel-toggle-icon { display: none; }\n .file-tree-popover-toggle .panel-toggle-icon { width: 13px; height: 13px; flex: none; transform: translateY(1px); }\n .copy-file-path .copy-icon { transform: none; }\n .file-tree-popover-toggle[aria-expanded=\"true\"] .panel-toggle-icon { transform: translateY(1px) rotate(180deg); }\n .copy-file-path { display: inline-flex; width: 28px; height: 28px; flex: none; align-items: center; justify-content: center; padding: 0; color: var(--fgColor-muted, #59636e); background: transparent; border: 0; border-radius: 5px; cursor: pointer; }\n .copy-file-path:hover { color: var(--fgColor-default, #1f2328); background: var(--button-default-bgColor-hover, #eaeef2); }\n .copy-file-path:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: 2px; }\n .file-tree { box-sizing: border-box; overflow: auto; padding: 12px; color: var(--fgColor-default, #1f2328); background: var(--bgColor-default, #fff); scrollbar-width: thin; scrollbar-color: var(--borderColor-default, #d0d7de) transparent; }\n .file-tree-sidebar { min-height: 0; flex: 1; padding: 10px 12px 16px; }\n .file-tree-popover { position: absolute; z-index: 15; top: calc(100% + 6px); left: 0; width: min(360px, calc(100vw - 48px)); max-height: min(520px, calc(100vh - 96px)); border: 1px solid var(--borderColor-default, #d0d7de); border-radius: 8px; box-shadow: 0 8px 24px rgba(31,35,40,.16); }\n .file-tree-view-tabs { display: grid; grid-template-columns: 1fr 1fr; margin: 0 0 8px; padding: 2px; background: var(--bgColor-muted, #f6f8fa); border-radius: 6px; }\n .file-tree-view-tabs button { min-height: 28px; padding: 3px 8px; color: var(--fgColor-muted, #59636e); font: inherit; font-size: 0.75rem; font-weight: 600; background: transparent; border: 0; border-radius: 4px; cursor: pointer; }\n .file-tree-view-tabs button[aria-selected=\"true\"] { color: var(--fgColor-default, #1f2328); background: var(--bgColor-default, #fff); box-shadow: 0 1px 2px rgba(31,35,40,.12); }\n .file-tree-view-tabs button:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: 1px; }\n .file-tree-filter { margin: 0 0 8px; }\n .file-tree-filter-input { box-sizing: border-box; width: 100%; min-height: 32px; padding: 5px 9px; color: var(--fgColor-default, #1f2328); font: inherit; font-size: 0.8125rem; line-height: 1.4; background: var(--bgColor-default, #fff); border: 1px solid var(--borderColor-default, #d0d7de); border-radius: 6px; outline: none; }\n .file-tree-filter-input::placeholder { color: var(--fgColor-muted, #59636e); }\n .file-tree-filter-input:focus { border-color: var(--borderColor-accent-emphasis, #0969da); box-shadow: 0 0 0 2px var(--bgColor-accent-muted, #ddf4ff); }\n .file-tree-filter-empty { margin: 10px 4px 2px; color: var(--fgColor-muted, #59636e); font-size: 0.8125rem; text-align: center; }\n .file-tree ul { margin: 0; padding: 0; list-style: none; }\n .file-tree [hidden] { display: none; }\n .file-tree details { margin: 0; }\n .file-tree details > ul { margin-left: 10px; padding-left: 10px; border-left: 1px solid var(--borderColor-muted, #d8dee4); }\n .file-tree summary { padding: 5px 7px; color: var(--fgColor-default, #1f2328); font-size: 0.875rem; font-weight: 600; line-height: 1.35; border-radius: 5px; cursor: pointer; user-select: none; }\n .folder-icon { display: inline-block; width: 14px; height: 14px; margin-right: 5px; vertical-align: -2px; fill: none; stroke: currentColor; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; }\n .file-tree summary:hover { background: var(--bgColor-muted, #f6f8fa); }\n .file-tree summary::marker { color: var(--fgColor-muted, #59636e); }\n .file-tree a { display: flex; margin: 1px 0; padding: 5px 8px; align-items: center; gap: 6px; overflow: hidden; color: var(--fgColor-muted, #59636e); font-size: 0.875rem; line-height: 1.35; text-decoration: none; white-space: nowrap; border-radius: 5px; }\n .file-tree-name { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; }\n .file-tree-comment-count { display: inline-flex; min-width: 18px; height: 18px; flex: none; align-items: center; justify-content: center; padding: 0 5px; color: var(--fgColor-muted, #59636e); font-size: 0.6875rem; font-weight: 600; line-height: 18px; background: var(--bgColor-neutral-muted, #818b981f); border-radius: 9px; }\n .file-tree-directory-comment-count { float: right; margin-left: 6px; }\n .file-tree details[open] > summary > .file-tree-directory-comment-count { display: none; }\n .file-tree a[aria-current=\"page\"] .file-tree-comment-count { color: var(--fgColor-accent, #0969da); background: var(--bgColor-default, #fff); }\n .file-tree a:hover { color: var(--fgColor-default, #1f2328); background: var(--bgColor-muted, #f6f8fa); text-decoration: none; }\n .file-tree a:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: -2px; }\n .file-tree a[aria-current=\"page\"] { color: var(--fgColor-accent, #0969da); font-weight: 600; background: var(--bgColor-accent-muted, #ddf4ff); }\n .file-tree-date { margin: 10px 0 3px; }\n .file-tree-date:first-child { margin-top: 4px; }\n .file-tree-date button { display: flex; width: 100%; min-height: 28px; align-items: center; gap: 4px; padding: 4px 7px; color: var(--fgColor-default, #1f2328); font: inherit; font-size: 0.75rem; font-weight: 600; text-align: left; background: transparent; border: 0; border-radius: 5px; cursor: pointer; }\n .file-tree-date button:hover { background: var(--bgColor-muted, #f6f8fa); }\n .file-tree-date button:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: -2px; }\n .file-tree-date button svg { width: 12px; height: 12px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; transition: transform 120ms ease; }\n .file-tree-date button[aria-expanded=\"false\"] svg { transform: rotate(-90deg); }\n .file-tree-date button span { min-width: 18px; margin-left: auto; padding: 1px 5px; color: var(--fgColor-muted, #59636e); font-size: 0.6875rem; font-weight: 600; line-height: 16px; text-align: center; background: var(--bgColor-neutral-muted, #818b981f); border-radius: 9px; }\n .file-tree-recent .is-date-collapsed { display: none; }\n .file-tree-directory-group { display: flex; min-width: 0; align-items: center; gap: 5px; margin: 7px 4px 2px; padding: 4px 6px; overflow: hidden; color: var(--fgColor-muted, #59636e); font-size: 0.6875rem; font-weight: 600; line-height: 1.25; background: var(--bgColor-muted, #f6f8fa); border-radius: 4px; }\n .file-tree-directory-group .folder-icon { width: 13px; height: 13px; flex: none; }\n .file-tree-directory-group span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .file-tree-recent-file a { align-items: flex-start; gap: 7px; }\n .file-tree-recent-label { display: flex; min-width: 0; flex: 1; flex-direction: column; gap: 1px; }\n .file-tree-recent-label .file-tree-name { width: 100%; color: var(--fgColor-default, #1f2328); font-size: 0.8125rem; font-weight: 600; }\n .file-tree-recent-file a:hover .file-tree-name { text-decoration: underline; text-underline-offset: 2px; }\n .file-tree-directory-path { display: flex; width: 100%; min-width: 0; align-items: center; gap: 4px; overflow: hidden; color: var(--fgColor-muted, #59636e); font-size: 0.6875rem; font-weight: 400; line-height: 1.25; white-space: nowrap; }\n .file-tree-directory-path .folder-icon { width: 11px; height: 11px; flex: none; margin: 0; }\n .file-tree-directory-path > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n .file-tree-recent-file.is-grouped .file-tree-directory-path { display: none; }\n .file-tree-recent-file .file-tree-comment-count { margin-top: 1px; }\n .file-tree-recent-file > a > time { width: 34px; flex: none; padding-top: 1px; color: var(--fgColor-muted, #59636e); font-size: 0.6875rem; font-variant-numeric: tabular-nums; line-height: 1.35; }\n .file-tree-recent-empty { margin: 10px 4px 2px; color: var(--fgColor-muted, #59636e); font-size: 0.8125rem; text-align: center; }\n @media (max-width: 900px) {\n body.markdown-body.has-file-tree, body.markdown-body.has-file-tree.file-sidebar-collapsed { width: calc(100% - 24px); margin: 0 12px; padding: 12px 0 0; grid-template-columns: minmax(0, 1fr); grid-template-areas: \"toc\" \"content\"; gap: 16px; }\n .file-sidebar { width: min(280px, calc(100vw - 24px)); box-shadow: 8px 0 24px rgba(31,35,40,.18); }\n }\n @media (max-width: 600px) { .file-tree-popover { width: calc(100vw - 40px); max-height: calc(100vh - 80px); } }\n ";
|
|
5
|
+
export declare const fileTreeStyles = " body.markdown-body.has-file-tree { width: 100%; margin: 0; padding: 32px 32px 0 0; grid-template-columns: 280px minmax(0, 1fr) 300px; grid-template-areas: \"files content toc\"; column-gap: 32px; }\n body.markdown-body.has-file-tree.file-sidebar-collapsed { width: calc(100% - 64px); margin: 0 32px; padding: 32px 0 0; grid-template-columns: minmax(0, 1fr) 300px; grid-template-areas: \"content toc\"; }\n .file-sidebar { grid-area: files; position: fixed; z-index: 45; top: 0; bottom: 0; left: 0; box-sizing: border-box; display: flex; width: 280px; min-height: 0; flex-direction: column; color: var(--fgColor-default, #1f2328); background: var(--bgColor-default, #fff); border: 0; border-right: 1px solid var(--borderColor-muted, #d8dee4); border-radius: 0; overflow: hidden; }\n .file-sidebar-header { display: flex; min-height: 52px; flex: none; align-items: center; gap: 9px; padding: 0 12px; font-size: 0.875rem; font-weight: 700; border-bottom: 1px solid var(--borderColor-muted, #d8dee4); }\n .file-sidebar-header > span { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .file-sidebar[hidden], .file-sidebar-open[hidden], .file-sidebar-close[hidden] { display: none; }\n .file-sidebar-close { position: fixed; z-index: 50; top: 13px; left: 12px; display: inline-flex; width: 30px; height: 30px; flex: none; align-items: center; justify-content: center; padding: 0; color: var(--fgColor-muted, #59636e); background: transparent; border: 0; border-radius: 6px; cursor: pointer; }\n .file-sidebar-close:hover { color: var(--fgColor-default, #1f2328); background: var(--button-default-bgColor-hover, #eaeef2); }\n .file-sidebar-close:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: -2px; }\n .file-breadcrumbs { display: flex; align-items: center; gap: 8px; margin: 0; padding-bottom: 14px; border-bottom: 1px solid var(--borderColor-muted, #d8dee4); }\n .file-breadcrumbs ol { display: flex; min-width: 0; min-height: 28px; flex: 0 1 auto; flex-wrap: wrap; align-items: baseline; gap: 6px; margin: 0; padding: 0; list-style: none; }\n .file-breadcrumbs li { display: inline-block; min-width: 0; height: 28px; color: var(--fgColor-muted, #59636e); font-size: 0.875rem; line-height: 28px; }\n .file-breadcrumbs li + li::before { margin-right: 6px; color: var(--fgColor-muted, #818b98); content: \"/\"; }\n .file-breadcrumb-separator { height: 28px; margin-right: -2px; color: var(--fgColor-muted, #818b98); font-size: 0.875rem; line-height: 28px; }\n .file-breadcrumbs a { display: inline-block; height: 28px; color: var(--fgColor-accent, #0969da); font-weight: 500; line-height: 28px; text-decoration: none; vertical-align: baseline; }\n .file-breadcrumbs a:hover { text-decoration: underline; }\n .file-breadcrumbs [aria-current=\"page\"] { color: var(--fgColor-default, #1f2328); font-weight: 600; white-space: nowrap; }\n .file-sidebar-open { position: fixed; z-index: 50; top: 13px; left: 12px; display: inline-flex; width: 30px; height: 30px; flex: none; align-items: center; justify-content: center; padding: 0; color: var(--fgColor-muted, #59636e); background: transparent; border: 0; border-radius: 6px; cursor: pointer; }\n .file-tree-popover-toggle { position: relative; top: 1px; display: inline-flex; height: 28px; min-width: 0; flex: none; align-items: center; justify-content: center; gap: 3px; padding: 0; color: var(--fgColor-accent, #0969da); font: inherit; font-size: 0.875rem; font-weight: 600; line-height: 28px; background: transparent; border: 0; border-radius: 4px; cursor: pointer; }\n .file-tree-popover-toggle span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .file-sidebar-toggle-icon { display: block; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.2; stroke-linecap: round; stroke-linejoin: round; }\n .file-sidebar-open:hover { color: var(--fgColor-default, #1f2328); background: var(--button-default-bgColor-hover, #eaeef2); }\n .file-sidebar-open:focus-visible, .file-tree-popover-toggle:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: 2px; }\n .file-tree-popover-toggle:hover { color: var(--fgColor-accent, #0969da); text-decoration: underline; background: transparent; }\n .file-tree-popover-toggle:disabled { color: var(--fgColor-default, #1f2328); text-decoration: none; cursor: default; }\n .file-tree-popover-toggle:disabled .panel-toggle-icon { display: none; }\n .file-tree-popover-toggle .panel-toggle-icon { width: 13px; height: 13px; flex: none; transform: translateY(1px); }\n .copy-file-path .copy-icon { transform: none; }\n .file-tree-popover-toggle[aria-expanded=\"true\"] .panel-toggle-icon { transform: translateY(1px) rotate(180deg); }\n .copy-file-path { display: inline-flex; width: 28px; height: 28px; flex: none; align-items: center; justify-content: center; padding: 0; color: var(--fgColor-muted, #59636e); background: transparent; border: 0; border-radius: 5px; cursor: pointer; }\n .copy-file-path:hover { color: var(--fgColor-default, #1f2328); background: var(--button-default-bgColor-hover, #eaeef2); }\n .copy-file-path:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: 2px; }\n .file-tree { box-sizing: border-box; overflow: auto; padding: 12px; color: var(--fgColor-default, #1f2328); background: var(--bgColor-default, #fff); scrollbar-width: thin; scrollbar-color: var(--borderColor-default, #d0d7de) transparent; }\n .file-tree-sidebar { min-height: 0; flex: 1; padding: 10px 12px 16px; }\n .file-tree-popover { position: absolute; z-index: 15; top: calc(100% + 6px); left: 0; width: min(360px, calc(100vw - 48px)); max-height: min(520px, calc(100vh - 96px)); border: 1px solid var(--borderColor-default, #d0d7de); border-radius: 8px; box-shadow: 0 8px 24px rgba(31,35,40,.16); }\n .file-tree-view-tabs { display: grid; grid-template-columns: 1fr 1fr; margin: 0 0 8px; padding: 2px; background: var(--bgColor-muted, #f6f8fa); border-radius: 6px; }\n .file-tree-view-tabs button { min-height: 28px; padding: 3px 8px; color: var(--fgColor-muted, #59636e); font: inherit; font-size: 0.75rem; font-weight: 600; background: transparent; border: 0; border-radius: 4px; cursor: pointer; }\n .file-tree-view-tabs button[aria-selected=\"true\"] { color: var(--fgColor-default, #1f2328); background: var(--bgColor-default, #fff); box-shadow: 0 1px 2px rgba(31,35,40,.12); }\n .file-tree-view-tabs button:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: 1px; }\n .file-tree-filter { margin: 0 0 8px; }\n .file-tree-filter-input { box-sizing: border-box; width: 100%; min-height: 32px; padding: 5px 9px; color: var(--fgColor-default, #1f2328); font: inherit; font-size: 0.8125rem; line-height: 1.4; background: var(--bgColor-default, #fff); border: 1px solid var(--borderColor-default, #d0d7de); border-radius: 6px; outline: none; }\n .file-tree-filter-input::placeholder { color: var(--fgColor-muted, #59636e); }\n .file-tree-filter-input:focus { border-color: var(--borderColor-accent-emphasis, #0969da); box-shadow: 0 0 0 2px var(--bgColor-accent-muted, #ddf4ff); }\n .file-tree-filter-empty { margin: 10px 4px 2px; color: var(--fgColor-muted, #59636e); font-size: 0.8125rem; text-align: center; }\n .file-tree ul { margin: 0; padding: 0; list-style: none; }\n .file-tree [hidden] { display: none; }\n .file-tree details { margin: 0; }\n .file-tree details > ul { margin-left: 10px; padding-left: 10px; border-left: 1px solid var(--borderColor-muted, #d8dee4); }\n .file-tree summary { padding: 5px 7px; color: var(--fgColor-default, #1f2328); font-size: 0.875rem; font-weight: 600; line-height: 1.35; border-radius: 5px; cursor: pointer; user-select: none; }\n .folder-icon { display: inline-block; width: 14px; height: 14px; margin-right: 5px; vertical-align: -2px; fill: none; stroke: currentColor; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; }\n .file-tree summary:hover { background: var(--bgColor-muted, #f6f8fa); }\n .file-tree summary::marker { color: var(--fgColor-muted, #59636e); }\n .file-tree a { display: flex; margin: 1px 0; padding: 5px 8px; align-items: center; gap: 6px; overflow: hidden; color: var(--fgColor-muted, #59636e); font-size: 0.875rem; line-height: 1.35; text-decoration: none; white-space: nowrap; border-radius: 5px; }\n .file-tree-name { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; }\n .file-tree-comment-count { display: inline-flex; min-width: 18px; height: 18px; flex: none; align-items: center; justify-content: center; padding: 0 5px; color: var(--fgColor-muted, #59636e); font-size: 0.6875rem; font-weight: 600; line-height: 18px; background: var(--bgColor-neutral-muted, #818b981f); border-radius: 9px; }\n .file-tree-directory-comment-count { float: right; margin-left: 6px; }\n .file-tree details[open] > summary > .file-tree-directory-comment-count { display: none; }\n .file-tree a[aria-current=\"page\"] .file-tree-comment-count { color: var(--fgColor-accent, #0969da); background: var(--bgColor-default, #fff); }\n .file-tree a:hover { color: var(--fgColor-default, #1f2328); background: var(--bgColor-muted, #f6f8fa); text-decoration: none; }\n .file-tree a:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: -2px; }\n .file-tree a[aria-current=\"page\"] { color: var(--fgColor-accent, #0969da); font-weight: 600; background: var(--bgColor-accent-muted, #ddf4ff); }\n .file-tree-recent { position: relative; }\n .file-tree-recent::before { position: absolute; top: 0; bottom: 0; left: 12px; width: 1px; content: \"\"; background: var(--borderColor-muted, #d8dee4); }\n .file-tree-date { position: relative; z-index: 1; margin: 10px 0 3px; background: var(--bgColor-default, #fff); }\n .file-tree-date::before { position: absolute; top: -10px; bottom: -3px; left: 12px; width: 1px; content: \"\"; background: var(--bgColor-default, #fff); }\n .file-tree-date:first-child { margin-top: 4px; }\n .file-tree-date button { display: flex; width: 100%; min-height: 28px; align-items: center; gap: 4px; padding: 4px 7px; color: var(--fgColor-default, #1f2328); font: inherit; font-size: 0.75rem; font-weight: 600; text-align: left; background: transparent; border: 0; border-radius: 5px; cursor: pointer; }\n .file-tree-date button:hover { background: var(--bgColor-muted, #f6f8fa); }\n .file-tree-date button:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: -2px; }\n .file-tree-date button svg { width: 12px; height: 12px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; transition: transform 120ms ease; }\n .file-tree-date button[aria-expanded=\"false\"] svg { transform: rotate(-90deg); }\n .file-tree-date button span { min-width: 18px; margin-left: auto; padding: 1px 5px; color: var(--fgColor-muted, #59636e); font-size: 0.6875rem; font-weight: 600; line-height: 16px; text-align: center; background: var(--bgColor-neutral-muted, #818b981f); border-radius: 9px; }\n .file-tree-recent .is-date-collapsed { display: none; }\n .file-tree-directory-group { display: none; }\n .file-tree-directory-group .folder-icon { width: 13px; height: 13px; flex: none; }\n .file-tree-directory-group span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .file-tree-recent-file { position: relative; margin-left: 22px; }\n .file-tree-recent-file a { position: relative; margin-top: 0; margin-bottom: 0; overflow: visible; align-items: flex-start; gap: 7px; }\n .file-tree-recent-label { display: flex; min-width: 0; flex: 1; }\n .file-tree-recent-label .file-tree-name { width: 100%; color: var(--fgColor-default, #1f2328); font-size: 0.8125rem; font-weight: 400; }\n .file-tree-recent-file a:hover .file-tree-name { text-decoration: underline; text-underline-offset: 2px; }\n .file-tree-directory-tooltip { position: fixed; z-index: 100; top: 0; left: 0; display: none; max-width: min(240px, calc(100vw - 16px)); flex-direction: column; align-items: flex-start; gap: 3px; padding: 6px 8px; color: var(--fgColor-default, #1f2328); font-size: 0.6875rem; font-weight: 400; line-height: 1.35; white-space: nowrap; background: var(--bgColor-default, #fff); border: 1px solid var(--borderColor-default, #d0d7de); border-radius: 5px; box-shadow: 0 2px 8px rgba(31,35,40,.16); transform: translateY(-50%); pointer-events: none; }\n .file-tree-directory-tooltip::before { position: absolute; top: 50%; right: calc(100% - 4px); width: 7px; height: 7px; content: \"\"; background: var(--bgColor-default, #fff); border: 0 solid var(--borderColor-default, #d0d7de); border-width: 0 0 1px 1px; transform: translateY(-50%) rotate(45deg); }\n .file-tree-directory-tooltip-path { display: flex; max-width: 220px; align-items: center; gap: 5px; overflow: hidden; }\n .file-tree-directory-tooltip-path .folder-icon { width: 12px; height: 12px; flex: none; margin: 0; }\n .file-tree-directory-tooltip-path > span { overflow: hidden; text-overflow: ellipsis; }\n .file-tree-directory-tooltip > time { color: var(--fgColor-muted, #59636e); font-variant-numeric: tabular-nums; }\n .file-tree-recent-file a:hover .file-tree-directory-tooltip, .file-tree-recent-file a:focus-visible .file-tree-directory-tooltip { display: flex; }\n .file-tree-recent-file .file-tree-comment-count { margin-top: 1px; }\n .file-tree-recent-empty { margin: 10px 4px 2px; color: var(--fgColor-muted, #59636e); font-size: 0.8125rem; text-align: center; }\n @media (max-width: 900px) {\n body.markdown-body.has-file-tree, body.markdown-body.has-file-tree.file-sidebar-collapsed { width: calc(100% - 24px); margin: 0 12px; padding: 12px 0 0; grid-template-columns: minmax(0, 1fr); grid-template-areas: \"toc\" \"content\"; gap: 16px; }\n .file-sidebar { width: min(280px, calc(100vw - 24px)); box-shadow: 8px 0 24px rgba(31,35,40,.18); }\n }\n @media (max-width: 600px) { .file-tree-popover { width: calc(100vw - 40px); max-height: calc(100vh - 80px); } }\n ";
|
package/dist/template/styles.js
CHANGED
|
@@ -105,7 +105,10 @@ export const fileTreeStyles = ` body.markdown-body.has-file-tree { width: 100
|
|
|
105
105
|
.file-tree a:hover { color: var(--fgColor-default, #1f2328); background: var(--bgColor-muted, #f6f8fa); text-decoration: none; }
|
|
106
106
|
.file-tree a:focus-visible { outline: 2px solid var(--focus-outlineColor, #0969da); outline-offset: -2px; }
|
|
107
107
|
.file-tree a[aria-current="page"] { color: var(--fgColor-accent, #0969da); font-weight: 600; background: var(--bgColor-accent-muted, #ddf4ff); }
|
|
108
|
-
.file-tree-
|
|
108
|
+
.file-tree-recent { position: relative; }
|
|
109
|
+
.file-tree-recent::before { position: absolute; top: 0; bottom: 0; left: 12px; width: 1px; content: ""; background: var(--borderColor-muted, #d8dee4); }
|
|
110
|
+
.file-tree-date { position: relative; z-index: 1; margin: 10px 0 3px; background: var(--bgColor-default, #fff); }
|
|
111
|
+
.file-tree-date::before { position: absolute; top: -10px; bottom: -3px; left: 12px; width: 1px; content: ""; background: var(--bgColor-default, #fff); }
|
|
109
112
|
.file-tree-date:first-child { margin-top: 4px; }
|
|
110
113
|
.file-tree-date button { display: flex; width: 100%; min-height: 28px; align-items: center; gap: 4px; padding: 4px 7px; color: var(--fgColor-default, #1f2328); font: inherit; font-size: 0.75rem; font-weight: 600; text-align: left; background: transparent; border: 0; border-radius: 5px; cursor: pointer; }
|
|
111
114
|
.file-tree-date button:hover { background: var(--bgColor-muted, #f6f8fa); }
|
|
@@ -114,19 +117,22 @@ export const fileTreeStyles = ` body.markdown-body.has-file-tree { width: 100
|
|
|
114
117
|
.file-tree-date button[aria-expanded="false"] svg { transform: rotate(-90deg); }
|
|
115
118
|
.file-tree-date button span { min-width: 18px; margin-left: auto; padding: 1px 5px; color: var(--fgColor-muted, #59636e); font-size: 0.6875rem; font-weight: 600; line-height: 16px; text-align: center; background: var(--bgColor-neutral-muted, #818b981f); border-radius: 9px; }
|
|
116
119
|
.file-tree-recent .is-date-collapsed { display: none; }
|
|
117
|
-
.file-tree-directory-group { display:
|
|
120
|
+
.file-tree-directory-group { display: none; }
|
|
118
121
|
.file-tree-directory-group .folder-icon { width: 13px; height: 13px; flex: none; }
|
|
119
122
|
.file-tree-directory-group span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
120
|
-
.file-tree-recent-file
|
|
121
|
-
.file-tree-recent-
|
|
122
|
-
.file-tree-recent-label
|
|
123
|
+
.file-tree-recent-file { position: relative; margin-left: 22px; }
|
|
124
|
+
.file-tree-recent-file a { position: relative; margin-top: 0; margin-bottom: 0; overflow: visible; align-items: flex-start; gap: 7px; }
|
|
125
|
+
.file-tree-recent-label { display: flex; min-width: 0; flex: 1; }
|
|
126
|
+
.file-tree-recent-label .file-tree-name { width: 100%; color: var(--fgColor-default, #1f2328); font-size: 0.8125rem; font-weight: 400; }
|
|
123
127
|
.file-tree-recent-file a:hover .file-tree-name { text-decoration: underline; text-underline-offset: 2px; }
|
|
124
|
-
.file-tree-directory-
|
|
125
|
-
.file-tree-directory-
|
|
126
|
-
.file-tree-directory-path
|
|
127
|
-
.file-tree-
|
|
128
|
+
.file-tree-directory-tooltip { position: fixed; z-index: 100; top: 0; left: 0; display: none; max-width: min(240px, calc(100vw - 16px)); flex-direction: column; align-items: flex-start; gap: 3px; padding: 6px 8px; color: var(--fgColor-default, #1f2328); font-size: 0.6875rem; font-weight: 400; line-height: 1.35; white-space: nowrap; background: var(--bgColor-default, #fff); border: 1px solid var(--borderColor-default, #d0d7de); border-radius: 5px; box-shadow: 0 2px 8px rgba(31,35,40,.16); transform: translateY(-50%); pointer-events: none; }
|
|
129
|
+
.file-tree-directory-tooltip::before { position: absolute; top: 50%; right: calc(100% - 4px); width: 7px; height: 7px; content: ""; background: var(--bgColor-default, #fff); border: 0 solid var(--borderColor-default, #d0d7de); border-width: 0 0 1px 1px; transform: translateY(-50%) rotate(45deg); }
|
|
130
|
+
.file-tree-directory-tooltip-path { display: flex; max-width: 220px; align-items: center; gap: 5px; overflow: hidden; }
|
|
131
|
+
.file-tree-directory-tooltip-path .folder-icon { width: 12px; height: 12px; flex: none; margin: 0; }
|
|
132
|
+
.file-tree-directory-tooltip-path > span { overflow: hidden; text-overflow: ellipsis; }
|
|
133
|
+
.file-tree-directory-tooltip > time { color: var(--fgColor-muted, #59636e); font-variant-numeric: tabular-nums; }
|
|
134
|
+
.file-tree-recent-file a:hover .file-tree-directory-tooltip, .file-tree-recent-file a:focus-visible .file-tree-directory-tooltip { display: flex; }
|
|
128
135
|
.file-tree-recent-file .file-tree-comment-count { margin-top: 1px; }
|
|
129
|
-
.file-tree-recent-file > a > time { width: 34px; flex: none; padding-top: 1px; color: var(--fgColor-muted, #59636e); font-size: 0.6875rem; font-variant-numeric: tabular-nums; line-height: 1.35; }
|
|
130
136
|
.file-tree-recent-empty { margin: 10px 4px 2px; color: var(--fgColor-muted, #59636e); font-size: 0.8125rem; text-align: center; }
|
|
131
137
|
@media (max-width: 900px) {
|
|
132
138
|
body.markdown-body.has-file-tree, body.markdown-body.has-file-tree.file-sidebar-collapsed { width: calc(100% - 24px); margin: 0 12px; padding: 12px 0 0; grid-template-columns: minmax(0, 1fr); grid-template-areas: "toc" "content"; gap: 16px; }
|
package/dist/utils/icons.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export declare function renderCopyIcon(): string;
|
|
|
2
2
|
export declare function renderAddIcon(): string;
|
|
3
3
|
export declare function renderWrapIcon(): string;
|
|
4
4
|
export declare function renderEditIcon(): string;
|
|
5
|
+
export declare function renderCloseIcon(): string;
|
|
5
6
|
export declare function renderDeleteIcon(): string;
|
|
6
7
|
export declare function renderArchiveIcon(): string;
|
|
7
8
|
export declare function renderRestoreIcon(): string;
|
package/dist/utils/icons.js
CHANGED
|
@@ -10,6 +10,9 @@ export function renderWrapIcon() {
|
|
|
10
10
|
export function renderEditIcon() {
|
|
11
11
|
return '<svg class="action-icon edit-icon" viewBox="0 0 16 16" aria-hidden="true"><path d="m10.5 2.5 3 3-7.75 7.75-3.5.5.5-3.5Z"/><path d="m9 4 3 3"/></svg>';
|
|
12
12
|
}
|
|
13
|
+
export function renderCloseIcon() {
|
|
14
|
+
return '<svg class="action-icon close-icon" viewBox="0 0 16 16" aria-hidden="true"><path d="m4 4 8 8M12 4l-8 8"/></svg>';
|
|
15
|
+
}
|
|
13
16
|
export function renderDeleteIcon() {
|
|
14
17
|
return '<svg class="action-icon delete-icon" viewBox="0 0 16 16" aria-hidden="true"><path d="M3.5 5h9M6 2.5h4l.75 2.5h-5.5Z"/><path d="m4.5 5 .5 8.5h6L11.5 5M7 7.5v3.5m2-3.5v3.5"/></svg>';
|
|
15
18
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type AnnotationDocument } from "../annotations/model.js";
|
|
2
|
-
export interface AnnotationsFeature {
|
|
3
|
-
markup: string;
|
|
4
|
-
panel: string;
|
|
5
|
-
styles: string;
|
|
6
|
-
script: string;
|
|
7
|
-
count: number;
|
|
8
|
-
}
|
|
9
|
-
export declare function createAnnotationsFeature(data?: AnnotationDocument): AnnotationsFeature;
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { countActiveAnnotations, } from "../annotations/model.js";
|
|
2
|
-
import { renderAddIcon, renderArchiveIcon, renderCopyIcon, renderDeleteIcon, renderEditIcon, renderRestoreIcon, } from "../utils/icons.js";
|
|
3
|
-
function safeJson(value) {
|
|
4
|
-
return JSON.stringify(value)
|
|
5
|
-
.replace(/</g, "\\u003c")
|
|
6
|
-
.replace(/>/g, "\\u003e")
|
|
7
|
-
.replace(/&/g, "\\u0026");
|
|
8
|
-
}
|
|
9
|
-
export function createAnnotationsFeature(data) {
|
|
10
|
-
if (!data)
|
|
11
|
-
return { markup: "", panel: "", styles: "", script: "", count: 0 };
|
|
12
|
-
const markup = `<script id="marksites-annotations-data" type="application/json">${safeJson(data)}</script>
|
|
13
|
-
<div class="selection-actions" id="selection-actions" hidden role="toolbar" aria-label="選択範囲の操作">
|
|
14
|
-
<button type="button" data-selection-action="copy" data-tooltip="選択範囲をコピー">${renderCopyIcon()}<span data-copy-label>コピー</span></button>
|
|
15
|
-
<button type="button" data-selection-action="ai" data-tooltip="AI向けの形式でコピー">${renderCopyIcon()}<span data-copy-label>AI向けコピー</span></button>
|
|
16
|
-
<button type="button" data-selection-action="comment" data-tooltip="選択範囲にコメントを追加" disabled title="コメントを追加するにはmarksites serveを起動してください">${renderAddIcon()}<span>コメント</span></button>
|
|
17
|
-
</div>`;
|
|
18
|
-
const panel = `<section class="annotations-panel sidebar-panel" id="sidebar-panel-comments" role="tabpanel" aria-labelledby="sidebar-tab-comments" hidden>
|
|
19
|
-
<div class="annotations-actions"><button type="button" data-add-document-comment data-tooltip="文書全体にコメントを追加" disabled title="コメントを追加するにはmarksites serveを起動してください">${renderAddIcon()}<span>コメントを追加</span></button><button type="button" data-copy-all-comments data-tooltip="有効なコメントをすべてコピー">${renderCopyIcon()}<span data-copy-comments-label>コメントをすべてコピー</span></button></div>
|
|
20
|
-
<p class="annotations-status" id="annotations-status" role="status"></p>
|
|
21
|
-
<div id="annotations-list"></div>
|
|
22
|
-
<p class="annotations-empty" id="annotations-empty" hidden>このページにコメントはありません。</p>
|
|
23
|
-
<form id="annotation-form" hidden><label><span class="annotation-form-label">コメント</span><textarea name="body" maxlength="10000" required></textarea></label><div class="annotation-form-actions"><button type="submit" data-tooltip="コメントを保存">保存</button><button type="button" data-cancel-comment data-tooltip="編集をキャンセル">キャンセル</button></div><p role="status"></p></form>
|
|
24
|
-
</section>`;
|
|
25
|
-
const styles = `
|
|
26
|
-
.selection-actions{position:fixed;z-index:20;display:flex;gap:4px;padding:6px;background:#24292f;border:1px solid #57606a;border-radius:6px;box-shadow:0 8px 24px #140f0f26}
|
|
27
|
-
.selection-actions[hidden],#annotation-form[hidden],.annotations-empty[hidden]{display:none}
|
|
28
|
-
.selection-actions button{display:inline-flex;align-items:center;justify-content:center;gap:5px;border:0;border-radius:4px;padding:5px 9px;color:#fff;background:transparent;font:12px/1 system-ui;cursor:pointer}
|
|
29
|
-
.selection-actions button:hover:not(:disabled){background:#57606a}.selection-actions button:disabled{color:#8c959f;cursor:not-allowed}
|
|
30
|
-
.selection-actions [data-tooltip],.annotations-panel [data-tooltip]{position:relative}.selection-actions [data-tooltip]::after,.annotations-panel [data-tooltip]::after{position:absolute;z-index:30;top:calc(100% + 6px);right:0;width:max-content;max-width:220px;padding:5px 7px;color:#fff;font-size:.6875rem;font-weight:400;line-height:1.3;white-space:normal;background:#24292f;border-radius:4px;box-shadow:0 3px 10px rgba(31,35,40,.2);content:attr(data-tooltip);opacity:0;pointer-events:none;transform:translateY(-2px);transition:opacity 120ms ease,transform 120ms ease}.selection-actions [data-tooltip]:hover::after,.selection-actions [data-tooltip]:focus-visible::after,.annotations-panel [data-tooltip]:hover::after,.annotations-panel [data-tooltip]:focus-visible::after{opacity:1;transform:translateY(0)}
|
|
31
|
-
.annotations-panel{color:#1f2328}
|
|
32
|
-
.annotations-actions{position:sticky;z-index:1;top:-12px;display:flex;flex-direction:column;gap:6px;margin:-12px -12px 0;padding:10px 12px;background:var(--bgColor-default,#fff);border-bottom:1px solid var(--borderColor-muted,#d8dee4)}.annotations-panel button{padding:6px 10px;color:var(--fgColor-default,#1f2328);font:inherit;font-size:.8125rem;font-weight:600;background:var(--button-default-bgColor-rest,#f6f8fa);border:1px solid var(--borderColor-default,#d0d7de);border-radius:6px;cursor:pointer}.annotations-panel button:hover:not(:disabled){background:var(--button-default-bgColor-hover,#eaeef2)}.annotations-panel button:focus-visible{outline:2px solid var(--focus-outlineColor,#0969da);outline-offset:2px}.annotations-panel button:disabled{color:var(--fgColor-muted,#818b98);cursor:not-allowed}.annotations-actions button{display:inline-flex;width:100%;align-items:center;justify-content:center;gap:5px}
|
|
33
|
-
.annotations-empty{margin:24px 8px;color:var(--fgColor-muted,#59636e);font-size:.8125rem;text-align:center}
|
|
34
|
-
.annotations-status{margin:8px;color:var(--fgColor-muted,#59636e);font-size:.75rem}.annotations-status:empty{display:none}.annotation-group{margin:0 -12px;overflow:visible}.annotation-group:last-child{margin-bottom:-12px}.annotation-group[data-comment-group="archived"]{border-top:1px solid var(--borderColor-muted,#d8dee4)}.annotation-group-header{display:flex;align-items:center;min-height:40px;padding:0 12px;background:var(--bgColor-muted,#f6f8fa)}.annotations-panel .annotation-group-toggle{display:flex;min-width:0;flex:1;align-items:center;gap:6px;padding:8px 0;background:transparent;border:0;text-align:left}.annotation-group-toggle .panel-toggle-icon{width:14px;height:14px;flex:none;fill:none;stroke:currentColor;stroke-width:1.5}.annotation-group-toggle[aria-expanded="false"] .panel-toggle-icon{transform:rotate(-90deg)}.annotation-group-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.annotation-group-body[hidden]{display:none}.annotation-group-empty{margin:14px 12px;color:var(--fgColor-muted,#59636e);font-size:.75rem;text-align:center}
|
|
35
|
-
.annotation-card{position:relative;margin:0;padding:12px;border:0;border-bottom:1px solid var(--borderColor-muted,#d8dee4);font-size:.8125rem;line-height:1.5;cursor:pointer}.annotation-card:hover{background:var(--bgColor-muted,#f6f8fa)}.annotation-card:focus-visible,.annotation-card.is-focused{background:var(--bgColor-accent-muted,#ddf4ff);outline:2px solid var(--borderColor-accent-emphasis,#0969da);outline-offset:-2px}.annotation-card:focus-visible .annotation-quote,.annotation-card.is-focused .annotation-quote{border-left-color:var(--borderColor-accent-emphasis,#0969da);color:var(--fgColor-accent,#0969da)}.annotation-quote{display:-webkit-box;margin:0 0 6px;padding-left:9px;overflow:hidden;border-left:3px solid #54aeff;color:#57606a;font-size:.75rem;line-height:1.5;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2}.annotation-context{display:block;margin:0 0 6px;color:var(--fgColor-muted,#59636e);font-size:.75rem}.annotation-source{display:-webkit-box;margin:0 0 6px;overflow:hidden;color:var(--fgColor-muted,#59636e);font-size:.75rem;line-height:1.5;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2}.annotation-card p{white-space:pre-wrap}.annotation-meta{display:flex;align-items:center;gap:8px;margin-top:8px;color:var(--fgColor-muted,#59636e);font-size:.6875rem;line-height:1.4}.annotation-updated{display:block;margin-left:auto}.annotation-kind{display:inline-flex;align-items:center;padding:2px 7px;color:var(--fgColor-muted,#59636e);font-weight:600;background:var(--bgColor-muted,#f6f8fa);border:1px solid var(--borderColor-muted,#d8dee4);border-radius:999px}.annotation-card-actions{position:absolute;top:6px;right:6px;display:flex;gap:1px;padding:2px;background:color-mix(in srgb,var(--bgColor-default,#fff) 94%,transparent);border:1px solid var(--borderColor-muted,#d8dee4);border-radius:6px;box-shadow:0 1px 2px rgba(31,35,40,.08);opacity:0;pointer-events:none;transition:opacity 120ms ease}.annotations-panel .annotation-card-actions button{display:inline-flex;width:28px;height:28px;align-items:center;justify-content:center;margin:0;padding:0;color:var(--fgColor-muted,#59636e);background:transparent;border:0;border-radius:4px}.annotations-panel .annotation-card-actions button:hover{color:var(--fgColor-default,#1f2328);background:var(--button-default-bgColor-hover,#eaeef2)}.annotations-panel .annotation-card-actions [data-annotation-action="delete"]:hover{color:var(--fgColor-danger,#d1242f);background:var(--bgColor-danger-muted,#ffebe9)}.annotation-card:hover>.annotation-card-actions,.annotation-card-actions:focus-within,.annotation-card.is-touch-actions>.annotation-card-actions{opacity:1;pointer-events:auto}.annotation-card.is-editing,.annotation-card.is-editing:hover,.annotation-card.is-editing:focus-visible{padding:12px;background:var(--bgColor-default,#fff);outline:0;box-shadow:0 1px 3px rgba(31,35,40,.08);cursor:default}.annotation-card.is-editing>.annotation-quote{margin-bottom:12px;color:var(--fgColor-muted,#59636e);border-left-color:var(--borderColor-accent-emphasis,#0969da)}.annotation-card.is-editing>p,.annotation-card.is-editing>.annotation-meta,.annotation-card.is-editing>.annotation-card-actions{display:none}.annotation-card.is-editing #annotation-form{margin:0}
|
|
36
|
-
.annotation-highlight{background:#fff8c5;border-bottom:2px solid #bf8700;cursor:pointer}.annotation-highlight.is-focused{background:var(--bgColor-accent-muted,#ddf4ff);border-bottom-color:var(--borderColor-accent-emphasis,#0969da)}
|
|
37
|
-
#annotation-form{margin-top:12px}.annotation-form-label{display:block;margin-bottom:6px;color:var(--fgColor-muted,#59636e);font-size:.75rem;font-weight:600}.annotation-form-actions{display:flex;justify-content:flex-end;gap:6px;margin-top:8px}.annotations-panel .annotation-form-actions button{margin:0}.annotations-panel .annotation-form-actions button[type="submit"]{color:#fff;background:var(--button-primary-bgColor-rest,#1f883d);border-color:var(--button-primary-borderColor-rest,#1f232826);box-shadow:0 1px 0 rgba(31,35,40,.1)}.annotations-panel .annotation-form-actions button[type="submit"]:hover{background:var(--button-primary-bgColor-hover,#1a7f37)}#annotation-form textarea{box-sizing:border-box;width:100%;min-height:96px;display:block;resize:vertical;margin:0;padding:8px 10px;color:var(--fgColor-default,#1f2328);font:inherit;line-height:1.45;background:var(--bgColor-default,#fff);border:1px solid var(--borderColor-default,#d0d7de);border-radius:6px;outline:0}#annotation-form textarea:focus{border-color:var(--borderColor-accent-emphasis,#0969da);box-shadow:0 0 0 3px var(--bgColor-accent-muted,#ddf4ff)}#annotation-form [role="status"]{margin:6px 0 0;color:var(--fgColor-muted,#59636e);font-size:.75rem}
|
|
38
|
-
@media(prefers-reduced-motion:reduce){.annotation-card-actions{transition:none}}
|
|
39
|
-
`;
|
|
40
|
-
const script = `<script>(()=>{
|
|
41
|
-
const dataElement=document.getElementById('marksites-annotations-data');if(!dataElement)return;
|
|
42
|
-
let state=JSON.parse(dataElement.textContent||'{}'),editable=false,pendingSelection=null,editingId=null;
|
|
43
|
-
const content=document.querySelector('.markdown-content'),toolbar=document.getElementById('selection-actions'),addDocumentComment=document.querySelector('[data-add-document-comment]'),copyAllComments=document.querySelector('[data-copy-all-comments]'),list=document.getElementById('annotations-list'),empty=document.getElementById('annotations-empty'),count=document.getElementById('annotation-count'),panelStatus=document.getElementById('annotations-status'),form=document.getElementById('annotation-form'),formHome=document.createComment('annotation-form-home');form.before(formHome);
|
|
44
|
-
const excluded='button,textarea,input,.selection-actions,.annotations-panel,.file-tree,.table-of-contents,.code-block-actions';
|
|
45
|
-
const groupParameter='comments',groupDefinitions=[['comments',''],['archived','アーカイブ']],validGroups=new Set(['archived']),openGroups=new Set((new URL(location.href).searchParams.get(groupParameter)||'').split(',').filter(key=>validGroups.has(key)));
|
|
46
|
-
function syncGroupState(){const updateUrl=url=>{url.searchParams.delete(groupParameter);if(openGroups.size)url.searchParams.set(groupParameter,groupDefinitions.map(([key])=>key).filter(key=>openGroups.has(key)).join(','));return url};history.replaceState(null,'',updateUrl(new URL(location.href)));for(const link of document.querySelectorAll('a[href]')){const raw=link.getAttribute('href');if(!raw||raw.startsWith('#'))continue;const url=new URL(raw,location.href);if(url.protocol===location.protocol&&url.host===location.host&&url.pathname.endsWith('.html'))link.href=updateUrl(url).href}}
|
|
47
|
-
function resetFormPosition(){form.hidden=true;formHome.after(form)}
|
|
48
|
-
function openForm(card=null){resetFormPosition();form.reset();form.hidden=false;if(card){card.classList.add('is-editing');card.append(form)}else list.before(form);form.querySelector('textarea').focus()}
|
|
49
|
-
function copy(text){if(navigator.clipboard&&location.protocol!=='file:')return navigator.clipboard.writeText(text);const area=document.createElement('textarea');area.value=text;area.style.position='fixed';area.style.opacity='0';document.body.append(area);area.select();const ok=document.execCommand('copy');area.remove();return ok?Promise.resolve():Promise.reject(new Error('コピーに失敗しました'))}
|
|
50
|
-
function formatTimestamp(value){const date=new Date(value),pad=part=>String(part).padStart(2,'0');if(Number.isNaN(date.getTime()))return value;return date.getFullYear()+'-'+pad(date.getMonth()+1)+'-'+pad(date.getDate())+' '+pad(date.getHours())+':'+pad(date.getMinutes())+':'+pad(date.getSeconds())}
|
|
51
|
-
function sortedAnnotations(){return[...state.annotations].sort((left,right)=>Date.parse(right.createdAt)-Date.parse(left.createdAt))}
|
|
52
|
-
function annotationMetadata(a,title='コメント'){const located=a.selection.headingId?null:locate(a),headingId=a.selection.headingId||headingFor(located?.startContainer),heading=headingId?document.getElementById(headingId):null,headingText=heading?.textContent?.trim()||'なし',documentComment=a.selection.exact==='';return['# '+title,'文書: '+state.document,'見出し: '+headingText,'','引用:',documentComment?'文書全体':'> '+a.selection.exact.replace(/\\n/g,'\\n> '),'','コメント:',a.comment.body].join('\\n')}
|
|
53
|
-
function allCommentsMetadata(){const annotations=sortedAnnotations().filter(a=>a.status==='open');return annotations.length?annotations.map((a,index)=>annotationMetadata(a,'コメント '+(index+1))).join('\\n\\n'):['# コメント','文書: '+state.document,'','有効なコメントはありません。'].join('\\n')}
|
|
54
|
-
function headingFor(node){if(!node)return null;const el=node.nodeType===1?node:node.parentElement,direct=el&&el.closest('h1,h2,h3,h4,h5,h6');if(direct)return direct.id;let previous=null;for(const heading of content.querySelectorAll('h1,h2,h3,h4,h5,h6')){if(heading.compareDocumentPosition(node)&Node.DOCUMENT_POSITION_FOLLOWING)previous=heading;else break}return previous?previous.id:null}
|
|
55
|
-
function selectionData(){const selection=getSelection();if(!selection||selection.rangeCount!==1||selection.isCollapsed)return null;const range=selection.getRangeAt(0);if(!content.contains(range.commonAncestorContainer)||(range.commonAncestorContainer.parentElement&&range.commonAncestorContainer.parentElement.closest(excluded)))return null;const exact=selection.toString().trim();if(!exact)return null;const all=content.innerText,index=all.indexOf(exact);return{exact,prefix:index<0?'':all.slice(Math.max(0,index-40),index),suffix:index<0?'':all.slice(index+exact.length,index+exact.length+40),headingId:headingFor(range.startContainer),startOffset:Math.max(0,index),endOffset:Math.max(0,index)+exact.length}}
|
|
56
|
-
document.addEventListener('selectionchange',()=>{clearTimeout(window.__marksitesSelectionTimer);window.__marksitesSelectionTimer=setTimeout(()=>{const next=selectionData();if(!next){toolbar.hidden=true;return}pendingSelection=next;const r=getSelection().getRangeAt(0).getBoundingClientRect();toolbar.style.left=Math.max(8,Math.min(innerWidth-toolbar.offsetWidth-8,r.left))+'px';toolbar.style.top=Math.max(8,r.top-44)+'px';toolbar.hidden=false},80)});
|
|
57
|
-
toolbar.addEventListener('mousedown',e=>e.preventDefault());toolbar.addEventListener('click',async e=>{const button=e.target.closest('button');if(!button||!pendingSelection)return;const label=button.querySelector('[data-copy-label]');try{if(button.dataset.selectionAction==='copy')await copy(pendingSelection.exact);if(button.dataset.selectionAction==='ai')await copy('文書: '+state.document+'\\n見出し: '+(pendingSelection.headingId||'なし')+'\\n\\n> '+pendingSelection.exact.replace(/\\n/g,'\\n> '));if(button.dataset.selectionAction==='comment'&&editable){editingId=null;dispatchEvent(new Event('marksites:show-comments'));openForm()}if(label){label.textContent='コピーしました';setTimeout(()=>label.textContent=button.dataset.selectionAction==='ai'?'AI向けコピー':'コピー',1000)}}catch{if(label)label.textContent='コピー失敗'}});
|
|
58
|
-
addDocumentComment.addEventListener('click',()=>{if(!editable)return;editingId=null;pendingSelection={exact:'',prefix:'',suffix:'',headingId:null,startOffset:0,endOffset:0};openForm()});
|
|
59
|
-
copyAllComments.addEventListener('click',async()=>{const label=copyAllComments.querySelector('[data-copy-comments-label]');try{await copy(allCommentsMetadata());label.textContent='コピーしました';setTimeout(()=>label.textContent='コメントをすべてコピー',1000)}catch{label.textContent='コピー失敗'}});
|
|
60
|
-
function locate(a){const preferred=a.selection.headingId?document.getElementById(a.selection.headingId):null,roots=preferred&&preferred!==content?[preferred,content]:[content];for(const root of roots){const walker=document.createTreeWalker(root,NodeFilter.SHOW_TEXT);let node,text='',nodes=[];while(node=walker.nextNode()){nodes.push([node,text.length]);text+=node.data}let index=text.indexOf(a.selection.exact);if(index<0)continue;const matches=[];while(index>=0){matches.push(index);index=text.indexOf(a.selection.exact,index+1)}if(matches.length>1){const contextual=matches.find(i=>text.slice(Math.max(0,i-a.selection.prefix.length),i)===a.selection.prefix&&text.slice(i+a.selection.exact.length,i+a.selection.exact.length+a.selection.suffix.length)===a.selection.suffix);index=contextual??matches.reduce((best,current)=>Math.abs(current-a.selection.startOffset)<Math.abs(best-a.selection.startOffset)?current:best)}else index=matches[0];let start,end,so=0,eo=0;for(const [n,offset] of nodes){if(!start&&offset+n.data.length>=index){start=n;so=index-offset}if(offset+n.data.length>=index+a.selection.exact.length){end=n;eo=index+a.selection.exact.length-offset;break}}if(!start||!end)continue;const range=document.createRange();range.setStart(start,so);range.setEnd(end,eo);return range}return null}
|
|
61
|
-
function activeAnnotations(){return state.annotations.filter(a=>a.status==='open')}
|
|
62
|
-
function updateCurrentFileCount(){const links=document.querySelectorAll('.file-tree a[aria-current="page"]'),total=activeAnnotations().length;for(const link of links){let badge=link.querySelector('.file-tree-comment-count');if(total===0){if(badge)badge.remove();continue}if(!badge){badge=document.createElement('span');badge.className='file-tree-comment-count';link.append(badge)}badge.textContent=String(total);badge.setAttribute('aria-label','コメント'+total+'件')}}
|
|
63
|
-
function classify(a){const key=a.status==='archived'?'archived':'comments';if(a.selection.exact==='')return{key,kind:'document',range:null};const range=locate(a);return range&&!range.collapsed?{key,kind:'quoted',range}:{key,kind:'unavailable',range:null}}
|
|
64
|
-
function render(){resetFormPosition();document.querySelectorAll('.annotation-highlight').forEach(el=>el.replaceWith(...el.childNodes));list.textContent='';const active=activeAnnotations();count.textContent=String(active.length);empty.hidden=state.annotations.length!==0;updateCurrentFileCount();const classified=sortedAnnotations().map(a=>({a,...classify(a)}));for(const [key,title] of groupDefinitions){const items=classified.filter(item=>item.key===key),section=document.createElement('section');section.className='annotation-group';section.dataset.commentGroup=key;const groupBody=document.createElement('div');groupBody.className='annotation-group-body';groupBody.hidden=key==='archived'&&!openGroups.has(key);if(key==='archived'){const header=document.createElement('div');header.className='annotation-group-header';const toggle=document.createElement('button'),expanded=openGroups.has(key),tip=expanded?'アーカイブを閉じる':'アーカイブを開く';toggle.type='button';toggle.className='annotation-group-toggle';toggle.dataset.toggleCommentGroup=key;toggle.dataset.tooltip=tip;toggle.title=tip;toggle.setAttribute('aria-label',tip);toggle.setAttribute('aria-expanded',String(expanded));toggle.innerHTML='<svg class="panel-toggle-icon" viewBox="0 0 16 16" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg><span class="annotation-group-title">'+title+'</span>';header.append(toggle);section.append(header)}if(items.length===0){const noItems=document.createElement('p');noItems.className='annotation-group-empty';noItems.textContent='コメントはありません。';groupBody.append(noItems)}section.append(groupBody);list.append(section);for(const {a,range,kind} of items){const card=document.createElement('article');card.className='annotation-card';card.dataset.id=a.id;card.tabIndex=0;if(kind==='quoted'){const quote=document.createElement('blockquote');quote.className='annotation-quote';quote.textContent=a.selection.exact;card.append(quote)}else{const context=document.createElement('small');context.className='annotation-context';context.textContent=kind==='document'?'文書全体':'引用先なし';card.append(context);if(kind==='unavailable'){const source=document.createElement('div');source.className='annotation-source';source.textContent=a.selection.exact;card.append(source)}}const body=document.createElement('p');body.textContent=a.comment.body;const meta=document.createElement('div');meta.className='annotation-meta';const kindLabel=document.createElement('span');kindLabel.className='annotation-kind';kindLabel.textContent=kind==='quoted'?'引用':kind==='unavailable'?'引用先なし':'文書全体';const updated=document.createElement('time');updated.className='annotation-updated';updated.dateTime=a.updatedAt;updated.textContent='更新 '+formatTimestamp(a.updatedAt);meta.append(kindLabel,updated);card.append(body,meta);const actions=document.createElement('div');actions.className='annotation-card-actions';const availableActions=[['コメントをコピー','copy',${JSON.stringify(renderCopyIcon())}]];if(editable){if(a.status==='archived')availableActions.push(['コメントを復元','restore',${JSON.stringify(renderRestoreIcon())}]);else availableActions.push(['コメントを編集','edit',${JSON.stringify(renderEditIcon())}],['コメントをアーカイブ','archive',${JSON.stringify(renderArchiveIcon())}]);availableActions.push(['コメントを削除','delete',${JSON.stringify(renderDeleteIcon())}])}for(const [label,action,icon] of availableActions){const b=document.createElement('button');b.type='button';b.innerHTML=icon;b.setAttribute('aria-label',label);b.title=label;b.dataset.tooltip=label;b.dataset.annotationAction=action;b.dataset.id=a.id;actions.append(b)}card.append(actions);groupBody.append(card);if(kind==='quoted'&&range&&a.status==='open'){const mark=document.createElement('mark');mark.className='annotation-highlight';mark.dataset.annotationId=a.id;try{range.surroundContents(mark)}catch{}}}}}
|
|
65
|
-
function focusAnnotation(id){list.querySelectorAll('.annotation-card.is-focused').forEach(item=>item.classList.remove('is-focused'));document.querySelectorAll('.annotation-highlight.is-focused').forEach(item=>item.classList.remove('is-focused'));const escaped=CSS.escape(id),card=list.querySelector('[data-id="'+escaped+'"]'),mark=document.querySelector('.annotation-highlight[data-annotation-id="'+escaped+'"]');if(card)card.classList.add('is-focused');if(mark)mark.classList.add('is-focused');return{card,mark}}
|
|
66
|
-
function showAnnotation(id){dispatchEvent(new Event('marksites:show-comments'));const annotation=state.annotations.find(item=>item.id===id),focused=focusAnnotation(id);if(!annotation||annotation.selection.exact==='')return;if(focused.mark)focused.mark.scrollIntoView({behavior:'smooth',block:'center'})}
|
|
67
|
-
function setGroupOpen(key,open,sync=true){const section=list.querySelector('[data-comment-group="'+CSS.escape(key)+'"]');if(open)openGroups.add(key);else openGroups.delete(key);if(section){const toggle=section.querySelector('[data-toggle-comment-group]'),tip=open?'アーカイブを閉じる':'アーカイブを開く';toggle.setAttribute('aria-expanded',String(open));toggle.setAttribute('aria-label',tip);toggle.dataset.tooltip=tip;toggle.title=tip;section.querySelector('.annotation-group-body').hidden=!open}if(sync)syncGroupState()}
|
|
68
|
-
list.addEventListener('click',e=>{const toggle=e.target.closest('[data-toggle-comment-group]');if(toggle)setGroupOpen(toggle.dataset.toggleCommentGroup,toggle.getAttribute('aria-expanded')!=='true')});
|
|
69
|
-
document.addEventListener('click',async e=>{const mark=e.target.closest('.annotation-highlight');if(mark){dispatchEvent(new Event('marksites:show-comments'));const focused=focusAnnotation(mark.dataset.annotationId);if(focused.card)focused.card.scrollIntoView({block:'nearest'})}const card=e.target.closest('.annotation-card');if(card&&!e.target.closest('button,textarea,form'))showAnnotation(card.dataset.id);const action=e.target.closest('[data-annotation-action]');if(action){const a=state.annotations.find(x=>x.id===action.dataset.id);if(!a)return;focusAnnotation(a.id);if(action.dataset.annotationAction==='copy'){try{await copy(annotationMetadata(a));action.setAttribute('aria-label','コメントをコピーしました');action.title='コピーしました';action.dataset.tooltip='コピーしました';setTimeout(()=>{action.setAttribute('aria-label','コメントをコピー');action.title='コメントをコピー';action.dataset.tooltip='コメントをコピー'},1000)}catch{action.title='コピーに失敗しました';action.dataset.tooltip='コピーに失敗しました'}}else if(action.dataset.annotationAction==='edit'){editingId=a.id;pendingSelection=a.selection;dispatchEvent(new Event('marksites:show-comments'));openForm(card);form.body.value=a.comment.body;form.body.focus()}else if(action.dataset.annotationAction==='archive')mutate('PATCH','/annotations/'+encodeURIComponent(a.id),{baseRevision:state.revision,status:'archived'});else if(action.dataset.annotationAction==='restore')mutate('PATCH','/annotations/'+encodeURIComponent(a.id),{baseRevision:state.revision,status:'open'});else if(action.dataset.annotationAction==='delete'&&confirm(window.marksitesTranslate?window.marksitesTranslate('このコメントを削除しますか?'):'このコメントを削除しますか?'))mutate('DELETE','/annotations/'+encodeURIComponent(a.id),{baseRevision:state.revision})}});
|
|
70
|
-
document.addEventListener('pointerdown',e=>{if(e.pointerType!=='touch')return;const card=e.target.closest('.annotation-card');list.querySelectorAll('.annotation-card.is-touch-actions').forEach(item=>item.classList.toggle('is-touch-actions',item===card));if(card)card.classList.add('is-touch-actions')});
|
|
71
|
-
list.addEventListener('keydown',e=>{const card=e.target.closest('.annotation-card');if(card&&!e.target.closest('form')&&(e.key==='Enter'||e.key===' ')){e.preventDefault();showAnnotation(card.dataset.id)}});
|
|
72
|
-
form.addEventListener('submit',e=>{e.preventDefault();const body=form.body.value;if(editingId)mutate('PATCH','/annotations/'+encodeURIComponent(editingId),{baseRevision:state.revision,comment:{body}});else mutate('POST','/annotations',{document:state.document,baseRevision:state.revision,selection:pendingSelection,comment:{body}})});form.querySelector('[data-cancel-comment]').addEventListener('click',()=>{editingId=null;render()});
|
|
73
|
-
async function mutate(method,path,body){body.document=state.document;const formStatus=form.querySelector('[role=status]'),previousIds=new Set(state.annotations.map(item=>item.id)),setStatus=value=>{formStatus.textContent=value;panelStatus.textContent=value};setStatus('保存中…');try{const response=await fetch('/_marksites/api/v1'+path,{method,headers:{'content-type':'application/json'},body:JSON.stringify(body)});const result=await response.json();if(response.status===409){const latest=await fetch('/_marksites/api/v1/annotations?document='+encodeURIComponent(state.document),{cache:'no-store'}).then(r=>r.json());if(latest.data)state=latest.data;render();setStatus('別の画面でコメントが更新されました。最新の内容を確認して、もう一度操作してください。');return}if(!response.ok)throw new Error(result.error&&result.error.message||'保存に失敗しました');state=result.data;const created=method==='POST'?state.annotations.find(item=>!previousIds.has(item.id)):null;form.hidden=true;setStatus('');render();syncGroupState();dispatchEvent(new Event('marksites:show-comments'));if(created){const focused=focusAnnotation(created.id);focused.card?.focus({preventScroll:true});focused.card?.scrollIntoView({block:'nearest'})}}catch(error){setStatus(error.message);if(error instanceof TypeError){editable=false;toolbar.querySelector('[data-selection-action=comment]').disabled=true;addDocumentComment.disabled=true;render()}}}
|
|
74
|
-
async function connect(){if(location.protocol==='file:')return;try{const controller=new AbortController();setTimeout(()=>controller.abort(),1500);const response=await fetch('/_marksites/api/v1/runtime',{cache:'no-store',signal:controller.signal});const runtime=await response.json();if(runtime.data&&runtime.data.service==='marksites'&&runtime.data.apiVersion===1&&runtime.data.projectId&&runtime.data.capabilities.includes('annotations:write')){editable=true;const selectionComment=toolbar.querySelector('[data-selection-action=comment]');selectionComment.disabled=false;selectionComment.title='選択範囲にコメントを追加';addDocumentComment.disabled=false;addDocumentComment.title='文書全体にコメントを追加';const latest=await fetch('/_marksites/api/v1/annotations?document='+encodeURIComponent(state.document),{cache:'no-store'}).then(r=>r.json());if(latest.data)state=latest.data;render()}}catch{}}
|
|
75
|
-
render();syncGroupState();connect();
|
|
76
|
-
})()</script>`;
|
|
77
|
-
return { markup, panel, styles, script, count: countActiveAnnotations(data) };
|
|
78
|
-
}
|