frontend, etc.
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
import sqlalchemy
|
||||
from sqlalchemy.ext.automap import automap_base
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
Base = automap_base()
|
||||
|
||||
dbEngine = sqlalchemy.create_engine('sqlite:///db.sqlite')
|
||||
|
||||
def get_token_header():
|
||||
pass
|
||||
dbSession = Session(dbEngine)
|
||||
|
||||
Base.prepare(dbEngine, reflect=True)
|
||||
|
||||
24
app/main.py
24
app/main.py
@@ -1,16 +1,30 @@
|
||||
from fastapi import FastAPI
|
||||
from app.routers import admin, user
|
||||
from fastapi import FastAPI, Request
|
||||
from app.routers import admin, user, songs
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
app.include_router(admin.router)
|
||||
app.include_router(user.router)
|
||||
app.include_router(songs.router)
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def root():
|
||||
return {"message": "Hello World"}
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def root(request: Request, session_id : str = ""):
|
||||
if session_id == "":
|
||||
return templates.TemplateResponse(
|
||||
request=request, name="landing.html"
|
||||
)
|
||||
else:
|
||||
return templates.TemplateResponse(
|
||||
request=request, name="voting.html"
|
||||
)
|
||||
|
||||
# 1PMy17eraogNUz436w3aZKxyij39G1didaN02Ka_-45Q
|
||||
# 71046222
|
||||
@@ -1,8 +1,7 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, Security
|
||||
from app.models import Genre, Song, GoogleFile
|
||||
from app.dependencies import get_token_header, dbEngine
|
||||
from app.routers.user import get_current_user, User
|
||||
from typing import Annotated
|
||||
from fastapi import APIRouter, HTTPException, Security, File, UploadFile
|
||||
from app.models import GoogleFile
|
||||
from app.dependencies import dbEngine
|
||||
from app.routers.user import get_current_user
|
||||
import gspread
|
||||
from gspread.urls import DRIVE_FILES_API_V3_URL
|
||||
import pandas as pd
|
||||
@@ -93,3 +92,8 @@ def process_worksheets():
|
||||
song_list.to_sql(name='songs', con=dbEngine,
|
||||
index=False, if_exists='append')
|
||||
# song_list.to_csv("song-list.csv")
|
||||
|
||||
|
||||
@router.post("/process_file")
|
||||
async def create_upload_file(file: UploadFile):
|
||||
return {"filename": file.filename}
|
||||
16
app/routers/songs.py
Normal file
16
app/routers/songs.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from fastapi import APIRouter, HTTPException, Security
|
||||
from app.models import Song
|
||||
from app.dependencies import dbEngine, Base, dbSession
|
||||
from app.routers.user import get_current_user, User
|
||||
from typing import Annotated
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/songs",
|
||||
#dependencies=[Security(get_current_user, scopes=["public"])],
|
||||
responses={404: {"description": "Not found"}},
|
||||
)
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def get_songs() -> list[dict]:
|
||||
return dbSession.query(Base.songs).all()
|
||||
@@ -12,7 +12,7 @@ from app.secrets import SECRET_KEY, fake_users_db
|
||||
# openssl rand -hex 32
|
||||
|
||||
ALGORITHM = "HS256"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES = 30
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 31
|
||||
|
||||
|
||||
class Token(BaseModel):
|
||||
@@ -42,7 +42,8 @@ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
oauth2_scheme = OAuth2PasswordBearer(
|
||||
tokenUrl="user/token",
|
||||
scopes={
|
||||
"admin": "Perform admin actions."
|
||||
"admin": "Perform admin actions.",
|
||||
"public": "Perform public actions."
|
||||
}
|
||||
)
|
||||
|
||||
@@ -65,6 +66,7 @@ def get_user(db, username: str):
|
||||
return UserInDB(**user_dict)
|
||||
|
||||
|
||||
|
||||
def authenticate_user(fake_db, username: str, password: str):
|
||||
user = get_user(fake_db, username)
|
||||
if not user:
|
||||
@@ -84,7 +86,6 @@ def create_access_token(data: dict, expires_delta: timedelta | None = None):
|
||||
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||
return encoded_jwt
|
||||
|
||||
|
||||
async def get_current_user(
|
||||
security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)]
|
||||
):
|
||||
@@ -144,3 +145,11 @@ async def login_for_access_token(
|
||||
data={"sub": user.username, "scopes": user.scopes}, expires_delta=access_token_expires
|
||||
)
|
||||
return Token(access_token=access_token, token_type="bearer")
|
||||
|
||||
# @router.get("/public_token")
|
||||
# async def get_public_access_token(secret_identity : str) -> Token:
|
||||
# access_token_expires = timedelta(minutes=60*24*365)
|
||||
# access_token = create_access_token(
|
||||
# data={"sub": "public", "secret_identity" : secret_identity, "scopes": ["public"]}, expires_delta=access_token_expires
|
||||
# )
|
||||
# return Token(access_token=access_token, token_type="bearer")
|
||||
@@ -7,3 +7,4 @@ sqlalchemy
|
||||
python-jose[cryptography]
|
||||
passlib[bcrypt]
|
||||
python-multipart
|
||||
jinja2
|
||||
90
static/colors.css
Normal file
90
static/colors.css
Normal file
@@ -0,0 +1,90 @@
|
||||
.cat-1 {
|
||||
background-color: #1f77b4;
|
||||
}
|
||||
.cat-2 {
|
||||
background-color: #ff7f0e;
|
||||
}
|
||||
.cat-3 {
|
||||
background-color: #2ca02c;
|
||||
}
|
||||
.cat-4 {
|
||||
background-color: #d62728;
|
||||
}
|
||||
.cat-5 {
|
||||
background-color: #9467bd;
|
||||
}
|
||||
.cat-6 {
|
||||
background-color: #8c564b;
|
||||
}
|
||||
.cat-7 {
|
||||
background-color: #e377c2;
|
||||
}
|
||||
.cat-8 {
|
||||
background-color: #7f7f7f;
|
||||
}
|
||||
.cat-9 {
|
||||
background-color: #bcbd22;
|
||||
}
|
||||
.cat-10 {
|
||||
background-color: #17becf;
|
||||
}
|
||||
.cat-11 {
|
||||
background-color: #a1c9f4;
|
||||
}
|
||||
.cat-12 {
|
||||
background-color: #ffb482;
|
||||
}
|
||||
.cat-13 {
|
||||
background-color: #8de5a1;
|
||||
}
|
||||
.cat-14 {
|
||||
background-color: #ff9f9b;
|
||||
}
|
||||
.cat-15 {
|
||||
background-color: #d0bbff;
|
||||
}
|
||||
.cat-16 {
|
||||
background-color: #debb9b;
|
||||
}
|
||||
.cat-17 {
|
||||
background-color: #fab0e4;
|
||||
}
|
||||
.cat-18 {
|
||||
background-color: #cfcfcf;
|
||||
}
|
||||
.cat-19 {
|
||||
background-color: #fffea3;
|
||||
}
|
||||
.cat-20 {
|
||||
background-color: #b9f2f0;
|
||||
}
|
||||
.cat-21 {
|
||||
background-color: #001c7f;
|
||||
}
|
||||
.cat-22 {
|
||||
background-color: #b1400d;
|
||||
}
|
||||
.cat-23 {
|
||||
background-color: #12711c;
|
||||
}
|
||||
.cat-24 {
|
||||
background-color: #8c0800;
|
||||
}
|
||||
.cat-25 {
|
||||
background-color: #591e71;
|
||||
}
|
||||
.cat-26 {
|
||||
background-color: #592f0d;
|
||||
}
|
||||
.cat-27 {
|
||||
background-color: #a23582;
|
||||
}
|
||||
.cat-28 {
|
||||
background-color: #3c3c3c;
|
||||
}
|
||||
.cat-29 {
|
||||
background-color: #b8850a;
|
||||
}
|
||||
.cat-30 {
|
||||
background-color: #006374;
|
||||
}
|
||||
BIN
static/cover.jpg
Normal file
BIN
static/cover.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 133 KiB |
15
static/index.html
Normal file
15
static/index.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Hello jQuery</title>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
||||
<script src="hello.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<p class="greeting-id">The ID is </p>
|
||||
<p class="greeting-content">The content is </p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
8
static/landing_script.js
Normal file
8
static/landing_script.js
Normal file
@@ -0,0 +1,8 @@
|
||||
$(document).ready(function () {
|
||||
var s_id = localStorage.getItem('session_id')
|
||||
if (s_id === null) {
|
||||
s_id = window.crypto.randomUUID();
|
||||
localStorage.setItem('session_id', s_id)
|
||||
}
|
||||
$('.vote-from-existing').attr('href', '?session_id=' + s_id);
|
||||
});
|
||||
22
static/neutral.svg
Normal file
22
static/neutral.svg
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
|
||||
<svg
|
||||
width="326.09866"
|
||||
height="533.33331"
|
||||
viewBox="0 0 9.7829599 15.999999"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<path
|
||||
d="m 4.78296,15 h 0.01 M 1,3.69689 C 1.54049,2.12753 3.03006,1 4.78296,1 c 2.2091,0 4,1.79086 4,4 0,1.6565 -1.0069,3.0778 -2.442,3.6852 -0.7408,0.3136 -1.1112,0.4704 -1.2408,0.5915 -0.1543,0.1442 -0.1836,0.1884 -0.2562,0.3867 -0.061,0.1665 -0.061,0.4232 -0.061,0.9366 V 12"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
id="path1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 789 B |
22
static/no.svg
Normal file
22
static/no.svg
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
|
||||
<svg
|
||||
width="466.66666"
|
||||
height="466.66666"
|
||||
viewBox="0 0 14 14"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<path
|
||||
d="M 1,1 13,13 M 13,1 1,13"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
id="path1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 529 B |
23
static/play.svg
Normal file
23
static/play.svg
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
|
||||
<svg
|
||||
width="259.76822"
|
||||
height="419.52487"
|
||||
viewBox="0 0 7.7930466 12.585746"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<path
|
||||
d="m 1.0001448,2.2242414 v 8.1372996 c 0,0.6058 0,0.9087 0.1198,1.0489 0.10394,0.1218 0.25987,0.1863 0.41943,0.1738 0.18389,-0.0145 0.39808,-0.2287 0.82647,-0.6571 l 4.0686,-4.0685996 c 0.198,-0.198 0.297,-0.297 0.3341,-0.4112 0.0327,-0.1004 0.0327,-0.2086 0,-0.309 -0.0371,-0.1141 -0.1361,-0.2131 -0.3341,-0.4112 l -4.0686,-4.06859 c -0.42839,-0.42837 -0.64258,-0.64256 -0.82647,-0.65703 -0.15956,-0.01256 -0.31549,0.05203 -0.41943,0.17373 -0.1198,0.14026 -0.1198,0.44317 -0.1198,1.04899 z"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
id="path1"
|
||||
style="stroke:#000000;stroke-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
184
static/site.css
Normal file
184
static/site.css
Normal file
@@ -0,0 +1,184 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
@media only screen and (min-resolution: 200dpi) {
|
||||
body {
|
||||
font-size: 3.2vmin;
|
||||
}
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.song {
|
||||
background-color: #f0f0f0;
|
||||
padding: 0.4em;
|
||||
border-radius: 0.5em;
|
||||
width: 30em;
|
||||
font-family: sans-serif;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
||||
.cover-container {
|
||||
position: relative;
|
||||
width: 10.67em;
|
||||
height: 6em;
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.cover {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
|
||||
.overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
transition: .3s ease;
|
||||
}
|
||||
|
||||
.cover-container:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cover-container:hover .overlay {
|
||||
opacity: 1;
|
||||
filter: drop-shadow(0px 0px 1em black);
|
||||
}
|
||||
|
||||
.overlay img {
|
||||
height: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
-ms-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
filter: invert();
|
||||
transition: .1s ease;
|
||||
}
|
||||
|
||||
.cover-container:active .overlay img {
|
||||
height: 60%;
|
||||
}
|
||||
|
||||
|
||||
.vote-buttons {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.button {
|
||||
height: 2em;
|
||||
width: 3em;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
font-size: 1.5em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.button img {
|
||||
height: 30%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
-ms-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
transition: .1s ease;
|
||||
}
|
||||
|
||||
.button:active img {
|
||||
height: 40%;
|
||||
}
|
||||
|
||||
.button-no {
|
||||
background-color: #e1412f;
|
||||
border-top-left-radius: 1em;
|
||||
border-bottom-left-radius: 1em;
|
||||
}
|
||||
|
||||
.button-neutral {
|
||||
background-color: #f5bb00;
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.button-yes {
|
||||
background-color: #48a84f;
|
||||
border-top-right-radius: 1em;
|
||||
border-bottom-right-radius: 1em;
|
||||
}
|
||||
|
||||
.button:not(.selected):not(:hover) {
|
||||
background-color: #b0b0b0;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
filter: drop-shadow(2px 2px 2px) brightness(95%);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button span {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.button-no span {
|
||||
top: 10%;
|
||||
}
|
||||
|
||||
.button-yes span {
|
||||
top: 10%;
|
||||
}
|
||||
|
||||
.button-neutral span {
|
||||
top: 20%;
|
||||
}
|
||||
|
||||
.categories {
|
||||
width: 60%;
|
||||
overflow: hidden;
|
||||
cursor: grab;
|
||||
white-space: nowrap;
|
||||
font-size: 0.7em;
|
||||
line-height: 1.2em;
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
|
||||
.categories span {
|
||||
border-radius: 1.2em;
|
||||
padding: 0 0.5em 0 0.5em;
|
||||
margin-right: 0.4em;
|
||||
display: inline-block;
|
||||
color: white;
|
||||
max-width: 10em;
|
||||
overflow: clip;
|
||||
}
|
||||
|
||||
.vote-buttons {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.song-data {
|
||||
width: 100%;
|
||||
overflow: clip;
|
||||
white-space: nowrap;
|
||||
}
|
||||
70
static/voting_script.js
Normal file
70
static/voting_script.js
Normal file
@@ -0,0 +1,70 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const eles = document.getElementsByClassName('categories');
|
||||
Array.prototype.forEach.call(eles, ele => {
|
||||
|
||||
|
||||
//ele.style.cursor = 'grab';
|
||||
|
||||
let pos = { top: 0, left: 0, x: 0, y: 0 };
|
||||
|
||||
const mouseDownHandler = function (e) {
|
||||
ele.style.cursor = 'grabbing';
|
||||
ele.style.userSelect = 'none';
|
||||
|
||||
pos = {
|
||||
left: ele.scrollLeft,
|
||||
top: ele.scrollTop,
|
||||
// Get the current mouse position
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', mouseMoveHandler);
|
||||
document.addEventListener('mouseup', mouseUpHandler);
|
||||
};
|
||||
|
||||
const mouseMoveHandler = function (e) {
|
||||
// How far the mouse has been moved
|
||||
const dx = e.clientX - pos.x;
|
||||
const dy = e.clientY - pos.y;
|
||||
|
||||
// Scroll the element
|
||||
ele.scrollTop = pos.top - dy;
|
||||
ele.scrollLeft = pos.left - dx;
|
||||
};
|
||||
|
||||
const mouseUpHandler = function () {
|
||||
ele.style.cursor = 'grab';
|
||||
ele.style.removeProperty('user-select');
|
||||
|
||||
document.removeEventListener('mousemove', mouseMoveHandler);
|
||||
document.removeEventListener('mouseup', mouseUpHandler);
|
||||
};
|
||||
|
||||
// Attach the handler
|
||||
ele.addEventListener('mousedown', mouseDownHandler);
|
||||
});
|
||||
});
|
||||
|
||||
const getQueryParameter = (param) => new URLSearchParams(document.location.search.substring(1)).get(param);
|
||||
|
||||
$(document).ready(function () {
|
||||
var session_id = getQueryParameter("session_id");
|
||||
|
||||
$(".greeting-id").append(session_id);
|
||||
$(".greeting-id").append("Foo");
|
||||
$.ajax({
|
||||
url: "/songs"
|
||||
}).then(function (user_list) {
|
||||
$('.greeting-id').append(user_list.total);
|
||||
localStorage.setItem("test-storage", user_list.total);
|
||||
var users = [];
|
||||
$.each(user_list.data, function (key, user) {
|
||||
users.push("<li id='" + user.id + "'>" + user.first_name + "</li>");
|
||||
});
|
||||
$("<ul/>", {
|
||||
"class": "my-new-list",
|
||||
html: users.join("")
|
||||
}).appendTo("body");
|
||||
});
|
||||
});
|
||||
22
static/yes.svg
Normal file
22
static/yes.svg
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
|
||||
<svg
|
||||
width="600"
|
||||
height="433.33197"
|
||||
viewBox="0 0 18 12.999959"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<path
|
||||
d="M 1,7.1111 5.92308,12 17,1"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
id="path1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 533 B |
9
templates/item.html
Normal file
9
templates/item.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Item Details</title>
|
||||
<link href="{{ url_for('static', path='/styles.css') }}" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<h1><a href="test.html">Item ID: {{ id }}</a></h1>
|
||||
</body>
|
||||
</html>
|
||||
15
templates/landing.html
Normal file
15
templates/landing.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Liederwahl</title>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
||||
<script src="{{ url_for('static', path='/landing_script.js') }}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<p><a href="" class="vote-from-existing">Abstimmen</a></p>
|
||||
<!--<p>Fange eine neue Abstimmung an<a href="">Abstimmen</a></p>-->
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
27
templates/voting.html
Normal file
27
templates/voting.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Liederwahl</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', path='/colors.css') }}">
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', path='/site.css') }}">
|
||||
<script src="{{ url_for('static', path='/voting_script.js') }}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="song">
|
||||
<div class="cover-container">
|
||||
<img src="{{ url_for('static', path='/cover.jpg') }}" class="cover">
|
||||
<div class="overlay"><img src="{{ url_for('static', path='/play.svg') }}"></div>
|
||||
</div>
|
||||
<div class="song-data">VoicePlay: In The Air Tonight</div>
|
||||
<div class="categories" id="container">
|
||||
<span class="cat-1">Ballade</span><span class="cat-2">< 90er Remake</span><span class="cat-3">Something else </span><span class="cat-4">Something else </span>
|
||||
</div>
|
||||
<div class="vote-buttons">
|
||||
<div class="button button-no"><img src="{{ url_for('static', path='/no.svg') }}"></div><div class="button button-neutral"><img src="{{ url_for('static', path='/neutral.svg') }}"></div><div class="button button-yes selected"><img src="{{ url_for('static', path='/yes.svg') }}"></div>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user