add some css to the mix, add search functionality #3

Open
flynn wants to merge 2 commits from feature/ui into master
15 changed files with 10897 additions and 62 deletions

23
app.py
View file

@ -1,6 +1,25 @@
from flask import Flask
import os
from flask import Flask, send_from_directory
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app = Flask(__name__, static_url_path='/public')
app.config.from_object('config.Configuration')
db = SQLAlchemy(app)
@app.route('/js/<path:path>')
def send_js(path):
return send_from_directory('public/js', path)
@app.route('/css/<path:path>')
def send_css(path):
return send_from_directory('public/css', path)
@app.route('/favicon.ico')
def favicon():
return send_from_directory(os.path.join(app.root_path, 'public', 'img'),
'favicon.ico',
mimetype='image/vnd.microsoft.icon')

10599
public/css/bulma.css vendored Normal file

File diff suppressed because it is too large Load diff

1
public/css/bulma.css.map Normal file

File diff suppressed because one or more lines are too long

1
public/css/bulma.min.css vendored Normal file

File diff suppressed because one or more lines are too long

3
public/css/index.css Normal file
View file

@ -0,0 +1,3 @@
a {
color: #ff9f00;
}

BIN
public/img/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

24
public/js/index.js Normal file
View file

@ -0,0 +1,24 @@
document.addEventListener('DOMContentLoaded', () => {
// Get all "navbar-burger" elements
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
// Check if there are any navbar burgers
if ($navbarBurgers.length > 0) {
// Add a click event on each of them
$navbarBurgers.forEach( el => {
el.addEventListener('click', () => {
// Get the target from the "data-target" attribute
const target = el.dataset.target;
const $target = document.getElementById(target);
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
});
});
}
});

27
public/js/users.js Normal file
View file

@ -0,0 +1,27 @@
function searchUser(search) {
matches = [];
users.forEach(user => {
if (user.id.toLowerCase().includes(search.toLowerCase())) {
matches.push(user);
}
});
if (matches.length === 0) {
document.getElementById("users-parent").innerHTML = "<p>No matches found</p>";
} else {
var html = "";
matches.forEach(match => {
html += `
<a href="/users/${match.id}" class="tile is-child box is-4">
<!-- The magical tile element! -->
<p class="title">${ match.id }</p>
<div class="content">
${ match.achievements.length } achievement${(match.achievements.length != 1) ? "s" : "" }
</div>
</a>
`
});
document.getElementById("users-parent").innerHTML = html;
}
}

View file

@ -1,3 +1,3 @@
#!/bin/bash
FLASK_APP="endorsement.py" flask run
FLASK_APP="endorsement.py" FLASK_DEBUG=true flask run

View file

@ -1,21 +1,36 @@
<html>
<body>
<h2>{{data.name}} by <a href="{{url_for('get_user', id=data.achieved_by)}}">{{ data.achieved_by }} </a></h2>
<ul>
{% for endorser in data.endorsed_by -%}
{% extends 'base.html' %}
{% block content %}
<div class="section">
<div class="container">
<h2 class="title is-2">Achievement: {{data.name}}</h2>
<h4 class="subtitle is-4">by <a href="{{url_for('get_user', id=data.achieved_by)}}">{{ data.achieved_by }} </a></h4>
<div class="menu">
<p></p>
<ul>
<li>
{% if endorsed -%}
<a href="{{url_for('unendorse_achievement', id=data.id)}}" class="has-text-danger">Unendorse</a>
{% else -%}
<a href="{{url_for('endorse_achievement', id=data.id)}}" class="has-text-success">Endorse</a>
{% endif -%}
</li>
</ul>
<p class="menu-label">Endorsed by</p>
<ul class="menu-list">
{% for endorser in data.endorsed_by -%}
<li>
<a href="{{url_for('get_user', id=endorser.id)}}">{{ endorser.id }} </a>
</li>
{% endfor -%}
{% if endorsed -%}
<li>
<a href="{{url_for('unendorse_achievement', id=data.id)}}">Unendorse</a>
</li>
{% else -%}
<li>
<a href="{{url_for('endorse_achievement', id=data.id)}}">Endorse</a>
</li>
{% endif -%}
</ul>
</body>
</html>
{% endfor -%}
</ul>
</div>
</div>
</div>
{% endblock %}

View file

@ -1,12 +1,42 @@
<html>
<body>
<h2>Insert cool name here</h2>
<ul>
{% for user in data -%}
<li>
<a href="{{url_for('get_user', id=user.id)}}">{{ user.id }}</a>: {{ user.achievements|length }} achievement{{ "s" if (user.achievements|length != 1) else "" }}
</li>
{% endfor -%}
</ul>
</body>
</html>
{% extends 'base.html' %}
{% block head %}
<script src="/js/users.js"></script>
{% endblock %}
{% block content %}
<div class="section">
<div class="container">
<h1 class="title is-2">Endorsements</h1>
<div class="field">
<p class="control has-icons-left has-icons-right">
<input oninput="searchUser(this.value)" class="input" type="text" placeholder="Search">
<span class="icon is-small is-left">
<i class="fas fa-search"></i>
</span>
</p>
</div>
<div class="tile is-ancestor">
<div id="users-parent" class="tile is-parent is-vertical">
{% for user in data -%}
<!-- If you update this block, update it also in the js search function -->
<a href="{{url_for('get_user', id=user.id)}}" class="tile is-child box is-4">
<!-- The magical tile element! -->
<p class="title">{{ user.id }}</p>
<div class="content">
{{ user.achievements|length }} achievement{{ "s" if (user.achievements|length != 1) else "" }}
</div>
</a>
{% endfor -%}
</div>
</div>
</div>
</div>
<script>
var users = {{ data|safe }};
</script>
{% endblock %}

62
templates/base.html Normal file
View file

@ -0,0 +1,62 @@
<html>
<head>
<link rel="stylesheet" href="/css/bulma.css" type="text/css">
<link rel="stylesheet" href="/css/index.css" type="text/css">
<script src="/js/index.js"></script>
{% block head %}
{% endblock %}
</head>
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="https://bulma.io">
<img src="https://bulma.io/images/bulma-logo.png" width="112" height="28">
</a>
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<a href="/" class="navbar-item">
Endorsements
</a>
<a href="/graph" class="navbar-item" disabled>
Graph
</a>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons">
<a class="button is-primary">
<strong>Log in</strong>
</a>
</div>
</div>
</div>
</div>
</nav>
<body>
{% block content %}
No content yet.
{% endblock %}
</body>
</html>

View file

@ -1,15 +1,34 @@
<html>
<body>
<form action="" method="post">
{{ form.csrf }}
<div class="input text">
{{ form.name.label }} {{ form.name }}
</div>
<div class="input submit">
<input type="submit" value="Add" />
</div>
</form>
</body>
</html>
{% extends 'base.html' %}
{% block content %}
<div class="section"><div class="container">
<h1 class="title">New achievement</h1>
<form action="" method="post">
{{ form.csrf }}
<div class="field">
<label class="label" for="{{form.name.label.for}}">Name</label>
<div class="control has-icons-left has-icons-right">
<input id="{{form.name.id}}" name="{{form.name.name}}" type="{{form.name.type}}" value="{{form.name.value}}" required="{{form.name.required}}" class="input" placeholder="the bestest boi" >
<span class="icon is-small is-left">
<i class="fas fa-user"></i>
</span>
<span class="icon is-small is-right">
<i class="fas fa-check"></i>
</span>
</div>
</div>
<div class="field">
<div class="control">
<button class="button is-link">Add</button>
</div>
</div>
</form>
</div></div>
{% endblock %}

View file

@ -1,13 +1,29 @@
<html>
<body>
<h2>{{data.id}}</h2>
<ul>
{% for achievement in data.achievements -%}
<li>
<a href="{{url_for('get_achievement', id=achievement.id)}}">{{ achievement.name }}</a>: {{ achievement.endorsed_by|length }} endorsement{{ "s" if (achievement.endorsed_by|length != 1) else "" }}
</li>
{% endfor -%}
<li> <a href="{{url_for('add_achievement', id=data.id)}}">Add achievement</a></li>
</ul>
</body>
</html>
{% extends 'base.html' %}
{% block content %}
<div class="section">
<div class="container">
<h1 class="title is-1">User: {{data.id}}</h1>
<h3 class="subtitle is-3">Achievements</h3>
<div class="tile is-ancestor">
<div class="tile is-parent is-vertical">
{% for achievement in data.achievements -%}
<a href="{{url_for('get_achievement', id=achievement.id)}}" class="tile is-child box is-4">
<!-- The magical tile element! -->
<p class="title">{{ achievement.name }}</p>
<div class="content">
{{ achievement.endorsed_by|length }} endorsement{{ "s" if (achievement.endorsed_by|length != 1) else "" }}
</div>
</a>
{% else %}
<h5 class="subtitle is-5">No achievements</h5>
{% endfor -%}
</div>
</div>
<a class="button" href="{{url_for('add_achievement', id=data.id)}}">Add achievement</a>
</div>
</div>
{% endblock %}

21
test.py
View file

@ -1,5 +1,8 @@
from models import User, Achievement
import random
import string
from app import db
from models import Achievement, User
db.drop_all()
db.create_all()
@ -13,6 +16,22 @@ achievementB = Achievement(name="BB", achieved_by=persoonB.id)
achievementA.endorsed_by.append(persoonC)
# Long generated lists
for i in range(30):
achievement = Achievement(name=''.join(
random.choices(string.ascii_uppercase + string.digits, k=6)),
achieved_by=persoonA.id)
db.session.add(achievement)
people = [
User(id=''.join(random.choices(string.ascii_uppercase +
string.digits, k=6))) for i in range(30)
]
for person in people:
db.session.add(person)
achievementA.endorsed_by.append(person)
db.session.add(persoonA)
db.session.add(persoonB)
db.session.add(persoonC)