summaryrefslogtreecommitdiffstats
path: root/$mmm/plugins
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2022-05-08 19:14:58 +0000
committers-ol <s+removethis@s-ol.nu>2022-05-20 08:38:41 +0000
commitb615a7cf0fc9d81b4b905a9d4e1db0beebdebd3d (patch)
tree2bf24f2da1aa80df2534637de10e0fe45aeb80f0 /$mmm/plugins
downloadhw.s-ol.nu-b615a7cf0fc9d81b4b905a9d4e1db0beebdebd3d.tar.gz
hw.s-ol.nu-b615a7cf0fc9d81b4b905a9d4e1db0beebdebd3d.zip
initial commit
Diffstat (limited to '$mmm/plugins')
-rw-r--r--$mmm/plugins/code/converts: text$lua -> table.lua121
-rw-r--r--$mmm/plugins/code/converts: text$moonscript -> table.moon90
-rw-r--r--$mmm/plugins/code/scripts: text$lua -> fn -> text$html+frag.lua12
-rw-r--r--$mmm/plugins/code/scripts: text$moonscript -> fn -> text$html+frag.moon14
-rw-r--r--$mmm/plugins/code/style: text$css.css110
-rw-r--r--$mmm/plugins/gltf/converts: text$lua -> table.lua16
-rw-r--r--$mmm/plugins/gltf/converts: text$moonscript -> table.moon16
-rw-r--r--$mmm/plugins/gltf/scripts: text$html+frag.html2
-rw-r--r--$mmm/plugins/layout/converts: text$lua -> table.lua193
-rw-r--r--$mmm/plugins/layout/converts: text$moonscript -> table.moon164
-rw-r--r--$mmm/plugins/markdown/converts: text$lua -> table.lua88
-rw-r--r--$mmm/plugins/markdown/converts: text$moonscript -> table.moon67
-rw-r--r--$mmm/plugins/markdown/scripts: text$html+frag.html1
-rw-r--r--$mmm/plugins/moonscript/converts: text$lua -> table.lua24
-rw-r--r--$mmm/plugins/moonscript/converts: text$moonscript -> table.moon22
-rw-r--r--$mmm/plugins/sass/converts: text$lua -> table.lua54
-rw-r--r--$mmm/plugins/sass/converts: text$moonscript -> table.moon55
-rw-r--r--$mmm/plugins/youtube/converts: text$lua -> table.lua24
-rw-r--r--$mmm/plugins/youtube/converts: text$moonscript -> table.moon25
19 files changed, 1098 insertions, 0 deletions
diff --git a/$mmm/plugins/code/converts: text$lua -> table.lua b/$mmm/plugins/code/converts: text$lua -> table.lua
new file mode 100644
index 0000000..c578a69
--- /dev/null
+++ b/$mmm/plugins/code/converts: text$lua -> table.lua
@@ -0,0 +1,121 @@
+local pre, div, button
+do
+ local _obj_0 = require('mmm.dom')
+ pre, div, button = _obj_0.pre, _obj_0.div, _obj_0.button
+end
+local languages
+languages = require('mmm.highlighting').languages
+local Editor
+do
+ local _class_0
+ local o
+ local _base_0 = {
+ EDITOR = true,
+ change = function(self)
+ self.timeout = nil
+ local doc = self.cm:getDoc()
+ if self.lastPreview and doc:isClean(self.lastPreview) then
+ return
+ end
+ self.lastPreview = doc:changeGeneration()
+ local value = doc:getValue()
+ self.fileder.facets[self.key] = value
+ return BROWSER:refresh()
+ end,
+ save = function(self, e)
+ e:preventDefault()
+ local doc = self.cm:getDoc()
+ self.fileder:set(self.key, doc:getValue())
+ self.lastSave = doc:changeGeneration(true)
+ end
+ }
+ _base_0.__index = _base_0
+ _class_0 = setmetatable({
+ __init = function(self, value, mode, fileder, key)
+ self.fileder, self.key = fileder, key
+ self.node = div({
+ class = 'editor'
+ })
+ do
+ local _with_0 = button('save')
+ _with_0.disabled = true
+ _with_0.onclick = function(_, e)
+ return self:save(e)
+ end
+ self.saveBtn = _with_0
+ end
+ self.cm = window:CodeMirror(self.node, o({
+ value = value,
+ mode = mode,
+ lineNumber = true,
+ lineWrapping = true,
+ autoRefresh = true,
+ theme = 'hybrid'
+ }))
+ self.lastSave = self.cm:getDoc():changeGeneration(true)
+ return self.cm:on('changes', function(_, mirr)
+ local doc = self.cm:getDoc()
+ self.saveBtn.disabled = doc:isClean(self.lastSave)
+ if self.timeout then
+ window:clearTimeout(self.timeout)
+ end
+ self.timeout = window:setTimeout((function()
+ return self:change()
+ end), 300)
+ end)
+ end,
+ __base = _base_0,
+ __name = "Editor"
+ }, {
+ __index = _base_0,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ local self = _class_0
+ if MODE == 'CLIENT' then
+ local mkobj = window:eval("(function () { return {}; })")
+ o = function(tbl)
+ do
+ local obj = mkobj()
+ for k, v in pairs(tbl) do
+ obj[k] = v
+ end
+ return obj
+ end
+ end
+ end
+ Editor = _class_0
+end
+local _ = [[ editors: if MODE == 'CLIENT' then {
+ {
+ inp: 'text/([^ ]*).*'
+ out: 'mmm/dom'
+ cost: 0
+ transform: (value, fileder, key) =>
+ mode = @from\match @convert.inp
+ Editor value, mode, fileder, key
+ }
+ {
+ inp: 'URL.*'
+ out: 'mmm/dom'
+ cost: 0
+ transform: (value, fileder, key) =>
+ Editor value, nil, fileder, key
+ }
+ }
+]]
+return {
+ {
+ inp = 'text/([^ ]*).*',
+ out = 'mmm/dom',
+ cost = 5,
+ transform = function(self, val)
+ local lang = self.from:match(self.convert.inp)
+ return pre(languages[lang](val))
+ end
+ }
+}
diff --git a/$mmm/plugins/code/converts: text$moonscript -> table.moon b/$mmm/plugins/code/converts: text$moonscript -> table.moon
new file mode 100644
index 0000000..851efba
--- /dev/null
+++ b/$mmm/plugins/code/converts: text$moonscript -> table.moon
@@ -0,0 +1,90 @@
+import pre, div, button from require 'mmm.dom'
+import languages from require 'mmm.highlighting'
+
+class Editor
+ o = if MODE == 'CLIENT'
+ mkobj = window\eval "(function () { return {}; })"
+ (tbl) ->
+ with obj = mkobj!
+ for k,v in pairs(tbl)
+ obj[k] = v
+
+ EDITOR: true
+
+ new: (value, mode, @fileder, @key) =>
+ @node = div class: 'editor'
+
+ @saveBtn = with button 'save'
+ .disabled = true
+ .onclick = (_, e) -> @save e
+
+ @cm = window\CodeMirror @node, o {
+ :value
+ :mode
+ lineNumber: true
+ lineWrapping: true
+ autoRefresh: true
+ theme: 'hybrid'
+ }
+
+ @lastSave = @cm\getDoc!\changeGeneration true
+
+ @cm\on 'changes', (_, mirr) ->
+ doc = @cm\getDoc!
+ @saveBtn.disabled = doc\isClean @lastSave
+
+ window\clearTimeout @timeout if @timeout
+ @timeout = window\setTimeout (-> @change!), 300
+
+ change: =>
+ @timeout = nil
+ doc = @cm\getDoc!
+
+ if @lastPreview and doc\isClean @lastPreview
+ -- no changes since last event
+ return
+
+ @lastPreview = doc\changeGeneration!
+ value = doc\getValue!
+
+ @fileder.facets[@key] = value
+ BROWSER\refresh!
+
+ save: (e) =>
+ e\preventDefault!
+
+ doc = @cm\getDoc!
+ @fileder\set @key, doc\getValue!
+ @lastSave = doc\changeGeneration true
+
+[[
+ editors: if MODE == 'CLIENT' then {
+ {
+ inp: 'text/([^ ]*).*'
+ out: 'mmm/dom'
+ cost: 0
+ transform: (value, fileder, key) =>
+ mode = @from\match @convert.inp
+ Editor value, mode, fileder, key
+ }
+ {
+ inp: 'URL.*'
+ out: 'mmm/dom'
+ cost: 0
+ transform: (value, fileder, key) =>
+ Editor value, nil, fileder, key
+ }
+ }
+]]
+
+-- syntax-highlighted code
+{
+ {
+ inp: 'text/([^ ]*).*'
+ out: 'mmm/dom'
+ cost: 5
+ transform: (val) =>
+ lang = @from\match @convert.inp
+ pre languages[lang] val
+ }
+}
diff --git a/$mmm/plugins/code/scripts: text$lua -> fn -> text$html+frag.lua b/$mmm/plugins/code/scripts: text$lua -> fn -> text$html+frag.lua
new file mode 100644
index 0000000..87a182f
--- /dev/null
+++ b/$mmm/plugins/code/scripts: text$lua -> fn -> text$html+frag.lua
@@ -0,0 +1,12 @@
+local tourl
+tourl = (require('mmm.mmmfs.util'))({ }).tourl
+return function(self)
+ return "\n <link rel=\"stylesheet\" type=\"text/css\" href=\"" .. tostring(self:gett('style: URL -> text/css')) .. "\" />" .. [[<!--
+ <link rel="stylesheet" type="text/css" href="//unpkg.com/codemirror@5.49.2/lib/codemirror.css" />
+ <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/lib/codemirror.js"></script>
+ <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/mode/lua/lua.js"></script>
+ <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/mode/markdown/markdown.js"></script>
+ <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/addon/display/autorefresh.js"></script>
+-->
+ ]]
+end
diff --git a/$mmm/plugins/code/scripts: text$moonscript -> fn -> text$html+frag.moon b/$mmm/plugins/code/scripts: text$moonscript -> fn -> text$html+frag.moon
new file mode 100644
index 0000000..9799ac6
--- /dev/null
+++ b/$mmm/plugins/code/scripts: text$moonscript -> fn -> text$html+frag.moon
@@ -0,0 +1,14 @@
+import tourl from (require 'mmm.mmmfs.util') {}
+
+=>
+ "
+ <link rel=\"stylesheet\" type=\"text/css\" href=\"#{@gett 'style: URL -> text/css'}\" />" ..
+ [[
+<!--
+ <link rel="stylesheet" type="text/css" href="//unpkg.com/codemirror@5.49.2/lib/codemirror.css" />
+ <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/lib/codemirror.js"></script>
+ <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/mode/lua/lua.js"></script>
+ <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/mode/markdown/markdown.js"></script>
+ <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/addon/display/autorefresh.js"></script>
+-->
+ ]]
diff --git a/$mmm/plugins/code/style: text$css.css b/$mmm/plugins/code/style: text$css.css
new file mode 100644
index 0000000..0acf4a2
--- /dev/null
+++ b/$mmm/plugins/code/style: text$css.css
@@ -0,0 +1,110 @@
+/*
+
+vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid)
+
+*/
+
+/*background color*/
+.hljs {
+ background: #1d1f21;
+ border-radius: 6px;
+ padding: 0.2em 0.5em;
+ white-space: nowrap;
+}
+
+pre > .hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 1em;
+ white-space: pre-wrap;
+ margin: 0 2em;
+}
+
+/*selection color*/
+.hljs::selection,
+.hljs span::selection {
+ background: #373b41;
+}
+
+.hljs::-moz-selection,
+.hljs span::-moz-selection {
+ background: #373b41;
+}
+
+/*foreground color*/
+.hljs {
+ color: #c5c8c6;
+}
+
+/*color: fg_yellow*/
+.hljs-title,
+.hljs-name {
+ color: #f0c674;
+}
+
+/*color: fg_comment*/
+.hljs-comment,
+.hljs-meta,
+.hljs-meta .hljs-keyword {
+ color: #707880;
+}
+
+/*color: fg_red*/
+.hljs-number,
+.hljs-symbol,
+.hljs-literal,
+.hljs-deletion,
+.hljs-link {
+ color: #cc6666
+}
+
+/*color: fg_green*/
+.hljs-string,
+.hljs-doctag,
+.hljs-addition,
+.hljs-regexp,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+ color: #b5bd68;
+}
+
+/*color: fg_purple*/
+.hljs-attribute,
+.hljs-code,
+.hljs-selector-id {
+ color: #b294bb;
+}
+
+/*color: fg_blue*/
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-bullet,
+.hljs-tag {
+ color: #81a2be;
+}
+
+/*color: fg_aqua*/
+.hljs-subst,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable {
+ color: #8abeb7;
+}
+
+/*color: fg_orange*/
+.hljs-type,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-quote,
+.hljs-section,
+.hljs-selector-class {
+ color: #de935f;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/$mmm/plugins/gltf/converts: text$lua -> table.lua b/$mmm/plugins/gltf/converts: text$lua -> table.lua
new file mode 100644
index 0000000..5a7869f
--- /dev/null
+++ b/$mmm/plugins/gltf/converts: text$lua -> table.lua
@@ -0,0 +1,16 @@
+local dom = require('mmm.dom')
+return {
+ {
+ inp = 'URL -> model/gltf-binary',
+ out = 'mmm/dom',
+ cost = 1,
+ transform = function(self, href)
+ return dom['model-viewer']({
+ src = href,
+ ['auto-rotate'] = true,
+ ['camera-controls'] = true,
+ ['camera-orbit'] = "548.2deg 117deg 282.4m"
+ })
+ end
+ }
+}
diff --git a/$mmm/plugins/gltf/converts: text$moonscript -> table.moon b/$mmm/plugins/gltf/converts: text$moonscript -> table.moon
new file mode 100644
index 0000000..1036eee
--- /dev/null
+++ b/$mmm/plugins/gltf/converts: text$moonscript -> table.moon
@@ -0,0 +1,16 @@
+dom = require 'mmm.dom'
+
+{
+ {
+ inp: 'URL -> model/gltf-binary'
+ out: 'mmm/dom'
+ cost: 1
+ transform: (href) =>
+ dom['model-viewer'] {
+ src: href
+ 'auto-rotate': true
+ 'camera-controls': true
+ 'camera-orbit': "548.2deg 117deg 282.4m"
+ }
+ }
+}
diff --git a/$mmm/plugins/gltf/scripts: text$html+frag.html b/$mmm/plugins/gltf/scripts: text$html+frag.html
new file mode 100644
index 0000000..d2b1e44
--- /dev/null
+++ b/$mmm/plugins/gltf/scripts: text$html+frag.html
@@ -0,0 +1,2 @@
+ <script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>
+ <script nomodule src="https://unpkg.com/@google/model-viewer/dist/model-viewer-legacy.js"></script>
diff --git a/$mmm/plugins/layout/converts: text$lua -> table.lua b/$mmm/plugins/layout/converts: text$lua -> table.lua
new file mode 100644
index 0000000..2acf8b7
--- /dev/null
+++ b/$mmm/plugins/layout/converts: text$lua -> table.lua
@@ -0,0 +1,193 @@
+local header, aside, footer, nav, div, svg, script, g, path, ul, li, h1, span, b, a, img
+do
+ local _obj_0 = require('mmm.dom')
+ header, aside, footer, nav, div, svg, script, g, path, ul, li, h1, span, b, a, img = _obj_0.header, _obj_0.aside, _obj_0.footer, _obj_0.nav, _obj_0.div, _obj_0.svg, _obj_0.script, _obj_0.g, _obj_0.path, _obj_0.ul, _obj_0.li, _obj_0.h1, _obj_0.span, _obj_0.b, _obj_0.a, _obj_0.img
+end
+local navigate_to
+navigate_to = (require('mmm.mmmfs.util'))(require('mmm.dom')).navigate_to
+local get_plugins
+get_plugins = require('mmm.mmmfs.meta').get_plugins
+local unpack = unpack or table.unpack
+local pick
+pick = function(...)
+ local num = select('#', ...)
+ local i = math.ceil(math.random() * num)
+ return (select(i, ...))
+end
+local iconlink
+iconlink = function(href, src, alt, style)
+ return a({
+ class = 'iconlink',
+ target = '_blank',
+ rel = 'me',
+ href = href,
+ img({
+ src = src,
+ alt = alt,
+ style = style
+ })
+ })
+end
+local logo = svg({
+ class = 'sun',
+ viewBox = '0 0 1 1',
+ xmlns = 'http://www.w3.org/2000/svg',
+ baseProfile = 'full',
+ version = '1.1',
+ g({
+ transform = 'translate(0.5, 0.52)',
+ g({
+ class = 'circle out',
+ path({
+ fill = 'none',
+ ['stroke-width'] = 0.053,
+ d = 'M 0.5 0.15625 C 0.44839986 0.15625 0.22697194 0.28343797 0.20117188 0.328125 C 0.17537181 0.37281203 0.1753718 0.62718797 0.20117188 0.671875 C 0.22697195 0.71656203 0.44839986 0.84375 0.5 0.84375 C 0.55160014 0.84375 0.77302806 0.71656203 0.79882812 0.671875 C 0.82462819 0.62718797 0.8246282 0.37281203 0.79882812 0.328125 C 0.77302805 0.28343797 0.55160014 0.15625 0.5 0.15625 z',
+ transform = 'translate(-0.5, -0.5)'
+ })
+ }),
+ g({
+ class = 'circle in',
+ path({
+ stroke = 'none',
+ d = 'M 0.50195312 0.38476562 C 0.4851293 0.38476563 0.41466191 0.42683639 0.40625 0.44140625 C 0.39783809 0.45597611 0.39783809 0.53816452 0.40625 0.55273438 C 0.41466191 0.56730423 0.4851293 0.609375 0.50195312 0.609375 C 0.51877695 0.609375 0.59119746 0.56730423 0.59960938 0.55273438 C 0.60802129 0.53816452 0.60802129 0.45597611 0.59960938 0.44140625 C 0.59119746 0.42683639 0.51877695 0.38476562 0.50195312 0.38476562 z',
+ transform = 'translate(-0.5, -0.5)'
+ })
+ })
+ })
+})
+local gen_header
+gen_header = function(self)
+ return header({
+ div({
+ h1({
+ navigate_to('', logo),
+ span({
+ span('kb', {
+ class = 'bold'
+ }),
+ '&#8203;',
+ '.s&#8209;ol.nu'
+ })
+ }),
+ "low-profile hexagon keyboards."
+ })
+ })
+end
+footer = footer({
+ span({
+ 'made with \xe2\x98\xbd by ',
+ a('s-ol', {
+ href = 'https://s-ol.nu'
+ }),
+ ", " .. tostring(os.date('%Y'))
+ }),
+ div({
+ class = 'icons',
+ iconlink('https://github.com/s-ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg', 'github'),
+ iconlink('https://merveilles.town/@s_ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/mastodon.svg', 'mastodon'),
+ iconlink('https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg', 'twitter')
+ })
+})
+local get_header_tags
+get_header_tags = function(self)
+ local title = (self:get('title: text/plain')) or self:gett('name: alpha')
+ local l
+ l = function(str)
+ str = str:gsub('[%s\n]+$', '')
+ return str:gsub('\n', ' ')
+ end
+ local e
+ e = function(str)
+ return string.format('%q', l(str))
+ end
+ local meta = "\n <meta charset=\"UTF-8\">\n <title>" .. tostring(l(title)) .. "</title>\n "
+ do
+ local page_meta = self:get('_meta: mmm/dom')
+ if page_meta then
+ meta = meta .. page_meta
+ else
+ meta = meta .. "\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\n <meta property=\"og:title\" content=" .. tostring(e(title)) .. " />\n <meta property=\"og:type\" content=\"website\" />\n <meta property=\"og:url\" content=\"https://kb.s-ol.nu" .. tostring(self.path) .. "/\" />\n <meta property=\"og:site_name\" content=\"mmm\" />"
+ do
+ local desc = self:get('description: text/plain')
+ if desc then
+ meta = meta .. "\n <meta property=\"og:description\" content=" .. tostring(e(desc)) .. " />"
+ end
+ end
+ end
+ end
+ return meta
+end
+local get_scripts
+get_scripts = function(self)
+ local scripts = ''
+ for plugin in get_plugins(self) do
+ do
+ local snippet = plugin:get('scripts: text/html+frag')
+ if snippet then
+ scripts = scripts .. snippet
+ end
+ end
+ end
+ return scripts
+end
+local render
+render = function(content, fileder, opts)
+ if opts == nil then
+ opts = { }
+ end
+ opts.meta = opts.meta or get_header_tags(fileder)
+ opts.scripts = opts.scripts or ''
+ if not (opts.noview) then
+ content = [[ <div class="view main">
+ <div class="content">
+ ]] .. content .. [[ </div>
+ </div>
+ ]]
+ end
+ local buf = [[<!DOCTYPE html>
+<html>
+ <head>]]
+ buf = buf .. (function()
+ if STATIC then
+ return STATIC.style
+ else
+ return "<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/style/:text/css\" />"
+ end
+ end)()
+ buf = buf .. [[<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400,600" />]]
+ buf = buf .. "\n " .. tostring(opts.meta) .. "\n " .. tostring(get_scripts(fileder)) .. "\n </head>\n <body>\n " .. tostring(gen_header(fileder)) .. "\n\n " .. tostring(content) .. "\n\n " .. tostring(footer)
+ buf = buf .. (function()
+ if STATIC then
+ return ''
+ else
+ return [[ <script type="text/javascript" src="/static/highlight-pack/:text/javascript"></script>
+ <script type="text/javascript">hljs.initHighlighting()</script>]]
+ end
+ end)()
+ buf = buf .. opts.scripts
+ if STATIC then
+ buf = buf .. STATIC.scripts
+ end
+ buf = buf .. "\n </body>\n</html>"
+ return buf
+end
+return {
+ {
+ inp = 'mmm/dom',
+ out = 'text/html',
+ cost = 3,
+ transform = function(self, html, fileder)
+ return render(html, fileder)
+ end
+ },
+ {
+ inp = 'mmm/dom%+noview',
+ out = 'text/html',
+ cost = 3,
+ transform = function(self, html, fileder)
+ return render(html, fileder, {
+ noview = true
+ })
+ end
+ }
+}
diff --git a/$mmm/plugins/layout/converts: text$moonscript -> table.moon b/$mmm/plugins/layout/converts: text$moonscript -> table.moon
new file mode 100644
index 0000000..cde34a4
--- /dev/null
+++ b/$mmm/plugins/layout/converts: text$moonscript -> table.moon
@@ -0,0 +1,164 @@
+import header, aside, footer, nav, div, svg, script, g, path, ul, li, h1, span, b, a, img from require 'mmm.dom'
+import navigate_to from (require 'mmm.mmmfs.util') require 'mmm.dom'
+import get_plugins from require 'mmm.mmmfs.meta'
+
+unpack or= table.unpack
+
+pick = (...) ->
+ num = select '#', ...
+ i = math.ceil math.random! * num
+ (select i, ...)
+
+iconlink = (href, src, alt, style) -> a {
+ class: 'iconlink',
+ target: '_blank',
+ rel: 'me',
+ :href,
+ img :src, :alt, :style
+}
+
+logo = svg {
+ class: 'sun'
+ viewBox: '0 0 1 1'
+ xmlns: 'http://www.w3.org/2000/svg'
+ baseProfile: 'full'
+ version: '1.1'
+
+ g {
+ transform: 'translate(0.5, 0.52)'
+ g {
+ class: 'circle out',
+ path fill: 'none', 'stroke-width': 0.053, d: 'M 0.5 0.15625 C 0.44839986 0.15625 0.22697194 0.28343797 0.20117188 0.328125 C 0.17537181 0.37281203 0.1753718 0.62718797 0.20117188 0.671875 C 0.22697195 0.71656203 0.44839986 0.84375 0.5 0.84375 C 0.55160014 0.84375 0.77302806 0.71656203 0.79882812 0.671875 C 0.82462819 0.62718797 0.8246282 0.37281203 0.79882812 0.328125 C 0.77302805 0.28343797 0.55160014 0.15625 0.5 0.15625 z', transform: 'translate(-0.5, -0.5)'
+ }
+
+ g {
+ class: 'circle in',
+ path stroke: 'none', d: 'M 0.50195312 0.38476562 C 0.4851293 0.38476563 0.41466191 0.42683639 0.40625 0.44140625 C 0.39783809 0.45597611 0.39783809 0.53816452 0.40625 0.55273438 C 0.41466191 0.56730423 0.4851293 0.609375 0.50195312 0.609375 C 0.51877695 0.609375 0.59119746 0.56730423 0.59960938 0.55273438 C 0.60802129 0.53816452 0.60802129 0.45597611 0.59960938 0.44140625 C 0.59119746 0.42683639 0.51877695 0.38476562 0.50195312 0.38476562 z', transform: 'translate(-0.5, -0.5)'
+ }
+ }
+}
+
+gen_header = =>
+ header {
+ div {
+ h1 {
+ navigate_to '', logo
+ span {
+ span 'kb', class: 'bold'
+ '&#8203;'
+ '.s&#8209;ol.nu'
+ }
+ }
+ "low-profile hexagon keyboards."
+ },
+ }
+
+footer = footer {
+ span {
+ 'made with \xe2\x98\xbd by '
+ a 's-ol', href: 'https://s-ol.nu'
+ ", #{os.date '%Y'}"
+ }
+ div {
+ class: 'icons',
+ iconlink 'https://github.com/s-ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg', 'github'
+ iconlink 'https://merveilles.town/@s_ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/mastodon.svg', 'mastodon'
+ iconlink 'https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg', 'twitter'
+ }
+}
+
+get_header_tags = =>
+ title = (@get 'title: text/plain') or @gett 'name: alpha'
+
+ l = (str) ->
+ str = str\gsub '[%s\n]+$', ''
+ str\gsub '\n', ' '
+ e = (str) -> string.format '%q', l str
+
+ meta = "
+ <meta charset=\"UTF-8\">
+ <title>#{l title}</title>
+ "
+
+ if page_meta = @get '_meta: mmm/dom'
+ meta ..= page_meta
+ else
+ meta ..= "
+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
+
+ <meta property=\"og:title\" content=#{e title} />
+ <meta property=\"og:type\" content=\"website\" />
+ <meta property=\"og:url\" content=\"https://kb.s-ol.nu#{@path}/\" />
+ <meta property=\"og:site_name\" content=\"mmm\" />"
+
+ if desc = @get 'description: text/plain'
+ meta ..= "
+ <meta property=\"og:description\" content=#{e desc} />"
+
+ meta
+
+get_scripts = =>
+ scripts = ''
+ for plugin in get_plugins @
+ if snippet = plugin\get 'scripts: text/html+frag'
+ scripts ..= snippet
+
+ scripts
+
+render = (content, fileder, opts={}) ->
+ opts.meta or= get_header_tags fileder
+ opts.scripts or= ''
+
+ unless opts.noview
+ content = [[
+ <div class="view main">
+ <div class="content">
+ ]] .. content .. [[
+ </div>
+ </div>
+ ]]
+
+ buf = [[
+<!DOCTYPE html>
+<html>
+ <head>]]
+ buf ..= if STATIC then STATIC.style else "<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/style/:text/css\" />"
+ buf ..= [[<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400,600" />]]
+ buf ..= "
+ #{opts.meta}
+ #{get_scripts fileder}
+ </head>
+ <body>
+ #{gen_header fileder}
+
+ #{content}
+
+ #{footer}"
+ buf ..= if STATIC then '' else [[
+ <script type="text/javascript" src="/static/highlight-pack/:text/javascript"></script>
+ <script type="text/javascript">hljs.initHighlighting()</script>]]
+
+ buf ..= opts.scripts
+ buf ..= STATIC.scripts if STATIC
+ buf ..= "
+ </body>
+</html>"
+
+ buf
+
+{
+ {
+ -- inp: 'text/html%+frag',
+ -- @TODO: this doesn't feel right... maybe mmm/dom has to go?
+ inp: 'mmm/dom',
+ out: 'text/html',
+ cost: 3
+ transform: (html, fileder) => render html, fileder
+ },
+ {
+ inp: 'mmm/dom%+noview',
+ out: 'text/html',
+ cost: 3
+ transform: (html, fileder) => render html, fileder, noview: true
+ }
+}
diff --git a/$mmm/plugins/markdown/converts: text$lua -> table.lua b/$mmm/plugins/markdown/converts: text$lua -> table.lua
new file mode 100644
index 0000000..5d33b62
--- /dev/null
+++ b/$mmm/plugins/markdown/converts: text$lua -> table.lua
@@ -0,0 +1,88 @@
+local markdown
+if MODE == 'SERVER' then
+ local success, discount = pcall(require, 'discount')
+ assert(success, "couldn't require 'discount'")
+ markdown = function(md)
+ local res = assert(discount.compile(md, 'githubtags', 'fencedcode'))
+ return res.body
+ end
+else
+ assert(window and window.marked, "marked.js not found")
+ local o
+ do
+ local mkobj = window:eval("(function () { return {}; })")
+ o = function(tbl)
+ do
+ local obj = mkobj()
+ for k, v in pairs(tbl) do
+ obj[k] = v
+ end
+ return obj
+ end
+ end
+ end
+ local trim
+ trim = function(str)
+ return str:match('^ *(..-) *$')
+ end
+ window.marked:setOptions(o({
+ gfm = true,
+ smartypants = true,
+ langPrefix = 'lang-',
+ highlight = function(self, code, lang)
+ code = trim(code)
+ local result
+ if lang and #lang > 0 then
+ result = window.hljs:highlight(lang, code, true)
+ else
+ result = window.hljs:highlightAuto(code)
+ end
+ return result.value
+ end
+ }))
+ do
+ local _base_0 = window
+ local _fn_0 = _base_0.marked
+ markdown = function(...)
+ return _fn_0(_base_0, ...)
+ end
+ end
+end
+assert(markdown, "no markdown implementation found")
+return {
+ {
+ inp = 'text/markdown',
+ out = 'text/html+frag',
+ cost = 1,
+ transform = function(self, md)
+ return "<div class=\"markdown\">" .. tostring(markdown(md)) .. "</div>"
+ end
+ },
+ {
+ inp = 'text/markdown%+sidenotes',
+ out = 'text/html+frag',
+ cost = 1,
+ transform = function(self, md)
+ return "<div class=\"markdown sidenote-container\">" .. tostring(markdown(md)) .. "</div>"
+ end
+ },
+ {
+ inp = 'text/markdown%+wide',
+ out = 'text/html+frag',
+ cost = 1,
+ transform = function(self, md)
+ return "<div class=\"markdown wide\">" .. tostring(markdown(md)) .. "</div>"
+ end
+ },
+ {
+ inp = 'text/markdown%+span',
+ out = 'text/html+frag',
+ cost = 1,
+ transform = function(self, source)
+ local html = markdown(source)
+ html = html:gsub('^%s*<p>%s*', '<span>')
+ html = html:gsub('%s*</p>%s*$', '</span>')
+ return html
+ end
+ }
+}
diff --git a/$mmm/plugins/markdown/converts: text$moonscript -> table.moon b/$mmm/plugins/markdown/converts: text$moonscript -> table.moon
new file mode 100644
index 0000000..4e0da31
--- /dev/null
+++ b/$mmm/plugins/markdown/converts: text$moonscript -> table.moon
@@ -0,0 +1,67 @@
+markdown = if MODE == 'SERVER'
+ success, discount = pcall require, 'discount'
+ assert success, "couldn't require 'discount'"
+
+ (md) ->
+ res = assert discount.compile md, 'githubtags', 'fencedcode'
+ res.body
+else
+ assert window and window.marked, "marked.js not found"
+
+ o = do
+ mkobj = window\eval "(function () { return {}; })"
+ (tbl) ->
+ with obj = mkobj!
+ for k,v in pairs(tbl)
+ obj[k] = v
+
+ trim = (str) -> str\match '^ *(..-) *$'
+
+ window.marked\setOptions o {
+ gfm: true
+ smartypants: true
+ langPrefix: 'lang-'
+ highlight: (code, lang) =>
+ code = trim code
+ result = if lang and #lang > 0
+ window.hljs\highlight lang, code, true
+ else
+ window.hljs\highlightAuto code
+
+ result.value
+ }
+
+ window\marked
+
+assert markdown, "no markdown implementation found"
+
+{
+ {
+ inp: 'text/markdown'
+ out: 'text/html+frag'
+ cost: 1
+ transform: (md) => "<div class=\"markdown\">#{markdown md}</div>"
+ }
+ {
+ inp: 'text/markdown%+sidenotes'
+ out: 'text/html+frag'
+ cost: 1
+ transform: (md) => "<div class=\"markdown sidenote-container\">#{markdown md}</div>"
+ }
+ {
+ inp: 'text/markdown%+wide'
+ out: 'text/html+frag'
+ cost: 1
+ transform: (md) => "<div class=\"markdown wide\">#{markdown md}</div>"
+ }
+ {
+ inp: 'text/markdown%+span'
+ out: 'text/html+frag'
+ cost: 1
+ transform: (source) =>
+ html = markdown source
+ html = html\gsub '^%s*<p>%s*', '<span>'
+ html = html\gsub '%s*</p>%s*$', '</span>'
+ html
+ }
+}
diff --git a/$mmm/plugins/markdown/scripts: text$html+frag.html b/$mmm/plugins/markdown/scripts: text$html+frag.html
new file mode 100644
index 0000000..5bfb275
--- /dev/null
+++ b/$mmm/plugins/markdown/scripts: text$html+frag.html
@@ -0,0 +1 @@
+ <script type="text/javascript" src="//unpkg.com/marked@0.7.0/marked.min.js"></script>
diff --git a/$mmm/plugins/moonscript/converts: text$lua -> table.lua b/$mmm/plugins/moonscript/converts: text$lua -> table.lua
new file mode 100644
index 0000000..1ac91b4
--- /dev/null
+++ b/$mmm/plugins/moonscript/converts: text$lua -> table.lua
@@ -0,0 +1,24 @@
+if MODE == 'CLIENT' then
+ return { }
+end
+local _, moon = assert(pcall(require, 'moonscript.base'))
+local _load = moon.load or moon.loadstring
+return {
+ {
+ inp = 'text/moonscript -> (.+)',
+ out = '%1',
+ cost = 1,
+ transform = function(self, val, fileder, key)
+ local func = _load(val, tostring(fileder) .. "#" .. tostring(key))
+ return func()
+ end
+ },
+ {
+ inp = 'text/moonscript -> (.+)',
+ out = 'text/lua -> %1',
+ cost = 2,
+ transform = function(self, val)
+ return moon.to_lua(val)
+ end
+ }
+}
diff --git a/$mmm/plugins/moonscript/converts: text$moonscript -> table.moon b/$mmm/plugins/moonscript/converts: text$moonscript -> table.moon
new file mode 100644
index 0000000..2e5652c
--- /dev/null
+++ b/$mmm/plugins/moonscript/converts: text$moonscript -> table.moon
@@ -0,0 +1,22 @@
+if MODE == 'CLIENT'
+ return {}
+
+_, moon = assert pcall require, 'moonscript.base'
+_load = moon.load or moon.loadstring
+
+{
+ {
+ inp: 'text/moonscript -> (.+)',
+ out: '%1',
+ cost: 1
+ transform: (val, fileder, key) =>
+ func = _load val, "#{fileder}##{key}"
+ func!
+ },
+ {
+ inp: 'text/moonscript -> (.+)',
+ out: 'text/lua -> %1',
+ cost: 2
+ transform: (val) => moon.to_lua val
+ },
+}
diff --git a/$mmm/plugins/sass/converts: text$lua -> table.lua b/$mmm/plugins/sass/converts: text$lua -> table.lua
new file mode 100644
index 0000000..f2887e3
--- /dev/null
+++ b/$mmm/plugins/sass/converts: text$lua -> table.lua
@@ -0,0 +1,54 @@
+if MODE == 'CLIENT' then
+ return { }
+end
+local posix = require('posix')
+return {
+ {
+ inp = 'text/x-scss',
+ out = 'text/css',
+ cost = 1,
+ transform = function(self, content)
+ local r0, w0 = posix.pipe()
+ local r1, w1 = posix.pipe()
+ local r2, w2 = posix.pipe()
+ local pid = assert(posix.fork())
+ if pid == 0 then
+ posix.close(w0)
+ posix.close(r1)
+ posix.close(r2)
+ posix.dup2(r0, posix.fileno(io.stdin))
+ posix.dup2(w1, posix.fileno(io.stdout))
+ posix.dup2(w2, posix.fileno(io.stderr))
+ posix.close(r0)
+ posix.close(w1)
+ posix.close(w2)
+ local err = assert(posix.execp('sassc', '-s'))
+ posix._exit(err)
+ return
+ else
+ posix.close(r0)
+ posix.close(w1)
+ posix.close(w2)
+ posix.write(w0, content)
+ posix.close(w0)
+ local _, status
+ _, _, status = posix.wait(pid)
+ local out
+ if status == 0 then
+ out = r1
+ else
+ out = r2
+ end
+ out = assert(posix.fdopen(out, 'r'))
+ out = out:read('a')
+ posix.close(r1)
+ posix.close(r2)
+ if status == 0 then
+ return out
+ else
+ return error(out)
+ end
+ end
+ end
+ }
+}
diff --git a/$mmm/plugins/sass/converts: text$moonscript -> table.moon b/$mmm/plugins/sass/converts: text$moonscript -> table.moon
new file mode 100644
index 0000000..e353c53
--- /dev/null
+++ b/$mmm/plugins/sass/converts: text$moonscript -> table.moon
@@ -0,0 +1,55 @@
+if MODE == 'CLIENT'
+ return {}
+
+posix = require 'posix'
+
+{
+ {
+ inp: 'text/x-scss'
+ out: 'text/css'
+ cost: 1
+ transform: (content) =>
+ r0, w0 = posix.pipe!
+ r1, w1 = posix.pipe!
+ r2, w2 = posix.pipe!
+
+ pid = assert posix.fork!
+ if pid == 0
+ posix.close w0
+ posix.close r1
+ posix.close r2
+
+ posix.dup2 r0, posix.fileno io.stdin
+ posix.dup2 w1, posix.fileno io.stdout
+ posix.dup2 w2, posix.fileno io.stderr
+
+ posix.close r0
+ posix.close w1
+ posix.close w2
+
+ err = assert posix.execp 'sassc', '-s'
+ posix._exit err
+ return
+ else
+ posix.close r0
+ posix.close w1
+ posix.close w2
+
+ posix.write w0, content
+ posix.close w0
+
+ _, _, status = posix.wait pid
+
+ out = if status == 0 then r1 else r2
+ out = assert posix.fdopen out, 'r'
+ out = out\read 'a'
+
+ posix.close r1
+ posix.close r2
+
+ if status == 0
+ out
+ else
+ error out
+ }
+}
diff --git a/$mmm/plugins/youtube/converts: text$lua -> table.lua b/$mmm/plugins/youtube/converts: text$lua -> table.lua
new file mode 100644
index 0000000..de5b8a8
--- /dev/null
+++ b/$mmm/plugins/youtube/converts: text$lua -> table.lua
@@ -0,0 +1,24 @@
+local iframe
+iframe = require('mmm.dom').iframe
+return {
+ {
+ inp = 'URL -> youtube/video',
+ out = 'mmm/dom',
+ cost = -4,
+ transform = function(self, link)
+ local id = link:match('youtu%.be/([^/]+)')
+ id = id or link:match('youtube.com/watch.*[?&]v=([^&]+)')
+ id = id or link:match('youtube.com/[ev]/([^/]+)')
+ id = id or link:match('youtube.com/embed/([^/]+)')
+ assert(id, "couldn't parse youtube URL: '" .. tostring(link) .. "'")
+ return iframe({
+ width = 560,
+ height = 315,
+ border = 0,
+ frameborder = 0,
+ allowfullscreen = true,
+ src = "//www.youtube.com/embed/" .. tostring(id)
+ })
+ end
+ }
+}
diff --git a/$mmm/plugins/youtube/converts: text$moonscript -> table.moon b/$mmm/plugins/youtube/converts: text$moonscript -> table.moon
new file mode 100644
index 0000000..8983730
--- /dev/null
+++ b/$mmm/plugins/youtube/converts: text$moonscript -> table.moon
@@ -0,0 +1,25 @@
+import iframe from require 'mmm.dom'
+
+{
+ {
+ inp: 'URL -> youtube/video'
+ out: 'mmm/dom'
+ cost: -4
+ transform: (link) =>
+ id = link\match 'youtu%.be/([^/]+)'
+ id or= link\match 'youtube.com/watch.*[?&]v=([^&]+)'
+ id or= link\match 'youtube.com/[ev]/([^/]+)'
+ id or= link\match 'youtube.com/embed/([^/]+)'
+
+ assert id, "couldn't parse youtube URL: '#{link}'"
+
+ iframe {
+ width: 560
+ height: 315
+ border: 0
+ frameborder: 0
+ allowfullscreen: true
+ src: "//www.youtube.com/embed/#{id}"
+ }
+ }
+}