transformation buttons
This commit is contained in:
parent
e403be8090
commit
221e15d7ac
@ -7,11 +7,15 @@ use leptos::prelude::*;
|
|||||||
pub fn Button(
|
pub fn Button(
|
||||||
#[prop(into, optional)] icon: MaybeProp<Icon>,
|
#[prop(into, optional)] icon: MaybeProp<Icon>,
|
||||||
|
|
||||||
#[prop(into)] text: Signal<String>,
|
#[prop(into, optional)] text: MaybeProp<String>,
|
||||||
|
|
||||||
#[prop(optional)] color: Gradient,
|
#[prop(optional)] color: Gradient,
|
||||||
|
|
||||||
#[prop(into, optional)] highlight: MaybeProp<bool>,
|
#[prop(into, optional)] highlight: MaybeProp<bool>,
|
||||||
|
|
||||||
|
#[prop(into, optional)] disabled: MaybeProp<bool>,
|
||||||
|
|
||||||
|
#[prop(into, optional)] on_click: MaybeProp<Callback<()>>,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
let margin = "mx-2 my-1 sm:mx-5 sm:my-2.5";
|
let margin = "mx-2 my-1 sm:mx-5 sm:my-2.5";
|
||||||
|
|
||||||
@ -26,7 +30,7 @@ pub fn Button(
|
|||||||
view! { <div class=classes>{icon_view}</div> }
|
view! { <div class=classes>{icon_view}</div> }
|
||||||
});
|
});
|
||||||
|
|
||||||
let separator = icon.get().is_some().then(|| {
|
let separator = (icon.read().is_some() && text.read().is_some()).then(|| {
|
||||||
let mut classes = "w-0.5 bg-linear-to-br min-w-0.5".to_string();
|
let mut classes = "w-0.5 bg-linear-to-br min-w-0.5".to_string();
|
||||||
classes.push(' ');
|
classes.push(' ');
|
||||||
classes.push_str(color.class_from());
|
classes.push_str(color.class_from());
|
||||||
@ -36,16 +40,34 @@ pub fn Button(
|
|||||||
view! { <div class=classes /> }
|
view! { <div class=classes /> }
|
||||||
});
|
});
|
||||||
|
|
||||||
let text_view = {
|
let text_view = text.get().map(|text| {
|
||||||
let mut classes = "self-center uppercase w-full text-sm sm:text-base md:text-lg font-thin".to_string();
|
let mut classes = "self-center uppercase w-full text-sm sm:text-base md:text-lg font-thin".to_string();
|
||||||
classes.push(' ');
|
classes.push(' ');
|
||||||
classes.push_str(margin);
|
classes.push_str(margin);
|
||||||
|
|
||||||
view! { <div class=classes>{text.get()}</div> }
|
view! { <div class=classes>{text}</div> }
|
||||||
|
});
|
||||||
|
|
||||||
|
let class = move || {
|
||||||
|
let mut classes = vec![];
|
||||||
|
if disabled.get().unwrap_or_default() {
|
||||||
|
classes.extend(["brightness-50"]);
|
||||||
|
} else {
|
||||||
|
classes.extend(["cursor-pointer", "hover:brightness-125", "active:brightness-90"]);
|
||||||
|
}
|
||||||
|
classes.join(" ")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let on_click = move |_| {
|
||||||
|
if let Some(cb) = on_click.get() {
|
||||||
|
cb.run(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let prop_disabled = move || disabled.get();
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<button type="button" class="cursor-pointer hover:brightness-125 active:brightness-90">
|
<button type="button" class=class prop:disabled=prop_disabled on:click=on_click>
|
||||||
<OutlinedBox color highlight>
|
<OutlinedBox color highlight>
|
||||||
<div class="flex items-stretch">{icon_view} {separator} {text_view}</div>
|
<div class="flex items-stretch">{icon_view} {separator} {text_view}</div>
|
||||||
</OutlinedBox>
|
</OutlinedBox>
|
||||||
|
@ -13,6 +13,9 @@ pub enum Icon {
|
|||||||
NoSymbol,
|
NoSymbol,
|
||||||
Trophy,
|
Trophy,
|
||||||
ArrowTrendingUp,
|
ArrowTrendingUp,
|
||||||
|
ChevronLeft,
|
||||||
|
ChevronRight,
|
||||||
|
CodeBracketSquare,
|
||||||
}
|
}
|
||||||
impl Icon {
|
impl Icon {
|
||||||
// TODO: Actually impl IntoView for Icon instead
|
// TODO: Actually impl IntoView for Icon instead
|
||||||
@ -29,6 +32,9 @@ impl Icon {
|
|||||||
Icon::NoSymbol => view! { <NoSymbol /> }.into_any(),
|
Icon::NoSymbol => view! { <NoSymbol /> }.into_any(),
|
||||||
Icon::Trophy => view! { <Trophy /> }.into_any(),
|
Icon::Trophy => view! { <Trophy /> }.into_any(),
|
||||||
Icon::ArrowTrendingUp => view! { <ArrowTrendingUp /> }.into_any(),
|
Icon::ArrowTrendingUp => view! { <ArrowTrendingUp /> }.into_any(),
|
||||||
|
Icon::ChevronLeft => view! { <ChevronLeft /> }.into_any(),
|
||||||
|
Icon::ChevronRight => view! { <ChevronRight /> }.into_any(),
|
||||||
|
Icon::CodeBracketSquare => view! { <CodeBracketSquare /> }.into_any(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,3 +232,55 @@ pub fn ArrowTrendingUp() -> impl IntoView {
|
|||||||
</svg>
|
</svg>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn ChevronLeft() -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="size-6"
|
||||||
|
>
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5" />
|
||||||
|
</svg>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn ChevronRight() -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="size-6"
|
||||||
|
>
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5" />
|
||||||
|
</svg>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn CodeBracketSquare() -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="size-6"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M14.25 9.75 16.5 12l-2.25 2.25m-4.5 0L7.5 12l2.25-2.25M6 20.25h12A2.25 2.25 0 0 0 20.25 18V6A2.25 2.25 0 0 0 18 3.75H6A2.25 2.25 0 0 0 3.75 6v12A2.25 2.25 0 0 0 6 20.25Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -177,37 +177,59 @@ fn View() -> impl IntoView {
|
|||||||
<Wall />
|
<Wall />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col" style="width:38rem">
|
<div class="flex flex-col px-2 pt-3" style="width:38rem">
|
||||||
<Section title="Filter">
|
<Section title="Problems">
|
||||||
<Filter />
|
<Filter />
|
||||||
|
|
||||||
|
<Separator />
|
||||||
|
|
||||||
|
<div class="flex flex-row justify-around">
|
||||||
|
<Transformations />
|
||||||
|
<NextProblemButton />
|
||||||
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
<NextProblemButton />
|
<Section title="Current problem">
|
||||||
|
|
||||||
<Separator />
|
|
||||||
|
|
||||||
<Section title="Problem">
|
|
||||||
{move || ctx.problem.get().map(|problem| view! { <ProblemInfo problem /> })}
|
{move || ctx.problem.get().map(|problem| view! { <ProblemInfo problem /> })}
|
||||||
|
<Separator /> <AttemptRadioGroup /> <Separator /> <History />
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Separator />
|
|
||||||
|
|
||||||
<AttemptRadioGroup />
|
|
||||||
|
|
||||||
<Separator />
|
|
||||||
|
|
||||||
<History />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-auto flex flex-row justify-end items-start px-5 pt-3">
|
<div class="flex-auto flex flex-row justify-end items-start px-2 pt-3">
|
||||||
<HoldsButton />
|
<HoldsButton />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
fn Transformations() -> impl IntoView {
|
||||||
|
crate::tracing::on_enter!();
|
||||||
|
|
||||||
|
let ctx = use_context::<Context>().unwrap();
|
||||||
|
|
||||||
|
let on_left = Callback::new(move |()| {
|
||||||
|
tracing::info!("left");
|
||||||
|
});
|
||||||
|
let on_mirror = Callback::new(move |()| {
|
||||||
|
tracing::info!("mirror");
|
||||||
|
});
|
||||||
|
let on_right = Callback::new(move |()| {
|
||||||
|
tracing::info!("right");
|
||||||
|
});
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<div class="flex flex-row justify-center gap-2">
|
||||||
|
<Button icon=Icon::ChevronLeft disabled=true on_click=on_left />
|
||||||
|
<Button icon=Icon::CodeBracketSquare on_click=on_mirror />
|
||||||
|
<Button icon=Icon::ChevronRight on_click=on_right />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
fn HoldsButton() -> impl IntoView {
|
fn HoldsButton() -> impl IntoView {
|
||||||
@ -231,19 +253,8 @@ fn NextProblemButton() -> impl IntoView {
|
|||||||
|
|
||||||
let ctx = use_context::<Context>().unwrap();
|
let ctx = use_context::<Context>().unwrap();
|
||||||
|
|
||||||
let on_click = move |_| ctx.cb_next_problem.run(());
|
let on_click = Callback::new(move |_| ctx.cb_next_problem.run(()));
|
||||||
view! {
|
view! { <Button icon=Icon::ArrowPath text="Next problem" on_click color=Gradient::PurpleBlue /> }
|
||||||
<div class="flex flex-col">
|
|
||||||
<div class="self-center">
|
|
||||||
<Button
|
|
||||||
icon=Icon::ArrowPath
|
|
||||||
text="Next problem"
|
|
||||||
on:click=on_click
|
|
||||||
color=Gradient::PurpleBlue
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
@ -425,7 +436,10 @@ fn History() -> impl IntoView {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
view! { <Section title="History">{placeholder} {attempts}</Section> }
|
view! {
|
||||||
|
{placeholder}
|
||||||
|
{attempts}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
|
@ -10,29 +10,6 @@ pub async fn run_migrations(db: &Database) -> Result<(), Box<dyn std::error::Err
|
|||||||
migrate_to_v3(db).await?;
|
migrate_to_v3(db).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
migrate_wall(db).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(skip_all, err)]
|
|
||||||
pub async fn migrate_wall(db: &Database) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
tracing::warn!("MIGRATING WALL");
|
|
||||||
|
|
||||||
db.write(|txn| {
|
|
||||||
let mut table = txn.open_table(db::current::TABLE_WALLS)?;
|
|
||||||
let wall = table
|
|
||||||
.get(models::WallUid(uuid::Uuid::parse_str("8a00ab39-89f5-4fc5-b9c6-f86b4c040f68").unwrap()))?
|
|
||||||
.map(|x| x.value());
|
|
||||||
if let Some(mut wall) = wall {
|
|
||||||
wall.rows = 11;
|
|
||||||
wall.holds.retain(|k, _| k.row < 11);
|
|
||||||
table.insert(wall.uid, wall)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user