split ui into smaller templates and separate css

This commit is contained in:
glyph 2022-07-07 09:02:13 +01:00
parent 56b5609da3
commit 801934e5aa
9 changed files with 205 additions and 168 deletions

View File

@ -1,7 +1,9 @@
use async_std::channel::Sender;
use log::{debug, warn};
use markdown;
use rocket::{form::Form, get, post, response::Redirect, uri, FromForm, State};
use rocket_dyn_templates::{tera::Context, Template};
use uri_encode;
use crate::{db::Database, sbot, task_loop::Task, utils, WhoAmI};
@ -17,7 +19,7 @@ pub async fn home(db: &State<Database>) -> Template {
let mut context = Context::new();
context.insert("peers", &peers);
Template::render("home", &context.into_json())
Template::render("base", &context.into_json())
}
#[get("/posts/<public_key>")]
@ -30,7 +32,7 @@ pub async fn posts(db: &State<Database>, public_key: &str) -> Template {
context.insert("peers", &peers);
context.insert("posts", &posts);
Template::render("home", &context.into_json())
Template::render("base", &context.into_json())
}
#[get("/posts/<public_key>/<msg_id>")]
@ -41,12 +43,54 @@ pub async fn post(db: &State<Database>, public_key: &str, msg_id: &str) -> Templ
let mut context = Context::new();
context.insert("selected_peer", &public_key);
context.insert(
"selected_peer_encoded",
&uri_encode::encode_uri_component(public_key),
);
context.insert("selected_post", &msg_id);
context.insert(
"selected_post_encoded",
&uri_encode::encode_uri_component(msg_id),
);
context.insert("peers", &peers);
context.insert("posts", &posts);
// TODO: consider converting markdown to html here
context.insert("post", &post);
context.insert("post_is_selected", &true);
Template::render("home", &context.into_json())
Template::render("base", &context.into_json())
}
#[get("/posts/<public_key>/<msg_id>/read")]
pub async fn mark_post_read(db: &State<Database>, public_key: &str, msg_id: &str) -> Redirect {
// Retrieve the post from the database, mark it as read and reinsert it.
if let Ok(Some(mut post)) = db.get_post(public_key, msg_id) {
post.read = true;
db.add_post(public_key, post).unwrap();
} else {
warn!(
"failed to find post {} authored by {} in database",
msg_id, public_key
)
}
Redirect::to(uri!(post(public_key, msg_id)))
}
#[get("/posts/<public_key>/<msg_id>/unread")]
pub async fn mark_post_unread(db: &State<Database>, public_key: &str, msg_id: &str) -> Redirect {
// Retrieve the post from the database, mark it as unread and reinsert it.
if let Ok(Some(mut post)) = db.get_post(public_key, msg_id) {
post.read = false;
db.add_post(public_key, post).unwrap();
} else {
warn!(
"failed to find post {} authored by {} in database",
msg_id, public_key
)
}
Redirect::to(uri!(post(public_key, msg_id)))
}
#[post("/subscribe", data = "<peer>")]
@ -77,6 +121,8 @@ pub async fn subscribe_form(
_ => (),
}
let peer = peer.public_key.to_string();
// Fetch all root posts authored by the peer we're subscribing
// to. Posts will be added to the key-value database.
if let Err(e) = tx.send(Task::FetchAll(peer)).await {
warn!("task loop error: {}", e)
}

85
static/css/lykin.css Normal file
View File

@ -0,0 +1,85 @@
.nav {
background-color: lightgreen;
border: 5px solid #19A974;
border-radius: 15px;
grid-area: nav;
padding: 1rem;
}
.peers {
background-color: lightblue;
border: 5px solid #357EDD;
border-radius: 15px;
grid-area: peers;
}
.posts {
background-color: bisque;
border: 5px solid #FF6300;
border-radius: 15px;
grid-area: posts;
overflow-y: scroll;
}
.post > ul {
padding-left: 25px;
padding-right: 25px;
}
.content {
background-color: lightyellow;
border: 5px solid #FFD700;
border-radius: 15px;
grid-area: content;
padding: 1.5rem;
overflow-y: scroll;
word-wrap: anywhere;
}
.container {
height: 100%;
width: 100%;
margin: 0;
}
/*
.flex-container {
display: flex;
justify-content: space-between;
}
*/
.grid-container {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: 1fr 3fr 4fr;
grid-template-areas:
'nav nav nav nav nav'
'peers posts posts posts posts'
'peers content content content content';
grid-gap: 10px;
padding-left: 15px;
padding-right: 15px;
padding-top: 5px;
overflow: hidden;
height: 85vh;
}
.grid-container > div {
/* background-color: rgba(255, 255, 255, 0.8); */
/* text-align: center; */
/* padding: 20px 0; */
/* font-size: 30px; */
}
.flex-container {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.flex-container > input {
margin: 5px;
}
a { text-decoration: none; color: black; }

20
templates/base.html.tera Normal file
View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>lykin</title>
<meta name="description" content="lykin: an SSB tutorial application">
<meta name="author" content="glyph">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/css/lykin.css">
</head>
<body class="container">
<a href="/"><h1 style="margin-left: 15px;">lykin</h1></a>
<div class="grid-container">
{% include "topbar" %}
{% include "peer_list" %}
{% include "post_list" %}
{% include "post_content" %}
</div>
</body>
</html>

View File

@ -1,133 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>lykin</title>
<meta name="description" content="lykin: an SSB tutorial application">
<meta name="author" content="glyph">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
.nav {
grid-area: nav;
border: 5px solid #19A974;
border-radius: 15px;
padding: 1rem;
}
.peers {
grid-area: peers;
border: 5px solid #357EDD;
border-radius: 15px;
}
.posts {
grid-area: posts;
border: 5px solid #FF6300;
border-radius: 15px;
overflow-y: scroll;
}
.content {
border: 5px solid #FFD700;
border-radius: 15px;
grid-area: content;
padding: 1.5rem;
}
.container {
height: 100%;
width: 100%;
margin: 0;
}
.flex-container {
display: flex;
justify-content: space-between;
}
.grid-container {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: 1fr 200px 4fr;
grid-template-areas:
'nav nav nav nav nav'
'peers posts posts posts posts'
'peers content content content content';
grid-gap: 10px;
padding-left: 15px;
padding-right: 15px;
padding-top: 5px;
overflow: hidden;
}
.grid-container > div {
background-color: rgba(255, 255, 255, 0.8);
/* text-align: center; */
/* padding: 20px 0; */
/* font-size: 30px; */
}
.flex-container {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.flex-container > input {
margin: 5px;
}
a { text-decoration: none; color: black; }
</style>
</head>
<body class="container">
<a href="/"><h1 style="margin-left: 15px;">lykin</h1></a>
<div class="grid-container">
<div class="nav">
<div class="flex-container">
<a href="/"><img src="/icons/download.png" style="width: 55px;"></a>
<a href="/" style="margin-left: 20px;"><img src="/icons/read_post.png" style="width: 55px;"></a>
<a href="/" style="margin-left: 20px;"><img src="/icons/unread_post.png" style="width: 55px;"></a>
<a href="/" style="margin-left: 20px;"><img src="/icons/delete_post.png" style="width: 55px;"></a>
<form class="flex-container" style="margin-left: auto; margin-right: 10px;" action="/subscribe" method="post">
<label for="public_key">Public Key</label>
<input type="text" id="public_key" name="public_key" size=50 maxlength=53>
<input type="submit" value="Subscribe">
<input type="submit" value="Unsubscribe" formaction="/unsubscribe">
</form>
</div>
</div>
<div class="peers" style="text-align: center;">
<ul style="padding-left: 0;">
{% for peer in peers -%}
<li style="list-style: none; font-size: 12px;">
<a href="/posts/{{ peer | replace(from="/", to="%2F") }}">
<code style="word-wrap: anywhere;{% if selected_peer and peer == selected_peer %} font-weight: bold;{% endif %}">{{ peer }}</code>
</a>
</li>
{%- endfor %}
</ul>
</div>
<div class="posts">
{% if posts %}
<ul style="padding-left: 25px;">
{% for post in posts -%}
<li class="flex" style="list-style: none; font-size: 12px;">
<a href="/posts/{{ selected_peer | replace(from="/", to="%2F") }}/{{ post.key | replace(from="/", to="%2F") }}">
<code style="word-wrap: anywhere;{% if selected_post and post.key == selected_post %} font-weight: bold;{% endif %}">{{ post.key }}</code>
| {{ post.date }}
</a>
</li>
{%- endfor %}
</ul>
{% endif %}
</div>
<div class="content">
{% if post %}
{{ post.text }}
{% endif %}
</div>
</div>
</body>
</html>

View File

@ -1,32 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>lykin</title>
<meta name="description" content="lykin: an SSB tutorial application">
<meta name="author" content="glyph">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>lykin</h1>
<form action="/subscribe" method="post" style="width: 500px;">
<fieldset>
<legend>Subscription Management</legend>
<input type="text" id="public_key" name="public_key" size=53 maxlength=53><br>
<label for="public_key">Public Key</label><br>
<br>
<input type="submit" value="Subscribe">
<input type="submit" value="Unsubscribe" formaction="/unsubscribe">
</fieldset>
</form>
<div>
<h2>Subscriptions</h2>
<ul>
{% for feed in feeds -%}
<li>{{ feed }}</li>
{%- endfor %}
</ul>
</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
<div class="peers" style="text-align: center;">
<ul style="padding-left: 0;">
{% for peer in peers -%}
<li style="list-style: none; font-size: 12px;">
<a href="/posts/{{ peer | replace(from="/", to="%2F") }}">
<code style="word-wrap: anywhere;{% if selected_peer and peer == selected_peer %} font-weight: bold;{% endif %}">{{ peer }}</code>
</a>
</li>
{%- endfor %}
</ul>
</div>

View File

@ -0,0 +1,5 @@
<div class="content">
{% if post %}
{{ post.text | trim_start_matches(pat='"') | trim_end_matches(pat='"') | trim }}
{% endif %}
</div>

View File

@ -0,0 +1,14 @@
<div class="posts">
{% if posts %}
<ul style="padding-left: 25px; padding-right: 25px;">
{% for post in posts -%}
<li style="list-style: none; font-size: 12px; margin-bottom: 5px;{% if selected_post and post.key == selected_post %} background-color: #FF6300;{% endif %}">
<a class="flex-container" style="justify-content: space-between;{% if not post.read %} font-weight: bold;{% endif %}" href="/posts/{{ selected_peer | urlencode_strict }}/{{ post.key | urlencode_strict }}">
<code style="word-wrap: anywhere;">{{ post.key }}</code>
<p style="margin: 0;">{{ post.date }}</p>
</a>
</li>
{%- endfor %}
</ul>
{% endif %}
</div>

View File

@ -0,0 +1,21 @@
<div class="nav">
<div class="flex-container">
<a href="/" title="Download latest posts"><img src="/icons/download.png" style="width: 55px;"></a>
{% if post_is_selected %}
{% if post.read %}
{% set mark_unread_url = "/posts/" ~ selected_peer_encoded ~ "/" ~ selected_post_encoded ~ "/unread" %}
<a href={{ mark_unread_url }} style="margin-left: 20px;" title="Mark as unread"><img src="/icons/unread_post.png" style="width: 55px;"></a>
{% else %}
{% set mark_read_url = "/posts/" ~ selected_peer_encoded ~ "/" ~ selected_post_encoded ~ "/read" %}
<a href={{ mark_read_url }} style="margin-left: 20px;" title="Mark as read"><img src="/icons/read_post.png" style="width: 55px;"></a>
{% endif %}
<a href="/" style="margin-left: 20px;" title="Delete post"><img src="/icons/delete_post.png" style="width: 55px;"></a>
{% endif %}
<form class="flex-container" style="margin-left: auto; margin-right: 10px;" action="/subscribe" method="post">
<label for="public_key">Public Key</label>
<input type="text" id="public_key" name="public_key" size=50 maxlength=53>
<input type="submit" value="Subscribe">
<input type="submit" value="Unsubscribe" formaction="/unsubscribe">
</form>
</div>
</div>