init repo

master
km0 2 years ago
commit 3719f26082

14
.gitignore vendored

@ -0,0 +1,14 @@
venv/
*.pyc
__pycache__/
instance/
.pytest_cache/
.coverage
htmlcov/
dist/
build/
*.egg-info/

@ -0,0 +1,41 @@
import os
from flask import Flask
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'exquisite'),
)
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
from . import db
db.init_app(app)
from . import draw
app.register_blueprint(draw.bp)
from . import share
app.register_blueprint(share.bp)
from . import display
app.register_blueprint(display.bp)
from . import home
app.register_blueprint(home.bp)
return app

@ -0,0 +1,43 @@
import sqlite3
import click
from flask import current_app, g
from flask.cli import with_appcontext
def get_db():
if 'db' not in g:
g.db = sqlite3.connect(
current_app.config['DATABASE'],
detect_types=sqlite3.PARSE_DECLTYPES
)
g.db.row_factory = sqlite3.Row
return g.db
def close_db(e=None):
db = g.pop('db', None)
if db is not None:
db.close()
def init_db():
db = get_db()
with current_app.open_resource('schema.sql') as f:
db.executescript(f.read().decode('utf8'))
@click.command('init-db')
@with_appcontext
def init_db_command():
"""Clear the existing data and create new tables."""
init_db()
click.echo('Initialized the database.')
def init_app(app):
app.teardown_appcontext(close_db)
app.cli.add_command(init_db_command)

@ -0,0 +1,35 @@
from flask import (Blueprint, flash, g, redirect,
render_template, request, session, url_for)
from exquisite_branch.db import get_db
bp = Blueprint('display', __name__, url_prefix='/display')
@bp.route('/')
def display():
db = get_db()
branches = db.execute(
"SELECT content, branch, parent FROM branches"
).fetchall()
streams = []
for branch in branches[::-1]:
if branch not in flatten(streams):
stream = [branch]
parent = branch['parent']
while parent != 'NEW':
current = next(
(x for x in branches if x['branch'] == parent), None)
parent = current['parent']
stream.append(current)
streams.append(stream[::-1])
return render_template('display.html', branches=branches, streams=streams)
def flatten(t):
return [item for sublist in t for item in sublist]

@ -0,0 +1,85 @@
from flask import (Blueprint, flash, g, redirect,
render_template, request, session, url_for)
from exquisite_branch.db import get_db
from werkzeug.exceptions import abort
from shortuuid import uuid
bp = Blueprint('draw', __name__, url_prefix='/draw')
@bp.route('/<parent>', methods=('GET', 'POST'))
def draw(parent=None):
db = get_db()
if request.method == 'POST':
content = request.form.get('content')
branch = request.form.get('branch')
print(content)
db.execute(
'INSERT INTO branches (content, parent, branch) VALUES (?, ?, ?)',
(content, parent, branch,)
)
db.commit()
return redirect(url_for('share.share', branch=branch))
branch = uuid()
previous = db.execute(
"SELECT content, branch, parent FROM branches"
" WHERE branch = ?",
(parent,)
).fetchone()
if previous is None:
abort(404, f"Previous with id {parent} doesn't exist")
return render_template('draw.html', parent=parent, content=previous['content'], branch=branch)
@bp.route('/last', methods=('GET', 'POST'))
def last():
branch = uuid()
db = get_db()
previous = db.execute(
'SELECT * FROM branches ORDER BY id DESC LIMIT 1'
).fetchone()
parent = previous['branch']
if request.method == 'POST':
content = request.form['content']
branch = request.form['branch']
db.execute(
'INSERT INTO branches (content, parent, branch) VALUES (?, ?, ?)',
(content, parent, branch,)
)
db.commit()
return redirect(url_for('share.share', branch=branch))
return render_template('draw.html', parent=parent, content=previous['content'], branch=branch)
@bp.route('/', methods=('GET', 'POST'))
def new():
db = get_db()
branch = uuid()
parent = 'NEW'
if request.method == 'POST':
content = request.form['content']
branch = request.form['branch']
db.execute(
'INSERT INTO branches (content, parent, branch) VALUES (?, ?, ?)',
(content, parent, branch,)
)
db.commit()
return redirect(url_for('share.share', branch=branch))
return render_template('draw.html', parent=parent, branch=branch)

@ -0,0 +1,7 @@
from flask import (Blueprint, render_template)
bp = Blueprint('home', __name__, url_prefix='/')
@bp.route('/')
def home():
return render_template('home.html')

@ -0,0 +1,8 @@
DROP TABLE IF EXISTS branches;
CREATE TABLE branches (
id INTEGER PRIMARY KEY AUTOINCREMENT,
branch TEXT NOT NULL,
content TEXT NOT NULL,
parent TEXT NOT NULL
);

@ -0,0 +1,10 @@
from flask import (Blueprint, flash, g, redirect,
render_template, request, session, url_for)
bp = Blueprint('share', __name__, url_prefix='/share')
@bp.route('/<branch>')
def share(branch=None):
return render_template('share.html', branch=branch)

@ -0,0 +1,14 @@
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
}
canvas {
width: 500px;
height: 500px;
border: 1px solid currentColor;
}

@ -0,0 +1,116 @@
// Great resource from https://stackoverflow.com/a/40700068
// Thank you ConnorFan
var strokeWidth = 2;
var bufferSize;
var svgElement = document.getElementById("svgElement");
var rect = svgElement.getBoundingClientRect();
var path = null;
var strPath;
var buffer = []; // Contains the last positions of the mouse cursor
svgElement.addEventListener("mousedown", function (e) {
bufferSize = document.getElementById("cmbBufferSize").value;
path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute("fill", "none");
path.setAttribute("stroke", "#000");
path.setAttribute("stroke-width", strokeWidth);
buffer = [];
var pt = getMousePosition(e);
appendToBuffer(pt);
strPath = "M" + pt.x + " " + pt.y;
path.setAttribute("d", strPath);
svgElement.appendChild(path);
});
svgElement.addEventListener("mousemove", function (e) {
if (path) {
appendToBuffer(getMousePosition(e));
updateSvgPath();
}
});
svgElement.addEventListener("mouseup", function () {
if (path) {
path = null;
}
});
var getMousePosition = function (e) {
return {
x: e.pageX - rect.left,
y: e.pageY - rect.top,
};
};
var appendToBuffer = function (pt) {
buffer.push(pt);
while (buffer.length > bufferSize) {
buffer.shift();
}
};
// Calculate the average point, starting at offset in the buffer
var getAveragePoint = function (offset) {
var len = buffer.length;
if (len % 2 === 1 || len >= bufferSize) {
var totalX = 0;
var totalY = 0;
var pt, i;
var count = 0;
for (i = offset; i < len; i++) {
count++;
pt = buffer[i];
totalX += pt.x;
totalY += pt.y;
}
return {
x: totalX / count,
y: totalY / count,
};
}
return null;
};
var updateSvgPath = function () {
var pt = getAveragePoint(0);
if (pt) {
// Get the smoothed part of the path that will not change
strPath += " L" + pt.x + " " + pt.y;
// Get the last part of the path (close to the current mouse position)
// This part will change if the mouse moves again
var tmpPath = "";
for (var offset = 2; offset < buffer.length; offset += 2) {
pt = getAveragePoint(offset);
tmpPath += " L" + pt.x + " " + pt.y;
}
// Set the complete current path coordinates
path.setAttribute("d", strPath + tmpPath);
}
};
//
//
//
// SAVE THE BRANCH
const send = document.getElementById("send");
send.addEventListener("click", (e) => saveSVG(e));
function saveSVG(e) {
let wrapper = document.createElement("div");
wrapper.appendChild(svgElement);
fetch(`${svgElement.dataset.parent}`, {
method: "POST",
body: JSON.stringify({
content: wrapper.innerHTML,
parent: svgElement.dataset.parent,
branch: svgElement.dataset.branch,
}),
});
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 28 KiB

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Display</title>
</head>
<body>
<h1>Exquisite Branch</h1>
<h2>Entries</h2>
{% for branch in branches %} {{branch['content']}} {%endfor%}
<h2>Branches</h2>
<ul>
{% for stream in streams %}
<li>
{% for branch in stream %}
<span>{{branch['content']}}</span>
{%endfor%}
</li>
{%endfor%}
</ul>
</body>
</html>

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Draw</title>
<script src="{{url_for('static', filename='js/draw.js')}}" defer></script>
<link rel="stylesheet" href="{{url_for('static', filename='css/draw.css')}}" />
</head>
<body>
<h1>Draw</h1>
<div id="divSmoothingFactor">
<label for="cmbBufferSize">Buffer size:</label>
<select id="cmbBufferSize">
<option value="1">1 - No smoothing</option>
<option value="4">4 - Sharp curves</option>
<option value="8" selected="selected">8 - Smooth curves</option>
<option value="12">12 - Very smooth curves</option>
<option value="16">16 - Super smooth curves</option>
<option value="20">20 - Hyper smooth curves</option>
</select>
</div>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
id="svgElement"
x="0px"
y="0px"
width="600px"
height="400px"
viewBox="0 0 600 400"
enable-background="new 0 0 600 400"
xml:space="preserve"
data-parent="{{parent or None}}"
data-branch="{{branch}}"
></svg>
<button id="send">Send</button>
<h2>Previous content</h2>
{% if content %} {{content}} {% endif %}
<h2>Parent</h2>
{%if parent %} {{parent}} {%endif %}
<h2>Branch</h2>
{%if branch %} {{branch}} {%endif %}`
<form class="canvas" method="POST">
<input type="text" name="content" />
<input type="hidden" name="branch" value="{{branch}}" />
<input type="submit" />
</form>
</body>
</html>

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Exquisite Branch</title>
</head>
<body>
<h1>Exquisite Branch</h1>
<a href="{{url_for('draw.new')}}">Start new</a> <br />
<a href="{{url_for('draw.last')}}">Continue from last</a> <br />
<a href="{{url_for('display.display')}}">Display results</a>
</body>
</html>

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Share</title>
</head>
<body>
Send this link to your friends:
<a href="{{url_for('draw.draw', parent=branch)}}"
>{{url_for('draw.draw', parent=branch)}}</a
>
</body>
</html>
Loading…
Cancel
Save