diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2019-10-07 17:49:16 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2019-10-07 17:49:16 +0000 |
| commit | ad26c7c4e374f66a978f9946bbb083377f2224a6 (patch) | |
| tree | 7bdee1e299cb2a907294b115b577e14ccbee4986 | |
| parent | add simple HTTP server (diff) | |
| download | mmm-ad26c7c4e374f66a978f9946bbb083377f2224a6.tar.gz mmm-ad26c7c4e374f66a978f9946bbb083377f2224a6.zip | |
allow server to render with layout
| -rw-r--r-- | build/layout.moon | 108 | ||||
| -rw-r--r-- | build/render_all.moon | 71 | ||||
| -rw-r--r-- | build/server.moon | 3 | ||||
| -rw-r--r-- | mmm/mmmfs/conversion.moon | 262 | ||||
| -rw-r--r-- | mmm/mmmfs/converts.moon | 269 | ||||
| -rw-r--r-- | mmm/mmmfs/layout.moon | 166 |
6 files changed, 449 insertions, 430 deletions
diff --git a/build/layout.moon b/build/layout.moon deleted file mode 100644 index 61f93cb..0000000 --- a/build/layout.moon +++ /dev/null @@ -1,108 +0,0 @@ -import header, aside, footer, div, svg, script, g, circle, h1, span, b, a, img from require 'mmm.dom' -import navigate_to from (require 'mmm.mmmfs.util') require 'mmm.dom' - -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.75 -1 1.5 2' - xmlns: 'http://www.w3.org/2000/svg' - baseProfile: 'full' - version: '1.1' - - g { - transform: 'translate(0 .18)' - - g { class: 'circle out', circle r: '.6', fill: 'none', 'stroke-width': '.12' } - g { class: 'circle in', circle r: '.2', stroke: 'none' } - } -} - -{ - header: header { - div { - h1 { - logo - span { - span 'mmm', class: 'bold' - '​' - '.s‑ol.nu' - } - } - span "fun stuff with code and wires" - -- pick 'fun', 'cool', 'weird', 'interesting', 'new' - -- pick 'stuff', 'things', 'projects', 'experiments', 'news' - -- "with" - -- pick 'mostly code', 'code and wires', 'silicon', 'electronics' - } - aside { - navigate_to '/about', 'about me' - navigate_to '/games', 'games' - navigate_to '/projects', 'other' - a { - href: 'mailto:s%20[removethis]%20[at]%20s-ol.nu' - 'contact' - script " - var l = document.currentScript.parentElement; - l.href = l.href.replace('%20[at]%20', '@'); - l.href = l.href.replace('%20[removethis]', '') + '?subject=Hey there :)'; - " - } - } - } - footer: footer { - span { - 'made with \xe2\x98\xbd by ' - a 's-ol', href: 'https://twitter.com/S0lll0s' - ", #{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' - iconlink 'https://webring.xxiivv.com/#random', 'https://webring.xxiivv.com/icon.black.svg', 'webring', - { height: '1.3em', 'margin-left': '.3em', 'margin-top': '-0.12em' } - } - } - get_meta: => - 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://mmm.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 -} diff --git a/build/render_all.moon b/build/render_all.moon index 14e4cce..4fe827b 100644 --- a/build/render_all.moon +++ b/build/render_all.moon @@ -10,73 +10,24 @@ add '?/init.server' require 'mmm' import tohtml from require 'mmm.component' import Browser from require 'mmm.mmmfs.browser' -import get_meta, header, footer from require 'build.layout' +import render from require 'mmm.mmmfs.layout' +import SQLStore from require 'mmm.mmmfs.drivers.sql' +import load_tree from require 'build.util' -- usage: --- moon render_all.moon [db.sqlite3] -{ file } = arg +-- moon render_all.moon [db.sqlite3] [startpath] +{ file, startpath } = arg export BROWSER -render = (fileder, output) -> - BROWSER = Browser fileder - - with io.open output, 'w' - \write [[ - <!DOCTYPE html> - <html> - <head> - <link rel="stylesheet" type="text/css" href="/main.css" /> - <!-- - <link rel="preload" as="fetch" href="/mmm/dom/init.lua" /> - <link rel="preload" as="fetch" href="/mmm/component/init.lua" /> - <link rel="preload" as="fetch" href="/mmm/mmmfs/init.lua" /> - <link rel="preload" as="fetch" href="/mmm/mmmfs/fileder.lua" /> - <link rel="preload" as="fetch" href="/mmm/mmmfs/browser.lua" /> - --> - - <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400" rel="stylesheet"> - ]] - \write " - #{get_meta fileder} - </head> - <body> - #{header} - - #{assert (tohtml BROWSER), "couldn't render BROWSER"} - - #{footer} - " - \write [[ - <script src="/highlight.pack.js"></script> - <script src="//cdnjs.cloudflare.com/ajax/libs/marked/0.5.1/marked.min.js"></script> - <script src="//cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.min.js"></script> - <script src="//platform.twitter.com/widgets.js" charset="utf-8"></script> - <script src="/fengari-web.js"></script> - <script type="application/lua" src="/mmm.bundle.lua"></script> - <script type="application/lua">require 'mmm'</script> - ]] - \write " - <script type=\"application/lua\"> - on_load = on_load or {} - table.insert(on_load, function() - local path = #{string.format '%q', path} - local browser = require 'mmm.mmmfs.browser' - local root = dofile '/$bundle.lua' - root:mount('', true) - - BROWSER = browser.Browser(root, path, true) - end) - </script> - </body> - </html> - " - \close! - - tree = load_tree SQLStore :name +tree = tree\walk startpath if startpath for fileder in coroutine.wrap tree\iterate print "rendering '#{fileder.path}'..." os.execute "mkdir -p 'out/#{fileder.path}'" - render fileder, "out/#{fileder.path}/index.html" + + BROWSER = Browser fileder + with io.open "out/#{fileder.path}/index.html", 'w' + \write render (tohtml BROWSER), fileder + \close! diff --git a/build/server.moon b/build/server.moon index dd491d3..b178636 100644 --- a/build/server.moon +++ b/build/server.moon @@ -82,7 +82,6 @@ class Server path = req\get ':path' path, facet = dir_base path - print "'#{path}', '#{facet}'" facet = if #facet > 0 facet = '' if facet == ':' accept = req\get 'mmm-accept' @@ -95,7 +94,7 @@ class Server res = headers.new! response_type = if status > 299 then 'text/plain' else if facet then facet.type - else 'text/plain' + else 'text/json' res\append ':status', tostring status res\append 'content-type', response_type diff --git a/mmm/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon index f6ca8c0..54cd680 100644 --- a/mmm/mmmfs/conversion.moon +++ b/mmm/mmmfs/conversion.moon @@ -1,263 +1,5 @@ -import div, code, img, video, blockquote, a, span, source, iframe from require 'mmm.dom' -import find_fileder, link_to, embed from (require 'mmm.mmmfs.util') require 'mmm.dom' -import tohtml from require 'mmm.component' - --- fix JS null values -js_fix = if MODE == 'CLIENT' - (arg) -> - return if arg == js.null - arg - --- limit function to one argument -single = (func) -> (val) -> func val - --- load a chunk using a specific 'load'er -loadwith = (_load) -> (val, fileder, key) -> - func = assert _load val, "#{fileder}##{key}" - func! - --- list of converts --- converts each have --- * inp - input type. can capture subtypes using `(.+)` --- * out - output type. can substitute subtypes from inp with %1, %2 etc. --- * transform - function (val: inp, fileder) -> val: out -converts = { - { - inp: 'fn -> (.+)', - out: '%1', - transform: (val, fileder) -> val fileder - }, - { - inp: 'mmm/component', - out: 'mmm/dom', - transform: single tohtml - }, - { - inp: 'mmm/dom', - out: 'text/html', - transform: (node) -> if MODE == 'SERVER' then node else node.outerHTML - }, - { - inp: 'text/html', - out: 'mmm/dom', - transform: if MODE == 'SERVER' - (html, fileder) -> - html = html\gsub '<mmm%-link%s+(.-)>(.-)</mmm%-link>', (attrs, text) -> - text = nil if #text == 0 - path = '' - while attrs and attrs != '' - key, val, _attrs = attrs\match '^(%w+)="([^"]-)"%s*(.*)' - if not key - key, _attrs = attrs\match '^(%w+)%s*(.*)$' - val = true - - attrs = _attrs - - switch key - when 'path' then path = val - else warn "unkown attribute '#{key}=\"#{val}\"' in <mmm-link>" - - link_to path, text, fileder - - html = html\gsub '<mmm%-embed%s+(.-)>(.-)</mmm%-embed>', (attrs, desc) -> - path, facet = '', '' - opts = {} - if #desc != 0 - opts.desc = desc - - while attrs and attrs != '' - key, val, _attrs = attrs\match '^(%w+)="([^"]-)"%s*(.*)' - if not key - key, _attrs = attrs\match '^(%w+)%s*(.*)$' - val = true - - attrs = _attrs - - switch key - when 'path' then path = val - when 'facet' then facet = val - when 'nolink' then opts.nolink = true - when 'inline' then opts.inline = true - else warn "unkown attribute '#{key}=\"#{val}\"' in <mmm-embed>" - - embed path, facet, fileder, opts - - html - else - (html, fileder) -> - parent = with document\createElement 'div' - .innerHTML = html - - -- copy to iterate safely, HTMLCollections update when nodes are GC'ed - embeds = \getElementsByTagName 'mmm-embed' - embeds = [embeds[i] for i=0, embeds.length - 1] - for element in *embeds - path = js_fix element\getAttribute 'path' - facet = js_fix element\getAttribute 'facet' - nolink = js_fix element\getAttribute 'nolink' - inline = js_fix element\getAttribute 'inline' - desc = js_fix element.innerText - - element\replaceWith embed path or '', facet or '', fileder, { :nolink, :inline, :desc } - - embeds = \getElementsByTagName 'mmm-link' - embeds = [embeds[i] for i=0, embeds.length - 1] - for element in *embeds - text = js_fix element.innerText - path = js_fix element\getAttribute 'path' - - element\replaceWith link_to path or '', text, fileder - - assert 1 == parent.childElementCount, "text/html with more than one child!" - parent.firstElementChild - }, - { - inp: 'text/lua -> (.+)', - out: '%1', - transform: loadwith load or loadstring - }, - { - inp: 'mmm/tpl -> (.+)', - out: '%1', - transform: (source, fileder) -> - source\gsub '{{(.-)}}', (expr) -> - path, facet = expr\match '^([%w%-_%./]*)%+(.*)' - assert path, "couldn't match TPL expression '#{expr}'" - - (find_fileder path, fileder)\gett facet - }, - { - inp: 'time/iso8601-date', - out: 'time/unix', - transform: (val) -> - year, _, month, day = val\match '^%s*(%d%d%d%d)(%-?)([01]%d)%2([0-3]%d)%s*$' - assert year, "failed to parse ISO 8601 date: '#{val}'" - os.time :year, :month, :day - }, - { - inp: 'URL -> twitter/tweet', - out: 'mmm/dom', - transform: (href) -> - id = assert (href\match 'twitter.com/[^/]-/status/(%d*)'), "couldn't parse twitter/tweet URL: '#{href}'" - if MODE == 'CLIENT' - with parent = div! - window.twttr.widgets\createTweet id, parent - else - div blockquote { - class: 'twitter-tweet' - 'data-lang': 'en' - a '(linked tweet)', :href - } - }, - { - inp: 'URL -> youtube/video', - out: 'mmm/dom', - 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 - frameborder: 0 - allowfullscreen: true - frameBorder: 0 - src: "//www.youtube.com/embed/#{id}" - } - }, - { - inp: 'URL -> image/.+', - out: 'mmm/dom', - transform: (src, fileder) -> img :src - }, - { - inp: 'URL -> video/.+', - out: 'mmm/dom', - transform: (src) -> - -- @TODO: add parsed MIME type - video (source :src), controls: true, loop: true - }, - { - inp: 'text/plain', - out: 'mmm/dom', - transform: (val) -> span val - }, - { - inp: 'alpha', - out: 'mmm/dom', - transform: single code - }, - { - inp: 'URL -> .*', - out: 'mmm/dom', - transform: single code - }, -} - -if MODE == 'SERVER' - ok, moon = pcall require, 'moonscript.base' - if ok - _load = moon.load or moon.loadstring - table.insert converts, { - inp: 'text/moonscript -> (.+)', - out: '%1', - transform: loadwith moon.load or moon.loadstring - } - - table.insert converts, { - inp: 'text/moonscript -> (.+)', - out: 'text/lua -> %1', - transform: single moon.to_lua - } -else - table.insert converts, { - inp: 'text/javascript -> (.+)', - out: '%1', - transform: (source) -> - f = js.new window.Function, source - f! - } - -do - local markdown - if MODE == 'SERVER' - success, discount = pcall require, 'discount' - if not success - warn "NO MARKDOWN SUPPORT!", discount - - markdown = success and (md) -> - res = assert discount.compile md, 'githubtags' - res.body - else - markdown = window and window.marked and window\marked - - if markdown - table.insert converts, { - inp: 'text/markdown', - out: 'text/html', - transform: (md) -> "<div class=\"markdown\">#{markdown md}</div>" - } - - table.insert converts, { - inp: 'text/markdown%+span', - out: 'mmm/dom', - transform: if MODE == 'SERVER' - (source) -> - html = markdown source - html = html\gsub '^<p', '<span' - html\gsub '/p>$', '/span>' - else - (source) -> - html = markdown source - html = html\gsub '^%s*<p>%s*', '' - html = html\gsub '%s*</p>%s*$', '' - with document\createElement 'span' - .innerHTML = html - } +require = relative ..., 1 +converts = require '.converts' count = (base, pattern='->') -> select 2, base\gsub pattern, '' escape_pattern = (inp) -> "^#{inp\gsub '([-/])', '%%%1'}$" diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon new file mode 100644 index 0000000..f8aad9f --- /dev/null +++ b/mmm/mmmfs/converts.moon @@ -0,0 +1,269 @@ +require = relative ..., 1 +import div, code, img, video, blockquote, a, span, source, iframe from require 'mmm.dom' +import find_fileder, link_to, embed from (require 'mmm.mmmfs.util') require 'mmm.dom' +import render from require '.layout' +import tohtml from require 'mmm.component' + +-- fix JS null values +js_fix = if MODE == 'CLIENT' + (arg) -> + return if arg == js.null + arg + +-- limit function to one argument +single = (func) -> (val) -> func val + +-- load a chunk using a specific 'load'er +loadwith = (_load) -> (val, fileder, key) -> + func = assert _load val, "#{fileder}##{key}" + func! + +-- list of converts +-- converts each have +-- * inp - input type. can capture subtypes using `(.+)` +-- * out - output type. can substitute subtypes from inp with %1, %2 etc. +-- * transform - function (val: inp, fileder) -> val: out +converts = { + { + inp: 'fn -> (.+)', + out: '%1', + transform: (val, fileder) -> val fileder + }, + { + inp: 'mmm/component', + out: 'mmm/dom', + transform: single tohtml + }, + { + inp: 'mmm/dom', + out: 'text/html+frag', + transform: (node) -> if MODE == 'SERVER' then node else node.outerHTML + }, + { + inp: 'text/html%+frag', + out: 'text/html', + transform: (html, fileder) -> render html, fileder + }, + { + inp: 'text/html%+frag', + out: 'mmm/dom', + transform: if MODE == 'SERVER' + (html, fileder) -> + html = html\gsub '<mmm%-link%s+(.-)>(.-)</mmm%-link>', (attrs, text) -> + text = nil if #text == 0 + path = '' + while attrs and attrs != '' + key, val, _attrs = attrs\match '^(%w+)="([^"]-)"%s*(.*)' + if not key + key, _attrs = attrs\match '^(%w+)%s*(.*)$' + val = true + + attrs = _attrs + + switch key + when 'path' then path = val + else warn "unkown attribute '#{key}=\"#{val}\"' in <mmm-link>" + + link_to path, text, fileder + + html = html\gsub '<mmm%-embed%s+(.-)>(.-)</mmm%-embed>', (attrs, desc) -> + path, facet = '', '' + opts = {} + if #desc != 0 + opts.desc = desc + + while attrs and attrs != '' + key, val, _attrs = attrs\match '^(%w+)="([^"]-)"%s*(.*)' + if not key + key, _attrs = attrs\match '^(%w+)%s*(.*)$' + val = true + + attrs = _attrs + + switch key + when 'path' then path = val + when 'facet' then facet = val + when 'nolink' then opts.nolink = true + when 'inline' then opts.inline = true + else warn "unkown attribute '#{key}=\"#{val}\"' in <mmm-embed>" + + embed path, facet, fileder, opts + + html + else + (html, fileder) -> + parent = with document\createElement 'div' + .innerHTML = html + + -- copy to iterate safely, HTMLCollections update when nodes are GC'ed + embeds = \getElementsByTagName 'mmm-embed' + embeds = [embeds[i] for i=0, embeds.length - 1] + for element in *embeds + path = js_fix element\getAttribute 'path' + facet = js_fix element\getAttribute 'facet' + nolink = js_fix element\getAttribute 'nolink' + inline = js_fix element\getAttribute 'inline' + desc = js_fix element.innerText + + element\replaceWith embed path or '', facet or '', fileder, { :nolink, :inline, :desc } + + embeds = \getElementsByTagName 'mmm-link' + embeds = [embeds[i] for i=0, embeds.length - 1] + for element in *embeds + text = js_fix element.innerText + path = js_fix element\getAttribute 'path' + + element\replaceWith link_to path or '', text, fileder + + assert 1 == parent.childElementCount, "text/html with more than one child!" + parent.firstElementChild + }, + { + inp: 'text/lua -> (.+)', + out: '%1', + transform: loadwith load or loadstring + }, + { + inp: 'mmm/tpl -> (.+)', + out: '%1', + transform: (source, fileder) -> + source\gsub '{{(.-)}}', (expr) -> + path, facet = expr\match '^([%w%-_%./]*)%+(.*)' + assert path, "couldn't match TPL expression '#{expr}'" + + (find_fileder path, fileder)\gett facet + }, + { + inp: 'time/iso8601-date', + out: 'time/unix', + transform: (val) -> + year, _, month, day = val\match '^%s*(%d%d%d%d)(%-?)([01]%d)%2([0-3]%d)%s*$' + assert year, "failed to parse ISO 8601 date: '#{val}'" + os.time :year, :month, :day + }, + { + inp: 'URL -> twitter/tweet', + out: 'mmm/dom', + transform: (href) -> + id = assert (href\match 'twitter.com/[^/]-/status/(%d*)'), "couldn't parse twitter/tweet URL: '#{href}'" + if MODE == 'CLIENT' + with parent = div! + window.twttr.widgets\createTweet id, parent + else + div blockquote { + class: 'twitter-tweet' + 'data-lang': 'en' + a '(linked tweet)', :href + } + }, + { + inp: 'URL -> youtube/video', + out: 'mmm/dom', + 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 + frameborder: 0 + allowfullscreen: true + frameBorder: 0 + src: "//www.youtube.com/embed/#{id}" + } + }, + { + inp: 'URL -> image/.+', + out: 'mmm/dom', + transform: (src, fileder) -> img :src + }, + { + inp: 'URL -> video/.+', + out: 'mmm/dom', + transform: (src) -> + -- @TODO: add parsed MIME type + video (source :src), controls: true, loop: true + }, + { + inp: 'text/plain', + out: 'mmm/dom', + transform: (val) -> span val + }, + { + inp: 'alpha', + out: 'mmm/dom', + transform: single code + }, + { + inp: 'URL -> .*', + out: 'mmm/dom', + transform: single code + }, +} + +if MODE == 'SERVER' + ok, moon = pcall require, 'moonscript.base' + if ok + _load = moon.load or moon.loadstring + table.insert converts, { + inp: 'text/moonscript -> (.+)', + out: '%1', + transform: loadwith moon.load or moon.loadstring + } + + table.insert converts, { + inp: 'text/moonscript -> (.+)', + out: 'text/lua -> %1', + transform: single moon.to_lua + } +else + table.insert converts, { + inp: 'text/javascript -> (.+)', + out: '%1', + transform: (source) -> + f = js.new window.Function, source + f! + } + +do + local markdown + if MODE == 'SERVER' + success, discount = pcall require, 'discount' + if not success + warn "NO MARKDOWN SUPPORT!", discount + + markdown = success and (md) -> + res = assert discount.compile md, 'githubtags' + res.body + else + markdown = window and window.marked and window\marked + + if markdown + table.insert converts, { + inp: 'text/markdown', + out: 'text/html+frag', + transform: (md) -> "<div class=\"markdown\">#{markdown md}</div>" + } + + table.insert converts, { + inp: 'text/markdown%+span', + out: 'mmm/dom', + transform: if MODE == 'SERVER' + (source) -> + html = markdown source + html = html\gsub '^<p', '<span' + html\gsub '/p>$', '/span>' + else + (source) -> + html = markdown source + html = html\gsub '^%s*<p>%s*', '' + html = html\gsub '%s*</p>%s*$', '' + with document\createElement 'span' + .innerHTML = html + } + +converts diff --git a/mmm/mmmfs/layout.moon b/mmm/mmmfs/layout.moon new file mode 100644 index 0000000..47e511b --- /dev/null +++ b/mmm/mmmfs/layout.moon @@ -0,0 +1,166 @@ +require = relative ..., 1 +import header, aside, footer, div, svg, script, g, circle, h1, span, b, a, img from require 'mmm.dom' +import navigate_to from (require 'mmm.mmmfs.util') require 'mmm.dom' + +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.75 -1 1.5 2' + xmlns: 'http://www.w3.org/2000/svg' + baseProfile: 'full' + version: '1.1' + + g { + transform: 'translate(0 .18)' + + g { class: 'circle out', circle r: '.6', fill: 'none', 'stroke-width': '.12' } + g { class: 'circle in', circle r: '.2', stroke: 'none' } + } +} + +header = header { + div { + h1 { + logo + span { + span 'mmm', class: 'bold' + '​' + '.s‑ol.nu' + } + } + span "fun stuff with code and wires" + -- pick 'fun', 'cool', 'weird', 'interesting', 'new' + -- pick 'stuff', 'things', 'projects', 'experiments', 'news' + -- "with" + -- pick 'mostly code', 'code and wires', 'silicon', 'electronics' + } + aside { + navigate_to '/about', 'about me' + navigate_to '/games', 'games' + navigate_to '/projects', 'other' + a { + href: 'mailto:s%20[removethis]%20[at]%20s-ol.nu' + 'contact' + script " + var l = document.currentScript.parentElement; + l.href = l.href.replace('%20[at]%20', '@'); + l.href = l.href.replace('%20[removethis]', '') + '?subject=Hey there :)'; + " + } + } +} + +footer = footer { + span { + 'made with \xe2\x98\xbd by ' + a 's-ol', href: 'https://twitter.com/S0lll0s' + ", #{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' + iconlink 'https://webring.xxiivv.com/#random', 'https://webring.xxiivv.com/icon.black.svg', 'webring', + { height: '1.3em', 'margin-left': '.3em', 'margin-top': '-0.12em' } + } +} + +get_meta = => + 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://mmm.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 + +render = (content, fileder) -> + buf = [[ +<!DOCTYPE html> +<html> + <head> + <link rel="stylesheet" type="text/css" href="/main.css" /> + <!-- + <link rel="preload" as="fetch" href="/mmm/dom/init.lua" /> + <link rel="preload" as="fetch" href="/mmm/component/init.lua" /> + <link rel="preload" as="fetch" href="/mmm/mmmfs/init.lua" /> + <link rel="preload" as="fetch" href="/mmm/mmmfs/fileder.lua" /> + <link rel="preload" as="fetch" href="/mmm/mmmfs/browser.lua" /> + --> + + <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400" rel="stylesheet"> + ]] + buf ..= " + #{get_meta fileder} + </head> + <body> + #{header} + + #{content} + + #{footer} + " + buf ..= [[ + <script src="/highlight.pack.js"></script> + <script src="//cdnjs.cloudflare.com/ajax/libs/marked/0.5.1/marked.min.js"></script> + <script src="//cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.min.js"></script> + <script src="//platform.twitter.com/widgets.js" charset="utf-8"></script> + <script src="/fengari-web.js"></script> + <script type="application/lua" src="/mmm.bundle.lua"></script> + <script type="application/lua">require 'mmm'</script> + ]] + buf ..= " + <script type=\"application/lua\"> + on_load = on_load or {} + table.insert(on_load, function() + local path = #{string.format '%q', path} + local browser = require 'mmm.mmmfs.browser' + local root = dofile '/$bundle.lua' + root:mount('', true) + + BROWSER = browser.Browser(root, path, true) + end) + </script> + </body> +</html> + " + + buf + +{ + :render +} |
