cleanup and setup.py

master
km0 2 years ago
parent 330cf88089
commit 2f7d25bbb7

@ -2,7 +2,22 @@
![frog](cover.jpg) ![frog](cover.jpg)
A way to archive and retrieve all our pads. Now with a fast way to insert new pads without too much effort uiii. A way to create, archive and retrieve our pads. Now with a fast way to insert new pads without too much effort uiii.
# Features
- Custom categories
- Filter by categories
- Table sorting
- Create new pad if URL is not provided
# TODO
- Setup script
- Search
- Server side rendering?
![lifecycle](lifecycle.jpg) ![lifecycle](lifecycle.jpg)

@ -1,245 +0,0 @@
:root {
--bg: dodgerblue;
--color: white;
}
* {
box-sizing: border-box;
}
html,
body {
font-family: Arial, Helvetica, sans-serif;
line-height: 1.6;
color: var(--color);
background-color: var(--bg);
}
a {
color: currentColor;
}
.version {
font-size: 18px;
font-weight: normal;
}
input {
color: currentColor;
border: 1px solid currentColor;
outline: none;
padding: 0.4em;
margin: 0;
background: none;
}
input.overview {
width: 60ch;
}
button {
display: inline-block;
background: none;
border: 1px solid currentColor;
border-radius: 50%;
color: currentColor;
line-height: 1rem;
text-align: center;
padding: 0.4em;
cursor: pointer;
}
button.add {
display: inline-block;
width: 2em;
height: 2em;
font-size: 1em;
margin-left: 8px;
}
button.submit {
margin-left: 12px;
padding: 0.6em;
font-size: 1em;
}
button:hover {
background-color: var(--color);
color: var(--bg);
}
*:not(h2) + input {
margin-left: 12px;
}
.app-form {
display: inline-block;
padding-left: 12px;
border-left: 1px solid currentColor;
margin-top: 12px;
margin-bottom: 12px;
}
.app-form h2 {
margin: 0;
font-weight: normal;
}
table {
width: 100%;
}
table a {
text-decoration: none;
}
tr.header {
position: sticky;
top: 0;
background-color: var(--bg);
z-index: 100;
}
th {
text-align: left;
padding: 24px 0;
border-bottom: 1px solid currentColor;
text-transform: capitalize;
font-size: 21px;
user-select: none;
cursor: pointer;
}
td {
padding: 12px;
border-bottom: 1px solid currentColor;
}
td.title {
font-weight: bold;
}
td.overview,
th.overview {
flex-grow: 3;
}
td.overview p {
margin: 0;
}
tr {
position: relative;
transition: transform 0.1s ease-in;
}
tr:hover:not(:first-of-type) {
transition: transform 0.2s ease-out;
transform: translateX(10px);
}
.stretched:after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.loading {
font-size: 28px;
}
.grow {
animation: grow 5s;
}
.filter {
padding-left: 12px;
border-left: 1px solid currentColor;
margin-top: 32px;
margin-bottom: 48px;
}
.filter h2 {
font-weight: normal;
margin: 0;
margin-bottom: 8px;
}
.filter ul {
display: flex;
flex-wrap: wrap;
list-style: none;
gap: 8px;
margin: 0;
padding: 0;
}
.filter ul li,
.category {
display: inline-block;
border: 1px solid currentColor;
padding: 0 4px;
user-select: none;
cursor: pointer;
}
.filter .active {
background-color: var(--color);
color: var(--bg);
}
tr {
display: flex;
justify-content: space-between;
}
th,
td {
padding: 12px 12px;
}
th:first-of-type,
td:first-child {
padding-left: 0;
}
th:last-of-type,
td:last-child {
padding-right: 0;
}
th.date,
td.date {
flex-grow: 0.4;
margin-left: auto;
}
tr > * {
flex: 1;
}
td.categories {
align-content: flex-start;
display: flex;
flex-wrap: wrap;
gap: 8px;
height: auto;
}
.categories .category {
border: none;
}
@keyframes grow {
from {
transform: scale(100%);
}
to {
transform: scale(0, 1000%) rotate(1turn);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 722 KiB

After

Width:  |  Height:  |  Size: 713 KiB

@ -1,5 +1,5 @@
# Flask application to serve the web pages # Flask application to serve the web pages
from flask import Flask, request, redirect, url_for, jsonify from flask import Flask, request, redirect, url_for, jsonify, render_template
from flask_cors import CORS from flask_cors import CORS
# Mediawiki client to interact with the Wiki # Mediawiki client to interact with the Wiki
@ -14,10 +14,6 @@ import os
from dotenv import load_dotenv from dotenv import load_dotenv
from pathlib import Path from pathlib import Path
# datetime to work with dates
from datetime import datetime
# load the mediawiki credentials from the shared folder # load the mediawiki credentials from the shared folder
dotenv_path = Path("/var/www/.mw-credentials") dotenv_path = Path("/var/www/.mw-credentials")
load_dotenv(dotenv_path=dotenv_path) load_dotenv(dotenv_path=dotenv_path)
@ -47,11 +43,14 @@ app = Flask(__name__)
CORS(app) CORS(app)
# Url prefix for the soupboat # Url prefix for the soupboat and port
base_url = os.environ.get('BASE_URL', '') base_url = os.environ.get('BASE_URL', '')
port = os.environ.get('FLASK_RUN_PORT', '')
# Page of the wiki with the pads # Page of the wiki with the pads
padliography = 'Padliography2' padliography = os.environ.get('PAGE', '')
# register the middleware to prefix all the requests with our base_url # register the middleware to prefix all the requests with our base_url
app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix=base_url) app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix=base_url)
@ -98,8 +97,13 @@ def get_pads():
return pads return pads
@app.route('/', methods=['GET', 'POST'])
@app.route('/')
def home(): def home():
return render_template('home.html')
@app.route('/api/', methods=['GET', 'POST'])
def api():
if request.method == 'POST': if request.method == 'POST':
link = request.json.get('link', None) link = request.json.get('link', None)
@ -108,8 +112,8 @@ def home():
categories = request.json.get('categories', '') categories = request.json.get('categories', '')
date = request.json.get('date', None) date = request.json.get('date', None)
date = datetime.strftime(datetime.strptime( # date = datetime.strftime(datetime.strptime(
date, 'yyyy-mm-dd'), 'dd-mm-yyyy') # date, '%Y-%m-%d'), '%d-%m-%Y')
add_pad(link, title, overview, categories, date) add_pad(link, title, overview, categories, date)
redirect(url_for('home')) redirect(url_for('home'))
@ -121,4 +125,4 @@ def home():
return jsonify(response) return jsonify(response)
app.run(port=3147) app.run(port=port)

@ -0,0 +1,16 @@
from setuptools import find_packages, setup
setup(
name='Padliography',
version='2.0.0',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
install_requires=[
'flask',
'flask_cors',
'bs4',
'mwclient',
'python-dotenv',
],
)

@ -1,124 +1,245 @@
body { :root {
font-size: 1.5rem; --bg: dodgerblue;
margin: 0; --color: white;
background: rgb(255, 244, 235);
} }
.contents { * {
margin: 32px; box-sizing: border-box;
} }
h1 { html,
color: #ecab72; body {
margin: 32px; font-family: Arial, Helvetica, sans-serif;
text-align: center; line-height: 1.6;
color: var(--color);
background-color: var(--bg);
} }
a { a {
color: currentColor; color: currentColor;
} }
a.stretched-link::after { .version {
content: ""; font-size: 18px;
position: absolute; font-weight: normal;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
} }
/* FILTERS */ input {
color: currentColor;
.tag { border: 1px solid currentColor;
outline: none;
padding: 0.4em;
margin: 0;
background: none; background: none;
font-size: 20px; }
input.overview {
width: 60ch;
}
button {
display: inline-block; display: inline-block;
background: none;
border: 1px solid currentColor; border: 1px solid currentColor;
padding: 0 0.5em; border-radius: 50%;
border-radius: 1em; color: currentColor;
margin: 4px; line-height: 1rem;
text-transform: capitalize; text-align: center;
user-select: none; padding: 0.4em;
cursor: pointer; cursor: pointer;
}
transform: translateY(0); button.add {
transition: transform 0.4s ease-in; display: inline-block;
width: 2em;
height: 2em;
font-size: 1em;
margin-left: 8px;
} }
.tag.active { button.submit {
background-color: white; margin-left: 12px;
padding: 0.6em;
font-size: 1em;
} }
.tag.active.all { button:hover {
background: none; background-color: var(--color);
color: var(--bg);
} }
.filters .tag:focus, *:not(h2) + input {
.filters .tag:hover { margin-left: 12px;
transform: translateY(-4px);
transition: transform 0.2s ease-out;
} }
ul { .app-form {
padding: 0; display: inline-block;
padding-left: 12px;
border-left: 1px solid currentColor;
margin-top: 12px;
margin-bottom: 12px;
} }
/* TABLE */ .app-form h2 {
margin: 0;
font-weight: normal;
}
table { table {
border-collapse: collapse; width: 100%;
}
table a {
text-decoration: none;
}
tr.header {
position: sticky;
top: 0;
background-color: var(--bg);
z-index: 100;
}
th {
text-align: left;
padding: 24px 0;
border-bottom: 1px solid currentColor;
text-transform: capitalize;
font-size: 21px;
user-select: none;
cursor: pointer;
}
td {
padding: 12px;
border-bottom: 1px solid currentColor;
}
td.title {
font-weight: bold;
}
td.overview,
th.overview {
flex-grow: 3;
}
td.overview p {
margin: 0;
} }
tr { tr {
/* display: none; */
position: relative; position: relative;
transition: transform 0.1s ease-in;
}
tr:hover:not(:first-of-type) {
transition: transform 0.2s ease-out;
transform: translateX(10px);
} }
tr:nth-child(even) { .stretched:after {
background-color: rgb(251, 237, 225); content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
} }
tr.active { .loading {
display: table-row; font-size: 28px;
} }
tr:hover { .grow {
background-color: rgb(250, 232, 217); animation: grow 5s;
} }
tr .tag { .filter {
cursor: default; padding-left: 12px;
border-left: 1px solid currentColor;
margin-top: 32px;
margin-bottom: 48px;
} }
tr.header { .filter h2 {
display: table-row; font-weight: normal;
text-align: left; margin: 0;
margin-bottom: 8px;
}
.filter ul {
display: flex;
flex-wrap: wrap;
list-style: none;
gap: 8px;
margin: 0;
padding: 0;
} }
.categories { .filter ul li,
width: 20%; .category {
display: inline-block;
border: 1px solid currentColor;
padding: 0 4px;
user-select: none;
cursor: pointer;
} }
.overview { .filter .active {
font-style: italic; background-color: var(--color);
width: 40%; color: var(--bg);
} }
.date { tr {
width: 14ch; display: flex;
justify-content: space-between;
} }
form { th,
margin: 32px; td {
display: inline-block; padding: 12px 12px;
padding: 2rem;
background-color: rgb(250, 232, 217);
border-radius: 50%;
} }
form h2 { th:first-of-type,
margin: 0; td:first-child {
margin-bottom: 16px; padding-left: 0;
font-size: 28px; }
th:last-of-type,
td:last-child {
padding-right: 0;
}
th.date,
td.date {
flex-grow: 0.4;
margin-left: auto;
}
tr > * {
flex: 1;
}
td.categories {
align-content: flex-start;
display: flex;
flex-wrap: wrap;
gap: 8px;
height: auto;
}
.categories .category {
border: none;
}
@keyframes grow {
from {
transform: scale(100%);
}
to {
transform: scale(0, 1000%) rotate(1turn);
}
} }

@ -25,14 +25,14 @@ export default {
link.value = newPad(); link.value = newPad();
} }
fetch("https://hub.xpub.nl/soupboat/padliography/", { fetch("api", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ body: JSON.stringify({
title: title.value.trim(), title: title.value.trim(),
link: link.value, link: link.value,
overview: overview.value, overview: overview.value,
categories: categories.value, categories: categories.value.join(", "),
date: date.value, date: date.value,
}), }),
}); });

@ -16,11 +16,11 @@ export default {
selected.value.has(tag) ? selected.value.delete(tag) : selected.value.add(tag); selected.value.has(tag) ? selected.value.delete(tag) : selected.value.add(tag);
}; };
// fetch("https://hub.xpub.nl/soupboat/padliography/") fetch("api")
fetch("http://127.0.0.1:3147/")
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
pads.value = data.pads; pads.value = data.pads;
pads.value.map( pads.value.map(
(pad) => (pad) =>
(pad.categories = pad.categories (pad.categories = pad.categories

@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}" />
<script src="https://unpkg.com/vue@3"></script> <script src="https://unpkg.com/vue@3"></script>
<title>Padliography</title> <title>Padliography</title>
</head> </head>
@ -16,8 +16,8 @@
</div> </div>
<script type="module"> <script type="module">
import PadForm from "./components/PadForm.js"; import PadForm from "{{url_for('static', filename='js/components/PadForm.js')}}";
import PadTable from "./components/PadTable.js"; import PadTable from "{{url_for('static', filename='js/components/PadTable.js')}}";
const { createApp } = Vue; const { createApp } = Vue;
Loading…
Cancel
Save