Server: Start work on better nav bar

This commit is contained in:
asonix 2021-01-31 17:22:15 -06:00
parent 0387e09959
commit 1e62b11a01
9 changed files with 159 additions and 65 deletions

View file

@ -25,6 +25,26 @@ picture {
display: none;
}
.profile-nav {
display: flex;
align-items: center;
.bar-icon {
margin-right: 0;
margin-left: 16px;
}
.toolkit-icon--link .toolkit-icon {
border-width: 1px;
}
.notification-bell {
.toolkit-link,
i {
display: block;
}
}
}
.narrow-nav {
display: none;
}

View file

@ -1,15 +1,19 @@
use crate::{
admin::Admin, extensions::ProfileExt, middleware::UserProfile,
notifications::total_for_profile, ActixLoader, State,
admin::Admin,
error::Error,
extensions::ProfileExt,
middleware::UserProfile,
notifications::total_for_profile,
views::{OwnedProfileView, ProfileView},
ActixLoader, State,
};
use actix_web::{
dev::Payload,
web::{Data, Query},
web::{self, Data, Query},
FromRequest, HttpRequest,
};
use futures::future::LocalBoxFuture;
use hyaenidae_accounts::LogoutState;
use hyaenidae_profiles::store::Profile;
use hyaenidae_toolkit::Button;
use i18n_embed_fl::fl;
@ -66,6 +70,29 @@ impl FromRequest for NavState {
None
};
let store = state.profiles.clone();
let profile = if let Some(profile) = profile {
let profile = web::block(move || {
let icon = if let Some(file_id) = profile.icon() {
store.store.files.by_id(file_id)?
} else {
None
};
Ok(OwnedProfileView {
profile,
icon,
banner: None,
}) as Result<_, Error>
})
.await?;
Some(profile)
} else {
None
};
Ok(NavState {
profile,
notification_count,
@ -73,14 +100,14 @@ impl FromRequest for NavState {
admin,
href,
is_open,
dark: false,
dark: true,
})
})
}
}
pub struct NavState {
profile: Option<Profile>,
profile: Option<OwnedProfileView>,
notification_count: Option<u64>,
logout_state: Option<LogoutState>,
admin: Option<Admin>,
@ -94,50 +121,70 @@ impl NavState {
&self.href
}
fn submission_button(&self, loader: &ActixLoader) -> Button {
Button::primary(&fl!(loader, "nav-submission-button")).href("/submissions/create")
pub(crate) fn profile<'a>(&'a self) -> Option<ProfileView<'a>> {
self.profile.as_ref().map(|p| ProfileView {
profile: &p.profile,
icon: p.icon.as_ref(),
banner: p.banner.as_ref(),
})
}
pub(crate) fn submission_button(&self, loader: &ActixLoader) -> Button {
Button::primary_link(&fl!(loader, "nav-submission-button")).href("/submissions/create")
}
fn nav_button(&self, loader: &ActixLoader) -> Button {
Button::secondary(&fl!(loader, "nav-text"))
Button::link(&fl!(loader, "nav-text"))
.href(&self.href)
.class("nav-link")
}
fn browse_button(&self, loader: &ActixLoader) -> Button {
Button::secondary(&fl!(loader, "nav-browse-button")).href("/browse")
pub(crate) fn browse_button(&self, loader: &ActixLoader) -> Button {
Button::link(&fl!(loader, "nav-browse-button")).href("/browse")
}
fn profile_button(&self, loader: &ActixLoader) -> Button {
if let Some(profile) = self.profile.as_ref() {
Button::secondary(&fl!(loader, "nav-profile-button")).href(&profile.view_path())
if let Some(view) = self.profile.as_ref() {
Button::link(&fl!(loader, "nav-profile-button")).href(&view.profile.view_path())
} else {
Button::secondary(&fl!(loader, "nav-switch-profile-button")).href("/profiles/change")
Button::link(&fl!(loader, "nav-switch-profile-button")).href("/profiles/change")
}
}
pub(crate) fn notifications_path(&self) -> &'static str {
"/notifications"
}
fn notifications_button(&self, loader: &ActixLoader) -> Button {
Button::secondary(&fl!(loader, "nav-notifications-button")).href("/notifications")
Button::link(&fl!(loader, "nav-notifications-button")).href(self.notifications_path())
}
fn admin_button(&self, loader: &ActixLoader) -> Button {
Button::secondary(&fl!(loader, "nav-admin-button")).href("/admin")
Button::link(&fl!(loader, "nav-admin-button")).href("/admin")
}
fn account_button(&self, loader: &ActixLoader) -> Button {
Button::secondary(&fl!(loader, "nav-account-button")).href("/session/account")
Button::link(&fl!(loader, "nav-account-button")).href("/session/account")
}
fn login_button(&self, loader: &ActixLoader) -> Button {
Button::primary_outline(&fl!(loader, "nav-login-button")).href("/session/auth/login")
Button::primary_link(&fl!(loader, "nav-login-button")).href("/session/auth/login")
}
fn register_button(&self, loader: &ActixLoader) -> Button {
Button::primary_outline(&fl!(loader, "nav-register-button")).href("/session/auth/register")
Button::primary_link(&fl!(loader, "nav-register-button")).href("/session/auth/register")
}
fn logout_button(&self, logout_state: &LogoutState, loader: &ActixLoader) -> Button {
Button::primary_outline(&fl!(loader, "nav-logout-button")).form(&logout_state.logout_path())
Button::primary_link(&fl!(loader, "nav-logout-button")).form(&logout_state.logout_path())
}
pub(crate) fn has_notifications(&self) -> bool {
if let Some(count) = self.notification_count {
count > 0
} else {
false
}
}
pub(crate) fn buttons(&self, loader: &ActixLoader) -> Vec<Button> {
@ -148,10 +195,8 @@ impl NavState {
nav.push(self.browse_button(loader));
nav.push(self.profile_button(loader));
if let Some(count) = self.notification_count {
if count > 0 {
nav.push(self.notifications_button(loader));
}
if self.has_notifications() {
nav.push(self.notifications_button(loader));
}
nav.push(self.account_button(loader));
@ -189,10 +234,8 @@ impl NavState {
site_nav.push(self.browse_button(loader));
site_nav.push(self.profile_button(loader));
if let Some(count) = self.notification_count {
if count > 0 {
site_nav.push(self.notifications_button(loader));
}
if self.has_notifications() {
site_nav.push(self.notifications_button(loader));
}
if self.admin.is_some() {

View file

@ -5,14 +5,14 @@
@use hyaenidae_toolkit::templates::bbcode;
@use hyaenidae_toolkit::templates::{card_body, card_section};
@use hyaenidae_toolkit::{templates::link, Link};
@use hyaenidae_toolkit::templates::icon;
@use hyaenidae_toolkit::{templates::icon, Size};
@use hyaenidae_toolkit::{templates::{tile, tiles}, Tiles};
@(loader: &ActixLoader, sub_view: &OwnedSubmissionView, pro_view: &OwnedProfileView, dark: bool)
@:card_body({
<div class="profile-box">
@:icon(&pro_view.icon(loader).small(true).dark(dark))
@:icon(&pro_view.icon(loader).size(Size::Small).dark(dark))
<div class="profile-box--content">
<div class="profile-box--all-meta">
<div>

53
templates/bar.rs.html Normal file
View file

@ -0,0 +1,53 @@
@use crate::ActixLoader;
@use crate::nav::NavState;
@use hyaenidae_toolkit::templates::bar;
@use hyaenidae_toolkit::templates::{button, button_group};
@use hyaenidae_toolkit::{templates::icon, Size};
@use hyaenidae_toolkit::{templates::link, Link};
@use i18n_embed_fl::fl;
@(loader: &ActixLoader, nav_state: &NavState)
@:bar(nav_state.dark(), "desktop-bar", {
<div>
@:link(&Link::current_tab("/").plain(true), {
<h2>@fl!(loader, "site-name")</h2>
})
</div>
<nav>
@if let Some(profile) = nav_state.profile() {
<div class="profile-nav">
<div class="toolkit-button-group">
@:button(&nav_state.submission_button(loader))
@:button(&nav_state.browse_button(loader))
@if nav_state.has_notifications() {
<div class="toolkit-button toolkit-button__link">
<span><i class="fa fa-bell"></i></span>
@:link(&Link::current_tab(nav_state.notifications_path()).plain(true).class("toolkit-button--action"), {
<i class="fa fa-bell"></i>
})
</div>
}
</div>
@:icon(&profile.icon(loader).size(Size::Tiny).class("bar-icon").dark(true))
</div>
} else {
<div class="narrow-nav">
@:button_group(&nav_state.narrow_buttons(loader))
</div>
<div class="wide-nav">
@:button_group(&nav_state.buttons(loader))
</div>
}
</nav>
})
@:bar(nav_state.dark(), "mobile-bar", {
@:link(&Link::current_tab("/").plain(true), {
<h2>@fl!(loader, "site-name")</h2>
})
<h3 class="nav-link">
@:link(&Link::current_tab(nav_state.href()).plain(true), {
@fl!(loader, "nav-text")
})
</h3>
})

View file

@ -5,13 +5,13 @@
@use crate::views::OwnedProfileView;
@use chrono::{DateTime, Utc};
@use hyaenidae_toolkit::{templates::link, Link};
@use hyaenidae_toolkit::templates::icon;
@use hyaenidae_toolkit::{templates::icon, Size};
@use i18n_embed_fl::fl;
@(loader: &ActixLoader, view: &OwnedProfileView, published: DateTime<Utc>, parent: &CommentNode, cache: &Cache, dark: bool, meta: Content, body: Content)
<div class="profile-box">
@:icon(&view.icon(loader).small(true).dark(dark))
@:icon(&view.icon(loader).size(Size::Small).dark(dark))
<div class="profile-box--content">
<div class="profile-box--all-meta">
<div>

View file

@ -1,7 +1,9 @@
@use crate::ActixLoader;
@use crate::{templates::layouts::root, nav::NavState};
@use crate::nav::NavState;
@use crate::templates::bar;
@use crate::templates::layouts::root;
@use crate::templates::statics::nav_js;
@use hyaenidae_toolkit::templates::{bar, centered};
@use hyaenidae_toolkit::templates::centered;
@use hyaenidae_toolkit::{templates::{card, card_body}, Card};
@use hyaenidae_toolkit::{templates::link, Link};
@use hyaenidae_toolkit::{templates::button_group, Button};
@ -13,31 +15,7 @@
<script src="@crate::statics_path(nav_js.name)"></script>
@:head()
}, {
@:bar(nav_state.dark(), "desktop-bar", {
<div>
@:link(&Link::current_tab("/").plain(true), {
<h2>@fl!(loader, "site-name")</h2>
})
</div>
<nav>
<div class="narrow-nav">
@:button_group(&nav_state.narrow_buttons(loader))
</div>
<div class="wide-nav">
@:button_group(&nav_state.buttons(loader))
</div>
</nav>
})
@:bar(nav_state.dark(), "mobile-bar", {
@:link(&Link::current_tab("/").plain(true), {
<h2>@fl!(loader, "site-name")</h2>
})
<h3 class="nav-link">
@:link(&Link::current_tab(nav_state.href()).plain(true), {
@fl!(loader, "nav-text")
})
</h3>
})
@:bar(loader, nav_state)
<div class="home-content">
@:body()
</div>

View file

@ -6,7 +6,7 @@
@use hyaenidae_toolkit::{templates::button_group, Button};
@use hyaenidae_toolkit::{templates::{card, card_body, card_section}, Card};
@use hyaenidae_toolkit::templates::centered;
@use hyaenidae_toolkit::templates::{icon, image};
@use hyaenidae_toolkit::{templates::{icon, image}, Size};
@use hyaenidae_toolkit::{templates::link, Link};
@use hyaenidae_toolkit::templates::search;
@use hyaenidae_toolkit::{templates::{tab, tab_group}, Tab};
@ -42,7 +42,7 @@
}
<div class="profile-result--left">
<div class="profile-result--icon">
@:icon(&pview.icon(loader).small(true).dark(nav_state.dark()))
@:icon(&pview.icon(loader).size(Size::Small).dark(nav_state.dark()))
</div>
<div class="profile-result--meta">
<div class="profile-result--display-name">

View file

@ -5,7 +5,7 @@
@use crate::views::OwnedProfileView;
@use hyaenidae_toolkit::{templates::button_group, Button};
@use hyaenidae_toolkit::{templates::{card, card_body, card_section, card_title}, Card};
@use hyaenidae_toolkit::templates::{icon, image};
@use hyaenidae_toolkit::{templates::{icon, image}, Size};
@use hyaenidae_toolkit::{templates::link, Link};
@use i18n_embed_fl::fl;
@ -24,7 +24,7 @@
}
<div class="profile-result--left">
<div class="profile-result--icon">
@:icon(&pview.icon(loader).small(true).dark(nav_state.dark()))
@:icon(&pview.icon(loader).size(Size::Small).dark(nav_state.dark()))
</div>
<div class="profile-result--meta">
<div class="profile-result--display-name">

View file

@ -4,12 +4,12 @@
@use crate::views::OwnedProfileView;
@use chrono::{DateTime, Utc};
@use hyaenidae_toolkit::{templates::link, Link};
@use hyaenidae_toolkit::templates::icon;
@use hyaenidae_toolkit::{templates::icon, Size};
@(loader: &ActixLoader, view: &OwnedProfileView, published: Option<DateTime<Utc>>, dark: bool, body: Content)
<div class="profile-box">
@:icon(&view.icon(loader).small(true).dark(dark))
@:icon(&view.icon(loader).size(Size::Small).dark(dark))
<div class="profile-box--content">
<div class="profile-box--all-meta">
<div class="profile-box--meta">