This commit is contained in:
Asger Juul Brunshøj 2025-01-19 23:55:09 +01:00
parent 5fd2b1206a
commit 8beaa5b0d4
4 changed files with 125 additions and 22 deletions

View File

@ -40,11 +40,6 @@ pub fn App() -> impl leptos::IntoView {
<Title text="Ascend" /> <Title text="Ascend" />
<Router> <Router>
// <nav class="shadow-md mb-2 bg-white border-gray-200 px-4 lg:px-6 py-2.5">
// <div class="flex flex-wrap justify-start items-center gap-4 max-w-screen-xl">
// <HeaderItem text="Home" link="/"/>
// </div>
// </nav>
<main> <main>
<Routes fallback=|| "Not found"> <Routes fallback=|| "Not found">
<Route path=path!("/wall") view=Wall /> <Route path=path!("/wall") view=Wall />

View File

@ -1,6 +1,54 @@
use leptos::prelude::*; use leptos::prelude::*;
#[component] pub struct HeaderItems {
pub fn Header() -> impl leptos::IntoView { pub left: Vec<HeaderItem>,
leptos::view! { <div class="border-b py-2 mb-4">"Ascend"</div> } pub middle: Vec<HeaderItem>,
pub right: Vec<HeaderItem>,
}
pub struct HeaderItem {
pub text: String,
pub link: Option<String>,
}
#[component]
pub fn Header(items: HeaderItems) -> impl IntoView {
let HeaderItems { left, middle, right } = items;
view! {
<div class="text-xl font-semibold p-4 flex gap-4">
// Left side of header
<Items items=left />
// Expanding space in the middle
<div class="flex-auto mx-auto">
<Items items=middle />
</div>
// Right side of header
<Items items=right />
</div>
}
}
#[component]
fn Items(items: Vec<HeaderItem>) -> impl IntoView {
items.into_iter().map(|item| view! { <Item item /> }).collect_view()
}
#[component]
fn Item(item: HeaderItem) -> impl IntoView {
let text = item.text;
let link = item.link;
if let Some(link) = link {
view! {
<a href=link>
<span class="whitespace-nowrap">{text}</span>
</a>
}
.into_any()
} else {
view! { <span class="whitespace-nowrap">{text}</span> }.into_any()
}
} }

View File

@ -1,5 +1,7 @@
use crate::codec::ron::RonCodec; use crate::codec::ron::RonCodec;
use crate::components::header::Header; use crate::components::header::Header;
use crate::components::header::HeaderItem;
use crate::components::header::HeaderItems;
use crate::models; use crate::models;
use crate::models::HoldPosition; use crate::models::HoldPosition;
use crate::models::Wall; use crate::models::Wall;
@ -21,10 +23,54 @@ pub fn EditWall() -> impl leptos::IntoView {
load_initial_data().await.unwrap() load_initial_data().await.unwrap()
}; };
let header_items = HeaderItems {
left: vec![HeaderItem {
text: "".to_string(),
link: Some("/wall".to_string()),
}],
middle: vec![HeaderItem {
text: "Edit wall".to_string(),
link: None,
}],
right: vec![],
};
leptos::view! { leptos::view! {
<div class="min-w-screen min-h-screen bg-slate-900"> <div class="min-w-screen min-h-screen bg-slate-900">
<div class="container mx-auto"> <div class="flex">
<Header /> // Left gradient chunk
<div class="flex-grow">
<div class="h-2/5" style="background: #eaac53" />
<div class="h-3/5" style="background: linear-gradient(to bottom left, #eaac53 49.5%, rgb(15 23 42) 50.5%)" />
</div>
<div class="flex-none container mx-auto text-black" style="background: #eaac53">
<Header items=header_items />
</div>
// Right gradient chunk
<div class="flex-grow" style="background: #eaac53" />
</div>
<div class="flex">
// Left gradient chunk
<div class="flex-grow" />
<div class="flex-none container mx-auto">
// Background color gradient
<div
class="h-6"
style="background: linear-gradient(to bottom left, #eaac53 49.5%, rgb(15 23 42) 50.5%)"
/>
</div>
// Right gradient chunk
<div class="flex-grow">
<div class="h-4/5" style="background: #eaac53" />
<div class="h-1/5" style="background: linear-gradient(to bottom right, #eaac53 49.5%, rgb(15 23 42) 50.5%)" />
</div>
</div>
<div class="container mx-auto mt-2">
<Await future=load let:data> <Await future=load let:data>
<Ready data=data.deref().to_owned() /> <Ready data=data.deref().to_owned() />
</Await> </Await>
@ -44,7 +90,10 @@ fn Ready(data: InitialData) -> impl leptos::IntoView {
let grid_classes = format!("grid grid-rows-{} grid-cols-{} gap-2", data.wall.rows, data.wall.cols); let grid_classes = format!("grid grid-rows-{} grid-cols-{} gap-2", data.wall.rows, data.wall.cols);
view! { <div class=move || { grid_classes.clone() }>{holds}</div> } view! {
<div>
<p class="my-4 font-semibold">"Click hold to replace image"</p>
<div class=move || { grid_classes.clone() }>{holds}</div> </div>}
} }
#[component] #[component]
@ -98,9 +147,7 @@ fn Hold(hold: models::Hold) -> impl leptos::IntoView {
let img = move || { let img = move || {
hold.read().image.as_ref().map(|img| { hold.read().image.as_ref().map(|img| {
let src = format!("/files/holds/{}", img.filename); let src = format!("/files/holds/{}", img.filename);
view! { view! { <img class="object-cover w-full h-full" src=src /> }
<img class="object-cover w-full h-full" src=src />
}
}) })
}; };

View File

@ -1,5 +1,7 @@
use crate::codec::ron::RonCodec; use crate::codec::ron::RonCodec;
use crate::components::header::Header; use crate::components::header::Header;
use crate::components::header::HeaderItem;
use crate::components::header::HeaderItems;
use crate::models; use crate::models;
use crate::models::HoldRole; use crate::models::HoldRole;
use leptos::prelude::*; use leptos::prelude::*;
@ -15,10 +17,22 @@ pub fn Wall() -> impl leptos::IntoView {
load_initial_data().await.unwrap() load_initial_data().await.unwrap()
}; };
let header_items = HeaderItems {
left: vec![],
middle: vec![HeaderItem {
text: "Ascend".to_string(),
link: None,
}],
right: vec![HeaderItem {
text: "Edit wall".to_string(),
link: Some("/wall/edit".to_string()),
}],
};
leptos::view! { leptos::view! {
<div class="min-w-screen min-h-screen bg-slate-900"> <div class="min-w-screen min-h-screen bg-slate-900">
<div class="container mx-auto"> <div class="container mx-auto">
<Header /> <Header items=header_items />
<Await future=load let:data> <Await future=load let:data>
<Ready data=data.deref().to_owned() /> <Ready data=data.deref().to_owned() />
</Await> </Await>
@ -63,7 +77,8 @@ fn Hold(hold: models::Hold, #[prop(into)] role: Signal<Option<HoldRole>>) -> imp
Some(HoldRole::Normal) => Some("outline outline-offset-2 outline-blue-500"), Some(HoldRole::Normal) => Some("outline outline-offset-2 outline-blue-500"),
Some(HoldRole::Zone) => Some("outline outline-offset-2 outline-amber-500"), Some(HoldRole::Zone) => Some("outline outline-offset-2 outline-amber-500"),
Some(HoldRole::End) => Some("outline outline-offset-2 outline-red-500"), Some(HoldRole::End) => Some("outline outline-offset-2 outline-red-500"),
None => Some("brightness-50"), // None => Some("brightness-50"),
None => None,
}; };
let mut s = "bg-indigo-100 aspect-square rounded".to_string(); let mut s = "bg-indigo-100 aspect-square rounded".to_string();
if let Some(c) = role_classes { if let Some(c) = role_classes {
@ -75,9 +90,7 @@ fn Hold(hold: models::Hold, #[prop(into)] role: Signal<Option<HoldRole>>) -> imp
let img = hold.image.map(|img| { let img = hold.image.map(|img| {
let src = format!("/files/holds/{}", img.filename); let src = format!("/files/holds/{}", img.filename);
view! { view! { <img class="hover:object-scale-down object-cover w-full h-full" src=src /> }
<img class="hover:object-scale-down object-cover w-full h-full" src=src />
}
}); });
view! { <div class=class>{img}</div> } view! { <div class=class>{img}</div> }