local h = require 'html'
local M = {}
local site_sections = {
default = "account",
}
local function navbar(links)
h.nav({class = "site-nav"}, function()
for _, link in ipairs(links) do
h.a({
href = link[2],
class = link[2] == links.selected and "selected" or nil
}, link[1])
h.text " "
end
end)
end
function M.page(param)
return h.render_doc(function()
h.meta {charset = "utf-8"}
h.title(param.title and
param.title .. " — auth.citrons.xyz" or "auth.citrons.xyz")
h.meta {
name = "viewport",
content = "width=device-width, initial-scale=0.75"
}
h.link {rel = "stylesheet", href = "/static/citrine.css"}
h.div({id = "page-grid"}, function()
h.header({class = "site-header"}, function()
param.section = param.section or "default"
h.img({
src = "/static/headers/"..param.section..".png",
alt = site_sections[param.section]
})
end)
h.div({class = "content"}, function()
h.main(param[1])
h.footer({class = "site-footer"}, function()
h.p(function()
h.a({href =
"https://citrons.xyz/git/auth.git/"
}, "© 2023 citrons")
end)
end)
end)
h.div({class = "header-icons"}, function()
h.a({class = "help", href = "/account"}, function()
h.img {
src = "/static/gear.png", alt = "account settings",
class = "help"
}
end)
h.a({class = "help", href = "/"}, function()
h.img {
src = "/static/qmark.png", alt = "about",
class = "help"
}
end)
end)
end)
end)
end
local function class_article(e)
return function(...)
h[e]({class = "article"}, ...)
end
end
M.h1 = class_article "h1"
M.h2 = class_article "h2"
M.h3 = class_article "h3"
M.h4 = class_article "h4"
M.h5 = class_article "h5"
M.h6 = class_article "h6"
function M.quote(quote, attrib)
h.figure({class = attrib and "quote attrib" or "quote"}, function()
h.blockquote(function()
h.p({}, quote)
end)
if attrib then
h.figcaption({}, attrib)
end
end)
end
function M.dyk(content)
h.aside({class = "dyk"}, function()
h.h2 "did you know?"
if type(content) == "string" then
html.p(content)
else
content()
end
end)
end
function M.code_block(content)
h.pre({class = "code-block"}, content)
end
function M.apiobutton()
h.a({href = "https://citrons.xyz/a/memetic-apioform-page",
class="apiopage"}, function()
h.img {src = "https://citrons.xyz/a/static/apiopage.png",
alt = "memetic apiopage: click to view"}
end)
end
function M.redact(s)
h.del({class = "redaction", title = "redacted text"}, function()
h.span({}, s:gsub(utf8.charpattern, function(c)
if c ~= " " then return "X" end
end))
end)
end
function M.errmsg(e)
h.div({class = "errmsg"}, function()
h.p({}, e)
end)
end
local statuses = {
[400] = "400 Bad Request",
[401] = "401 Unauthorized",
[403] = "403 Forbidden",
[404] = "404 Not Found",
[405] = "405 Method Not Allowed",
[410] = "410 Gone",
[411] = "411 Length Required",
[413] = "413 Payload Too Large",
[429] = "429 Too Many Requests",
[500] = "500 Internal Server Error",
[501] = "501 Not Implemented",
[502] = "502 Bad Gateway",
[503] = "503 Service Unavailable",
[504] = "504 Gateway Timeout"
}
local messages = {
[400] = "your software has sent an invalid request to the server.",
[401] = "permission denied.",
[403] = "permission denied.",
[404] = "the page you attempted to access was not found.",
[405] = "your software has sent a request with an invalid method.",
[410] = "this content is no longer available.",
[411] = "your software failed to provide a length for the request body.",
[413] = "your software sent too much data to the server.",
[429] = "you are doing this too often. try again later.",
[500] = "a temporary internal error has occurred. this is my fault.",
[501] = "the requested feature is not implemented.",
}
function M.error(code, message)
return {
content_type = 'text/html', status = statuses[code] or code
}, M.page {
section = "error",
function()
M.h1((statuses[code] or ("error "..code)):lower())
h.p(message or messages[code] or
messages[code // 100 * 100] or "an error has occurred")
end
}
end
return M