feat: Initial e-commerce setup with core pages
- Initializes a new Nuxt.js 3 project. - Configures Tailwind CSS with custom theme settings. - Creates reusable components for Header, Footer, and ProductCard. - Implements the Homepage, Product Listing, Product Detail, Shopping Cart, and Checkout pages with mock data. - The core e-commerce flow is now in place for further development.
This commit is contained in:
24
ecommerce-app/.gitignore
vendored
Normal file
24
ecommerce-app/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Nuxt dev/build outputs
|
||||
.output
|
||||
.data
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
dist
|
||||
|
||||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.fleet
|
||||
.idea
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
75
ecommerce-app/README.md
Normal file
75
ecommerce-app/README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Nuxt Minimal Starter
|
||||
|
||||
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||
|
||||
## Setup
|
||||
|
||||
Make sure to install dependencies:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm install
|
||||
|
||||
# pnpm
|
||||
pnpm install
|
||||
|
||||
# yarn
|
||||
yarn install
|
||||
|
||||
# bun
|
||||
bun install
|
||||
```
|
||||
|
||||
## Development Server
|
||||
|
||||
Start the development server on `http://localhost:3000`:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run dev
|
||||
|
||||
# pnpm
|
||||
pnpm dev
|
||||
|
||||
# yarn
|
||||
yarn dev
|
||||
|
||||
# bun
|
||||
bun run dev
|
||||
```
|
||||
|
||||
## Production
|
||||
|
||||
Build the application for production:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run build
|
||||
|
||||
# pnpm
|
||||
pnpm build
|
||||
|
||||
# yarn
|
||||
yarn build
|
||||
|
||||
# bun
|
||||
bun run build
|
||||
```
|
||||
|
||||
Locally preview production build:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run preview
|
||||
|
||||
# pnpm
|
||||
pnpm preview
|
||||
|
||||
# yarn
|
||||
yarn preview
|
||||
|
||||
# bun
|
||||
bun run preview
|
||||
```
|
||||
|
||||
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
||||
7
ecommerce-app/app.vue
Normal file
7
ecommerce-app/app.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<Header />
|
||||
<NuxtPage />
|
||||
<Footer />
|
||||
</div>
|
||||
</template>
|
||||
46
ecommerce-app/components/Footer.vue
Normal file
46
ecommerce-app/components/Footer.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<footer class="bg-gray-100 dark:bg-black/20 text-gray-600 dark:text-gray-300">
|
||||
<div class="container mx-auto px-6 lg:px-8 py-12">
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-8">
|
||||
<div>
|
||||
<h3 class="font-bold text-sm text-[#0d111b] dark:text-white mb-4">Customer Service</h3>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li><a class="hover:text-primary" href="#">Contact Us</a></li>
|
||||
<li><a class="hover:text-primary" href="#">Shipping & Returns</a></li>
|
||||
<li><a class="hover:text-primary" href="#">FAQ</a></li>
|
||||
<li><a class="hover:text-primary" href="#">Track Order</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-bold text-sm text-[#0d111b] dark:text-white mb-4">About LUXE</h3>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li><a class="hover:text-primary" href="#">Our Story</a></li>
|
||||
<li><a class="hover:text-primary" href="#">Careers</a></li>
|
||||
<li><a class="hover:text-primary" href="#">Press</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-bold text-sm text-[#0d111b] dark:text-white mb-4">Legal</h3>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li><a class="hover:text-primary" href="#">Terms & Conditions</a></li>
|
||||
<li><a class="hover:text-primary" href="#">Privacy Policy</a></li>
|
||||
<li><a class="hover:text-primary" href="#">Cookie Policy</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-bold text-sm text-[#0d111b] dark:text-white mb-4">Follow Us</h3>
|
||||
<div class="flex space-x-4">
|
||||
<a class="hover:text-primary" href="#"><svg class="h-6 w-6" fill="currentColor" viewbox="0 0 24 24"><path d="M22.46,6C21.69,6.35 20.86,6.58 20,6.69C20.88,6.16 21.56,5.32 21.88,4.31C21.05,4.81 20.13,5.16 19.16,5.36C18.37,4.5 17.26,4 16,4C13.65,4 11.73,5.92 11.73,8.29C11.73,8.63 11.77,8.96 11.84,9.27C8.28,9.09 5.11,7.38 3,4.79C2.63,5.42 2.42,6.16 2.42,6.94C2.42,8.43 3.17,9.75 4.33,10.5C3.62,10.48 2.96,10.26 2.38,9.95C2.38,9.97 2.38,9.98 2.38,10C2.38,12.11 3.86,13.85 5.82,14.24C5.46,14.34 5.08,14.39 4.69,14.39C4.42,14.39 4.15,14.36 3.89,14.31C4.43,16.03 6.02,17.25 7.89,17.29C6.43,18.45 4.58,19.13 2.56,19.13C2.22,19.13 1.88,19.11 1.54,19.07C3.44,20.29 5.7,21 8.12,21C16,21 20.33,14.46 20.33,8.79C20.33,8.6 20.33,8.42 20.32,8.23C21.16,7.63 21.88,6.87 22.46,6Z"></path></svg></a>
|
||||
<a class="hover:text-primary" href="#"><svg class="h-6 w-6" fill="currentColor" viewbox="0 0 24 24"><path d="M12,2.163C15.204,2.163 15.552,2.175 16.705,2.233C17.857,2.291 18.683,2.498 19.46,2.793C20.254,3.1 20.9,3.747 21.207,4.54C21.503,5.327 21.71,6.153 21.767,7.305C21.825,8.457 21.837,8.796 21.837,12C21.837,15.204 21.825,15.552 21.767,16.705C21.71,17.857 21.503,18.683 21.207,19.46C20.9,20.254 20.254,20.9 19.46,21.207C18.683,21.503 17.857,21.71 16.705,21.767C15.552,21.825 15.204,21.837 12,21.837C8.796,21.837 8.448,21.825 7.305,21.767C6.153,21.71 5.327,21.503 4.54,21.207C3.747,20.9 3.1,20.254 2.793,19.46C2.498,18.683 2.291,17.857 2.233,16.705C2.175,15.552 2.163,15.204 2.163,12C2.163,8.796 2.175,8.448 2.233,7.305C2.291,6.153 2.498,5.327 2.793,4.54C3.1,3.747 3.747,3.1 4.54,2.793C5.327,2.498 6.153,2.291 7.305,2.233C8.457,2.175 8.796,2.163 12,2.163M12,0C8.741,0 8.389,0.012 7.211,0.068C6.033,0.124 4.962,0.333 3.996,0.728C2.981,1.139 2.138,1.748 1.353,2.533C0.568,3.318 0.139,4.161 0.728,5.176C0.333,6.142 0.124,7.213 0.068,8.391C0.012,9.569 0,9.921 0,13C0,16.079 0.012,16.431 0.068,17.609C0.124,18.787 0.333,19.858 0.728,20.824C1.139,21.839 1.748,22.682 2.533,23.467C3.318,24.252 4.161,24.681 5.176,25.072C6.142,25.467 7.213,25.676 8.391,25.732C9.569,25.788 9.921,25.8 13,25.8C16.079,25.8 16.431,25.788 17.609,25.732C18.787,25.676 19.858,25.467 20.824,25.072C21.839,24.681 22.682,24.252 23.467,23.467C24.252,22.682 24.681,21.839 25.072,20.824C25.467,19.858 25.676,18.787 25.732,17.609C25.788,16.431 25.8,16.079 25.8,13C25.8,9.921 25.788,9.569 25.732,8.391C25.676,7.213 25.467,6.142 25.072,5.176C24.681,4.161 24.252,3.318 23.467,2.533C22.682,1.748 21.839,1.139 20.824,0.728C19.858,0.333 18.787,0.124 17.609,0.068C16.431,0.012 16.079,0 13,0M13,6.25C9.271,6.25 6.25,9.271 6.25,13C6.25,16.729 9.271,19.75 13,19.75C16.729,19.75 19.75,16.729 19.75,13C19.75,9.271 16.729,6.25 13,6.25M13,17.917C10.28,17.917 8.083,15.72 8.083,13C8.083,10.28 10.28,8.083 13,8.083C15.72,8.083 17.917,10.28 17.917,13C17.917,15.72 15.72,17.917 13,17.917M18.833,6.167C18.204,6.167 17.694,6.676 17.694,7.306C17.694,7.935 18.204,8.444 18.833,8.444C19.463,8.444 19.972,7.935 19.972,7.306C19.972,6.676 19.463,6.167 18.833,6.167"></path></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 dark:border-gray-700 mt-8 pt-6 text-center text-sm">
|
||||
<p>© 2024 LUXE. All Rights Reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
33
ecommerce-app/components/Header.vue
Normal file
33
ecommerce-app/components/Header.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header class="flex items-center justify-between whitespace-nowrap border-b border-solid border-gray-200 dark:border-gray-700 px-6 sm:px-10 lg:px-20 py-4 sticky top-0 bg-background-light/80 dark:bg-background-dark/80 backdrop-blur-sm z-50">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="size-6 text-[#0d111b] dark:text-white">
|
||||
<svg fill="none" viewbox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M36.7273 44C33.9891 44 31.6043 39.8386 30.3636 33.69C29.123 39.8386 26.7382 44 24 44C21.2618 44 18.877 39.8386 17.6364 33.69C16.3957 39.8386 14.0109 44 11.2727 44C7.25611 44 4 35.0457 4 24C4 12.9543 7.25611 4 11.2727 4C14.0109 4 16.3957 8.16144 17.6364 14.31C18.877 8.16144 21.2618 4 24 4C26.7382 4 29.123 8.16144 30.3636 14.31C31.6043 8.16144 33.9891 4 36.7273 4C40.7439 4 44 12.9543 44 24C44 35.0457 40.7439 44 36.7273 44Z" fill="currentColor"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="text-[#0d111b] dark:text-white text-xl font-bold tracking-[-0.015em]">LUXE</h2>
|
||||
</div>
|
||||
<nav class="hidden lg:flex items-center gap-9">
|
||||
<a class="text-sm font-medium hover:text-primary dark:hover:text-primary" href="#">New Arrivals</a>
|
||||
<a class="text-sm font-medium hover:text-primary dark:hover:text-primary" href="#">Designers</a>
|
||||
<a class="text-sm font-medium hover:text-primary dark:hover:text-primary" href="#">Clothing</a>
|
||||
<a class="text-sm font-medium hover:text-primary dark:hover:text-primary" href="#">Accessories</a>
|
||||
<a class="text-sm font-medium hover:text-primary dark:hover:text-primary" href="#">Sale</a>
|
||||
</nav>
|
||||
<div class="flex items-center gap-2">
|
||||
<button class="flex items-center justify-center rounded-full h-10 w-10 hover:bg-gray-200 dark:hover:bg-gray-700">
|
||||
<span class="material-symbols-outlined text-2xl">search</span>
|
||||
</button>
|
||||
<button class="flex items-center justify-center rounded-full h-10 w-10 hover:bg-gray-200 dark:hover:bg-gray-700">
|
||||
<span class="material-symbols-outlined text-2xl">person</span>
|
||||
</button>
|
||||
<button class="flex items-center justify-center rounded-full h-10 w-10 hover:bg-gray-200 dark:hover:bg-gray-700">
|
||||
<span class="material-symbols-outlined text-2xl">shopping_bag</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
23
ecommerce-app/components/ProductCard.vue
Normal file
23
ecommerce-app/components/ProductCard.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
product: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="group relative flex flex-col">
|
||||
<div class="relative w-full overflow-hidden rounded-xl bg-gray-200 dark:bg-gray-800 aspect-square">
|
||||
<img :src="product.image" :alt="product.name" class="h-full w-full object-cover object-center transition-transform duration-300 group-hover:scale-105" />
|
||||
<div class="absolute inset-0 flex items-end justify-center bg-black bg-opacity-0 p-4 opacity-0 transition-opacity duration-300 group-hover:bg-opacity-20 group-hover:opacity-100">
|
||||
<button class="w-full rounded-lg bg-white/90 px-4 py-2 text-sm font-bold text-black backdrop-blur-sm hover:bg-white">Quick View</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 flex flex-col gap-1">
|
||||
<h3 class="text-base font-semibold text-[#0d111b] dark:text-white">{{ product.name }}</h3>
|
||||
<p class="text-base font-medium text-gray-700 dark:text-gray-300">{{ product.price }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
6
ecommerce-app/nuxt.config.ts
Normal file
6
ecommerce-app/nuxt.config.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2025-07-15',
|
||||
devtools: { enabled: true },
|
||||
modules: ['@nuxtjs/tailwindcss']
|
||||
})
|
||||
11304
ecommerce-app/package-lock.json
generated
Normal file
11304
ecommerce-app/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
ecommerce-app/package.json
Normal file
21
ecommerce-app/package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "ecommerce-app",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"nuxt": "^4.2.0",
|
||||
"vue": "^3.5.22",
|
||||
"vue-router": "^4.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||
"@playwright/test": "^1.56.1"
|
||||
}
|
||||
}
|
||||
81
ecommerce-app/pages/cart.vue
Normal file
81
ecommerce-app/pages/cart.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<script setup lang="ts">
|
||||
const cartItems = [
|
||||
{
|
||||
name: 'Minimalist Leather Wallet',
|
||||
price: '$49.99',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuDWrI6RNsR7PE-jrrWMu3jglUrAwOOQzJ5b-icYx2RHGlblHMNvPw8qBKCZvG2CevRs0bAe3GCSZP2uJfVasyNWIjT1EIps42kBTgG-Uq6BKtNCGcpiz6ovCOvuwma3Oc6GCO7MoY-X0-nf81NWencqRIsbsnWexfxrpArYIsRv7c3aYU-wX6DOmNRsxcnFN5s0xkv1RbHl4BFMYAWyVetaqVV97MIkpVQN7TCFbHVMe3BkSuy56niU9_4noARnjY9uPh7DeMHVK2ye',
|
||||
quantity: 1
|
||||
},
|
||||
{
|
||||
name: 'Stainless Steel Watch',
|
||||
price: '$199.00',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuB9uYuSgRdusg0NxIECAIL1u-CRsvfhmGMwKu7SSAoukxPdz8dvrInw21rArVOuY8_ZM64BZBguYO6Uc_uu-7vsxHX_IGeiflSu6LyHzQD6659asPBhVAMrd7txXvdbMNafeqn2kPzSCruJZUqaasNEwtuyJ5xR5XmuFO5vgGhH0sKToP5HA1R-VnHpJ1aXId8xrP4Ay98HPoXwQEpHFw79K1PPKXajmGx-Zqu4vid3r0Lj5shiZfmWvN8OHNeGgFVzjX3S5KCJsq08',
|
||||
quantity: 1
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="px-4 md:px-10 lg:px-20 py-10 lg:py-16">
|
||||
<div class="mx-auto max-w-7xl">
|
||||
<div class="flex flex-col lg:flex-row lg:gap-12">
|
||||
<!-- Left Column: Cart Items -->
|
||||
<div class="w-full lg:w-2/3">
|
||||
<div class="flex flex-wrap justify-between items-baseline gap-3 mb-8">
|
||||
<div class="flex min-w-72 flex-col gap-2">
|
||||
<p class="text-white text-4xl font-black leading-tight tracking-[-0.033em]">Your Bag</p>
|
||||
<p class="text-[#92a0c9] text-base font-normal leading-normal">You have {{ cartItems.length }} items in your bag</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col divide-y divide-white/10">
|
||||
<!-- List Item -->
|
||||
<div v-for="item in cartItems" :key="item.name" class="flex items-center gap-4 bg-transparent py-6 justify-between">
|
||||
<div class="flex items-center gap-4 w-full">
|
||||
<div class="bg-center bg-no-repeat aspect-square bg-cover rounded-lg size-16 shrink-0" :style="{ backgroundImage: `url(${item.image})` }"></div>
|
||||
<div class="flex flex-col justify-center flex-grow">
|
||||
<p class="text-white text-base font-medium leading-normal line-clamp-1">{{ item.name }}</p>
|
||||
<p class="text-[#92a0c9] text-sm font-normal leading-normal line-clamp-2">{{ item.price }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-6">
|
||||
<div class="shrink-0">
|
||||
<div class="flex items-center gap-2 text-white">
|
||||
<button class="text-base font-medium leading-normal flex h-7 w-7 items-center justify-center rounded-full bg-white/10 hover:bg-white/20 transition-colors cursor-pointer">-</button>
|
||||
<input class="text-base font-medium leading-normal w-6 p-0 text-center bg-transparent focus:outline-0 focus:ring-0 focus:border-none border-none [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none" type="number" :value="item.quantity" />
|
||||
<button class="text-base font-medium leading-normal flex h-7 w-7 items-center justify-center rounded-full bg-white/10 hover:bg-white/20 transition-colors cursor-pointer">+</button>
|
||||
</div>
|
||||
</div>
|
||||
<button class="text-[#92a0c9] hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined text-xl">delete</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Right Column: Order Summary -->
|
||||
<div class="w-full lg:w-1/3 mt-10 lg:mt-0">
|
||||
<div class="sticky top-10 bg-white/5 rounded-xl p-6 lg:p-8">
|
||||
<h2 class="text-white text-2xl font-bold leading-tight tracking-[-0.015em] pb-6 border-b border-white/10">Order Summary</h2>
|
||||
<div class="space-y-4 py-6 border-b border-white/10">
|
||||
<div class="flex justify-between text-base">
|
||||
<p class="text-[#92a0c9]">Subtotal</p>
|
||||
<p class="text-white font-medium">$248.99</p>
|
||||
</div>
|
||||
<div class="flex justify-between text-base">
|
||||
<p class="text-[#92a0c9]">Shipping</p>
|
||||
<p class="text-white font-medium">$5.00</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between text-lg font-bold pt-6 pb-8">
|
||||
<p class="text-white">Total</p>
|
||||
<p class="text-white">$253.99</p>
|
||||
</div>
|
||||
<button class="w-full flex items-center justify-center h-12 px-6 bg-primary text-white rounded-lg font-bold text-base hover:bg-primary/90 transition-colors">
|
||||
Proceed to Checkout
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
110
ecommerce-app/pages/checkout.vue
Normal file
110
ecommerce-app/pages/checkout.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<main class="container mx-auto px-4 py-8 md:py-12">
|
||||
<div class="mb-8">
|
||||
<h1 class="text-4xl font-black leading-tight tracking-[-0.033em]">Checkout</h1>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
<div class="lg:col-span-2 space-y-6">
|
||||
<!-- Shipping Information -->
|
||||
<div class="flex flex-col rounded-xl bg-component-light dark:bg-component-dark shadow-sm">
|
||||
<details class="flex flex-col p-6 group" open="">
|
||||
<summary class="flex cursor-pointer list-none items-center justify-between gap-6">
|
||||
<h3 class="text-xl font-semibold">Shipping Information</h3>
|
||||
<div class="text-text-secondary-light dark:text-text-secondary-dark group-open:rotate-180 transition-transform">
|
||||
<span class="material-symbols-outlined">expand_more</span>
|
||||
</div>
|
||||
</summary>
|
||||
<div class="mt-6 grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<label class="flex flex-col col-span-2">
|
||||
<p class="text-sm font-medium pb-2">Full Name</p>
|
||||
<input class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-lg text-text-light dark:text-text-dark focus:outline-0 focus:ring-2 focus:ring-primary/50 border border-border-light dark:border-border-dark bg-background-light dark:bg-background-dark focus:border-primary h-12 placeholder:text-text-secondary-light dark:placeholder:text-text-secondary-dark px-4 text-base font-normal leading-normal" placeholder="Enter your full name" value="" />
|
||||
</label>
|
||||
<label class="flex flex-col col-span-2">
|
||||
<p class="text-sm font-medium pb-2">Address</p>
|
||||
<input class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-lg text-text-light dark:text-text-dark focus:outline-0 focus:ring-2 focus:ring-primary/50 border border-border-light dark:border-border-dark bg-background-light dark:bg-background-dark focus:border-primary h-12 placeholder:text-text-secondary-light dark:placeholder:text-text-secondary-dark px-4 text-base font-normal leading-normal" placeholder="1234 Main St" value="" />
|
||||
</label>
|
||||
<label class="flex flex-col">
|
||||
<p class="text-sm font-medium pb-2">City</p>
|
||||
<input class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-lg text-text-light dark:text-text-dark focus:outline-0 focus:ring-2 focus:ring-primary/50 border border-border-light dark:border-border-dark bg-background-light dark:bg-background-dark focus:border-primary h-12 placeholder:text-text-secondary-light dark:placeholder:text-text-secondary-dark px-4 text-base font-normal leading-normal" placeholder="San Francisco" value="" />
|
||||
</label>
|
||||
<label class="flex flex-col">
|
||||
<p class="text-sm font-medium pb-2">State / Province</p>
|
||||
<input class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-lg text-text-light dark:text-text-dark focus:outline-0 focus:ring-2 focus:ring-primary/50 border border-border-light dark:border-border-dark bg-background-light dark:bg-background-dark focus:border-primary h-12 placeholder:text-text-secondary-light dark:placeholder:text-text-secondary-dark px-4 text-base font-normal leading-normal" placeholder="CA" value="" />
|
||||
</label>
|
||||
<label class="flex flex-col">
|
||||
<p class="text-sm font-medium pb-2">Zip / Postal Code</p>
|
||||
<input class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-lg text-text-light dark:text-text-dark focus:outline-0 focus:ring-2 focus:ring-primary/50 border border-border-light dark:border-border-dark bg-background-light dark:bg-background-dark focus:border-primary h-12 placeholder:text-text-secondary-light dark:placeholder:text-text-secondary-dark px-4 text-base font-normal leading-normal" placeholder="94107" value="" />
|
||||
</label>
|
||||
<label class="flex flex-col">
|
||||
<p class="text-sm font-medium pb-2">Country</p>
|
||||
<input class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-lg text-text-light dark:text-text-dark focus:outline-0 focus:ring-2 focus:ring-primary/50 border border-border-light dark:border-border-dark bg-background-light dark:bg-background-dark focus:border-primary h-12 placeholder:text-text-secondary-light dark:placeholder:text-text-secondary-dark px-4 text-base font-normal leading-normal" placeholder="United States" value="" />
|
||||
</label>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<!-- Payment Method -->
|
||||
<div class="flex flex-col rounded-xl bg-component-light dark:bg-component-dark shadow-sm">
|
||||
<details class="flex flex-col p-6 group">
|
||||
<summary class="flex cursor-pointer list-none items-center justify-between gap-6">
|
||||
<h3 class="text-xl font-semibold">Payment Method</h3>
|
||||
<div class="text-text-secondary-light dark:text-text-secondary-dark group-open:rotate-180 transition-transform">
|
||||
<span class="material-symbols-outlined">expand_more</span>
|
||||
</div>
|
||||
</summary>
|
||||
<p class="text-text-secondary-light dark:text-text-secondary-dark text-sm font-normal leading-normal mt-2">Please enter your payment details below.</p>
|
||||
<!-- Payment options would be added here -->
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Order Summary -->
|
||||
<aside class="lg:col-span-1">
|
||||
<div class="sticky top-28 bg-component-light dark:bg-component-dark p-6 rounded-xl shadow-sm">
|
||||
<h3 class="text-xl font-semibold mb-6">Order Summary</h3>
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-16 h-16 rounded-lg bg-cover bg-center" style="background-image: url('https://lh3.googleusercontent.com/aida-public/AB6AXuB2G4bdtTdqZ5qDnzccbWEkJPyPJWtObX4PMO_KPswJFkA6rRbAadJl_ExWmyTa91TXAMbjlKtjbTiACoSE0ZN4v9HeuUJ2uLPYa6aOTazikKHZN5FLxawOuI0GD7eqDCbsOGnFh98OJjj2H9SN0KBKt-XE7E96Ei2kXWARnpVQ4fVOsRzhfVleasErhkJD4GtjvMYuRu0ntDbZ7g3iPLOnWrqmHhquNGreBgQ3lNlEQRnDZ3s5p1GZ6Uyc7D_L1y-vc9HjlyPVDqR0');"></div>
|
||||
<div class="flex-1">
|
||||
<p class="font-medium">Wireless Headphones</p>
|
||||
<p class="text-sm text-text-secondary-light dark:text-text-secondary-dark">Qty: 1</p>
|
||||
</div>
|
||||
<p class="font-medium">$199.00</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-16 h-16 rounded-lg bg-cover bg-center" style="background-image: url('https://lh3.googleusercontent.com/aida-public/AB6AXuCBLtMIuLHA-oWhz6gFA7EBDEso49y7mlkw9H4LmLJcwakw5mquqjy1UTLg7O8JKkNuc4Rh9Sf27929WDGqSV75umgU3a81WzF6-eoN5DCEXhAhcDVy1c7FlikkgdoWB4ICTFT0IEt-aiTI-ZrN_bUxXZsHeuUAg0f5LGP1CLffcmzr3QI97p6PXNFnJmZg0ZgqDChqhaEFpDps4ZgAdJIb00e7MZ_tolc3nWT2Oryftjt_bMVRjaGW7O3veJH_SsXnA1nqbc3u2PRr');"></div>
|
||||
<div class="flex-1">
|
||||
<p class="font-medium">Minimalist Backpack</p>
|
||||
<p class="text-sm text-text-secondary-light dark:text-text-secondary-dark">Qty: 1</p>
|
||||
</div>
|
||||
<p class="font-medium">$79.99</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-border-light dark:border-border-dark my-6"></div>
|
||||
<div class="space-y-3 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-text-secondary-light dark:text-text-secondary-dark">Subtotal</span>
|
||||
<span>$278.99</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-text-secondary-light dark:text-text-secondary-dark">Shipping</span>
|
||||
<span>$5.00</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-text-secondary-light dark:text-text-secondary-dark">Taxes</span>
|
||||
<span>$22.32</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-border-light dark:border-border-dark my-6"></div>
|
||||
<div class="flex justify-between items-center font-bold text-lg">
|
||||
<span>Total</span>
|
||||
<span>$306.31</span>
|
||||
</div>
|
||||
<button class="w-full mt-8 h-12 bg-primary text-white rounded-lg font-bold text-base hover:bg-primary/90 transition-colors flex items-center justify-center gap-2">
|
||||
<span class="material-symbols-outlined">lock</span>
|
||||
<span>Place Order</span>
|
||||
</button>
|
||||
<p class="text-xs text-center mt-3 text-text-secondary-light dark:text-text-secondary-dark">SSL Secure Transaction</p>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
104
ecommerce-app/pages/index.vue
Normal file
104
ecommerce-app/pages/index.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<script setup lang="ts">
|
||||
import ProductCard from '~/components/ProductCard.vue';
|
||||
|
||||
const recommendedProducts = [
|
||||
{
|
||||
name: 'Silk Blend Blouse',
|
||||
price: '$750',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBjblTsJLCHI19PJ9XgLqLJRZ7B3Wr15qmL7tpIEzeKpQaLAu_mqQXWY6LidttYiT3_IOju3R4rmt9N1bBqr6Fi5QbAgK57bkpgk6yoVA7-W4IIMb2Kn4n7te66s_DU5UOY2OdzRxryhDEC3v-pu8v9TqYUOtz0YgdnvdHmRIs3tyA4fkTZODo4RJ3PCOlNrXiS_RIZUHwab43h048AMa1BG4lvRgYLjKK_UFdscQK3M5017ipZEpQTfACf0DqAGs5twglMKJTSrFRg'
|
||||
},
|
||||
{
|
||||
name: 'Italian Leather Loafers',
|
||||
price: '$920',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuAaYnyFClvQZ-uBClVmEbEpzr8rIdrSYzhGCf11Ur7nEOrX54qawxY_c5P9D5guyQJPfPaWBKbfcTRvciAebQSnHPaiHWUTsqvcbjhCcmDlhdZ9-o7j6PLOFLlAcJDSeBYeDsHvB_HQmxXxGi77sY6q58ATBV_gU-FxeYOUjEXyr67G0J9VnC5159AGn4Ipieq2LghTyyaRoQ0gygLLe7VG6boCmC5ZRzDFRX_RPYHc-STMtdqtBFfDN5a_Y_lG5wcouwtzvgC_DFCu'
|
||||
},
|
||||
{
|
||||
name: 'Cashmere V-Neck Sweater',
|
||||
price: '$1,200',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBkkJtM54APVgqD6I9KZJtB4fB9ZE0dXNTZNvuaoAFfpDrdgSK5FRX_W_vR78f8D1qdtXy-pyxFkH5I0kx2Su6bo1aGHrzbZ5iN6eKEK3NJf1f5CALLBDI05mPGsYPojWp6G4E87gClo57JPhrveAvRjGaYry4NYp84T_CN0v6o9bfPucYGhlBTEa-vCHmsomtEgZyUxGl2wirxlOMgYV54AnjXA7rBoNLhgfI_bNUMPCjr34X7luWt_qgsxD2iZ0TfFdSSe7AkyBvY'
|
||||
},
|
||||
{
|
||||
name: 'Classic Trench Coat',
|
||||
price: '$2,590',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuDObyhLf7WY3GmclLbPdUuHvX_WUxtb3YDCHDh2sxeyiuLk8fzKarVTiISG_zmt84z1I0W2947Q9vh07ehI-vFyaQS0wsbEgMcl3nUXmA8Fw-7R87kqu4hJ1Ndnnyfdmpjuy218OiXFST4gBqH6NHYgN-eIOFO1kbMO9sN8D5iF_oT9XhEmQ1wyfXLw-x4C7ZOYnJ5-k8dSQA6OUWDJ_x0T5nLFeXBTfvAWgHsDme5zK3vig5BRnl4LTlomy_ayZXECN7Lq_OQ0nHGj'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="flex-1">
|
||||
<section class="relative w-full h-[60vh] md:h-[80vh] bg-gray-200 dark:bg-gray-800">
|
||||
<div class="absolute inset-0 bg-cover bg-center" style="background-image: url('https://lh3.googleusercontent.com/aida-public/AB6AXuCOe-mlu0aQheTfR_lYUNpRbWOQ5oh0rMUouR6dJqZqVEpL0aMk1bF6VMtptG9BYNamGmiZQsquVd3-XRA5nX2V9IVpzIC1yZu2l2n7JQVJHiKYbGAXHwudG_S9oE441yRRzuf_FaUFuWI6D5_WtnCOOC4OfvYlwH_LR7pGPPXz-FRd3bRwCxTsK_SehslEl3AA6tW9syNPcDyIAn9xg2MRptXsQcynIuGA0CDMbpkcImQSgB6fzHFP9vteYUB46AVgXsPC4TpzFXkN');"></div>
|
||||
<div class="absolute inset-0 bg-black/30"></div>
|
||||
<div class="relative z-10 flex flex-col items-center justify-center h-full text-center text-white p-4">
|
||||
<h1 class="text-4xl md:text-6xl font-extrabold tracking-tight">The Art of Tailoring</h1>
|
||||
<p class="mt-4 text-lg md:text-xl max-w-2xl">Discover our curated collection of modern suiting and timeless essentials.</p>
|
||||
<button class="mt-8 px-8 py-3 bg-white text-black text-sm font-bold rounded-full hover:bg-gray-200 transition-colors">Shop The Collection</button>
|
||||
</div>
|
||||
</section>
|
||||
<section class="py-12 md:py-20">
|
||||
<div class="container mx-auto px-6 lg:px-8">
|
||||
<div class="flex overflow-x-auto [-ms-scrollbar-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden pb-4">
|
||||
<div class="flex items-stretch gap-4 md:gap-6 flex-shrink-0">
|
||||
<div class="flex h-full flex-1 flex-col gap-4 rounded-lg w-64 md:w-80">
|
||||
<div class="w-full bg-center bg-no-repeat aspect-[4/5] bg-cover rounded-xl" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuC3TinM5AZPGx6wlZKrzayKfmi7OEP4e7J9y3xinMYqqUnop0FHyv9-_7YW2VCgdk638pTc5WyHuSCor0ZQU6zeTHyASMnx5eo3O2AO3I3S_zrUysz13SWp4uc1ycv-W5GT2n92BkLoOYk9L8q1On5PEFhqqPOVafbyIM7r_OPU8IRSKmA_JHch-bE1rExot5lDUZ2fMj91uvQbLaH-0zgYWkvL4jRL0HhiGiiFsdVY7Rg47RTUQjDr-VL3GT4QBiF7AkLnY-Luc9Ch");'></div>
|
||||
<div>
|
||||
<p class="text-base font-medium">The Spring '24 Collection</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">Discover the latest trends</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex h-full flex-1 flex-col gap-4 rounded-lg w-64 md:w-80">
|
||||
<div class="w-full bg-center bg-no-repeat aspect-[4/5] bg-cover rounded-xl" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuBHw26pk-bojJv5yxmIMODqajO5fIUYjs76iPJ6FgZODV8huORP_xfQELDNQYKhEwdEolM3L6szNr0U16TIIGLmlOl-QjaQcbkrZJQqU9ibGvtvDMQlvWZ8e1FtVblOfaqX76HXg_4GoTfssVlqyggXysrbpP7rFB-0eeesn8Uan2PdP3rk6YY8BNodAdp63beIT_J4rGgZfnpvwfohjbrqUm0QEzl2iDu7Hj_zOG2kpxX8nvXtoCdEpVMV19EQ-H0YnQUmO0Uy_RAM");'></div>
|
||||
<div>
|
||||
<p class="text-base font-medium">Timeless Leather Goods</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">Shop now</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex h-full flex-1 flex-col gap-4 rounded-lg w-64 md:w-80">
|
||||
<div class="w-full bg-center bg-no-repeat aspect-[4/5] bg-cover rounded-xl" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuCQL28qlN6Hc9sVOAb3-LiqAp-jFenP7qyV-iCFIhPvsCV2I4pYzsL_n4XOcvGVAk-FWNgxnUCdhfsVtZiLBgVCCoZ2Rpk_HtbsfaAGQY4QrG69uqixW2uPX2P-6XS-gE6D5bmpN-kWNegzJ_NtzZQBDIIimqlk-AFUMgGnIx6twr7A_AweA5ejNj4ZjHRKtV1dAKq3IOD8fYoywJ_N_NgwVVHsOu7X_cKaiRucR1KaId4zNrPR9ScDwNBIICGb1bH6mzj88R-AapG0");'></div>
|
||||
<div>
|
||||
<p class="text-base font-medium">Modern Tailoring</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">Explore the collection</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex h-full flex-1 flex-col gap-4 rounded-lg w-64 md:w-80">
|
||||
<div class="w-full bg-center bg-no-repeat aspect-[4/5] bg-cover rounded-xl" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuBKDVHX7wup54Kz1HPNjbMOWyxPd0iAhvCzS4MAJs7oHv7yolpfag2Mp8RyNjWbFg8TmydXVu4rrWvjUys5wIKCgworkGzgswx_80pR-aBtv8fMmLNglmXpXEuFE4oa7u0IhOPDgIFZshr1Qt-2Uv1CsWZOXyTK-rEcu9OcKsghv3Xrw7P0QOly24TxdYGHdGYz11Xu7HD1RlhwM5Z78163WNREpDaRXh94v3Zmi6FrvWr5otF8V4M4P6c6QNrkab_R5qHpYskDShG9");'></div>
|
||||
<div>
|
||||
<p class="text-base font-medium">Horology Redefined</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">View the selection</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="py-12 md:py-20">
|
||||
<div class="container mx-auto px-6 lg:px-8">
|
||||
<h2 class="text-3xl font-bold tracking-tight px-4 pb-8 text-center">Recommended For You</h2>
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 md:gap-6">
|
||||
<ProductCard v-for="product in recommendedProducts" :key="product.name" :product="product" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="bg-gray-100 dark:bg-black/20 py-16 md:py-24">
|
||||
<div class="container mx-auto px-6 lg:px-8">
|
||||
<div class="@container">
|
||||
<div class="flex flex-col justify-end gap-6 px-4 py-10 @[480px]:gap-8 @[480px]:px-10 @[480px]:py-0">
|
||||
<div class="flex flex-col gap-2 text-center">
|
||||
<h1 class="text-3xl font-bold tracking-tight @[480px]:text-4xl @[480px]:font-black">Join The Inner Circle</h1>
|
||||
<p class="text-base font-normal leading-normal max-w-2xl mx-auto text-gray-600 dark:text-gray-300">Sign up for exclusive access to new collections, events, and sales.</p>
|
||||
</div>
|
||||
<div class="flex justify-center mt-4">
|
||||
<form class="flex w-full max-w-lg">
|
||||
<input class="form-input flex-1 w-full min-w-0 resize-none overflow-hidden rounded-l-full text-[#0d111b] focus:outline-0 focus:ring-2 focus:ring-primary/50 border-gray-300 dark:border-gray-600 dark:bg-background-dark bg-white focus:border-primary/50 h-12 placeholder:text-gray-500 dark:placeholder:text-gray-400 px-6 text-sm" placeholder="Enter your email address" type="email" />
|
||||
<button class="flex items-center justify-center rounded-r-full h-12 px-6 bg-primary text-white text-sm font-bold hover:bg-primary/90 transition-colors">
|
||||
<span>Subscribe</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</template>
|
||||
108
ecommerce-app/pages/products.vue
Normal file
108
ecommerce-app/pages/products.vue
Normal file
@@ -0,0 +1,108 @@
|
||||
<script setup lang="ts">
|
||||
import ProductCard from '~/components/ProductCard.vue';
|
||||
|
||||
const products = [
|
||||
{
|
||||
name: 'Crystal Buckle Heels',
|
||||
price: '$249.00',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuDFgRVLo9r2hiuGgs2Abz_T6QKG9bOi3wc9zsCQDh4YPBMqYZEqAY1hYCrq4uaRMy1-MATzPvgWEfCHTNTik6id4JZQsOSvIuc7iqdOOJ3y2SjL_VSd95VnBnFSdlkhZ3lB7whEYd4JgrGDzMW1DqRcBK2UJAqR7-6RyF3eQZvUxNScqGpUndwdU3eQa-m8zfUaCNa0Oim6p8QVlSsKxEvLdt11LBBZc7s3AJtD0L8s0shyWOQztiC06zBvvNE7q5wTPvGHZxs0QGkw'
|
||||
},
|
||||
{
|
||||
name: 'Aura Running Sneaker',
|
||||
price: '$120.00',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBUsoj7sI3otebpOT1NvFacPi_bAMGK7M3XtgTWHidCzih-2B1hc_KOboRzlmnpqSgX1SRXJOP9gwwGplvwwYNGePtxMYBdtBhoXrIezkhaxS3cmKQ3QzJ8isICLNJR3sz3GqQdPFuBf2uHATljRPogFt7pz9Cep0n-dpyRoGRK46rUz5I3ZlyzKozkthLm192lM0NVLV5b1VeglxznHPBCon4mh991UkMULX76hF-b3MgTVTXwqV7H8PGOSzcGHPRIhXlaGNVjMUzh'
|
||||
},
|
||||
{
|
||||
name: 'Classic Leather Boot',
|
||||
price: '$180.00',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuASYqQ-xv37442xXiKtayimwYtsTwOCVoPrxqaTGCd78jFIKE7g7PJIw_Qqz1jQNLleGS7T3gdD1o7DPDTpHBy8aA6O9R-GMCZGoyEQHEGlXIdo3upRGRjrZvyo6XomAmQc8lNn-ndUbH-ljkWunHJNeA5vAlpdj0IvSIhKPwNJHDof3fTX0kHQtNOX4A6kybAFp6WQsGw1AAIkAYwkKzIvKpxars9A-2oORUY_DqZppwmveUZQqS0_UdDAuWHFsBgPPkU2VDgyfM0M'
|
||||
},
|
||||
{
|
||||
name: 'Essential Leather Flat',
|
||||
price: '$95.00',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuAL2vyOQmOO4bSBIZbGPkf7-mh-KNap_e9mpQqEnBT90u_Jyu0m5sFQmwWUps7suJk4jT1dIT19UB_xcOcjdHrEXPKBkTptuKaiGy5lQOKUZ5u-nOHeGRizo1Y9sinFrq0RB6zimeAJ1hGmBc-ZNa1i3Pcz9LVP6ZZc4YBPBE-ggXMj6WmyBFGsg4NjDEh0Eni4cx8kRGiiUTQHfaNr5l1G2OOvUkCd08Xt4SUjA_heSHqToJRxbUlACq5TSwpGVoKJP31TnLFiBz0_'
|
||||
},
|
||||
{
|
||||
name: 'Retro Runner 95',
|
||||
price: '$145.00',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuC3Y_W0OtGAaWhjNJdTXpe_MYiY-ScEB4UCYIa_s6FO9yzvTZ_7FdrtfbxP3Hmv8w4k9aR01kQidWeAGACUpaqMCvYzIeNnSSqP12y4atL1I2Afk6LLpRZzeooGx68gj5mGyrK_GDjTyozj3uA_QEUzlSLHOppzk_eDBr84UngqCl9pl3uhpUr_A51hHJ07Gj8hQontBjGYWE6IlUDh-h0fcKTFGrYTZplFJ13pzXT6UycWmAVVV8E2gTVrMOqC9IOotVlrDpLf0kpT'
|
||||
},
|
||||
{
|
||||
name: 'Minimalist Sandal',
|
||||
price: '$88.00',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBmi5QsPgRn3vix_w7I69BCImcy3cow7lvsuSD1VftP4jy3qoy5N0JlpvAJ4ed533Tq-scSsaIFX-xdSzUZrNfkhhq_2QzaBbes1c_X5cQ2UgkRoJPpNneOPELvk3QNMRZGPAU3Kqb16A_7JjHkJiFjhwykYzNP6_GBuQK9KZ2Wyh3NkNqk62iDWhbWMfNOe9aJDeeDZtCbo9YfIiRJfhH3_SDA_YzmBFRvq0riET-tEuz0H5meo1vZ7W7TsOSImSEN0AUA5WzmJZtO'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="mx-auto w-full max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
|
||||
<div class="mb-6">
|
||||
<!-- Breadcrumbs -->
|
||||
<div class="flex flex-wrap gap-2 text-sm">
|
||||
<a class="font-medium text-gray-500 dark:text-gray-400 hover:text-primary" href="#">Home</a>
|
||||
<span class="font-medium text-gray-500 dark:text-gray-400">/</span>
|
||||
<a class="font-medium text-gray-500 dark:text-gray-400 hover:text-primary" href="#">Women</a>
|
||||
<span class="font-medium text-gray-500 dark:text-gray-400">/</span>
|
||||
<span class="font-medium text-[#0d111b] dark:text-white">Shoes</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-8 lg:grid-cols-4 lg:gap-12">
|
||||
<!-- Sidebar with Filters -->
|
||||
<aside class="w-full lg:col-span-1">
|
||||
<div class="sticky top-28 space-y-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-xl font-bold text-[#0d111b] dark:text-white">Filters</h3>
|
||||
<button class="text-sm font-medium text-gray-500 dark:text-gray-400 hover:text-primary">Clear All</button>
|
||||
</div>
|
||||
<!-- Category Filter -->
|
||||
<div class="space-y-4 border-t border-gray-200 dark:border-gray-700 pt-6">
|
||||
<h4 class="font-semibold text-[#0d111b] dark:text-white">Category</h4>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li><a class="text-gray-600 dark:text-gray-300 hover:text-primary" href="#">Sneakers</a></li>
|
||||
<li><a class="text-gray-600 dark:text-gray-300 hover:text-primary" href="#">Heels</a></li>
|
||||
<li><a class="text-gray-600 dark:text-gray-300 hover:text-primary" href="#">Boots</a></li>
|
||||
<li><a class="text-gray-600 dark:text-gray-300 hover:text-primary" href="#">Flats</a></li>
|
||||
<li><a class="text-gray-600 dark:text-gray-300 hover:text-primary" href="#">Sandals</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Price Filter -->
|
||||
<div class="space-y-4 border-t border-gray-200 dark:border-gray-700 pt-6">
|
||||
<h4 class="font-semibold text-[#0d111b] dark:text-white">Price Range</h4>
|
||||
<div class="flex items-center gap-2">
|
||||
<input class="w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-lg appearance-none cursor-pointer accent-primary" max="500" min="0" type="range" value="75" />
|
||||
</div>
|
||||
<div class="flex justify-between text-sm text-gray-500 dark:text-gray-400">
|
||||
<span>$0</span>
|
||||
<span>$500+</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<!-- Product Grid -->
|
||||
<div class="w-full lg:col-span-3">
|
||||
<div class="flex flex-col gap-6">
|
||||
<div class="flex flex-wrap items-center justify-between gap-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
<!-- Page Heading -->
|
||||
<h1 class="text-3xl font-black leading-tight tracking-[-0.033em] text-[#0d111b] dark:text-white sm:text-4xl">Women's Shoes</h1>
|
||||
<!-- Meta Text -->
|
||||
<p class="text-sm font-normal leading-normal text-gray-500 dark:text-gray-400">Showing 1-12 of 128 results</p>
|
||||
</div>
|
||||
<!-- Chips for Sorting -->
|
||||
<div class="flex gap-3">
|
||||
<button class="flex h-10 shrink-0 items-center justify-center gap-x-2 rounded-lg bg-gray-200/60 dark:bg-gray-800/60 pl-4 pr-3 text-[#0d111b] dark:text-white hover:bg-gray-200 dark:hover:bg-gray-800">
|
||||
<p class="text-sm font-medium leading-normal">Sort by: Relevance</p>
|
||||
<span class="material-symbols-outlined">expand_more</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Product Grid Container -->
|
||||
<div class="grid grid-cols-1 gap-x-6 gap-y-10 sm:grid-cols-2 xl:grid-cols-3">
|
||||
<ProductCard v-for="product in products" :key="product.name" :product="product" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
103
ecommerce-app/pages/products/[id].vue
Normal file
103
ecommerce-app/pages/products/[id].vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<script setup lang="ts">
|
||||
const product = {
|
||||
name: 'Classic Linen Shirt',
|
||||
price: '$120.00',
|
||||
description: 'A timeless piece for effortless style and comfort. Made from 100% organic linen.',
|
||||
images: [
|
||||
'https://lh3.googleusercontent.com/aida-public/AB6AXuDPG8HMlTi71oTQGS8YElm7L_VOTb_WQF33iXN7yUylFJg_liNba2q1UCKxgE4vZgMyjhMRuj1KAxkd11WLV0DDOzsff8MX9ZynecSbdKfyoG8CLr4miyYER5TFvGcFull0guSbkzIy29XMoaT-WvOgghMfAw5qiBI_U9UMRX90tZhP3OKnSWsNfARMW8p0J8XNHqytdMXeaXJ389HX71jGNObzdGcJPmujtP_d0-khGJeOS0gs8q8ql8Ek67re5XJHcYwGZvKV4GIK',
|
||||
'https://lh3.googleusercontent.com/aida-public/AB6AXuBTteXYnnHtsiQikS2Ge0IKwDkSRAE_rHhLLfK-hM3HHcfazGMYy51Nk15hipVPcIUlbTQgiAjnGPaADnqsdkugTua50xJBoyBR6si-Rm4xnuiJ31Y2mvgswIZkpevlmseklZNeRd_v7HROM99e1iQiD8ABsU5bSNWAsjF2zIeXAJC7jsgAF25zD9WFUKPJ3Ax6D0eJMhzZrUwgNAS9HF9VNsFnkjX-8Ps2Kbz1BG-Uc_5o5imNBkrK2xx82VVOgVsQyTK6TMXklxu1',
|
||||
'https://lh3.googleusercontent.com/aida-public/AB6AXuBet_zS-tDq88uVaFtfKw3abVNwIzXwFQjGyTpQlRmW_ELi-QmCjzofaIyVyphYsLokQ7kQHNmQlySMj52fkBJld0SAzzV3zZpMU4bOLsPipkJHC33yHxmTph0ERlnsCYeiByxscemfq6X6h4Y3nEgdvnel-MAB8RsH1_9mb-I_yC6kkhRyMIWo3_9bmlw4FTgh-R2C1GdwcVY-WKvYK_3-D64WuLTUL0eedHwQ9Qj5OD5ffFVVgMGEy8bxqaeMnoieSPNM6LuI4Cpr',
|
||||
'https://lh3.googleusercontent.com/aida-public/AB6AXuBAMDn8hJO2oJj6v5vW8FpdPF1rVFjqCZa-pyCYukUMwglUThiRKtzqjzKraKZ6WQ0xmvpEaBPQJ_NforaomufafGDrILkSHVlefDEIuzUyW2uzKcPXpoJR0D_N1DCFKGl0U07XgwRQT_2JEeHOHrv7EGORH-T2AqUYsLJAWYEkE7YIYQtNfL9coAZTOy49Ea1QrFnjdG1M5Xqm-VEPGXoLWZUkHaSVUvnaQDGnJef87O77sduxperJ69BKBsAosTRqMrdZ5z9jnRlY'
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="flex-1 px-4 sm:px-10 lg:px-20 xl:px-40 py-5">
|
||||
<div class="layout-content-container mx-auto flex w-full max-w-7xl flex-col flex-1">
|
||||
<!-- Breadcrumbs Component -->
|
||||
<div class="flex flex-wrap gap-2 p-4">
|
||||
<a class="text-gray-500 dark:text-gray-400 text-sm font-medium leading-normal" href="#">Home</a>
|
||||
<span class="text-gray-500 dark:text-gray-400 text-sm font-medium leading-normal">/</span>
|
||||
<a class="text-gray-500 dark:text-gray-400 text-sm font-medium leading-normal" href="#">Apparel</a>
|
||||
<span class="text-gray-500 dark:text-gray-400 text-sm font-medium leading-normal">/</span>
|
||||
<span class="text-[#0d111b] dark:text-white text-sm font-medium leading-normal">{{ product.name }}</span>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-12 mt-6">
|
||||
<!-- Left Column: Image Gallery -->
|
||||
<div class="flex flex-col gap-4">
|
||||
<!-- Images Component -->
|
||||
<div class="w-full h-auto aspect-[4/5] rounded-xl overflow-hidden">
|
||||
<div class="w-full h-full bg-center bg-no-repeat bg-cover" :style="{ backgroundImage: `url(${product.images[0]})` }"></div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<div v-for="(image, index) in product.images" :key="index" class="w-full cursor-pointer aspect-square rounded-lg overflow-hidden" :class="{ 'border-2 border-primary': index === 0 }">
|
||||
<div class="w-full h-full bg-center bg-no-repeat bg-cover" :style="{ backgroundImage: `url(${image})` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Right Column: Product Information -->
|
||||
<div class="flex flex-col p-4">
|
||||
<!-- PageHeading Component -->
|
||||
<div class="flex flex-wrap justify-between gap-3">
|
||||
<div class="flex flex-col gap-3">
|
||||
<p class="text-[#0d111b] dark:text-white text-4xl font-black leading-tight tracking-[-0.033em]">{{ product.name }}</p>
|
||||
<p class="text-gray-600 dark:text-gray-300 text-base font-normal leading-normal">{{ product.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Rating -->
|
||||
<div class="flex items-center gap-2 mt-4">
|
||||
<div class="flex items-center text-yellow-500">
|
||||
<span class="material-symbols-outlined !text-lg" style="font-variation-settings: 'FILL' 1;">star</span>
|
||||
<span class="material-symbols-outlined !text-lg" style="font-variation-settings: 'FILL' 1;">star</span>
|
||||
<span class="material-symbols-outlined !text-lg" style="font-variation-settings: 'FILL' 1;">star</span>
|
||||
<span class="material-symbols-outlined !text-lg" style="font-variation-settings: 'FILL' 1;">star</span>
|
||||
<span class="material-symbols-outlined !text-lg">star</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">(121 reviews)</p>
|
||||
</div>
|
||||
<!-- TitleText (Price) Component -->
|
||||
<h1 class="text-[#0d111b] dark:text-white text-[28px] font-bold leading-tight tracking-[-0.015em] text-left pb-3 pt-5">{{ product.price }}</h1>
|
||||
<div class="border-t border-gray-200 dark:border-gray-800 my-6"></div>
|
||||
<!-- Variant Selectors -->
|
||||
<div class="flex flex-col gap-6">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#0d111b] dark:text-white">Color</label>
|
||||
<div class="flex items-center gap-3 mt-2">
|
||||
<button class="size-8 rounded-full bg-white border-2 border-primary ring-2 ring-offset-2 ring-primary dark:ring-offset-background-dark"></button>
|
||||
<button class="size-8 rounded-full bg-black border-2 border-transparent"></button>
|
||||
<button class="size-8 rounded-full bg-blue-900 border-2 border-transparent"></button>
|
||||
<button class="size-8 rounded-full bg-gray-300 border-2 border-transparent"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm font-medium text-[#0d111b] dark:text-white">Size</label>
|
||||
<div class="flex items-center gap-3 mt-2">
|
||||
<button class="flex items-center justify-center px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-700 bg-transparent text-[#0d111b] dark:text-white text-sm">XS</button>
|
||||
<button class="flex items-center justify-center px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-700 bg-transparent text-[#0d111b] dark:text-white text-sm">S</button>
|
||||
<button class="flex items-center justify-center px-4 py-2 rounded-lg border border-primary bg-primary/20 text-primary text-sm font-bold">M</button>
|
||||
<button class="flex items-center justify-center px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-700 bg-transparent text-[#0d111b] dark:text-white text-sm">L</button>
|
||||
<button class="flex items-center justify-center px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-700 bg-transparent text-[#0d111b] dark:text-white text-sm">XL</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 dark:border-gray-800 my-6"></div>
|
||||
<!-- Quantity & CTA -->
|
||||
<div class="flex items-center gap-4 mt-2">
|
||||
<div class="flex items-center border border-gray-300 dark:border-gray-700 rounded-lg">
|
||||
<button class="px-3 py-2 text-gray-500 dark:text-gray-400"><span class="material-symbols-outlined">remove</span></button>
|
||||
<span class="px-4 text-lg font-semibold">1</span>
|
||||
<button class="px-3 py-2 text-gray-500 dark:text-gray-400"><span class="material-symbols-outlined">add</span></button>
|
||||
</div>
|
||||
<button class="flex-1 flex items-center justify-center h-12 px-6 bg-primary text-white rounded-lg text-base font-bold shadow-sm hover:bg-primary/90 transition-colors">
|
||||
Add to Cart
|
||||
</button>
|
||||
<button class="flex items-center justify-center size-12 border border-gray-300 dark:border-gray-700 rounded-lg text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
|
||||
<span class="material-symbols-outlined">favorite</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
5
ecommerce-app/playwright.config.ts
Normal file
5
ecommerce-app/playwright.config.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { defineConfig } from '@playwright/test';
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './tests',
|
||||
});
|
||||
BIN
ecommerce-app/public/favicon.ico
Normal file
BIN
ecommerce-app/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
2
ecommerce-app/public/robots.txt
Normal file
2
ecommerce-app/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-Agent: *
|
||||
Disallow:
|
||||
31
ecommerce-app/tailwind.config.js
Normal file
31
ecommerce-app/tailwind.config.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./components/**/*.{js,vue,ts}",
|
||||
"./layouts/**/*.vue",
|
||||
"./pages/**/*.vue",
|
||||
"./plugins/**/*.{js,ts}",
|
||||
"./nuxt.config.{js,ts}",
|
||||
"./app.vue",
|
||||
],
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#1142d4",
|
||||
"background-light": "#f6f6f8",
|
||||
"background-dark": "#101522",
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Manrope", "sans-serif"]
|
||||
},
|
||||
borderRadius: {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
15
ecommerce-app/tests/homepage.spec.ts
Normal file
15
ecommerce-app/tests/homepage.spec.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('homepage has a header and footer', async ({ page }) => {
|
||||
await page.goto('http://localhost:3000/');
|
||||
|
||||
// Check for the header
|
||||
await expect(page.locator('header')).toBeVisible();
|
||||
await expect(page.getByText('LUXE')).toBeVisible();
|
||||
|
||||
// Check for the footer
|
||||
await expect(page.locator('footer')).toBeVisible();
|
||||
|
||||
// Take a screenshot to visually verify the page
|
||||
await page.screenshot({ path: 'homepage.png' });
|
||||
});
|
||||
18
ecommerce-app/tsconfig.json
Normal file
18
ecommerce-app/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.server.json"
|
||||
},
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.shared.json"
|
||||
},
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
4
test-results/.last-run.json
Normal file
4
test-results/.last-run.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"status": "failed",
|
||||
"failedTests": []
|
||||
}
|
||||
Reference in New Issue
Block a user