Skip to content

Commit f80bba2

Browse files
committed
fix: Fix incorrect viewport responsive value
1 parent ffa2e47 commit f80bba2

2 files changed

Lines changed: 98 additions & 41 deletions

File tree

app/assets/styles/scss/variables/responsive.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
$responsive-small-mobile: 21.25em; // 340px
88
$responsive-standard-mobile: 24.375em; // 390px
9-
$responsive-large-mobile: 28.125rem; // 450px
9+
$responsive-large-mobile: 28.125em; // 450px
1010
$responsive-small-tablet: 40em; // 640px
1111
$responsive-standard-tablet: 48em; // 768px
1212
$responsive-large-tablet: 62.5em; // 1000px
Lines changed: 97 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div class="container">
3-
<ul v-once class="project-feed">
3+
<ul class="project-feed">
44
<li
55
v-for="(project, index) in list"
66
:key="project.name"
@@ -20,29 +20,46 @@
2020
:target="project.url?.startsWith('http') ? '_blank' : undefined"
2121
class="project-row__link"
2222
>
23-
<h3 class="project-row__title">{{ project.name }}</h3>
23+
<component :is="headingLevel" class="project-row__title">{{ project.name }}</component>
2424
</component>
2525
</div>
2626

2727
<p class="project-row__description">{{ project.description }}</p>
2828
</div>
2929

3030
<div v-if="project.image" class="lightbox">
31-
<input :id="`zoom-${index}`" type="checkbox" class="lightbox__toggle" aria-label="Open preview" />
32-
<label :for="`zoom-${index}`" class="lightbox__trigger">
31+
<button
32+
class="lightbox__trigger"
33+
:aria-label="`Open ${project.name} preview`"
34+
@click="openLightbox(project)"
35+
>
3336
<img
3437
:src="project.image"
3538
:alt="`${project.name} preview`"
3639
class="thumb"
37-
:loading="index <= props.preloadProjectImages ? 'eager' : 'lazy'"
40+
:loading="index < props.preloadProjectImages ? 'eager' : 'lazy'"
3841
/>
39-
</label>
40-
<label :for="`zoom-${index}`" class="lightbox__overlay">
41-
<img :src="project.image" alt="" class="full-view" />
42-
</label>
42+
</button>
4343
</div>
4444
</li>
4545
</ul>
46+
47+
<dialog
48+
ref="dialogEl"
49+
class="lightbox-dialog"
50+
aria-label="Project image preview"
51+
@click.self="closeLightbox"
52+
>
53+
<button class="lightbox-dialog__close" aria-label="Close preview" @click="closeLightbox">
54+
<span aria-hidden="true">&times;</span>
55+
</button>
56+
<img
57+
v-if="activeProject"
58+
:src="activeProject.image"
59+
:alt="`${activeProject.name} preview`"
60+
class="lightbox-dialog__img"
61+
/>
62+
</dialog>
4663
</div>
4764
</template>
4865

@@ -58,9 +75,31 @@ interface Project {
5875
const props = withDefaults(defineProps<{
5976
limit?: number;
6077
preloadProjectImages?: number;
78+
headingLevel?: 'h2' | 'h3';
6179
}>(), {
6280
limit: undefined,
63-
preloadProjectImages: 0
81+
preloadProjectImages: 0,
82+
headingLevel: 'h2'
83+
})
84+
85+
const dialogEl = ref<HTMLDialogElement | null>(null)
86+
const activeProject = ref<Project | null>(null)
87+
88+
function openLightbox(project: Project): void {
89+
activeProject.value = project
90+
nextTick(() => {
91+
dialogEl.value?.showModal()
92+
})
93+
}
94+
95+
function closeLightbox(): void {
96+
dialogEl.value?.close()
97+
}
98+
99+
onMounted(() => {
100+
dialogEl.value?.addEventListener('close', () => {
101+
activeProject.value = null
102+
})
64103
})
65104
66105
const projects: Project[] = [{
@@ -248,14 +287,16 @@ $row-padding-h: 1rem;
248287
249288
.lightbox {
250289
flex-shrink: 0;
251-
252-
&__toggle { display: none; }
253290
254291
&__trigger {
255292
display: block;
256293
width: 8.875rem;
257294
height: 5rem;
258295
cursor: zoom-in;
296+
padding: 0;
297+
background: none;
298+
border: none;
299+
259300
@media (min-width: $responsive-standard-tablet) { width: 11.125rem; height: 6.25rem; }
260301
261302
.thumb {
@@ -264,39 +305,55 @@ $row-padding-h: 1rem;
264305
object-fit: cover;
265306
border-radius: 0.25rem;
266307
border: 1px solid var(--color-fg1);
267-
transition: transform 0.2s ease, opacity 0.3s ease, filter 0.3s ease;
268-
&:hover { transform: scale(1.02); }
308+
309+
@media (prefers-reduced-motion: no-preference) {
310+
transition: transform 0.2s ease, opacity 0.3s ease, filter 0.3s ease;
311+
&:hover { transform: scale(1.02); }
312+
}
269313
}
270314
}
315+
}
271316
272-
&__overlay {
273-
position: fixed;
274-
inset: 0;
275-
background: rgba(0, 0, 0, 0.92);
276-
display: flex;
277-
align-items: center;
278-
justify-content: center;
279-
z-index: 10000;
280-
cursor: zoom-out;
281-
opacity: 0;
282-
pointer-events: none;
283-
transition: opacity 0.2s ease;
284-
padding: 1.5rem;
285-
286-
.full-view {
287-
max-width: 100%;
288-
max-height: 100%;
289-
border-radius: 0.25rem;
290-
transform: scale(0.98);
291-
transition: transform 0.2s ease;
292-
filter: none !important;
317+
.lightbox-dialog {
318+
padding: 0;
319+
background: rgba(0, 0, 0, 0.92);
320+
border: none;
321+
border-radius: 0.5rem;
322+
max-width: min(90vw, 72rem);
323+
max-height: 90vh;
324+
width: fit-content;
325+
326+
&::backdrop {
327+
background: rgba(0, 0, 0, 0.75);
328+
}
329+
330+
&__close {
331+
position: absolute;
332+
top: 0.75rem;
333+
right: 0.75rem;
334+
background: rgba(255, 255, 255, 0.15);
335+
border: 1px solid rgba(255, 255, 255, 0.4);
336+
color: #fff;
337+
border-radius: 50%;
338+
width: 2.25rem;
339+
height: 2.25rem;
340+
font-size: 1.5rem;
341+
line-height: 1;
342+
cursor: pointer;
343+
display: grid;
344+
place-items: center;
345+
346+
&:hover,
347+
&:focus {
348+
background: rgba(255, 255, 255, 0.3);
293349
}
294350
}
295351
296-
&__toggle:checked ~ &__overlay {
297-
opacity: 1;
298-
pointer-events: auto;
299-
.full-view { transform: scale(1); }
352+
&__img {
353+
display: block;
354+
max-width: 100%;
355+
max-height: 90vh;
356+
border-radius: 0.5rem;
300357
}
301358
}
302-
</style>
359+
</style>

0 commit comments

Comments
 (0)