diff options
| -rw-r--r-- | about.html | 34 | ||||
| -rw-r--r-- | debug/nginx.conf | 2 | ||||
| -rw-r--r-- | robots.txt | 3 | ||||
| -rw-r--r-- | static/amethyst.css | 59 | ||||
| -rw-r--r-- | static/redirect-demonstration.png | bin | 0 -> 56818 bytes | |||
| -rwxr-xr-x | zzcxz.cgi | 260 |
6 files changed, 288 insertions, 70 deletions
@@ -8,7 +8,7 @@ </head> <body> <h1>about zzcxz</h1> - <h2 id="what is zzcxz">what is zzcxz?</h2> + <h2 id="what-is-zzcxz">what is zzcxz?</h2> <p> zzcxz consists of user generated, fictional content. do not believe what you read, for it is not real and could be written by anyone. </p> @@ -39,7 +39,7 @@ tell the story; do not submit non-sequitur nonsense <li> - maintain continuity between previous events; do not suddenly start telling a completely different story or try to <a href="https://en.wikipedia.org/wiki/Retroactive_continuity">retcon</a> previous events. + maintain continuity between previous events; do not suddenly start telling a completely different story or try to <a href="https://en.wikipedia.org/wiki/Retroactive_continuity">retcon</a> previous events. </ul> <p> @@ -54,7 +54,7 @@ once content is posted, it can only be modified by me (the site administrator). I will fix any obvious typos I find. if you want content edited/removed for other reasons, <a href="mailto:stuff@mondecitronne.com">send me an email</a>. </p> - <h2 id="how does the markup work">how does the markup work?</h2> + <h2 id="how-does-the-markup-work">how does the markup work?</h2> <ul> <li> each line becomes a paragraph. @@ -66,29 +66,35 @@ surround text in square brackets to <code>[emphasize it as important]</code>. <li> - type <code>#REDIRECT <room></code> on its own line to cause the action to bring you to <code><room></code> instead of a new room. replace <code><room></code> with the five letters at the end of the url of the desired room. for instance, to make the action link to <code>https://zzcxz.citrons.xyz/g/zzcxz</code>, type <code>#REDIRECT zzcxz</code>. - - <li> - by default, a title at the top of the page contains the action which brings you to the room. this title can be overridden with <code>#PAGETITLE <title></code>. - - <li> - you can add <code>/raw</code> to the end of the URL of a room to see its markup (on the lines starting with tab) (<a href="/g/zzcxz/raw">example</a>). this feature could also potentially be utilized to implement third-party interfaces. + type <code>#redirect <id></code> to bring the player back to an existing scene. replace <code><id></code> with the scene's id. the id of the scene is displayed in the log at the bottom in grey. </li> + <img src="/static/redirect-demonstration.png" alt="the id of the scene is displayed in the log at the bottom in grey" /> </ul> - <p>if you use special formatting, and you see the literal characters that you intend to use to invoke special formatting, you have an error in your formatting. for instance, you should never see "#BACKLINK" in the preview.</p> + <p>you can add <code>/raw</code> to the end of the URL of a scene to see its markup (on the lines starting with tab) (<a href="/g/zzcxz/raw">example</a>). this feature can be used to implement third-party interfaces.</p> + + <p>if you use special formatting, and you see the literal characters that you intend to use to invoke special formatting, you have an error in your formatting. for instance, you should never see "#REDIRECT" in the preview.</p> - <h2 id="where can I discuss">where can I discuss zzcxz?</h2> + <h2 id="where-can-I-discuss">where can I discuss zzcxz?</h2> <p> please join #m on <a href="https://apionet.gh0.pw">apionet</a>. </p> - <h2 id="if you die">if you die in zzcxz, do you die in real life?</h2> + <h2 id"third-party">third party creations</h2> + <p> + <ul> + <li> + <a href="https://trimill.github.io/tools/zzcxz_vis/">zzcxz visualizer</a> + — dynamic graph of zzcxz scenes + </ul> + </p> + + <h2 id="if-you-die">if you die in zzcxz, do you die in real life?</h2> <p> no, you will not die in real life. </p> - <h2 id="who is john">who is john?</h2> + <h2 id="who-is-john">who is john?</h2> <p> I don't know. </p> diff --git a/debug/nginx.conf b/debug/nginx.conf index 1ff0baf..dd560b1 100644 --- a/debug/nginx.conf +++ b/debug/nginx.conf @@ -19,6 +19,8 @@ http { gzip off; + proxy_temp_path /tmp; + server { listen 8080; diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..4111bca --- /dev/null +++ b/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Allow: /g/zzcxz +Disallow: /g/ diff --git a/static/amethyst.css b/static/amethyst.css index 904a2bc..a6f22c1 100644 --- a/static/amethyst.css +++ b/static/amethyst.css @@ -59,19 +59,19 @@ li { footer { border-top: 2px solid white; - margin-top: 50px; + margin-top: 20px; padding-bottom: 50px; font-size: smaller; font-style: italic; } -#about-links { +.links { display: flex; justify-content: flex-end; flex-wrap: wrap; } -#about-links > p { +.links > p { margin-left: 20px; white-space: nowrap; } @@ -123,6 +123,12 @@ button, input[type="submit"] { min-width: 100px; } +input[type="file"] { + font-size: inherit; + font-style: italic; + cursor: pointer; +} + button:active, input[type="submit"]:active { background-color: lightblue; } @@ -248,7 +254,6 @@ grge { font-size: smaller; } - .important { color: cyan !important; } @@ -258,10 +263,54 @@ grge { box-sizing: border-box; } +#draw-this { + font-size: small; +} + +#img-form { + display: flex; + align-items: center; + flex-wrap: wrap; +} + +.hist-log { + padding: 10px; + border-radius: 10px; + font-family: monospace; + overflow-y: scroll; + overflow-x: hidden; + height: 85px; + background-color: black; + font-size: larger; + margin-top: 20px; + margin-bottom: 20px; +} + +.hist-log > li { + list-style: none; +} + +.hist-log > li:before { + content: "→ "; +} + +.hist-log > li > strong { + color: white; +} + +.page-id { + color: lightgrey; + font-style: italic; +} + +.illustration { + border-radius: 20px; +} + pre { background-color: white; padding: 10px; - overflow-x: scroll; + overflow-x: hidden; } pre > code { diff --git a/static/redirect-demonstration.png b/static/redirect-demonstration.png Binary files differnew file mode 100644 index 0000000..3f3b2fa --- /dev/null +++ b/static/redirect-demonstration.png @@ -34,15 +34,16 @@ local function html_encode(x) end local function parse_qs(str,sep) - sep = sep or "&" + sep = sep or '&' local function decode(str, path) local str = str if not path then str = str:gsub('+', ' ') end - return (str:gsub("%%(%x%x)", function(c) + str = str:gsub("%%(%x%x)", function(c) return string.char(tonumber(c, 16)) - end)) + end) + return (str:gsub('\r\n', '\n')) end local values = {} @@ -93,7 +94,13 @@ local function parse_qs(str,sep) return values end -local cookies = env "HTTP_COOKIE" and parse_qs(env "HTTP_COOKIE",";%s") or {} +local cookies = env "HTTP_COOKIE" and parse_qs(env "HTTP_COOKIE","; ") or {} +local history = {} +if cookies.history then + for page in cookies.history:gmatch "(%w%w%w%w%w)%," do + table.insert(history, page) + end +end local flags = {} for k,v in pairs(cookies) do local flag = k:match "flag_(.+)" @@ -130,8 +137,8 @@ local base = template [[ <h1>zzcxz</h1> <main>$content</main> <footer> - <div id="about-links"> - <p><a href="/">back to start</a></p> + <div class="links"> + <p><a href="/g/zzcxz">back to start</a></p> <p><a href="/about">help</a></p> <p><a href="https://citrons.xyz/git/zzcxz.git/about"> source code @@ -157,10 +164,6 @@ local function parse_directive(line, directives, tmp_flags) directive = directive and directive:lower() if not directive then return - elseif directive == "pagetitle" then - if args:match "^%s*$" then return end - if utf8.len(args) > 150 then return end - directives.title = args elseif directive == "redirect" then local redirect = args:match "^%s*(%w%w%w%w%w)%s*$" if not redirect then return end @@ -205,8 +208,22 @@ local function convert_markup(m) goto continue end if line:sub(1,1) == '#' and - parse_directive(line, directives, tmp_flags) then - goto continue + parse_directive(line, directives, tmp_flags) then + if directives.redirect then + local to = load_page(directives.redirect) + if to then + local m, d = convert_markup(to.content) + -- the final destination will not have a redirect + -- value in this directive. as such, this will store + -- final destination of a chain of redirects. + d.redirect = d.redirect or to + return m, d + else + directives.redirect = nil + end + else + goto continue + end end line = html_encode(line) @@ -214,6 +231,9 @@ local function convert_markup(m) table.insert(result, '<pre><code>') code_block = true else + line = line:gsub("\\\\([%[%]\\])", "\%1") + line = line:gsub("\\([%[%]])", + { ['['] = "[", [']'] = "]" }) line = line:gsub("%[(.-)%]", function(s) return ('<span class="important">%s</span>'):format(s) @@ -237,14 +257,6 @@ local function convert_markup(m) code_block = false end - if directives.redirect then - local r = directives.redirect - return ( - '<p class="note">this action will link to ' .. - '<a href="/g/%s" target="_blank">%s</a>.</p>' - ):format(r, r), directives - end - return table.concat(result), directives end local function target_requirements(p) @@ -264,6 +276,8 @@ local function parse_page(s) for line in (s..'\n'):gmatch "(.-\n)" do if line:sub(1,1) == '\t' then table.insert(content, line:sub(2)) + elseif line:match("^!image") then + page.illustration = line:match "^!image%s+(%w+)" else local target, action = line:match "^(%w%w%w%w%w):(.-)\n$" if action then @@ -284,18 +298,13 @@ function load_page(p, raw) f:close() if not s then return nil end if raw then return s end - return parse_page(s) + local page = parse_page(s) + page.id = p + return page end local function new_action(page, action, result) local _, directives = convert_markup(result) - local old = assert(io.open('content/'..page, 'a')) - - if directives.redirect then - assert(old:write(('%s:%s\n'):format(directives.redirect, action))) - old:close() - return directives.redirect - end ::generate_name:: local new_name = {} @@ -311,10 +320,11 @@ local function new_action(page, action, result) goto generate_name end + local old = assert(io.open('content/'..page, 'a')) local new = assert(io.open('content/'..new_name, 'w')) action = action:gsub('\n', ' ') - assert(new:write((directives.title or action)..'\n')) + assert(new:write(action..'\n')) for line in (result..'\n'):gmatch "(.-\n)" do assert(new:write('\t' .. line)) end @@ -332,20 +342,70 @@ local function new_action(page, action, result) return new_name end +local hist_template = template [[ + <ul class="hist-log"> + $log + </ul> +]] +local function show_hist(show_ids) + local log = {} + if #history == 0 then return "" end + + for i=#history,1,-1 do + local page = load_page(history[i]) + if not page then goto continue end + + -- highlight the current page + local title = i ~= #history and html_encode(page.title) + or '<strong>'..html_encode(page.title)..'</strong>' + if show_ids then + table.insert(log, + ('<li>%s <span class="page-id">%s</span></li>') + :format(title, history[i])) + else + table.insert(log, ('<li>%s</li>'):format(title)) + end + ::continue:: + end + return hist_template { + log = table.concat(log), + } +end + local map = {} local page_template = template [[ <h2>$title</h2> + $illustration $content + $drawthis <ul class="actions"> $actions </ul> + $log +]] +local draw_this = [[ + <p id="draw-this"><a href="$page/illustrate">illustrate this</a></p> ]] map["^/g/(%w%w%w%w%w)$"] = function(p) local page = load_page(p) if not page then return not_found() end - local _, directives = convert_markup(page.content) + local content, directives = convert_markup(page.content) + if env "REQUEST_METHOD" ~= "POST" then + if history[#history] ~= p then + table.insert(history, p) + end + if #history > 75 then + table.remove(history, 1) + end + + local title = page.title + + if directives.redirect then + page = directives.redirect + end + local actions = {} for _,a in ipairs(page.actions) do if target_requirements(a.target) then @@ -357,13 +417,32 @@ map["^/g/(%w%w%w%w%w)$"] = function(p) if not directives.deadend then table.insert(actions, ([[ - <li><a class="important" href="%s/act#what">%s</a></li> - ]]):format(p, #page.actions == 0 and + <li> + <a class="important" href="%s/act?back=%s#what">%s</a> + </li> + ]]):format(page.id, p, #page.actions == 0 and "do something..." or "do something else...") ) end + local illustration, draw_this + if page.illustration then + illustration = ([[ + <img class="illustration" src="/i/%s.%s" /> + ]]):format(page.id, page.illustration) + else +-- draw_this = ([[ +-- <p id="draw-this"><a href="%s/illustrate"> +-- illustrate this +-- </a></p> +-- ]]):format(p) + end + local cookies = {} + table.insert(cookies, + ('history=%s; path=/; secure; max-age=99999999999') + :format(table.concat(history, ',')..',')) + for flagname, text in pairs(directives.flags_updated) do if text then table.insert(cookies, @@ -378,11 +457,14 @@ map["^/g/(%w%w%w%w%w)$"] = function(p) end return base { - title = html_encode(page.title), + title = html_encode(title), content = page_template { - title = html_encode(page.title), - content = convert_markup(page.content), + title = html_encode(title), + content = content, actions = table.concat(actions), + illustration = illustration, + drawthis = draw_this, + log = show_hist(), }, }, {headers = {["set-cookie"] = cookies, bees = "3.14"}} else @@ -430,10 +512,11 @@ local edit_template = template [[ maxlength="10000" required >$editing</textarea> <div class="buttons"> - <a href="../$page">cancel</a> - <input type="submit" formaction="act#what" value="preview" /> + <a href="$cancel">cancel</a> + <input type="submit" value="preview" /> $submit </div> + $log </form> ]] local preview_template = template [[ @@ -451,12 +534,17 @@ map["^/g/(%w%w%w%w%w)/act$"] = function(p) local _, directives = convert_markup(page.content) if directives.deadend then return not_found() end + local query = parse_qs(env "QUERY_STRING" or "") + local cancel = '/g/'..(query.back or p) + if env "REQUEST_METHOD" ~= "POST" then return base { title = "do something new", content = edit_template { page = p, content = convert_markup(page.content), + log = show_hist(true), + cancel = html_encode(cancel), }, } else @@ -465,46 +553,108 @@ map["^/g/(%w%w%w%w%w)/act$"] = function(p) form.happens = form.happens or "something" local prev, prev_direct = convert_markup(form.happens) - + + local prev_title = + prev_direct.title and html_encode(prev_direct.title) or + html_encode(form.wyd) + + if prev_direct.redirect then + local note = + ('<span class="note">previewing %s</span>') + :format(prev_direct.redirect.id) + prev = note..prev + end + return base { title = "do something new", content = edit_template { page = p, content = convert_markup(page.content), preview = preview_template { - title = - prev_direct.title and html_encode(prev_direct.title) - or html_encode(form.wyd), + title = prev_title, content = prev, }, title = html_encode(form.wyd), editing = html_encode(form.happens), submit = submit_template { page = p }, + cancel = html_encode(cancel), + log = show_hist(true), }, } end end +local illustrate_template = template [[ + <h2>$title</h2> + $content + <hr/> + <h2 id="what">what does this look like?</h2> + <form method="POST" action="/g/$page/illustrate" + enctype="multipart/form-data" id="img-form"> + <input + type="file" + name="file" + accept="image/png,image/jpeg,image/gif" + /> + <input type="submit" value="submit image" /> + </form> +]] +-- map["^/g/(%w%w%w%w%w)/illustrate"] = function(p) +-- local page = load_page(p) +-- if not page then return not_found() end +-- +-- if env "REQUEST_METHOD" ~= "POST" then +-- return base { +-- title = "illustration: " .. html_encode(page.title), +-- content = illustrate_template { +-- title = html_encode(page.title), +-- content = convert_markup(page.content), +-- page = p, +-- }, +-- } +-- else +-- end +-- end + +map["^/i/(%w%w%w%w%w).(%w+)$"] = function(p, format) + local page = load_page(p) + if not page or + not page.illustration or not page.illustration == format then + return not_found() + end + return + assert(io.open(('content/%s.%s'):format(p, format), 'r')), + { content_type = 'image/'..format } +end + map["^/g/(%w%w%w%w%w)/raw$"] = function(p) local page = load_page(p, true) if not page then return not_found() end - return page, { content_type = 'text/plain' } + return page, { + content_type = 'text/plain', + headers = { ['access-control-allow-origin'] = "*" } + } end map["^/about/?$"] = function() - local f = assert(io.open("about.html", 'r')) - local h = assert(f:read 'a') - f:close() + return assert(io.open("about.html", 'r')) +end - return h +map["^/robots.txt$"] = function() + return assert(io.open("robots.txt", 'r')), + { content_type = 'text/plain' } end -local function main() - if env "PATH_INFO" == "/" then - return redirect "/g/zzcxz" +map["^/$"] = function() + if #history > 0 then + return redirect('/g/'..history[#history]) + else + return redirect '/g/zzcxz' end +end +local function main() for k,v in pairs(map) do local m = {(env "PATH_INFO"):match(k)} if m[1] then @@ -515,7 +665,7 @@ local function main() end local ok, content, resp = pcall(main) -if not ok or type(content) ~= 'string' then +if not ok or (type(content) ~= 'string' and type(content) ~= 'userdata') then io.stderr:write(content..'\n') content = base { @@ -544,4 +694,12 @@ for k,v in pairs(resp.headers) do end print "" -io.write(content) +if type(content) == 'string' then + io.write(content) +else + while 1 do + local data = content:read(1024) + if not data then break end + io.write(data) + end +end |
