Skip to content

Instantly share code, notes, and snippets.

@DylanPiercey
Last active December 12, 2020 16:56
Show Gist options
  • Save DylanPiercey/00a972937194bdb1b944b0085b303520 to your computer and use it in GitHub Desktop.
Save DylanPiercey/00a972937194bdb1b944b0085b303520 to your computer and use it in GitHub Desktop.
Marko tag variables (as syntax)
static function createBuilder(template) {
const parts = template.replace(/\\n/, "\n").replace(/</g, "&lt;").split(" ");
const partEntries = Object.entries(parts.reduce((map, str, i) => {
["TAG", "VAR", "PARAMS", "ATTRS"].forEach(name => {
if (str.indexOf(name) >= 0) {
map[name] = i;
}
});
return map;
}, {}));
const closingTagIndex = parts.findIndex(str => str === "/>");
return (TAG, VAR, PARAMS, ATTRS, selfClosed) => {
const valueMap = { TAG, VAR, PARAMS, ATTRS };
const currentParts = [...parts];
for (const [name, index] of partEntries) {
const value = valueMap[name];
currentParts[index] = value == null ? "" : currentParts[index].replace(name, `<span class="${name}">${value}</span>`);
}
if (!selfClosed) {
currentParts[closingTagIndex] = ">";
}
return currentParts.join("");
}
}
static const SPACE = (str) => str.trim().replace(/\n/g, "<br>");
static const TEXT = (strings, ...values) => {
let text = "";
for (let i = 0; i < strings.length; i++) {
text += `<span class="text">${strings[i]}</span>`;
if (values[i]) {
text += `<span class="interpolate">\${</span><span class="placeholder">${values[i]}</span><span class="interpolate">}</span>`
}
}
return text;
}
static const CLOSE = (name) => `<span class="symbol">&lt;/</span><span class="TAG">${name}</span><span class="symbol">></span>`;
$ const OPEN = createBuilder(state.template);
class {
onCreate() {
this.state = {
template: `< TAG |PARAMS| ATTRS /> as VAR`,
stateTag: "let",
computationTag: "const",
tagTag: "tag",
defaultAttr: ""
}
}
onMount() {
try {
const state = (new URL(window.location.href)).searchParams.get("state");
if (state) {
this.state = JSON.parse(state);
}
} catch (e) {
console.log("unable to parse state from url", e);
}
}
syncState(e) {
this.state[e.target.name] = e.target.value;
const url = new URL(window.location.href);
url.searchParams.set("state", JSON.stringify(this.state));
window.history.replaceState({}, "", url);
}
}
<style>
code {
background: #eee;
padding:0.2em;
}
label, small, input {
display: block;
}
label {
margin-top: 1em;
}
input, textarea {
font: monospace;
width: 30em;
}
.example {
background:#222;
border-radius:2px;
padding:1em;
color:#fff;
font:monospace;
}
.TAG {
color: #F92672;
}
.ATTRS {
color: #A6E22E;
}
.PARAMS {
color: #AE81FF;
}
.VAR {
color: #66D9EF;
}
.text {
color: #E6DB74;
}
.interpolate {
color: #66D9EF;
}
</style>
<h1>Tag Var Syntax</h1>
<form>
<label>Template</label>
<input name="template" value=state.template on-input("syncState")/>
<small>Use <code>TAG</code> <code>VAR</code> <code>PARAMS</code> <code>ATTRS</code>) delimited by two spaces</small>
<label>State Tag</label>
<input name="stateTag" value=state.stateTag on-input("syncState")>
<label>Computation Tag</label>
<input name="computationTag" value=state.computationTag on-input("syncState")>
<label>Tag Tag</label>
<input name="tagTag" value=state.tagTag on-input("syncState")>
<label>Default Attribute</label>
<input name="defaultAttr" value=state.defaultAttr on-input("syncState")>
</form>
<h2>Counter</h2>
<div class="example">
$!{SPACE(`
${OPEN(state.stateTag, "count", null, `${state.defaultAttr}=0`, true)}
${OPEN("div", null, null, ` class="count"`, false)}
&nbsp;&nbsp;${TEXT`${"count"}`}
${CLOSE("div")}
${OPEN("button", null, null, ` onclick() { count++ }`, false)}
&nbsp;&nbsp;${TEXT`increment`}
${CLOSE("button")}
`)}
</div>
<h2>Ref</h2>
<div class="example">
$!{SPACE(`
${OPEN("div", "el", null, null, false)}
&nbsp;&nbsp;${TEXT`Hello`}
${CLOSE("div")}
${OPEN("button", null, null, ` onclick() { console.log(el.offsetWidth) }`, false)}
&nbsp;&nbsp;${TEXT`Print Size`}
${CLOSE("button")}
`)}
</div>
<h2>Tag Tag</h2>
<div class="example">
$!{SPACE(`
${OPEN(state.tagTag, "Welcome", "{ name }", null, false)}
&nbsp;&nbsp;${TEXT`Hello ${"name"}!`}
${CLOSE(state.tagTag)}
`)}
</div>
<h2>Import Helper</h2>
<div class="example">
$!{SPACE(`
${OPEN("import", "{ double }", null, `="./math"`, true)}
${OPEN(state.computationTag, "original", null, `${state.defaultAttr}=5`, true)}
${OPEN(state.computationTag, "originalX2", null, `${state.defaultAttr}=double(original)`, true)}
${OPEN("div", null, null, ` class="count"`, false)}
&nbsp;&nbsp;${TEXT`Two times ${"original"} is ${"originalX2"}`}
${CLOSE("div")}
`)}
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment