pull/1/head
klara 2024-11-24 21:49:15 +01:00
parent 92ca0e870b
commit d9d2b2c917
5 changed files with 267 additions and 0 deletions

94
public/app.js 100644
View File

@ -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();

28
public/index.html 100644
View File

@ -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>

90
public/style.css 100644
View File

@ -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;
}

14
static/styles.css 100644
View File

@ -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);
}

View File

@ -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>