scrapboxのページカードを作成するscript
説明文の実装
1行づつ<p>で囲む
各種構文
無視するもの
テーブル
コードブロック
数式
画像
DOMじゃなくてelement.insertAdjacentHTML()に入れられるtext形式で返したほうがいいな
textならWebWorkerでも計算できる
code:script.js
import {ScrapboxParser} from '/api/code/takker/scrapbox-parser.min.js/parser.js';
export function createPageCard({project, title, description, imageUrl=undefined} = {}) {
//console.log(project: ${project});
//console.log(description: ${description});
//console.log(imageUrl: ${imageUrl});
const content = imageUrl ?
`<div class="icon">
<img loading="lazy" src="${imageUrl}">
</div>` :
<div class="description">${parse(description, project)}</div>;
return `
<li class="page-list-item grid-style-itme">
<a href="/${project}/${encodeURIComponent(title)}" rel="route">
<div class="hover"></div>
<div class="content">
<div class="header">
<div class="title">${title}</div>
</div>
${content}
</div>
</a>
</li>`;
}
function parse(text, project) {
const blocks = ScrapboxParser.parse(text, {hasTitle: false});
return blocks.map(block => convertSb2HTML(block, project)).join('\n');
}
function convertSb2HTML(block, project) {
switch (block.type) {
case 'title':
return ''; // タイトルは選択範囲に入らないので無視
case 'codeBlock':
case 'table':
return '';
case 'line':
if (block.nodes.length === 0) return '';
if(block.nodes.length === 1) {
const node = block.nodes0; if (node.type === 'blank') return '';
if (node.type === 'plain') return <p>${node.text}</p>;
}
return <p>${block.nodes.map(node => '<span>' + convertNode(node, project) +'</span>').join('')}</p>;
}
}
function convertNode(node, project) {
switch (node.type) {
case 'quote':
case 'image':
case 'strongImage':
case 'formula':
case 'googleMap':
return '';
case 'icon':
case 'strongIcon':
if (node.pathType ==='relative') {
return <img class="inline-icon" src="https://scrapbox.io/api/pages/${project}/${node.path}/icon" />;
}
return <img class="inline-icon" src="https://scrapbox.io/api/pages${node.path}/icon" />;
case 'strong':
return <strong>${node.text}</strong>;
case 'decoration':
let result = node.nodes.map(node => convertNode(node)).join('');
if (node.decos.includes('/')) result = <i>${result}</i>;
if (node.decos.some(deco => /\*-/.test(deco0))) result = <strong>${result}</strong>; if (node.decos.some(deco => deco0 === '~')) result = <strike>${result}</strike>; return result;
case 'helpfeel':
return <code>? ${node.text}</code>;
case 'code':
return <code>${node.text}</code>;
case 'commandLine':
return <code>${node.symbol} ${node.text}</code>;
case 'link':
switch(node.pathType) {
case 'root':
return <span class="page-link">${node.href}<span>;
case 'relative':
return <span class="page-link">${node.href}</span>;
case 'absolute':
return <span class="link">${node.content ?? node.href}</span>;
}
case 'hashTag':
return <span class="page-link">${node.href}<span>;
case 'blank':
case 'plain':
return node.text;
}
}