Skip to content

Commit

Permalink
Adds swipe component
Browse files Browse the repository at this point in the history
  • Loading branch information
sanpii committed Jan 17, 2025
1 parent a7508f7 commit 913647a
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 5 deletions.
2 changes: 1 addition & 1 deletion front/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ features = ["v4"]

[dependencies.web-sys]
version = "0.3"
features = ["HtmlDocument", "Performance"]
features = ["HtmlDocument", "Performance", "Touch", "TouchEvent", "TouchList"]

[dependencies.yew]
version = "0.21"
Expand Down
2 changes: 1 addition & 1 deletion front/src/components/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub(crate) fn Component(props: &Properties) -> yew::Html {

if props.inline {
yew::html! {
<div class={ yew::classes!("actions", "inline") }>
<div class={ yew::classes!("actions", "inline", "d-md-none") }>
<span class="read" onclick={ on_read } title={ read_icon.label }>
<super::Svg icon={ read_icon.icon } size=24 />
</span>
Expand Down
3 changes: 2 additions & 1 deletion front/src/components/item.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[macro_export]
macro_rules! toggle {
($name:ident, $item:ident, $context:ident) => {{
let item = $item.clone();
Expand Down Expand Up @@ -123,7 +124,7 @@ pub(crate) fn Component(props: &Properties) -> yew::Html {
<span class="text-body-secondary">{ "· " }{ &item.source }</span>

<div class="float-end">
<span class={ published_class }>{ &published_ago.to_string() }</span>
<span class={ yew::classes!(published_class, "d-none", "d-md-inline") }>{ &published_ago.to_string() }</span>
<span onclick={ toggle_content }>
<super::Svg icon={ caret } size=24 />
</span>
Expand Down
22 changes: 20 additions & 2 deletions front/src/components/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,28 @@ pub(crate) fn Component(props: &Properties) -> yew::Html {
<>
<ul class="list-group">
{
for pager.iterator.iter().map(|item| {
for pager.iterator.iter().map(move |item| {
let action_end = super::swipe::Action {
active: item.favorite,
callback: crate::toggle!(favorite, item, context),
color: "--bs-orange",
icon: "star",
id: item.id.clone(),
};

let action_start = super::swipe::Action {
active: item.read,
callback: crate::toggle!(read, item, context),
color: "--bs-blue",
icon: "eye",
id: item.id.clone(),
};

yew::html! {
<li class="list-group-item">
<crate::components::Item value={ item.clone() } />
<super::Swipe {action_end} {action_start}>
<crate::components::Item value={ item.clone() } />
</super::Swipe>
</li>
}
})
Expand Down
2 changes: 2 additions & 0 deletions front/src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod sidebar;
mod source;
mod sources;
mod svg;
mod swipe;
mod switch;
mod tag;
mod tags;
Expand All @@ -43,6 +44,7 @@ pub(crate) use sidebar::Component as Sidebar;
pub(crate) use source::Component as Source;
pub(crate) use sources::Component as Sources;
pub(crate) use svg::Component as Svg;
pub(crate) use swipe::Component as Swipe;
pub(crate) use switch::Component as Switch;
pub(crate) use tag::Component as Tag;
pub(crate) use tags::Component as Tags;
Expand Down
106 changes: 106 additions & 0 deletions front/src/components/swipe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#[derive(Clone, PartialEq)]
pub struct Action {
pub active: bool,
pub callback: yew::Callback<uuid::Uuid>,
pub color: &'static str,
pub icon: &'static str,
pub id: uuid::Uuid,
}

impl Action {
fn emit(&self) {
self.callback.emit(self.id);
}

fn inactive_icon(&self) -> String {
self.icon.to_string()
}

fn active_icon(&self) -> String {
format!("{}-fill", self.icon)
}

fn view(&self, position: &str) -> yew::Html {
let icon = if self.active {
self.active_icon()
} else {
self.inactive_icon()
};

yew::html! {
<div
class={ yew::classes!("action", position.to_string()) }
style={ format!("color: var({})", self.color) }
>
<super::Svg {icon} size=24 />
</div>
}
}
}

#[derive(Clone, PartialEq, yew::Properties)]
pub(crate) struct Properties {
pub children: yew::Html,
pub action_start: Action,
pub action_end: Action,
}

#[yew::function_component]
pub(crate) fn Component(props: &Properties) -> yew::Html {
let start = yew::use_state(|| 0);
let delta = yew::use_state(|| 0);

let ontouchstart = {
let start = start.clone();

yew::Callback::from(move |e: web_sys::TouchEvent| {
start.set(e.touches().get(0).unwrap().client_x());
})
};

let ontouchmove = {
let delta = delta.clone();

yew::Callback::from(move |e: web_sys::TouchEvent| {
delta.set(e.touches().get(0).unwrap().client_x());
})
};

let ontouchend = {
let delta = delta.clone();
let props = props.clone();
let start = start.clone();

yew::Callback::from(move |e: web_sys::TouchEvent| {
use wasm_bindgen::JsCast as _;

let container = e.target().unwrap().unchecked_into::<web_sys::Element>();
let distance = (*start - *delta) as f32 / container.client_width() as f32;

if distance < -0.5 {
props.action_start.emit();
} else if distance > 0.5 {
props.action_end.emit();
}
})
};

yew::html! {
<>
<div
class="swipe-container"
{ontouchstart}
{ontouchmove}
{ontouchend}
>
{ props.action_start.view("start") }
<div
class="swipe-element"
>
{ props.children.clone() }
</div>
{ props.action_end.view("end") }
</div>
</>
}
}
52 changes: 52 additions & 0 deletions front/static/css/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -321,3 +321,55 @@ li.list-group-item {
}
}

.swipe {
div {
overflow: hidden;
}

& > .action {
height: 100%;
position: absolute;
right: 3px;
top: 3px;
z-index: -1;
}

.favorite {
color: var(--bs-orange);
}
}

@mixin scrollbar-hide() {
-ms-overflow-style: none;
scrollbar-width: none;

&::-webkit-scrollbar {
display: none;
}
}

.swipe-container {
display: flex;
overflow: scroll auto;
scroll-snap-type: x mandatory;
@include scrollbar-hide();

.swipe-element {
scroll-snap-align: start;
min-width: 100%;
}

.action {
min-width: 50%;
display: flex;
align-items: center;

svg {
position: sticky;
}

&.end {
justify-content: flex-end;
}
}
}

0 comments on commit 913647a

Please sign in to comment.