Compare commits
No commits in common. "c1272788f011dfac20f1b2f2b21fbc074e8f8f81" and "bb3070aa1a3008fc9517dc7b01a5baea688aec6f" have entirely different histories.
c1272788f0
...
bb3070aa1a
|
@ -96,16 +96,15 @@ VIEW_URI=/
|
||||||
schema, self.path.database, sort_keys=True, indent=4, separators=(",", ": ")
|
schema, self.path.database, sort_keys=True, indent=4, separators=(",", ": ")
|
||||||
)
|
)
|
||||||
|
|
||||||
self.theme = Path(__file__).parent / "themes" / self.config.THEME
|
self.theme = Path(__file__).parent / "themes" / "default"
|
||||||
|
|
||||||
self.web = Flask(self.config.NAME, template_folder=self.theme, static_folder=self.theme / 'static')
|
self.web = Flask(self.config.NAME, template_folder=self.theme)
|
||||||
self.web.config["SECRET_KEY"] = self.config.SECRET_KEY
|
self.web.config["SECRET_KEY"] = self.config.SECRET_KEY
|
||||||
self.web.config["SEND_FILE_MAX_AGE_DEFAULT"] = 0
|
self.web.config["SEND_FILE_MAX_AGE_DEFAULT"] = 0
|
||||||
self.web.config["DEBUG"] = True
|
self.web.config["DEBUG"] = True
|
||||||
self.web.config["SESSION_TYPE"] = "filesystem"
|
self.web.config["SESSION_TYPE"] = "filesystem"
|
||||||
self.web.config["SESSION_REFRESH_EACH_REQUEST"] = True
|
self.web.config["SESSION_REFRESH_EACH_REQUEST"] = True
|
||||||
self.web.config["SESSION_FILE_DIR"] = self.path.sessions
|
self.web.config["SESSION_FILE_DIR"] = self.path.sessions
|
||||||
|
|
||||||
Session(self.web)
|
Session(self.web)
|
||||||
|
|
||||||
self._initialized = True
|
self._initialized = True
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
from ttfrog import app, schema
|
|
||||||
|
|
||||||
TEMPLATE = """
|
|
||||||
# Heading 1
|
|
||||||
|
|
||||||
## Heading 2
|
|
||||||
|
|
||||||
### Heading 3
|
|
||||||
|
|
||||||
#### Heading 4
|
|
||||||
|
|
||||||
##### Heading 5
|
|
||||||
|
|
||||||
###### Heading 6
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
Normal text.
|
|
||||||
**Bold text.**
|
|
||||||
*Italic Text.*
|
|
||||||
[A link](/).
|
|
||||||
|
|
||||||
1. a
|
|
||||||
2. numbered
|
|
||||||
3. list.
|
|
||||||
|
|
||||||
> a block quote
|
|
||||||
|
|
||||||
| A | Table | Section |
|
|
||||||
| --- | ----- | ------- |
|
|
||||||
| foo | bar | baz |
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def bootstrap():
|
|
||||||
"""
|
|
||||||
Bootstrap the database entries by populating the first Page, the Admin user and the Admins group.
|
|
||||||
"""
|
|
||||||
app.check_state()
|
|
||||||
|
|
||||||
# create the top-level pages
|
|
||||||
root = app.db.save(schema.Page(name=app.config.VIEW_URI, title="Home", body="This is the home page"))
|
|
||||||
|
|
||||||
users = root.add_member(schema.Page(name="User", title="Users", body="users go here."))
|
|
||||||
groups = root.add_member(schema.Page(name="Group", title="Groups", body="groups go here."))
|
|
||||||
npcs = root.add_member(schema.Page(name="NPC", title="NPCS!", body="NPCS!"))
|
|
||||||
wiki = root.add_member(schema.Page(name="Wiki", title="Wiki", body=TEMPLATE))
|
|
||||||
|
|
||||||
# create the NPCs
|
|
||||||
npcs.add_member(schema.NPC(name="Sabetha", body=""))
|
|
||||||
npcs.add_member(schema.NPC(name="John", body=""))
|
|
||||||
|
|
||||||
# create the users
|
|
||||||
guest = users.add_member(schema.User(name="guest"))
|
|
||||||
admin = users.add_member(
|
|
||||||
schema.User(name=app.config.ADMIN_USERNAME, password="fnord", email=app.config.ADMIN_EMAIL)
|
|
||||||
)
|
|
||||||
|
|
||||||
# create the admin user and admins group
|
|
||||||
admins = groups.add_member(schema.Group(name="administrators", members=[admin]))
|
|
||||||
|
|
||||||
# admins get full access
|
|
||||||
root.set_permissions(
|
|
||||||
admins, permissions=[schema.Permissions.READ, schema.Permissions.WRITE, schema.Permissions.DELETE]
|
|
||||||
)
|
|
||||||
|
|
||||||
# guests get read access by default, except on Groups and Users
|
|
||||||
groups.set_permissions(guest, permissions=[])
|
|
||||||
users.set_permissions(guest, permissions=[])
|
|
||||||
root.set_permissions(guest, permissions=[schema.Permissions.READ])
|
|
|
@ -1,38 +1,47 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
{% block head %}
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>{% block title %}TTFROG{% endblock %}</title>
|
<title>{% block title %}TTFROG{% endblock %}</title>
|
||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='site.css' ) }}">
|
<link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||||
{% block styles %}
|
{% block styles %}
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css' ) }}">
|
||||||
|
{% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<form id='data_form' method='POST'>
|
<nav>
|
||||||
<input type="hidden" id="data_form__id" name="uid" value="{{ page.uid }}">
|
{% for uri, name in breadcrumbs %}
|
||||||
<input name='title' id="data_form__title" type='text' value="{{ page.title }}">
|
<span> / <a href="{{ app.config.VIEW_URI }}{{ uri }}">{{ name }}</a></span>
|
||||||
<textarea name="body" id="data_form__body">{{ page.body }}</textarea>
|
{% endfor %}
|
||||||
</form>
|
</nav>
|
||||||
|
{% if session['user_id'] == 1 %}
|
||||||
|
Welcome, {{ user['name'] }}. [ <a href="{{ url_for('login') }}">LOGIN</a> ]
|
||||||
|
{% else %}
|
||||||
|
Welcome, <a href="{{ url_for('view', path='User/' + user['name']) }}">{{ user['name'] }}</a>.
|
||||||
|
{% endif %}
|
||||||
|
<nav>
|
||||||
|
Menu:
|
||||||
|
<ul>
|
||||||
|
{% block menu %}{% endblock %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
Last Edited By: {{ page.author.name }}
|
||||||
|
<br>
|
||||||
|
|
||||||
{% block nav %}
|
<main>
|
||||||
{% include "nav.html" %}
|
{% for message in g.messages %}
|
||||||
|
<div class="alert">
|
||||||
|
{{ message }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
{% block footer %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
<div class='table-wrapper'>
|
</footer>
|
||||||
<main>
|
|
||||||
{% for message in g.messages %}
|
|
||||||
<div class="alert">
|
|
||||||
{{ message }}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% block content %}{% endblock %}
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
<footer>
|
|
||||||
{% block footer %}
|
|
||||||
fnord
|
|
||||||
{% endblock %}
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
{% block scripts %}{% endblock %}
|
{% block scripts %}{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
<div id='breadcrumbs'>
|
|
||||||
<a href="{{ url_for('index') }}">Home</a>{% for (uri, name) in breadcrumbs %}.<a href="{{ uri }}">{{ name }}</a>{% endfor %}
|
|
||||||
<div id='actions'>
|
|
||||||
<a id='action__edit' data-state='view'>edit</a>
|
|
||||||
<a id='action__save' style='display: none;'>save</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,12 +0,0 @@
|
||||||
|
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block content %}
|
|
||||||
<form method='POST'>
|
|
||||||
<h1>Login</h1>
|
|
||||||
Username: <input type="text" name="username">
|
|
||||||
<br>
|
|
||||||
Password: <input type="password" name="password">
|
|
||||||
<br>
|
|
||||||
<input type="submit">
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
|
|
@ -1,45 +0,0 @@
|
||||||
<nav>
|
|
||||||
<ul class="container">
|
|
||||||
<li><a href='{{ root.uri }}'>Home</a></li>
|
|
||||||
{% for subpage in root.members %}
|
|
||||||
{% if user.can_read(subpage) %}
|
|
||||||
<li><a href="{{ url_for('view', path=subpage.uri) }}">{{ subpage.name }}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
<li class='user'>
|
|
||||||
{% if user.name == 'guest' %}
|
|
||||||
Welcome, {{ user.name }}. [ <a href="{{ url_for('login') }}">Login</a> ]
|
|
||||||
{% else %}
|
|
||||||
Welcome, <a href="{{ url_for('view', path=user.uri) }}">{{ user.name }}</a>.
|
|
||||||
[<a href="{{ url_for('logout') }}">Logout</a>]
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
<!--
|
|
||||||
<li class='dropdown'>
|
|
||||||
<a href='#'>Pages <i class="fa fa-angle-down"></i></a>
|
|
||||||
<div class='mega-menu'>
|
|
||||||
<div class="container">
|
|
||||||
<div class="item">
|
|
||||||
<h3>Home Page</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href='#'>Home Page No #1</a></li>
|
|
||||||
<li><a href='#'>Home Page No #2</a></li>
|
|
||||||
<li><a href='#'>Home Page No #3</a></li>
|
|
||||||
<li><a href='#'>Home Page No #4</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<</div>
|
|
||||||
</li>
|
|
||||||
-->
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
<menu>
|
|
||||||
<ul class="container">
|
|
||||||
{% for member in page.members %}
|
|
||||||
{% if user.can_read(member) %}
|
|
||||||
<li><a href="{{ app.config.VIEW_URI }}{{ member.uri }}">{{ member.name }}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</menu>
|
|
|
@ -1,60 +1,26 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block styles %}
|
{% block menu %}
|
||||||
<link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" />
|
{% for member in page.members %}
|
||||||
|
<li><a href="{{ app.config.VIEW_URI }}{{ member.uri }}">{{ member.name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% include "breadcrumbs.html" %}
|
<form method='POST'>
|
||||||
<div id='viewer'></div>
|
<input type="hidden" name="uid" value="{{ page.uid }}">
|
||||||
<div id='editor'></div>
|
<h1>{{ page.doc_id }}: <input name='title' type='text' value="{{ page.title }}"></h1>
|
||||||
|
<h3>{{ app.config.VIEW_URI }}{{ page.parent.uri if page.parent else "/" }} <input name='stub' type='text' value='{{ page.stub }}'></h3>
|
||||||
|
<textarea name='body'>{{ page.body }}</textarea>
|
||||||
|
<input type=submit>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
{{ page }}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
{{ app.web.config }}
|
||||||
|
</pre>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% block scripts %}
|
|
||||||
<script src="https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js"></script>
|
|
||||||
<script>
|
|
||||||
const viewerEl = document.querySelector("#viewer");
|
|
||||||
const editorEl = document.querySelector("#editor");;
|
|
||||||
|
|
||||||
const initialValue = (
|
|
||||||
"# " + document.getElementById("data_form__title").value +
|
|
||||||
"\n" +
|
|
||||||
document.getElementById("data_form__body").value
|
|
||||||
);
|
|
||||||
|
|
||||||
const editor = new toastui.Editor({
|
|
||||||
el: editorEl,
|
|
||||||
initialEditType: 'wysiwyg',
|
|
||||||
initialValue: initialValue,
|
|
||||||
minHeight: '500px',
|
|
||||||
previewStyle: 'tab',
|
|
||||||
usageStatistics: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const edit_btn = document.querySelector("#action__edit");
|
|
||||||
const save_btn = document.querySelector("#action__save");
|
|
||||||
|
|
||||||
toggleEditor = function() {
|
|
||||||
if (edit_btn.dataset.state == 'view') {
|
|
||||||
edit_btn.dataset.state = 'edit';
|
|
||||||
edit_btn.innerText = "discard draft";
|
|
||||||
viewerEl.style['display'] = "none";
|
|
||||||
editorEl.style['display'] = "inline";
|
|
||||||
save_btn.style['display'] = 'inline-block';
|
|
||||||
} else {
|
|
||||||
edit_btn.dataset.state = 'view';
|
|
||||||
edit_btn.innerText = "edit";
|
|
||||||
editorEl.style['display'] = "none";
|
|
||||||
viewerEl.style['display'] = "inline";
|
|
||||||
save_btn.style['display'] = 'none';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
edit_btn.addEventListener('click', toggleEditor)
|
|
||||||
viewerEl.innerHTML = editor.getHTML();
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
@ -1,261 +0,0 @@
|
||||||
@import "theme.css";
|
|
||||||
|
|
||||||
html {
|
|
||||||
padding: 0px;
|
|
||||||
margin: 0px;
|
|
||||||
height: 100vh;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
font-family: var(--default-font-family);
|
|
||||||
font-size: var(--default-font-size);
|
|
||||||
height: inherit;
|
|
||||||
width: 100%;
|
|
||||||
margin: 0px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
overflow-y: scroll;
|
|
||||||
scrollbar-gutter: stable;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, .toastui-editor-contents h1 {
|
|
||||||
font-size: var(--h1-size) !important;
|
|
||||||
font-weight: var(--header-weight) !important;
|
|
||||||
font-family: var(--header-font) !important;
|
|
||||||
text-decoration: inherit !important;
|
|
||||||
font-variant: inherit !important;
|
|
||||||
border: none !important;
|
|
||||||
margin: initial !important;
|
|
||||||
line-height: initial !important;
|
|
||||||
padding: initial !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
h2, .toastui-editor-contents h2 {
|
|
||||||
font-size: var(--h2-size) !important;
|
|
||||||
font-weight: var(--header2-weight) !important;
|
|
||||||
font-family: var(--header-font) !important;
|
|
||||||
text-decoration: inherit !important;
|
|
||||||
font-variant: inherit !important;
|
|
||||||
border: none !important;
|
|
||||||
margin: initial !important;
|
|
||||||
line-height: initial !important;
|
|
||||||
padding: initial !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
h3, .toastui-editor-contents h3 {
|
|
||||||
font-size: var(--h3-size) !important;
|
|
||||||
font-weight: var(--header3-weight) !important;
|
|
||||||
font-family: var(--header-font) !important;
|
|
||||||
text-decoration: inherit !important;
|
|
||||||
font-variant: inherit !important;
|
|
||||||
border: none !important;
|
|
||||||
margin: initial !important;
|
|
||||||
line-height: initial !important;
|
|
||||||
padding: initial !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
h4, .toastui-editor-contents h4 {
|
|
||||||
font-size: var(--h4-size) !important;
|
|
||||||
font-weight: var(--header4-weight) !important;
|
|
||||||
font-family: var(--header-font) !important;
|
|
||||||
text-decoration: inherit !important;
|
|
||||||
font-variant: inherit !important;
|
|
||||||
border: none !important;
|
|
||||||
margin: initial !important;
|
|
||||||
line-height: initial !important;
|
|
||||||
padding: initial !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
h5, .toastui-editor-contents h5 {
|
|
||||||
font-size: var(--h5-size) !important;
|
|
||||||
font-weight: var(--header5-weight) !important;
|
|
||||||
font-family: var(--header-font) !important;
|
|
||||||
text-decoration: inherit !important;
|
|
||||||
font-variant: inherit !important;
|
|
||||||
border: none !important;
|
|
||||||
margin: initial !important;
|
|
||||||
line-height: initial !important;
|
|
||||||
padding: initial !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
h6, .toastui-editor-contents h6 {
|
|
||||||
font-size: var(--h6-size) !important;
|
|
||||||
font-weight: var(--header6-weight) !important;
|
|
||||||
font-family: var(--header-font) !important;
|
|
||||||
text-decoration: inherit !important;
|
|
||||||
font-variant: inherit !important;
|
|
||||||
border: none !important;
|
|
||||||
margin: initial !important;
|
|
||||||
line-height: initial !important;
|
|
||||||
padding: initial !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
a {text-decoration: none;}
|
|
||||||
|
|
||||||
nav ul.container {
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding-left: 0;
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav {
|
|
||||||
display: block;
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
height: var(--nav-height);
|
|
||||||
background: #0ca0d6;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav > ul > li {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 14px;
|
|
||||||
padding: 0 15px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav > ul > li > a {
|
|
||||||
color: #fff;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 20px 0;
|
|
||||||
border-bottom: 3px solid transparent;
|
|
||||||
transition: all .3s ease;
|
|
||||||
}
|
|
||||||
nav > ul > li:hover > a {
|
|
||||||
color: #444;
|
|
||||||
border-bottom: 3px solid #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mega-menu {
|
|
||||||
background: #eee;
|
|
||||||
visibility: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
transition: visibility 0s, opacity 0.5s linear;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
padding-bottom: 20px;
|
|
||||||
}
|
|
||||||
.mega-menu h3 {color: #444;}
|
|
||||||
|
|
||||||
.mega-menu .container {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.mega-menu .item {
|
|
||||||
flex-grow: 1;
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
.mega-menu .item img {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.mega-menu a {
|
|
||||||
border-bottom: 1px solid #ddd;
|
|
||||||
color: #4ea3d8;
|
|
||||||
display: block;
|
|
||||||
padding: 10px 0;
|
|
||||||
}
|
|
||||||
.mega-menu a:hover {color: #2d6a91;}
|
|
||||||
|
|
||||||
|
|
||||||
.dropdown {position: static;}
|
|
||||||
|
|
||||||
.dropdown:hover .mega-menu {
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#breadcrumbs {
|
|
||||||
height: var(--breadcrumbs-height);
|
|
||||||
border-bottom: 1px dotted #DEDEDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#data_form {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#editor {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#viewer {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#actions {
|
|
||||||
display: flex;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
#actions > a {
|
|
||||||
display: flex;
|
|
||||||
border: 1px solid black;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 5px;
|
|
||||||
background: #FFF;
|
|
||||||
color: blue;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-left: 5px;
|
|
||||||
|
|
||||||
}
|
|
||||||
#actions a:hover {
|
|
||||||
color: white;
|
|
||||||
background: blue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.table-wrapper {
|
|
||||||
padding: 0px;
|
|
||||||
padding-top: var(--wrapper-padding);
|
|
||||||
display: table;
|
|
||||||
margin: auto;
|
|
||||||
width: var(--max-width);
|
|
||||||
max-width: 960px;
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
display: table-row;
|
|
||||||
height: var(--main-height);
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
bottom: 100vh - var(--footer-height);
|
|
||||||
height: var(--footer-height);
|
|
||||||
background-color: #DEDEDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toastui-editor-main-container {
|
|
||||||
display: contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toastui-editor,
|
|
||||||
.toastui-editor-main,
|
|
||||||
.toastui-editor-md-container,
|
|
||||||
.toastui-editor-defaultUI,
|
|
||||||
.toastui-editor-contents,
|
|
||||||
.toastui-editor-ww-mode,
|
|
||||||
.toastui-editor-md-preview,
|
|
||||||
.toastui-editor-md,
|
|
||||||
.ProseMirror {
|
|
||||||
border: 0px !important;
|
|
||||||
padding: 0px !important;
|
|
||||||
margin: 0px !important;
|
|
||||||
font-size: var(--default-font-size) !important;
|
|
||||||
font-family: var(--default-font-family) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
menu {
|
|
||||||
display: none;
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
:root {
|
|
||||||
/* Typography */
|
|
||||||
--default-font-family: sans-serif;
|
|
||||||
--default-font-size: 16px;
|
|
||||||
--header-font: sans-serif;
|
|
||||||
--header-weight: 700;
|
|
||||||
--h1-size: 32px;
|
|
||||||
--h2-size: 24px;
|
|
||||||
--h3-size: 18.72px;
|
|
||||||
--h4-size: 16px;
|
|
||||||
--h5-size: 13.28px;
|
|
||||||
--h6-size: 10.72px;
|
|
||||||
|
|
||||||
/* Layout */
|
|
||||||
--nav-height: 50px;
|
|
||||||
--footer-height: 150px;
|
|
||||||
--breadcrumbs-height: 50px;
|
|
||||||
--wrapper-padding: 20px;
|
|
||||||
--main-height: calc(100vh - var(--nav-height) - var(--footer-height) - var(--breadcrumbs-height) + var(--wrapper-padding));
|
|
||||||
--max-width: calc(100vw - 20px);
|
|
||||||
}
|
|
|
@ -3,6 +3,8 @@ from tinydb import where
|
||||||
|
|
||||||
from ttfrog import app, forms, schema
|
from ttfrog import app, forms, schema
|
||||||
|
|
||||||
|
STATIC = ["static"]
|
||||||
|
|
||||||
|
|
||||||
def relative_uri(path: str = ""):
|
def relative_uri(path: str = ""):
|
||||||
"""
|
"""
|
||||||
|
@ -21,12 +23,12 @@ def get_parent(table: str, uri: str):
|
||||||
return get_page(parent_uri, table=table if "/" in parent_uri else "Page", create_okay=False)
|
return get_page(parent_uri, table=table if "/" in parent_uri else "Page", create_okay=False)
|
||||||
|
|
||||||
|
|
||||||
def get_page(path: str, table: str = "Page", create_okay: bool = False):
|
def get_page(path: str = "", table: str = "Page", create_okay: bool = False):
|
||||||
"""
|
"""
|
||||||
Get one page, including its members, but not recursively.
|
Get one page, including its members, but not recursively.
|
||||||
"""
|
"""
|
||||||
uri = relative_uri(path)
|
uri = path.strip("/") or relative_uri(request.path)
|
||||||
|
app.web.logger.debug(f"Need a page in {table} for {uri = }")
|
||||||
if table not in app.db.tables():
|
if table not in app.db.tables():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -56,31 +58,29 @@ def get_page(path: str, table: str = "Page", create_okay: bool = False):
|
||||||
def rendered(page: schema.Record, template: str = "page.html"):
|
def rendered(page: schema.Record, template: str = "page.html"):
|
||||||
if not page:
|
if not page:
|
||||||
return Response("Page not found", status=404)
|
return Response("Page not found", status=404)
|
||||||
|
return render_template(template, page=page, app=app, breadcrumbs=breadcrumbs(), user=session["user"], g=g)
|
||||||
|
|
||||||
return render_template(
|
|
||||||
template,
|
def get_static(path):
|
||||||
page=page,
|
return Response("OK", status=200)
|
||||||
app=app,
|
|
||||||
breadcrumbs=breadcrumbs(),
|
|
||||||
root=g.root,
|
|
||||||
user=g.user,
|
|
||||||
g=g
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def breadcrumbs():
|
def breadcrumbs():
|
||||||
"""
|
"""
|
||||||
Return (uri, name) pairs for the parents leading from the VIEW_URI to the current request.
|
Return (uri, name) pairs for the parents leading from the VIEW_URI to the current request.
|
||||||
"""
|
"""
|
||||||
|
if app.config.VIEW_URI != "/":
|
||||||
|
root = get_page()
|
||||||
|
yield (app.config.VIEW_URI, root.name)
|
||||||
uri = ""
|
uri = ""
|
||||||
for name in relative_uri().split("/"):
|
for name in relative_uri().split("/"):
|
||||||
uri = "/".join([uri, name])
|
uri = "/".join([uri, name]).lstrip("/")
|
||||||
yield (uri, name)
|
yield (uri, name)
|
||||||
|
|
||||||
|
|
||||||
@app.web.route(app.config.VIEW_URI)
|
@app.web.route("/")
|
||||||
def index():
|
def index():
|
||||||
return rendered(get_page(app.config.VIEW_URI, create_okay=False))
|
return rendered(get_page(create_okay=False))
|
||||||
|
|
||||||
|
|
||||||
@app.web.route("/login", methods=["GET", "POST"])
|
@app.web.route("/login", methods=["GET", "POST"])
|
||||||
|
@ -94,6 +94,7 @@ def login():
|
||||||
g.user = user
|
g.user = user
|
||||||
session["user_id"] = g.user.doc_id
|
session["user_id"] = g.user.doc_id
|
||||||
session["user"] = dict(g.user.serialize())
|
session["user"] = dict(g.user.serialize())
|
||||||
|
app.web.logger.debug(f"Session for {user.name} ({user.doc_id}) started.")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
g.messages.append(f"Invalid login for {username}")
|
g.messages.append(f"Invalid login for {username}")
|
||||||
return rendered(schema.Page(name="Login", title="Please enter your login details"), "login.html")
|
return rendered(schema.Page(name="Login", title="Please enter your login details"), "login.html")
|
||||||
|
@ -111,8 +112,7 @@ def logout():
|
||||||
@app.web.route(f"{app.config.VIEW_URI}/<path:path>", methods=["GET"], defaults={"table": "Page"})
|
@app.web.route(f"{app.config.VIEW_URI}/<path:path>", methods=["GET"], defaults={"table": "Page"})
|
||||||
def view(table, path):
|
def view(table, path):
|
||||||
parent = get_parent(table, relative_uri())
|
parent = get_parent(table, relative_uri())
|
||||||
page = get_page(request.path, table=table, create_okay=(parent and parent.doc_id is not None))
|
return rendered(get_page(request.path, table=table, create_okay=(parent and parent.doc_id is not None)))
|
||||||
return rendered(page)
|
|
||||||
|
|
||||||
|
|
||||||
@app.web.route(f"{app.config.VIEW_URI}/<path:table>/<path:path>", methods=["POST"])
|
@app.web.route(f"{app.config.VIEW_URI}/<path:table>/<path:path>", methods=["POST"])
|
||||||
|
@ -146,7 +146,6 @@ def before_request():
|
||||||
g.user = app.db.User.get(doc_id=user_id)
|
g.user = app.db.User.get(doc_id=user_id)
|
||||||
session["user_id"] = user_id
|
session["user_id"] = user_id
|
||||||
session["user"] = dict(g.user.serialize())
|
session["user"] = dict(g.user.serialize())
|
||||||
g.root = get_page(app.config.VIEW_URI)
|
|
||||||
|
|
||||||
|
|
||||||
@app.web.after_request
|
@app.web.after_request
|
||||||
|
|
Loading…
Reference in New Issue
Block a user