ignore checkpoints
parent
f90cf92086
commit
12152974e5
@ -1,13 +0,0 @@
|
|||||||
from setuptools import find_packages, setup
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name='exquisite_branch',
|
|
||||||
version='1.0.0',
|
|
||||||
packages=find_packages(),
|
|
||||||
include_package_data=True,
|
|
||||||
zip_safe=False,
|
|
||||||
install_requires=[
|
|
||||||
'flask',
|
|
||||||
'shortuuid'
|
|
||||||
],
|
|
||||||
)
|
|
@ -1,61 +0,0 @@
|
|||||||
import os
|
|
||||||
from flask import Flask
|
|
||||||
|
|
||||||
class PrefixMiddleware(object):
|
|
||||||
|
|
||||||
def __init__(self, app, prefix=''):
|
|
||||||
self.app = app
|
|
||||||
self.prefix = prefix
|
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
|
||||||
|
|
||||||
if environ['PATH_INFO'].startswith(self.prefix):
|
|
||||||
environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):]
|
|
||||||
environ['SCRIPT_NAME'] = self.prefix
|
|
||||||
return self.app(environ, start_response)
|
|
||||||
else:
|
|
||||||
start_response('404', [('Content-Type', 'text/plain')])
|
|
||||||
return ["This url does not belong to the app.".encode()]
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/soupboat/xquisite')
|
|
||||||
|
|
||||||
return app
|
|
@ -1,90 +0,0 @@
|
|||||||
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')
|
|
||||||
if request.is_json:
|
|
||||||
data = request.get_json()
|
|
||||||
content = data['content']
|
|
||||||
branch = data['branch']
|
|
||||||
|
|
||||||
|
|
||||||
db.execute(
|
|
||||||
'INSERT INTO branches (content, parent, branch) VALUES (?, ?, ?)',
|
|
||||||
(content, parent, branch,)
|
|
||||||
)
|
|
||||||
db.commit()
|
|
||||||
print(url_for('share.share', branch=f"{branch}"))
|
|
||||||
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()
|
|
||||||
print(url_for('share.share', branch=f"{branch}"))
|
|
||||||
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)
|
|
@ -1,7 +0,0 @@
|
|||||||
from flask import (Blueprint, render_template)
|
|
||||||
bp = Blueprint('home', __name__, url_prefix='/')
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/')
|
|
||||||
def home():
|
|
||||||
return render_template('home.html')
|
|
@ -1,9 +0,0 @@
|
|||||||
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)
|
|
@ -1,114 +0,0 @@
|
|||||||
// 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", "currentColor");
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
svgElement.addEventListener("mouseleave", 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 form = document.querySelector("form");
|
|
||||||
|
|
||||||
form.addEventListener("submit", () => {
|
|
||||||
let wrapper = document.createElement("div");
|
|
||||||
wrapper.appendChild(svgElement);
|
|
||||||
form["content"].value = wrapper.innerHTML;
|
|
||||||
return true;
|
|
||||||
});
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 28 KiB |
@ -1,37 +0,0 @@
|
|||||||
<!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>
|
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/variables.css')}}" />
|
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/global.css')}}" />
|
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/display.css')}}" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Exquisite Branch</h1>
|
|
||||||
|
|
||||||
<div class="streams">
|
|
||||||
{% for stream in streams %}
|
|
||||||
<div
|
|
||||||
class="stream"
|
|
||||||
style="color: rgb({{ range(0, 255) | random }},{{ range(0, 255) | random }},{{ range(0, 255) | random }}); transform: translate({{ range(-5, 5) | random }}px, {{ range(-5, 5) | random }}px)"
|
|
||||||
>
|
|
||||||
{% for branch in stream %} {{branch['content'] | safe}} {%endfor%}
|
|
||||||
</div>
|
|
||||||
{%endfor%}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{colors}}
|
|
||||||
|
|
||||||
<h2>Branches</h2>
|
|
||||||
<div class="branches">
|
|
||||||
{% for stream in streams %}
|
|
||||||
<div class="branch">
|
|
||||||
{% for branch in stream %} {{branch['content'] | safe}} {%endfor%}
|
|
||||||
</div>
|
|
||||||
{%endfor%}
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,54 +0,0 @@
|
|||||||
<!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/variables.css')}}" />
|
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/global.css')}}" />
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<div id="svg-container">
|
|
||||||
<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="500px"
|
|
||||||
height="500px"
|
|
||||||
viewBox="0 0 500 500"
|
|
||||||
enable-background="new 0 0 500 500"
|
|
||||||
xml:space="preserve"
|
|
||||||
data-parent="{{parent or None}}"
|
|
||||||
data-branch="{{branch}}"
|
|
||||||
></svg>
|
|
||||||
<div id="previous">{% if content %} {{content|safe}} {% endif %}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form method="POST">
|
|
||||||
<input type="hidden" name="branch" value="{{branch}}" />
|
|
||||||
<input type="hidden" name="content" />
|
|
||||||
<input type="submit" />
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,20 +0,0 @@
|
|||||||
<!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>
|
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/variables.css')}}" />
|
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/global.css')}}" />
|
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/share.css')}}" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="share">
|
|
||||||
Send this link to your friends:
|
|
||||||
<a href="{{url_for('draw.draw', parent=branch)}}"
|
|
||||||
>{{url_for('draw.draw', parent=branch)}}</a
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Loading…
Reference in New Issue