pull/1/head
parent
92ca0e870b
commit
d9d2b2c917
|
|
@ -0,0 +1,94 @@
|
|||
// State management
|
||||
let products = [];
|
||||
let cart = [];
|
||||
|
||||
// DOM Elements
|
||||
const productsContainer = document.getElementById('products-container');
|
||||
const cartItems = document.getElementById('cart-items');
|
||||
const cartTotal = document.getElementById('cart-total');
|
||||
const cartCount = document.getElementById('cart-count');
|
||||
|
||||
// Fetch products from API
|
||||
async function fetchProducts() {
|
||||
const response = await fetch('/api/products');
|
||||
products = await response.json();
|
||||
renderProducts();
|
||||
}
|
||||
|
||||
// Render products
|
||||
function renderProducts() {
|
||||
productsContainer.innerHTML = products.map(product => `
|
||||
<div class="product-card">
|
||||
<img src="${product.image}" alt="${product.name}">
|
||||
<h3>${product.name}</h3>
|
||||
<p>${product.description}</p>
|
||||
<p class="price">€${product.price.toFixed(2)}</p>
|
||||
<button onclick="addToCart(${product.id})">In den Warenkorb</button>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// Add to cart
|
||||
async function addToCart(productId) {
|
||||
const response = await fetch('/api/cart', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ productId })
|
||||
});
|
||||
cart = await response.json();
|
||||
updateCart();
|
||||
}
|
||||
|
||||
// Remove from cart
|
||||
async function removeFromCart(productId) {
|
||||
const response = await fetch(`/api/cart/${productId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
cart = await response.json();
|
||||
updateCart();
|
||||
}
|
||||
|
||||
// Update quantity
|
||||
async function updateQuantity(productId, quantity) {
|
||||
if (quantity < 1) return;
|
||||
|
||||
const response = await fetch(`/api/cart/${productId}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ quantity })
|
||||
});
|
||||
cart = await response.json();
|
||||
updateCart();
|
||||
}
|
||||
|
||||
// Update cart display
|
||||
function updateCart() {
|
||||
cartItems.innerHTML = cart.map(item => `
|
||||
<div class="cart-item">
|
||||
<div>
|
||||
<h4>${item.product.name}</h4>
|
||||
<div class="quantity-controls">
|
||||
<button onclick="updateQuantity(${item.productId}, ${item.quantity - 1})">-</button>
|
||||
<span>${item.quantity}</span>
|
||||
<button onclick="updateQuantity(${item.productId}, ${item.quantity + 1})">+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p>€${(item.product.price * item.quantity).toFixed(2)}</p>
|
||||
<button onclick="removeFromCart(${item.productId})">Entfernen</button>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
const total = cart.reduce((sum, item) => sum + (item.product.price * item.quantity), 0);
|
||||
cartTotal.innerHTML = `Gesamt: €${total.toFixed(2)}`;
|
||||
cartCount.innerHTML = cart.reduce((sum, item) => sum + item.quantity, 0);
|
||||
}
|
||||
|
||||
// Initialize
|
||||
fetchProducts();
|
||||
updateCart();
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Online Shop</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Online Shop</h1>
|
||||
<div id="cart-icon">
|
||||
🛒 <span id="cart-count">0</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div id="products-container"></div>
|
||||
<div id="cart-container">
|
||||
<h2>Warenkorb</h2>
|
||||
<div id="cart-items"></div>
|
||||
<div id="cart-total"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
header {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#cart-icon {
|
||||
cursor: pointer;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
main {
|
||||
max-width: 1200px;
|
||||
margin: 2rem auto;
|
||||
padding: 0 1rem;
|
||||
display: grid;
|
||||
grid-template-columns: 3fr 1fr;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
#products-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
background: white;
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.product-card img {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.product-card button {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.product-card button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
background: white;
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
#cart-total {
|
||||
margin-top: 1rem;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/* Add basic styles */
|
||||
.product-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
gap: 2rem;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Einfacher Online-Shop</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
||||
</head>
|
||||
<body class="bg-gray-100 min-h-screen">
|
||||
<header class="bg-white shadow-sm mb-8">
|
||||
<div class="container mx-auto px-4 py-6">
|
||||
<h1 class="text-3xl font-bold text-gray-900">Unser Shop</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container mx-auto px-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{% for product in products %}
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<img
|
||||
src="{{ product.image }}"
|
||||
alt="{{ product.name }}"
|
||||
class="w-full h-48 object-cover"
|
||||
>
|
||||
<div class="p-4">
|
||||
<h2 class="text-xl font-semibold mb-2">{{ product.name }}</h2>
|
||||
<p class="text-gray-600 text-lg mb-4">€{{ "%.2f"|format(product.price) }}</p>
|
||||
<button
|
||||
onclick="alert('Produkt wurde zum Warenkorb hinzugefügt!')"
|
||||
class="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-600 transition-colors"
|
||||
>
|
||||
In den Warenkorb
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue