fitur fitur darkmode dan foto foto
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<section class="container-page py-10">
|
||||
<RouterLink to="/marketplace" class="mb-6 inline-flex text-sm font-bold text-brand-700">
|
||||
← Kembali ke Marketplace
|
||||
<- Kembali ke Marketplace
|
||||
</RouterLink>
|
||||
|
||||
<div v-if="loading" class="card p-10 text-center">
|
||||
@@ -9,8 +9,23 @@
|
||||
</div>
|
||||
|
||||
<div v-else-if="product" class="grid gap-8 lg:grid-cols-2">
|
||||
<div class="card overflow-hidden">
|
||||
<img :src="getProductImageUrl(product.image)" :alt="product.title" class="aspect-[4/3] w-full object-cover" />
|
||||
<div class="grid gap-4 sm:grid-cols-[88px_1fr]">
|
||||
<div class="order-2 flex gap-3 overflow-x-auto sm:order-1 sm:grid sm:max-h-[520px] sm:overflow-y-auto">
|
||||
<button
|
||||
v-for="(image, index) in productImages"
|
||||
:key="`${image}-${index}`"
|
||||
type="button"
|
||||
class="h-20 w-20 shrink-0 overflow-hidden rounded-xl border-2 bg-white"
|
||||
:class="selectedImage === image ? 'border-brand-600' : 'border-slate-200'"
|
||||
@click="selectedImage = image"
|
||||
>
|
||||
<img :src="getProductImageUrl(image)" :alt="`${product.title} ${index + 1}`" class="h-full w-full object-cover" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="card order-1 overflow-hidden sm:order-2">
|
||||
<img :src="getProductImageUrl(selectedImage)" :alt="product.title" class="aspect-[4/3] w-full object-cover" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -45,7 +60,7 @@
|
||||
</div>
|
||||
|
||||
<div class="mt-8 flex flex-wrap gap-3">
|
||||
<a :href="waLink" target="_blank" class="btn-WA">Hubungi via WhatsApp</a>
|
||||
<a :href="waLink" target="_blank" class="btn-primary">Hubungi via WhatsApp</a>
|
||||
<button class="btn-secondary" @click="toggleSave">
|
||||
{{ saved ? "Hapus dari Tersimpan" : "Simpan Barang" }}
|
||||
</button>
|
||||
@@ -61,7 +76,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from "vue"
|
||||
import { computed, onMounted, ref, watch } from "vue"
|
||||
import { useRoute } from "vue-router"
|
||||
import { products as defaultProducts } from "../data/products"
|
||||
import { fetchProduct, formatRupiah, getProductImageUrl, getSavedProducts, setSavedProducts } from "../utils"
|
||||
@@ -70,6 +85,23 @@ const route = useRoute()
|
||||
const id = Number(route.params.id)
|
||||
const product = ref(null)
|
||||
const loading = ref(true)
|
||||
const selectedImage = ref("")
|
||||
|
||||
const productImages = computed(() => {
|
||||
if (!product.value) return []
|
||||
const images = product.value.images?.length ? product.value.images : [product.value.image]
|
||||
return [...new Set(images.filter(Boolean))]
|
||||
})
|
||||
|
||||
watch(
|
||||
productImages,
|
||||
(images) => {
|
||||
if (!images.includes(selectedImage.value)) {
|
||||
selectedImage.value = images[0] || ""
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
const savedIds = ref(getSavedProducts())
|
||||
const saved = computed(() => savedIds.value.includes(id))
|
||||
@@ -95,7 +127,8 @@ async function loadProduct() {
|
||||
const data = await fetchProduct(id)
|
||||
product.value = data.product
|
||||
} catch {
|
||||
product.value = defaultProducts.find((item) => Number(item.id) === id) || null
|
||||
const fallbackProduct = defaultProducts.find((item) => Number(item.id) === id) || null
|
||||
product.value = fallbackProduct ? { ...fallbackProduct, images: [fallbackProduct.image] } : null
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user