Initial webapp design

This commit is contained in:
jaseg 2019-09-28 13:53:02 +02:00
parent 6002d40914
commit 031b6f7361
52 changed files with 18066 additions and 0 deletions

34
webapp/job_processor.py Normal file
View file

@ -0,0 +1,34 @@
import signal
import subprocess
import logging
import itertools
from job_queue import JobQueue
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('queue', help='job queue sqlite3 database file')
parser.add_argument('--loglevel', '-l', default='info')
args = parser.parse_args()
numeric_level = getattr(logging, args.loglevel.upper(), None)
if not isinstance(numeric_level, int):
raise ValueError('Invalid log level: %s' % loglevel)
logging.basicConfig(level=numeric_level)
job_queue = JobQueue(args.queue)
signal.signal(signal.SIGALRM, lambda *args: None) # Ignore incoming alarm signals while processing jobs
signal.setitimer(signal.ITIMER_REAL, 0.001, 1)
while signal.sigwait([signal.SIGALRM, signal.SIGINT]) == signal.SIGALRM:
logging.debug('Checking for jobs')
for job in job_queue.job_iter('render'):
logging.info(f'Processing {job.type} job {job.id} session {job["session_id"]} from {job.client} submitted {job.created}')
with job:
job.result = subprocess.call(['sudo', '/usr/local/sbin/pogojig_render.sh', job['session_id']])
logging.info(f'Finishied processing {job.type} job {job.id}')
logging.info('Caught SIGINT. Exiting.')

77
webapp/job_queue.py Normal file
View file

@ -0,0 +1,77 @@
import json
import sqlite3
class JobQueue:
def __init__(self, dbfile):
self.dbfile = dbfile
self.db = sqlite3.connect(dbfile, check_same_thread=False)
self.db.row_factory = sqlite3.Row
with self.db as conn:
conn.execute('''CREATE TABLE IF NOT EXISTS jobs
(id INTEGER PRIMARY KEY,
type TEXT,
params TEXT,
client TEXT,
result INTEGER DEFAULT NULL,
created DATETIME DEFAULT CURRENT_TIMESTAMP,
consumed DATETIME DEFAULT NULL,
aborted DATETIME DEFAULT NULL,
finished DATETIME DEFAULT NULL);''')
def enqueue(self, task_type:str, client, **params):
""" Enqueue a job of the given type with the given params. Returns the new job ID. """
with self.db as conn:
return conn.execute('INSERT INTO jobs(type, client, params) VALUES (?, ?, ?)',
(task_type, client, json.dumps(params))).lastrowid
def pop(self, task_type):
""" Fetch the next job of the given type. Returns a sqlite3.Row object of the job or None if no jobs of the given
type are queued. """
with self.db as conn:
job = conn.execute('SELECT * FROM jobs WHERE type=? AND consumed IS NULL AND aborted IS NULL ORDER BY created ASC LIMIT 1',
(task_type,)).fetchone()
if job is None:
return None
# Atomically commit to this job
conn.execute('UPDATE jobs SET consumed=datetime("now") WHERE id=?', (job['id'],))
return Job(self.db, job)
def job_iter(self, task_type):
return iter(lambda: self.pop(task_type), None)
def __getitem__(self, key):
""" Return the job with the given ID, or raise a KeyError if the key cannot be found. """
with self.db as conn:
job = conn.execute('SELECT * FROM jobs WHERE id=?', (key,)).fetchone()
if job is None:
raise KeyError(f'Unknown job ID "{key}"')
return Job(self.db, job)
class Job(dict):
def __init__(self, db, row):
super().__init__(json.loads(row['params']))
self._db = db
self._row = row
self.id = row['id']
self.type = row['type']
self.client = row['client']
self.created = row['created']
self.consumed = row['consumed']
self.finished = row['finished']
self.result = row['result']
def __enter__(self):
return self
def __exit__(self, _exc_type, _exc_val, _exc_tb):
with self._db as conn:
conn.execute('UPDATE jobs SET finished=datetime("now"), result=? WHERE id=?', (self.result, self.id,))
def abort(self, job_id):
with self.db as conn:
conn.execute('UPDATE jobs SET aborted=datetime("now") WHERE id=?', (self.id,))

4
webapp/pogojig.cfg Normal file
View file

@ -0,0 +1,4 @@
MAX_CONTENT_LENGTH=10000000
SECRET_KEY="FIXME: CHANGE THIS KEY"
UPLOAD_PATH="/var/cache/pogojig/upload"
JOB_QUEUE_DB="/var/cache/pogojig/job_queue.sqlite3"

111
webapp/pogojig.py Normal file
View file

@ -0,0 +1,111 @@
#!/usr/bin/env python3
# TODO setup webserver user disk quota
import tempfile
import uuid
from functools import wraps
from os import path
import os
import sqlite3
from flask import Flask, url_for, redirect, session, make_response, render_template, request, send_file, abort, flash
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired
from wtforms.fields import RadioField
from wtforms.validators import DataRequired
from werkzeug.utils import secure_filename
from job_queue import JobQueue
app = Flask(__name__, static_url_path='/static')
app.config.from_envvar('POGOJIG_SETTINGS')
class UploadForm(FlaskForm):
upload_file = FileField(validators=[DataRequired()])
class ResetForm(FlaskForm):
pass
job_queue = JobQueue(app.config['JOB_QUEUE_DB'])
def tempfile_path(namespace):
""" Return a path for a per-session temporary file identified by the given namespace. Create the session tempfile
dir if necessary. The application tempfile dir is controlled via the upload_path config value and not managed by
this function. """
sess_tmp = path.join(app.config['UPLOAD_PATH'], session['session_id'])
os.makedirs(sess_tmp, exist_ok=True)
return path.join(sess_tmp, namespace)
def require_session_id(fun):
@wraps(fun)
def wrapper(*args, **kwargs):
if 'session_id' not in session:
session['session_id'] = str(uuid.uuid4())
return fun(*args, **kwargs)
return wrapper
@app.route('/')
def index():
return app.send_static_file('index.html')
@app.route('/jigerator')
@require_session_id
def jigerator():
forms = {
'svg_form': UploadForm(),
'reset_form': ResetForm() }
if 'render_job' in session:
job = job_queue[session['render_job']]
if job.finished:
if job.result != 0:
flash(f'Error processing SVG file', 'success') # FIXME make this an error, add CSS
del session['render_job']
r = make_response(render_template('jigerator.html', has_renders=path.isfile(tempfile_path('output.zip')), **forms))
if 'render_job' in session:
r.headers.set('refresh', '10')
return r
# NOTES about the SVG file upload routines
# * The maximum upload size is limited by the MAX_CONTENT_LENGTH config setting.
# * The uploaded files are deleted after a while by systemd tmpfiles.d
# TODO: validate this setting applies *after* gzip transport compression
def render():
if 'render_job' in session:
job_queue[session['render_job']].abort()
session['render_job'] = job_queue.enqueue('render',
session_id=session['session_id'],
client=request.remote_addr)
@app.route('/upload/svg', methods=['POST'])
@require_session_id
def upload_svg():
upload_form = UploadForm()
if upload_form.validate_on_submit():
f = upload_form.upload_file.data
f.save(tempfile_path('input.svg'))
session['filename'] = secure_filename(f.filename) # Cache filename for later download
render()
flash(f'SVG file successfully uploaded.', 'success')
return redirect(url_for('jigerator'))
@app.route('/render/download')
def render_download():
return send_file(tempfile_path(f'renders.zip'),
mimetype='application/zip',
as_attachment=True,
attachment_filename=f'{path.splitext(session["filename"])[0]}_pogojig.zip')
@app.route('/session_reset', methods=['POST'])
@require_session_id
def session_reset():
if 'render_job' in session:
job_queue[session['render_job']].abort()
session.clear()
flash('Session reset', 'success');
return redirect(url_for('jigerator'))

BIN
webapp/static/3d_models.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
webapp/static/arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
webapp/static/bg-gears.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

47
webapp/static/bg.svg Normal file
View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg8"
version="1.1"
viewBox="0 0 10 10"
height="10mm"
width="10mm">
<defs
id="defs2" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-287)"
id="layer1">
<path
id="path853-7-5"
d="m 4.9999974,291.19333 v -1.82507"
style="fill:none;stroke:#505050;stroke-width:0.2;stroke-linecap:butt;" />
<path
id="path853-7-5-6"
d="m 4.9999975,294.63169 v -1.82507"
style="fill:none;stroke:#505050;stroke-width:0.2;stroke-linecap:butt;" />
<path
id="path853-7-5-6-2"
d="m 5.8066428,291.99997 h 1.82507"
style="fill:none;stroke:#505050;stroke-width:0.2;stroke-linecap:butt;" />
<path
id="path853-7-5-6-2-9"
d="m 2.3682832,291.99997 h 1.82507"
style="fill:none;stroke:#505050;stroke-width:0.2;stroke-linecap:butt;" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
webapp/static/bubble1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

BIN
webapp/static/bubble2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

View file

@ -0,0 +1,587 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg2371"
version="1.1"
viewBox="0 0 49.77145 43.68911"
height="43.68911mm"
width="49.77145mm">
<defs
id="defs2365" />
<metadata
id="metadata2368">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-78.654536,-117.51911)"
id="layer1">
<g
transform="translate(3.3973463,-8.6235988)"
id="g3027"
style="display:inline">
<g
style="stroke-width:1.78494132"
id="g9144"
transform="matrix(0.56024251,0,0,0.56024251,83.834048,-2.2500089)">
<g
style="stroke-width:1.78494132"
id="g1990"
transform="matrix(0.001,0,0,-0.001,-70.961805,164.78416)">
<g
style="stroke-width:1.78494132"
id="g1988">
<g
class="CbY_IYrtRvGd5RWKriaG_sm"
id="CbY_IYrtRvGd5RWKriaG_top_sm-copy"
style="color:#000000;fill:currentColor;stroke:currentColor;stroke-width:1.78494132">
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1562"
d="m 104826.94,-118483.48 191.27,-79.23 172.14,-115.02 146.38,-146.39 115.03,-172.14 79.22,-191.27 40.39,-203.05 v -207.03 l -40.39,-203.05 -79.22,-191.27 -115.03,-172.14 -146.38,-146.39 -172.14,-115.02 -191.27,-79.23 -203.05,-40.39 h -207.03 l -203.05,40.39 -191.27,79.23 -172.14,115.02 -146.39,146.39 -115.02,172.14 -79.23,191.27 -40.39,203.05 v 207.03 l 40.39,203.05 79.23,191.27 115.02,172.14 146.39,146.39 172.14,115.02 191.27,79.23 203.05,40.38 h 207.03 l 203.05,-40.38 v 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1564"
d="m 90413.04,-118943.17 145.775,-544.04 28.392,-105.96 -1488.195,-398.76 -542.181,-145.28 v 0 l -442.093,1649.92 -101.944,380.46 v 0 l 1669.763,447.41 360.613,96.63 v 0 l 369.87,-1380.38 v 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1566"
d="m 100101,-119626 h -1302 v 852 h 1302 v -852 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1568"
d="m 102001,-119626 h -1302 v 852 h 1302 v -852 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1570"
d="m 110514.04,-118483.48 91.27,-340.64 31.9,-119.05 -1601.31,-429.07 -429.07,-114.97 v 0 l -489.75,1827.79 -54.29,202.59 v 0 l 1601.31,429.07 429.07,114.97 v 0 l 420.87,-1570.69 v 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1572"
d="m 94436.194,-116545.29 191.269,-79.23 172.142,-115.02 146.387,-146.39 115.022,-172.14 79.226,-191.27 40.389,-203.05 v -207.03 l -40.389,-203.05 -79.226,-191.27 -115.022,-172.14 -146.387,-146.39 -172.142,-115.02 -191.269,-79.23 -203.049,-40.39 h -207.032 l -203.049,40.39 -191.269,79.23 -172.142,115.02 -146.387,146.39 -115.022,172.14 -79.226,191.27 -40.389,203.05 v 207.03 l 40.389,203.05 79.226,191.27 115.022,172.14 146.387,146.39 172.142,115.02 191.269,79.23 203.049,40.38 h 207.032 l 203.049,-40.38 v 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1574"
d="m 104351,-117176 h -1302 v 852 h 1302 v -852 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1576"
d="m 102451,-117176 h -1302 v 852 h 1302 v -852 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1578"
d="m 98151,-116926 h -1302 v 852 h 1302 v -852 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1580"
d="m 100051,-116926 h -1302 v 852 h 1302 v -852 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1582"
d="m 102551,-115051 h -1602 v 2102 h 1602 v -2102 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1584"
d="m 97951,-115051 h -1602 v 2102 h 1602 v -2102 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1586"
d="m 100251,-115051 h -1602 v 2102 h 1602 v -2102 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1588"
d="m 111001,-112501 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1590"
d="m 113676,-112301 h -1352 v 1102 h 1352 v -1102 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1592"
d="m 108251,-112151 h -1002 v 902 h 1002 v -902 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1594"
d="m 106251,-111201 h -1002 v 902 h 1002 v -902 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1596"
d="m 84251,-110601 h -1302 v 1002 h 1302 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1598"
d="m 86451,-110601 h -1302 v 1002 h 1302 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1600"
d="m 111001,-110301 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1602"
d="m 113676,-110301 h -1352 v 1102 h 1352 v -1102 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1604"
d="m 108251,-110251 h -1002 v 902 h 1002 v -902 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1606"
d="m 101401,-108751 h -3902 v 2102 h 3902 v -2102 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1608"
d="m 82701,-108751 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1610"
d="m 85276,-108551 h -1352 v 1102 h 1352 v -1102 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1612"
d="m 87501,-108401 h -1002 v 902 h 1002 v -902 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1614"
d="m 105051,-108001 h -1302 v 1002 h 1302 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1616"
d="m 107251,-108001 h -1302 v 1002 h 1302 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1618"
d="m 89501,-107451 h -1002 v 902 h 1002 v -902 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1620"
d="m 85276,-106551 h -1352 v 1102 h 1352 v -1102 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1622"
d="m 82701,-106551 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1624"
d="m 87501,-106501 h -1002 v 902 h 1002 v -902 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1626"
d="m 105051,-106001 h -1302 v 1002 h 1302 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1628"
d="m 107251,-106001 h -1302 v 1002 h 1302 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1630"
d="m 114676,-105751 h -1352 v 1102 h 1352 v -1102 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1632"
d="m 116201,-104151 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1634"
d="m 90051,-104101 h -3402 v 1802 h 3402 v -1802 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1636"
d="m 84551,-104101 h -3402 v 1802 h 3402 v -1802 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1638"
d="m 118601,-103801 h -902 v 1002 h 902 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1640"
d="m 120501,-103801 h -902 v 1002 h 902 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1642"
d="m 114676,-103751 h -1352 v 1102 h 1352 v -1102 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1644"
d="m 97826,-103201 h -1552 v 6402 h 1552 v -6402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1646"
d="m 103726,-103201 h -1552 v 6402 h 1552 v -6402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1648"
d="m 108201,-102401 h -1602 v 1602 h 1602 v -1602 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1650"
d="m 110901,-102401 h -1602 v 1602 h 1602 v -1602 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1652"
d="m 116201,-101951 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1654"
d="m 105926,-101901 h -852 v 1302 h 852 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1656"
d="m 119551,-101801 h -902 v 1002 h 902 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1658"
d="m 94501,-101251 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1660"
d="m 90051,-100901 h -3402 v 1802 h 3402 v -1802 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1662"
d="m 84551,-100901 h -3402 v 1802 h 3402 v -1802 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1664"
d="m 109401,-100201 h -1802 v 3402 h 1802 v -3402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1666"
d="m 105926,-100001 h -852 v 1302 h 852 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1668"
d="m 116101,-99751 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1670"
d="m 120751,-99351 h -3302 v 2802 h 3302 v -2802 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1672"
d="m 113751,-99251 h -1302 v 1002 h 1302 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1674"
d="m 111551,-99251 h -1302 v 1002 h 1302 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1676"
d="m 94501,-99051 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1678"
d="m 91651,-97651 h -1802 v 1802 h 1802 v -1802 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1680"
d="m 88320.443,-95855.519 66.184,-6.518 113.226,-34.347 56.614,-17.173 138.62,-74.095 17.904,-9.57 35.738,-29.33 101.457,-83.262 83.262,-101.457 29.33,-35.738 h 10e-4 l 83.664,-156.522 v 0 l 51.52,-169.839 17.396,-176.627 -17.396,-176.627 -34.347,-113.226 -17.173,-56.614 -42.512,-79.533 -41.153,-76.991 -29.33,-35.738 -83.262,-101.457 -101.457,-83.262 -35.738,-29.33 v 0 l -156.522,-83.664 -56.614,-17.173 -113.226,-34.347 -66.185,-6.519 -66.182,-6.518 h -88.52 l -66.182,6.518 -66.185,6.519 -113.226,34.347 -56.614,17.173 -156.522,83.664 v 0 l -35.738,29.33 -101.457,83.262 -83.262,101.457 -29.33,35.738 -41.153,76.991 -42.512,79.533 -17.173,56.614 -34.347,113.226 -17.396,176.627 17.396,176.627 51.52,169.839 v 0 l 83.664,156.522 h 10e-4 l 29.33,35.738 83.262,101.457 101.457,83.262 35.738,29.33 17.904,9.57 138.62,74.095 56.614,17.173 113.226,34.347 66.184,6.518 66.183,6.519 h 88.52 l 66.183,-6.519 v 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1682"
d="m 85780.444,-95855.519 66.184,-6.518 113.226,-34.347 56.614,-17.173 138.62,-74.095 17.904,-9.57 35.738,-29.33 101.457,-83.262 83.262,-101.457 29.33,-35.738 v 0 l 83.664,-156.522 v 0 l 51.52,-169.839 17.396,-176.627 -17.396,-176.627 -34.347,-113.226 -17.173,-56.614 -42.512,-79.533 -41.153,-76.991 -29.33,-35.738 -83.262,-101.457 -101.457,-83.262 -35.738,-29.33 v 0 l -156.522,-83.664 -56.614,-17.173 -113.226,-34.347 -66.185,-6.519 -66.182,-6.518 h -88.52 l -66.182,6.518 -66.185,6.519 -113.226,34.347 -56.614,17.173 -156.522,83.664 v 0 l -35.738,29.33 -101.457,83.262 -83.262,101.457 -29.33,35.738 -41.153,76.991 -42.512,79.533 -17.173,56.614 -34.347,113.226 -17.396,176.627 17.396,176.627 51.52,169.839 v 0 l 83.664,156.522 v 0 l 29.33,35.738 83.262,101.457 101.457,83.262 35.738,29.33 17.904,9.57 138.62,74.095 56.614,17.173 113.226,34.347 66.184,6.518 66.183,6.519 h 88.52 l 66.183,-6.519 v 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1684"
d="m 83240.443,-95855.519 66.184,-6.518 113.226,-34.347 56.614,-17.173 138.62,-74.095 17.904,-9.57 35.738,-29.33 101.457,-83.262 83.262,-101.457 29.33,-35.738 h 10e-4 l 83.664,-156.522 v 0 l 51.52,-169.839 17.396,-176.627 -17.396,-176.627 -34.347,-113.226 -17.173,-56.614 -42.512,-79.533 -41.153,-76.991 -29.33,-35.738 -83.262,-101.457 -101.457,-83.262 -35.738,-29.33 v 0 l -156.522,-83.664 -56.614,-17.173 -113.226,-34.347 -66.185,-6.519 -66.182,-6.518 h -88.52 l -66.182,6.518 -66.185,6.519 -113.226,34.347 -56.614,17.173 -156.522,83.664 v 0 l -35.738,29.33 -101.457,83.262 -83.262,101.457 -29.33,35.738 -41.153,76.991 -42.512,79.533 -17.173,56.614 -34.347,113.226 -17.396,176.627 17.396,176.627 51.52,169.839 v 0 l 83.664,156.522 h 10e-4 l 29.33,35.738 83.262,101.457 101.457,83.262 35.738,29.33 17.904,9.57 138.62,74.095 56.614,17.173 113.226,34.347 66.184,6.518 66.183,6.519 h 88.52 l 66.183,-6.519 v 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1686"
d="m 116101,-97551 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1688"
d="m 106701,-97501 h -1602 v 1602 h 1602 v -1602 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1690"
d="m 113601,-97176 h -1302 v 852 h 1302 v -852 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1692"
d="m 111701,-97176 h -1302 v 852 h 1302 v -852 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1694"
d="m 99301,-95101 h -1302 v 1502 h 1302 v -1502 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1696"
d="m 101001,-95101 h -1302 v 1502 h 1302 v -1502 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1698"
d="m 95001,-95001 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1700"
d="m 106701,-95001 h -1602 v 1602 h 1602 v -1602 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1702"
d="m 111501,-95001 h -902 v 1002 h 902 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1704"
d="m 113401,-95001 h -902 v 1002 h 902 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1706"
d="m 97176,-94901 h -852 v 1302 h 852 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1708"
d="m 102926,-94851 h -852 v 1302 h 852 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1710"
d="m 109401,-94701 h -1802 v 3402 h 1802 v -3402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1712"
d="m 97176,-93001 h -852 v 1302 h 852 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1714"
d="m 112451,-93001 h -902 v 1002 h 902 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1716"
d="m 102926,-92951 h -852 v 1302 h 852 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1718"
d="m 101001,-92901 h -1302 v 1502 h 1302 v -1502 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1720"
d="m 99301,-92901 h -1302 v 1502 h 1302 v -1502 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1722"
d="m 95001,-92801 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1724"
d="m 120751,-91451 h -3302 v 2802 h 3302 v -2802 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1726"
d="m 111101,-89951 h -3602 v 2402 h 3602 v -2402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1728"
d="m 116501,-89951 h -3602 v 2402 h 3602 v -2402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1730"
d="m 92679.544,-89863.48 h -3602 v 2402 h 3602 v -2402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1732"
d="m 87279.544,-89863.48 h -3602 v 2402 h 3602 v -2402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1734"
d="m 106451,-89151 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1736"
d="m 104451,-89151 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1738"
d="m 102501,-89151 h -1802 v 3402 h 1802 v -3402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1740"
d="m 97301,-89001 h -1302 v 1002 h 1302 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1742"
d="m 99501,-89001 h -1302 v 1002 h 1302 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1744"
d="m 104451,-86951 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1746"
d="m 106451,-86951 h -1002 v 1302 h 1002 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1748"
d="m 99426,-86851 h -852 v 1302 h 852 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1750"
d="m 96201,-86751 h -902 v 1002 h 902 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1752"
d="m 116501,-84951 h -3602 v 2402 h 3602 v -2402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1754"
d="m 99426,-84951 h -852 v 1302 h 852 v -1302 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1756"
d="m 111101,-84951 h -3602 v 2402 h 3602 v -2402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1758"
d="m 87279.544,-84863.48 h -3602 v 2402 h 3602 v -2402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1760"
d="m 92679.544,-84863.48 h -3602 v 2402 h 3602 v -2402 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1762"
d="m 95251,-84751 h -902 v 1002 h 902 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1764"
d="m 97151,-84751 h -902 v 1002 h 902 v -1002 0" />
<path
style="fill:#666666;stroke-width:1.78494132"
id="path1766"
d="m 102501,-83651 h -1802 v 3402 h 1802 v -3402 0" />
</g>
<g
class="CbY_IYrtRvGd5RWKriaG_sp"
id="CbY_IYrtRvGd5RWKriaG_top_sp-copy"
style="color:#dddddd;fill:currentColor;stroke:currentColor;stroke-width:1.78494132" />
</g>
</g>
<g
style="stroke-width:1.78494132"
id="g1998"
transform="matrix(0.001,0,0,-0.001,-70.961805,164.78417)">
<g
style="stroke-width:1.78494132"
id="g1996">
<g
style="color:#0000ff;fill:none;stroke:currentColor;stroke-width:1.78494132"
class="CbY_IYrtRvGd5RWKriaG_out board-outline"
id="CbY_IYrtRvGd5RWKriaG_top_out-copy">
<path
style="fill:none;stroke:#dc0000;stroke-width:356.98825073"
id="path1993"
d="m 87734.397,-126954.93 -2395.72,1805.06 2484.08,3296.96 2874.429,-1375.11 3013.627,-995.09 3115.408,-605.29 3179.779,-205.71 3204,214.11 3137.48,619.7 3032.7,1015.14 2889.67,1400.46 2535.77,-3365.17 -2395.72,-1805.06 3994.58,-5300.96 12778.04,9629.38 -3994.59,5300.45 -2395.72,-1805.06 -2956.93,3923.8 1181.33,1676.68 1035.05,1758.81 885.48,1831.3 732.62,1894.15 576.49,1947.36 417.07,1990.93 254.35,2024.86 88.36,2049.14 -84.93,2018.255 -246.01,1995.106 -404.01,1962.729 -558.91,1921.121 -710.73,1870.283 -859.45,1810.213 -1005.09,1740.914 -1147.62,1662.383 2802.93,3719.15 2395.72,-1805.06 3994.59,5300.45 -12778.04,9629.39 -3994.58,-5300.968 2395.72,-1805.058 -2321.83,-3080.944 -2933.49,1450.199 -3084.42,1051.007 -3194.91,640.919 -3264.97,219.939 -3237.426,-218.737 -3168.786,-632.721 -3060.712,-1036.141 -2913.199,-1428.995 -2287.2,3035.474 2395.72,1805.058 -3994.59,5300.968 -12778.03,-9629.39 3994.59,-5300.45 2395.72,1805.06 2740.4,-3636.47 -1162.565,-1668.416 -1018.418,-1748.528 -871.094,-1819.233 -720.593,-1880.531 -566.916,-1932.423 -410.063,-1974.908 -250.033,-2007.986 -86.828,-2031.659 87.259,-2064.49 255.732,-2039.86 420.835,-2005.37 582.565,-1961.03 740.926,-1906.85 895.915,-1842.81 1047.535,-1768.93 1195.783,-1685.18 -2880.44,-3822.51 -2395.72,1805.06 -3994.59,-5300.45 12778.03,-9629.38 3994.59,5300.96" />
</g>
</g>
</g>
<g
id="g2895"
style="stroke:#b50000">
<path
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#dc0000;stroke-width:1.78494263;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 204.19141,967.18164 c -12.45601,0 -22.48438,10.02834 -22.48438,22.48438 v 23.94138 c 0,12.4561 10.02837,22.4844 22.48438,22.4844 h 59.33203 v -68.91016 z"
transform="scale(0.26458333)"
id="rect2881-5" />
<path
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#dc0000;stroke-width:1.78494263;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m -43.476562,967.18164 v 68.91016 h 59.332031 c 12.456049,0 22.484375,-10.0283 22.484375,-22.4844 v -23.94138 c 0,-12.45604 -10.028326,-22.48438 -22.484375,-22.48438 z"
transform="scale(0.26458333)"
id="rect2881-5-3" />
<path
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#dc0000;stroke-width:1.78494382;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m -43.476562,1078.7871 v 67.7324 H 263.52344 v -67.7324 z"
transform="scale(0.26458333)"
id="rect2881-5-3-5" />
</g>
<g
id="g2759">
<circle
style="display:inline;opacity:1;vector-effect:none;fill:#b50000;fill-opacity:1;stroke:none;stroke-width:0.94453275;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path2834"
cx="-0.77764279"
cy="249.81239"
r="1.6000022" />
<circle
style="display:inline;opacity:1;vector-effect:none;fill:#b50000;fill-opacity:1;stroke:none;stroke-width:0.94453353;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path2834-3"
cx="58.998592"
cy="249.81239"
r="1.6000032" />
<circle
style="display:inline;opacity:1;vector-effect:none;fill:#b50000;fill-opacity:1;stroke:none;stroke-width:0.94453418;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path2834-3-6"
cx="-0.77764279"
cy="280.22067"
r="1.6000044" />
<circle
style="display:inline;opacity:1;vector-effect:none;fill:#b50000;fill-opacity:1;stroke:none;stroke-width:0.94453353;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path2834-7"
cx="58.998592"
cy="280.22067"
r="1.6000032" />
</g>
<g
id="g2753"
style="fill:#ffc022">
<circle
style="display:inline;opacity:1;vector-effect:none;fill:#ffc022;fill-opacity:1;stroke:none;stroke-width:0.94453353;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path3250"
cx="34.938358"
cy="258.98401"
r="1.0000019" />
<circle
style="display:inline;opacity:1;vector-effect:none;fill:#ffc022;fill-opacity:1;stroke:none;stroke-width:0.94453418;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path3250-3"
cx="36.438358"
cy="266.38403"
r="1.0000026" />
<circle
style="display:inline;opacity:1;vector-effect:none;fill:#ffc022;fill-opacity:1;stroke:none;stroke-width:0.94453418;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path3250-6"
cx="34.938358"
cy="261.48401"
r="1.0000026" />
<circle
style="display:inline;opacity:1;vector-effect:none;fill:#ffc022;fill-opacity:1;stroke:none;stroke-width:0.94453418;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path3250-7"
cx="39.138363"
cy="266.38403"
r="1.0000026" />
<circle
style="display:inline;opacity:1;vector-effect:none;fill:#ffc022;fill-opacity:1;stroke:none;stroke-width:0.94453418;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path3250-5"
cx="17.248314"
cy="261.53403"
r="0.75000161" />
<circle
style="display:inline;opacity:1;vector-effect:none;fill:#ffc022;fill-opacity:1;stroke:none;stroke-width:0.94453478;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path3250-5-3"
cx="19.788315"
cy="261.53403"
r="0.75000209" />
<circle
style="display:inline;opacity:1;vector-effect:none;fill:#ffc022;fill-opacity:1;stroke:none;stroke-width:0.94453478;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path3250-5-5"
cx="14.708309"
cy="261.53403"
r="0.75000209" />
<circle
style="display:inline;opacity:1;vector-effect:none;fill:#ffc022;fill-opacity:1;stroke:none;stroke-width:0.94453478;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path3250-5-6"
cx="12.168308"
cy="261.53403"
r="0.75000209" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 74 KiB

66
webapp/static/index.html Normal file
View file

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Pogojig Test Fixture Generator</title>
<link rel="stylesheet" type="text/css" href="static/style.css">
<link rel="icon" type="image/png" href="static/favicon-512.png">
<link rel="apple-touch-icon" href="static/favicon-512.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="layout-container">
<div class="header">
<img class="title" alt="Pogojig" src="static/pogojig-title.png">
<p class="blurb">
Pogojig is a tool to generate pogo pin test fixtures for printed circuit board manufacturing and development.
Pogojig generates a 3d printable board holder with holes for mounting pogo pins, along with a matching KiCAD
PCB project for a pogo pin breakout and mounting PCB.
You can start with either Gerber files exported from any PCB toolchain, or you can do a free-form layout using
the <a href="static/static_template.svg">static Inkscape SVG template</a> if you
wan to work from construction drawings, scanned or photographed PCBs etc.
</p>
</div>
<div class="annot top">
<div class="desc right">
<strong>1.</strong> Convert your Gerbers to an SVG template and draw pogo pins, mounting holes and cutouts
into the template. Don't have gerbers? Start with an
<a href="static/pogojig_template_empty.svg">empty template</a>.
</div>
<div class="bubble left">
<div>click to open</div>
<a class="btn red" href="pogospace">Pogospace</a>
</div>
</div>
<div class="workflow-images">
<img class="gerber" alt="Gerber files" src="static/realistic_render.png" width="11em">
<img class="arrow" alt="arrow pointing right" src="static/arrow-small.png" width="6em">
<img class="svg" alt="SVG blueprint" src="static/cad_example.svg" width="15em">
<img class="arrow" alt="arrow pointing right" src="static/arrow-small.png" width="6em">
<img class="models" alt="3D models of matching plastic holder and base PCB" src="static/3d_models.png" width="14em">
</div>
<div class="annot bottom">
<div class="desc left">
<strong>2.</strong> Upload your SVG to generate STL and OpenSCAD files for the plastic holder, and KiCAD and
DXF files for the base PCB.
</div>
<div class="bubble right">
<div>click to open</div>
<a class="btn red">Jigerator</a>
</div>
</div>
<div class="footer">
<img class="title" alt="Made with love in Berlin" src="static/footer_love.svg">
<a href="https://github.com/jaseg/pogojig">i can haz sources</a>
<a href="https://blog.jaseg.net/imprint">imprint</a>
<div class="copyright">&#169; 2019 jaseg</div>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

176
webapp/static/style.css Normal file
View file

@ -0,0 +1,176 @@
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 300;
font-display: swap;
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(fonts/SourceSansPro-Light.woff2) format('woff2');
}
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
font-display: swap;
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/SourceSansPro-Regular.woff2) format('woff2');
}
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
font-display: swap;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(fonts/SourceSansPro-Bold.woff2) format('woff2');
}
html {
background: #2d2829;
background-image: url(bg.svg);
color: #ffffff;
font-family: 'Source Sans Pro';
font-size: 14pt;
font-weight: 300;
}
a:active, a:hover, a:visited, a:link {
color: #fff;
font-weight: 400;
}
body {
display: flex;
flex-direction: column;
align-items: center;
margin: 0 0 0 0;
padding: 3mm 3mm 3mm 3mm;
}
.layout-container {
display: flex;
flex-direction: column;
align-items: center;
width: 38em;
max-width: 100%;
}
.header {
text-align: center;
}
.header > img.title {
width: 100%;
padding-top: 50px;
padding-bottom: 50px;
}
.header > .blurb {
text-align: justify;
hyphens: auto;
padding-bottom: 50px;
}
.annot {
display: flex;
align-items: center;
align-content: start;
}
.annot.top {
align-items: end;
flex-direction: row-reverse;
align-content: start;
}
.annot.bottom {
align-items: start;
flex-direction: row;
}
.annot.top > .desc {
padding-left: 1em;
padding-bottom: 2em;
max-width: 60%;
}
.annot.bottom > .desc {
padding-right: 1em;
padding-top: 4.5em;
max-width: 60%;
}
.annot > .bubble {
max-width: 30%;
background-size: contain;
background-repeat: no-repeat;
text-align: center;
font-size: .7rem;
}
.annot.top > .bubble {
background-image: url(bubble1-small.png);
padding: 2em 2em 5em 2em;
}
.annot.bottom > .bubble {
background-image: url(bubble2-small.png);
padding: 7em 2em 5em 2em;
}
a.btn {
display: block;
font-weight: 700;
background-color: #b50000;
border-radius: 0.5em;
padding: .4em 1em .4em 1em;
margin-top: .2em;
}
a.btn:active, a.btn:hover, a.btn:visited, a.btn:link {
text-decoration: none;
}
.workflow-images {
display: flex;
align-items: center;
width: 100%;
}
.workflow-images > .gerber {
width: 220px;
}
.workflow-images > .svg {
width: 300px;
}
.workflow-images > .models {
width: 280px;
}
.workflow-images > .arrow {
width: 120px
}
.footer {
opacity: 0.5;
text-align: center;
padding-top: 5em;
}
.footer > img {
padding-bottom: .5em;
}
.footer > a {
display: block;
}
.footer > .copyright {
padding-top: 1em;
}

1596
webapp/static/workflow.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 806 KiB

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 821 KiB

1582
webapp/static/workflow2.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 805 KiB

1596
webapp/static/workflow3.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 806 KiB

View file

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Pogojig SVG Upload</title>
<link rel="stylesheet" type="text/css" href="{{url_for('static', filename='style.css')}}">
<link rel="icon" type="image/png" href="{{url_for('static', filename='favicon-512.png')}}">
<link rel="apple-touch-icon" href="{{url_for('static', filename='favicon-512.png')}}">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="layout-container">
<div class="header">
<img class="title" alt="Pogojig" src="{{url_for('static', filename='pogojig-title.png')}}">
</div>
{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
<div class="flashes">
{% for category, message in messages %}
<div class="flash flash-{{category}}">{{ message }}</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<form id="reset-form" method="POST" action="{{url_for('session_reset')}}" class="reset-form">{{reset_form.csrf_token}}</form>
<div class="controls">
<form id="svg-upload-form" method="POST" action="{{url_for('upload_svg')}}" enctype="multipart/form-data">
{{svg_form.csrf_token}}
</form>
<div class="form-controls">
<div class="upload-label">Upload completed SVG file:</div>
<input class='upload-button' form="gerber-upload-form" name="upload_file" size="20" type="file">
</div>
<div class="submit-buttons">
<input class='reset-button' form="reset-form" type="submit" value="Start over">
<input class='submit-button' form="svg-upload-form" type="submit" value="Submit">
</div>
</div>
{% if 'render_job' in session or has_renders %}
<div class="render_output">
{% if 'render_job' in session %}
<div class="loading-message">
<div class="lds-ring"><div></div><div></div><div></div><div></div></div>
<div><strong>Processing...</strong></div>
<div>(this may take several minutes!)</div>
</div>
{% else %}
<div class="preview-images">
<a href="{{url_for('render_download')}}" class="render" style="background-image:url('{{url_for('render_preview')}}');">
<div class="overlay">Download model and PCB</div>
</a>
</div>
{% endif %}
</div>
{% endif %} {# render job #}
</div>
</body>
</html>