crw-dev commited on
Commit
9249145
·
verified ·
1 Parent(s): 64c5ea0

Upload 10 files

Browse files
app.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request, redirect, url_for, jsonify, session
2
+ from supabase import create_client, Client
3
+ from dotenv import load_dotenv
4
+ import os
5
+
6
+ load_dotenv()
7
+ # Initialize Flask app
8
+ app = Flask(__name__)
9
+ app.secret_key = os.urandom(24)
10
+
11
+
12
+ SUPABASE_URL = os.getenv('SUPABASE_URL')
13
+ SUPABASE_KEY = os.getenv('SUPABASE_KEY')
14
+ supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
15
+
16
+
17
+ # Admin credentials (for simplicity, hardcoded; use env vars in production)
18
+ ADMIN_USERNAME = os.getenv('ADMIN_USERNAME', 'default_admin')
19
+ ADMIN_PASSWORD = os.getenv('ADMIN_PASSWORD', 'default_password')
20
+ # Home Page Route
21
+ @app.route('/')
22
+ def home():
23
+ return render_template('home.html')
24
+
25
+ # Product List Page Route
26
+ @app.route('/products')
27
+ def products():
28
+ response = supabase.table('products').select('*').execute()
29
+ products = response.data
30
+ return render_template('product_list.html', products=products)
31
+
32
+ # Product Detail Page Route
33
+ @app.route('/products/<int:product_id>')
34
+ def product_detail(product_id):
35
+ response = supabase.table('products').select('*').eq('id', product_id).execute()
36
+ if response.data:
37
+ product = response.data[0]
38
+ return render_template('product_detail.html', product=product)
39
+ else:
40
+ return "Product not found", 404
41
+
42
+ # Admin Login Page Route
43
+ @app.route('/admin/login', methods=['GET', 'POST'])
44
+ def admin_login():
45
+ if request.method == 'POST':
46
+ username = request.form['username']
47
+ password = request.form['password']
48
+ if username == ADMIN_USERNAME and password == ADMIN_PASSWORD:
49
+ session['admin_logged_in'] = True
50
+ return redirect(url_for('admin_dashboard'))
51
+ else:
52
+ return "Invalid credentials", 401
53
+ return render_template('admin_login.html')
54
+
55
+ # Admin Dashboard Route
56
+ @app.route('/admin')
57
+ def admin_dashboard():
58
+ if not session.get('admin_logged_in'):
59
+ return redirect(url_for('admin_login'))
60
+ response = supabase.table('products').select('*').execute()
61
+ products = response.data
62
+ return render_template('admin_dashboard.html', products=products)
63
+
64
+ # Add Product Route
65
+ @app.route('/admin/add', methods=['GET', 'POST'])
66
+ def add_product():
67
+ if not session.get('admin_logged_in'):
68
+ return redirect(url_for('admin_login'))
69
+ if request.method == 'POST':
70
+ name = request.form['name']
71
+ price = request.form['price']
72
+ details = request.form['details']
73
+ image_link = request.form['image_link']
74
+ whatsapp_link = request.form['whatsapp_link']
75
+ supabase.table('products').insert({
76
+ 'name': name,
77
+ 'price': price,
78
+ 'details': details,
79
+ 'image_link': image_link,
80
+ 'whatsapp_link': whatsapp_link
81
+ }).execute()
82
+ return redirect(url_for('admin_dashboard'))
83
+ return render_template('add_product.html')
84
+
85
+ # Edit Product Route
86
+ @app.route('/admin/edit/<int:product_id>', methods=['GET', 'POST'])
87
+ def edit_product(product_id):
88
+ if not session.get('admin_logged_in'):
89
+ return redirect(url_for('admin_login'))
90
+ if request.method == 'POST':
91
+ name = request.form['name']
92
+ price = request.form['price']
93
+ details = request.form['details']
94
+ image_link = request.form['image_link']
95
+ whatsapp_link = request.form['whatsapp_link']
96
+ supabase.table('products').update({
97
+ 'name': name,
98
+ 'price': price,
99
+ 'details': details,
100
+ 'image_link': image_link,
101
+ 'whatsapp_link': whatsapp_link
102
+ }).eq('id', product_id).execute()
103
+ return redirect(url_for('admin_dashboard'))
104
+ response = supabase.table('products').select('*').eq('id', product_id).execute()
105
+ if response.data:
106
+ product = response.data[0]
107
+ return render_template('edit_product.html', product=product)
108
+ else:
109
+ return "Product not found", 404
110
+
111
+ # Delete Product Route
112
+ @app.route('/admin/delete/<int:product_id>', methods=['POST'])
113
+ def delete_product(product_id):
114
+ if not session.get('admin_logged_in'):
115
+ return redirect(url_for('admin_login'))
116
+ supabase.table('products').delete().eq('id', product_id).execute()
117
+ return redirect(url_for('admin_dashboard'))
118
+
119
+ # Admin Logout Route
120
+ @app.route('/admin/logout')
121
+ def admin_logout():
122
+ session.pop('admin_logged_in', None)
123
+ return redirect(url_for('admin_login'))
124
+
125
+ # Main function
126
+ if __name__ == '__main__':
127
+ app.run(debug=True)
128
+
requirements.txt CHANGED
@@ -1,45 +0,0 @@
1
- aiohappyeyeballs==2.4.4
2
- aiohttp==3.11.11
3
- aiosignal==1.3.2
4
- annotated-types==0.7.0
5
- anyio==4.7.0
6
- async-timeout==5.0.1
7
- attrs==24.3.0
8
- blinker==1.9.0
9
- certifi==2024.12.14
10
- click==8.1.8
11
- deprecation==2.1.0
12
- exceptiongroup==1.2.2
13
- Flask==3.1.0
14
- frozenlist==1.5.0
15
- gotrue==2.11.0
16
- gunicorn==23.0.0
17
- h11==0.14.0
18
- h2==4.1.0
19
- hpack==4.0.0
20
- httpcore==1.0.7
21
- httpx==0.27.2
22
- hyperframe==6.0.1
23
- idna==3.10
24
- itsdangerous==2.2.0
25
- Jinja2==3.1.5
26
- MarkupSafe==3.0.2
27
- multidict==6.1.0
28
- packaging==24.2
29
- postgrest==0.18.0
30
- propcache==0.2.1
31
- pydantic==2.10.4
32
- pydantic_core==2.27.2
33
- python-dateutil==2.9.0.post0
34
- python-dotenv==1.0.1
35
- realtime==2.0.6
36
- six==1.17.0
37
- sniffio==1.3.1
38
- storage3==0.9.0
39
- StrEnum==0.4.15
40
- supabase==2.10.0
41
- supafunc==0.7.0
42
- typing_extensions==4.12.2
43
- websockets==13.1
44
- Werkzeug==3.1.3
45
- yarl==1.18.3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
static/styles.css ADDED
@@ -0,0 +1,406 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Colorful Wooden Nameplate E-commerce Stylesheet */
2
+
3
+ /* Import Google Fonts */
4
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&family=Playfair+Display:wght@700&display=swap');
5
+
6
+ /* Reset and base styles */
7
+ * {
8
+ margin: 0;
9
+ padding: 0;
10
+ box-sizing: border-box;
11
+ }
12
+
13
+ :root {
14
+ --color-wood-dark: #8B4513;
15
+ --color-wood-light: #DEB887;
16
+ --color-accent-1: #FF6B6B;
17
+ --color-accent-2: #4ECDC4;
18
+ --color-accent-3: #FFA500;
19
+ --color-text: #333;
20
+ --color-background: #FFF8E7;
21
+ }
22
+
23
+ body {
24
+ font-family: 'Poppins', sans-serif;
25
+ line-height: 1.6;
26
+ color: var(--color-text);
27
+ background-color: var(--color-background);
28
+ }
29
+
30
+ .container {
31
+ max-width: 1200px;
32
+ margin: 0 auto;
33
+ padding: 0 20px;
34
+ }
35
+
36
+ /* Typography */
37
+ h1, h2, h3 {
38
+ font-family: 'Playfair Display', serif;
39
+ margin-bottom: 1rem;
40
+ color: var(--color-wood-dark);
41
+ }
42
+
43
+ h1 {
44
+ font-size: 3rem;
45
+ font-weight: 700;
46
+ }
47
+
48
+ h2 {
49
+ font-size: 2.5rem;
50
+ font-weight: 700;
51
+ }
52
+
53
+ p {
54
+ margin-bottom: 1rem;
55
+ }
56
+
57
+ a {
58
+ color: var(--color-wood-dark);
59
+ text-decoration: none;
60
+ transition: color 0.3s ease;
61
+ }
62
+
63
+ a:hover {
64
+ color: var(--color-accent-1);
65
+ }
66
+
67
+ /* Header */
68
+ header {
69
+ background-color: var(--color-wood-light);
70
+ padding: 1rem 0;
71
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
72
+ }
73
+
74
+ nav ul {
75
+ list-style-type: none;
76
+ display: flex;
77
+ justify-content: center;
78
+ }
79
+
80
+ nav ul li {
81
+ margin: 0 1rem;
82
+ }
83
+
84
+ nav ul li a {
85
+ font-weight: 600;
86
+ text-transform: uppercase;
87
+ letter-spacing: 0.5px;
88
+ color: var(--color-wood-dark);
89
+ position: relative;
90
+ }
91
+
92
+ nav ul li a::after {
93
+ content: '';
94
+ position: absolute;
95
+ width: 100%;
96
+ height: 2px;
97
+ bottom: -5px;
98
+ left: 0;
99
+ background-color: var(--color-accent-1);
100
+ transform: scaleX(0);
101
+ transition: transform 0.3s ease;
102
+ }
103
+
104
+ nav ul li a:hover::after {
105
+ transform: scaleX(1);
106
+ }
107
+
108
+ /* Main content */
109
+ main {
110
+ padding: 2rem 0;
111
+ }
112
+
113
+ /* Home page */
114
+ .hero {
115
+ text-align: center;
116
+ padding: 4rem 0;
117
+ background-color: var(--color-wood-light);
118
+ position: relative;
119
+ overflow: hidden;
120
+ }
121
+
122
+ .hero::before {
123
+ content: '';
124
+ position: absolute;
125
+ top: 0;
126
+ left: 0;
127
+ right: 0;
128
+ bottom: 0;
129
+ background-image: url('https://images.unsplash.com/photo-1610505460324-989d7439edb8?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80');
130
+ background-size: cover;
131
+ background-position: center;
132
+ opacity: 0.2;
133
+ z-index: 0;
134
+ }
135
+
136
+ .hero-content {
137
+ position: relative;
138
+ z-index: 1;
139
+ }
140
+
141
+ .hero h1 {
142
+ font-size: 4rem;
143
+ margin-bottom: 1.5rem;
144
+ color: var(--color-wood-dark);
145
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
146
+ }
147
+
148
+ .cta-button {
149
+ display: inline-block;
150
+ background-color: var(--color-accent-1);
151
+ color: #fff;
152
+ padding: 0.75rem 1.5rem;
153
+ border-radius: 50px;
154
+ font-weight: 600;
155
+ text-transform: uppercase;
156
+ letter-spacing: 0.5px;
157
+ transition: all 0.3s ease;
158
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
159
+ }
160
+
161
+ .cta-button:hover {
162
+ background-color: var(--color-wood-dark);
163
+ color: #fff;
164
+ transform: translateY(-2px);
165
+ box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
166
+ }
167
+
168
+ /* Product list */
169
+ .product-list {
170
+ display: grid;
171
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
172
+ gap: 2rem;
173
+ }
174
+
175
+ .product-card {
176
+ background-color: #fff;
177
+ border-radius: 10px;
178
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
179
+ overflow: hidden;
180
+ transition: all 0.3s ease;
181
+ position: relative;
182
+ }
183
+
184
+ .product-card:hover {
185
+ transform: translateY(-5px);
186
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
187
+ }
188
+
189
+ .product-card img {
190
+ width: 100%;
191
+ height: 200px;
192
+ object-fit: cover;
193
+ }
194
+
195
+ .product-card-content {
196
+ padding: 1.5rem;
197
+ }
198
+
199
+ .product-card h2 {
200
+ font-size: 1.5rem;
201
+ margin-bottom: 0.5rem;
202
+ color: var(--color-wood-dark);
203
+ }
204
+
205
+ .product-card .price {
206
+ font-weight: 600;
207
+ color: var(--color-accent-3);
208
+ font-size: 1.25rem;
209
+ margin-bottom: 1rem;
210
+ }
211
+
212
+ /* Product detail */
213
+ .product-detail {
214
+ display: flex;
215
+ gap: 2rem;
216
+ align-items: flex-start;
217
+ background-color: #fff;
218
+ border-radius: 10px;
219
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
220
+ padding: 2rem;
221
+ }
222
+
223
+ .product-detail img {
224
+ width: 50%;
225
+ max-width: 500px;
226
+ border-radius: 10px;
227
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
228
+ }
229
+
230
+ .product-info {
231
+ flex: 1;
232
+ }
233
+
234
+ .product-info h1 {
235
+ margin-bottom: 0.5rem;
236
+ color: var(--color-wood-dark);
237
+ }
238
+
239
+ .product-info .price {
240
+ font-size: 1.5rem;
241
+ font-weight: 600;
242
+ color: var(--color-accent-3);
243
+ margin-bottom: 1rem;
244
+ }
245
+
246
+ .product-info .details {
247
+ margin-bottom: 1.5rem;
248
+ line-height: 1.8;
249
+ }
250
+
251
+ .whatsapp-button {
252
+ display: inline-block;
253
+ background-color: #25d366;
254
+ color: #fff;
255
+ padding: 0.75rem 1.5rem;
256
+ border-radius: 50px;
257
+ font-weight: 600;
258
+ text-transform: uppercase;
259
+ letter-spacing: 0.5px;
260
+ transition: all 0.3s ease;
261
+ margin-right: 1rem;
262
+ }
263
+
264
+ .whatsapp-button:hover {
265
+ background-color: #128c7e;
266
+ color: #fff;
267
+ transform: translateY(-2px);
268
+ }
269
+
270
+ /* Forms */
271
+ form {
272
+ background-color: #fff;
273
+ padding: 2rem;
274
+ border-radius: 10px;
275
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
276
+ }
277
+
278
+ .form-group {
279
+ margin-bottom: 1.5rem;
280
+ }
281
+
282
+ label {
283
+ display: block;
284
+ margin-bottom: 0.5rem;
285
+ font-weight: 600;
286
+ color: var(--color-wood-dark);
287
+ }
288
+
289
+ input[type="text"],
290
+ input[type="password"],
291
+ textarea {
292
+ width: 100%;
293
+ padding: 0.75rem;
294
+ border: 2px solid var(--color-wood-light);
295
+ border-radius: 5px;
296
+ font-family: inherit;
297
+ font-size: inherit;
298
+ transition: border-color 0.3s ease;
299
+ }
300
+
301
+ input[type="text"]:focus,
302
+ input[type="password"]:focus,
303
+ textarea:focus {
304
+ outline: none;
305
+ border-color: var(--color-accent-2);
306
+ }
307
+
308
+ button[type="submit"] {
309
+ background-color: var(--color-accent-2);
310
+ color: #fff;
311
+ padding: 0.75rem 1.5rem;
312
+ border: none;
313
+ border-radius: 50px;
314
+ font-weight: 600;
315
+ text-transform: uppercase;
316
+ letter-spacing: 0.5px;
317
+ cursor: pointer;
318
+ transition: all 0.3s ease;
319
+ }
320
+
321
+ button[type="submit"]:hover {
322
+ background-color: var(--color-wood-dark);
323
+ transform: translateY(-2px);
324
+ }
325
+
326
+ /* Admin dashboard */
327
+ .admin-actions {
328
+ margin-bottom: 2rem;
329
+ }
330
+
331
+ .admin-product-list {
332
+ display: grid;
333
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
334
+ gap: 2rem;
335
+ }
336
+
337
+ .admin-product-card {
338
+ background-color: #fff;
339
+ border-radius: 10px;
340
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
341
+ overflow: hidden;
342
+ }
343
+
344
+ .admin-product-card img {
345
+ width: 100%;
346
+ height: 200px;
347
+ object-fit: cover;
348
+ }
349
+
350
+ .admin-product-card-content {
351
+ padding: 1.5rem;
352
+ }
353
+
354
+ .admin-actions-buttons {
355
+ display: flex;
356
+ justify-content: space-between;
357
+ margin-top: 1rem;
358
+ }
359
+
360
+ .edit-button,
361
+ .delete-button {
362
+ padding: 0.5rem 1rem;
363
+ border: none;
364
+ border-radius: 50px;
365
+ font-weight: 600;
366
+ text-transform: uppercase;
367
+ letter-spacing: 0.5px;
368
+ cursor: pointer;
369
+ transition: all 0.3s ease;
370
+ }
371
+
372
+ .edit-button {
373
+ background-color: var(--color-accent-2);
374
+ color: #fff;
375
+ }
376
+
377
+ .edit-button:hover {
378
+ background-color: var(--color-wood-dark);
379
+ }
380
+
381
+ .delete-button {
382
+ background-color: var(--color-accent-1);
383
+ color: #fff;
384
+ }
385
+
386
+ .delete-button:hover {
387
+ background-color: #c0392b;
388
+ }
389
+
390
+ /* Responsive design */
391
+ @media (max-width: 768px) {
392
+ .product-detail {
393
+ flex-direction: column;
394
+ }
395
+
396
+ .product-detail img {
397
+ width: 100%;
398
+ max-width: none;
399
+ }
400
+
401
+ .hero h1 {
402
+ font-size: 3rem;
403
+ }
404
+ }
405
+
406
+
templates/add_product.html ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <link rel="stylesheet" href="/static/styles.css">
7
+ <title>{{ 'Add Product' if not product else 'Edit Product' }} - Custom Wooden Nameplates</title>
8
+ </head>
9
+ <body>
10
+ <header>
11
+ <nav>
12
+ <ul>
13
+ <li><a href="/">Home</a></li>
14
+ <li><a href="/products">Products</a></li>
15
+ <li><a href="/admin">Admin Dashboard</a></li>
16
+ </ul>
17
+ </nav>
18
+ </header>
19
+ <main>
20
+ <div class="container">
21
+ <h1>{{ 'Add Product' if not product else 'Edit Product' }}</h1>
22
+ <form method="POST">
23
+ <div class="form-group">
24
+ <label for="name">Name</label>
25
+ <input type="text" id="name" name="name" value="{{ product.name if product else '' }}" required>
26
+ </div>
27
+ <div class="form-group">
28
+ <label for="price">Price</label>
29
+ <input type="text" id="price" name="price" value="{{ product.price if product else '' }}" required>
30
+ </div>
31
+ <div class="form-group">
32
+ <label for="details">Details</label>
33
+ <textarea id="details" name="details" required>{{ product.details if product else '' }}</textarea>
34
+ </div>
35
+ <div class="form-group">
36
+ <label for="image_link">Image Link</label>
37
+ <input type="text" id="image_link" name="image_link" value="{{ product.image_link if product else '' }}" required>
38
+ </div>
39
+ <div class="form-group">
40
+ <label for="whatsapp_link">WhatsApp Link</label>
41
+ <input type="text" id="whatsapp_link" name="whatsapp_link" value="{{ product.whatsapp_link if product else '' }}" required>
42
+ </div>
43
+ <button type="submit">{{ 'Add' if not product else 'Update' }}</button>
44
+ </form>
45
+ </div>
46
+ </main>
47
+ </body>
48
+ </html>
49
+
50
+
templates/admin_dashboard.html ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Admin Dashboard - Custom Wooden Nameplates</title>
7
+ <link rel="stylesheet" href="/static/styles.css">
8
+ </head>
9
+ <body>
10
+ <header>
11
+ <nav>
12
+ <ul>
13
+ <li><a href="/">Home</a></li>
14
+ <li><a href="/products">Products</a></li>
15
+ <li><a href="/admin/logout">Logout</a></li>
16
+ </ul>
17
+ </nav>
18
+ </header>
19
+ <main>
20
+ <div class="container">
21
+ <h1>Admin Dashboard</h1>
22
+ <div class="admin-actions">
23
+ <a href="/admin/add" class="cta-button">Add New Product</a>
24
+ </div>
25
+ <div class="admin-product-list">
26
+ {% for product in products %}
27
+ <div class="admin-product-card">
28
+ <img src="{{ product.image_link }}" alt="{{ product.name }}">
29
+ <div class="admin-product-card-content">
30
+ <h2>{{ product.name }}</h2>
31
+ <p class="price">{{ product.price }}</p>
32
+ <div class="admin-actions-buttons">
33
+ <a href="/admin/edit/{{ product.id }}" class="edit-button">Edit</a>
34
+ <form method="POST" action="/admin/delete/{{ product.id }}" style="display:inline;">
35
+ <button type="submit" class="delete-button">Delete</button>
36
+ </form>
37
+ </div>
38
+ </div>
39
+ </div>
40
+ {% endfor %}
41
+ </div>
42
+ </div>
43
+ </main>
44
+ </body>
45
+ </html>
46
+
47
+
templates/admin_login.html ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Admin Login - Custom Wooden Nameplates</title>
7
+ <link rel="stylesheet" href="/static/styles.css">
8
+ </head>
9
+ <body>
10
+ <main>
11
+ <div class="container">
12
+ <h1>Admin Login</h1>
13
+ <form method="POST">
14
+ <div class="form-group">
15
+ <label for="username">Username</label>
16
+ <input type="text" id="username" name="username" required>
17
+ </div>
18
+ <div class="form-group">
19
+ <label for="password">Password</label>
20
+ <input type="password" id="password" name="password" required>
21
+ </div>
22
+ <button type="submit">Login</button>
23
+ </form>
24
+ </div>
25
+ </main>
26
+ </body>
27
+ </html>
28
+
29
+
templates/edit_product.html ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <link rel="stylesheet" href="/static/styles.css">
7
+ <title>{{ 'Add Product' if not product else 'Edit Product' }} - Custom Wooden Nameplates</title>
8
+ </head>
9
+ <body>
10
+ <header>
11
+ <nav>
12
+ <ul>
13
+ <li><a href="/">Home</a></li>
14
+ <li><a href="/products">Products</a></li>
15
+ <li><a href="/admin">Admin Dashboard</a></li>
16
+ </ul>
17
+ </nav>
18
+ </header>
19
+ <main>
20
+ <div class="container">
21
+ <h1>{{ 'Add Product' if not product else 'Edit Product' }}</h1>
22
+ <form method="POST">
23
+ <div class="form-group">
24
+ <label for="name">Name</label>
25
+ <input type="text" id="name" name="name" value="{{ product.name if product else '' }}" required>
26
+ </div>
27
+ <div class="form-group">
28
+ <label for="price">Price</label>
29
+ <input type="text" id="price" name="price" value="{{ product.price if product else '' }}" required>
30
+ </div>
31
+ <div class="form-group">
32
+ <label for="details">Details</label>
33
+ <textarea id="details" name="details" required>{{ product.details if product else '' }}</textarea>
34
+ </div>
35
+ <div class="form-group">
36
+ <label for="image_link">Image Link</label>
37
+ <input type="text" id="image_link" name="image_link" value="{{ product.image_link if product else '' }}" required>
38
+ </div>
39
+ <div class="form-group">
40
+ <label for="whatsapp_link">WhatsApp Link</label>
41
+ <input type="text" id="whatsapp_link" name="whatsapp_link" value="{{ product.whatsapp_link if product else '' }}" required>
42
+ </div>
43
+ <button type="submit">{{ 'Add' if not product else 'Update' }}</button>
44
+ </form>
45
+ </div>
46
+ </main>
47
+ </body>
48
+ </html>
49
+
50
+
templates/home.html ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Custom Wooden Nameplates</title>
7
+ <link rel="stylesheet" href="/static/styles.css">
8
+ </head>
9
+ <body>
10
+ <header>
11
+ <nav>
12
+ <ul>
13
+ <li><a href="/">Home</a></li>
14
+ <li><a href="/products">Products</a></li>
15
+ </ul>
16
+ </nav>
17
+ </header>
18
+ <main>
19
+ <section class="hero">
20
+ <div class="container">
21
+ <div class="hero-content">
22
+ <h1>Custom Wooden Nameplates</h1>
23
+ <p>Personalized, handcrafted wooden nameplates for your home or office</p>
24
+ <a href="/products" class="cta-button">View Our Collection</a>
25
+ </div>
26
+ </div>
27
+ </section>
28
+ </main>
29
+ </body>
30
+ </html>
31
+
32
+
templates/product_detail.html ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <link rel="stylesheet" href="/static/styles.css">
7
+ <title>{{ product.name }} - Custom Wooden Nameplate</title>
8
+ </head>
9
+ <body>
10
+ <header>
11
+ <nav>
12
+ <ul>
13
+ <li><a href="/">Home</a></li>
14
+ <li><a href="/products">Products</a></li>
15
+ </ul>
16
+ </nav>
17
+ </header>
18
+ <main>
19
+ <div class="container">
20
+ <div class="product-detail">
21
+ <img src="{{ product.image_link }}" alt="{{ product.name }}">
22
+ <div class="product-info">
23
+ <h1>{{ product.name }}</h1>
24
+ <p class="price">{{ product.price }}</p>
25
+ <p class="details">{{ product.details }}</p>
26
+ <a href="{{ product.whatsapp_link }}" target="_blank" class="whatsapp-button">Buy on WhatsApp</a>
27
+ <a href="/products" class="cta-button">Back to Products</a>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </main>
32
+ </body>
33
+ </html>
34
+
35
+
templates/product_list.html ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Our Wooden Nameplates</title>
7
+ <link rel="stylesheet" href="/static/styles.css">
8
+ </head>
9
+ <body>
10
+ <header>
11
+ <nav>
12
+ <ul>
13
+ <li><a href="/">Home</a></li>
14
+ <li><a href="/products">Products</a></li>
15
+ </ul>
16
+ </nav>
17
+ </header>
18
+ <main>
19
+ <div class="container">
20
+ <h1>Our Wooden Nameplate Collection</h1>
21
+ <div class="product-list">
22
+ {% for product in products %}
23
+ <div class="product-card">
24
+ <img src="{{ product.image_link }}" alt="{{ product.name }}">
25
+ <div class="product-card-content">
26
+ <h2>{{ product.name }}</h2>
27
+ <p class="price">{{ product.price }}</p>
28
+ <a href="/products/{{ product.id }}" class="cta-button">View Details</a>
29
+ </div>
30
+ </div>
31
+ {% endfor %}
32
+ </div>
33
+ </div>
34
+ </main>
35
+ </body>
36
+ </html>
37
+
38
+