From 2671f43b8b1f16e5066db4f3fbef0dd469ca0fb7 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Tue, 21 Jul 2026 19:19:52 +0200 Subject: [PATCH] first version --- .gitignore | 2 + README.md | 11 +- index.html | 110 ------------ soakbean/src/.init.lua | 52 ------ src/.args | 2 + src/.init.lua | 65 +++++++ {soakbean/middleware => src/.lua}/json.lua | 0 {soakbean/src => src}/.lua/opendirectory.lua | 114 +++++++------ {soakbean/src => src}/.lua/soakbean.lua | 1 + src/.lua/util.lua | 158 ++++++++++++++++++ src/admin/index.html | 158 ++++++++++++++++++ src/cmd/help.lua | 13 ++ src/cmd/server.lua | 3 + {soakbean/src => src}/data.lua | 0 src/experiences | 1 + src/img/arrow-down.svg | 12 ++ src/img/arrow-left.svg | 12 ++ src/img/arrow-right.svg | 12 ++ src/img/arrow-up.svg | 12 ++ {img => src/img}/folder.svg | 0 {img => src/img}/vaporgrid.svg | 0 soakbean/src/index.html => src/index.bak | 0 src/index.lua | 16 ++ {soakbean => src}/middleware/blacklisturl.lua | 0 {soakbean => src}/middleware/cgi.lua | 0 src/middleware/httpauth.lua | 50 ++++++ .../src/.lua => src/middleware}/json.lua | 0 {soakbean => src}/middleware/rproxy.lua | 0 src/run.sh | 2 + src/template/footer.html | 31 ++++ src/template/header.html | 37 ++++ src/template/index.html | 45 +++++ {soakbean/src => src}/tests.html | 0 ui-kit.html => src/ui-kit.html | 0 xrforge.css => src/xrforge.css | 30 ++-- src/xrforge.max.css | 60 +++++++ util/xrforge.sh | 4 +- xrforge.max.css | 32 ---- 38 files changed, 788 insertions(+), 257 deletions(-) create mode 100644 .gitignore delete mode 100644 index.html delete mode 100644 soakbean/src/.init.lua create mode 100644 src/.args create mode 100644 src/.init.lua rename {soakbean/middleware => src/.lua}/json.lua (100%) rename {soakbean/src => src}/.lua/opendirectory.lua (55%) rename {soakbean/src => src}/.lua/soakbean.lua (99%) create mode 100644 src/.lua/util.lua create mode 100644 src/admin/index.html create mode 100644 src/cmd/help.lua create mode 100644 src/cmd/server.lua rename {soakbean/src => src}/data.lua (100%) create mode 120000 src/experiences create mode 100644 src/img/arrow-down.svg create mode 100644 src/img/arrow-left.svg create mode 100644 src/img/arrow-right.svg create mode 100644 src/img/arrow-up.svg rename {img => src/img}/folder.svg (100%) rename {img => src/img}/vaporgrid.svg (100%) rename soakbean/src/index.html => src/index.bak (100%) create mode 100644 src/index.lua rename {soakbean => src}/middleware/blacklisturl.lua (100%) rename {soakbean => src}/middleware/cgi.lua (100%) create mode 100644 src/middleware/httpauth.lua rename {soakbean/src/.lua => src/middleware}/json.lua (100%) rename {soakbean => src}/middleware/rproxy.lua (100%) create mode 100755 src/run.sh create mode 100644 src/template/footer.html create mode 100644 src/template/header.html create mode 100644 src/template/index.html rename {soakbean/src => src}/tests.html (100%) rename ui-kit.html => src/ui-kit.html (100%) rename xrforge.css => src/xrforge.css (89%) create mode 100644 src/xrforge.max.css delete mode 100644 xrforge.max.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..425ba6d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +experiences +result diff --git a/README.md b/README.md index ad015a4..58ff181 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ``` $ source .env # not needed if your system has autoenv -$ build # fast: repeatable build +$ util/xrforge.sh build # fast: repeatable build $ nix-build # slow: reproducable nix build (for experts) ``` @@ -25,3 +25,12 @@ scan files ]] ``` + +## Scan manyfold + +------------- +``` +manual scan (via cli?) +curl -L -X 'GET' 'http://xrforge.isvery.ninja/models?page=1&order=name' -H 'accept: application/vnd.manyfold.v0+json' +curl -L -X 'GET' 'http://xrforge.isvery.ninja/models?page=1&order=recent' -H 'accept: application/vnd.manyfold.v0+json' +``` diff --git a/index.html b/index.html deleted file mode 100644 index 8a90297..0000000 --- a/index.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - XRForge - selfsovereign interoperable XR experiences - - - - - - - - - -
-
- -
-
- - - - - -
-
- - - -
-
-

Hi there

- This is a hosting tool for portable XR experiences. -
-
- -
- button -
- - - - -
-
-
- -
-
-
-
-  Item 1 -
-
-
-
-
-  Item 2 -
-
-
-
-
-  Item 3 -
-
-
- -
- -
-
- - - - - - - - - -
- -
-
- - - - - - - diff --git a/soakbean/src/.init.lua b/soakbean/src/.init.lua deleted file mode 100644 index f85bbaf..0000000 --- a/soakbean/src/.init.lua +++ /dev/null @@ -1,52 +0,0 @@ -package.path = package.path .. ";.lua/?.lua" -package.path = package.path .. ";src/.lua/?.lua" -package.path = package.path .. ";middleware/?.lua" - -json = require "json" - --- special script called by main redbean process at startup -HidePath('/usr/share/zoneinfo/') -HidePath('/usr/share/ssl/') - -dir = require "opendirectory" - -function OnHttpRequest() - if( not dir.serve() ) then - print("default") - Route() - end -end - ----- create ---app = require("soakbean") { --- bin = "./redbean.com", --- opts = { --- my_cli_arg=1 --- }, --- cmd={ --- -- runtask = {file="sometask.lua", info="description of cli cmd"} --- }, --- title = 'SOAKBEAN - a buddy of redbean', --- subtitle = 'SOAKBEAN makes redbean programming easy', --- notes = {'🤩 express-style programming', '🖧 easy routings', '♻ re-use middleware functions'} ---} --- ---app.url['^/data'] = '/data.lua' -- setup custom file endpoint --- ---app.get('^/', app.template('index.html') ) -- alias for app.tpl( LoadAsset('index.html'), app ) --- ---app.post('^/save', function(req,res,next) -- setup inline POST endpoint --- -- also .get(), .put(), .delete(), .options() --- app.cache = req.body -- middleware auto-decodes json --- res.status(200) --- res.body({cache=app.cache}) -- middleware auto-encodes json --- next() ---end) --- ---app -- ---.use( require("json").middleware() ) -- try plug'n'play json API middleware ---.use( app.router( app.url ) ) -- try url router ---.use( app.response() ) -- try serve app response (if any) ---.use( function(req,next) Route() end) -- fallback default redbean fileserver --- ---function OnHttpRequest() app.run() end diff --git a/src/.args b/src/.args new file mode 100644 index 0000000..bd02a5f --- /dev/null +++ b/src/.args @@ -0,0 +1,2 @@ +-D +. diff --git a/src/.init.lua b/src/.init.lua new file mode 100644 index 0000000..bebd3a2 --- /dev/null +++ b/src/.init.lua @@ -0,0 +1,65 @@ +package.path = package.path .. ";.lua/?.lua" +package.path = package.path .. ";src/.lua/?.lua" +package.path = package.path .. ";middleware/?.lua" +package.path = package.path .. ";cmd/?.lua" + +util = require "util" +json = require "json" + +-- special script called by main redbean process at startup +HidePath('/usr/share/zoneinfo/') +HidePath('/usr/share/ssl/') + +dir = require "opendirectory" + +-- create +app = require("soakbean") { + bin = "./xrforge.com", + cache = {}, + opts = { + title="My XRForge experiences", + subtitle="Portable XR experiences for PhoneVR, VRheadset, desktop & mobile." + }, + cmd={ + help = {file="help.lua", info="displays help cmds"}, + server = {file="server.lua", info="starts the webserver"} + }, + title = 'XRForge - local-first XR experiences', + subtitle = 'XRForge makes local-first XR easy', + notes = {'🤩 portable selfsovereign', '🖧 JanusXR / XR Fragments', '♻ decentralized'} +} + +app.url['^/data'] = '/data.lua' -- setup custom file endpoint + +app.url['^/$'] = '/index.lua' -- alias for app.tpl( LoadAsset('index.html'), app ) +app.get('^/admin/$', app.template('admin/index.html') ) -- alias for app.tpl( LoadAsset('index.html'), app ) + +app.post('^/save', function(req,res,next) -- setup inline POST endpoint + -- also .get(), .put(), .delete(), .options() + app.cache = req.body -- middleware auto-decodes json + res.status(200) + res.body({cache=app.cache}) -- middleware auto-encodes json + next() +end) + +app -- +.use( require("httpauth")() ) +.use( require("json").middleware() ) -- try plug'n'play json API middleware +.use( app.router( app.url ) ) -- try url router +.use( app.response() ) -- try serve app response (if any) +.use( function(req,next) Route() end) -- fallback default redbean fileserver + +app.on('template', function(a,b,c,d,e) + print("TEMPLATE!") +end) + +function OnHttpRequest() app.run() end + +print("ja") +--function OnHttpRequest() +-- if( not dir.serve("./experiences") ) then +-- print("default") +-- Route() +-- end +--end +-- diff --git a/soakbean/middleware/json.lua b/src/.lua/json.lua similarity index 100% rename from soakbean/middleware/json.lua rename to src/.lua/json.lua diff --git a/soakbean/src/.lua/opendirectory.lua b/src/.lua/opendirectory.lua similarity index 55% rename from soakbean/src/.lua/opendirectory.lua rename to src/.lua/opendirectory.lua index dc19263..d56ca98 100644 --- a/soakbean/src/.lua/opendirectory.lua +++ b/src/.lua/opendirectory.lua @@ -29,16 +29,33 @@ local dir = {} -dir.serve = function() - - local path = '.' .. GetPath() - if not path:find("..") == nil then return ServeError(403,"=]") end +dir.scan = function(path) local stat = unix.stat(path) if stat == nil then return ServeError(404,"does not exist") else if not unix.S_ISDIR( stat:mode() ) then return false end -- let redbean take care of serving static file end + state = assert(unix.opendir(path)) + return stat, state +end + +dir.foreach = function(path,cb) + local stat, state = dir.scan(path) + for name, kind, ino, off in state do + if name == "." then goto continue end + attr,err = unix.stat(path..'/'..name, unix.AT_SYMLINK_NOFOLLOW) + if err then print("error: ".. name .. ": " ..err) end + cb(path,stat,state,name,kind,ino,off,attr) + ::continue:: + end +end + +dir.serve = function(folder) -- raw redbean function (use dir.foreach in soakbean) + + local path = '.' .. GetPath() + if not path:match('^' .. folder) then return false end -- should start with folder + if not path:find("..") == nil then return ServeError(403,"=]") end SetStatus(200) SetHeader('Content-Type', 'text/html; charset=utf-8') @@ -51,38 +68,36 @@ dir.serve = function() Write('td { white-space: nowrap; }\r\n') Write('.l { text-align: left; }\r\n') Write('.r { text-align: right; }\r\n') + Write('.hide { display:none; }\r\n') Write('\r\n') - Write('

Open Directory Demo

\r\n') + Write('

Open Directory Demo '.. path .. '

\r\n') Write('\r\n') Write('\r\n') Write('\r\n') Write('\r\n') - print("opendir: "..path) - state = assert(unix.opendir(path)) - - for name, kind, ino, off in state do - if name == "." then goto continue end + local stat, state = dir.scan(path) + dir.foreach(path, function(path,stat,state,name,kind,ino,off,attr) Write('\r\n') Write('
name\r\n') - Write('type\r\n') - Write('ino\r\n') - Write('off\r\n') + Write('type\r\n') + Write('ino\r\n') + Write('off\r\n') Write('size\r\n') - Write('blocks\r\n') - Write('mode\r\n') - Write('uid\r\n') - Write('gid\r\n') - Write('dev\r\n') - Write('rdev\r\n') - Write('nlink\r\n') - Write('blksize\r\n') - Write('gen\r\n') - Write('flags\r\n') - Write('birthtim\r\n') - Write('mtim\r\n') - Write('atim\r\n') - Write('ctim\r\n') + Write('blocks\r\n') + Write('mode\r\n') + Write('uid\r\n') + Write('gid\r\n') + Write('dev\r\n') + Write('rdev\r\n') + Write('nlink\r\n') + Write('blksize\r\n') + Write('gen\r\n') + Write('flags\r\n') + Write('birthtim\r\n') + Write('mtim\r\n') + Write('atim\r\n') + Write('ctim\r\n') Write('
') local link = EscapeHtml(name) @@ -90,7 +105,7 @@ dir.serve = function() Write('' .. link .. '') Write('\r\n') - Write('') + Write('') if kind == unix.DT_REG then Write('DT_REG') elseif kind == unix.DT_DIR then Write('DT_DIR') elseif kind == unix.DT_FIFO then Write('DT_FIFO') @@ -102,41 +117,38 @@ dir.serve = function() end Write('\r\n') - Write('%d\r\n' % {ino}) - Write('%d\r\n' % {off}) + Write('%d\r\n' % {ino}) + Write('%d\r\n' % {off}) - st,err = unix.stat(path..'/'..name, unix.AT_SYMLINK_NOFOLLOW) - if st then - - Write('%d\r\n' % {st:size()}) - Write('%d\r\n' % {st:blocks()}) - Write('%.7o\r\n' % {st:mode()}) - Write('%d\r\n' % {st:uid()}) - Write('%d\r\n' % {st:gid()}) - Write('%d\r\n' % {st:dev()}) - Write('%d,%d\r\n' % {unix.major(st:rdev()), unix.minor(st:rdev())}) - Write('%d\r\n' % {st:nlink()}) - Write('%d\r\n' % {st:blksize()}) - Write('%d\r\n' % {st:gen()}) - Write('%#x\r\n' % {st:flags()}) + if attr then + Write('%d\r\n' % {attr:size()}) + Write('%d\r\n' % {attr:blocks()}) + Write('%.7o\r\n' % {attr:mode()}) + Write('%d\r\n' % {attr:uid()}) + Write('%d\r\n' % {attr:gid()}) + Write('%d\r\n' % {attr:dev()}) + Write('%d,%d\r\n' % {unix.major(attr:rdev()), unix.minor(attr:rdev())}) + Write('%d\r\n' % {attr:nlink()}) + Write('%d\r\n' % {attr:blksize()}) + Write('%d\r\n' % {attr:gen()}) + Write('%#x\r\n' % {attr:flags()}) function WriteTime(unixsec,nanos) year,mon,mday,hour,min,sec,gmtoffsec = unix.localtime(unixsec) - Write('%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.9d%+.2d%.2d\r\n' % { + Write('%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.9d%+.2d%.2d\r\n' % { year, mon, mday, hour, min, sec, nanos, gmtoffsec / (60 * 60), math.abs(gmtoffsec) % 60}) end - WriteTime(st:birthtim()) - WriteTime(st:mtim()) - WriteTime(st:atim()) - WriteTime(st:ctim()) + WriteTime(attr:birthtim()) + WriteTime(attr:mtim()) + WriteTime(attr:atim()) + WriteTime(attr:ctim()) else Write('%s\r\n' % {err}) end - ::continue:: - end + end) Write('
\r\n') state:close() return true diff --git a/soakbean/src/.lua/soakbean.lua b/src/.lua/soakbean.lua similarity index 99% rename from soakbean/src/.lua/soakbean.lua rename to src/.lua/soakbean.lua index 0e53e6d..6fcf244 100644 --- a/soakbean/src/.lua/soakbean.lua +++ b/src/.lua/soakbean.lua @@ -49,6 +49,7 @@ sb = { -- print( util.tpl("${name} is ${value}", {name = "foo", value = "bar"}) ) -- "foo is bar" tpl = function(s,tab) + if not s then return "" end return (s:gsub('($%b{})', function(w) return tab[w:sub(3, -2)] or w end)) end, diff --git a/src/.lua/util.lua b/src/.lua/util.lua new file mode 100644 index 0000000..2c4f421 --- /dev/null +++ b/src/.lua/util.lua @@ -0,0 +1,158 @@ +local util = { } + +util.clone = function(orig) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[util.clone(orig_key)] = util.clone(orig_value) + end + setmetatable(copy, util.clone(getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy +end + +util.flatten = function(tbl, prefix, result) + result = result or {} + for k, v in pairs(tbl) do + local new_key = (prefix or "") .. "." .. k + if type(v) == "table" then + util.flatten(v, new_key, result) + else + result[new_key] = v + end + end + return result +end + +util.template = function(content,data) + local finaldata = util.merge(app,{}) + finaldata = util.merge(finaldata, util.flatten(app.opts,"opts") ) + finaldata.header = app.tpl( LoadAsset('template/header.html'), finaldata ) + finaldata.footer = app.tpl( LoadAsset('template/footer.html'), finaldata ) + return app.tpl( content, finaldata ) +end + +util.memoize = function(fn, ttl_seconds) + local cached_results = nil + local last_executed = 0 + + return function(...) + local now = os.time() + -- Check if cache is missing or if the TTL has passed + print("now = "..now .. " last_executed = " ..last_executed) + if not cached_results or (now - last_executed) >= ttl_seconds then + -- Pass all input arguments and pack all return values into a table + cached_results = { fn(...) } + last_executed = now + end + -- Unpack and return the cached results + return table.unpack(cached_results) + end +end + +util.cmdExist = function(cmd) + if api.runtime.os == 'unixy' then cmd = cmd .. " 1>/dev/null 2>/dev/null" end + local stdout, retstr, retcode = os.execute(cmd) + return retcode ~= 127 +end + +function util.merge(t1,t2) + local t3 = {} + foreach( t1, function(k,v) t3[k] = v end) + foreach( t2, function(k,v) t3[k] = v end) + return t3 +end + +function util.dump(value, indent, seen) + indent = indent or "" + seen = seen or {} + local t = type(value) + if t == "string" then + return string.format("%q", value) + elseif t == "boolean" or t == "number" or t == "nil" then + return tostring(value) + elseif t == "function" or t == "userdata" or t == "thread" then + return string.format("<%s: %s>", t, tostring(value)) + elseif t == "table" then + if seen[value] then + return string.format("", tostring(value)) + end + seen[value] = true + + local result = "{\n" + local next_indent = indent .. " " + local seen_keys = {} + for i, v in ipairs(value) do + seen_keys[i] = true + result = result .. next_indent .. util.dump(v, next_indent, seen) .. ",\n" + end + + for k, v in pairs(value) do + if not seen_keys[k] then + local key_str + if type(k) == "string" and k:match("^[%a_][%w_]*$") then + key_str = k + else + key_str = "[" .. util.dump(k, next_indent, seen) .. "]" + end + + result = result .. next_indent .. key_str .. " = " .. util.dump(v, next_indent, seen) .. ",\n" + end + end + + if result:sub(-2) == ",\n" then + result = result:sub(1, -3) .. "\n" + end + + return result .. indent .. "}" + end +end + +function util.count(self) + local i = 0 + if self == nil then return i end + if type(self) == 'table' then + for _, _ in pairs(self) do + i = i + 1 + end + return i + else + return #self + end +end + +util.call = function(fn,a,b,c,d,e,f) + return function(k,v) + if v ~= nil and v[fn] then + v[fn](a,b,c,d,e,f) + end + end +end + +function foreach(t, f, sort) + if t ~= nil then + for k, v in pairs(t) do f(k, v) end + end +end + +function trace(o) + if os.getenv('DEBUG') then + if type(o) == 'table' then + print_r(o) + else + print(o) + end + end +end + + +function print_r(t) + print( util.dump(t) ) +end + + +return util diff --git a/src/admin/index.html b/src/admin/index.html new file mode 100644 index 0000000..b074aa4 --- /dev/null +++ b/src/admin/index.html @@ -0,0 +1,158 @@ + + + + + + Lorem ipsum - dolor sit + + + + + + + + + +
+
+ +
+
+ + + + + +
+
+ + + +
+

HEADER 1

+ Lorem ipsum dolor sit amter.
+ Amet puti solor fati corpus a link flap.

+
+ +
+ button +
+ + + + +
+
+
+ +
    +
  • foo bar
  • +
  • flop flap
  • +
+ + +
+
+
+
+┌─────────────────┐┌────────────────┐
+│  Foo     CLI    ││ Foo     Web    │
+└─────────────────┘└────────────────┘
+┌───────────────────────────────────┐
+│  Foo     Repository               │
+│ ┌────────┐ ┌────────┐ ┌─────────┐ │
+│ │  code  │ │ issues │ │ patches │ │
+│ └────────┘ └────────┘ └─────────┘ │
+├───────────────────────────────────┤
+│  Foo     Storage (Git)            │
+└───────────────────────────────────┘
+┌────────────────┐┌─────────────────┐
+│  Foo     Node  ││  Foo     HTTPD  │
+├────────────────┤├─────────────────┤
+│    NoiseXK     ││   HTTP + JSON   │
+└────────────────┘└─────────────────┘
+
+
+
+┌─────────────────┐┌────────────────┐
+│  Foo     CLI    ││ Foo     Web    │
+└─────────────────┘└────────────────┘
+┌───────────────────────────────────┐
+│  Foo     Repository               │
+│ ┌────────┐ ┌────────┐ ┌─────────┐ │
+│ │  code  │ │ issues │ │ patches │ │
+│ └────────┘ └────────┘ └─────────┘ │
+├───────────────────────────────────┤
+│  Foo     Storage (Git)            │
+└───────────────────────────────────┘
+┌────────────────┐┌─────────────────┐
+│  Foo     Node  ││  Foo     HTTPD  │
+├────────────────┤├─────────────────┤
+│    NoiseXK     ││   HTTP + JSON   │
+└────────────────┘└─────────────────┘
+
+
+
+┌─────────────────┐┌────────────────┐
+│  Foo     CLI    ││ Foo     Web    │
+└─────────────────┘└────────────────┘
+┌───────────────────────────────────┐
+│  Foo     Repository               │
+│ ┌────────┐ ┌────────┐ ┌─────────┐ │
+│ │  code  │ │ issues │ │ patches │ │
+│ └────────┘ └────────┘ └─────────┘ │
+├───────────────────────────────────┤
+│  Foo     Storage (Git)            │
+└───────────────────────────────────┘
+┌────────────────┐┌─────────────────┐
+│  Foo     Node  ││  Foo     HTTPD  │
+├────────────────┤├─────────────────┤
+│    NoiseXK     ││   HTTP + JSON   │
+└────────────────┘└─────────────────┘
+
+

hello world

+ Lorem ipsum +
+

hello world

+ Lorem ipsum +
+

hello world

+ Lorem ipsum + +
+
+ + + + + + + + + +
+
+
+
+ + + + + + + diff --git a/src/cmd/help.lua b/src/cmd/help.lua new file mode 100644 index 0000000..27ccc19 --- /dev/null +++ b/src/cmd/help.lua @@ -0,0 +1,13 @@ +return function(app,argv) + print("help!") + foreach( app.opts, function(k,v) + if not k:match("/") and not k:match("^help") then + print( app.bin .. " -- " .. k .. "=...\t # '" .. v .. "' e.g." ) + end + end) + foreach( app.cmd, function(k,v) + print( app.bin .. " -- " .. k .. "\t\t # " .. v.info ) + end) + + os.exit() +end diff --git a/src/cmd/server.lua b/src/cmd/server.lua new file mode 100644 index 0000000..0c9602d --- /dev/null +++ b/src/cmd/server.lua @@ -0,0 +1,3 @@ +return function(app,argv) + print("starting server") +end diff --git a/soakbean/src/data.lua b/src/data.lua similarity index 100% rename from soakbean/src/data.lua rename to src/data.lua diff --git a/src/experiences b/src/experiences new file mode 120000 index 0000000..78b5114 --- /dev/null +++ b/src/experiences @@ -0,0 +1 @@ +../experiences \ No newline at end of file diff --git a/src/img/arrow-down.svg b/src/img/arrow-down.svg new file mode 100644 index 0000000..46d2740 --- /dev/null +++ b/src/img/arrow-down.svg @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/src/img/arrow-left.svg b/src/img/arrow-left.svg new file mode 100644 index 0000000..8348fd2 --- /dev/null +++ b/src/img/arrow-left.svg @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/src/img/arrow-right.svg b/src/img/arrow-right.svg new file mode 100644 index 0000000..3575813 --- /dev/null +++ b/src/img/arrow-right.svg @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/src/img/arrow-up.svg b/src/img/arrow-up.svg new file mode 100644 index 0000000..0121746 --- /dev/null +++ b/src/img/arrow-up.svg @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/img/folder.svg b/src/img/folder.svg similarity index 100% rename from img/folder.svg rename to src/img/folder.svg diff --git a/img/vaporgrid.svg b/src/img/vaporgrid.svg similarity index 100% rename from img/vaporgrid.svg rename to src/img/vaporgrid.svg diff --git a/soakbean/src/index.html b/src/index.bak similarity index 100% rename from soakbean/src/index.html rename to src/index.bak diff --git a/src/index.lua b/src/index.lua new file mode 100644 index 0000000..868ec14 --- /dev/null +++ b/src/index.lua @@ -0,0 +1,16 @@ +local util = require("util") + +if not app.cache['index.html'] then + app.cache['index.html'] = util.memoize( + function() + print("processing!") + local html = util.template( LoadAsset("template/index.html"),app) + return html + end, + 60*5 -- re-run every 5 mins (otherwise return cache) + ) +end + +SetStatus(200) +SetHeader('Content-Type', 'text/html; charset=utf-8') +Write( app.cache['index.html']() ) diff --git a/soakbean/middleware/blacklisturl.lua b/src/middleware/blacklisturl.lua similarity index 100% rename from soakbean/middleware/blacklisturl.lua rename to src/middleware/blacklisturl.lua diff --git a/soakbean/middleware/cgi.lua b/src/middleware/cgi.lua similarity index 100% rename from soakbean/middleware/cgi.lua rename to src/middleware/cgi.lua diff --git a/src/middleware/httpauth.lua b/src/middleware/httpauth.lua new file mode 100644 index 0000000..8159002 --- /dev/null +++ b/src/middleware/httpauth.lua @@ -0,0 +1,50 @@ +-- Middleware function to check credentials +function Authenticate(opts,realm) + realm = realm or "Restricted Area" + + local auth_header = GetHeader("Authorization") + + if auth_header and auth_header:find("^Basic ") then + -- Extract the Base64 portion + local encoded = auth_header:sub(7) + local decoded = DecodeBase64(encoded) + + -- Basic Auth format is "username:password" + local user, pass = decoded:match("([^:]+):(.*)") + if user == opts.user and pass == opts.pass then + print("info: succesful login for user: "..user) + return true -- Access granted + end + end + + -- Request credentials if missing or invalid + SetStatus(401, "Unauthorized") + SetHeader("WWW-Authenticate", 'Basic realm="' .. realm .. '"') + Write("401 Unauthorized - Access Denied\n") + return false +end + + +-- soakbean middleware functions +return function(opts) + opts = opts or { + user = "admin", + pass = "admin", + path = "^/admin" + } + return function(req,res,next) + -- Protect a specific path (e.g., /admin or everything under /private/) + if req.url:match( opts.path ) then + if not Authenticate(opts,"Admin Zone") then + print("ERROR") + else + req.authenticated = true + req.user = opts.user + next() + end + else + next() + end + end +end + diff --git a/soakbean/src/.lua/json.lua b/src/middleware/json.lua similarity index 100% rename from soakbean/src/.lua/json.lua rename to src/middleware/json.lua diff --git a/soakbean/middleware/rproxy.lua b/src/middleware/rproxy.lua similarity index 100% rename from soakbean/middleware/rproxy.lua rename to src/middleware/rproxy.lua diff --git a/src/run.sh b/src/run.sh new file mode 100755 index 0000000..e7e4477 --- /dev/null +++ b/src/run.sh @@ -0,0 +1,2 @@ +#!/bin/sh +../result/bin/xrforge.com -D . -p 8081 -- server diff --git a/src/template/footer.html b/src/template/footer.html new file mode 100644 index 0000000..12f9956 --- /dev/null +++ b/src/template/footer.html @@ -0,0 +1,31 @@ + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + diff --git a/src/template/header.html b/src/template/header.html new file mode 100644 index 0000000..bdfbb44 --- /dev/null +++ b/src/template/header.html @@ -0,0 +1,37 @@ + + + + + + XRForge - selfsovereign interoperable XR experiences + + + + + + + + + +
+
+ +
+
+
+ + + +
+
+ + +
diff --git a/src/template/index.html b/src/template/index.html new file mode 100644 index 0000000..566a53b --- /dev/null +++ b/src/template/index.html @@ -0,0 +1,45 @@ +${header} + +
+

${opts.title}

+ ${opts.subtitle} +
+
+ +
+ button +
+ + + + +
+
+
+ +
+
+
+
+  Item 1 +
+
+
+
+
+  Item 2 +
+
+
+
+
+  Item 3 +
+
+
+ +${footer} diff --git a/soakbean/src/tests.html b/src/tests.html similarity index 100% rename from soakbean/src/tests.html rename to src/tests.html diff --git a/ui-kit.html b/src/ui-kit.html similarity index 100% rename from ui-kit.html rename to src/ui-kit.html diff --git a/xrforge.css b/src/xrforge.css similarity index 89% rename from xrforge.css rename to src/xrforge.css index 0816fb1..761d172 100644 --- a/xrforge.css +++ b/src/xrforge.css @@ -1,4 +1,4 @@ -/* Progressive enhancement +/* Progressive enhancment * NetSurf and Dillo will ignore this entirely because of the modern orientation/feature query */ @import url("xrforge.max.css") supports(display: grid); @@ -15,6 +15,7 @@ .page{ width:640px; } /* spacers */ +.margin1L{ margin: 0px 20px 10px 0px;} .margin1{ margin: 10px 20px; } .padding1{ padding: 10px 20px 10px 20px; } @@ -23,13 +24,17 @@ margin:0; padding:0; } + body,html { - background:#112; font-family: monospace,sans-serif; color:#f7f7f7; font-size:15px; } +body{ + margin:20px; +} + td,div,p{ word-spacing: 0.2em; line-height:24px; @@ -40,10 +45,13 @@ td,div,p{ margin: 0px 10px 10px 0px; } -.btn a{ +.btn a, +.btn a:active, +.btn a:visited, +.btn a:link { display: inline-block; padding:8px 16px; - color: #AAD; + color: #f3f; text-decoration:none; } @@ -52,6 +60,8 @@ td,div,p{ background:#000; } +.btn a, .border{ border:1px dotted #AAD; } + a, a:active, a:visited, a:link { text-decoration: none; color:#FFF; @@ -64,11 +74,6 @@ a:hover{ border-bottom:1px dotted #f3f; } -.primary{ color: #f3f; } -.secondary{ color: #7070ff; } -.btn.primary{ background: #f3F; color:#000; } -.btn.secondary{ background: #7070ff; color:#000; } -.btn a, .border{ border:1px dotted #AAD; } .border.primary{ border:1px dotted #87a; } .border.secondary{ border:1px dotted #7070ff; } @@ -129,6 +134,8 @@ ul{ visibility: hidden; } +img.icon{ display:none; } + /* progressive enhancement quirks */ @media (min-width:1px) { .grid .tile{ @@ -137,5 +144,8 @@ ul{ .grid .tile .img{ visibility: visible; } - .page{ width:80%; } + .page{ + width:100%; + max-width:1280px; + } } diff --git a/src/xrforge.max.css b/src/xrforge.max.css new file mode 100644 index 0000000..b4ba568 --- /dev/null +++ b/src/xrforge.max.css @@ -0,0 +1,60 @@ +body{ + background:#000000; +} + +.grid .tile .img{ + visibility: visible; + border:1px dotted #223; + background-size:cover; + background-position:center; + background-repeat: no-repeat; + border-radius:5px 5px 0px 0px; + height:33vh; +} +.grid .tile{ + margin: 0px 15px 15px 0px; + width:31%; + float:left; + background-color:#333; +} + +@media (max-width: 890px){ + .grid .tile { + width:47%; + } +} +@media (max-width: 713px){ + .grid .tile { + float:none; + width:100%; + margin: 0px 0px 15px 0px; + } +} + +.grid .tile .text{ + padding: 10px 20px 10px 20px !important; +} + +.grid .tile img.icon{ + transform: translate(0,5px); +} + +.clear{ + clear:both; +} + +.jumbotron{ + padding:20px 0px; + background:linear-gradient(45deg,#0000,#0000,#F7F2,#0000,#07F2,#0000,#0000); +} + +img.icon{ + display: inline-block !important; + margin-top: 0px; + margin-bottom: -5px; + width: 17px; +} + +.btn a.primary{ background: #ff33Ff; color:#000 !important;} +.btn a.secondary{ background: #7070ff; color:#000 !important;} + diff --git a/util/xrforge.sh b/util/xrforge.sh index 3efb78b..cdb64cf 100755 --- a/util/xrforge.sh +++ b/util/xrforge.sh @@ -14,7 +14,7 @@ download(){ sha256sum -c /tmp/checksum || { echo "psuedosecurity checksum failed"; exit 1; } chmod +x $OUTDIR/xrforge.com } - test -f /tmp/xrforge.com || wget "$REDBEAN_URL" -O /tmp/xrforge.com + test -f /tmp/xrforge.com || wget --no-check-certificate "$REDBEAN_URL" -O /tmp/xrforge.com cp /tmp/xrforge.com $OUTDIR/xrforge.com verify } @@ -24,6 +24,8 @@ download(){ build(){ download redbean + cd src + zip -r ../result/bin/xrforge.com * .lua .init.lua } "$@" diff --git a/xrforge.max.css b/xrforge.max.css deleted file mode 100644 index 69ac379..0000000 --- a/xrforge.max.css +++ /dev/null @@ -1,32 +0,0 @@ -.grid .tile .img{ - visibility: visible; - border:1px dotted #223; - background-size:cover; - background-position:center; - background-repeat: no-repeat; - border-radius:5px 5px 0px 0px; - height:33vh; -} -.grid .tile{ - margin: 0px 15px 15px 0px; - width:31%; - float:left; - background-color:#333; -} -.grid .tile .text{ - padding: 10px 20px 10px 20px !important; -} - - -.grid .tile img.icon{ - transform: translate(0,5px); -} - -.clear{ - clear:both; -} - -.jumbotron{ - padding: 15px 20px 15px 20px; -} -