Make mobile nav not require page refresh when JS enabled
Make top bar stick to top of screen Make wide view show rows of 4 Improve notification page styles, text Add button js to more pages
This commit is contained in:
parent
95b3b17c61
commit
5f0682ee22
|
@ -3,16 +3,31 @@
|
|||
font-style: italic;
|
||||
}
|
||||
|
||||
picture {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.toolkit-card.nav {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.desktop-bar,
|
||||
.mobile-bar {
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.mobile-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-body {
|
||||
position: fixed;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
@ -22,6 +37,13 @@
|
|||
|
||||
&.nav-open {
|
||||
display: block;
|
||||
animation-duration: 0.3s;
|
||||
animation-name: slideup;
|
||||
}
|
||||
&.nav-closing {
|
||||
display: block;
|
||||
animation-duration: 0.5s;
|
||||
animation-name: slidedown;
|
||||
}
|
||||
&.nav-closed {
|
||||
display: none;
|
||||
|
@ -44,7 +66,7 @@
|
|||
}
|
||||
|
||||
.home-content {
|
||||
padding: 32px 0;
|
||||
padding: 96px 0 32px;
|
||||
}
|
||||
|
||||
.profile-box {
|
||||
|
@ -119,7 +141,7 @@
|
|||
|
||||
.submission-tiles {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
|
||||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||||
|
||||
.submission-icon {
|
||||
position: relative;
|
||||
|
@ -128,7 +150,6 @@
|
|||
|
||||
picture {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
@ -185,10 +206,38 @@
|
|||
}
|
||||
|
||||
.submission-box {
|
||||
max-height: 70vh;
|
||||
max-height: 90vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background-color: #000;
|
||||
|
||||
img {
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideup {
|
||||
from {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
bottom: -100vh;
|
||||
}
|
||||
|
||||
to {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
bottom: 0vh;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slidedown {
|
||||
from {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
bottom: 0vh;
|
||||
}
|
||||
|
||||
to {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
bottom: -100vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{error::Error, State};
|
||||
use activitystreams::base::AnyBase;
|
||||
use actix_web::{web, HttpResponse, Scope};
|
||||
use hyaenidae_profiles::{apub::ApubIds, Spawner};
|
||||
use hyaenidae_profiles::apub::ApubIds;
|
||||
use sled::Tree;
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
|
@ -54,9 +54,11 @@ async fn shared_inbox(
|
|||
do_inbox(body.into_inner(), &state).await
|
||||
}
|
||||
|
||||
// TODO: signature validation, Actor check
|
||||
// TODO: signature validation
|
||||
async fn do_inbox(any_base: AnyBase, state: &State) -> Result<HttpResponse, Error> {
|
||||
state.spawn.process(any_base, vec![]);
|
||||
state
|
||||
.spawn
|
||||
.ingest(any_base, "http://temporary.url".parse().unwrap());
|
||||
Ok(HttpResponse::Created().finish())
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ use ructe::Ructe;
|
|||
fn main() -> ructe::Result<()> {
|
||||
let mut ructe = Ructe::from_env()?;
|
||||
let mut statics = ructe.statics()?;
|
||||
statics.add_files("static")?;
|
||||
statics.add_sass_file("scss/layout.scss")?;
|
||||
ructe.compile_templates("templates")?;
|
||||
|
||||
|
|
|
@ -43,6 +43,18 @@ pub(super) fn build(
|
|||
#[derive(Clone)]
|
||||
pub(super) struct Spawn(QueueHandle);
|
||||
|
||||
impl Spawn {
|
||||
pub(crate) fn ingest(&self, any_base: AnyBase, key_owner: Url) {
|
||||
if let Err(e) = self.0.queue(Ingest {
|
||||
any_base,
|
||||
key_owner: Some(key_owner),
|
||||
stack: vec![],
|
||||
}) {
|
||||
log::error!("Failed to queue ingest: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Spawner for Spawn {
|
||||
fn download_apub(&self, url: Url, stack: Vec<AnyBase>) {
|
||||
if let Err(e) = self.0.queue(DownloadApub { url, stack }) {
|
||||
|
@ -63,7 +75,11 @@ impl Spawner for Spawn {
|
|||
}
|
||||
|
||||
fn process(&self, any_base: AnyBase, stack: Vec<AnyBase>) {
|
||||
if let Err(e) = self.0.queue(Ingest { any_base, stack }) {
|
||||
if let Err(e) = self.0.queue(Ingest {
|
||||
any_base,
|
||||
key_owner: None,
|
||||
stack,
|
||||
}) {
|
||||
log::error!("Failed to queue process job: {}", e);
|
||||
}
|
||||
}
|
||||
|
@ -109,6 +125,7 @@ struct DownloadApub {
|
|||
#[derive(Clone, serde::Deserialize, serde::Serialize)]
|
||||
struct Ingest {
|
||||
any_base: AnyBase,
|
||||
key_owner: Option<Url>,
|
||||
stack: Vec<AnyBase>,
|
||||
}
|
||||
|
||||
|
@ -267,7 +284,10 @@ impl ActixJob for Ingest {
|
|||
if self.stack.len() > MAX_INGEST_DEPTH {
|
||||
return Err(anyhow::anyhow!("Max recursion depth exceded"));
|
||||
}
|
||||
state.profiles.ingest(self.any_base, self.stack).await?;
|
||||
state
|
||||
.profiles
|
||||
.ingest(self.any_base, self.key_owner, self.stack)
|
||||
.await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -58,16 +58,18 @@ async fn main() -> anyhow::Result<()> {
|
|||
secret_key
|
||||
};
|
||||
|
||||
let domain = config
|
||||
.base_url
|
||||
.domain()
|
||||
.expect("Invalid domain for base url")
|
||||
.to_owned();
|
||||
|
||||
let accounts_config = hyaenidae_accounts::Config {
|
||||
toolkit_path: format!(
|
||||
"/toolkit/{}",
|
||||
hyaenidae_toolkit::templates::statics::toolkit_css.name
|
||||
),
|
||||
domain: config
|
||||
.base_url
|
||||
.domain()
|
||||
.expect("Invalid domain for base url")
|
||||
.to_owned(),
|
||||
domain: domain.clone(),
|
||||
key: secret_key,
|
||||
https: false,
|
||||
pages: std::sync::Arc::new(accounts::Pages),
|
||||
|
@ -81,14 +83,17 @@ async fn main() -> anyhow::Result<()> {
|
|||
)?;
|
||||
let accounts_state = hyaenidae_accounts::state(&accounts_config, db.clone())?;
|
||||
|
||||
let state = State::new(
|
||||
spawner.clone(),
|
||||
config.base_url.clone(),
|
||||
config.pictrs_upstream.clone(),
|
||||
&db.clone(),
|
||||
)?;
|
||||
|
||||
state.profiles.create_server_actor(domain).await?;
|
||||
|
||||
if let Some(user) = config.make_admin {
|
||||
let user = accounts_state.by_username(user).await?.req()?;
|
||||
let state = State::new(
|
||||
spawner.clone(),
|
||||
config.base_url,
|
||||
config.pictrs_upstream,
|
||||
&db.clone(),
|
||||
)?;
|
||||
|
||||
state.admin.make_admin(user.id())?;
|
||||
return Ok(());
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use crate::{comments::Comment, error::Error, nav::NavState, profiles::Profile, State};
|
||||
use crate::{
|
||||
comments::Comment, error::Error, nav::NavState, profiles::Profile, submissions::Submission,
|
||||
State,
|
||||
};
|
||||
use actix_web::{web, HttpResponse, Scope};
|
||||
use futures::stream::{FuturesUnordered, StreamExt};
|
||||
use hyaenidae_toolkit::{Button, Link};
|
||||
|
@ -206,20 +209,37 @@ async fn remove_comment_notification(
|
|||
}
|
||||
|
||||
pub(crate) struct CommentView<'a> {
|
||||
submission: &'a Submission,
|
||||
parent: Option<&'a Comment>,
|
||||
comment: &'a Comment,
|
||||
author: &'a Profile,
|
||||
id: Uuid,
|
||||
self_id: Uuid,
|
||||
}
|
||||
|
||||
impl<'a> CommentView<'a> {
|
||||
fn comment_reply(&self) -> Option<Uuid> {
|
||||
self.parent.and_then(|c| {
|
||||
if c.profile_id() == self.self_id {
|
||||
Some(c.id())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn submission_path(&self) -> Option<String> {
|
||||
if self.comment.comment_id().is_none() {
|
||||
if self.comment_reply().is_none() {
|
||||
Some(format!("/submissions/{}", self.comment.submission_id()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn submission_title(&self) -> String {
|
||||
self.submission.title()
|
||||
}
|
||||
|
||||
pub(crate) fn submission_link(&self, dark: bool) -> Option<Link> {
|
||||
self.submission_path().map(|path| {
|
||||
let mut link = Link::new_tab(&path);
|
||||
|
@ -229,7 +249,7 @@ impl<'a> CommentView<'a> {
|
|||
}
|
||||
|
||||
fn reply_to_path(&self) -> Option<String> {
|
||||
if let Some(reply_to_id) = self.comment.comment_id() {
|
||||
if let Some(reply_to_id) = self.comment_reply() {
|
||||
Some(format!("/comments/{}", reply_to_id))
|
||||
} else {
|
||||
None
|
||||
|
@ -249,7 +269,7 @@ impl<'a> CommentView<'a> {
|
|||
}
|
||||
|
||||
pub(crate) fn view_button(&self, dark: bool) -> Button {
|
||||
let btn = Button::primary("View");
|
||||
let btn = Button::secondary("View");
|
||||
btn.href(&self.comment_path()).new_tab().dark(dark);
|
||||
btn
|
||||
}
|
||||
|
@ -259,7 +279,7 @@ impl<'a> CommentView<'a> {
|
|||
}
|
||||
|
||||
pub(crate) fn remove_button(&self, dark: bool) -> Button {
|
||||
let btn = Button::primary_outline("Remove");
|
||||
let btn = Button::secondary("Remove");
|
||||
btn.form(&self.remove_path()).dark(dark);
|
||||
btn
|
||||
}
|
||||
|
@ -282,7 +302,7 @@ pub(crate) struct FollowRequestView<'a> {
|
|||
|
||||
impl<'a> FollowRequestView<'a> {
|
||||
pub(crate) fn accept_button(&self, dark: bool) -> Button {
|
||||
let btn = Button::primary("Accept");
|
||||
let btn = Button::secondary("Accept");
|
||||
btn.form(&format!(
|
||||
"/notifications/follow-requests/{}/accept",
|
||||
self.id
|
||||
|
@ -292,7 +312,7 @@ impl<'a> FollowRequestView<'a> {
|
|||
}
|
||||
|
||||
pub(crate) fn reject_button(&self, dark: bool) -> Button {
|
||||
let btn = Button::primary_outline("Reject");
|
||||
let btn = Button::secondary("Reject");
|
||||
btn.form(&format!(
|
||||
"/notifications/follow-requests/{}/reject",
|
||||
self.id
|
||||
|
@ -306,10 +326,12 @@ impl<'a> FollowRequestView<'a> {
|
|||
pub struct NotificationsView {
|
||||
comment_hm: HashMap<Uuid, Comment>,
|
||||
profile_hm: HashMap<Uuid, Profile>,
|
||||
submission_hm: HashMap<Uuid, Submission>,
|
||||
fr_profile_hm: HashMap<Uuid, Uuid>,
|
||||
comments: Vec<Uuid>,
|
||||
follow_requests: Vec<Uuid>,
|
||||
count: u64,
|
||||
self_id: Uuid,
|
||||
}
|
||||
|
||||
impl NotificationsView {
|
||||
|
@ -317,11 +339,16 @@ impl NotificationsView {
|
|||
self.comments.iter().filter_map(move |comment_id| {
|
||||
let comment = self.comment_hm.get(comment_id)?;
|
||||
let author = self.profile_hm.get(&comment.profile_id())?;
|
||||
let submission = self.submission_hm.get(&comment.submission_id())?;
|
||||
let parent = comment.comment_id().and_then(|id| self.comment_hm.get(&id));
|
||||
|
||||
Some(CommentView {
|
||||
comment,
|
||||
parent,
|
||||
author,
|
||||
submission,
|
||||
id: *comment_id,
|
||||
self_id: self.self_id,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -397,6 +424,7 @@ impl NotificationsView {
|
|||
|
||||
let comment_store = state.profiles.store.comments.clone();
|
||||
let profile_store = state.profiles.store.profiles.clone();
|
||||
let submission_store = state.profiles.store.submissions.clone();
|
||||
let file_store = state.profiles.store.files.clone();
|
||||
let follow_request_store = state.profiles.store.view.follow_requests.clone();
|
||||
let comment_notifs = state.profiles.store.view.comments.clone();
|
||||
|
@ -406,10 +434,12 @@ impl NotificationsView {
|
|||
let mut view = NotificationsView {
|
||||
comment_hm: HashMap::new(),
|
||||
profile_hm: HashMap::new(),
|
||||
submission_hm: HashMap::new(),
|
||||
fr_profile_hm: HashMap::new(),
|
||||
comments: vec![],
|
||||
follow_requests: vec![],
|
||||
count,
|
||||
self_id: profile_id,
|
||||
};
|
||||
|
||||
for comment_id in comment_notifs.for_profile(profile_id) {
|
||||
|
@ -422,6 +452,21 @@ impl NotificationsView {
|
|||
)?;
|
||||
view.profile_hm.insert(profile.id(), profile);
|
||||
}
|
||||
if !view.submission_hm.contains_key(&comment.submission_id()) {
|
||||
let submission = Submission::from_stores(
|
||||
comment.submission_id(),
|
||||
&submission_store,
|
||||
&file_store,
|
||||
)?;
|
||||
view.submission_hm.insert(submission.id(), submission);
|
||||
}
|
||||
if let Some(id) = comment.comment_id() {
|
||||
if !view.profile_hm.contains_key(&id) {
|
||||
if let Some(comment) = comment_store.by_id(id)? {
|
||||
view.comment_hm.insert(comment.id(), comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
view.comments.push(comment.id());
|
||||
view.comment_hm.insert(comment.id(), comment);
|
||||
|
|
47
server/static/nav.js
Normal file
47
server/static/nav.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
(function(fn) {
|
||||
if (document.readyState === "complete" || document.readyState === "interactive") {
|
||||
setTimeout(fn, 1);
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", fn);
|
||||
}
|
||||
})(function() {
|
||||
function onClick(nav) {
|
||||
return function _listener(event) {
|
||||
event.preventDefault();
|
||||
var containsOpen = false;
|
||||
|
||||
for (var i = 0; i < nav.classList.length; i++) {
|
||||
if (nav.classList[i] == "nav-open") {
|
||||
containsOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (containsOpen) {
|
||||
nav.setAttribute("class", "nav-body nav-closing");
|
||||
setTimeout(function() {
|
||||
nav.setAttribute("class", "nav-body nav-closed");
|
||||
}, 500)
|
||||
} else {
|
||||
nav.setAttribute("class", "nav-body nav-open");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var navs = document.getElementsByClassName("nav-body");
|
||||
var nav = navs[0];
|
||||
if (!nav) {
|
||||
return;
|
||||
}
|
||||
|
||||
var links = document.getElementsByClassName("nav-link");
|
||||
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
var link = links[i];
|
||||
|
||||
if (!link) {
|
||||
continue;
|
||||
}
|
||||
|
||||
link.addEventListener("click", onClick(nav));
|
||||
}
|
||||
})
|
4
server/templates/button_js.rs.html
Normal file
4
server/templates/button_js.rs.html
Normal file
|
@ -0,0 +1,4 @@
|
|||
@use hyaenidae_toolkit::templates::statics::button_js;
|
||||
|
||||
@()
|
||||
<script src="@crate::toolkit_path(button_js.name)"></script>
|
|
@ -1,3 +1,4 @@
|
|||
@use crate::templates::button_js;
|
||||
@use crate::templates::layouts::home;
|
||||
@use crate::templates::comments::{nodes, profile_box};
|
||||
@use crate::comments::CommentView;
|
||||
|
@ -11,7 +12,9 @@
|
|||
@(view: &CommentView, nav_state: &NavState)
|
||||
|
||||
@if let Some((comment, author)) = view.comments.item.comment() {
|
||||
@:home(&author.name(), comment.body(), nav_state, {}, {
|
||||
@:home(&author.name(), comment.body(), nav_state, {
|
||||
@:button_js()
|
||||
}, {
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
@:card_title({ Comment })
|
||||
@:card_body({
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
@use crate::comments::ReportView;
|
||||
@use crate::nav::NavState;
|
||||
@use crate::templates::button_js;
|
||||
@use crate::templates::layouts::home;
|
||||
@use crate::templates::comments::profile_box;
|
||||
@use hyaenidae_toolkit::{templates::button_group, Button};
|
||||
|
@ -8,7 +9,9 @@
|
|||
|
||||
@(view: &ReportView, nav_state: &NavState)
|
||||
|
||||
@:home("Report Comment", &format!("Report comment by {}", view.author.name()), nav_state, {}, {
|
||||
@:home("Report Comment", &format!("Report comment by {}", view.author.name()), nav_state, {
|
||||
@:button_js()
|
||||
}, {
|
||||
@:card(Card::full_width().dark(nav_state.dark()), {
|
||||
@:card_title({ Report Comment })
|
||||
@:card_body({
|
||||
|
|
5
server/templates/file_js.rs.html
Normal file
5
server/templates/file_js.rs.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
@use hyaenidae_toolkit::templates::statics::file_input_js;
|
||||
|
||||
@()
|
||||
<script src="@crate::toolkit_path(file_input_js.name)"></script>
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
@use crate::{templates::{layouts::root, nav}, nav::NavState};
|
||||
@use crate::templates::statics::nav_js;
|
||||
@use hyaenidae_toolkit::templates::{bar, centered};
|
||||
@use hyaenidae_toolkit::{templates::{card, card_body}, Card};
|
||||
@use hyaenidae_toolkit::{templates::link, Link};
|
||||
|
@ -6,7 +7,10 @@
|
|||
|
||||
@(title: &str, description: &str, nav_state: &NavState, head: Content, body: Content)
|
||||
|
||||
@:root(title, description, nav_state.dark(), { @:head() }, {
|
||||
@:root(title, description, nav_state.dark(), {
|
||||
<script src="@crate::statics_path(nav_js.name)"></script>
|
||||
@:head()
|
||||
}, {
|
||||
@:bar(nav_state.dark(), "desktop-bar", {
|
||||
<div>
|
||||
@:link(&Link::current_tab("/").plain(true).dark(nav_state.dark()), {
|
||||
|
@ -21,7 +25,7 @@
|
|||
@:link(&Link::current_tab("/").plain(true).dark(nav_state.dark()), {
|
||||
<h2>Hyaenidae</h2>
|
||||
})
|
||||
<h3>@:link(&Link::current_tab(nav_state.href()).plain(true).dark(nav_state.dark()), { Nav })</h3>
|
||||
<h3 class="nav-link">@:link(&Link::current_tab(nav_state.href()).plain(true).dark(nav_state.dark()), { Nav })</h3>
|
||||
})
|
||||
<div class="home-content">
|
||||
@:centered(false, {
|
||||
|
@ -29,10 +33,12 @@
|
|||
})
|
||||
</div>
|
||||
<div class="nav-body @nav_state.class_string()">
|
||||
@:link(&Link::current_tab(nav_state.href()).plain(true).dark(nav_state.dark()), {
|
||||
<div class="nav-background">
|
||||
</div>
|
||||
})
|
||||
<div class="nav-link nav-background">
|
||||
@:link(&Link::current_tab(nav_state.href()).plain(true).dark(nav_state.dark()), {
|
||||
<div class="nav-background">
|
||||
</div>
|
||||
})
|
||||
</div>
|
||||
<nav class="nav-links">
|
||||
@:centered(false, {
|
||||
@:card(&Card::full_width().classes(&["nav"]).dark(nav_state.dark()), {
|
||||
|
@ -40,9 +46,11 @@
|
|||
@:nav(nav_state)
|
||||
})
|
||||
@:card_body({
|
||||
@:button_group(&[
|
||||
Button::primary_outline("Close").href(nav_state.href()).dark(nav_state.dark()),
|
||||
])
|
||||
<div class="nav-link">
|
||||
@:button_group(&[
|
||||
Button::primary_outline("Close").href(nav_state.href()).dark(nav_state.dark()),
|
||||
])
|
||||
</div>
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
@use crate::nav::NavState;
|
||||
@use crate::notifications::NotificationsView;
|
||||
@use crate::templates::button_js;
|
||||
@use crate::templates::layouts::home;
|
||||
@use crate::templates::submissions::profile_box;
|
||||
@use hyaenidae_toolkit::templates::button_group;
|
||||
|
@ -8,7 +9,9 @@
|
|||
|
||||
@(view: &NotificationsView, nav_state: &NavState)
|
||||
|
||||
@:home(&format!("Notifications: {}", view.count()), "Notifications on Hyaenidae", nav_state, {}, {
|
||||
@:home(&format!("Notifications: {}", view.count()), "Notifications on Hyaenidae", nav_state, {
|
||||
@:button_js()
|
||||
}, {
|
||||
@:card(Card::full_width().dark(nav_state.dark()), {
|
||||
@:card_title({ Clear All })
|
||||
@:card_body({
|
||||
|
@ -25,12 +28,13 @@
|
|||
@:card_title({ Follow Requests })
|
||||
@for fr in view.follow_requests() {
|
||||
@:card_body({
|
||||
@:profile_box(fr.profile, None, nav_state.dark(), {
|
||||
@:profile_box(fr.profile, None, nav_state.dark(), {})
|
||||
<div class="button-section">
|
||||
@:button_group(&[
|
||||
&fr.accept_button(nav_state.dark()),
|
||||
&fr.reject_button(nav_state.dark()),
|
||||
])
|
||||
})
|
||||
</div>
|
||||
})
|
||||
}
|
||||
@:card_body({
|
||||
|
@ -50,8 +54,8 @@
|
|||
@c.author_name()
|
||||
})
|
||||
@if let Some(l) = c.submission_link(nav_state.dark()) {
|
||||
commented on your
|
||||
@:link(&l, { submission })
|
||||
commented on your submission:
|
||||
@:link(&l, { @c.submission_title() })
|
||||
}
|
||||
@if let Some(l) = c.reply_to_link(nav_state.dark()) {
|
||||
replied to your
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
@use crate::{templates::{layouts::home, profiles::view}, nav::NavState, profiles::Profile};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, file_input, statics::{button_js, file_input_js}}, Button, Card, FileInput};
|
||||
@use crate::templates::{button_js, file_js};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, file_input}, Button, Card, FileInput};
|
||||
|
||||
@(banner_input: &FileInput, error: Option<String>, profile: &Profile, nav_state: &NavState)
|
||||
|
||||
@:home("Create Profile", "Create a new profile on Hyaenidae", nav_state, {
|
||||
<script src="/toolkit/@file_input_js.name"></script>
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
@:button_js()
|
||||
@:file_js()
|
||||
}, {
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
<form method="POST" action="/profiles/create/banner" enctype="multipart/form-data">
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
@use crate::{templates::{layouts::home, profiles::view}, nav::NavState, profiles::Profile};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, text_input, statics::button_js}, Button, Card, TextInput};
|
||||
@use crate::templates::button_js;
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, text_input}, Button, Card, TextInput};
|
||||
|
||||
@(display_name_input: &TextInput, description_input: &TextInput, profile: &Profile, nav_state: &NavState)
|
||||
|
||||
@:home("Create Profile", "Create a new profile on Hyaenidae", nav_state, {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
@:button_js()
|
||||
}, {
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
<form method="POST" action="/profiles/create/bio">
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
@use crate::{templates::layouts::home, nav::NavState};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, text_input, statics::button_js}, Button, Card, TextInput};
|
||||
@use crate::templates::button_js;
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, text_input}, Button, Card, TextInput};
|
||||
|
||||
@(handle_input: &TextInput, nav_state: &NavState)
|
||||
|
||||
@:home("Create Profile", "Create a new profile on Hyaenidae", nav_state, {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
@:button_js()
|
||||
}, {
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
<form method="POST" action="/profiles/create/handle">
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
@use crate::templates::{button_js, file_js};
|
||||
@use crate::{templates::{layouts::home, profiles::view}, nav::NavState, profiles::Profile};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, file_input, statics::{button_js, file_input_js}}, Button, Card, FileInput};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, file_input}, Button, Card, FileInput};
|
||||
|
||||
@(icon_input: &FileInput, error: Option<String>, profile: &Profile, nav_state: &NavState)
|
||||
|
||||
@:home("Create Profile", "Create a new profile on Hyaenidae", nav_state, {
|
||||
<script src="/toolkit/@file_input_js.name"></script>
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
@:button_js()
|
||||
@:file_js()
|
||||
}, {
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
<form method="POST" action="/profiles/create/icon" enctype="multipart/form-data">
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
@use crate::templates::button_js;
|
||||
@use crate::{templates::{layouts::home, profiles::view}, nav::NavState, profiles::Profile};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, statics::button_js}, Button, Card};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title}, Button, Card};
|
||||
|
||||
@(require_login: bool, error: Option<String>, profile: &Profile, nav_state: &NavState)
|
||||
|
||||
@:home("Create Profile", "Create a new profile on Hyaenidae", nav_state, {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
@:button_js()
|
||||
}, {
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
<form method="POST" action="/profiles/create/require-login">
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
@use crate::templates::{button_js, file_js};
|
||||
@use crate::{templates::{layouts::home, profiles::{banner, icon, view}}, nav::NavState, profiles::ProfileState};
|
||||
@use hyaenidae_toolkit::{templates::{button, button_group, card, card_body, card_title, file_input, text_input, statics::{button_js, file_input_js}}, Button, Card};
|
||||
@use hyaenidae_toolkit::{templates::{button, button_group, card, card_body, card_title, file_input, text_input}, Button, Card};
|
||||
|
||||
@(state: &ProfileState, nav_state: &NavState)
|
||||
|
||||
@:home("Profile Settings", &format!("{}'s profile", state.profile.name()), nav_state, {
|
||||
<script src="/toolkit/@file_input_js.name"></script>
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
@:button_js()
|
||||
@:file_js()
|
||||
}, {
|
||||
@:card(Card::full_width().dark(nav_state.dark()), { @:view(&state.profile, nav_state.dark()) })
|
||||
@:card(Card::full_width().dark(nav_state.dark()), {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
@use crate::templates::button_js;
|
||||
@use crate::{templates::{layouts::home, profiles::view}, nav::NavState, profiles::Profile};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, statics::button_js}, Button, Card};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title}, Button, Card};
|
||||
|
||||
@(profile: &Profile, nav_state: &NavState)
|
||||
|
||||
@:home("Delete Profile", &format!("Delete {}", profile.name()), nav_state, {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
@:button_js()
|
||||
}, {
|
||||
@:card(Card::full_width().dark(nav_state.dark()), { @:view(profile, nav_state.dark()) })
|
||||
@:card(Card::full_width().dark(nav_state.dark()), {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@use crate::templates::button_js;
|
||||
@use crate::{templates::{layouts::home, profiles::view}, nav::NavState, profiles::ReportView};
|
||||
@use hyaenidae_toolkit::{templates::button_group, Button};
|
||||
@use hyaenidae_toolkit::{templates::{card, card_body, card_title}, Card};
|
||||
|
@ -5,7 +6,9 @@
|
|||
|
||||
@(rview: &ReportView, nav_state: &NavState)
|
||||
|
||||
@:home("Report Profile", rview.profile.description().unwrap_or(&format!("Report {}'s profile on Hyaenidae", rview.profile.name())), nav_state, {}, {
|
||||
@:home("Report Profile", rview.profile.description().unwrap_or(&format!("Report {}'s profile on Hyaenidae", rview.profile.name())), nav_state, {
|
||||
@:button_js()
|
||||
}, {
|
||||
@:card(Card::full_width().dark(nav_state.dark()), { @:view(&rview.profile, nav_state.dark()) })
|
||||
@:card(Card::full_width().dark(nav_state.dark()), {
|
||||
<form method="POST" action="@rview.profile.report_path()">
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
@use crate::templates::button_js;
|
||||
@use crate::{templates::layouts::home, nav::NavState};
|
||||
@use hyaenidae_accounts::{templates::{update_password, update_username}, UpdatePasswordState, UpdateUsernameState, User};
|
||||
@use hyaenidae_toolkit::{templates::{button, card, card_body, card_title, statics::button_js}, Button, Card};
|
||||
@use hyaenidae_toolkit::{templates::{button, card, card_body, card_title}, Button, Card};
|
||||
|
||||
@(user: &User, uname_state: &UpdateUsernameState, pass_state: &UpdatePasswordState, nav_state: &NavState)
|
||||
|
||||
@:home("Account Settings", "Update account information", nav_state, {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
@:button_js()
|
||||
}, {
|
||||
@:card(Card::full_width().dark(nav_state.dark()), {
|
||||
@:card_title({ Current Username: @user.username() })
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
@use crate::templates::button_js;
|
||||
@use crate::{templates::layouts::home, nav::NavState};
|
||||
@use hyaenidae_accounts::{templates::delete_user, DeleteUserState};
|
||||
@use hyaenidae_toolkit::Card;
|
||||
|
||||
@(state: &DeleteUserState, nav_state: &NavState)
|
||||
|
||||
@:home("Delete Account", "Are you sure you want to delete your account?", nav_state, {}, {
|
||||
@:home("Delete Account", "Are you sure you want to delete your account?", nav_state, {
|
||||
@:button_js()
|
||||
}, {
|
||||
@:delete_user(&Card::full_width().dark(nav_state.dark()), state)
|
||||
})
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
@use crate::templates::button_js;
|
||||
@use crate::{templates::layouts::home, nav::NavState};
|
||||
@use hyaenidae_accounts::{templates::login, LoginState};
|
||||
@use hyaenidae_toolkit::{templates::statics::button_js, Card};
|
||||
@use hyaenidae_toolkit::Card;
|
||||
|
||||
@(login_state: &LoginState, nav_state: &NavState)
|
||||
|
||||
@:home("Login", "Log into Hyaenidae", nav_state, {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
@:button_js()
|
||||
}, {
|
||||
@:login(&Card::full_width().dark(nav_state.dark()), login_state)
|
||||
})
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
@use crate::templates::button_js;
|
||||
@use crate::{templates::layouts::home, nav::NavState};
|
||||
@use hyaenidae_accounts::{templates::register, RegisterState};
|
||||
@use hyaenidae_toolkit::{templates::statics::button_js, Card};
|
||||
@use hyaenidae_toolkit::Card;
|
||||
|
||||
@(register_state: &RegisterState, nav_state: &NavState)
|
||||
|
||||
@:home("Register", "Register for Hyaenidae", nav_state, {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
}, {
|
||||
@:home("Register", "Register for Hyaenidae", nav_state, { @:button_js() }, {
|
||||
@:register(&Card::full_width().dark(nav_state.dark()), register_state)
|
||||
})
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
@use crate::templates::{button_js, file_js};
|
||||
@use crate::{templates::layouts::home, nav::NavState};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, file_input, statics::{button_js, file_input_js}}, Button, Card, FileInput};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, file_input}, Button, Card, FileInput};
|
||||
|
||||
@(file: &FileInput, error: Option<String>, nav_state: &NavState)
|
||||
|
||||
@:home("Create Submission", "Upload a file", nav_state, {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
<script src="/toolkit/@file_input_js.name"></script>
|
||||
@:button_js()
|
||||
@:file_js()
|
||||
}, {
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
<form method="POST" action="/submissions/create" enctype="multipart/form-data">
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@use crate::templates::button_js;
|
||||
@use crate::templates::layouts::home;
|
||||
@use crate::templates::comments::nodes;
|
||||
@use crate::templates::submissions::{image, profile_box};
|
||||
|
@ -9,7 +10,9 @@
|
|||
|
||||
@(view: &SubmissionView, nav_state: &NavState)
|
||||
|
||||
@:home(&view.submission.title(), view.submission.description().unwrap_or(&format!("{} hosted on Hyaenidae", view.submission.title())), nav_state, {}, {
|
||||
@:home(&view.submission.title(), view.submission.description().unwrap_or(&format!("{} hosted on Hyaenidae", view.submission.title())), nav_state, {
|
||||
@:button_js()
|
||||
}, {
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
@:card_title({
|
||||
@view.submission.title()
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@use crate::templates::button_js;
|
||||
@use crate::templates::admin::submission_box;
|
||||
@use crate::templates::layouts::home;
|
||||
@use crate::{nav::NavState, submissions::ReportView};
|
||||
|
@ -7,8 +8,9 @@
|
|||
|
||||
@(view: &ReportView, nav_state: &NavState)
|
||||
|
||||
@:home("Report Submission", view.submission.description().unwrap_or(&format!("Report {}'s
|
||||
submission on Hyaenidae", view.profile.name())), nav_state, {}, {
|
||||
@:home("Report Submission", view.submission.description().unwrap_or(&format!("Report {}'s submission on Hyaenidae", view.profile.name())), nav_state, {
|
||||
@:button_js()
|
||||
}, {
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
@:card_title({
|
||||
Report @view.submission.title()
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
@use crate::templates::{button_js, file_js};
|
||||
@use crate::{templates::{layouts::home, submissions::image}, nav::NavState, submissions::SubmissionState};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, file_input, text_input, statics::{button_js, file_input_js}}, Button, Card};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, file_input, text_input}, Button, Card};
|
||||
|
||||
@(state: &SubmissionState, nav_state: &NavState)
|
||||
|
||||
@:home("Update Submission", "Update information or images", nav_state, {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
<script src="/toolkit/@file_input_js.name"></script>
|
||||
@:button_js()
|
||||
@:file_js()
|
||||
}, {
|
||||
@if !state.is_published() {
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
|
|
Loading…
Reference in a new issue