mirror of
https://github.com/lxsang/antd-web-apps
synced 2024-12-25 17:08:22 +01:00
Add Booklet front end
This commit is contained in:
parent
16801d947d
commit
44f50f3a52
2
Makefile
2
Makefile
@ -1,5 +1,5 @@
|
||||
BUILDDIR?=./build
|
||||
PROJS?=grs info blog apps os
|
||||
PROJS?=grs info blog apps os doc
|
||||
copyfiles = index.ls mimes.json
|
||||
main: copy
|
||||
for f in $(PROJS); do BUILDDIR=$(BUILDDIR)/"$${f}" make -C "$${f}" ; done
|
||||
|
@ -125,7 +125,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id = "bottom">
|
||||
Powered by antd server, (c) 2017 - 2018 Xuan Sang LE
|
||||
Powered by antd server, (c) 2017 - <?=os.date("*t").year?> Xuan Sang LE
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
6
doc/Makefile
Normal file
6
doc/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
copyfiles = views controllers router.lua assets
|
||||
|
||||
main:
|
||||
- mkdir $(BUILDDIR)
|
||||
cp -rvf $(copyfiles) $(BUILDDIR)
|
||||
- cd $(BUILDDIR) && ln -s ../grs ./rst
|
164
doc/assets/style.css
Normal file
164
doc/assets/style.css
Normal file
@ -0,0 +1,164 @@
|
||||
html,body{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: "Ubuntu";
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
#top{
|
||||
background-color: #2c2c2c;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
text-align: center;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
#bottom{
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
color:#878887;
|
||||
background-color: white;
|
||||
font-size: 12px;
|
||||
width: 100%;
|
||||
padding:5px;
|
||||
border-top: 1px solid #878887;
|
||||
}
|
||||
|
||||
#cover{
|
||||
height: calc(100% - 80px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
#navbar{
|
||||
margin:0 auto;
|
||||
max-width: 85%;
|
||||
display: flex;
|
||||
justify-content:flex-end;
|
||||
flex-direction: row;
|
||||
}
|
||||
#book{
|
||||
margin:0 auto;
|
||||
max-width: 85%;
|
||||
max-height: 100%;
|
||||
display: block;
|
||||
justify-content:flex-end;
|
||||
flex-direction: row;
|
||||
text-align: justify;
|
||||
height: 100%;
|
||||
}
|
||||
div.doc-name {
|
||||
width: 300px;
|
||||
text-align: left;
|
||||
padding-top:3px;
|
||||
}
|
||||
div.doc-name a {
|
||||
text-decoration: none;
|
||||
color: #c9c9c9;
|
||||
}
|
||||
|
||||
div.doc-name a:before{
|
||||
/* padding-top:13px; */
|
||||
content: "\f015";
|
||||
color:#c9c9c9;
|
||||
width:20px;
|
||||
height: 25px;
|
||||
font-family: "FontAwesome";
|
||||
font-size: 18px;
|
||||
}
|
||||
input.search-box{
|
||||
outline: none;
|
||||
border: 0;
|
||||
flex:1;
|
||||
padding:0;
|
||||
margin:0;
|
||||
/* padding-top:13px; */
|
||||
height: 25px;
|
||||
background-color: transparent;
|
||||
border-bottom: 1px solid #878887;
|
||||
font-size: 15px;
|
||||
font-family: "Ubuntu";
|
||||
line-height: 0.5;
|
||||
color: #878887;
|
||||
}
|
||||
div.search-icon:before{
|
||||
/* padding-top:13px; */
|
||||
content: "\f002";
|
||||
color:#878887;
|
||||
display: block;
|
||||
width:20px;
|
||||
height: 25px;
|
||||
font-family: "FontAwesome";
|
||||
font-size: 18px;
|
||||
border-bottom: 1px solid #878887;
|
||||
}
|
||||
div.search-icon {
|
||||
width: 35px;
|
||||
}
|
||||
div.doc-toc {
|
||||
width: 300px;
|
||||
/* font-size: 11px; */
|
||||
background-color: #e3e3e3;
|
||||
color: #2c2c2c;
|
||||
overflow: auto;
|
||||
position: fixed;
|
||||
top: 30px;
|
||||
bottom: 30px;
|
||||
border-right: 1px solid #c9c9c9;
|
||||
padding-top: 10px;
|
||||
}
|
||||
div.doc-toc a {
|
||||
text-decoration: none;
|
||||
color: #2c2c2c;
|
||||
}
|
||||
#toc {
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
padding-left: 10px;
|
||||
}
|
||||
div.doc-toc ul.nested {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
div.doc-toc .caret {
|
||||
cursor: pointer;
|
||||
user-select: none; /* Prevent text selection */
|
||||
}
|
||||
div.doc-toc .caret::before {
|
||||
content: "\f147";
|
||||
color: #2c2c2c;
|
||||
display: inline-block;
|
||||
font-family: "FontAwesome";
|
||||
margin-right: 5px;
|
||||
}
|
||||
div.doc-toc .nested {
|
||||
display: none;
|
||||
}
|
||||
div.doc-toc .caret-down::before {
|
||||
content: "\f196";
|
||||
color: #2c2c2c;
|
||||
display: inline-block;
|
||||
font-family: "FontAwesome";
|
||||
margin-right: 5px;
|
||||
}
|
||||
div.doc-toc .active {
|
||||
display: block;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
div.doc-content {
|
||||
display: block;
|
||||
width: calc(100% - 320px);
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* for block of code */
|
||||
/* #container .blogentry .hljs-ln td.hljs-ln-code {
|
||||
padding-left: 10px;
|
||||
} */
|
||||
img {max-width:100%}
|
8
doc/controllers/AntosController.lua
Normal file
8
doc/controllers/AntosController.lua
Normal file
@ -0,0 +1,8 @@
|
||||
require(CONTROLLER_ROOT..".doccontroller")
|
||||
DocController:subclass("AntosController", {
|
||||
path_map = {
|
||||
vfs_path = "home://testws/antos",
|
||||
local_path = "/home/mrsang/testws/antos"
|
||||
},
|
||||
name = "antos"
|
||||
})
|
10
doc/controllers/IndexController.lua
Normal file
10
doc/controllers/IndexController.lua
Normal file
@ -0,0 +1,10 @@
|
||||
BaseController:subclass("IndexController")
|
||||
|
||||
function IndexController:index(...)
|
||||
return true
|
||||
end
|
||||
|
||||
function IndexController:actionnotfound(...)
|
||||
self.template:setView("index")
|
||||
return self:index(table.unpack({...}))
|
||||
end
|
5
doc/controllers/TocController.lua
Normal file
5
doc/controllers/TocController.lua
Normal file
@ -0,0 +1,5 @@
|
||||
BaseController:subclass("TocController")
|
||||
|
||||
function TocController:index(...)
|
||||
return true
|
||||
end
|
107
doc/controllers/doccontroller.lua
Normal file
107
doc/controllers/doccontroller.lua
Normal file
@ -0,0 +1,107 @@
|
||||
BaseController:subclass("DocController")
|
||||
|
||||
local getpath = function(vfspath, controller)
|
||||
return vfspath:gsub(controller.path_map.vfs_path, controller.path_map.local_path)
|
||||
end
|
||||
|
||||
function DocController:loadTOC()
|
||||
local path = self.path_map.local_path.."/meta.json"
|
||||
local result = { error = false}
|
||||
if ulib.exists(path) then
|
||||
local bmeta = JSON.decodeFile(path)
|
||||
if bmeta == nil then
|
||||
result.error = true
|
||||
result.data = "Unable to read book meta.json"
|
||||
else
|
||||
result.data = {
|
||||
name = bmeta.name,
|
||||
path = self.path_map.vfs_path.."/INTRO.md",
|
||||
entries = {}
|
||||
}
|
||||
-- read all the entries
|
||||
for kc,vc in pairs(bmeta.entries) do
|
||||
local cpath = getpath(vc.path, self).."/meta.json"
|
||||
if ulib.exists(cpath) then
|
||||
local cmeta = JSON.decodeFile(cpath)
|
||||
if cmeta then
|
||||
local chapter = {
|
||||
name = cmeta.name,
|
||||
path = vc.path.."/INTRO.md",
|
||||
entries = {}
|
||||
}
|
||||
-- read all sections
|
||||
for ks,vs in pairs(cmeta.entries) do
|
||||
local spath = getpath(vs.path, self).."/meta.json"
|
||||
local smeta = JSON.decodeFile(spath)
|
||||
if smeta then
|
||||
local section = {
|
||||
name = smeta.name,
|
||||
path = vs.path.."/INTRO.md",
|
||||
entries = {}
|
||||
}
|
||||
-- read all files
|
||||
for kf,vf in pairs(smeta.entries) do
|
||||
local fpath = getpath(vf.path, self)
|
||||
if ulib.exists(fpath) then
|
||||
local file = io.open(fpath, "r")
|
||||
io.input(file)
|
||||
local line = io.read()
|
||||
io.close()
|
||||
if line then
|
||||
local file = {
|
||||
name = std.trim(std.trim(line, "#"), " "),
|
||||
path = vf.path
|
||||
}
|
||||
table.insert( section.entries, file)
|
||||
end
|
||||
end
|
||||
end
|
||||
table.insert( chapter.entries, section)
|
||||
end
|
||||
end
|
||||
table.insert( result.data.entries, chapter)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
result.error = true
|
||||
result.data = "No meta-data found"
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function DocController:index(...)
|
||||
local args = {...}
|
||||
local toc = self:loadTOC()
|
||||
toc.controller = self.name
|
||||
self.template:set("toc", toc)
|
||||
-- read data from the parameter
|
||||
local path = nil
|
||||
if args[1] then
|
||||
local b64text = args[1]
|
||||
if b64text then
|
||||
local p = bytes.__tostring(std.b64decode(b64text .. "=="))
|
||||
if p then
|
||||
path = getpath(p, self)
|
||||
end
|
||||
end
|
||||
else
|
||||
path = self.path_map.local_path.."/INTRO.md"
|
||||
end
|
||||
if path and ulib.exists(path) then
|
||||
local file = io.open(path, "r")
|
||||
local content = file:read("*a")
|
||||
file.close()
|
||||
self.template:setView("index", "index")
|
||||
self.template:set("data", content)
|
||||
else
|
||||
self.template:setView("notfound", "index")
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function DocController:actionnotfound(...)
|
||||
local args = {...}
|
||||
return self:index(table.unpack(args))
|
||||
end
|
52
doc/router.lua
Normal file
52
doc/router.lua
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
-- the rewrite rule for the framework
|
||||
-- should be something like this
|
||||
-- ^\/apps\/+(.*)$ = /apps/router.lua?r=<1>&<query>
|
||||
-- some global variables
|
||||
DIR_SEP = "/"
|
||||
WWW_ROOT = __ROOT__.."/doc"
|
||||
if HEADER.Host then
|
||||
HTTP_ROOT= "https://"..HEADER.Host
|
||||
else
|
||||
HTTP_ROOT = "https://doc.iohub.dev"
|
||||
end
|
||||
-- class path: path.to.class
|
||||
BASE_FRW = ""
|
||||
-- class path: path.to.class
|
||||
CONTROLLER_ROOT = BASE_FRW.."doc.controllers"
|
||||
MODEL_ROOT = BASE_FRW.."doc.models"
|
||||
-- file path: path/to/file
|
||||
VIEW_ROOT = WWW_ROOT..DIR_SEP.."views"
|
||||
LOG_ROOT = WWW_ROOT..DIR_SEP.."logs"
|
||||
POST_LIMIT = 10
|
||||
-- require needed library
|
||||
require(BASE_FRW.."silk.api")
|
||||
|
||||
if REQUEST.r then
|
||||
REQUEST.r = REQUEST.r:gsub("%:", "/")
|
||||
end
|
||||
|
||||
-- registry object store global variables
|
||||
local REGISTRY = {}
|
||||
-- set logging level
|
||||
REGISTRY.logger = Logger:new{ levels = {INFO = false, ERROR = true, DEBUG = false}}
|
||||
REGISTRY.layout = 'default'
|
||||
REGISTRY.fileaccess = true
|
||||
|
||||
local router = Router:new{registry = REGISTRY}
|
||||
REGISTRY.router = router
|
||||
router:setPath(CONTROLLER_ROOT)
|
||||
--router:route('edit', 'post/edit', "ALL" )
|
||||
|
||||
-- example of depedencies to the current main route
|
||||
-- each layout may have different dependencies
|
||||
local default_routes_dependencies = {
|
||||
toc = {
|
||||
url = "toc/index",
|
||||
visibility = "ALL"
|
||||
}
|
||||
}
|
||||
router:route('default', default_routes_dependencies )
|
||||
--router:remap("r", "post")
|
||||
router:delegate()
|
||||
|
4
doc/views/default/index/index.ls
Normal file
4
doc/views/default/index/index.ls
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
<?lua
|
||||
echo(data)
|
||||
?>
|
1
doc/views/default/index/notfound.ls
Normal file
1
doc/views/default/index/notfound.ls
Normal file
@ -0,0 +1 @@
|
||||
404 not found
|
93
doc/views/default/layout.ls
Normal file
93
doc/views/default/layout.ls
Normal file
@ -0,0 +1,93 @@
|
||||
<?lua
|
||||
local tocdata = __main__:get("toc")
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="<?=HTTP_ROOT?>/rst/gscripts/showdown.min.js"
|
||||
></script>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="<?=HTTP_ROOT?>/assets/style.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="<?=HTTP_ROOT?>/rst/font-awesome.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="<?=HTTP_ROOT?>/rst/ubuntu-regular.css" />
|
||||
<title>
|
||||
<?lua
|
||||
if tocdata then
|
||||
echo(tocdata.data.name)
|
||||
else
|
||||
echo("Untitled")
|
||||
end
|
||||
?>
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id = "top">
|
||||
<div id = "navbar">
|
||||
<div class = "doc-name">
|
||||
<?lua if tocdata then ?>
|
||||
<a href ="<?=HTTP_ROOT..'/'..tocdata.controller..'/'?>">
|
||||
<?=tocdata.data.name?>
|
||||
</a>
|
||||
<?lua end ?>
|
||||
</div>
|
||||
<input type = "text" class = "search-box"></input>
|
||||
<div class= "search-icon"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id = "cover">
|
||||
<div id = "book">
|
||||
<div class = "doc-toc">
|
||||
<?lua
|
||||
if toc then
|
||||
toc:set("data", tocdata)
|
||||
toc:render()
|
||||
end
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="doc-content">
|
||||
<?lua
|
||||
if __main__ then
|
||||
__main__:render()
|
||||
end
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id = "bottom">
|
||||
Powered by antd server, (c) 2019 - <?=os.date("*t").year?> Xuan Sang LE
|
||||
</div>
|
||||
<script>
|
||||
window.onload = function () {
|
||||
var els = document.getElementsByClassName("doc-content");
|
||||
var converter = new showdown.Converter();
|
||||
for (var i in els) {
|
||||
var text = els[i].innerHTML;
|
||||
var html = converter.makeHtml(text);
|
||||
els[i].innerHTML = html;
|
||||
}
|
||||
// tree view events
|
||||
var toggler = document.getElementsByClassName("caret");
|
||||
var i;
|
||||
for (i = 0; i < toggler.length; i++) {
|
||||
toggler[i].addEventListener("click", function() {
|
||||
this.parentElement.querySelector(".nested").classList.toggle("active");
|
||||
this.classList.toggle("caret-down");
|
||||
});
|
||||
}
|
||||
// TODO math display
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
31
doc/views/default/toc/index.ls
Normal file
31
doc/views/default/toc/index.ls
Normal file
@ -0,0 +1,31 @@
|
||||
<?lua
|
||||
gentree = function(data, controller)
|
||||
if not data then
|
||||
return ""
|
||||
end
|
||||
local caret = ''
|
||||
if data.entries then
|
||||
caret = '<span class = "caret"></span>'
|
||||
end
|
||||
local markup = '<li>'..caret..'<a href="'..HTTP_ROOT..'/'..controller..'/'..std.b64encode(data.path):gsub("=","")..'/'..data.name:gsub(" ", "_")..'.md">'..data.name.."</a>"
|
||||
if data.entries then
|
||||
markup = markup.."<ul class='nested'>"
|
||||
for k,v in pairs(data.entries) do
|
||||
markup = markup..gentree(v, controller)
|
||||
end
|
||||
markup = markup.."</ul>"
|
||||
end
|
||||
markup = markup.."</li>"
|
||||
return markup
|
||||
end
|
||||
?>
|
||||
<ul id = "toc">
|
||||
<?lua
|
||||
if data.error then
|
||||
return echo("Unable to read toc")
|
||||
end
|
||||
for k,v in pairs(data.data.entries) do
|
||||
echo(gentree(v, data.controller))
|
||||
end
|
||||
?>
|
||||
</ul>
|
@ -49,7 +49,7 @@
|
||||
?>
|
||||
<div class = "container_footer">
|
||||
<h1 style="margin:0;"></h1>
|
||||
<p style="text-align:right; padding:0; margin:0;color:#878887;">Powered by antd server, (C) 2017-2018 Xuan Sang LE</p>
|
||||
<p style="text-align:right; padding:0; margin:0;color:#878887;">Powered by antd server, (C) 2017-<?=os.date("*t").year?> Xuan Sang LE</p>
|
||||
</div>
|
||||
</div>
|
||||
<?lua
|
||||
|
@ -73,7 +73,8 @@ function Router:infer(url)
|
||||
-- create the coresponding controller
|
||||
data.controller = _G[controller_name]:new {registry = self.registry}
|
||||
if not data.controller[data.action] then
|
||||
data.args = {data.action}
|
||||
--data.args = {data.action}
|
||||
table.insert(data.args, 1, data.action)
|
||||
data.action = "actionnotfound"
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user