crw-dev commited on
Commit
33902ad
·
verified ·
1 Parent(s): 902d573

Upload 7 files

Browse files
Dockerfile ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python runtime as the base image
2
+ FROM python:3.10-slim
3
+
4
+ # Set the working directory in the container
5
+ WORKDIR /app
6
+
7
+ # Copy the requirements file into the container
8
+ COPY requirements.txt .
9
+
10
+ # Install the required packages
11
+ RUN pip install --no-cache-dir -r requirements.txt
12
+
13
+ # Copy the rest of the application code
14
+ COPY . .
15
+
16
+ # Set environment variables
17
+ ENV FLASK_APP=app.py
18
+ ENV FLASK_RUN_HOST=0.0.0.0
19
+ ENV FLASK_ENV=production
20
+
21
+ # Expose the port the app runs on
22
+ EXPOSE 7860
23
+
24
+ # Run the application
25
+ CMD ["gunicorn", "--bind", "0.0.0.0:7860", "app:app"]
26
+
27
+ # Print the contents of the current directory
28
+ RUN ls -la
29
+
30
+ # Print the contents of the app.py file
31
+ RUN cat app.py
app.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request, redirect, url_for, jsonify
2
+ from supabase import create_client, Client
3
+ from dotenv import load_dotenv
4
+ import os
5
+
6
+ load_dotenv()
7
+
8
+ app = Flask(__name__)
9
+
10
+ SUPABASE_URL = os.getenv('SUPABASE_URL')
11
+ SUPABASE_KEY = os.getenv('SUPABASE_KEY')
12
+ supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
13
+
14
+ @app.route('/')
15
+ def home():
16
+ return render_template('home.html')
17
+
18
+ @app.route('/products')
19
+ def products():
20
+ response = supabase.table('products').select('*').execute()
21
+ products = response.data
22
+ return render_template('product_list.html', products=products)
23
+
24
+ @app.route('/products/<int:product_id>')
25
+ def product_detail(product_id):
26
+ response = supabase.table('products').select('*').eq('id', product_id).execute()
27
+ if response.data:
28
+ product = response.data[0]
29
+ return render_template('product_detail.html', product=product)
30
+ else:
31
+ return "Product not found", 404
32
+
33
+ if __name__ == '__main__':
34
+ app.run(debug=True, port=5000)
35
+
36
+
requirements.txt ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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/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
+