update password
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div class="flex flex-col items-center gap-2 text-center">
|
||||
<img
|
||||
src="/brand/welcome-dark.png"
|
||||
alt="خوش آمدید"
|
||||
:class="['dark:hidden', imgClass]"
|
||||
/>
|
||||
<img
|
||||
src="/brand/welcome-lite.png"
|
||||
alt="خوش آمدید"
|
||||
:class="['hidden dark:block', imgClass]"
|
||||
/>
|
||||
<p class="max-w-xs text-sm leading-7 text-muted">
|
||||
نوبت گیری سریع ، مدیرت آسان زمان
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
class?: string;
|
||||
}>(),
|
||||
{},
|
||||
);
|
||||
|
||||
const imgClass = computed(() => props.class ?? 'h-9 w-auto object-contain');
|
||||
</script>
|
||||
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<div class="relative -mx-4 overflow-hidden">
|
||||
<div
|
||||
v-if="images.length"
|
||||
ref="trackRef"
|
||||
class="flex snap-x snap-mandatory overflow-x-auto scroll-smooth"
|
||||
dir="ltr"
|
||||
@scroll.passive="updateActiveIndex"
|
||||
>
|
||||
<img
|
||||
v-for="(src, index) in images"
|
||||
:key="`${src}-${index}`"
|
||||
:src="src"
|
||||
:alt="`${title} — تصویر ${index + 1}`"
|
||||
class="aspect-[4/3] w-full shrink-0 snap-center object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="flex aspect-[4/3] items-center justify-center bg-surface-3 text-muted/40"
|
||||
>
|
||||
<AppIcon name="store" size="lg" />
|
||||
</div>
|
||||
|
||||
<template v-if="images.length > 1">
|
||||
<div
|
||||
class="pointer-events-none absolute inset-x-0 bottom-3 flex justify-center gap-1.5"
|
||||
>
|
||||
<span
|
||||
v-for="(_, index) in images"
|
||||
:key="index"
|
||||
class="h-1.5 rounded-full transition-all"
|
||||
:class="
|
||||
index === activeIndex
|
||||
? 'w-4 bg-white shadow-sm'
|
||||
: 'w-1.5 bg-white/60'
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import AppIcon from '@/components/ui/AppIcon.vue';
|
||||
import { businessGalleryUrls } from '@/utils/media';
|
||||
import type { BusinessImage } from '@/api/types';
|
||||
|
||||
const props = defineProps<{
|
||||
images?: BusinessImage[] | null;
|
||||
title?: string;
|
||||
}>();
|
||||
|
||||
const trackRef = ref<HTMLElement | null>(null);
|
||||
const activeIndex = ref(0);
|
||||
|
||||
const images = computed(() => businessGalleryUrls(props.images));
|
||||
|
||||
function updateActiveIndex() {
|
||||
const track = trackRef.value;
|
||||
if (!track || !images.value.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const width = track.clientWidth;
|
||||
if (!width) {
|
||||
return;
|
||||
}
|
||||
|
||||
activeIndex.value = Math.min(
|
||||
images.value.length - 1,
|
||||
Math.max(0, Math.round(track.scrollLeft / width)),
|
||||
);
|
||||
}
|
||||
|
||||
watch(images, () => {
|
||||
activeIndex.value = 0;
|
||||
if (trackRef.value) {
|
||||
trackRef.value.scrollLeft = 0;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user