Last active
December 12, 2020 16:56
-
-
Save DylanPiercey/00a972937194bdb1b944b0085b303520 to your computer and use it in GitHub Desktop.
Marko tag variables (as syntax)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static function createBuilder(template) { | |
const parts = template.replace(/\\n/, "\n").replace(/</g, "<").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"></</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)} | |
${TEXT`${"count"}`} | |
${CLOSE("div")} | |
${OPEN("button", null, null, ` onclick() { count++ }`, false)} | |
${TEXT`increment`} | |
${CLOSE("button")} | |
`)} | |
</div> | |
<h2>Ref</h2> | |
<div class="example"> | |
$!{SPACE(` | |
${OPEN("div", "el", null, null, false)} | |
${TEXT`Hello`} | |
${CLOSE("div")} | |
${OPEN("button", null, null, ` onclick() { console.log(el.offsetWidth) }`, false)} | |
${TEXT`Print Size`} | |
${CLOSE("button")} | |
`)} | |
</div> | |
<h2>Tag Tag</h2> | |
<div class="example"> | |
$!{SPACE(` | |
${OPEN(state.tagTag, "Welcome", "{ name }", null, false)} | |
${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)} | |
${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