lua generator
This commit is contained in:
parent
b931ab0070
commit
c5fe6f2833
|
@ -0,0 +1,488 @@
|
|||
meta = {
|
||||
domain = "compudanzas.net",
|
||||
title = "compudanzas",
|
||||
description = "explorations of computing at a human scale",
|
||||
fecha = os.date("%Y-%m-%d")
|
||||
}
|
||||
|
||||
webdir = "webtest" -- web output directory
|
||||
gemdir = "gemtest" -- gemini output directory
|
||||
templates = {
|
||||
webEn = {
|
||||
header = { path = "pageheader.html", template = ""},
|
||||
footer = { path = "pagefooter.html", template = ""},
|
||||
incoming = { path = "pageincoming.html", template = ""}
|
||||
},
|
||||
gemEn = {
|
||||
header = { path = "pageheader.gmi", template = ""},
|
||||
footer = { path = "pagefooter.gmi", template = ""},
|
||||
incoming = { path = "pageincoming.gmi", template = ""}
|
||||
},
|
||||
}
|
||||
|
||||
pages = {}
|
||||
|
||||
function slugify( s )
|
||||
return (string.gsub( s, "%s", "_" ))
|
||||
end
|
||||
|
||||
function spacify( s ) -- opposite of slugify (?)
|
||||
return (string.gsub( s, "_", " "))
|
||||
end
|
||||
|
||||
function fillTemplate( template, pagemeta )
|
||||
return ( string.gsub( template, "({.-})", function (key)
|
||||
local var = string.sub(key,2,-2) -- remove { }
|
||||
return meta[var] or pagemeta[var]
|
||||
end) )
|
||||
end
|
||||
|
||||
function getHeader( line ) -- returns title, level
|
||||
local head, title = string.match(line,"^(#+)%s*(.-)$")
|
||||
return title, #head
|
||||
end
|
||||
|
||||
function getLink( line ) -- returns dest, text
|
||||
return string.match( line, "^=>%s*(%S-)%s+(.-)$")
|
||||
end
|
||||
|
||||
function isImagePath( text )
|
||||
return text:match(".jpg$") or text:match(".gif$") or text:match(".png$")
|
||||
end
|
||||
|
||||
function sanitize( line ) -- replace relevant html entities
|
||||
return line:gsub("<","<"):gsub(">",">")
|
||||
end
|
||||
|
||||
function closeTags()
|
||||
local close = ""
|
||||
if flags.list then
|
||||
close = "</ul>\n"
|
||||
flags.list = false
|
||||
elseif flags.p then
|
||||
close = "</p>\n"
|
||||
flags.p = false
|
||||
elseif flags.gallery then
|
||||
close = "</gallery>\n"
|
||||
flags.gallery = false
|
||||
end
|
||||
|
||||
return close
|
||||
end
|
||||
|
||||
function insertIncoming( pagename, incomingname )
|
||||
if incomingname == "pages" then return false end
|
||||
|
||||
local incoming = pages[pagename].incoming
|
||||
for i = 1, #incoming do
|
||||
if incoming[i] == incomingname then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
table.insert( incoming, incomingname)
|
||||
return true
|
||||
end
|
||||
|
||||
function firstPass()
|
||||
-- load templates
|
||||
for _,t in pairs(templates) do
|
||||
-- read templates
|
||||
for k,subtemp in pairs( t ) do
|
||||
local f = assert(io.open(string.format("templates/%s",subtemp.path),"r"))
|
||||
subtemp.template = f:read("a")
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
|
||||
-- for each page:
|
||||
-- convert gmo to gmi and html
|
||||
-- and calculate incoming links
|
||||
for name,page in pairs(pages) do
|
||||
local pagemeta = pages[name]
|
||||
|
||||
local gmopath = string.format("src/%s.gmo", pagemeta.slug)
|
||||
|
||||
-- open file
|
||||
local f = assert( io.open(gmopath, "r") )
|
||||
|
||||
-- initialize flags
|
||||
flags = { list = false, pre = false , p = false, gallery = false }
|
||||
|
||||
-- table to store the lines to write to file
|
||||
local lines = { web = {}, gem = {} }
|
||||
|
||||
-- convert one line at a time
|
||||
local count = 1
|
||||
for line in f:lines() do
|
||||
-- the output line:
|
||||
local out = { gem = line, web = nil}
|
||||
|
||||
if count == 1 then -- extract title
|
||||
pagemeta.ptitle = string.match(line, "^#+%s*(.-)$")
|
||||
elseif count == 2 then -- language
|
||||
if line == "" then
|
||||
pagemeta.lang = "en,es-MX" -- default
|
||||
else
|
||||
pagemeta.lang, pagemeta.trlang, pagemeta.trname = string.match("^lang=(.-)%s(.-)->(.-)$")
|
||||
end
|
||||
elseif count == 3 then -- obtain page description
|
||||
pagemeta.pdescription,n = string.gsub(line,"[{}]","")
|
||||
end
|
||||
|
||||
if count <=2 then goto nextline end -- skip normal processing for the first lines
|
||||
|
||||
-- CONVERT LINES
|
||||
if string.match( line, "^```") then -- preformated
|
||||
if flags.pre then
|
||||
out.web = "</pre>"
|
||||
else
|
||||
out.web = "<pre>"
|
||||
end
|
||||
flags.pre = not flags.pre
|
||||
goto insert -- skip more checks
|
||||
end
|
||||
|
||||
if flags.pre then
|
||||
out.web = sanitize( line )
|
||||
goto insert
|
||||
end
|
||||
|
||||
if string.match( line, "^%+") then -- + append html
|
||||
out.gem = nil
|
||||
out.web = string.sub(line,3) -- remove "+ "
|
||||
|
||||
elseif string.match( line, "^&") then -- & append gemtext
|
||||
out.gem = string.sub(line,3) -- remove "& "
|
||||
|
||||
elseif string.match( line, "^$") then -- empty line
|
||||
out.web = closeTags()
|
||||
|
||||
elseif string.match( line, "^#+") then -- HEADERS
|
||||
-- TODO create nav
|
||||
local title, level = getHeader( line )
|
||||
|
||||
local close = closeTags()
|
||||
out.web = string.format("%s<h%d>%s</h%d>",close,level,title,level)
|
||||
|
||||
elseif string.match( line, "^>") then -- BLOCKQUOTE
|
||||
local close = closeTags()
|
||||
out.web = string.format("%s<blockquote>%s</blockquote>", close, string.sub(line,3))
|
||||
|
||||
elseif string.match( line, "^%*") then -- LIST ITEMS
|
||||
local li = string.format("<li>%s</li>", string.sub(line,3)) -- remove "* "
|
||||
if not flags.list then -- start list
|
||||
out.web = string.format("<ul>\n%s", li)
|
||||
flags.list = true
|
||||
else -- append list element
|
||||
out.web = li
|
||||
end
|
||||
|
||||
elseif string.match( line, "^=>") then -- LINKS
|
||||
local dest, text = getLink( line )
|
||||
if string.match( dest, "^%./") then --local links
|
||||
local t = string.match( text, "^{(.-)}$" )
|
||||
if t ~= nil then -- wikilink
|
||||
local close = closeTags()
|
||||
out.web = string.format("%s<p><a href='%s' class='arrow'>%s</a></p>",close,dest,t)
|
||||
|
||||
elseif isImagePath( dest ) then -- images
|
||||
local img = string.format('<img src="%s" alt="%s" loading="lazy"/>',dest,text)
|
||||
if not flags.gallery then
|
||||
local close = closeTags()
|
||||
out.web = string.format("%s<gallery>\n%s", close, img)
|
||||
flags.gallery = true
|
||||
else
|
||||
out.web = img
|
||||
end
|
||||
|
||||
else -- other files
|
||||
local close = closeTags()
|
||||
out.web = string.format("%s<p><a href='%s'>%s</a></p>",close,dest,text)
|
||||
end
|
||||
|
||||
else -- external links
|
||||
out.web = string.format('<p><a href="%s" rel="external noreferrer noopener" target=_blank class="arrow">%s</a></p>', dest, text)
|
||||
end
|
||||
|
||||
else -- PARAGRAPHS
|
||||
-- web
|
||||
-- search and replace wikilinks
|
||||
local webline = string.gsub( line, "{(.-)}", function (wikiname)
|
||||
return string.format("<a href='./%s.html'>%s</a>", pages[wikiname].slug, wikiname)
|
||||
end)
|
||||
if not flags.p then
|
||||
out.web = string.format("<p>%s", webline)
|
||||
flags.p = true
|
||||
else
|
||||
out.web = string.format("<br/>\n%s",webline)
|
||||
end
|
||||
|
||||
-- gem
|
||||
local gemlinks = {}
|
||||
local gemline = string.gsub( line, "{(.-)}", function (wikiname)
|
||||
table.insert(gemlinks, string.format("=> ./%s.gmi %s",pages[wikiname].slug, wikiname))
|
||||
return wikiname
|
||||
end)
|
||||
|
||||
out.gem = gemline
|
||||
-- append links if there were any
|
||||
if #gemlinks > 0 then
|
||||
out.gem = out.gem.."\n"..table.concat(gemlinks,"\n")
|
||||
end
|
||||
end -- paragraphs
|
||||
|
||||
::insert:: -- insert line in table
|
||||
for k,l in pairs(out) do
|
||||
if l ~= nil then
|
||||
table.insert( lines[k], l )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- skip incoming links calculation if <pre> mode
|
||||
if flags.pre then goto nextline end
|
||||
|
||||
-- calculate incoming links from outgoing
|
||||
for outname in string.gmatch( line, "{([^ ]?.-[^ ]?)}" ) do
|
||||
insertIncoming( outname, name )
|
||||
end
|
||||
|
||||
::nextline::
|
||||
count = count + 1
|
||||
end -- end for line in f:lines()
|
||||
|
||||
-- finalize html
|
||||
local close = closeTags()
|
||||
if isPre then
|
||||
table.insert( lines.web, "</pre>" )
|
||||
elseif close~="" then
|
||||
table.insert( lines.web, close )
|
||||
end
|
||||
|
||||
-- set templates
|
||||
pagemeta.outs.web.templates = templates.webEn
|
||||
pagemeta.outs.gem.templates = templates.gemEn
|
||||
|
||||
-- fill templates and write results
|
||||
for key, out in pairs(pagemeta.outs) do
|
||||
local fo = assert( io.open( out.path, "w" ) )
|
||||
fo:write( fillTemplate(out.templates.header.template, pagemeta) )
|
||||
fo:write( table.concat( lines[key],"\n" )) -- content
|
||||
fo:write( "\n" )
|
||||
fo:close()
|
||||
end
|
||||
|
||||
-- close source file
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
|
||||
function secondPass() -- write incoming links and footer
|
||||
|
||||
for name,page in pairs(pages) do
|
||||
local pagemeta = page
|
||||
|
||||
local doIncoming = true
|
||||
if #pagemeta.incoming > 0 then
|
||||
local gemlines = {}
|
||||
local weblines = { "<p>" }
|
||||
|
||||
-- format list of incoming links
|
||||
for i = 1, #pagemeta.incoming do
|
||||
name = pagemeta.incoming[i]
|
||||
slug = pages[name].slug
|
||||
table.insert( gemlines, string.format("=> ./%s.gmi %s",slug,name) )
|
||||
table.insert( weblines, string.format("<a href='./%s.html'>%s</a> ",slug,name) )
|
||||
end
|
||||
|
||||
table.insert(weblines,"</p>")
|
||||
|
||||
page.gemincoming = table.concat( gemlines, "\n" )
|
||||
page.webincoming = table.concat( weblines )
|
||||
|
||||
else
|
||||
doIncoming = false
|
||||
print( string.format("{%s} is an orphan!", name) )
|
||||
end
|
||||
|
||||
-- fill incoming and footer templates and write results
|
||||
for key, out in pairs(pagemeta.outs) do
|
||||
local fo = assert( io.open( out.path, "a" ) )
|
||||
if doIncoming then
|
||||
fo:write( fillTemplate(out.templates.incoming.template, pagemeta) )
|
||||
end
|
||||
fo:write( fillTemplate(out.templates.footer.template, pagemeta) )
|
||||
fo:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function initPageMetadata( name ) -- return a table with metadata
|
||||
local meta = {
|
||||
incoming = {},
|
||||
slug = slugify(name), name = name,
|
||||
ptitle = "", pdescription = "",
|
||||
updatedate = "",
|
||||
navcontent = "",
|
||||
gemincoming = "", webincoming = "",
|
||||
}
|
||||
meta.outs = {
|
||||
web = { path = string.format("%s/%s.html", webdir, meta.slug) },
|
||||
gem = { path = string.format("%s/%s.gmi", gemdir, meta.slug) }
|
||||
}
|
||||
-- get update date for file
|
||||
local stat = io.popen(string.format("stat -c %%y src/%s.gmo", meta.slug),"r")
|
||||
local dat = stat:read("l")
|
||||
stat:close()
|
||||
meta.updatedate = string.sub(dat, 1, 10) -- YYYY-MM-DD
|
||||
return meta
|
||||
end
|
||||
|
||||
function genIndex()
|
||||
local indexpath = "src/pages.gmo"
|
||||
|
||||
-- initialize and open index file
|
||||
os.execute(string.format("cp templates/index.gmi %s",indexpath))
|
||||
local index = assert( io.open(indexpath,"a" ) )
|
||||
|
||||
-- get gmo files in chronological order
|
||||
local gmofiles = io.popen("ls -t src/*gmo")
|
||||
for filename in gmofiles:lines() do
|
||||
local basename = string.sub(filename, 5, -5) -- remove src/ and .gmo
|
||||
local name = spacify(basename)
|
||||
-- create an entry for each file
|
||||
local entry = string.format("=> ./%s.gmi {%s}\n", basename, name)
|
||||
index:write(entry)
|
||||
|
||||
-- also initialize each name in the pages table
|
||||
-- initialize page metadata
|
||||
pages[ name ] = initPageMetadata( name )
|
||||
|
||||
end
|
||||
gmofiles:close()
|
||||
index:close()
|
||||
end
|
||||
|
||||
function genLog()
|
||||
-- generate the following log files:
|
||||
-- * twtxt gemini and web
|
||||
-- * atom feed gemini and web
|
||||
-- * gmo log
|
||||
-- * gmisub
|
||||
|
||||
local logsrc = assert( io.open( "src/log.txt", "r" ) )
|
||||
|
||||
local logs = {
|
||||
gemtw = { path = string.format("%s/tw.txt",gemdir), head="templates/twheader.txt" },
|
||||
webtw = { path = string.format("%s/tw.txt",webdir), head="templates/twheader.txt" },
|
||||
gmolog = { path = "src/log.gmo", head="templates/logheader.gmi" },
|
||||
gematom = { path = string.format("%s/atom.xml",gemdir), head="templates/gematomheader.txt" },
|
||||
webatom = { path = string.format("%s/atom.xml",webdir), head="templates/webatomheader.txt" },
|
||||
gemfeed = { path = string.format("%s/feed.gmi",gemdir), head="templates/feedheader.gmi" }
|
||||
}
|
||||
|
||||
-- create and open logs
|
||||
for _,log in pairs(logs) do
|
||||
os.execute(string.format("cp %s %s",log.head,log.path))
|
||||
log.f = assert( io.open( log.path, "a" ) )
|
||||
end
|
||||
|
||||
logs.gematom.f:write(string.format("<updated>%sT12:00:00Z</updated>\n",fecha))
|
||||
logs.webatom.f:write(string.format("<updated>%sT12:00:00Z</updated>\n",fecha))
|
||||
|
||||
|
||||
-- process each line of log.txt
|
||||
for line in logsrc:lines() do
|
||||
local pattern = "^(.-)%s(.-)%s{(.-)}$"
|
||||
local timestamp, text, wikilink = string.match(line,pattern)
|
||||
local slug = slugify(wikilink)
|
||||
local date = string.sub(timestamp,1,10) -- YYYY-MM-DD
|
||||
|
||||
-- gmo log
|
||||
local gmoformat = "## %s\n%s\n=> ./%s.gmi {%s}\n\n"
|
||||
logs.gmolog.f:write(string.format(gmoformat, date, text, slug, wikilink))
|
||||
|
||||
-- twtxt
|
||||
local weburl = string.format("https://%s/%s.html",domain,slug)
|
||||
local gemurl = string.format("gemini://%s/%s.gmi",domain,slug)
|
||||
local twtxtformat = "%s\t%s | %s\n"
|
||||
logs.webtw.f:write(string.format(twtxtformat, timestamp, text, weburl))
|
||||
logs.gemtw.f:write(string.format(twtxtformat, timestamp, text, gemurl))
|
||||
|
||||
-- atom
|
||||
local weburldate = string.format("https://%s/%s.html#%s",domain,slug,date)
|
||||
local atomformat = [[
|
||||
|
||||
<entry>
|
||||
<title>%s</title>
|
||||
<updated>%s</updated>
|
||||
<link rel='alternate' href='%s'/>
|
||||
<id>%s</id>
|
||||
</entry>
|
||||
]]
|
||||
logs.webatom.f:write(string.format(atomformat, text, timestamp, weburldate, weburldate))
|
||||
logs.gematom.f:write(string.format(atomformat, text, timestamp, gemurl, gemurl))
|
||||
end
|
||||
|
||||
|
||||
--close logs
|
||||
logs.webatom.f:write("</feed>\n")
|
||||
logs.gematom.f:write("</feed>\n")
|
||||
for _,log in pairs(logs) do
|
||||
log.f:close()
|
||||
end
|
||||
|
||||
logsrc:close()
|
||||
end
|
||||
|
||||
|
||||
-- THE SCRIPT
|
||||
|
||||
-- create directories
|
||||
os.execute(string.format("mkdir -p %s/static %s/img %s/img tmp",webdir,webdir,gemdir))
|
||||
|
||||
print(meta.fecha)
|
||||
|
||||
-- clean up
|
||||
print("limpiando archivos previos...")
|
||||
os.execute(string.format("find %s -iname *.html -exec rm {} \\;", webdir))
|
||||
os.execute(string.format("find %s -iname *.gmi -exec rm {} \\;", gemdir))
|
||||
os.execute("find tmp -iname *.gmo -exec rm {} \\;")
|
||||
|
||||
-- copy images
|
||||
print("copiando imágenes y otros archivos...")
|
||||
local imgs = io.popen("ls src/img/")
|
||||
for img in imgs:lines() do
|
||||
os.execute(string.format("cp -vu src/img/%s %s/img/", img, webdir))
|
||||
os.execute(string.format("cp -vu src/img/%s %s/img/", img, gemdir))
|
||||
end
|
||||
imgs:close()
|
||||
|
||||
-- copy stylesheet and misc files
|
||||
os.execute(string.format("cp -vu templates/estilo.css %s/static/",webdir))
|
||||
|
||||
local miscfiles = { "src/llave_sejo.asc" }
|
||||
for k = 1, #miscfiles do
|
||||
os.execute(string.format("cp -vu %s %s/", miscfiles[k], webdir))
|
||||
os.execute(string.format("cp -vu %s %s/", miscfiles[k], gemdir))
|
||||
end
|
||||
|
||||
|
||||
-- generate log files
|
||||
print("generando log...")
|
||||
genLog()
|
||||
|
||||
-- generate index
|
||||
print("generando índice de páginas...")
|
||||
genIndex()
|
||||
|
||||
-- start first pass
|
||||
-- converting from gmo to gmi and html and calculating incoming links
|
||||
print("convirtiendo páginas...")
|
||||
firstPass()
|
||||
-- second pass, write incoming links
|
||||
print("escribiendo incoming links...")
|
||||
secondPass()
|
||||
|
||||
print("listx!")
|
|
@ -0,0 +1,100 @@
|
|||
/* links externos */
|
||||
a[rel^=external]:after{ content: "↗"; }
|
||||
a{
|
||||
color: #857;
|
||||
}
|
||||
a:visited{
|
||||
color: #404;
|
||||
}
|
||||
a.icon{
|
||||
background-color: #fff;
|
||||
}
|
||||
/* gemtext-like format */
|
||||
/* h1:before{ content: "# "; }
|
||||
h2:before{ content: "## "; }
|
||||
h3:before{ content: "### "; }*/
|
||||
a.arrow:before{ content: "⇒ "; }
|
||||
body{
|
||||
color: #100;
|
||||
max-width:36em;
|
||||
margin:0 auto;
|
||||
font-size:18px;
|
||||
padding: 1em;
|
||||
font-family:sans-serif;
|
||||
}
|
||||
|
||||
footer{
|
||||
font-size: x-small;
|
||||
padding-top:2em;
|
||||
}
|
||||
|
||||
footer img{
|
||||
margin:0;
|
||||
}
|
||||
|
||||
pre{
|
||||
background-color: #edd;
|
||||
color: #433;
|
||||
padding:1em;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
blockquote{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
main h1{
|
||||
margin-top: 1.5em;
|
||||
font-size: xx-large;
|
||||
}
|
||||
main h2{
|
||||
font-size: x-large;
|
||||
margin-left:0.3em;
|
||||
}
|
||||
main h3{
|
||||
font-size: larger;
|
||||
margin-left:1em;
|
||||
}
|
||||
|
||||
gallery{
|
||||
display:flex;
|
||||
flex-direction:row;
|
||||
flex-wrap:wrap;
|
||||
justify-content:space-evenly;
|
||||
align-content:center;
|
||||
}
|
||||
img{
|
||||
margin:10px;
|
||||
border-radius:5px;
|
||||
max-width: 320px;
|
||||
}
|
||||
|
||||
nav{ font-size:smaller; }
|
||||
nav li{ padding:0.2em; }
|
||||
main li{ padding:0.5em; }
|
||||
|
||||
table {
|
||||
font-size: smaller;
|
||||
max-width: 90%;
|
||||
border-collapse: collapse;
|
||||
margin: 1em auto;
|
||||
text-align:left;
|
||||
}
|
||||
table th {
|
||||
border-bottom: 1px solid black;
|
||||
padding: 0.1em 1em;
|
||||
}
|
||||
table td {
|
||||
padding: 0.1em 1em;
|
||||
}
|
||||
td.num{
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
/* desktop */
|
||||
@media screen and (min-width: 600px) {
|
||||
nav li{
|
||||
display:inline;
|
||||
}
|
||||
img{ max-width: 100%; }
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
# compudanzas
|
||||
|
||||
our gemsub feed
|
||||
|
||||
see also:
|
||||
=> ./log.gmi log
|
||||
|
||||
# entries
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<feed xmlns='http://www.w3.org/2005/Atom'>
|
||||
|
||||
<id>gemini://compudanzas.net/</id>
|
||||
<title>compudanzas</title>
|
||||
<author><name>sejo</name></author>
|
||||
<generator>genlog</generator>
|
||||
<link href='gemini://compudanzas.net/atom.xml' rel='self'/>
|
||||
<link href='gemini://compudanzas.net/log.gmi' rel='alternate'/>
|
|
@ -0,0 +1,4 @@
|
|||
# index of pages
|
||||
|
||||
most recently modified, above:
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# compudanzas log
|
||||
|
||||
updates of the project
|
||||
|
||||
=> ./tw.txt [twtxt]
|
||||
=> ./atom.xml [atom feed]
|
||||
& => ./feed.gmi [gemsub feed]
|
||||
|
||||
# entries
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
# meta
|
||||
=> ./home.gmi {title}
|
||||
=> ./contact.gmi contact
|
||||
=> https://wiki.p2pfoundation.net/Peer_Production_License text, images, and code are shared with the peer production license
|
|
@ -0,0 +1,15 @@
|
|||
</main>
|
||||
<footer>
|
||||
<p>
|
||||
<a href='https://tildegit.org/sejo/compudanzas/src/branch/main/src/{slug}.gmo' rel='external noreferrer noopener' target=_blank>source file</a> —
|
||||
most recent update:
|
||||
<time datetime='{updatedate}'>1{updatedate}</time> —
|
||||
<a href='gemini://{domain}/{slug}.gmi' rel='external noreferrer noopener' target=_blank>view in gemini://</a>
|
||||
</p>
|
||||
<hr/>
|
||||
<p><a href='./about.html'>about</a> <a href='./contact.html'>contact</a> <a href='./support.html'>support</a></p>
|
||||
<p><a class='icon' href='./home.html' title='compudanzas'><img src='./img/iconocompudanzas_32.png' width=32 height=32 alt='icono de compudanzas'/></a>
|
||||
<a href='https://webring.xxiivv.com/#random' target='_blank' title='webring' class='icon'><img src='./img/icon.black.svg' width='32' height='32' alt='xxiivv webring'/></a></p>
|
||||
<p>texts, images, and code are shared with the <a href='https://wiki.p2pfoundation.net/Peer_Production_License' target=_blank rel='external noreferrer noopener' title='Peer Production License'>peer production license</a></p>
|
||||
</footer>
|
||||
</body>
|
|
@ -0,0 +1,2 @@
|
|||
# {ptitle}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns='http://www.w3.org/1999/xhtml' lang='{lang}'>
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
|
||||
<meta content='initial-scale=1.0' name='viewport'/>
|
||||
<link rel='me' href='https://sunbeam.city/@compudanzas'>
|
||||
<link rel='me' href='https://post.lurk.org/@compudanzas'>
|
||||
<link rel='me' href='https://merveilles.town/@sejo'>
|
||||
<link rel='stylesheet' href='./static/estilo.css'>
|
||||
<link rel='icon' href='./img/iconocompudanzas_16.png' type='image/png' sizes='16x16'>
|
||||
<link rel='icon' href='./img/iconocompudanzas_32.png' type='image/png' sizes='32x32'>
|
||||
<link rel='icon' href='./img/iconocompudanzas_64.png' type='image/png' sizes='64x64'>
|
||||
<meta property='og:type' content='website' />
|
||||
<meta property='og:image' content='https://compudanzas.net/img/iconocompudanzas_128_w.png'>
|
||||
<meta property='og:title' content='{title} — {ptitle}'>
|
||||
<meta property='og:description' content='{pdescription}'>
|
||||
<meta name='description' content='{pdescription}'>
|
||||
<meta property='og:url' content='https://compudanzas.net/{slug}.html'>
|
||||
<title>{title} — {ptitle}</title>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<p><a class='icon' href='./home.html' title='{title}'><img src='./img/iconocompudanzas_32.png' style='margin:0' alt='icono de compudanzas'/></a></p>
|
||||
<h1>{ptitle}</h1>
|
||||
</header>
|
||||
<nav>
|
||||
{navcontent}
|
||||
</nav>
|
||||
<main>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
# incoming links
|
||||
{gemincoming}
|
|
@ -0,0 +1,4 @@
|
|||
<section id='incoming'>
|
||||
<h1>incoming links</h1>
|
||||
{webincoming}
|
||||
</section>
|
|
@ -0,0 +1 @@
|
|||
# nick = compudanzas
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<feed xmlns='http://www.w3.org/2005/Atom'>
|
||||
|
||||
<id>https://compudanzas.net/</id>
|
||||
<title>compudanzas</title>
|
||||
<author><name>sejo</name></author>
|
||||
<generator>genlog</generator>
|
||||
<link href='https://compudanzas.net/atom.xml' rel='self'/>
|
||||
<link href='https://compudanzas.net/log.html' rel='alternate'/>
|
Loading…
Reference in New Issue