Skip to content

Commit c45d6a8

Browse files
feat: add full-size preview modal with magnifying glass button to gallery cards
1 parent 94c250c commit c45d6a8

1 file changed

Lines changed: 63 additions & 14 deletions

File tree

site/src/components/gallery_examples.rs

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ pub struct Example {
1010

1111
#[component]
1212
pub fn GalleryExamples() -> impl IntoView {
13+
let (preview_image, set_preview_image) = signal::<Option<String>>(None);
14+
1315
let examples = vec![
1416
Example {
1517
name: "3D Picking",
@@ -87,31 +89,78 @@ pub fn GalleryExamples() -> impl IntoView {
8789

8890
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
8991
{examples.into_iter().map(|example| {
92+
let screenshot = example.screenshot.to_string();
93+
let screenshot_for_preview = screenshot.clone();
9094
view! {
91-
<a
92-
href=example.path
93-
target="_blank"
94-
rel="noopener noreferrer"
95-
class="block bg-white dark:bg-gray-800 rounded-lg shadow-lg overflow-hidden hover:shadow-xl transition-all hover:scale-105 cursor-pointer flex flex-col"
96-
>
97-
<img
98-
src=example.screenshot
99-
alt=example.name
100-
class="w-full h-48 object-cover"
101-
/>
102-
<div class="p-6 flex-1">
95+
<div class="block bg-white dark:bg-gray-800 rounded-lg shadow-lg overflow-hidden hover:shadow-xl transition-all hover:scale-105 flex flex-col">
96+
<div class="relative">
97+
<a
98+
href=example.path
99+
target="_blank"
100+
rel="noopener noreferrer"
101+
>
102+
<img
103+
src=example.screenshot
104+
alt=example.name
105+
class="w-full h-48 object-contain bg-gray-100 dark:bg-gray-700"
106+
/>
107+
</a>
108+
<button
109+
on:click=move |e| {
110+
e.prevent_default();
111+
e.stop_propagation();
112+
set_preview_image.set(Some(screenshot_for_preview.clone()));
113+
}
114+
class="absolute top-2 right-2 p-2 bg-white dark:bg-gray-700 rounded-full shadow-lg hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors"
115+
title="View full size"
116+
>
117+
<svg class="w-5 h-5 text-gray-700 dark:text-gray-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
118+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM10 7v3m0 0v3m0-3h3m-3 0H7"/>
119+
</svg>
120+
</button>
121+
</div>
122+
<a
123+
href=example.path
124+
target="_blank"
125+
rel="noopener noreferrer"
126+
class="p-6 flex-1 cursor-pointer"
127+
>
103128
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-3">
104129
{example.name}
105130
</h3>
106131
<p class="text-gray-600 dark:text-gray-300">
107132
{example.description}
108133
</p>
109-
</div>
110-
</a>
134+
</a>
135+
</div>
111136
}
112137
}).collect_view()}
113138
</div>
114139
</div>
140+
141+
<Show when=move || preview_image.get().is_some()>
142+
<div
143+
class="fixed inset-0 bg-black bg-opacity-75 z-50 flex items-center justify-center p-4"
144+
on:click=move |_| set_preview_image.set(None)
145+
>
146+
<div
147+
class="relative max-w-7xl max-h-full"
148+
on:click=move |e| e.stop_propagation()
149+
>
150+
<button
151+
on:click=move |_| set_preview_image.set(None)
152+
class="absolute top-4 right-4 text-white hover:text-gray-300 text-4xl font-bold z-10 bg-black bg-opacity-50 rounded-full w-12 h-12 flex items-center justify-center leading-none"
153+
>
154+
"×"
155+
</button>
156+
<img
157+
src=move || preview_image.get().unwrap_or_default()
158+
class="max-w-full max-h-screen object-contain"
159+
alt="Preview"
160+
/>
161+
</div>
162+
</div>
163+
</Show>
115164
</section>
116165
}
117166
}

0 commit comments

Comments
 (0)