Create product view section
This commit is contained in:
@@ -114,6 +114,7 @@
|
||||
--breakpoint-2xs: 400px;
|
||||
--breakpoint-xs: 480px;
|
||||
|
||||
|
||||
/* ANIMATIONS */
|
||||
--animate-marquee: marquee 3s linear infinite;
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
// types
|
||||
|
||||
import ColorCircle from "~/components/ui/ColorCircle.vue";
|
||||
|
||||
type Props = {
|
||||
colors: string[];
|
||||
selectedColor: string;
|
||||
}
|
||||
|
||||
// props
|
||||
|
||||
defineProps<Props>();
|
||||
|
||||
// emit
|
||||
|
||||
defineEmits(["update:selectedColor"]);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<span>
|
||||
Color : {{ selectedColor}}
|
||||
</span>
|
||||
<div>
|
||||
<ColorCircle
|
||||
v-for="color in colors"
|
||||
:key="color"
|
||||
:color="color"
|
||||
:selected="selectedColor === color"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,20 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-between w-full bg-slate-100 border-[1.5px] border-slate-200 rounded-100 p-6">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="flex p-1 items-center justify-center rounded-full bg-success-500">
|
||||
<Icon name="ci:check" class="size-4 **:stroke-white"/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<span class="typo-label-sm whitespace-nowrap">Pick up from Store</span>
|
||||
<span class="typo-p-sm whitespace-nowrap">Usually ready in 2 hours</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="typo-p-xs">
|
||||
Check availability at other stores
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,58 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
modelValue: number;
|
||||
max: number;
|
||||
}
|
||||
|
||||
// props
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const { modelValue } = toRefs(props);
|
||||
|
||||
// emit
|
||||
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
|
||||
// state
|
||||
|
||||
const currentQuantity = ref(modelValue.value);
|
||||
|
||||
// methods
|
||||
|
||||
const onInput = (e: any) => {
|
||||
currentQuantity.value = Number(e.target.value);
|
||||
};
|
||||
|
||||
// watch
|
||||
|
||||
watch(() => currentQuantity.value, (newValue) => {
|
||||
emit("update:modelValue", newValue);
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="">
|
||||
<NumberFieldRoot
|
||||
class="rounded-full border-slate-200 border-[1.5px] flex items-center bg-white gap-4 p-4"
|
||||
v-model="currentQuantity"
|
||||
:min="1"
|
||||
:max="max"
|
||||
>
|
||||
<NumberFieldIncrement class="cursor-pointer">
|
||||
<Icon name="ci:plus" class="**:stroke-slate-500 size-5" />
|
||||
</NumberFieldIncrement>
|
||||
<NumberFieldInput
|
||||
@input="onInput"
|
||||
class="field-sizing-content bg-transparent outline-none typo-label-md text-black"
|
||||
/>
|
||||
<NumberFieldDecrement class="cursor-pointer">
|
||||
<Icon name="ci:minus" class="**:stroke-slate-500 size-5" />
|
||||
</NumberFieldDecrement>
|
||||
</NumberFieldRoot>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,33 @@
|
||||
<script lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="typo-p-sm">
|
||||
5.0
|
||||
</span>
|
||||
<div class="flex items-center gap-1">
|
||||
<Icon
|
||||
name="ci:star-solid"
|
||||
class="size-4.5 **:fill-yellow-500"
|
||||
/>
|
||||
<Icon
|
||||
name="ci:star-solid"
|
||||
class="size-4.5 **:fill-yellow-500"
|
||||
/>
|
||||
<Icon
|
||||
name="ci:star-solid"
|
||||
class="size-4.5 **:fill-yellow-500"
|
||||
/>
|
||||
<Icon
|
||||
name="ci:star-solid"
|
||||
class="size-4.5 **:fill-yellow-500"
|
||||
/>
|
||||
<Icon
|
||||
name="ci:star-solid"
|
||||
class="size-4.5 **:fill-yellow-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,28 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
quantity: number;
|
||||
}
|
||||
|
||||
// props
|
||||
|
||||
defineProps<Props>();
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-2 w-full items-end">
|
||||
<p class="typo-p-sm text-slate-500">
|
||||
Hurry, only
|
||||
<span class="text-black">
|
||||
{{ quantity }}
|
||||
</span>
|
||||
items left in stock
|
||||
</p>
|
||||
<div class="h-2 rounded-full relative bg-slate-200 w-full">
|
||||
<div class="w-[85%] h-full absolute left-0 rounded-full bg-black" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="flex items-center gap-6">
|
||||
<span class="typo-p-md text-black">
|
||||
Share:
|
||||
</span>
|
||||
<div class="flex items-center gap-3">
|
||||
<NuxtLink>
|
||||
<Icon name="ci:instagram" class="**:stroke-slate-500 size-6" />
|
||||
</NuxtLink>
|
||||
<NuxtLink>
|
||||
<Icon name="ci:facebook" class="**:stroke-slate-500 size-6" />
|
||||
</NuxtLink>
|
||||
<NuxtLink>
|
||||
<Icon name="ci:tiktok" class="**:stroke-slate-500 size-6" />
|
||||
</NuxtLink>
|
||||
<NuxtLink>
|
||||
<Icon name="ci:youtube" class="**:stroke-slate-500 size-6" />
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
@@ -0,0 +1,55 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
// state
|
||||
const quantity = ref(1);
|
||||
const maxQuantity = ref(10);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex gap-12">
|
||||
<div class="w-[800px] flex flex-col items-end gap-3 mt-12">
|
||||
<span class="typo-label-sm">
|
||||
Nova
|
||||
</span>
|
||||
<h1 class="typo-h-2">
|
||||
Nova
|
||||
</h1>
|
||||
<div class="flex w-full items-center justify-between">
|
||||
<Rating />
|
||||
<span class="typo-p-2xl">
|
||||
$689.00
|
||||
</span>
|
||||
</div>
|
||||
<p class="typo-p-md text-slate-500 text-left">
|
||||
Compact, stylish, and engineered for the future, Eco Tunes are more than just headphones; they're a
|
||||
statement. Hear the future, save the planet.
|
||||
</p>
|
||||
<div class="w-full flex flex-col gap-6 mt-4">
|
||||
<RemainQuantity :quantity="maxQuantity" />
|
||||
<div class="w-full flex gap-3 flex-col">
|
||||
<div class="w-full flex gap-3">
|
||||
<Button
|
||||
class="w-full"
|
||||
end-icon="ci:plus"
|
||||
>
|
||||
Add to cart
|
||||
</Button>
|
||||
<QuantityCounter v-model="quantity" :max="maxQuantity" />
|
||||
</div>
|
||||
<Button
|
||||
class="w-full"
|
||||
variant="outlined"
|
||||
>
|
||||
Buy it now
|
||||
</Button>
|
||||
</div>
|
||||
<InfoCard />
|
||||
<Share />
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-red-300 w-full h-[500px] rounded-200">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,3 +1,24 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
color: string;
|
||||
selected ?: boolean;
|
||||
}
|
||||
|
||||
// props
|
||||
|
||||
defineProps<Props>();
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="size-[30px] rounded-full shadow-black/30 shadow-inner"></div>
|
||||
<div
|
||||
class="size-[30px] ring ring-offset-1 rounded-full shadow-black/30 shadow-inner"
|
||||
:class="selected ? 'ring-black' : 'ring-transparent'"
|
||||
:style="{
|
||||
backgroundColor: color,
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProductView />
|
||||
</template>
|
||||
Reference in New Issue
Block a user