Moves styles into scss. Makes things prettier.

This commit is contained in:
Aaron Louie 2020-02-26 12:17:37 -05:00
parent 43a9a66d63
commit 52f8b0d2f9
8 changed files with 355 additions and 127 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.idea
__pycache__/
app.db
static/.webassets-cache*
static/*.css

View File

@ -12,12 +12,14 @@ gevent = "*"
flask-wtf = "*"
sqlalchemy = "*"
flask-sqlalchemy = "*"
flask-assets = "*"
flask-table = "*"
flask-migrate = "*"
flask-marshmallow = "*"
ma = "*"
marshmallow-sqlalchemy = "*"
wtforms-alchemy = "*"
pyscss = "*"
[requires]
python_version = "3.7"

42
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "96c16527bfb9e0a4363b92b0fff94997f533b831fedb0c5b06c84fcad31231d8"
"sha256": "d08ffb3e7cd1b35e9acf7581587157d4f9577b937b3f4a0289ac7ab7a0b2134e"
},
"pipfile-spec": 6,
"requires": {
@ -90,6 +90,14 @@
"index": "pypi",
"version": "==1.1.1"
},
"flask-assets": {
"hashes": [
"sha256:1dfdea35e40744d46aada72831f7613d67bf38e8b20ccaaa9e91fdc37aa3b8c2",
"sha256:2845bd3b479be9db8556801e7ebc2746ce2d9edb4e7b64a1c786ecbfc1e5867b"
],
"index": "pypi",
"version": "==2.0"
},
"flask-babel": {
"hashes": [
"sha256:247f4ec34cf605d03781f480bccb1a5acb719df1d1a2a743c091ab3db5d5fde2",
@ -195,10 +203,10 @@
},
"idna": {
"hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
"sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb",
"sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"
],
"version": "==2.8"
"version": "==2.9"
},
"importlib-metadata": {
"hashes": [
@ -306,10 +314,10 @@
},
"marshmallow": {
"hashes": [
"sha256:7669b944d6233b81f68739d5826f1176c3841cc31cf6b856841083b5a72f5ca9",
"sha256:c9d277f6092f32300395fb83d343be9f61b5e99d66d22bae1e5e7cd82608fee6"
"sha256:3a94945a7461f2ab4df9576e51c97d66bee2c86155d3d3933fab752b31effab8",
"sha256:4b95c7735f93eb781dfdc4dded028108998cad759dda8dd9d4b5b4ac574cbf13"
],
"version": "==3.4.0"
"version": "==3.5.0"
},
"marshmallow-sqlalchemy": {
"hashes": [
@ -333,6 +341,13 @@
],
"version": "==0.15.7"
},
"pyscss": {
"hashes": [
"sha256:14a25c33c221a66bb1f000a6a067f376528d3df2f9333cee9c95709a9280cdb0"
],
"index": "pypi",
"version": "==1.3.5"
},
"python-dateutil": {
"hashes": [
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
@ -373,10 +388,10 @@
},
"requests": {
"hashes": [
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
"sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee",
"sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"
],
"version": "==2.22.0"
"version": "==2.23.0"
},
"six": {
"hashes": [
@ -419,6 +434,13 @@
],
"version": "==0.14.2"
},
"webassets": {
"hashes": [
"sha256:167132337677c8cedc9705090f6d48da3fb262c8e0b2773b29f3352f050181cd",
"sha256:a31a55147752ba1b3dc07dee0ad8c8efff274464e08bbdb88c1fd59ffd552724"
],
"version": "==2.0"
},
"werkzeug": {
"hashes": [
"sha256:169ba8a33788476292d04186ab33b01d6add475033dfc07215e6d219cc077096",

5
app.py
View File

@ -4,6 +4,7 @@ from datetime import date
import connexion
import yaml
from flask import url_for, json, redirect, render_template, request, flash
from flask_assets import Environment, Bundle
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from flask_migrate import Migrate
@ -47,6 +48,10 @@ app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
ma = Marshmallow(app)
assets = Environment(app)
assets.url = app.static_url_path
scss = Bundle('scss/app.scss', filters='pyscss', output='app.css')
assets.register('app_scss', scss)
# Loads all the descriptions from the API so we can display them in the editor.
description_map = {}

View File

@ -32,16 +32,36 @@ class RequirementsTable(Table):
class InvestigatorsTable(Table):
NETBADGEID = Col('UVA Id')
INVESTIGATORTYPE = Col('Type')
delete = LinkCol('Delete', 'del_investigator', url_kwargs=dict(inv_id='id'))
delete = LinkCol(
'delete', 'del_investigator', url_kwargs=dict(inv_id='id'),
anchor_attrs={'class': 'btn btn-icon btn-warn', 'title': 'Delete Investigator'},
th_html_attrs={'class': 'mat-icon text-center', 'title': 'Delete Investigator'}
)
class StudyTable(Table):
def sort_url(self, col_id, reverse=False):
pass
edit = LinkCol('Edit', 'edit_study', url_kwargs=dict(study_id='STUDYID'))
delete = LinkCol('Delete', 'del_study', url_kwargs=dict(study_id='STUDYID'))
details = LinkCol('Details', 'study_details', url_kwargs=dict(study_id='STUDYID'))
add_inv = LinkCol('Add Person', 'new_investigator', url_kwargs=dict(study_id='STUDYID'))
edit = LinkCol(
'edit', 'edit_study', url_kwargs=dict(study_id='STUDYID'),
anchor_attrs={'class': 'btn btn-icon btn-primary', 'title': 'Edit Study'},
th_html_attrs={'class': 'mat-icon text-center', 'title': 'Edit Study'}
)
delete = LinkCol(
'delete', 'del_study', url_kwargs=dict(study_id='STUDYID'),
anchor_attrs={'class': 'btn btn-icon btn-warn', 'title': 'Delete Study'},
th_html_attrs={'class': 'mat-icon text-center', 'title': 'Delete Study'}
)
details = LinkCol(
'ballot', 'study_details', url_kwargs=dict(study_id='STUDYID'),
anchor_attrs={'class': 'btn btn-icon btn-default', 'title': 'Edit Questions'},
th_html_attrs={'class': 'mat-icon text-center', 'title': 'Edit Questions'}
)
add_inv = LinkCol(
'person_add', 'new_investigator', url_kwargs=dict(study_id='STUDYID'),
anchor_attrs={'class': 'btn btn-icon btn-accent', 'title': 'Add Investigator'},
th_html_attrs={'class': 'mat-icon text-center', 'title': 'Add Investigator'}
)
STUDYID = Col('Study Id')
TITLE = Col('Title')
NETBADGEID = Col('User')

244
static/scss/app.scss Normal file
View File

@ -0,0 +1,244 @@
// COLOR PALETTE
// gray
$color-gray: #4e4e4e;
$color-gray-light-2: scale-color($color-gray, $lightness: +90%);
$color-gray-light-1: scale-color($color-gray, $lightness: +70%);
$color-gray-light: $color-gray-light-1;
$color-gray-dark: scale-color($color-gray, $lightness: -30%);
// primary (UVA "Jefferson Blue")
$color-primary: #232D4B;
$color-primary-light: scale-color($color-primary, $lightness: +30%);
$color-primary-dark: scale-color($color-primary, $lightness: -30%);
// accent (UVA "Rotunda Orange")
$color-accent: #E57200;
$color-accent-light: scale-color($color-accent, $lightness: +30%);
$color-accent-dark: scale-color($color-accent, $lightness: -30%);
// warn (UVA "Emergency Red")
$color-warn: #DF1E43;
$color-warn-light: scale-color($color-warn, $lightness: +30%);
$color-warn-dark: scale-color($color-warn, $lightness: -30%);
$font-size-default: 16px;
$font-size-lg: 24px;
$font-size-md: 16px;
$font-size-sm: 14px;
@mixin mat-icon {
font-family: 'Material Icons', sans-serif;
font-size: $font-size-lg;
}
.mat-icon {
@include mat-icon;
}
.text-center {
text-align: center;
}
html, body {
padding: 1em;
margin: 0;
font-family: Arial, sans-serif;
font-size: $font-size-default;
}
table {
border: 1px solid $color-gray-light;
background-color: white;
width: 100%;
text-align: left;
border-collapse: collapse;
th, td {
padding: 0.5em;
}
td, &.blueTable th {
border: 1px solid $color-gray-light;
}
tbody td {
font-size: $font-size-sm;
}
tr:nth-child(even) {
background: $color-gray-light-2;
}
thead {
background-color: $color-primary-light;
th {
font-size: $font-size-default;
font-weight: bold;
color: white;
border-left: 1px solid $color-gray-light;
}
}
thead th:first-child {
border-left: none;
}
tfoot {
font-size: $font-size-default;
font-weight: bold;
color: white;
background-color: $color-gray-light;
td {
font-size: $font-size-default;
}
.links {
text-align: right;
a {
display: inline-block;
background: $color-primary-light;
color: white;
padding: 2px 8px;
border-radius: 5px;
}
}
}
}
.btn {
font-size: $font-size-default;
padding: 0.5em 1em;
border-radius: 5px;
text-decoration: none;
color: white;
white-space: nowrap;
border: none;
&:hover {
text-decoration: none;
}
&.btn-icon {
@include mat-icon;
border: none;
&.btn-default {
color: $color-gray;
background-color: transparent;
border: none;
&:hover {
color: $color-gray-dark;
background-color: transparent;
}
}
&.btn-primary {
color: $color-primary;
background-color: transparent;
&:hover {
color: $color-primary-dark;
background-color: transparent;
}
}
&.btn-accent {
color: $color-accent;
background-color: transparent;
&:hover {
color: $color-accent-dark;
background-color: transparent;
}
}
&.btn-warn {
color: $color-warn;
background-color: transparent;
&:hover {
color: $color-warn-dark;
background-color: transparent;
}
}
}
&.btn-default {
color: $color-gray-dark;
background-color: white;
border: 1px solid $color-gray-light;
&:hover {
background-color: $color-gray-light-2;
}
}
&.btn-primary {
background-color: $color-primary;
&:hover {
background-color: $color-primary-dark;
}
}
&.btn-warn {
background-color: $color-warn;
&:hover {
background-color: $color-warn-dark;
}
}
&.btn-accent {
background-color: $color-accent;
&:hover {
background-color: $color-accent-dark;
}
}
}
select.multi {
height: 600px;
}
.form-field {
display: flex;
width: 100%;
margin-bottom: 40px;
padding: 2em;
&:nth-child(even) {
background-color: $color-gray-light-2;
}
.form-field-label,
.form-field-help,
.form-field-input {
width: 30%;
text-align: left;
margin-right: 40px;
}
.form-field-label {
font-weight: bold;
}
.form-field-input input {
width: 100%;
}
.form-field-help {
font-style: italic;
}
.form-field-error {
color: $color-warn;
}
}

View File

@ -3,38 +3,31 @@
<head>
<meta charset="UTF-8">
<title>Protocol Builder Mock Configuration</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://use.typekit.net/kwp6dli.css">
{% assets 'app_scss' %}
<link href="{{ ASSET_URL }}" rel="stylesheet" type="text/css">
{% endassets %}
</head>
<style>
select.multi {
height: 600px;
}
input {
width: 500px;
}
span.label {
display: inline-block;
min-width: 200px;
text-align: left;
}
</style>
<body>
<h2>{{title}}</h2>
<p>{{details}}</p>
<form action="{{action}}" method="post">
<h2>{{ title }}</h2>
<p>{{ details }}</p>
<form action="{{ action }}" method="post">
{{ form.csrf_token() }}
{% for field in form if field.name != "csrf_token" %}
<p>
<span class="label">{{ field.label() }}:</span>
{{ field }}
<i>{{ description_map[field.name] }}</i>
<div class="form-field">
<div class="form-field-label">{{ field.label() }}:</div>
<div class="form-field-input">{{ field }}</div>
<div class="form-field-help">{{ description_map[field.name] }}</div>
{% for error in field.errors %}
{{ error }}
<div class="form-field-error">{{ error }}</div>
{% endfor %}
</p>
</div>
{% endfor %}
<input type="submit" value="Submit">
<button class="btn btn-primary" type="submit">Submit</button>
<a href="/" class="btn btn-default">Cancel</a>
</form>
</body>

View File

@ -1,93 +1,33 @@
<doctype html>
<head>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Protocol Builder Mock</title>
</head>
<style>
table {
border: 1px solid #1C6EA4;
background-color: #EEEEEE;
width: 100%;
text-align: left;
border-collapse: collapse;
}
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://use.typekit.net/kwp6dli.css">
{% assets 'app_scss' %}
<link href="{{ ASSET_URL }}" rel="stylesheet" type="text/css">
{% endassets %}
</head>
<body>
<h2>Protocol Builder Mock</h2>
table td, table.blueTable th {
border: 1px solid #AAAAAA;
padding: 3px 2px;
}
<p>
<a class="btn btn-primary" href="{{ url_for('.new_study') }}"> New Study </a>
</p>
table tbody td {
font-size: 13px;
}
table tr:nth-child(even) {
background: #D0E4F5;
}
table thead {
background: #1C6EA4;
background: -moz-linear-gradient(top, #5592bb 0%, #327cad 66%, #1C6EA4 100%);
background: -webkit-linear-gradient(top, #5592bb 0%, #327cad 66%, #1C6EA4 100%);
background: linear-gradient(to bottom, #5592bb 0%, #327cad 66%, #1C6EA4 100%);
border-bottom: 2px solid #444444;
}
table thead th {
font-size: 15px;
font-weight: bold;
color: #FFFFFF;
border-left: 2px solid #D0E4F5;
}
table thead th:first-child {
border-left: none;
}
table tfoot {
font-size: 14px;
font-weight: bold;
color: #FFFFFF;
background: #D0E4F5;
background: -moz-linear-gradient(top, #dcebf7 0%, #d4e6f6 66%, #D0E4F5 100%);
background: -webkit-linear-gradient(top, #dcebf7 0%, #d4e6f6 66%, #D0E4F5 100%);
background: linear-gradient(to bottom, #dcebf7 0%, #d4e6f6 66%, #D0E4F5 100%);
border-top: 2px solid #444444;
}
table tfoot td {
font-size: 14px;
}
table tfoot .links {
text-align: right;
}
table tfoot .links a {
display: inline-block;
background: #1C6EA4;
color: #FFFFFF;
padding: 2px 8px;
border-radius: 5px;
}
</style>
<h2>Protocol Builder Mock</h2>
<p>
<p>
<a href="{{ url_for('.new_study') }}"> New Study </a>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% endwith %}
<h3>Current Studies</h3>
{{ table }}
<h3>Current Studies</h3>
{{ table }}
</body>
</doctype>
</html>