Basic Nested & Collapsible Comments

This commit is contained in:
spikecodes 2020-12-19 19:54:46 -08:00
parent 19dc7de3c5
commit 7b8f694c8c
8 changed files with 124 additions and 69 deletions

23
Cargo.lock generated
View file

@ -338,6 +338,17 @@ dependencies = [
"toml",
]
[[package]]
name = "async-recursion"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5444eec77a9ec2bfe4524139e09195862e981400c4358d3b760cae634e4c4ee"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.54",
]
[[package]]
name = "async-trait"
version = "0.1.42"
@ -915,9 +926,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "1.6.0"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"
checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
dependencies = [
"autocfg",
"hashbrown",
@ -1004,10 +1015,11 @@ checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
[[package]]
name = "libreddit"
version = "0.1.11"
version = "0.2.0"
dependencies = [
"actix-web",
"askama",
"async-recursion",
"base64 0.13.0",
"chrono",
"pulldown-cmark",
@ -1640,13 +1652,12 @@ checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75"
[[package]]
name = "socket2"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c29947abdee2a218277abeca306f25789c938e500ea5a9d4b12a5a504466902"
checksum = "97e0e9fd577458a4f61fb91fcb559ea2afecc54c934119421f9f5d3d5b1a1057"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall",
"winapi 0.3.9",
]

View file

@ -3,7 +3,7 @@ name = "libreddit"
description = " Alternative private front-end to Reddit"
license = "AGPL-3.0"
repository = "https://github.com/spikecodes/libreddit"
version = "0.1.11"
version = "0.2.0"
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
edition = "2018"
@ -20,3 +20,4 @@ serde = "1.0.117"
serde_json = "1.0"
pulldown-cmark = "0.8.0"
chrono = "0.4.19"
async-recursion = "0.3.1"

View file

@ -1,5 +1,5 @@
// Import Crates
use actix_web::{web, get, App, HttpResponse, HttpServer, middleware::NormalizePath};
use actix_web::{get, middleware::NormalizePath, web, App, HttpResponse, HttpServer};
// Reference local files
mod popular;

View file

@ -2,6 +2,8 @@
use crate::utils::{format_num, format_url, request, val, Comment, ErrorTemplate, Flair, Params, Post};
use actix_web::{http::StatusCode, web, HttpResponse, Result};
use async_recursion::async_recursion;
use askama::Template;
use chrono::{TimeZone, Utc};
use pulldown_cmark::{html, Options, Parser};
@ -133,25 +135,35 @@ async fn parse_post(json: serde_json::Value) -> Result<Post, &'static str> {
}
// COMMENTS
#[async_recursion]
async fn parse_comments(json: serde_json::Value) -> Result<Vec<Comment>, &'static str> {
// Separate the comment JSON into a Vector of comments
let comment_data = json["data"]["children"].as_array().unwrap();
let mut comments: Vec<Comment> = Vec::new();
// For each comment, retrieve the values to build a Comment object
for comment in comment_data.iter() {
let unix_time: i64 = comment["data"]["created_utc"].as_f64().unwrap_or(0.0).round() as i64;
if unix_time == 0 {
continue;
}
let score = comment["data"]["score"].as_i64().unwrap_or(0);
let body = markdown_to_html(comment["data"]["body"].as_str().unwrap_or("")).await;
// if comment["data"]["replies"].is_object() {
// let replies = parse_comments(comment["data"]["replies"].clone()).await.unwrap();
// }
let replies: Vec<Comment> = if comment["data"]["replies"].is_object() {
parse_comments(comment["data"]["replies"].clone()).await.unwrap_or(Vec::new())
} else {
Vec::new()
};
comments.push(Comment {
body: body,
author: val(comment, "author").await,
score: format_num(score),
time: Utc.timestamp(unix_time, 0).format("%b %e %Y %H:%M UTC").to_string(),
replies: replies,
});
}

View file

@ -37,6 +37,7 @@ pub struct Comment {
pub author: String,
pub score: String,
pub time: String,
pub replies: Vec<Comment>,
}
#[allow(dead_code)]

View file

@ -1,5 +1,14 @@
/* General */
:root {
--background: #0F0F0F;
--foreground: #222;
--outside: #1F1F1F;
--post: #161616;
--highlighted: #333;
--black-contrast: 0 1px 3px rgba(0,0,0,0.5);
}
* {
transition: 0.2s all;
margin: 0px;
@ -8,15 +17,15 @@
font-weight: normal;
}
html {
background: black;
body {
background: var(--background);
}
header {
display: flex;
justify-content: space-between;
color: aqua;
background: #151515;
background: var(--outside);
padding: 15px;
font-weight: bold;
font-size: 20px;
@ -53,10 +62,6 @@ a:not(.post_right):hover {
text-decoration: underline;
}
span {
color: aqua;
}
#about {
background: #151515;
}
@ -128,7 +133,7 @@ span {
}
#sort > div, footer > a {
background: #151515;
background: var(--outside);
color: lightgrey;
border-radius: 5px;
margin-right: 5px;
@ -143,32 +148,24 @@ span {
}
#sort > div:hover {
background: #222;
background: var(--foreground);
}
/* Post */
.post {
border-radius: 5px;
background: #151515;
background: var(--post);
box-shadow: var(--black-contrast);
display: flex;
}
.post.highlighted {
border: 2px solid #555;
background: #222;
}
.post.highlighted > .post_left {
background: #333;
}
.post:hover {
background: #222;
background: var(--foreground);
}
.post:hover > .post_left {
background: #333;
background: var(--highlighted);
}
.post_left, .post_right {
@ -179,16 +176,12 @@ span {
.post_left {
text-align: center;
background: #222;
background: var(--foreground);
border-radius: 5px 0px 0px 5px;
min-width: 50px;
padding: 5px;
}
.datetime {
float: right;
}
.post_subreddit {
font-weight: bold;
}
@ -271,13 +264,14 @@ small {
/* Comment */
.comment {
margin-top: 1em;
border-radius: 5px;
display: flex;
border: 2px solid #222;
/* border: 2px solid var(--foreground); */
}
.comment:hover {
background: #111;
background: var(--post);
}
.comment_left, .comment_right {
@ -289,17 +283,21 @@ small {
text-align: center;
min-width: 50px;
padding: 5px;
align-items: flex-end;
align-items: center;
}
.comment_title {
font-size: 20px;
}
.comment_author {
opacity: 0.9;
}
.comment_upvote {
margin-top: 0.5em;
border-radius: 5px 5px 0px 0px;
background: #222;
background: var(--foreground);
width: 40px;
padding: 10px 0px 0px 0px;
}
@ -310,27 +308,23 @@ small {
.comment_score {
color: aqua;
background: #222;
width: 40px;
padding: 5px 0px 10px 0px;
border-radius: 0px 0px 5px 5px;
background: var(--foreground);
min-width: 40px;
border-radius: 5px;
padding: 10px 0px;
}
.comment_right {
word-wrap: anywhere;
padding: 10px 25px 10px 10px;
padding: 10px 25px 10px 5px;
flex-grow: 1;
flex-shrink: 1;
}
.comment_right > * {
.comment_data > * {
margin: 5px;
}
.comment_right > p {
opacity: 0.75;
}
.comment_image {
max-width: 500px;
align-self: center;
@ -355,9 +349,28 @@ small {
color: aqua;
}
::marker {
color: aqua;
}
.reply {
margin-top: 0;
margin-left: 2em;
}
.datetime {
opacity: 0.75;
}
.line {
width: 2px;
height: 100%;
background: var(--foreground);
}
.post.comment {
background: #000;
border: 2px solid #222;
border: 2px solid var(--foreground);
}
.post.comment > .post_left {
@ -367,12 +380,12 @@ small {
/* Tables */
table {
border: 3px #333 solid;
border: 3px var(--highlighted) solid;
border-spacing: 0rem;
}
td, th {
border: 1px #333 solid;
border: 1px var(--highlighted) solid;
padding: 0.5em;
}

View file

@ -4,6 +4,22 @@
{% call super() %}
<meta name="author" content="u/{{ post.author }}">
{% endblock %}
{% macro comment(item) -%}
<div class="comment">
<div class="comment_left">
<h3 class="comment_score">{{ item.score }}</h3>
<div class="line"></div>
</div>
<details class="comment_right" open>
<summary class="comment_data">
<a class="comment_author" href="/u/{{ item.author }}">u/{{ item.author }}</a><span class="datetime">{{ item.time }}</span>
</summary>
<h4 class="comment_body">{{ item.body }}</h4>
{%- endmacro %}
{% block content %}
<div class="post highlighted">
<div class="post_left">
@ -40,19 +56,21 @@
<div id="sort_controversial"><a href="?sort=controversial">Controversial</a></div>
<div id="sort_old"><a href="?sort=old">Old</a></div>
</div>
{% for comment in comments %}
<div class="comment">
<div class="comment_left">
<div class="comment_upvote"></div>
<h3 class="comment_score">{{ comment.score }}</h3>
{% for c in comments -%}
<div class="thread">
{% call comment(c) %}
<div class="replies">
{% for reply in c.replies %}
{% call comment(reply) %}
<div class="replies">
{% for response in reply.replies %}
{% call comment(response) %}</details></div>
{% endfor %}
</div></details></div>
{% endfor %}
</div></details></div>
</div>
<div class="comment_right">
<h4>
Posted by <a class="comment_author" href="/u/{{ comment.author }}">u/{{ comment.author }}</a>
<span class="datetime">{{ comment.time }}</span>
</h4>
<h4 class="comment_body">{{ comment.body }}</h4>
</div>
</div><br>
{% endfor %}
{%- endfor %}
{% endblock %}

View file

@ -46,7 +46,6 @@
{% else %}
<div class="comment">
<div class="comment_left">
<div class="comment_upvote"></div>
<h3 class="comment_score">{{ post.score }}</h3>
</div>
<div class="comment_right">