Initial commit

This commit is contained in:
2017-09-24 18:07:50 +02:00
commit 7d7642ead6
11 changed files with 316 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
/cards/
__pycache__
*.pyc
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
import glob, os
from yaml import load, dump
from common import Model
import config
class Card(Model):
filename = "[[filename_without_file_extention]]"
title = "[[title]]"
figure = "code"#https://material.io/icons/
description = "[[description]]"
steps = ["Do a", "Then do b"]
cost = "[[cost]]"
power = "[[power]]"
cp = "[[cp]]"
flags = []
def has_flag(self, flag): return flag in self.flags
def from_file(filename, in_carddir=True):#yaml syntax
os.path.join(config.carddir, filename) if in_carddir else filename
ret = Card()
ret.filename = ".".join(os.path.basename(filename).split(".")[:-1])
with open(os.path.join(config.carddir, filename) if in_carddir else filename, "r") as f:
for key, val in load(f.read()).items():
setattr(ret, key, val)
return ret
def from_dir(path):
return [from_file(i, in_carddir=False) for i in glob.glob(os.path.join(path, "*.yaml"))]
View File
+63
View File
@@ -0,0 +1,63 @@
import airspeed, config, os, html
def readfile(path, binary=False):
with open(path, "rb" if binary else "r") as f:
return f.read()
def escape_html(data):
return html.escape(str(data))
def escape_url(data):
return "ølailsf"
class Model:
def __setattr__(self, name, value):
if not hasattr(self, name):
raise Exception(f"{self.__class__.__name__} has no attribute {name!r}")
super(Model, self).__setattr__(name, value)
def __repr__(self):
return "Card(%s)" % \
", ".join(f"{i}={getattr(self, i)!r}" for i in dir(self) if "_" not in i)
__str__ = __repr__
#decorators with parameters:
def withResource(path, binary=False):
data = readfile(os.path.join(config.resourcedir, path), binary)
def decorator(func):
def newfunc(*args, **kwargs):
if not config.cache:
with open(os.path.join(config.resourcedir, path), "rb" if binary else "r") as f:
content = f.read()
else:
content = data
if "file" in kwargs:
kwargs["file"][os.path.basename(path)] = content
else:
kwargs["file"] = {os.path.basename(path): content}
return func(*args, **kwargs)
return newfunc
return decorator
def withTemplate(path):
template = airspeed.Template(readfile(os.path.join(config.resourcedir, path)))
def decorator(func):
def newfunc(*args, **kwargs):
if not config.cache:
t = airspeed.Template(readfile(os.path.join(config.resourcedir, path)))
else:
t = template
class T:
def merge(self, objects):
objects.update({"escape_html":escape_html, "escape_url":escape_url})
return t.merge(objects)
if "template" in kwargs:
kwargs["template"][os.path.basename(path)] = T()
else:
kwargs["template"] = {os.path.basename(path): T()}
return func(*args, **kwargs)
return newfunc
return decorator
+3
View File
@@ -0,0 +1,3 @@
cache = False
resourcedir = "resources/"
carddir = "cards/"
+3
View File
@@ -0,0 +1,3 @@
airspeed
sanic
PyYAML
+114
View File
@@ -0,0 +1,114 @@
* {
margin: 0; padding: 0; border: 0;
}
@page {
size: A4;
margin: 1.2cm;
}
:root {
font-family: sans-serif;
font-size: 3mm;
font-weight: 300;
}
body {
width: 21cm;
height: 29.7cm;
}
article {
margin: 3mm 5mm;
display: block;
float: left;
width: 5.5cm;
height: 8.9cm;
display: grid;
grid-template-columns: 2fr 1fr;
grid-template-rows: 2em 18mm 1.3em auto 1.5em;
grid-template-areas:
"header header"
"figure figure"
"cost cost"
"info info"
"power cp";
border-radius: 2mm;
grid-gap: 2mm 2mm;
border-style: solid;
border-width: 2mm;
border-color: #333;
background-color: #333;
}
article >* {
background-color: #ddd;
text-align: center;
line-height: 1.4em;
padding: 0 1mm;
}
article h1 {
grid-area: header;
font-size: 1em;
padding: 1mm 0;
font-size: 1.1em;
font-weight: 600;
}
article figure {
grid-area: figure;
background: #333;
}
article figure img{
height: 100%;
width: auto;
}
article figure .material-icons.figure {
font-size: 1.7cm;
color: #999;
}
article main {
padding: 2mm 0;
grid-area: info;
position: relative;
}
article main ol {
margin-top: 1mm;
text-align: left;
padding-left: 6mm;
}
article main ol li + li{
margin-top: 0.5mm;
}
article main big{
font-size: 1.5em;
}
article main .bottom {
width: 100%;
position: absolute;
bottom: 2mm;
}
article .power {
grid-area: power;
text-align: left;
}
article .power:before{
content: "Power: ";
font-size: 0.7em;
}
article .cost {
grid-area: cost;
}
article .cp {
grid-area: cp;
text-align: right;
}
article .cp:after{
content: " CP";
font-size: 0.7em;
}
+42
View File
@@ -0,0 +1,42 @@
<!DOCTYPE html>
<link rel="stylesheet" href="card.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
#foreach($card in $cards)
<article>
<h1>
$escape_html($card.title)
</h1>
<figure>
<!--https://material.io/icons/-->
<i class="material-icons figure">$escape_html($card.figure)</i>
</figure>
<main>
$escape_html($card.description)
<ol>
#foreach($item in $card.steps)
<li>$escape_html($item)</li>
#end
</ol>
#if($card.flags)
<div class="bottom">
<small>-
#foreach($flag in $card.flags)
$escape_html($flag.capitalize()) -
#end
</small>
<br>
#if($card.has_flag("mastery"))
<big>
&#x274F; &#x274F; &#x274F; &#x274F; &#x274F;
&#x274F; &#x274F; &#x274F; &#x274F; &#x274F;
</big>
#end
</div>
#end
</main>
<div class="cost">$escape_html($card.cost)</div>
<div class="power">$escape_html($card.power)</div>
<div class="cp">$escape_html($card.cp)</div>
</article>
#end
View File
+11
View File
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<link rel="stylesheet" href="cardlist.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<form action="show" method="get">
#foreach($card in $cards)
<input type="checkbox" name="card" value="$escape_html($card.filename)">$escape_html($card.title)<br>
#end
<br>
<input type="submit" value="Submit">
</form>
Executable
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env python3
import sys, os, airspeed, glob
from sanic import Sanic, response
from common import withTemplate, withResource
import card
import config
app = Sanic()
@app.get("/")
async def root(request):
return response.redirect('/cards/')
@app.get("/cards/")
@withTemplate("cards/cardlist.vm")
async def show_cardlist(request, template={}):
cards = card.from_dir(config.carddir)
return response.html(template["cardlist.vm"].merge(locals()))
@app.get('/cards/show')
@withTemplate("cards/card.vm")
async def show_cards(request, template={}):
if "card" not in request.args:
return response.redirect('/cards/')
cards = []
for i in request.args["card"]:
if "/" in i or "\\" in i:
return response.redirect('/cards/')
cards.append(card.from_file(i+".yaml"))
return response.html(template["card.vm"].merge(locals()))
#add static files:
for i in glob.iglob(os.path.join(config.resourcedir, "**","*"), recursive=True):
if i.split(".")[-1] in ("html", "css", "js"):
i = os.path.relpath(i, config.resourcedir)
print(i)
@app.get(f"/{i}")
@withResource(i)
async def card_style(request, file={}):
return response.text(tuple(file.values())[0], headers={"Content-Type": f"text/{i.split('.')[-1]}"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)