Add overlay when data fetching

This commit is contained in:
jude 2024-02-24 17:23:31 +00:00
parent a8ef3d03f9
commit e6b4ff8719
13 changed files with 171 additions and 146 deletions

3
.gitignore vendored
View File

@ -2,7 +2,7 @@ target
.env
/venv
.cargo
/.idea
.idea
web/static/index.html
web/static/assets
# Logs
@ -22,7 +22,6 @@ dist-ssr
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*

2
Cargo.lock generated
View File

@ -2358,7 +2358,7 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "reminder-rs"
version = "1.7.0-rc1"
version = "1.7.0-rc2"
dependencies = [
"base64 0.21.7",
"chrono",

View File

@ -1,6 +1,6 @@
[package]
name = "reminder-rs"
version = "1.7.0-rc1"
version = "1.7.0-rc2"
authors = ["Jude Southworth <judesouthworth@pm.me>"]
edition = "2021"
license = "AGPL-3.0 only"

View File

@ -4,16 +4,16 @@ The re-re-rewrite of the dashboard.
## Why
The existing beta variant of the dashboard is written using vanilla JavaScript. This is fine,
but annoying to update. This would've been okay if I was more dedicated to updating the vanilla
The existing beta variant of the dashboard is written using vanilla JavaScript. This is fine,
but annoying to update. This would've been okay if I was more dedicated to updating the vanilla
JavaScript too, but I want to experiment with "new" things.
This also allows me to expand my frontend skills, which is relevant to part of my job.
## Developing
1. Download the parent repo: https://gitea.jellypro.xyz/jude/reminder-bot
2. Initialise the submodules: `git pull --recurse-submodules`
3. Run both `npm run dev` and `cargo run`
4. Symlink assets: assuming cloned into `$HOME`, `ln -s $HOME/reminder-bot/reminder-dashboard/dist/index.html $HOME/reminder-bot/web/static/index.html` and
`ln -s $HOME/reminder-bot/reminder-dashboard/dist/static/assets $HOME/reminder-bot/web/static/assets`
1. Run both `npm run dev` and `cargo run`
2. Symlink assets: assuming cloned
into `$HOME`, `ln -s $HOME/reminder-bot/reminder-dashboard/dist/index.html $HOME/reminder-bot/web/static/index.html`
and
`ln -s $HOME/reminder-bot/reminder-dashboard/dist/static/assets $HOME/reminder-bot/web/static/assets`

View File

@ -14,7 +14,7 @@ enum Sort {
export const GuildReminders = () => {
const { guild } = useParams();
const { isSuccess, data: guildReminders } = useQuery(fetchGuildReminders(guild));
const { isSuccess, isFetching, data: guildReminders } = useQuery(fetchGuildReminders(guild));
const { data: channels } = useQuery(fetchGuildChannels(guild));
const [collapsed, setCollapsed] = useState(false);
@ -85,7 +85,7 @@ export const GuildReminders = () => {
</div>
</div>
<div id={"guildReminders"}>
<div id={"guildReminders"} className={isFetching ? "loading" : ""}>
{isSuccess &&
guildReminders
.sort((r1, r2) => {

View File

@ -97,3 +97,15 @@ macro_rules! json_err {
Err(json!({ "error": $message }))
};
}
macro_rules! path {
($path:expr) => {{
use rocket::fs::relative;
if Path::new(concat!("/lib/reminder-rs/", $path)).exists() {
concat!("/lib/reminder-rs/", $path)
} else {
relative!($path)
}
}};
}

View File

@ -2,12 +2,8 @@ use std::path::Path;
use chrono::{naive::NaiveDateTime, Utc};
use rand::{rngs::OsRng, seq::IteratorRandom};
use rocket::{
fs::{relative, NamedFile},
http::CookieJar,
response::Redirect,
serde::json::json,
};
use rocket::{fs::NamedFile, http::CookieJar, response::Redirect, serde::json::json};
use rocket_dyn_templates::Template;
use secrecy::ExposeSecret;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use serenity::{
@ -19,6 +15,7 @@ use serenity::{
use sqlx::types::Json;
use crate::{
catchers::internal_server_error,
check_guild_subscription, check_subscription,
consts::{
CHARACTERS, DAY, DEFAULT_AVATAR, MAX_CONTENT_LENGTH, MAX_EMBED_AUTHOR_LENGTH,
@ -672,28 +669,44 @@ async fn create_database_channel(
Ok(row.id)
}
#[get("/")]
pub async fn dashboard_home(cookies: &CookieJar<'_>) -> Result<NamedFile, Redirect> {
if cookies.get_private("userid").is_some() {
NamedFile::open(Path::new(relative!("static/index.html"))).await.map_err(|e| {
warn!("Couldn't render dashboard: {:?}", e);
#[derive(Responder)]
pub enum DashboardPage {
#[response(status = 200)]
Ok(NamedFile),
#[response(status = 200)]
Unauthorised(Redirect),
#[response(status = 500)]
NotConfigured(Template),
}
Redirect::to("/login/discord")
})
#[get("/")]
pub async fn dashboard_home(cookies: &CookieJar<'_>) -> DashboardPage {
if cookies.get_private("userid").is_some() {
match NamedFile::open(Path::new(path!("static/index.html"))).await {
Ok(f) => DashboardPage::Ok(f),
Err(e) => {
warn!("Couldn't render dashboard: {:?}", e);
DashboardPage::NotConfigured(internal_server_error().await)
}
}
} else {
Err(Redirect::to("/login/discord"))
DashboardPage::Unauthorised(Redirect::to("/login/discord"))
}
}
#[get("/<_..>")]
pub async fn dashboard(cookies: &CookieJar<'_>) -> Result<NamedFile, Redirect> {
pub async fn dashboard(cookies: &CookieJar<'_>) -> DashboardPage {
if cookies.get_private("userid").is_some() {
NamedFile::open(Path::new(relative!("static/index.html"))).await.map_err(|e| {
warn!("Couldn't render dashboard: {:?}", e);
match NamedFile::open(Path::new(path!("static/index.html"))).await {
Ok(f) => DashboardPage::Ok(f),
Err(e) => {
warn!("Couldn't render dashboard: {:?}", e);
Redirect::to("/login/discord")
})
DashboardPage::NotConfigured(internal_server_error().await)
}
}
} else {
Err(Redirect::to("/login/discord"))
DashboardPage::Unauthorised(Redirect::to("/login/discord"))
}
}

View File

@ -1 +1 @@
/home/jude/reminder-dashboard/dist/static/assets
/home/jude/reminder-bot/reminder-dashboard/dist/static/assets

View File

@ -55,6 +55,7 @@ div.reminderContent.is-collapsed .hide-box {
div.reminderContent.is-collapsed .hide-box i {
transform: rotate(90deg);
}
/* END */
/* dashboard styles */
@ -202,6 +203,7 @@ div.interval-group {
flex-direction: row;
justify-content: space-between;
}
/* !Interval inputs */
.left-pad {
@ -239,7 +241,7 @@ span.spacer {
}
nav .dashboard-button {
background: white ;
background: white;
}
span.patreon-color {
@ -694,7 +696,7 @@ li.highlight {
}
}
/* loader */
/* loaders */
#loader {
position: fixed;
top: 0;
@ -707,6 +709,14 @@ li.highlight {
font-size: 6rem;
}
.loading {
position: absolute;
top: 0;
height: 100%;
width: 100%;
background-color: rgba(255, 255, 255, 0.8);
}
/* END */
div.reminderError {

View File

@ -1 +0,0 @@
/home/jude/reminder-dashboard/dist/index.html

View File

@ -32,27 +32,54 @@
</div>
{% endif %}
<nav class="navbar is-dark is-spaced is-size-4" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<figure class="image">
<img src="/static/img/logo_flat.webp" alt="Reminder Bot Logo" class="is-rounded" style="width: auto;">
</figure>
</a>
<div style="min-height: 100vh;">
<nav class="navbar is-dark is-spaced is-size-4" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<figure class="image">
<img src="/static/img/logo_flat.webp" alt="Reminder Bot Logo" class="is-rounded" style="width: auto;">
</figure>
</a>
<a role="button" class="navbar-burger is-right" aria-label="menu" aria-expanded="false" data-target="pageNavbar">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div class="navbar-menu">
<div class="navbar-start">
<a role="button" class="navbar-burger is-right" aria-label="menu" aria-expanded="false" data-target="pageNavbar">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div class="navbar-menu">
<div class="navbar-start">
<a class="navbar-item" href="https://invite.reminder-bot.com">
<i class="fas fa-plus"></i>
</a>
<a class="navbar-item" href="https://gitea.jellypro.xyz/jude">
<i class="fab fa-git-square"></i>
</a>
<a class="navbar-item" href="https://discord.jellywx.com">
<i class="fab fa-discord"></i>
</a>
<a class="navbar-item" href="/help">
<i class="fas fa-book"></i>
</a>
</div>
<div class="navbar-end">
<div class="navbar-item">
<a class="button is-rounded is-light" href="/dashboard">
<p>
<span>Dashboard</span> <span class="icon"><i class="fas fa-chevron-right"></i></span>
</p>
</a>
</div>
</div>
</div>
<div class="navbar-menu is-hidden-desktop" id="pageNavbar">
<a class="navbar-item" href="https://invite.reminder-bot.com">
<i class="fas fa-plus"></i>
</a>
<a class="navbar-item" href="https://gitea.jellypro.xyz/jude">
<i class="fab fa-git-square"></i>
<a class="navbar-item" href="https://github.com/jellywx">
<i class="fab fa-github"></i>
</a>
<a class="navbar-item" href="https://discord.jellywx.com">
<i class="fab fa-discord"></i>
@ -60,92 +87,67 @@
<a class="navbar-item" href="/help">
<i class="fas fa-book"></i>
</a>
</div>
<div class="navbar-end">
<div class="navbar-item">
<a class="button is-rounded is-light" href="/dashboard">
<a href="/dashboard">
<p>
<span>Dashboard</span> <span class="icon"><i class="fas fa-chevron-right"></i></span>
Dashboard <span class="icon"><i class="fas fa-chevron-right"></i></span>
</p>
</a>
</div>
</div>
</div>
</nav>
<div class="navbar-menu is-hidden-desktop" id="pageNavbar">
<a class="navbar-item" href="https://invite.reminder-bot.com">
<i class="fas fa-plus"></i>
</a>
<a class="navbar-item" href="https://github.com/jellywx">
<i class="fab fa-github"></i>
</a>
<a class="navbar-item" href="https://discord.jellywx.com">
<i class="fab fa-discord"></i>
</a>
<a class="navbar-item" href="/help">
<i class="fas fa-book"></i>
</a>
<div class="navbar-item">
<a href="/dashboard">
<p>
Dashboard <span class="icon"><i class="fas fa-chevron-right"></i></span>
</p>
</a>
</div>
</div>
</nav>
{% if not hide_title_block %}
<section class="hero is-small is-dark">
<div class="hero-body">
<div class="">
<h1 class="title is-1">{{ page_title }}</h1>
<h2 class="subtitle is-3">{{ page_subtitle }}
{% if page_emoji %}
<span class="icon"><i class="fas {{ page_emoji }}"></i></span>
{% endif %}
</h2>
{% if not hide_title_block %}
<section class="hero is-small is-dark">
<div class="hero-body">
<div class="">
<h1 class="title is-1">{{ page_title }}</h1>
<h2 class="subtitle is-3">{{ page_subtitle }}
{% if page_emoji %}
<span class="icon"><i class="fas {{ page_emoji }}"></i></span>
{% endif %}
</h2>
</div>
</div>
</div>
{% if show_invite %}
<div class="hero-foot has-text-centered">
<a class="button is-size-4 is-rounded is-success" href="https://invite.reminder-bot.com">
<p class="is-size-4">
<span>Add to your Server</span> <span class="icon"><i class="fas fa-chevron-right"></i></span>
</p>
</a>
</div>
{% elif show_contact %}
<div class="hero-foot has-text-centered">
<a class="button is-size-4 is-rounded is-primary" href="https://discord.jellywx.com">
<p class="is-size-4">
<span>Join Discord</span> <span class="icon"><i class="fas fa-chevron-right"></i></span>
</p>
</a>
</div>
{% elif show_login %}
<div class="hero-foot has-text-centered">
<a class="button is-size-4 is-rounded is-light" href="/login/discord">
<p class="is-size-4">
<span>Login with Discord</span> <span class="icon"><i class="fas fa-chevron-right"></i></span>
</p>
</a>
</div>
{% endif %}
</section>
{% if show_invite %}
<div class="hero-foot has-text-centered">
<a class="button is-size-4 is-rounded is-success" href="https://invite.reminder-bot.com">
<p class="is-size-4">
<span>Add to your Server</span> <span class="icon"><i class="fas fa-chevron-right"></i></span>
</p>
</a>
</div>
{% elif show_contact %}
<div class="hero-foot has-text-centered">
<a class="button is-size-4 is-rounded is-primary" href="https://discord.jellywx.com">
<p class="is-size-4">
<span>Join Discord</span> <span class="icon"><i class="fas fa-chevron-right"></i></span>
</p>
</a>
</div>
{% elif show_login %}
<div class="hero-foot has-text-centered">
<a class="button is-size-4 is-rounded is-light" href="/login/discord">
<p class="is-size-4">
<span>Login with Discord</span> <span class="icon"><i class="fas fa-chevron-right"></i></span>
</p>
</a>
</div>
{% endif %}
</section>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 160">
<path transform="scale(1, 0.5)" fill="#98dc9a" fill-opacity="1" d="M0,288L80,266.7C160,245,320,203,480,202.7C640,203,800,245,960,218.7C1120,192,1280,96,1360,48L1440,0L1440,0L1360,0C1280,0,1120,0,960,0C800,0,640,0,480,0C320,0,160,0,80,0L0,0Z"></path>
<path transform="scale(1, 0.5)" fill="#363636" fill-opacity="1" d="M0,224L60,202.7C120,181,240,139,360,138.7C480,139,600,181,720,197.3C840,213,960,203,1080,176C1200,149,1320,107,1380,85.3L1440,64L1440,0L1380,0C1320,0,1200,0,1080,0C960,0,840,0,720,0C600,0,480,0,360,0C240,0,120,0,60,0L0,0Z">
</path>
</svg>
{% endif %}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 160">
<path transform="scale(1, 0.5)" fill="#98dc9a" fill-opacity="1" d="M0,288L80,266.7C160,245,320,203,480,202.7C640,203,800,245,960,218.7C1120,192,1280,96,1360,48L1440,0L1440,0L1360,0C1280,0,1120,0,960,0C800,0,640,0,480,0C320,0,160,0,80,0L0,0Z"></path>
<path transform="scale(1, 0.5)" fill="#363636" fill-opacity="1" d="M0,224L60,202.7C120,181,240,139,360,138.7C480,139,600,181,720,197.3C840,213,960,203,1080,176C1200,149,1320,107,1380,85.3L1440,64L1440,0L1380,0C1320,0,1200,0,1080,0C960,0,840,0,720,0C600,0,480,0,360,0C240,0,120,0,60,0L0,0Z">
</path>
</svg>
{% endif %}
{% block content %}
{% endblock %}
{% block content %}
{% endblock %}
</div>
<br>
<footer class="footer">
@ -165,25 +167,15 @@
<script>
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) {
$navbarBurgers.forEach( el => {
el.addEventListener('click', () => {
const target = el.dataset.target;
const $target = document.getElementById(target);
// 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');
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
});
});
}

View File

@ -6,5 +6,5 @@
{% set show_contact = True %}
{% set page_title = "Forbidden" %}
{% set page_subtitle = "You currently cannot access this page, if it exists. Sorry." %}
{% set page_subtitle = "You currently cannot access this page, if it exists." %}
{% endblock %}

View File

@ -6,5 +6,5 @@
{% set show_contact = True %}
{% set page_title = "File Not Found" %}
{% set page_subtitle = "This page does not exist. Sorry." %}
{% set page_subtitle = "This page does not exist." %}
{% endblock %}