New Initial Commit
This commit is contained in:
@@ -0,0 +1,321 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Shopping Cart')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
h1 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2.5rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.cart-container {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr;
|
||||
gap: 2rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.cart-items {
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.empty-cart {
|
||||
text-align: center;
|
||||
padding: 3rem 2rem;
|
||||
}
|
||||
|
||||
.empty-cart p {
|
||||
color: #666;
|
||||
margin-bottom: 2rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
display: grid;
|
||||
grid-template-columns: 120px 1fr auto;
|
||||
gap: 2rem;
|
||||
padding: 1.5rem 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cart-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.item-details h3 {
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 0.5rem;
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
}
|
||||
|
||||
.item-details p {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.item-price {
|
||||
font-weight: 600;
|
||||
color: var(--primary-color);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.item-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.quantity-form {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.quantity-form input {
|
||||
width: 60px;
|
||||
padding: 0.4rem;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.quantity-form button {
|
||||
background-color: black;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.4rem 0.8rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.quantity-form button:hover {
|
||||
background-color: #1f3633;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.summary {
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.summary h2 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 1.5rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.summary-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.summary-row.total {
|
||||
font-family: Abril Fatface;
|
||||
font-weight: 400;
|
||||
font-size: 2rem;
|
||||
color: var(--primary-color);
|
||||
border-top: 2px solid var(--primary-color);
|
||||
border-bottom: none;
|
||||
padding-top: 1.5rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.summary-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background-color: white;
|
||||
color: black;
|
||||
font-size: 0.9rem;
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background-color: #c09191;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 1rem;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #d4e8d4;
|
||||
color: var(--primary-color);
|
||||
border: 1px solid #a8d4a8;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
background-color: #d1ecf1;
|
||||
color: #0c5460;
|
||||
border: 1px solid #bee5eb;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.cart-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
grid-template-columns: 80px 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.item-actions {
|
||||
grid-column: 1 / -1;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<main class="container">
|
||||
<h1>Shopping Cart</h1>
|
||||
|
||||
@if (session('success'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (session('error'))
|
||||
<div class="alert alert-info">
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(count($items) > 0)
|
||||
<div class="cart-container">
|
||||
<!-- Cart Items -->
|
||||
<div class="cart-items">
|
||||
@foreach($items as $item)
|
||||
<div class="cart-item">
|
||||
@if($item['product']->images->count() > 0)
|
||||
<img src="{{ asset('storage/' . $item['product']->images->first()->image_path) }}" alt="{{ $item['product']->name }}" class="item-image">
|
||||
@else
|
||||
<img src="{{ $item['product']->image }}" alt="{{ $item['product']->name }}" class="item-image">
|
||||
@endif
|
||||
|
||||
<div class="item-details">
|
||||
<h3>{{ $item['product']->name }}</h3>
|
||||
<p>{{ $item['product']->category->name }}</p>
|
||||
|
||||
@php
|
||||
$stockCost = 0;
|
||||
$stockUnit = $item['type'] === 'wallpaper' ? '/m' : '/m²';
|
||||
|
||||
if ($item['stock']) {
|
||||
$stockCost = $item['type'] === 'wallpaper' ? $item['stock']->cost_per_meter : $item['stock']->cost_per_m2;
|
||||
}
|
||||
@endphp
|
||||
|
||||
@if($item['stock'])
|
||||
<p style="font-size: 0.9rem; color: #666;">
|
||||
{{ $item['stock']->name }}: <span class="item-price">R{{ number_format($stockCost, 2) }}{{ $stockUnit }}</span>
|
||||
</p>
|
||||
@endif
|
||||
|
||||
@if($item['type'] === 'wallpaper')
|
||||
<p style="color: #666; font-size: 0.9rem;">Length: {{ $item['length'] }}m</p>
|
||||
@elseif($item['type'] === 'mural')
|
||||
<p style="color: #666; font-size: 0.9rem;">Dimensions: {{ $item['width'] }}m × {{ $item['height'] }}m ({{ number_format($item['width'] * $item['height'], 2) }}m²)</p>
|
||||
@endif
|
||||
|
||||
<p style="color: var(--primary-color); font-weight: 600;">Subtotal: R{{ number_format($item['subtotal'], 2) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="item-actions">
|
||||
<!-- <form action="{{ route('cart-update') }}" method="POST" class="quantity-form">
|
||||
@csrf
|
||||
<input type="hidden" name="item_key" value="{{ $item['key'] }}">
|
||||
<input type="number" name="quantity" min="1" value="{{ $item['quantity'] }}">
|
||||
<button type="submit">Update</button>
|
||||
</form> -->
|
||||
|
||||
<form action="{{ route('cart-remove') }}" method="POST" style="margin-top: 0.5rem;">
|
||||
@csrf
|
||||
<input type="hidden" name="item_key" value="{{ $item['key'] }}">
|
||||
<button type="submit" class="btn btn-danger">Remove</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<!-- Summary -->
|
||||
<div class="summary">
|
||||
<h2>Order Summary</h2>
|
||||
|
||||
<div class="summary-row">
|
||||
<span>Subtotal:</span>
|
||||
<span>R{{ number_format($total, 2) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="summary-row">
|
||||
<span>Shipping:</span>
|
||||
<span>Free</span>
|
||||
</div>
|
||||
|
||||
<div class="summary-row">
|
||||
<span>Tax:</span>
|
||||
<span>TBD</span>
|
||||
</div>
|
||||
|
||||
<div class="summary-row total">
|
||||
<span>Total:</span>
|
||||
<span>R {{ number_format($total, 2) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="summary-actions">
|
||||
<a href="{{ route('checkout') }}" class="btn" style="text-decoration: none;">Proceed to Checkout</a>
|
||||
<a href="{{ route('wallpapers') }}" class="btn btn--secondary">Continue Shopping</a>
|
||||
</div>
|
||||
|
||||
<form action="{{ route('cart-clear') }}" method="POST" style="margin-top: 1rem;">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-danger" style="width: 100%;">Clear Cart</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="empty-cart">
|
||||
<p>Your cart is empty</p>
|
||||
<a href="{{ route('wallpapers') }}" class="btn">Start Shopping</a>
|
||||
</div>
|
||||
@endif
|
||||
</main>
|
||||
@endsection
|
||||
@@ -0,0 +1,293 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Checkout - Additional Design')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
h1 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2.5rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.checkout-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3rem;
|
||||
margin: 2rem 0 3rem 0;
|
||||
}
|
||||
|
||||
.checkout-form,
|
||||
.order-summary {
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.checkout-form h2,
|
||||
.order-summary h2 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 1.5rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group textarea {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
resize: vertical;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 3px rgba(45, 80, 71, 0.1);
|
||||
}
|
||||
|
||||
.order-summary {
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.order-item {
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.order-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.order-item-name {
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.order-item-details {
|
||||
font-size: 0.85rem;
|
||||
color: #666;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.order-item-price {
|
||||
text-align: right;
|
||||
font-weight: 600;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.summary-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.summary-row.total {
|
||||
font-weight: 600;
|
||||
font-size: 1.2rem;
|
||||
color: var(--primary-color);
|
||||
border-top: 2px solid var(--primary-color);
|
||||
border-bottom: none;
|
||||
padding-top: 1.5rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
width: 100%;
|
||||
margin-top: 2rem;
|
||||
padding: 1rem;
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.btn-submit:hover {
|
||||
background-color: #1f3633;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 1rem;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: var(--section-light-bg);
|
||||
padding: 1rem;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin-top: 1.5rem;
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.checkout-container {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<h1>Checkout</h1>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-error">
|
||||
<ul style="margin: 0; padding-left: 1.5rem;">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="checkout-container">
|
||||
<!-- Checkout Form -->
|
||||
<form action="{{ route('order-process') }}" method="POST" class="checkout-form">
|
||||
@csrf
|
||||
|
||||
<h2>Delivery Information</h2>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="customer_name">Full Name</label>
|
||||
<input type="text" id="customer_name" name="customer_name" value="{{ old('customer_name') }}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="customer_email">Email Address</label>
|
||||
<input type="email" id="customer_email" name="customer_email" value="{{ old('customer_email') }}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="customer_phone">Phone Number</label>
|
||||
<input type="tel" id="customer_phone" name="customer_phone" value="{{ old('customer_phone') }}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="shipping_address">Delivery Address</label>
|
||||
<textarea id="shipping_address" name="shipping_address" required>{{ old('shipping_address') }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="notes">Order Notes (Optional)</label>
|
||||
<textarea id="notes" name="notes" placeholder="Any special instructions or notes for your order...">{{ old('notes') }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>Note:</strong> Payment will be processed securely through Yoco. You'll be redirected to complete your card payment after confirming this order.
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn">Complete Order & Proceed to Payment</button>
|
||||
</form>
|
||||
|
||||
<!-- Order Summary -->
|
||||
<div class="order-summary">
|
||||
<h2>Order Summary</h2>
|
||||
|
||||
@foreach($items as $item)
|
||||
<div class="order-item">
|
||||
<div class="order-item-name">{{ $item['product']->name }}</div>
|
||||
|
||||
@php
|
||||
$stockCost = 0;
|
||||
$stockUnit = $item['type'] === 'wallpaper' ? '/m' : '/m²';
|
||||
|
||||
if ($item['stock']) {
|
||||
$stockCost = $item['type'] === 'wallpaper' ? $item['stock']->cost_per_meter : $item['stock']->cost_per_m2;
|
||||
}
|
||||
@endphp
|
||||
|
||||
<div class="order-item-details">
|
||||
@if($item['stock'])
|
||||
<strong>{{ $item['stock']->name }}:</strong> R{{ number_format($stockCost, 2) }}{{ $stockUnit }}<br>
|
||||
@endif
|
||||
|
||||
@if($item['type'] === 'wallpaper')
|
||||
<strong>Length:</strong> {{ $item['length'] }}m
|
||||
@elseif($item['type'] === 'mural')
|
||||
<strong>Dimensions:</strong> {{ $item['width'] }}m × {{ $item['height'] }}m ({{ number_format($item['width'] * $item['height'], 2) }}m²)
|
||||
@endif
|
||||
|
||||
@if($item['quantity'] > 1)
|
||||
<br><strong>Quantity:</strong> {{ $item['quantity'] }}
|
||||
@endif
|
||||
</div>
|
||||
<div class="order-item-price">R{{ number_format($item['subtotal'], 2) }}</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
<div class="summary-row">
|
||||
<span>Subtotal:</span>
|
||||
<span>R{{ number_format($total, 2) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="summary-row">
|
||||
<span>Shipping:</span>
|
||||
<span>TBD at payment</span>
|
||||
</div>
|
||||
|
||||
<div class="summary-row">
|
||||
<span>Tax:</span>
|
||||
<span>TBD at payment</span>
|
||||
</div>
|
||||
|
||||
<div class="summary-row total">
|
||||
<span>Total:</span>
|
||||
<span>R{{ number_format($total, 2) }}</span>
|
||||
</div>
|
||||
|
||||
<a href="{{ route('cart') }}" class="back-link">← Back to Cart</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="announcement-bar">
|
||||
<p>Free shipping on orders over R2000 | Holiday orders must be placed by Dec 15th | Happy Christmas</p>
|
||||
</div>
|
||||
@@ -0,0 +1,45 @@
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="footer-content">
|
||||
<div class="footer-column">
|
||||
<h4>Contact</h4>
|
||||
<p>Email: info@additionaldesign.com</p>
|
||||
<p>Phone: (555) 123-4567</p>
|
||||
<p>Address: 123 Design Street, Creative City, ST 12345</p>
|
||||
</div>
|
||||
|
||||
<div class="footer-column">
|
||||
<h4>Quick Links</h4>
|
||||
<a href="/">Home</a>
|
||||
<a href="/wallpapers">Wallpapers</a>
|
||||
<a href="/fabrics">Fabrics</a>
|
||||
<a href="/#portfolio">Portfolio</a>
|
||||
<a href="#">About Us</a>
|
||||
<a href="#">Terms & Conditions</a>
|
||||
<a href="#">Privacy Policy</a>
|
||||
</div>
|
||||
|
||||
<div class="footer-column">
|
||||
<h4>Follow Us</h4>
|
||||
<div class="social-links">
|
||||
<a href="#" target="_blank">Facebook</a>
|
||||
<a href="#" target="_blank">Instagram</a>
|
||||
<a href="#" target="_blank">Pinterest</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-column">
|
||||
<h4>Newsletter</h4>
|
||||
<p>Subscribe to stay updated on new collections and exclusive offers.</p>
|
||||
<form style="display: flex; gap: 8px; margin-top: var(--spacing-sm);">
|
||||
<input type="email" placeholder="Your email" style="flex: 1; padding: 8px 12px; border: 1px solid rgba(255,255,255,0.2); background-color: rgba(255,255,255,0.1); color: white; font-size: 0.9rem;">
|
||||
<button type="submit" class="btn" style="padding: 8px 16px;">Subscribe</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom">
|
||||
<p>© 2025 Additional Design. All rights reserved. Designed with care and creativity.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,32 @@
|
||||
<header>
|
||||
<div class="container">
|
||||
<div class="header-content">
|
||||
<div class="logo"><a href="/" style="text-decoration: none; color: inherit;">Additional Design</a></div>
|
||||
<nav>
|
||||
<!-- <a href="/">Home</a> -->
|
||||
<a href="/wallpapers">Wallpaper</a>
|
||||
<a href="/murals">Murals</a>
|
||||
<a href="/fabrics">Fabrics</a>
|
||||
<a href="/#portfolio">Portfolio</a>
|
||||
<a href="/#projects">Projects</a>
|
||||
<!-- <a href="/#shop">Decor Shop</a> -->
|
||||
<a href="/#contact">Contact</a>
|
||||
</nav>
|
||||
<a href="{{ route('cart') }}" style="display: flex; align-items: center; gap: 0.5rem; text-decoration: none; color: inherit; font-weight: 500; position: relative;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="9" cy="21" r="1"></circle>
|
||||
<circle cx="20" cy="21" r="1"></circle>
|
||||
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
|
||||
</svg>
|
||||
<span>Cart</span>
|
||||
@if($cartCount > 0)
|
||||
<span style="background: var(--accent-dark); color: white; border-radius: 50%; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 0.75rem; font-weight: bold; position: absolute; top: -8px; right: -8px;">{{ $cartCount }}</span>
|
||||
@endif
|
||||
</a>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
@@ -0,0 +1,18 @@
|
||||
<a href="{{ route('product-detail', $product) }}" style="text-decoration: none; color: inherit;">
|
||||
<div class="card" data-category="{{ $product->category->slug }}">
|
||||
@if($product->images->count() > 0)
|
||||
<img src="{{ asset('storage/' . $product->images->first()->image_path) }}" alt="{{ $product->name }}" class="card-image" style="background-size: cover; background-position: center;">
|
||||
@else
|
||||
<img src="{{ $product->image }}" alt="{{ $product->name }}" class="card-image" style="background-size: cover; background-position: center;">
|
||||
@endif
|
||||
<div class="card-content">
|
||||
<div class="card-title">{{ $product->name }}</div>
|
||||
<span class="card-tag">{{ $product->category->name }}</span>
|
||||
<p class="card-description">{{ substr($product->description, 0, 80) }}...</p>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 1rem;">
|
||||
<!-- <span style="font-family: var(--font-serif); font-weight: 600; font-size: 1.2rem;">R{{ number_format($product->price, 2) }}</span> -->
|
||||
<button class="btn btn--sm" style="pointer-events: none;">View Details</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@@ -0,0 +1,213 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Custom Printed Fabrics')
|
||||
|
||||
@section('content')
|
||||
<!-- HERO SECTION -->
|
||||
<section class="section" id="fabrics-hero" style="background: linear-gradient(to right, rgba(45, 80, 71, 0.7), rgba(45, 80, 71, 0.5)), url('https://images.unsplash.com/photo-1578926078328-123alce3f3ce?w=1200&q=80') center/cover no-repeat;">
|
||||
<div class="container">
|
||||
<div style="padding: 6rem 0; max-width: 700px;">
|
||||
<h1 style="color: white; font-size: 3rem; margin-bottom: 1rem;">Custom Printed Fabrics</h1>
|
||||
<p style="color: rgba(255, 255, 255, 0.95); font-size: 1.1rem;">Extend your favorite wallpaper designs to premium fabrics. From upholstery to curtains, cushions to bedding, create a cohesive interior where your designs flow seamlessly across all textiles.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FABRIC TYPES SECTION -->
|
||||
<section class="section section--light">
|
||||
<div class="container">
|
||||
<h2>Fabric Types & Applications</h2>
|
||||
<p style="max-width: 700px; margin-bottom: 3rem;">Choose from our range of premium fabrics, each optimized for different applications and uses.</p>
|
||||
|
||||
<div class="grid grid--3">
|
||||
<!-- Upholstery Fabrics -->
|
||||
<div class="card">
|
||||
<img src="https://images.unsplash.com/photo-1555041469-a586c61ea9bc?w=500&q=80" alt="Upholstery Fabrics" class="card-image" style="object-fit: cover;">
|
||||
<div class="card-content">
|
||||
<div class="card-title">Upholstery Fabrics</div>
|
||||
<p class="card-description">Durable, premium fabrics perfect for furniture upholstery. Available in various weights and finishes. Ideal for sofas, chairs, and ottomans.</p>
|
||||
<div style="margin-top: 1rem;">
|
||||
<button class="btn btn--sm">Explore Collection</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Curtain & Drape Fabrics -->
|
||||
<div class="card">
|
||||
<img src="https://images.unsplash.com/photo-1578926314433-8e18d4f89b16?w=500&q=80" alt="Curtain Fabrics" class="card-image" style="object-fit: cover;">
|
||||
<div class="card-content">
|
||||
<div class="card-title">Curtain & Drape Fabrics</div>
|
||||
<p class="card-description">Elegant draping fabrics in various opacities. Perfect for creating custom curtains, drapes, and window treatments that complement your wallpaper.</p>
|
||||
<div style="margin-top: 1rem;">
|
||||
<button class="btn btn--sm">Explore Collection</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Decorative Textiles -->
|
||||
<div class="card">
|
||||
<img src="https://images.unsplash.com/photo-1606389506042-4bc31f98b485?w=500&q=80" alt="Decorative Textiles" class="card-image" style="object-fit: cover;">
|
||||
<div class="card-content">
|
||||
<div class="card-title">Decorative Textiles</div>
|
||||
<p class="card-description">Versatile fabrics for cushions, pillows, throws, and home accents. Perfect for adding coordinated touches throughout your space.</p>
|
||||
<div style="margin-top: 1rem;">
|
||||
<button class="btn btn--sm">Explore Collection</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FEATURED FABRICS GRID -->
|
||||
<section class="section" id="featured-fabrics">
|
||||
<div class="container">
|
||||
<h2>Featured Fabric Collections</h2>
|
||||
<p style="margin-bottom: 2rem;">Our most popular custom-printed fabric options, available in various widths and finishes.</p>
|
||||
|
||||
<div class="grid grid--3">
|
||||
<!-- Botanical Garden Fabric -->
|
||||
<div class="card">
|
||||
<img src="https://images.unsplash.com/photo-1520763185298-1b434c919eba?w=500&q=80" alt="Botanical Garden" class="card-image" style="object-fit: cover;">
|
||||
<div class="card-content">
|
||||
<div class="card-title">Botanical Garden</div>
|
||||
<p class="card-description">Nature-inspired floral patterns printed on premium linen blend. Perfect for upholstery and curtains.</p>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 1rem;">
|
||||
<span style="font-weight: 600;">From $45/yard</span>
|
||||
<button class="btn btn--sm">View</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Geometric Modern -->
|
||||
<div class="card">
|
||||
<img src="https://images.unsplash.com/photo-1577720643272-265f434b3f6f?w=500&q=80" alt="Geometric Modern" class="card-image" style="object-fit: cover;">
|
||||
<div class="card-content">
|
||||
<div class="card-title">Geometric Modern</div>
|
||||
<p class="card-description">Contemporary geometric patterns on cotton canvas. Durable and perfect for high-traffic furniture.</p>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 1rem;">
|
||||
<span style="font-weight: 600;">From $48/yard</span>
|
||||
<button class="btn btn--sm">View</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Vintage Elegance -->
|
||||
<div class="card">
|
||||
<img src="https://images.unsplash.com/photo-1578500494198-246f612d03b3?w=500&q=80" alt="Vintage Elegance" class="card-image" style="object-fit: cover;">
|
||||
<div class="card-content">
|
||||
<div class="card-title">Vintage Elegance</div>
|
||||
<p class="card-description">Classic ornamental patterns on silk blend fabric. Ideal for luxury upholstery and formal drapery.</p>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 1rem;">
|
||||
<span style="font-weight: 600;">From $65/yard</span>
|
||||
<button class="btn btn--sm">View</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tropical Vibrancy -->
|
||||
<div class="card">
|
||||
<img src="https://images.unsplash.com/photo-1505142468610-359e7d316be0?w=500&q=80" alt="Tropical Vibrancy" class="card-image" style="object-fit: cover;">
|
||||
<div class="card-content">
|
||||
<div class="card-title">Tropical Vibrancy</div>
|
||||
<p class="card-description">Bright tropical foliage patterns on cotton velvet. Perfect for statement cushions and accent furniture.</p>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 1rem;">
|
||||
<span style="font-weight: 600;">From $52/yard</span>
|
||||
<button class="btn btn--sm">View</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Minimalist Serenity -->
|
||||
<div class="card">
|
||||
<img src="https://images.unsplash.com/photo-1511884642898-4c92249e20b6?w=500&q=80" alt="Minimalist Serenity" class="card-image" style="object-fit: cover;">
|
||||
<div class="card-content">
|
||||
<div class="card-title">Minimalist Serenity</div>
|
||||
<p class="card-description">Subtle minimalist patterns on natural linen. Versatile for any interior design style.</p>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 1rem;">
|
||||
<span style="font-weight: 600;">From $42/yard</span>
|
||||
<button class="btn btn--sm">View</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Luxe Textured -->
|
||||
<div class="card">
|
||||
<img src="https://images.unsplash.com/photo-1578926078328-123alce3f3ce?w=500&q=80" alt="Luxe Textured" class="card-image" style="object-fit: cover;">
|
||||
<div class="card-content">
|
||||
<div class="card-title">Luxe Textured</div>
|
||||
<p class="card-description">High-end jacquard weave fabrics with dimensional textures. Perfect for luxury applications.</p>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 1rem;">
|
||||
<span style="font-weight: 600;">From $75/yard</span>
|
||||
<button class="btn btn--sm">View</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CUSTOMIZATION SECTION -->
|
||||
<section class="section section--light">
|
||||
<div class="container">
|
||||
<h2>Fully Customizable</h2>
|
||||
<div class="two-col">
|
||||
<div class="two-col-text">
|
||||
<h3>Create Your Own Custom Fabric</h3>
|
||||
<p>Love a wallpaper design? We can print it on any of our premium fabric bases. Upload your own design or choose from our wallpaper collections and we'll print it on your fabric of choice.</p>
|
||||
<ul style="list-style: none; color: var(--text-secondary); margin: var(--spacing-md) 0;">
|
||||
<li style="margin-bottom: 12px;"><strong>✓ Any Wallpaper Design:</strong> Choose from our full wallpaper catalog</li>
|
||||
<li style="margin-bottom: 12px;"><strong>✓ Custom Uploads:</strong> Print your own designs or artwork</li>
|
||||
<li style="margin-bottom: 12px;"><strong>✓ Multiple Base Fabrics:</strong> Select from cotton, linen, silk blends, and more</li>
|
||||
<li style="margin-bottom: 12px;"><strong>✓ Custom Sizing:</strong> Order exact yardage you need</li>
|
||||
<li style="margin-bottom: 12px;"><strong>✓ Sample Swatches:</strong> Order fabric samples before committing</li>
|
||||
</ul>
|
||||
<button class="btn" style="margin-top: var(--spacing-lg);">Start Custom Design</button>
|
||||
</div>
|
||||
<div class="two-col-image">
|
||||
<img src="https://images.unsplash.com/photo-1578500494198-246f612d03b3?w=500&q=80" alt="Custom Fabrics" style="width: 100%; height: auto; border-radius: 8px; object-fit: cover;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FABRIC SPECIFICATIONS -->
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h2>Fabric Specifications & Care</h2>
|
||||
<div style="background-color: var(--bg-secondary); padding: var(--spacing-lg); border-radius: 8px;">
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-lg);">
|
||||
<div>
|
||||
<h4 style="color: var(--accent-dark); margin-bottom: 1rem;">Standard Widths</h4>
|
||||
<ul style="list-style: none; color: var(--text-secondary);">
|
||||
<li style="margin-bottom: 8px;">• 54" (Standard upholstery)</li>
|
||||
<li style="margin-bottom: 8px;">• 60" (Premium upholstery)</li>
|
||||
<li style="margin-bottom: 8px;">• 45" (Quilting & crafts)</li>
|
||||
<li style="margin-bottom: 8px;">• 118" (Curtain & drape)</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 style="color: var(--accent-dark); margin-bottom: 1rem;">Care Instructions</h4>
|
||||
<ul style="list-style: none; color: var(--text-secondary);">
|
||||
<li style="margin-bottom: 8px;">• Dry clean or gentle hand wash recommended</li>
|
||||
<li style="margin-bottom: 8px;">• Use cool water with mild detergent</li>
|
||||
<li style="margin-bottom: 8px;">• Air dry away from direct heat</li>
|
||||
<li style="margin-bottom: 8px;">• Professional upholstery cleaning safe</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA SECTION -->
|
||||
<section class="section section--highlight">
|
||||
<div class="container" style="text-align: center;">
|
||||
<h2>Ready to Start Your Fabric Project?</h2>
|
||||
<p style="max-width: 600px; margin: 0 auto var(--spacing-lg); color: var(--text-primary);">
|
||||
Contact our team to discuss your custom fabric needs. We'll provide samples, pricing, and personalized recommendations.
|
||||
</p>
|
||||
<button class="btn btn--secondary">Request Custom Quote</button>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
||||
@@ -0,0 +1,119 @@
|
||||
<x-filament::page>
|
||||
<div class="space-y-6">
|
||||
<!-- Order Header -->
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h1 class="text-3xl font-bold mb-4">Order #{{ $record->order_number }}</h1>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 md:grid-cols-4">
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm">Status</p>
|
||||
<p class="text-lg font-semibold">{{ ucfirst($record->status) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm">Payment Status</p>
|
||||
<p class="text-lg font-semibold">{{ ucfirst($record->payment_status) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm">Total</p>
|
||||
<p class="text-lg font-semibold">R{{ number_format($record->total, 2) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm">Order Date</p>
|
||||
<p class="text-lg font-semibold">{{ $record->created_at->format('M d, Y') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Items -->
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h2 class="text-2xl font-bold mb-4">Order Items</h2>
|
||||
|
||||
@if($record->items->count() > 0)
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm text-left text-gray-600">
|
||||
<thead class="text-xs text-gray-700 uppercase bg-gray-100">
|
||||
<tr>
|
||||
<th class="px-4 py-3">Product</th>
|
||||
<th class="px-4 py-3">Print Stock</th>
|
||||
<th class="px-4 py-3">Type</th>
|
||||
<th class="px-4 py-3">Specifications</th>
|
||||
<th class="px-4 py-3 text-right">Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($record->items as $item)
|
||||
<tr class="border-b hover:bg-gray-50">
|
||||
<td class="px-4 py-3 font-medium text-gray-900">
|
||||
{{ $item->product->name }}
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
{{ $item->printStock->name ?? 'N/A' }}
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
<span class="bg-blue-100 text-blue-800 px-2 py-1 rounded text-xs">
|
||||
{{ ucfirst($item->type) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm">
|
||||
@if($item->type === 'wallpaper')
|
||||
Length: {{ $item->length }}m
|
||||
@elseif($item->type === 'mural')
|
||||
{{ $item->width }}m × {{ $item->height }}m ({{ number_format($item->width * $item->height, 2) }}m²)
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-4 py-3 text-right font-semibold text-gray-900">
|
||||
R{{ number_format($item->price, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
<tfoot class="border-t-2 border-gray-300">
|
||||
<tr>
|
||||
<td colspan="4" class="px-4 py-3 text-right font-bold">Total:</td>
|
||||
<td class="px-4 py-3 text-right font-bold text-lg text-gray-900">
|
||||
R{{ number_format($record->items->sum('price'), 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
@else
|
||||
<p class="text-gray-600">No items in this order.</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Customer Information -->
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h2 class="text-2xl font-bold mb-4">Customer Information</h2>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm mb-1">Name</p>
|
||||
<p class="text-lg font-semibold">{{ $record->customer_name }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm mb-1">Email</p>
|
||||
<p class="text-lg">{{ $record->customer_email }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm mb-1">Phone</p>
|
||||
<p class="text-lg">{{ $record->customer_phone ?? 'N/A' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm mb-1">Payment Method</p>
|
||||
<p class="text-lg">{{ $record->payment_method ?? 'N/A' }}</p>
|
||||
</div>
|
||||
<div class="md:col-span-2">
|
||||
<p class="text-gray-600 text-sm mb-1">Shipping Address</p>
|
||||
<p class="text-lg whitespace-pre-wrap">{{ $record->shipping_address }}</p>
|
||||
</div>
|
||||
@if($record->notes)
|
||||
<div class="md:col-span-2">
|
||||
<p class="text-gray-600 text-sm mb-1">Notes</p>
|
||||
<p class="text-lg whitespace-pre-wrap">{{ $record->notes }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-filament::page>
|
||||
@@ -0,0 +1,66 @@
|
||||
<x-filament-panels::page>
|
||||
{{-- Default form fields will be rendered here by Filament --}}
|
||||
{{ $this->form }}
|
||||
|
||||
{{-- Custom Order Items Section --}}
|
||||
<div class="mt-6">
|
||||
<x-filament::section>
|
||||
<x-slot name="heading">
|
||||
Order Items
|
||||
</x-slot>
|
||||
|
||||
@if($this->record->items && $this->record->items->count() > 0)
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="border-b">
|
||||
<tr class="text-left">
|
||||
<th class="px-4 py-3 font-medium">Product</th>
|
||||
<th class="px-4 py-3 font-medium">Print Stock</th>
|
||||
<th class="px-4 py-3 font-medium">Type</th>
|
||||
<th class="px-4 py-3 font-medium">Specifications</th>
|
||||
<th class="px-4 py-3 font-medium text-right">Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y">
|
||||
@foreach($this->record->items as $item)
|
||||
<tr>
|
||||
<td class="px-4 py-3">
|
||||
{{ $item->product->name ?? 'N/A' }}
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
{{ $item->printStock->name ?? 'N/A' }}
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
<x-filament::badge>
|
||||
{{ ucfirst($item->type) }}
|
||||
</x-filament::badge>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm">
|
||||
@if($item->type === 'wallpaper')
|
||||
Length: {{ $item->length }}m
|
||||
@elseif($item->type === 'mural')
|
||||
{{ $item->width }}m × {{ $item->height }}m ({{ number_format($item->width * $item->height, 2) }}m²)
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-4 py-3 text-right font-semibold">
|
||||
R{{ number_format($item->price, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
<tfoot class="border-t-2 font-bold">
|
||||
<tr>
|
||||
<td colspan="4" class="px-4 py-3 text-right">Total:</td>
|
||||
<td class="px-4 py-3 text-right text-lg">
|
||||
R{{ number_format($this->record->items->sum('price'), 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
@else
|
||||
<p class="text-gray-600">No items in this order.</p>
|
||||
@endif
|
||||
</x-filament::section>
|
||||
</div>
|
||||
</x-filament-panels::page>
|
||||
@@ -0,0 +1,123 @@
|
||||
@extends('filament::layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="fi-main">
|
||||
<div class="fi-main-ctn fi-page-ctn space-y-6">
|
||||
<!-- Order Header -->
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h1 class="text-3xl font-bold mb-4">Order #{{ $record->order_number }}</h1>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 md:grid-cols-4">
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm">Status</p>
|
||||
<p class="text-lg font-semibold">{{ ucfirst($record->status) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm">Payment Status</p>
|
||||
<p class="text-lg font-semibold">{{ ucfirst($record->payment_status) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm">Total</p>
|
||||
<p class="text-lg font-semibold">R{{ number_format($record->total, 2) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm">Order Date</p>
|
||||
<p class="text-lg font-semibold">{{ $record->created_at->format('M d, Y') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Items -->
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h2 class="text-2xl font-bold mb-4">Order Items</h2>
|
||||
|
||||
@if($record->items && $record->items->count() > 0)
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm text-left text-gray-600">
|
||||
<thead class="text-xs text-gray-700 uppercase bg-gray-100">
|
||||
<tr>
|
||||
<th class="px-4 py-3">Product</th>
|
||||
<th class="px-4 py-3">Print Stock</th>
|
||||
<th class="px-4 py-3">Type</th>
|
||||
<th class="px-4 py-3">Specifications</th>
|
||||
<th class="px-4 py-3 text-right">Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($record->items as $item)
|
||||
<tr class="border-b hover:bg-gray-50">
|
||||
<td class="px-4 py-3 font-medium text-gray-900">
|
||||
{{ $item->product->name ?? 'N/A' }}
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
{{ $item->printStock->name ?? 'N/A' }}
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
<span class="bg-blue-100 text-blue-800 px-2 py-1 rounded text-xs">
|
||||
{{ ucfirst($item->type) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm">
|
||||
@if($item->type === 'wallpaper')
|
||||
Length: {{ $item->length }}m
|
||||
@elseif($item->type === 'mural')
|
||||
{{ $item->width }}m × {{ $item->height }}m ({{ number_format($item->width * $item->height, 2) }}m²)
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-4 py-3 text-right font-semibold text-gray-900">
|
||||
R{{ number_format($item->price, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
<tfoot class="border-t-2 border-gray-300">
|
||||
<tr>
|
||||
<td colspan="4" class="px-4 py-3 text-right font-bold">Total:</td>
|
||||
<td class="px-4 py-3 text-right font-bold text-lg text-gray-900">
|
||||
R{{ number_format($record->items->sum('price'), 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
@else
|
||||
<p class="text-gray-600">No items in this order.</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Customer Information -->
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h2 class="text-2xl font-bold mb-4">Customer Information</h2>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm mb-1">Name</p>
|
||||
<p class="text-lg font-semibold">{{ $record->customer_name }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm mb-1">Email</p>
|
||||
<p class="text-lg">{{ $record->customer_email }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm mb-1">Phone</p>
|
||||
<p class="text-lg">{{ $record->customer_phone ?? 'N/A' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600 text-sm mb-1">Payment Method</p>
|
||||
<p class="text-lg">{{ $record->payment_method ?? 'N/A' }}</p>
|
||||
</div>
|
||||
<div class="md:col-span-2">
|
||||
<p class="text-gray-600 text-sm mb-1">Shipping Address</p>
|
||||
<p class="text-lg whitespace-pre-wrap">{{ $record->shipping_address }}</p>
|
||||
</div>
|
||||
@if($record->notes)
|
||||
<div class="md:col-span-2">
|
||||
<p class="text-gray-600 text-sm mb-1">Notes</p>
|
||||
<p class="text-lg whitespace-pre-wrap">{{ $record->notes }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,463 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
.hero-slider {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 20px;
|
||||
margin: 20px;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.hero-slide {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
transition: opacity 0.8s ease-in-out;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.hero-slide.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.hero-slide-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3rem;
|
||||
align-items: center;
|
||||
padding: 6rem 5rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hero-dots {
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.hero-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border: 2px solid white;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.hero-dot.active {
|
||||
background: white;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
<!-- ===== 3. HERO SECTION ===== -->
|
||||
<section class="section" id="hero">
|
||||
<div class="hero-slider">
|
||||
@forelse($heroImages as $index => $image)
|
||||
<div class="hero-slide @if($index === 0) active @endif" style="background-image: url('{{ asset('storage/' . $image->image_path) }}');">
|
||||
<div class="hero-slide-content">
|
||||
<div>
|
||||
<div class="hero-content">
|
||||
<h1 style="color: white; font-size: 3rem;">{{ $image->title }}</h1>
|
||||
@if($image->description)
|
||||
<p style="color: rgba(255, 255, 255, 0.9); font-size: 1.1rem; max-width: 95%;">{{ $image->description }}</p>
|
||||
@endif
|
||||
<div class="hero-cta">
|
||||
@if($image->button_text && $image->button_link)
|
||||
@if(str_starts_with($image->button_link, '#'))
|
||||
<button class="btn" onclick="document.getElementById('{{ substr($image->button_link, 1) }}').scrollIntoView({behavior: 'smooth'})">{{ $image->button_text }}</button>
|
||||
@else
|
||||
<a href="{{ $image->button_link }}" class="btn">{{ $image->button_text }}</a>
|
||||
@endif
|
||||
@else
|
||||
<button class="btn" onclick="document.getElementById('wallpaper').scrollIntoView({behavior: 'smooth'})">Browse Wallpaper Ranges</button>
|
||||
<button class="btn btn--secondary" onclick="document.getElementById('consultation').scrollIntoView({behavior: 'smooth'})">Book a Free Consultation</button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<!-- Fallback hero images if none are configured in admin -->
|
||||
<div class="hero-slide active" style="background-image: url('https://images.unsplash.com/photo-1552321554-5fefe8c9ef14?w=1200&q=80');">
|
||||
<div class="hero-slide-content">
|
||||
<div>
|
||||
<div class="hero-content">
|
||||
<h1 style="color: white; font-size: 3rem;">Transform Your Spaces with Custom Wallpaper</h1>
|
||||
<p style="color: rgba(255, 255, 255, 0.9); font-size: 1.1rem; max-width: 95%;">Discover our curated collections of premium wallpapers and custom-printed fabrics, designed to elevate your interior aesthetic.</p>
|
||||
<div class="hero-cta">
|
||||
<button class="btn" onclick="document.getElementById('wallpaper').scrollIntoView({behavior: 'smooth'})">Browse Wallpaper Ranges</button>
|
||||
<button class="btn btn--secondary" onclick="document.getElementById('consultation').scrollIntoView({behavior: 'smooth'})">Book a Free Consultation</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-slide" style="background-image: url('https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&q=80');">
|
||||
<div class="hero-slide-content">
|
||||
<div>
|
||||
<div class="hero-content">
|
||||
<h1 style="color: white; font-size: 3rem;">Luxury Designs for Every Room</h1>
|
||||
<p style="color: rgba(255, 255, 255, 0.9); font-size: 1.1rem; max-width: 95%;">From botanical motifs to contemporary patterns, find the perfect wallpaper to match your style.</p>
|
||||
<div class="hero-cta">
|
||||
<button class="btn" onclick="document.getElementById('wallpaper').scrollIntoView({behavior: 'smooth'})">Explore Collections</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-slide" style="background-image: url('https://images.unsplash.com/photo-1568605114967-8130f3a36994?w=1200&q=80');">
|
||||
<div class="hero-slide-content">
|
||||
<div>
|
||||
<div class="hero-content">
|
||||
<h1 style="color: white; font-size: 3rem;">Custom Printed to Perfection</h1>
|
||||
<p style="color: rgba(255, 255, 255, 0.9); font-size: 1.1rem; max-width: 95%;">Every design is crafted with precision and printed to your exact specifications using eco-friendly materials.</p>
|
||||
<div class="hero-cta">
|
||||
<button class="btn" onclick="document.getElementById('sustainability').scrollIntoView({behavior: 'smooth'})">Learn About Our Process</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
@endforelse
|
||||
|
||||
<div class="hero-dots">
|
||||
@forelse($heroImages as $index => $image)
|
||||
<div class="hero-dot @if($index === 0) active @endif" data-slide="{{ $index }}"></div>
|
||||
@empty
|
||||
<div class="hero-dot active" data-slide="0"></div>
|
||||
<div class="hero-dot" data-slide="1"></div>
|
||||
<div class="hero-dot" data-slide="2"></div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== 4. WALLPAPER RANGES ===== -->
|
||||
<section class="section section--light" id="wallpaper">
|
||||
<div class="container">
|
||||
<h2>Wallpaper Ranges</h2>
|
||||
<p>Explore our carefully curated collections, from botanical motifs to contemporary geometric patterns. Each range is designed to inspire and transform your interior spaces.</p>
|
||||
|
||||
<div class="grid grid--3">
|
||||
@forelse($categories as $category)
|
||||
<div class="card">
|
||||
<div class="card-image" style="background-image: url('{{ $category->image }}'); background-size: cover; background-position: center;"></div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">{{ $category->name }}</div>
|
||||
<p class="card-description">{{ $category->description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<p>No categories available</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== 5. LATEST WALLPAPERS ===== -->
|
||||
<section class="section" id="featured">
|
||||
<div class="container">
|
||||
<h2>Our Latest Wallpapers</h2>
|
||||
<p>Discover our newest arrivals, hand-selected for their design excellence and quality.</p>
|
||||
|
||||
<div class="grid grid--3">
|
||||
@forelse($featuredWallpapers as $product)
|
||||
@include('components.product-card', ['product' => $product])
|
||||
@empty
|
||||
<p>No featured wallpapers available</p>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; margin-top: var(--spacing-lg);">
|
||||
<a href="{{ route('wallpapers') }}" class="btn">View All Wallpapers</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== 5.5 FEATURED MURALS ===== -->
|
||||
<section class="section section--light" id="featured-murals">
|
||||
<div class="container">
|
||||
<h2>Featured Murals</h2>
|
||||
<p>Stunning accent wall murals to transform any room. Single image, non-repeating designs perfect for making a statement.</p>
|
||||
|
||||
<div class="grid grid--3">
|
||||
@forelse($featuredMurals as $product)
|
||||
@include('components.product-card', ['product' => $product])
|
||||
@empty
|
||||
<p>No featured murals available</p>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; margin-top: var(--spacing-lg);">
|
||||
<a href="{{ route('murals') }}" class="btn">View All Murals</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== 6. FREE CONSULTATION CTA ===== -->
|
||||
<section class="section section--highlight" id="consultation">
|
||||
<div class="container" style="text-align: center;">
|
||||
<h2>Free Online Wallpaper Consultation</h2>
|
||||
<p style="max-width: 600px; margin: 0 auto var(--spacing-lg);">
|
||||
Unsure which design to choose? Our design experts offer complimentary 15-minute virtual consultations to help you select the perfect wallpaper and discuss customization options for your unique space.
|
||||
</p>
|
||||
<button class="btn btn--secondary">Schedule a Consultation</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== 7. RECENT PROJECTS ===== -->
|
||||
<section class="section section--light" id="projects">
|
||||
<div class="container">
|
||||
<h2>Recent Projects</h2>
|
||||
<p>Our work spans luxury hotels, high-end residences, and commercial spaces. See how we transform environments with our custom wallpaper and fabric solutions.</p>
|
||||
|
||||
<div class="grid grid--3">
|
||||
<div class="card">
|
||||
<div class="card-image" style="background-image: url('https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=500&q=80'); background-size: cover; background-position: center;"></div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">Luxury Resort Redesign</div>
|
||||
<p class="card-description">Custom botanical wallpapers throughout the main lobby and guest suites.</p>
|
||||
<a href="#" class="btn btn--text">View Project</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-image" style="background-image: url('https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=500&q=80'); background-size: cover; background-position: center;"></div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">Modern Executive Office</div>
|
||||
<p class="card-description">Bespoke geometric wallpaper for corporate interiors with sustainable materials.</p>
|
||||
<a href="#" class="btn btn--text">View Project</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-image" style="background-image: url('https://images.unsplash.com/photo-1568605114967-8130f3a36994?w=500&q=80'); background-size: cover; background-position: center;"></div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">Residential Penthouse</div>
|
||||
<p class="card-description">Custom-printed fabrics and vintage-inspired wallpapers for a luxury residence.</p>
|
||||
<a href="#" class="btn btn--text">View Project</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== 8. CERTIFIED GREEN / SUSTAINABILITY ===== -->
|
||||
<section class="section" id="sustainability">
|
||||
<div class="container">
|
||||
<div class="badge" style="border-radius: 20px;">
|
||||
<div class="badge-icon">♻️</div>
|
||||
<div class="badge-text">
|
||||
<h4>Certified Eco-Conscious</h4>
|
||||
<p>Our wallpapers and fabrics are printed using low-VOC inks and sustainable materials sourced responsibly.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="background-color: var(--bg-secondary); padding: var(--spacing-lg); border-radius: 20px;">
|
||||
<h3 style="color: var(--accent-dark); margin-bottom: var(--spacing-md);">Sustainability Commitment</h3>
|
||||
<ul style="list-style: none; color: var(--text-secondary);">
|
||||
<li style="margin-bottom: 12px;"><strong>Low-VOC Inks:</strong> Non-toxic printing processes safe for your home and the environment.</li>
|
||||
<li style="margin-bottom: 12px;"><strong>Local Production:</strong> Manufactured locally to reduce carbon footprint and ensure quality.</li>
|
||||
<li style="margin-bottom: 12px;"><strong>Sustainable Materials:</strong> Sourced from certified sustainable suppliers with ethical practices.</li>
|
||||
<li style="margin-bottom: 12px;"><strong>Recyclable Packaging:</strong> All packaging materials are fully recyclable or compostable.</li>
|
||||
</ul>
|
||||
<a href="#" class="btn btn--text" style="margin-top: var(--spacing-md);">Learn More About Our Practices</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== 9. CUSTOM FABRICS ===== -->
|
||||
<section class="section section--light" id="fabrics">
|
||||
<div class="container">
|
||||
<h2>Custom Printed Fabrics</h2>
|
||||
<div class="two-col">
|
||||
<div class="two-col-text">
|
||||
<h3>Extend Your Design to Soft Furnishings</h3>
|
||||
<p>Love a wallpaper design? We can print it onto premium fabrics for upholstery, curtains, cushions, and more. Create a cohesive interior where your wallpaper designs flow seamlessly across all textiles.</p>
|
||||
<ul style="list-style: none; color: var(--text-secondary);">
|
||||
<li style="margin-bottom: 8px;">✓ Custom upholstery and furniture fabric</li>
|
||||
<li style="margin-bottom: 8px;">✓ Bespoke curtain and drape materials</li>
|
||||
<li style="margin-bottom: 8px;">✓ Decorative cushion and throw pillow fabric</li>
|
||||
<li style="margin-bottom: 8px;">✓ Bedding and linens custom printing</li>
|
||||
</ul>
|
||||
<button class="btn" style="margin-top: var(--spacing-lg);">Browse Fabrics</button>
|
||||
</div>
|
||||
<div class="two-col-image">
|
||||
<img src="https://images.unsplash.com/photo-1578500494198-246f612d03b3?w=500&q=80" alt="Fabric Sample" style="width: 100%; height: auto; border-radius: 8px; object-fit: cover;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== 10. DECOR SHOP TEASER =====
|
||||
<section class="section" id="shop">
|
||||
<div class="container">
|
||||
<h2>Decor Shop</h2>
|
||||
<p>Discover curated home décor pieces that complement our wallpaper and fabric collections. From wall hangings to tableware.</p>
|
||||
|
||||
<div class="grid grid--3">
|
||||
<div class="card">
|
||||
<div class="card-image" style="background-image: url('https://images.unsplash.com/photo-1578926314433-8e18d4f89b16?w=400&q=80'); background-size: cover; background-position: center;"></div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">Artisan Wall Hangings</div>
|
||||
<p class="card-description">Hand-crafted textile wall art pieces.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-image" style="background-image: url('https://images.unsplash.com/photo-1578500494198-246f612d03b3?w=400&q=80'); background-size: cover; background-position: center;"></div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">Designer Tableware</div>
|
||||
<p class="card-description">Coordinated dinnerware sets with exclusive designs.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-image" style="background-image: url('https://images.unsplash.com/photo-1606389506042-4bc31f98b485?w=400&q=80'); background-size: cover; background-position: center;"></div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">Decorative Accents</div>
|
||||
<p class="card-description">Curated home accessories to complete your space.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; margin-top: var(--spacing-lg);">
|
||||
<button class="btn btn--secondary">Visit Decor Shop</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== 11. PORTFOLIO GALLERY ===== -->
|
||||
<!-- <section class="section section--light" id="portfolio">
|
||||
<div class="container">
|
||||
<h2>View Our Portfolio</h2>
|
||||
<p>Explore our diverse portfolio showcasing wallpaper and fabric applications across different room types and design styles.</p>
|
||||
|
||||
<div class="portfolio-grid">
|
||||
<div class="portfolio-item" style="background-image: url('https://images.unsplash.com/photo-1540932239986-310128078e37?w=600&q=80'); background-size: cover; background-position: center;">
|
||||
<div class="portfolio-item-caption">Master Bedroom</div>
|
||||
</div>
|
||||
<div class="portfolio-item" style="background-image: url('https://images.unsplash.com/photo-1522708323590-d24dbb6b0267?w=600&q=80'); background-size: cover; background-position: center;">
|
||||
<div class="portfolio-item-caption">Living Room</div>
|
||||
</div>
|
||||
<div class="portfolio-item" style="background-image: url('https://images.unsplash.com/photo-1556909114-f6e7ad7d3136?w=600&q=80'); background-size: cover; background-position: center;">
|
||||
<div class="portfolio-item-caption">Kitchen Nook</div>
|
||||
</div>
|
||||
<div class="portfolio-item" style="background-image: url('https://images.unsplash.com/photo-1593642632823-8f785ba67e45?w=600&q=80'); background-size: cover; background-position: center;">
|
||||
<div class="portfolio-item-caption">Home Office</div>
|
||||
</div>
|
||||
<div class="portfolio-item" style="background-image: url('https://images.unsplash.com/photo-1552321554-5fefe8c9ef14?w=600&q=80'); background-size: cover; background-position: center;">
|
||||
<div class="portfolio-item-caption">Bathroom Spa</div>
|
||||
</div>
|
||||
<div class="portfolio-item" style="background-image: url('https://images.unsplash.com/photo-1566073771259-6a8506099945?w=600&q=80'); background-size: cover; background-position: center;">
|
||||
<div class="portfolio-item-caption">Dining Space</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; margin-top: var(--spacing-lg);">
|
||||
<button class="btn">View Full Portfolio</button>
|
||||
</div>
|
||||
</div>
|
||||
</section> -->
|
||||
|
||||
<!-- ===== 12. OUR CLIENTS ===== -->
|
||||
<!-- <section class="section" id="clients">
|
||||
<div class="container">
|
||||
<h2>Brands We've Worked With</h2>
|
||||
|
||||
<div class="logo-strip">
|
||||
<div class="logo-item">Luxury Hotels Co.</div>
|
||||
<div class="logo-item">Interior Design Studio</div>
|
||||
<div class="logo-item">Modern Architects Ltd.</div>
|
||||
<div class="logo-item">Home & Living Mag</div>
|
||||
<div class="logo-item">Premium Resorts Group</div>
|
||||
<div class="logo-item">Urban Development</div>
|
||||
</div>
|
||||
</div>
|
||||
</section> -->
|
||||
|
||||
<!-- ===== 13. CONTACT CTA ===== -->
|
||||
<section class="section section--highlight" id="contact">
|
||||
<div class="container" style="text-align: center;">
|
||||
<h2>Ready to Start Your Project?</h2>
|
||||
<p style="max-width: 600px; margin: 0 auto var(--spacing-lg); color: var(--text-primary);">
|
||||
We'd love to hear about your vision. Send us your room measurements, mood boards, and any design inspirations, and our team will provide a personalized quote and design recommendations.
|
||||
</p>
|
||||
<button class="btn">Contact Us</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const slides = document.querySelectorAll('.hero-slide');
|
||||
const dots = document.querySelectorAll('.hero-dot');
|
||||
let currentSlide = 0;
|
||||
let slideInterval;
|
||||
|
||||
function showSlide(index) {
|
||||
slides.forEach(slide => slide.classList.remove('active'));
|
||||
dots.forEach(dot => dot.classList.remove('active'));
|
||||
|
||||
slides[index].classList.add('active');
|
||||
dots[index].classList.add('active');
|
||||
currentSlide = index;
|
||||
}
|
||||
|
||||
function nextSlide() {
|
||||
let next = (currentSlide + 1) % slides.length;
|
||||
showSlide(next);
|
||||
}
|
||||
|
||||
function startAutoSlide() {
|
||||
slideInterval = setInterval(nextSlide, 10000);
|
||||
}
|
||||
|
||||
function stopAutoSlide() {
|
||||
clearInterval(slideInterval);
|
||||
}
|
||||
|
||||
// Dot click handlers
|
||||
dots.forEach(dot => {
|
||||
dot.addEventListener('click', function() {
|
||||
stopAutoSlide();
|
||||
showSlide(parseInt(this.dataset.slide));
|
||||
startAutoSlide();
|
||||
});
|
||||
});
|
||||
|
||||
// Start automatic sliding
|
||||
startAutoSlide();
|
||||
|
||||
// Pause on hover
|
||||
const slider = document.querySelector('.hero-slider');
|
||||
slider.addEventListener('mouseenter', stopAutoSlide);
|
||||
slider.addEventListener('mouseleave', startAutoSlide);
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>@yield('title', 'Additional Design')</title>
|
||||
<!-- Google Fonts -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Abril+Fatface&family=Noto+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="{{ asset('css/styles.css') }}">
|
||||
@yield('styles')
|
||||
</head>
|
||||
<body>
|
||||
@include('components.announcement-bar')
|
||||
@include('components.header')
|
||||
|
||||
@yield('content')
|
||||
|
||||
@include('components.footer')
|
||||
|
||||
<script src="{{ asset('js/script.js') }}"></script>
|
||||
@yield('scripts')
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,278 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Murals - Premium Custom Designs')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
.hero-slider {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 20px;
|
||||
margin: 20px;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.hero-slide {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
transition: opacity 0.8s ease-in-out;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.hero-slide.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.hero-slide-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3rem;
|
||||
align-items: center;
|
||||
padding: 6rem 5rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hero-dots {
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.hero-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.hero-dot.active {
|
||||
background: white;
|
||||
width: 32px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.hero-cta {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.hero-slider:hover .hero-dot {
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.hero-slider:hover .hero-dot.active {
|
||||
background: white;
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<!-- HERO SECTION -->
|
||||
<section class="section" id="hero">
|
||||
<div class="hero-slider">
|
||||
@forelse($heroImages as $index => $image)
|
||||
<div class="hero-slide @if($index === 0) active @endif" style="background-image: url('{{ asset('storage/' . $image->image_path) }}');">
|
||||
<div class="hero-slide-content">
|
||||
<div>
|
||||
<div class="hero-content">
|
||||
<h1 style="color: white; font-size: 3rem;">{{ $image->title }}</h1>
|
||||
@if($image->description)
|
||||
<p style="color: rgba(255, 255, 255, 0.9); font-size: 1.1rem; max-width: 95%;">{{ $image->description }}</p>
|
||||
@endif
|
||||
<div class="hero-cta">
|
||||
@if($image->button_text && $image->button_link)
|
||||
@if(str_starts_with($image->button_link, '#'))
|
||||
<button class="btn" onclick="document.getElementById('{{ substr($image->button_link, 1) }}').scrollIntoView({behavior: 'smooth'})">{{ $image->button_text }}</button>
|
||||
@else
|
||||
<a href="{{ $image->button_link }}" class="btn">{{ $image->button_text }}</a>
|
||||
@endif
|
||||
@else
|
||||
<button class="btn" onclick="document.getElementById('mural-filters').scrollIntoView({behavior: 'smooth'})">Browse Murals</button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<!-- Fallback hero image if none are configured in admin -->
|
||||
<div class="hero-slide active" style="background: linear-gradient(to right, rgba(45, 80, 71, 0.7), rgba(45, 80, 71, 0.5)), url('https://images.unsplash.com/photo-1568605114967-8130f3a36994?w=1200&q=80') center/cover no-repeat;">
|
||||
<div class="hero-slide-content">
|
||||
<div>
|
||||
<div class="hero-content">
|
||||
<h1 style="color: white; font-size: 3rem;">Stunning Custom Murals</h1>
|
||||
<p style="color: rgba(255, 255, 255, 0.95); font-size: 1.1rem;">Make a statement with our collection of bold, eye-catching murals. Single-image designs perfect for accent walls in any room. Each mural is custom-printed to your exact dimensions.</p>
|
||||
<div class="hero-cta">
|
||||
<button class="btn" onclick="document.getElementById('mural-filters').scrollIntoView({behavior: 'smooth'})">Browse Murals</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
@endforelse
|
||||
|
||||
<div class="hero-dots">
|
||||
@forelse($heroImages as $index => $image)
|
||||
<div class="hero-dot @if($index === 0) active @endif" data-slide="{{ $index }}"></div>
|
||||
@empty
|
||||
<div class="hero-dot active" data-slide="0"></div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const slides = document.querySelectorAll('.hero-slide');
|
||||
const dots = document.querySelectorAll('.hero-dot');
|
||||
const slider = document.querySelector('.hero-slider');
|
||||
let currentSlide = 0;
|
||||
let autoAdvanceInterval;
|
||||
|
||||
function showSlide(n) {
|
||||
if (slides.length === 0) return;
|
||||
slides.forEach(s => s.classList.remove('active'));
|
||||
dots.forEach(d => d.classList.remove('active'));
|
||||
currentSlide = (n + slides.length) % slides.length;
|
||||
slides[currentSlide].classList.add('active');
|
||||
dots[currentSlide].classList.add('active');
|
||||
}
|
||||
|
||||
function startAutoAdvance() {
|
||||
autoAdvanceInterval = setInterval(() => {
|
||||
showSlide(currentSlide + 1);
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function resetAutoAdvance() {
|
||||
clearInterval(autoAdvanceInterval);
|
||||
startAutoAdvance();
|
||||
}
|
||||
|
||||
dots.forEach(dot => {
|
||||
dot.addEventListener('click', () => {
|
||||
showSlide(parseInt(dot.getAttribute('data-slide')));
|
||||
resetAutoAdvance();
|
||||
});
|
||||
});
|
||||
|
||||
slider.addEventListener('mouseenter', () => clearInterval(autoAdvanceInterval));
|
||||
slider.addEventListener('mouseleave', startAutoAdvance);
|
||||
|
||||
startAutoAdvance();
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- FILTERS & SORTING -->
|
||||
<section class="section" id="mural-filters" style="padding: 2rem 0;">
|
||||
<div class="container">
|
||||
<div style="display: flex; gap: 2rem; justify-content: space-between; align-items: center; flex-wrap: wrap; margin-bottom: 2rem;">
|
||||
<div>
|
||||
<h3>All Murals</h3>
|
||||
<p style="color: var(--text-secondary);">Showing all designs</p>
|
||||
</div>
|
||||
<div style="display: flex; gap: 1rem;">
|
||||
<select style="padding: 8px 12px; border: 1px solid var(--border-color); border-radius: 4px; font-size: 0.9rem;">
|
||||
<option>Sort by: Featured</option>
|
||||
<option>Newest</option>
|
||||
<option>Price: Low to High</option>
|
||||
<option>Price: High to Low</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 2rem;">
|
||||
<button class="filter-btn active" data-filter="all">All</button>
|
||||
<button class="filter-btn" data-filter="landscape">Landscape</button>
|
||||
<button class="filter-btn" data-filter="abstract">Abstract</button>
|
||||
<button class="filter-btn" data-filter="urban">Urban</button>
|
||||
<button class="filter-btn" data-filter="nature">Nature</button>
|
||||
<button class="filter-btn" data-filter="artistic">Artistic</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- MURAL GRID -->
|
||||
<section class="section" id="mural-grid" style="padding: 2rem 0;">
|
||||
<div class="container">
|
||||
<div class="grid grid--3">
|
||||
@forelse($products as $product)
|
||||
@include('components.product-card', ['product' => $product])
|
||||
@empty
|
||||
<p>No murals available yet</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- MURAL INFO SECTION -->
|
||||
<section class="section section--light">
|
||||
<div class="container">
|
||||
<h2>About Our Murals</h2>
|
||||
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem; margin-top: 2rem;">
|
||||
<div style="background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);">
|
||||
<h4 style="color: var(--primary-color); margin-bottom: 1rem;">Custom Dimensions</h4>
|
||||
<p>Order murals in any size. Simply provide your width and height measurements, and we'll print to exact specifications.</p>
|
||||
</div>
|
||||
<div style="background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);">
|
||||
<h4 style="color: var(--primary-color); margin-bottom: 1rem;">Non-Repeating Design</h4>
|
||||
<p>Unlike wallpapers, murals are single cohesive images perfect for accent walls. One stunning focal point for your space.</p>
|
||||
</div>
|
||||
<div style="background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);">
|
||||
<h4 style="color: var(--primary-color); margin-bottom: 1rem;">Premium Quality</h4>
|
||||
<p>High-resolution printing with vibrant colors and excellent durability. Professional installation guides included.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA SECTION -->
|
||||
<section class="section section--highlight">
|
||||
<div class="container" style="text-align: center;">
|
||||
<h2>Transform Your Space</h2>
|
||||
<p style="max-width: 600px; margin: 0 auto var(--spacing-lg); color: var(--text-primary);">
|
||||
Can't find the perfect mural? Our design experts can help you create a custom mural from your own image or concept.
|
||||
</p>
|
||||
<button class="btn btn--secondary">Request a Custom Mural</button>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
document.querySelectorAll('.filter-btn').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const filter = this.dataset.filter;
|
||||
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
|
||||
this.classList.add('active');
|
||||
|
||||
document.querySelectorAll('[data-category]').forEach(card => {
|
||||
if (filter === 'all' || card.dataset.category === filter) {
|
||||
card.style.display = '';
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
@@ -0,0 +1,248 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Order History')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
h1 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2.5rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
background: white;
|
||||
padding: 3rem;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
color: #666;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.orders-list {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.order-card {
|
||||
background: white;
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid var(--primary-color);
|
||||
}
|
||||
|
||||
.order-header {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.order-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.order-number {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 1.1rem;
|
||||
color: var(--primary-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.order-date {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.order-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 0.4rem 1rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.status-processing {
|
||||
background-color: #cfe2ff;
|
||||
color: #084298;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background-color: #d1e7dd;
|
||||
color: #0f5132;
|
||||
}
|
||||
|
||||
.order-total {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.total-amount {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 1.3rem;
|
||||
color: var(--primary-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.order-items {
|
||||
margin: 1rem 0;
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.item-qty {
|
||||
color: #666;
|
||||
margin: 0 1rem;
|
||||
}
|
||||
|
||||
.item-price {
|
||||
color: var(--primary-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.order-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.customer-info {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.customer-info strong {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.order-actions {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.btn-small {
|
||||
background-color: var(--accent-primary);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.9rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn-small:hover {
|
||||
background-color: #c09191;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.order-header {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.order-total {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<main class="container">
|
||||
<h1>Order History</h1>
|
||||
|
||||
@if($orders->count() > 0)
|
||||
<div class="orders-list">
|
||||
@foreach($orders as $order)
|
||||
<div class="order-card">
|
||||
<!-- Order Header -->
|
||||
<div class="order-header">
|
||||
<div class="order-info">
|
||||
<div class="order-number">{{ $order->order_number }}</div>
|
||||
<div class="order-date">{{ $order->created_at->format('M d, Y') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="order-status">
|
||||
<span class="status-badge status-{{ $order->status }}">
|
||||
{{ ucfirst($order->status) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="order-total">
|
||||
<div class="total-amount">${{ number_format($order->total, 2) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Items -->
|
||||
<div class="order-items">
|
||||
@foreach($order->items as $item)
|
||||
<div class="item">
|
||||
<span class="item-name">{{ $item->product->name }}</span>
|
||||
<span class="item-qty">Qty: {{ $item->quantity }}</span>
|
||||
<span class="item-price">${{ number_format($item->quantity * $item->price, 2) }}</span>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<!-- Order Footer -->
|
||||
<div class="order-footer">
|
||||
<div class="customer-info">
|
||||
<strong>{{ $order->customer_name }}</strong><br>
|
||||
{{ $order->customer_email }}
|
||||
</div>
|
||||
|
||||
<div class="order-actions">
|
||||
<button class="btn-small" onclick="printOrder({{ $order->id }})">Print</button>
|
||||
<a href="{{ route('product-detail', $order->items->first()->product) }}" class="btn-small">View Items</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<div class="empty-state">
|
||||
<p>No orders found. Start shopping today!</p>
|
||||
<a href="{{ route('wallpapers') }}" class="btn">Browse Products</a>
|
||||
</div>
|
||||
@endif
|
||||
</main>
|
||||
|
||||
<script>
|
||||
function printOrder(orderId) {
|
||||
window.print();
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
@@ -0,0 +1,228 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Order Confirmed')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
.success-container {
|
||||
background: white;
|
||||
padding: 3rem;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
font-size: 4rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2.5rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.order-details {
|
||||
background: #f9f9f9;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
margin: 2rem 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.detail-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-weight: 600;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.order-items {
|
||||
background: #f9f9f9;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
margin: 2rem 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.order-items h2 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 1.3rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.item-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.item-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-weight: 600;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.item-qty {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.item-price {
|
||||
font-weight: 600;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.total-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-top: 1.5rem;
|
||||
margin-top: 1rem;
|
||||
border-top: 2px solid var(--primary-color);
|
||||
font-weight: 600;
|
||||
font-size: 1.2rem;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-top: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.note {
|
||||
background: #d4e8d4;
|
||||
color: var(--primary-color);
|
||||
padding: 1rem;
|
||||
border-radius: 4px;
|
||||
margin: 2rem 0;
|
||||
border-left: 4px solid var(--primary-color);
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<main class="container">
|
||||
<div class="success-container">
|
||||
<div class="success-icon">✓</div>
|
||||
<h1>Order Confirmed!</h1>
|
||||
<p class="subtitle">Thank you for your purchase. Your order has been successfully received.</p>
|
||||
|
||||
<!-- Order Details -->
|
||||
<div class="order-details">
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">Order Number:</span>
|
||||
<span class="detail-value"><strong>{{ $order->order_number }}</strong></span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">Customer Name:</span>
|
||||
<span class="detail-value">{{ $order->customer_name }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">Email:</span>
|
||||
<span class="detail-value">{{ $order->customer_email }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">Shipping Address:</span>
|
||||
<span class="detail-value">{{ $order->shipping_address }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">Order Status:</span>
|
||||
<span class="detail-value">
|
||||
<strong style="color: var(--accent-primary); text-transform: capitalize;">{{ $order->status }}</strong>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Items -->
|
||||
<div class="order-items">
|
||||
<h2>Order Items</h2>
|
||||
@foreach($order->items as $item)
|
||||
<div class="item-row">
|
||||
<div class="item-info">
|
||||
<div class="item-name">{{ $item->product->name }}</div>
|
||||
<div class="item-qty">
|
||||
@php
|
||||
$stock = $item->printStock;
|
||||
$stockText = $stock ? "{$stock->name}" : "Standard";
|
||||
$stockCost = 0;
|
||||
|
||||
if ($stock) {
|
||||
$stockCost = $item->type === 'wallpaper' ? $stock->cost_per_meter : $stock->cost_per_m2;
|
||||
}
|
||||
@endphp
|
||||
|
||||
@if($item->type === 'wallpaper')
|
||||
Length: {{ $item->length }}m | Finish: {{ $stockText }}<br>
|
||||
<small>Stock Cost: R{{ number_format($stockCost, 2) }}/m</small>
|
||||
@elseif($item->type === 'mural')
|
||||
Dimensions: {{ $item->width }}m × {{ $item->height }}m ({{ number_format($item->width * $item->height, 2) }}m²) | Finish: {{ $stockText }}<br>
|
||||
<small>Stock Cost: R{{ number_format($stockCost, 2) }}/m²</small>
|
||||
@else
|
||||
<small>Price: R{{ number_format($stockCost, 2) }} per unit</small>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-price">
|
||||
R{{ number_format(
|
||||
$item->quantity * (
|
||||
$item->type === 'wallpaper'
|
||||
? $stockCost * $item->length
|
||||
: ($item->type === 'mural'
|
||||
? $stockCost * $item->width * $item->height
|
||||
: $stockCost
|
||||
)
|
||||
),
|
||||
2
|
||||
) }}
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
<div class="total-row">
|
||||
<span>Order Total:</span>
|
||||
<span>R{{ number_format($order->total, 2) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="note">
|
||||
<strong>🔔 What's Next?</strong><br>
|
||||
A confirmation email has been sent to <strong>{{ $order->customer_email }}</strong>. You'll receive updates about your order status and shipping information shortly.
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="actions">
|
||||
<a href="{{ route('wallpapers') }}" class="btn">Continue Shopping</a>
|
||||
<a href="{{ route('home') }}" class="btn btn--secondary">Back to Home</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
@endsection
|
||||
@@ -0,0 +1,733 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', $product->name . ' - Premium Custom Designs')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
.breadcrumb {
|
||||
margin-bottom: 2rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.breadcrumb a {
|
||||
color: var(--accent-primary);
|
||||
text-decoration: none;
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
|
||||
.product-section {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3rem;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.lightbox {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
|
||||
.lightbox.active {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.lightbox-content {
|
||||
position: relative;
|
||||
max-width: 90%;
|
||||
max-height: 90vh;
|
||||
}
|
||||
|
||||
.lightbox-image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: 85vh;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.lightbox-close {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 35px;
|
||||
color: white;
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.lightbox-close:hover {
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.lightbox-nav {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: white;
|
||||
font-size: 36px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
padding: 10px 15px;
|
||||
transition: color 0.2s;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.lightbox-nav:hover {
|
||||
color: var(--accent-primary);
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.lightbox-prev {
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
.lightbox-next {
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.lightbox-counter {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.product-info h1 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2.5rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.category-tag {
|
||||
display: inline-block;
|
||||
background-color: var(--accent-pink);
|
||||
color: white;
|
||||
padding: 0.4rem 1rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 900;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 2rem;
|
||||
color: var(--primary-color);
|
||||
font-weight: 600;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.stock-status {
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.stock-status.in-stock {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.stock-status.low-stock {
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.stock-status.out-of-stock {
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.description {
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
margin-bottom: 2rem;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.quantity-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.quantity-selector label {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.quantity-selector input {
|
||||
width: 80px;
|
||||
padding: 0.5rem;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.related-products {
|
||||
margin-top: 4rem;
|
||||
padding-top: 3rem;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.related-products h2 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 1rem;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #d4e8d4;
|
||||
color: var(--primary-color);
|
||||
border: 1px solid #a8d4a8;
|
||||
}
|
||||
|
||||
.calculator-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 2000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.calculator-modal.active {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.calculator-content {
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 12px;
|
||||
max-width: 500px;
|
||||
width: 90%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.calculator-close {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 20px;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.calculator-close:hover {
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.wall-schematic {
|
||||
background: var(--section-light-bg);
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
margin: 1.5rem 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wall-diagram {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
height: 150px;
|
||||
border: 3px solid var(--primary-color);
|
||||
position: relative;
|
||||
margin: 1rem auto;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.wall-label {
|
||||
position: absolute;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.wall-label.width {
|
||||
bottom: -25px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.wall-label.height {
|
||||
right: -60px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.calc-input-group {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.calc-input-group label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.calc-input-group input {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.calc-result {
|
||||
background: var(--accent-light);
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
margin-top: 1.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.calc-result h3 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
color: white;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.calc-result .result-value {
|
||||
font-size: 2.5rem;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
}
|
||||
|
||||
.calc-result small {
|
||||
display: block;
|
||||
margin-top: 0.5rem;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.product-section {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.product-info h1 {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.calculator-content {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<main class="container" style="padding-top: 20px;">
|
||||
<!-- Breadcrumb -->
|
||||
<!-- <div class="breadcrumb">
|
||||
<a href="{{ route('home') }}">Home</a> /
|
||||
<a href="{{ route('wallpapers') }}">Products</a> /
|
||||
<span>{{ $product->name }}</span>
|
||||
</div> -->
|
||||
|
||||
@if (session('success'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Product Section -->
|
||||
<section class="product-section">
|
||||
<div>
|
||||
@if($product->images->count() > 0)
|
||||
<img id="mainImage" src="{{ asset('storage/' . $product->images->first()->image_path) }}" alt="{{ $product->name }}" class="product-image">
|
||||
|
||||
@if($product->images->count() > 1)
|
||||
<div style="display: flex; gap: 0.5rem; margin-top: 1rem; overflow-x: auto;">
|
||||
@foreach($product->images as $image)
|
||||
<img
|
||||
src="{{ asset('storage/' . $image->image_path) }}"
|
||||
alt="{{ $product->name }}"
|
||||
class="product-thumbnail"
|
||||
onclick="document.getElementById('mainImage').src = '{{ asset('storage/' . $image->image_path) }}'"
|
||||
style="width: 80px; height: 80px; object-fit: cover; border-radius: 4px; cursor: pointer; border: 2px solid transparent; transition: border-color 0.2s; flex-shrink: 0;"
|
||||
onmouseover="this.style.borderColor = 'var(--accent-primary)'"
|
||||
onmouseout="this.style.borderColor = 'transparent'"
|
||||
>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@else
|
||||
<img id="mainImage" src="{{ $product->image }}" alt="{{ $product->name }}" class="product-image">
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="product-info">
|
||||
<h1>{{ $product->name }}</h1>
|
||||
<span class="category-tag">{{ $product->category->name }}</span>
|
||||
<!-- <div class="stock-status @if($product->stock > 10) in-stock @elseif($product->stock > 0) low-stock @else out-of-stock @endif">
|
||||
@if($product->stock > 0)
|
||||
<strong>{{ $product->stock }} in stock</strong>
|
||||
@else
|
||||
<strong>Out of stock</strong>
|
||||
@endif
|
||||
</div> -->
|
||||
|
||||
<p class="description">{{ $product->description }}</p>
|
||||
|
||||
@if($product->type === 'wallpaper')
|
||||
<div style="background: var(--section-light-bg); padding: 1rem; border-radius: 4px; margin-bottom: 1.5rem; font-size: 0.9rem;">
|
||||
<p><strong>Wallpaper Info:</strong> Sold per meter (10m rolls). Pattern is 1m wide x 2.7m high. For a wall height of 2.7m, you need 3m of wallpaper.</p>
|
||||
</div>
|
||||
@elseif($product->type === 'mural')
|
||||
<div style="background: var(--section-light-bg); padding: 1rem; border-radius: 4px; margin-bottom: 1.5rem; font-size: 0.9rem;">
|
||||
<p><strong>Mural Info:</strong> Sold per m² (square meter). Single image, non-repeating pattern. Perfect for accent walls.</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($product->stock > 0)
|
||||
<form action="{{ route('cart-add', $product) }}" method="POST">
|
||||
@csrf
|
||||
|
||||
<!-- Print Stock Selection -->
|
||||
<div class="quantity-selector" style="flex-direction: column; align-items: flex-start; gap: 0.5rem; margin-bottom: 2rem;">
|
||||
<label for="print_stock_id" style="font-weight: 600;">Select Print Stock:</label>
|
||||
<select id="print_stock_id" name="print_stock_id" required style="width: 100%; padding: 0.75rem; border: 1px solid #ddd; border-radius: 4px; font-size: 1rem;">
|
||||
@foreach($product->printStocks as $stock)
|
||||
<option value="{{ $stock->id }}"
|
||||
data-cost="{{ $product->type === 'wallpaper' ? $stock->cost_per_meter : $stock->cost_per_m2 }}"
|
||||
data-width="{{ $stock->width ?? 1 }}">
|
||||
{{ $stock->name }} ({{ $stock->width ?? 1 }}m wide) - R{{ $product->type === 'wallpaper' ? number_format($stock->cost_per_meter, 2) : number_format($stock->cost_per_m2, 2) }}/{{ $product->type === 'wallpaper' ? 'm' : 'm²' }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<small style="color: #666;">Base cost per {{ $product->type === 'wallpaper' ? 'meter' : 'm²' }} of print stock</small>
|
||||
</div>
|
||||
|
||||
@if($product->type === 'wallpaper')
|
||||
<!-- Calculator Button -->
|
||||
<div style="margin-bottom: 1.5rem;">
|
||||
<button type="button" class="btn btn--secondary" onclick="openCalculator()" style="width: 100%;">
|
||||
📐 Calculate Required Length
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="quantity-selector" style="flex-direction: column; align-items: flex-start; gap: 0.5rem;">
|
||||
<label for="length">Length Required (meters):</label>
|
||||
<input type="number" id="length" name="length" min="1" step="0.5" value="3" required style="width: 150px;">
|
||||
<small style="color: #666;">Recommended: Add 0.5m for pattern matching and trimming</small>
|
||||
</div>
|
||||
@elseif($product->type === 'mural')
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 2rem;">
|
||||
<div>
|
||||
<label for="width" style="display: block; font-weight: 600; margin-bottom: 0.5rem;">Width (meters):</label>
|
||||
<input type="number" id="width" name="width" min="0.5" step="0.1" value="2" required style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
|
||||
</div>
|
||||
<div>
|
||||
<label for="height" style="display: block; font-weight: 600; margin-bottom: 0.5rem;">Height (meters):</label>
|
||||
<input type="number" id="height" name="height" min="0.5" step="0.1" value="2.7" required style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Total Price Display -->
|
||||
<div style="background: var(--accent-light); padding: 1.5rem; border-radius: 20px; margin-bottom: 2rem;">
|
||||
<p style="margin: 0 0 0.5rem 0; color: black;">Estimated Total:</p>
|
||||
<div style="font-family: Abril fatface;font-size: 3rem; font-weight: 400; color: white;">R<span id="totalPrice">{{ number_format($product->price, 2) }}</span></div>
|
||||
<small style="color: #fff; display: block; margin-top: 0.5rem;" id="priceBreakdown"></small>
|
||||
</div>
|
||||
|
||||
<div class="btn-group" style="gap: 1rem;">
|
||||
<button type="submit" class="btn" style="flex: 1;">Add to Cart</button>
|
||||
<a href="{{ route('cart') }}" class="btn btn--secondary" style="flex: 1; text-align: center;">View Cart</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
const productType = 'wallpaper' === 'wallpaper' ? 'wallpaper' : 'mural';
|
||||
const basePrice = {{ $product->price }};
|
||||
const isWallpaper = {{ $product->type === 'wallpaper' ? 'true' : 'false' }};
|
||||
|
||||
function updatePrice() {
|
||||
const stockSelect = document.getElementById('print_stock_id');
|
||||
const selectedOption = stockSelect.options[stockSelect.selectedIndex];
|
||||
const stockCost = parseFloat(selectedOption.dataset.cost) || 0;
|
||||
|
||||
let totalCost = stockCost;
|
||||
let breakdown = '';
|
||||
|
||||
if (isWallpaper) {
|
||||
const length = parseFloat(document.getElementById('length').value) || 0;
|
||||
totalCost = stockCost * length;
|
||||
breakdown = `Stock: R${stockCost.toFixed(2)}/m × ${length}m`;
|
||||
} else {
|
||||
const width = parseFloat(document.getElementById('width').value) || 0;
|
||||
const height = parseFloat(document.getElementById('height').value) || 0;
|
||||
const m2 = width * height;
|
||||
totalCost = stockCost * m2;
|
||||
breakdown = `Stock: R${stockCost.toFixed(2)}/m² × ${m2.toFixed(2)}m²`;
|
||||
}
|
||||
|
||||
document.getElementById('totalPrice').textContent = totalCost.toFixed(2);
|
||||
document.getElementById('priceBreakdown').textContent = breakdown;
|
||||
}
|
||||
|
||||
document.getElementById('print_stock_id').addEventListener('change', updatePrice);
|
||||
if (isWallpaper) {
|
||||
document.getElementById('length').addEventListener('input', updatePrice);
|
||||
} else {
|
||||
document.getElementById('width').addEventListener('input', updatePrice);
|
||||
document.getElementById('height').addEventListener('input', updatePrice);
|
||||
}
|
||||
|
||||
updatePrice();
|
||||
</script>
|
||||
@else
|
||||
<button class="btn" disabled style="background-color: #ccc; cursor: not-allowed;">Out of Stock</button>
|
||||
@endif
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Calculator Modal -->
|
||||
<div id="calculatorModal" class="calculator-modal">
|
||||
<div class="calculator-content">
|
||||
<span class="calculator-close" onclick="closeCalculator()">×</span>
|
||||
<h2 style="color: var(--primary-color); margin-bottom: 1rem; font-family: 'Abril Fatface', cursive;">Wallpaper Calculator</h2>
|
||||
|
||||
<div class="wall-schematic">
|
||||
<p style="margin-bottom: 1rem; font-size: 0.9rem; color: #666;">Enter your wall dimensions:</p>
|
||||
<div class="wall-diagram">
|
||||
<span class="wall-label width">Width</span>
|
||||
<span class="wall-label height">Height</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="calc-input-group">
|
||||
<label for="calc-wall-width">Wall Width (meters):</label>
|
||||
<input type="number" id="calc-wall-width" min="0.1" step="0.1" value="4" oninput="calculateWallpaper()">
|
||||
</div>
|
||||
|
||||
<div class="calc-input-group">
|
||||
<label for="calc-wall-height">Wall Height (meters):</label>
|
||||
<input type="number" id="calc-wall-height" min="0.1" step="0.1" value="2.7" oninput="calculateWallpaper()">
|
||||
</div>
|
||||
|
||||
<div class="calc-input-group">
|
||||
<label for="calc-wallpaper-width">Wallpaper Width (meters):</label>
|
||||
<div style="padding: 0.75rem; background: var(--section-light-bg); border-radius: 6px; font-size: 1rem; font-weight: 600; color: var(--primary-color);">
|
||||
<span id="calc-wallpaper-width">1</span>m
|
||||
</div>
|
||||
<small style="color: #666; display: block; margin-top: 0.25rem;">Width from selected print stock</small>
|
||||
</div>
|
||||
|
||||
<div class="calc-result" id="calcResult" style="display: none;">
|
||||
<h3>Required Length:</h3>
|
||||
<div class="result-value"><span id="calcResultValue">0</span>m</div>
|
||||
<small id="calcBreakdown"></small>
|
||||
</div>
|
||||
|
||||
<button class="btn" onclick="useCalculatedLength()" style="width: 100%; margin-top: 1rem;">
|
||||
Use This Length
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Lightbox Modal -->
|
||||
<div id="lightbox" class="lightbox">
|
||||
<div class="lightbox-content">
|
||||
<span class="lightbox-close" onclick="closeLightbox()">×</span>
|
||||
<span class="lightbox-nav lightbox-prev" onclick="prevImage()">‹</span>
|
||||
<img id="lightboxImage" class="lightbox-image" style="border-radius: 20px;" src="" alt="">
|
||||
<span class="lightbox-nav lightbox-next" onclick="nextImage()">›</span>
|
||||
<div class="lightbox-counter">
|
||||
<span id="imageCounter">1</span> / <span id="totalImages">1</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentImageIndex = 0;
|
||||
let allImages = [];
|
||||
|
||||
function initLightboxImages() {
|
||||
@if($product->images->count() > 0)
|
||||
allImages = [
|
||||
@foreach($product->images as $image)
|
||||
'{{ asset('storage/' . $image->image_path) }}',
|
||||
@endforeach
|
||||
];
|
||||
@else
|
||||
allImages = ['{{ $product->image }}'];
|
||||
@endif
|
||||
|
||||
document.getElementById('totalImages').textContent = allImages.length;
|
||||
}
|
||||
|
||||
function openLightbox(imageSrc) {
|
||||
currentImageIndex = allImages.indexOf(imageSrc);
|
||||
if (currentImageIndex === -1) {
|
||||
currentImageIndex = 0;
|
||||
}
|
||||
updateLightboxImage();
|
||||
document.getElementById('lightbox').classList.add('active');
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeLightbox() {
|
||||
document.getElementById('lightbox').classList.remove('active');
|
||||
document.body.style.overflow = 'auto';
|
||||
}
|
||||
|
||||
function nextImage() {
|
||||
currentImageIndex = (currentImageIndex + 1) % allImages.length;
|
||||
updateLightboxImage();
|
||||
}
|
||||
|
||||
function prevImage() {
|
||||
currentImageIndex = (currentImageIndex - 1 + allImages.length) % allImages.length;
|
||||
updateLightboxImage();
|
||||
}
|
||||
|
||||
function updateLightboxImage() {
|
||||
document.getElementById('lightboxImage').src = allImages[currentImageIndex];
|
||||
document.getElementById('imageCounter').textContent = currentImageIndex + 1;
|
||||
}
|
||||
|
||||
// Close lightbox when clicking outside the image
|
||||
document.getElementById('lightbox').addEventListener('click', function(event) {
|
||||
if (event.target === this) {
|
||||
closeLightbox();
|
||||
}
|
||||
});
|
||||
|
||||
// Close lightbox with Escape key
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.key === 'Escape') {
|
||||
closeLightbox();
|
||||
}
|
||||
// Navigate with arrow keys
|
||||
if (document.getElementById('lightbox').classList.contains('active')) {
|
||||
if (event.key === 'ArrowRight') {
|
||||
nextImage();
|
||||
}
|
||||
if (event.key === 'ArrowLeft') {
|
||||
prevImage();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Add click handler to main image
|
||||
document.getElementById('mainImage').addEventListener('click', function() {
|
||||
openLightbox(this.src);
|
||||
});
|
||||
|
||||
// Initialize lightbox images on page load
|
||||
initLightboxImages();
|
||||
|
||||
// Calculator functions
|
||||
function openCalculator() {
|
||||
// Update calculator width from selected print stock
|
||||
const stockSelect = document.getElementById('print_stock_id');
|
||||
const selectedOption = stockSelect.options[stockSelect.selectedIndex];
|
||||
const stockWidth = parseFloat(selectedOption.dataset.width) || 1;
|
||||
document.getElementById('calc-wallpaper-width').textContent = stockWidth;
|
||||
|
||||
document.getElementById('calculatorModal').classList.add('active');
|
||||
document.body.style.overflow = 'hidden';
|
||||
calculateWallpaper();
|
||||
}
|
||||
|
||||
function closeCalculator() {
|
||||
document.getElementById('calculatorModal').classList.remove('active');
|
||||
document.body.style.overflow = 'auto';
|
||||
}
|
||||
|
||||
function calculateWallpaper() {
|
||||
const wallWidth = parseFloat(document.getElementById('calc-wall-width').value) || 0;
|
||||
const wallHeight = parseFloat(document.getElementById('calc-wall-height').value) || 0;
|
||||
const wallpaperWidth = parseFloat(document.getElementById('calc-wallpaper-width').textContent) || 1;
|
||||
|
||||
if (wallWidth > 0 && wallHeight > 0 && wallpaperWidth > 0) {
|
||||
// Calculate number of strips needed
|
||||
const stripsNeeded = Math.ceil(wallWidth / wallpaperWidth);
|
||||
|
||||
// Calculate total length needed (strips × wall height)
|
||||
const totalLength = stripsNeeded * wallHeight;
|
||||
|
||||
// Add 10% for pattern matching and waste
|
||||
const withWaste = totalLength * 1.1;
|
||||
const finalLength = Math.ceil(withWaste * 2) / 2; // Round up to nearest 0.5m
|
||||
|
||||
// Display results
|
||||
document.getElementById('calcResultValue').textContent = finalLength.toFixed(1);
|
||||
document.getElementById('calcBreakdown').innerHTML =
|
||||
`${stripsNeeded} strips × ${wallHeight}m height = ${totalLength.toFixed(1)}m<br>` +
|
||||
`+ 10% waste allowance = ${finalLength.toFixed(1)}m total`;
|
||||
document.getElementById('calcResult').style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function useCalculatedLength() {
|
||||
const calculatedLength = parseFloat(document.getElementById('calcResultValue').textContent);
|
||||
document.getElementById('length').value = calculatedLength;
|
||||
closeCalculator();
|
||||
updatePrice();
|
||||
}
|
||||
|
||||
// Close calculator when clicking outside
|
||||
document.getElementById('calculatorModal').addEventListener('click', function(event) {
|
||||
if (event.target === this) {
|
||||
closeCalculator();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Related Products -->
|
||||
@if($product->category->products->count() > 1)
|
||||
<section class="related-products" style="margin-bottom: 20px;">
|
||||
<h2>More from {{ $product->category->name }}</h2>
|
||||
<div class="grid grid--3">
|
||||
@foreach($product->category->products->where('id', '!=', $product->id)->take(3) as $relatedProduct)
|
||||
@include('components.product-card', ['product' => $relatedProduct])
|
||||
@endforeach
|
||||
</div>
|
||||
</section>
|
||||
@endif
|
||||
</main>
|
||||
@endsection
|
||||
@@ -0,0 +1,255 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Wallpapers - Premium Custom Designs')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
.hero-slider {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 20px;
|
||||
margin: 20px;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.hero-slide {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
transition: opacity 0.8s ease-in-out;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.hero-slide.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.hero-slide-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3rem;
|
||||
align-items: center;
|
||||
padding: 6rem 5rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hero-dots {
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.hero-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.hero-dot.active {
|
||||
background: white;
|
||||
width: 32px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.hero-cta {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.hero-slider:hover .hero-dot {
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.hero-slider:hover .hero-dot.active {
|
||||
background: white;
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<!-- HERO SECTION -->
|
||||
<section class="section" id="hero">
|
||||
<div class="hero-slider">
|
||||
@forelse($heroImages as $index => $image)
|
||||
<div class="hero-slide @if($index === 0) active @endif" style="background-image: url('{{ asset('storage/' . $image->image_path) }}');">
|
||||
<div class="hero-slide-content">
|
||||
<div>
|
||||
<div class="hero-content">
|
||||
<h1 style="color: white; font-size: 3rem;">{{ $image->title }}</h1>
|
||||
@if($image->description)
|
||||
<p style="color: rgba(255, 255, 255, 0.9); font-size: 1.1rem; max-width: 95%;">{{ $image->description }}</p>
|
||||
@endif
|
||||
<div class="hero-cta">
|
||||
@if($image->button_text && $image->button_link)
|
||||
@if(str_starts_with($image->button_link, '#'))
|
||||
<button class="btn" onclick="document.getElementById('{{ substr($image->button_link, 1) }}').scrollIntoView({behavior: 'smooth'})">{{ $image->button_text }}</button>
|
||||
@else
|
||||
<a href="{{ $image->button_link }}" class="btn">{{ $image->button_text }}</a>
|
||||
@endif
|
||||
@else
|
||||
<button class="btn" onclick="document.getElementById('wallpaper-grid').scrollIntoView({behavior: 'smooth'})">Browse Wallpapers</button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<!-- Fallback hero image if none are configured in admin -->
|
||||
<div class="hero-slide active" style="background: linear-gradient(to right, rgba(45, 80, 71, 0.7), rgba(45, 80, 71, 0.5)), url('https://images.unsplash.com/photo-1552321554-5fefe8c9ef14?w=1200&q=80') center/cover no-repeat;">
|
||||
<div class="hero-slide-content">
|
||||
<div>
|
||||
<div class="hero-content">
|
||||
<h1 style="color: white; font-size: 3rem;">Premium Custom Wallpapers</h1>
|
||||
<p style="color: rgba(255, 255, 255, 0.95); font-size: 1.1rem;">Transform your spaces with our carefully curated collection of high-quality wallpapers. From botanical motifs to contemporary geometric patterns, each design is crafted with precision and printed to perfection.</p>
|
||||
<div class="hero-cta">
|
||||
<button class="btn" onclick="document.getElementById('wallpaper-grid').scrollIntoView({behavior: 'smooth'})">Browse Wallpapers</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
@endforelse
|
||||
|
||||
<div class="hero-dots">
|
||||
@forelse($heroImages as $index => $image)
|
||||
<div class="hero-dot @if($index === 0) active @endif" data-slide="{{ $index }}"></div>
|
||||
@empty
|
||||
<div class="hero-dot active" data-slide="0"></div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const slides = document.querySelectorAll('.hero-slide');
|
||||
const dots = document.querySelectorAll('.hero-dot');
|
||||
const slider = document.querySelector('.hero-slider');
|
||||
let currentSlide = 0;
|
||||
let autoAdvanceInterval;
|
||||
|
||||
function showSlide(n) {
|
||||
if (slides.length === 0) return;
|
||||
slides.forEach(s => s.classList.remove('active'));
|
||||
dots.forEach(d => d.classList.remove('active'));
|
||||
currentSlide = (n + slides.length) % slides.length;
|
||||
slides[currentSlide].classList.add('active');
|
||||
dots[currentSlide].classList.add('active');
|
||||
}
|
||||
|
||||
function startAutoAdvance() {
|
||||
autoAdvanceInterval = setInterval(() => {
|
||||
showSlide(currentSlide + 1);
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function resetAutoAdvance() {
|
||||
clearInterval(autoAdvanceInterval);
|
||||
startAutoAdvance();
|
||||
}
|
||||
|
||||
dots.forEach(dot => {
|
||||
dot.addEventListener('click', () => {
|
||||
showSlide(parseInt(dot.getAttribute('data-slide')));
|
||||
resetAutoAdvance();
|
||||
});
|
||||
});
|
||||
|
||||
slider.addEventListener('mouseenter', () => clearInterval(autoAdvanceInterval));
|
||||
slider.addEventListener('mouseleave', startAutoAdvance);
|
||||
|
||||
startAutoAdvance();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<!-- WALLPAPER GRID -->
|
||||
<section class="section" id="wallpaper-grid" style="padding: 2rem 0;">
|
||||
<div class="container">
|
||||
<div style="display: flex; gap: 2rem; justify-content: space-between; align-items: center; flex-wrap: wrap; margin-bottom: 2rem;">
|
||||
<div>
|
||||
<h3>All Wallpapers</h3>
|
||||
<p style="color: var(--text-secondary);">Showing all designs</p>
|
||||
</div>
|
||||
<div style="display: flex; gap: 1rem;">
|
||||
<select style="padding: 8px 12px; border: 1px solid var(--border-color); border-radius: 4px; font-size: 0.9rem;">
|
||||
<option>Sort by: Featured</option>
|
||||
<option>Newest</option>
|
||||
<option>Price: Low to High</option>
|
||||
<option>Price: High to Low</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 2rem;">
|
||||
<button class="filter-btn active" data-filter="all">All</button>
|
||||
<button class="filter-btn" data-filter="botanical">Botanical</button>
|
||||
<button class="filter-btn" data-filter="vintage">Vintage</button>
|
||||
<button class="filter-btn" data-filter="modern">Modern</button>
|
||||
<button class="filter-btn" data-filter="geometric">Geometric</button>
|
||||
<button class="filter-btn" data-filter="texture">Texture</button>
|
||||
<button class="filter-btn" data-filter="floral">Floral</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="grid grid--3">
|
||||
@forelse($products as $product)
|
||||
@include('components.product-card', ['product' => $product])
|
||||
@empty
|
||||
<p>No products available</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA SECTION -->
|
||||
<section class="section section--highlight">
|
||||
<div class="container" style="text-align: center;">
|
||||
<h2>Need Help Choosing?</h2>
|
||||
<p style="max-width: 600px; margin: 0 auto var(--spacing-lg); color: var(--text-primary);">
|
||||
Schedule a free consultation with our design experts. We'll help you find the perfect wallpaper for your space.
|
||||
</p>
|
||||
<button class="btn btn--secondary">Book a Free Consultation</button>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
document.querySelectorAll('.filter-btn').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const filter = this.dataset.filter;
|
||||
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
|
||||
this.classList.add('active');
|
||||
|
||||
document.querySelectorAll('[data-category]').forEach(card => {
|
||||
if (filter === 'all' || card.dataset.category === filter) {
|
||||
card.style.display = '';
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user