Skip to content

Instantly share code, notes, and snippets.

@jrson83
Last active September 8, 2022 14:39
Show Gist options
  • Save jrson83/4480e31f8c681d9a0fa0feeb27a53ad5 to your computer and use it in GitHub Desktop.
Save jrson83/4480e31f8c681d9a0fa0feeb27a53ad5 to your computer and use it in GitHub Desktop.
markdown-it lume-code plugin
export default class LumeCode extends HTMLElement {
connectedCallback() {
document.querySelectorAll('[role="tab"]')?.forEach((tab) => {
tab.addEventListener("click", this.handleTabChange);
});
}
handleTabChange(e) {
const target = e.target;
const parent = target.parentNode;
const grandparent = parent.parentNode;
const current = target.getAttribute("aria-controls");
grandparent.querySelectorAll('[aria-selected="true"]').forEach((t) => {
if (t === target) return
t.setAttribute("aria-selected", false);
t.classList.remove("is-active");
});
target.setAttribute("aria-selected", true);
target.classList.add("is-active");
grandparent.parentNode.querySelectorAll('[role="tabpanel"]').forEach((p) => {
if (p.id === current) {
p.setAttribute("aria-selected", true);
} else {
p.setAttribute("aria-selected", false);
}
});
}
}
export default (md: any) => {
const getLine = (state: any, lineNum: any) => {
return state.src.slice(state.bMarks[lineNum], state.eMarks[lineNum]);
};
const tokenize = (state: any, startLine: any, endLine: any, silent: any) => {
const lume_code_open = "<lume-code>";
const lume_code_close = "</lume-code>";
const content: any[] = [];
let line;
// no whitespace allowed before beginning
if (state.sCount[startLine] - state.blkIndent > 0) {
return false;
}
// read start marker
line = getLine(state, startLine);
// if no marker found, skip || first line must be just the marker
if (line.indexOf(lume_code_open) !== 0 || line.trim() !== lume_code_open) {
return false;
}
const marker = line;
// keep reading until end marker
let properlyEnded = false;
let nextLine = startLine;
for (nextLine = startLine + 1; nextLine < endLine; nextLine++) {
line = getLine(state, nextLine);
if (line.includes(lume_code_close) && line.trim() === lume_code_close) {
properlyEnded = true;
break;
}
content.push(line);
}
if (!properlyEnded) {
return false;
}
state.line = nextLine + 1;
if (silent) {
return true;
}
let token = state.push("lume_code_open", "lume-code", 1);
token.markup = marker;
token.block = true;
token.map = [startLine, state.line];
state.md.block.tokenize(state, startLine + 1, nextLine);
token = state.push("lume_code_close", "lume-code", -1);
token.markup = lume_code_close;
token.block = true;
return true;
};
md.block.ruler.before("fence", "lume_code", tokenize, {
alt: ["paragraph", "reference", "blockquote", "list"],
});
const defaultRender = md.renderer.rules.fence ||
function (tokens: any, idx: number, options: any, env: any, self: any) {
return self.renderToken(tokens, idx, options, env, self);
};
/* md.renderer.rules.lume_code_open = () => {
return `<lume-code>`;
}; */
md.renderer.rules.fence = (
tokens: any,
idx: number,
options: any,
env: any,
self: any,
) => {
const token = tokens[idx];
if (
token.type === "fence" && Array.isArray(token.attrs) &&
token.attrs[0][0] === "title"
) {
// do work here. finall output should be, example page https://lume.land/docs/overview/installation/:
/*
The problem is, if we have multiple lume-code on one site, we have to use id="tab-TABLIST_NUMBER-ID" so the button controls ria-controls="panel-TABLIST_NUMBER-ID"
<lume-code>
<ul class="lume-code-menu" role="tablist" aria-label="Code Tabs">
<li>
<button class="lume-code-tab is-active" role="tab" aria-selected="true" aria-controls="panel-1-1" id="tab-1-1" tabindex="0">
_config.js
</button>
</li>
<li>
<button class="lume-code-tab" role="tab" aria-selected="false" aria-controls="panel-1-2" id="tab-1-2" tabindex="-1">
deno.json
</button>
</li>
<li>
<button class="lume-code-tab" role="tab" aria-selected="false" aria-controls="panel-1-3" id="tab-1-3" tabindex="-1">
import_map.json
</button>
</li>
</ul>
<pre id="panel-1" role="tabpanel" tabindex="0" aria-labelledby="tab-1-1">
<code title="_config.js" class="language-js hljs language-javascript">
// tokens[idx].content
</code>
</pre>
<pre id="panel-2" role="tabpanel" tabindex="0" aria-labelledby="tab-1-2" hidden>
<code title="deno.json" class="language-json hljs">
// tokens[idx].content
</code>
</pre>
<pre id="panel-3" role="tabpanel" tabindex="0" aria-labelledby="tab-1-3" hidden>
<code title="import_map.json" class="language-json hljs">
// tokens[idx].content
</code>
</pre>
</lume-code>
*/
}
return ``;
};
/* md.renderer.rules.lume_code_close = () => {
return `</lume-code>`;
}; */
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment