Skip to content

Commit 0c02b06

Browse files
committed
feat: redesigned product page
1 parent ddcbdf9 commit 0c02b06

File tree

3 files changed

+53
-35
lines changed

3 files changed

+53
-35
lines changed

gql/queries/getProduct.gql

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,20 @@ query getProduct($slug: ID!, $sku: String!) {
88
salePrice
99
description
1010
image {
11-
sourceUrl(size: WOOCOMMERCE_SINGLE)
11+
sourceUrl(size: LARGE)
1212
}
1313
productTypes {
1414
nodes {
1515
products(where: { sku: $sku }) {
1616
nodes {
1717
slug
1818
image {
19-
sourceUrl(size: THUMBNAIL)
19+
sourceUrl(size: LARGE)
20+
}
21+
allPaColor {
22+
nodes {
23+
name
24+
}
2025
}
2126
}
2227
}

gql/queries/getProducts.gql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ query getProducts($after: String, $search: String, $category: String, $order: Or
1515
}
1616
image {
1717
id
18-
sourceUrl(size: WOOCOMMERCE_SINGLE)
18+
sourceUrl(size: LARGE)
1919
altText
2020
}
2121
galleryImages {
2222
nodes {
23-
sourceUrl(size: WOOCOMMERCE_SINGLE)
23+
sourceUrl(size: LARGE)
2424
}
2525
}
2626
variations(where: { orderby: { field: NAME, order: DESC } }) {

pages/product/[slug].vue

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,53 @@
99
</div>
1010
</div>
1111
<div>
12-
<h1 class="text-2xl">{{ product.name }}</h1>
13-
<div class="flex-col flex">
14-
<div class="flex justify-between flex-row items-baseline">
15-
<div class="flex flex-row items-baseline">
16-
<p class="text-xl font-bold" v-html="product.salePrice"></p>
17-
<p class="text-sm ml-2">VAT included</p>
18-
</div>
12+
<div class="flex-col flex gap-3">
13+
<div>
14+
<h1 class="text-2xl">{{ product.name }}</h1>
1915
</div>
20-
<div class="flex-wrap items-baseline flex-row flex">
21-
<p class="text-sm">Originally:</p>
22-
<p class="text-sm ml-1 line-through" v-html="product.regularPrice"></p>
23-
<p class="text-sm ml-1">{{ calculateDiscountPercentage }}%</p>
16+
<div>
17+
<div class="flex justify-between flex-row items-baseline">
18+
<div class="flex flex-row items-baseline">
19+
<p class="text-xl font-bold" v-html="product.salePrice"></p>
20+
<p class="text-sm ml-2">VAT included</p>
21+
</div>
22+
</div>
23+
<div class="flex-wrap items-baseline flex-row flex">
24+
<p class="text-sm">Originally:</p>
25+
<p class="text-sm ml-1 line-through" v-html="product.regularPrice"></p>
26+
<p class="text-sm ml-1">{{ calculateDiscountPercentage }}%</p>
27+
</div>
2428
</div>
25-
<div v-for="(variation, i) in product.productTypes.nodes" :key="variation.id">
29+
<div class="flex gap-2" v-for="(variation, i) in product.productTypes.nodes" :key="variation.id">
2630
<div v-for="(vars, i) in variation.products.nodes" :key="vars.id">
27-
<NuxtLink :to="`/product/${vars.slug}-${product.sku.split('-')[0]}`"><NuxtImg :src="vars.image.sourceUrl" /></NuxtLink>
31+
<NuxtLink :to="`/product/${vars.slug}-${product.sku.split('-')[0]}`" class="flex w-12">
32+
<div class="">
33+
<NuxtImg :src="vars.image.sourceUrl" :title="vars.allPaColor.nodes[0].name" class="rounded-md" />
34+
</div>
35+
</NuxtLink>
2836
</div>
2937
</div>
30-
<div>Size: {{ selectedVariation }}</div>
31-
<div class="flex gap-2 mt-3 flex-wrap">
32-
<label v-for="(variation, i) in product.variations.nodes" :key="variation.id" :class="[variation.stockStatus === 'OUT_OF_STOCK' ? 'disabled' : '']">
33-
<input
34-
type="radio"
35-
class="hidden"
36-
name="variation"
37-
:checked="i == product.variations.nodes.findIndex((attr) => attr.stockStatus === `IN_STOCK`)"
38-
:value="variation.attributes.nodes.map((attr) => attr.value).toString()"
39-
v-model="selectedVariation"
40-
:disabled="variation.stockStatus === 'OUT_OF_STOCK'" />
41-
<span class="py-1.5 px-2 border rounded leading-[10px] h-6">{{ variation.attributes.nodes.map((attr) => attr.value).toString() }}</span>
42-
</label>
38+
<div>
39+
<div>Size: {{ selectedVariation }}</div>
40+
<div class="flex gap-2 mt-3 flex-wrap">
41+
<label
42+
class="py-1 px-3 border rounded-md"
43+
v-for="variation in product.variations.nodes"
44+
:key="variation.id"
45+
:class="[
46+
variation.stockStatus === 'OUT_OF_STOCK' ? 'disabled' : '',
47+
selectedVariation === variation.attributes.nodes.map((attr) => attr.value).toString() ? 'bg-red-500' : '',
48+
]">
49+
<input
50+
type="radio"
51+
class="hidden"
52+
name="variation"
53+
:value="variation.attributes.nodes.map((attr) => attr.value).toString()"
54+
:disabled="variation.stockStatus === 'OUT_OF_STOCK'"
55+
v-model="selectedVariation" />
56+
<span>{{ variation.attributes.nodes.map((attr) => attr.value).toString() }}</span>
57+
</label>
58+
</div>
4359
</div>
4460
<div v-html="product.description"></div>
4561
</div>
@@ -59,10 +75,10 @@ import { getProduct } from '~/gql/queries/getProduct.gql';
5975
const { result: productResult, loading } = useQuery(getProduct, () => ({ slug: slug, sku: sku }));
6076
const product = computed(() => productResult.value?.product);
6177
62-
let selectedVariation = ref(null);
78+
const selectedVariation = ref(null);
6379
6480
watchEffect(() => {
65-
if (productResult.value?.product && productResult.value?.product.variations && productResult.value?.product.variations.nodes) {
81+
if (productResult.value?.product.variations.nodes) {
6682
const variationInStock = product.value.variations.nodes.find((variation) => variation.stockStatus === 'IN_STOCK');
6783
selectedVariation.value = variationInStock ? variationInStock.attributes.nodes.map((attr) => attr.value).toString() : null;
6884
}
@@ -110,7 +126,4 @@ const calculateDiscountPercentage = computed(() => {
110126
.disabled {
111127
opacity: 0.4;
112128
}
113-
input[type='radio']:checked ~ span {
114-
background-color: #f00;
115-
}
116129
</style>

0 commit comments

Comments
 (0)