2024-04-17 22:07:47 +02:00
|
|
|
use leptos::*;
|
|
|
|
use leptos_router::*;
|
|
|
|
use crate::prelude::*;
|
|
|
|
|
2024-05-27 07:36:38 +02:00
|
|
|
use leptos_use::{storage::use_local_storage, use_cookie, utils::{FromToStringCodec, JsonCodec}};
|
2024-04-17 22:07:47 +02:00
|
|
|
|
2024-06-08 03:39:38 +02:00
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub struct Feeds {
|
|
|
|
// object feeds
|
|
|
|
pub home: Timeline,
|
|
|
|
pub global: Timeline,
|
|
|
|
// notification feeds
|
|
|
|
pub private: Timeline,
|
|
|
|
pub public: Timeline,
|
|
|
|
// exploration feeds
|
|
|
|
pub user: Timeline,
|
|
|
|
pub server: Timeline,
|
|
|
|
pub context: Timeline,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Feeds {
|
|
|
|
pub fn new(username: &str) -> Self {
|
|
|
|
Feeds {
|
|
|
|
home: Timeline::new(format!("{URL_BASE}/actors/{username}/feed/page")),
|
|
|
|
global: Timeline::new(format!("{URL_BASE}/feed/page")),
|
|
|
|
private: Timeline::new(format!("{URL_BASE}/actors/{username}/inbox/page")),
|
|
|
|
public: Timeline::new(format!("{URL_BASE}/inbox/page")),
|
|
|
|
user: Timeline::new(format!("{URL_BASE}/actors/{username}/outbox/page")),
|
|
|
|
server: Timeline::new(format!("{URL_BASE}/outbox/page")),
|
|
|
|
context: Timeline::new(format!("{URL_BASE}/outbox/page")), // TODO ehhh
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn reset(&self) {
|
|
|
|
self.home.reset(None);
|
|
|
|
self.global.reset(None);
|
|
|
|
self.private.reset(None);
|
|
|
|
self.public.reset(None);
|
|
|
|
self.user.reset(None);
|
|
|
|
self.server.reset(None);
|
|
|
|
self.context.reset(None);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-17 22:07:47 +02:00
|
|
|
|
|
|
|
#[component]
|
|
|
|
pub fn App() -> impl IntoView {
|
2024-05-27 07:36:38 +02:00
|
|
|
let (token, set_token) = use_cookie::<String, FromToStringCodec>("token");
|
2024-05-02 02:07:11 +02:00
|
|
|
let (userid, set_userid) = use_cookie::<String, FromToStringCodec>("user_id");
|
2024-05-27 07:36:38 +02:00
|
|
|
let (config, set_config, _) = use_local_storage::<crate::Config, JsonCodec>("config");
|
|
|
|
|
2024-05-02 02:07:11 +02:00
|
|
|
let auth = Auth { token, userid };
|
2024-04-17 22:07:47 +02:00
|
|
|
|
2024-05-03 03:55:26 +02:00
|
|
|
let username = auth.userid.get_untracked()
|
|
|
|
.map(|x| x.split('/').last().unwrap_or_default().to_string())
|
|
|
|
.unwrap_or_default();
|
2024-05-29 20:51:30 +02:00
|
|
|
|
2024-06-08 03:39:38 +02:00
|
|
|
let feeds = Feeds::new(&username);
|
|
|
|
|
|
|
|
provide_context(auth);
|
|
|
|
provide_context(config);
|
|
|
|
provide_context(feeds);
|
2024-04-17 22:07:47 +02:00
|
|
|
|
2024-05-01 16:46:19 +02:00
|
|
|
let reply_controls = ReplyControls::default();
|
|
|
|
provide_context(reply_controls);
|
|
|
|
|
2024-04-17 22:07:47 +02:00
|
|
|
let screen_width = window().screen().map(|x| x.avail_width().unwrap_or_default()).unwrap_or_default();
|
|
|
|
|
|
|
|
let (menu, set_menu) = create_signal(screen_width <= 786);
|
2024-04-23 02:48:30 +02:00
|
|
|
let (advanced, set_advanced) = create_signal(false);
|
2024-04-17 22:07:47 +02:00
|
|
|
|
2024-05-29 22:14:15 +02:00
|
|
|
let title_target = move || if auth.present() { "/web/home" } else { "/web/server" };
|
2024-05-27 16:50:42 +02:00
|
|
|
|
2024-06-07 05:26:22 +02:00
|
|
|
spawn_local(async move {
|
|
|
|
// refresh token first, or verify that we're still authed
|
|
|
|
if Auth::refresh(auth.token, set_token, set_userid).await {
|
2024-06-08 03:39:38 +02:00
|
|
|
feeds.home.more(auth); // home inbox requires auth to be read
|
|
|
|
feeds.private.more(auth);
|
2024-06-07 05:26:22 +02:00
|
|
|
}
|
2024-06-08 03:39:38 +02:00
|
|
|
feeds.global.more(auth);
|
|
|
|
feeds.public.more(auth); // server inbox may contain private posts
|
2024-06-07 05:26:22 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// refresh token every hour
|
|
|
|
set_interval(
|
|
|
|
move || spawn_local(async move { Auth::refresh(auth.token, set_token, set_userid).await; }),
|
|
|
|
std::time::Duration::from_secs(3600)
|
|
|
|
);
|
2024-04-17 23:07:56 +02:00
|
|
|
|
2024-04-17 22:07:47 +02:00
|
|
|
view! {
|
|
|
|
<nav class="w-100 mt-1 mb-1 pb-s">
|
2024-05-27 16:50:42 +02:00
|
|
|
<code class="color ml-3" ><a class="upub-title" href=title_target >μpub</a></code>
|
2024-05-13 17:10:46 +02:00
|
|
|
<small class="ml-1 mr-1 hidden-on-tiny" ><a class="clean" href="/web/server" >micro social network, federated</a></small>
|
2024-04-17 22:07:47 +02:00
|
|
|
/* TODO kinda jank with the float but whatever, will do for now */
|
|
|
|
<input type="submit" class="mr-2 rev" on:click=move |_| set_menu.set(!menu.get()) value="menu" style="float: right" />
|
|
|
|
</nav>
|
2024-05-13 01:21:20 +02:00
|
|
|
<hr class="sep sticky" />
|
2024-04-17 22:07:47 +02:00
|
|
|
<div class="container mt-2 pt-2" >
|
|
|
|
<div class="two-col" >
|
2024-04-23 03:05:22 +02:00
|
|
|
<div class="col-side sticky pb-s" class:hidden=move || menu.get() >
|
2024-05-13 01:21:20 +02:00
|
|
|
<Navigator />
|
|
|
|
<hr class="mt-1 mb-1" />
|
2024-04-17 22:07:47 +02:00
|
|
|
<LoginBox
|
2024-05-01 18:22:25 +02:00
|
|
|
token_tx=set_token
|
2024-05-02 02:07:11 +02:00
|
|
|
userid_tx=set_userid
|
2024-04-17 22:07:47 +02:00
|
|
|
/>
|
|
|
|
<hr class="mt-1 mb-1" />
|
2024-05-13 01:21:20 +02:00
|
|
|
<div class:hidden=move || !auth.present() >
|
|
|
|
{move || if advanced.get() { view! {
|
|
|
|
<AdvancedPostBox advanced=set_advanced/>
|
|
|
|
}} else { view! {
|
|
|
|
<PostBox advanced=set_advanced/>
|
|
|
|
}}}
|
|
|
|
<hr class="only-on-mobile sep mb-0 pb-0" />
|
|
|
|
</div>
|
2024-04-17 22:07:47 +02:00
|
|
|
</div>
|
|
|
|
<div class="col-main" class:w-100=move || menu.get() >
|
|
|
|
<Router // TODO maybe set base="/web" ?
|
|
|
|
trailing_slash=TrailingSlash::Redirect
|
|
|
|
fallback=move || view! {
|
2024-05-13 04:03:29 +02:00
|
|
|
<Breadcrumb back=true >404</Breadcrumb>
|
2024-04-17 22:07:47 +02:00
|
|
|
<div class="center">
|
|
|
|
<h3>nothing to see here!</h3>
|
|
|
|
<p><a href="/web"><button type="button">back to root</button></a></p>
|
|
|
|
</div>
|
|
|
|
}.into_view()
|
|
|
|
>
|
|
|
|
// TODO this is kind of ugly: the whole router gets rebuilt every time we log in/out
|
|
|
|
// in a sense it's what we want: refreshing the home tl is main purpose, but also
|
|
|
|
// server tl may contain stuff we can no longer see, or otherwise we may now be
|
|
|
|
// entitled to see new posts. so while being ugly it's techically correct ig?
|
2024-05-29 18:04:47 +02:00
|
|
|
<main>
|
|
|
|
<Routes>
|
|
|
|
<Route path="/web" view=move ||
|
|
|
|
if auth.present() {
|
|
|
|
view! { <Redirect path="/web/home" /> }
|
|
|
|
} else {
|
|
|
|
view! { <Redirect path="/web/server" /> }
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
|
2024-06-08 03:39:38 +02:00
|
|
|
<Route path="/web/home" view=move || view! { <TimelinePage name="home" tl=feeds.home /> } />
|
|
|
|
<Route path="/web/server" view=move || view! { <TimelinePage name="server" tl=feeds.global /> } />
|
|
|
|
<Route path="/web/local" view=move || view! { <TimelinePage name="local" tl=feeds.server /> } />
|
|
|
|
<Route path="/web/inbox" view=move || view! { <TimelinePage name="inbox" tl=feeds.private /> } />
|
2024-05-29 18:04:47 +02:00
|
|
|
|
|
|
|
<Route path="/web/about" view=AboutPage />
|
|
|
|
<Route path="/web/config" view=move || view! { <ConfigPage setter=set_config /> } />
|
|
|
|
<Route path="/web/config/dev" view=DebugPage />
|
|
|
|
|
2024-06-08 03:39:38 +02:00
|
|
|
<Route path="/web/actors/:id" view=UserPage />
|
2024-06-10 03:12:05 +02:00
|
|
|
<Route path="/web/actors/:id/following" view=move || view! { <FollowPage outgoing=true /> } />
|
|
|
|
<Route path="/web/actors/:id/followers" view=move || view! { <FollowPage outgoing=false /> } />
|
|
|
|
|
2024-06-08 03:39:38 +02:00
|
|
|
<Route path="/web/objects/:id" view=ObjectPage />
|
2024-05-29 20:51:30 +02:00
|
|
|
// <Route path="/web/activities/:id" view=move || view! { <ActivityPage tl=context_tl /> } />
|
2024-05-29 18:04:47 +02:00
|
|
|
|
|
|
|
<Route path="/web/search" view=SearchPage />
|
|
|
|
<Route path="/web/register" view=RegisterPage />
|
|
|
|
|
|
|
|
<Route path="/" view=move || view! { <Redirect path="/web" /> } />
|
|
|
|
</Routes>
|
|
|
|
</main>
|
2024-04-17 22:07:47 +02:00
|
|
|
</Router>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<footer>
|
2024-05-21 15:25:47 +02:00
|
|
|
<div class="sep-top">
|
2024-05-21 15:28:22 +02:00
|
|
|
<span class="footer" >"\u{26fc} woven under moonlight :: "<a class="clean" href="https://git.alemi.dev/upub.git" target="_blank" >src</a>" :: "<a class="clean" href="mailto:abuse@alemi.dev">contact</a>" :: "<a class="clean" href="javascript:window.scrollTo({top:0, behavior:'smooth'})">top</a></span>
|
2024-04-17 22:07:47 +02:00
|
|
|
</div>
|
|
|
|
</footer>
|
|
|
|
}
|
|
|
|
}
|