text-bubble-component@0.2.0
2021-05-29
2021-05-28
読み込み表示は分離したほうがいい
構文解析と描画だけに専念する
読み込み処理は外部に任せる
00:39:32 大体仕様が固まった
/icons2/すばら.iconyosider.icon
実装したいこと
特定のリンクが含まれる行に予めscrollする
特定のIDの行に予めscrollする
使い方
changeContentsに、{project, titleLc, lines}を返す非同期関数を渡す
これでtext bubbleの中身を作る
openで開閉を制御できる
falesのときは常に閉じる
trueでも中身が無い時は閉じる
Preact Componentにした
dependencies
code:script.js
import {html} from '../htm@3.0.4%2Fpreact/script.js';
import {Content, CSS as _CSS} from '../text-bubble-component@0.2.0%2Fparser/script.js'
export const TextBubble = ({project, titleLc, lines, theme, scroll, open, noIndent, ...rest}) =>
open && lines.length > 0 && html`
<div class="text-bubble" data-no-scroll="${!scroll}" data-theme="${theme}" ...${rest}>
<${Content} lines="${lines}" project="${project}" titleLc="${titleLc}" noIndent="${noIndent}" />
</div>`;
code:script.js
export const CSS = `
.text-bubble {
padding: 5px 0px 5px 5px;
font-size: 11px;
line-height: 1.42857;
user-select: text;
position: absolute;
border-radius: 4px;
box-shadow: 0 6px 12px rgba(0,0,0,0.175);
z-index: 9000;
}
max-height: 80vh;
overflow-y: auto;
}
${_CSS}
`;
test code
https://gyazo.com/65f05d713d81b3f281ec652c10834276
code:js
import('/api/code/programming-notes/text-bubble-component@0.2.0/test1.js');
code:test1.js
import {TextBubble, CSS} from './script.js';
import {html, render} from '../htm@3.0.4%2Fpreact/script.js';
import {useState} from '../preact@10.5.13/hooks.js';
import {useLoader} from '../use-loader/script.js';
import {useCursorObserver} from '../use-cursor-observer/script.js';
const App = props => {
// .page-link内にcursorが来たらpreviewを開始する
useCursorObserver(({
cursorRect: {bottom, left},
parentRect: {top: eTop, left: eLeft},
elements,
}) => {
const link = elements.find(element => element.classList.contains('page-link'));
if (!link) {
setOpen(false);
return;
}
setOpen(true);
const matches = new URL(link.href).pathname.match(/\/(\w\-+)\/(.*)$/) setPath({project: matches1, titleLc: matches2}); setPosition({top: Math.round(bottom - eTop), left: Math.round(left - eLeft)});
}, {immediate: false});
// データを読み込む
const {loading} = useLoader(async () => {
if (project === '' || titleLc === '') return;
const res = await fetch(/api/pages/${project}/${titleLc});
const json = await res.json();
setLines(json.lines.slice(1));
return html`
<style>
${CSS}
</style>
${loading ? 'Loading...' : html`
<${TextBubble}
project="${project}"
titleLc="${titleLc}"
lines="${lines}"
style="top: ${position.top}px; left: ${position.left}px;"
scroll
open="${open}"/>
`}
`;
};
const app = document.createElement('div');
app.dataset.userscriptName= 'text-bubble-test';
document.getElementById('editor').append(app);
app.attachShadow({mode: 'open'});
render(html<${App} />, app.shadowRoot);