mirror of
https://github.com/Nutomic/ibis.git
synced 2025-02-04 17:34:40 +00:00
remove more code
This commit is contained in:
parent
d7d79af7a9
commit
ee34c98b52
5 changed files with 21 additions and 320 deletions
|
@ -1,8 +1,6 @@
|
|||
use crate::{
|
||||
common::SiteView,
|
||||
frontend::{
|
||||
api::CLIENT, components::nav::Nav, dark_mode::DarkMode, pages::notifications::Notifications,
|
||||
},
|
||||
frontend::{api::CLIENT, components::nav::Nav, pages::notifications::Notifications},
|
||||
};
|
||||
use leptos::prelude::*;
|
||||
use leptos_meta::{provide_meta_context, *};
|
||||
|
@ -66,9 +64,6 @@ pub fn App() -> impl IntoView {
|
|||
let site_resource = Resource::new(|| (), |_| async move { CLIENT.site().await.unwrap() });
|
||||
provide_context(site_resource);
|
||||
|
||||
let darkmode = DarkMode::init();
|
||||
provide_context(darkmode.clone());
|
||||
|
||||
view! {
|
||||
<Html attr:data-theme=darkmode.theme {..} class="h-full" />
|
||||
<Body {..} class="h-full max-sm:flex max-sm:flex-col" />
|
||||
|
|
|
@ -1,164 +1,31 @@
|
|||
use crate::frontend::{
|
||||
api::CLIENT,
|
||||
app::{is_logged_in, site, DefaultResource},
|
||||
dark_mode::DarkMode,
|
||||
};
|
||||
use leptos::{component, prelude::*, view, IntoView, *};
|
||||
use leptos_router::{components::A, hooks::use_navigate};
|
||||
use crate::frontend::{api::CLIENT, app::is_logged_in};
|
||||
use leptos::{component, prelude::*, view, IntoView};
|
||||
use leptos_router::components::A;
|
||||
|
||||
#[component]
|
||||
pub fn Nav() -> impl IntoView {
|
||||
let logout_action = Action::new(move |_| async move {
|
||||
CLIENT.logout().await.unwrap();
|
||||
site().refetch();
|
||||
});
|
||||
let notification_count = Resource::new(
|
||||
|| (),
|
||||
move |_| async move { CLIENT.notifications_count().await.unwrap_or_default() },
|
||||
);
|
||||
|
||||
let (search_query, set_search_query) = signal(String::new());
|
||||
let mut dark_mode = expect_context::<DarkMode>();
|
||||
view! {
|
||||
<nav class="max-sm:navbar p-2.5 h-full md:fixed md:w-64 max-sm: border-b md:border-e border-slate-400 border-solid">
|
||||
<div
|
||||
id="navbar-start"
|
||||
class="max-sm:navbar-start max-sm:flex max-sm:dropdown max-sm:dropdown-bottom max-sm:dropdown-end max-sm:w-full md:h-full"
|
||||
>
|
||||
<h1 class="w-min md:hidden text-3xl font-bold font-serif">
|
||||
{CLIENT.hostname.clone()}
|
||||
</h1>
|
||||
<div class="flex-grow md:hidden"></div>
|
||||
<button tabindex="0" class="btn btn-outline lg:hidden">
|
||||
Menu
|
||||
</button>
|
||||
<div
|
||||
tabindex="0"
|
||||
class="menu dropdown-content p-2 max-sm:rounded-box max-sm:z-[1] max-sm:shadow md:h-full"
|
||||
>
|
||||
<img src="/logo.png" class="m-auto max-sm:hidden" />
|
||||
<h1 class="px-4 py-2 text-3xl font-bold font-serif sm:hidden">
|
||||
{CLIENT.hostname.clone()}
|
||||
</h1>
|
||||
<ul>
|
||||
<li>
|
||||
<A href="/">"Main Page"</A>
|
||||
</li>
|
||||
<li>
|
||||
<A href="/instance/list">"Instances"</A>
|
||||
</li>
|
||||
<li>
|
||||
<A href="/article/list">"Articles"</A>
|
||||
</li>
|
||||
<Transition>
|
||||
<Show when=is_logged_in>
|
||||
<li>
|
||||
<A href="/article/create">"Create Article"</A>
|
||||
</li>
|
||||
<li>
|
||||
<A href="/notifications">
|
||||
"Notifications "
|
||||
<span class="indicator-item indicator-end badge badge-neutral">
|
||||
{move || notification_count.get()}
|
||||
</span>
|
||||
</A>
|
||||
</li>
|
||||
</Show>
|
||||
</Transition>
|
||||
<li>
|
||||
<form
|
||||
class="form-control m-0 p-1"
|
||||
on:submit=move |ev| {
|
||||
ev.prevent_default();
|
||||
let navigate = use_navigate();
|
||||
let query = search_query.get();
|
||||
if !query.is_empty() {
|
||||
navigate(
|
||||
&format!("/search?query={query}"),
|
||||
Default::default(),
|
||||
);
|
||||
}
|
||||
}
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
class="input input-secondary input-bordered input-xs w-full rounded"
|
||||
placeholder="Search"
|
||||
prop:value=search_query
|
||||
on:keyup=move |ev: ev::KeyboardEvent| {
|
||||
let val = event_target_value(&ev);
|
||||
set_search_query.update(|v| *v = val);
|
||||
}
|
||||
/>
|
||||
|
||||
<button class="btn btn-xs btn-secondary">Go</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="divider"></div>
|
||||
<Transition>
|
||||
<Show
|
||||
when=is_logged_in
|
||||
fallback=move || {
|
||||
view! {
|
||||
<li>
|
||||
<A href="/login">"Login"</A>
|
||||
</li>
|
||||
<Show when=move || {
|
||||
site().with_default(|s| s.config.registration_open)
|
||||
}>
|
||||
<li>
|
||||
<A href="/register">"Register"</A>
|
||||
</li>
|
||||
</Show>
|
||||
}
|
||||
}
|
||||
>
|
||||
|
||||
{
|
||||
let my_profile = site()
|
||||
.with_default(|site| site.clone().my_profile.unwrap());
|
||||
let profile_link = format!("/user/{}", my_profile.person.username);
|
||||
view! {
|
||||
<p class="self-center pb-2">
|
||||
"Logged in as " <a class="link" href=profile_link>
|
||||
{my_profile.person.username}
|
||||
</a>
|
||||
</p>
|
||||
<button
|
||||
class="btn btn-outline btn-xs w-min self-center"
|
||||
on:click=move |_| {
|
||||
logout_action.dispatch(());
|
||||
}
|
||||
>
|
||||
Logout
|
||||
</button>
|
||||
}
|
||||
}
|
||||
|
||||
</Show>
|
||||
</Transition>
|
||||
<div class="grow min-h-2"></div>
|
||||
<div class="m-1 grid gap-2">
|
||||
<label class="flex cursor-pointer gap-2">
|
||||
<span class="label-text">Light</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle"
|
||||
prop:checked=dark_mode.is_dark
|
||||
on:click=move |_| { dark_mode.toggle() }
|
||||
/>
|
||||
<span class="label-text">Dark</span>
|
||||
</label>
|
||||
<p>"Version "{env!("CARGO_PKG_VERSION")}</p>
|
||||
<p>
|
||||
<a href="https://github.com/Nutomic/ibis" class="link">
|
||||
Source Code
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav>
|
||||
<Transition>
|
||||
<Show when=is_logged_in>
|
||||
<li>
|
||||
<A href="/article/create">"Create Article"</A>
|
||||
</li>
|
||||
<li>
|
||||
<A href="/notifications">
|
||||
"Notifications "
|
||||
<span class="indicator-item indicator-end badge badge-neutral">
|
||||
{move || notification_count.get()}
|
||||
</span>
|
||||
</A>
|
||||
</li>
|
||||
</Show>
|
||||
</Transition>
|
||||
</nav>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
use chrono::{Duration, Local};
|
||||
use codee::string::FromToStringCodec;
|
||||
use leptos::prelude::*;
|
||||
use leptos_use::{use_cookie_with_options, use_preferred_dark, SameSite, UseCookieOptions};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DarkMode {
|
||||
cookie: WriteSignal<Option<bool>>,
|
||||
pub is_dark: Signal<bool>,
|
||||
pub theme: Signal<&'static str>,
|
||||
}
|
||||
|
||||
impl DarkMode {
|
||||
pub fn init() -> Self {
|
||||
let expires = (Local::now() + Duration::days(356)).timestamp();
|
||||
let cookie_options = UseCookieOptions::default()
|
||||
.path("/")
|
||||
.expires(expires)
|
||||
.same_site(SameSite::Strict);
|
||||
let cookie =
|
||||
use_cookie_with_options::<bool, FromToStringCodec>("dark_mode", cookie_options);
|
||||
|
||||
let is_dark = Signal::derive(move || {
|
||||
let default = || use_preferred_dark().get_untracked();
|
||||
cookie.0.get().unwrap_or_else(default)
|
||||
});
|
||||
let theme = Signal::derive(move || if is_dark.get() { "dim" } else { "emerald" });
|
||||
Self {
|
||||
cookie: cookie.1,
|
||||
is_dark,
|
||||
theme,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle(&mut self) {
|
||||
let new = !self.is_dark.get_untracked();
|
||||
self.cookie.set(Some(new));
|
||||
}
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
use crate::common::{utils::extract_domain, DbArticle};
|
||||
|
||||
pub mod api;
|
||||
pub mod app;
|
||||
mod components;
|
||||
pub mod dark_mode;
|
||||
pub mod error;
|
||||
pub mod markdown;
|
||||
pub mod pages;
|
||||
|
@ -16,24 +13,3 @@ pub fn hydrate() {
|
|||
console_error_panic_hook::set_once();
|
||||
leptos::mount::hydrate_body(App);
|
||||
}
|
||||
|
||||
fn article_link(article: &DbArticle) -> String {
|
||||
if article.local {
|
||||
format!("/article/{}", article.title)
|
||||
} else {
|
||||
format!(
|
||||
"/article/{}@{}",
|
||||
article.title,
|
||||
extract_domain(&article.ap_id)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn article_title(article: &DbArticle) -> String {
|
||||
let title = article.title.replace('_', " ");
|
||||
if article.local {
|
||||
title
|
||||
} else {
|
||||
format!("{}@{}", title, extract_domain(&article.ap_id))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,104 +1,6 @@
|
|||
use crate::{
|
||||
common::Notification,
|
||||
frontend::{api::CLIENT, article_link, article_title},
|
||||
};
|
||||
use leptos::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub fn Notifications() -> impl IntoView {
|
||||
let notifications = Resource::new(
|
||||
move || {},
|
||||
|_| async move { CLIENT.notifications_list().await.unwrap() },
|
||||
);
|
||||
|
||||
view! {
|
||||
<h1 class="text-4xl font-bold font-serif my-6 grow flex-auto">Notifications</h1>
|
||||
<Suspense fallback=|| view! { "Loading..." }>
|
||||
<ul class="divide-y divide-solid">
|
||||
{move || {
|
||||
notifications
|
||||
.get()
|
||||
.map(|n| {
|
||||
n.into_iter()
|
||||
.map(|ref notif| {
|
||||
use Notification::*;
|
||||
let (my_style, link, title) = match notif {
|
||||
EditConflict(c) => {
|
||||
(
|
||||
"visibility: hidden",
|
||||
format!("{}/edit/{}", article_link(&c.article), c.id.0),
|
||||
format!(
|
||||
"Conflict: {} - {}",
|
||||
article_title(&c.article),
|
||||
c.summary,
|
||||
),
|
||||
)
|
||||
}
|
||||
ArticleApprovalRequired(a) => {
|
||||
(
|
||||
"",
|
||||
article_link(a),
|
||||
format!("Approval required: {}", a.title),
|
||||
)
|
||||
}
|
||||
};
|
||||
let notif_ = notif.clone();
|
||||
let click_approve = Action::new(move |_: &()| {
|
||||
let notif_ = notif_.clone();
|
||||
async move {
|
||||
if let ArticleApprovalRequired(a) = notif_ {
|
||||
CLIENT.approve_article(a.id, true).await.unwrap();
|
||||
}
|
||||
notifications.refetch();
|
||||
}
|
||||
});
|
||||
let notif_ = notif.clone();
|
||||
let click_reject = Action::new(move |_: &()| {
|
||||
let notif_ = notif_.clone();
|
||||
async move {
|
||||
match notif_ {
|
||||
EditConflict(c) => {
|
||||
CLIENT.delete_conflict(c.id).await.unwrap();
|
||||
}
|
||||
ArticleApprovalRequired(a) => {
|
||||
CLIENT.approve_article(a.id, false).await.unwrap();
|
||||
}
|
||||
}
|
||||
notifications.refetch();
|
||||
}
|
||||
});
|
||||
view! {
|
||||
<li class="py-2">
|
||||
<a class="link text-lg" href=link>
|
||||
{title}
|
||||
</a>
|
||||
<div class="card-actions mt-2">
|
||||
<button
|
||||
class="btn btn-sm btn-outline"
|
||||
style=my_style
|
||||
on:click=move |_| {
|
||||
click_approve.dispatch(());
|
||||
}
|
||||
>
|
||||
Approve
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm btn-outline"
|
||||
on:click=move |_| {
|
||||
click_reject.dispatch(());
|
||||
}
|
||||
>
|
||||
Reject
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
}}
|
||||
|
||||
</ul>
|
||||
</Suspense>
|
||||
}
|
||||
view! {}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue