createsonline 0.1.26__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. createsonline/__init__.py +46 -0
  2. createsonline/admin/__init__.py +7 -0
  3. createsonline/admin/content.py +526 -0
  4. createsonline/admin/crud.py +805 -0
  5. createsonline/admin/field_builder.py +559 -0
  6. createsonline/admin/integration.py +482 -0
  7. createsonline/admin/interface.py +2562 -0
  8. createsonline/admin/model_creator.py +513 -0
  9. createsonline/admin/model_manager.py +388 -0
  10. createsonline/admin/modern_dashboard.py +498 -0
  11. createsonline/admin/permissions.py +264 -0
  12. createsonline/admin/user_forms.py +594 -0
  13. createsonline/ai/__init__.py +202 -0
  14. createsonline/ai/fields.py +1226 -0
  15. createsonline/ai/orm.py +325 -0
  16. createsonline/ai/services.py +1244 -0
  17. createsonline/app.py +506 -0
  18. createsonline/auth/__init__.py +8 -0
  19. createsonline/auth/management.py +228 -0
  20. createsonline/auth/models.py +552 -0
  21. createsonline/cli/__init__.py +5 -0
  22. createsonline/cli/commands/__init__.py +122 -0
  23. createsonline/cli/commands/database.py +416 -0
  24. createsonline/cli/commands/info.py +173 -0
  25. createsonline/cli/commands/initdb.py +218 -0
  26. createsonline/cli/commands/project.py +545 -0
  27. createsonline/cli/commands/serve.py +173 -0
  28. createsonline/cli/commands/shell.py +93 -0
  29. createsonline/cli/commands/users.py +148 -0
  30. createsonline/cli/main.py +2041 -0
  31. createsonline/cli/manage.py +274 -0
  32. createsonline/config/__init__.py +9 -0
  33. createsonline/config/app.py +2577 -0
  34. createsonline/config/database.py +179 -0
  35. createsonline/config/docs.py +384 -0
  36. createsonline/config/errors.py +160 -0
  37. createsonline/config/orm.py +43 -0
  38. createsonline/config/request.py +93 -0
  39. createsonline/config/settings.py +176 -0
  40. createsonline/data/__init__.py +23 -0
  41. createsonline/data/dataframe.py +925 -0
  42. createsonline/data/io.py +453 -0
  43. createsonline/data/series.py +557 -0
  44. createsonline/database/__init__.py +60 -0
  45. createsonline/database/abstraction.py +440 -0
  46. createsonline/database/assistant.py +585 -0
  47. createsonline/database/fields.py +442 -0
  48. createsonline/database/migrations.py +132 -0
  49. createsonline/database/models.py +604 -0
  50. createsonline/database.py +438 -0
  51. createsonline/http/__init__.py +28 -0
  52. createsonline/http/client.py +535 -0
  53. createsonline/ml/__init__.py +55 -0
  54. createsonline/ml/classification.py +552 -0
  55. createsonline/ml/clustering.py +680 -0
  56. createsonline/ml/metrics.py +542 -0
  57. createsonline/ml/neural.py +560 -0
  58. createsonline/ml/preprocessing.py +784 -0
  59. createsonline/ml/regression.py +501 -0
  60. createsonline/performance/__init__.py +19 -0
  61. createsonline/performance/cache.py +444 -0
  62. createsonline/performance/compression.py +335 -0
  63. createsonline/performance/core.py +419 -0
  64. createsonline/project_init.py +789 -0
  65. createsonline/routing.py +528 -0
  66. createsonline/security/__init__.py +34 -0
  67. createsonline/security/core.py +811 -0
  68. createsonline/security/encryption.py +349 -0
  69. createsonline/server.py +295 -0
  70. createsonline/static/css/admin.css +263 -0
  71. createsonline/static/css/common.css +358 -0
  72. createsonline/static/css/dashboard.css +89 -0
  73. createsonline/static/favicon.ico +0 -0
  74. createsonline/static/icons/icon-128x128.png +0 -0
  75. createsonline/static/icons/icon-128x128.webp +0 -0
  76. createsonline/static/icons/icon-16x16.png +0 -0
  77. createsonline/static/icons/icon-16x16.webp +0 -0
  78. createsonline/static/icons/icon-180x180.png +0 -0
  79. createsonline/static/icons/icon-180x180.webp +0 -0
  80. createsonline/static/icons/icon-192x192.png +0 -0
  81. createsonline/static/icons/icon-192x192.webp +0 -0
  82. createsonline/static/icons/icon-256x256.png +0 -0
  83. createsonline/static/icons/icon-256x256.webp +0 -0
  84. createsonline/static/icons/icon-32x32.png +0 -0
  85. createsonline/static/icons/icon-32x32.webp +0 -0
  86. createsonline/static/icons/icon-384x384.png +0 -0
  87. createsonline/static/icons/icon-384x384.webp +0 -0
  88. createsonline/static/icons/icon-48x48.png +0 -0
  89. createsonline/static/icons/icon-48x48.webp +0 -0
  90. createsonline/static/icons/icon-512x512.png +0 -0
  91. createsonline/static/icons/icon-512x512.webp +0 -0
  92. createsonline/static/icons/icon-64x64.png +0 -0
  93. createsonline/static/icons/icon-64x64.webp +0 -0
  94. createsonline/static/image/android-chrome-192x192.png +0 -0
  95. createsonline/static/image/android-chrome-512x512.png +0 -0
  96. createsonline/static/image/apple-touch-icon.png +0 -0
  97. createsonline/static/image/favicon-16x16.png +0 -0
  98. createsonline/static/image/favicon-32x32.png +0 -0
  99. createsonline/static/image/favicon.ico +0 -0
  100. createsonline/static/image/favicon.svg +17 -0
  101. createsonline/static/image/icon-128x128.png +0 -0
  102. createsonline/static/image/icon-128x128.webp +0 -0
  103. createsonline/static/image/icon-16x16.png +0 -0
  104. createsonline/static/image/icon-16x16.webp +0 -0
  105. createsonline/static/image/icon-180x180.png +0 -0
  106. createsonline/static/image/icon-180x180.webp +0 -0
  107. createsonline/static/image/icon-192x192.png +0 -0
  108. createsonline/static/image/icon-192x192.webp +0 -0
  109. createsonline/static/image/icon-256x256.png +0 -0
  110. createsonline/static/image/icon-256x256.webp +0 -0
  111. createsonline/static/image/icon-32x32.png +0 -0
  112. createsonline/static/image/icon-32x32.webp +0 -0
  113. createsonline/static/image/icon-384x384.png +0 -0
  114. createsonline/static/image/icon-384x384.webp +0 -0
  115. createsonline/static/image/icon-48x48.png +0 -0
  116. createsonline/static/image/icon-48x48.webp +0 -0
  117. createsonline/static/image/icon-512x512.png +0 -0
  118. createsonline/static/image/icon-512x512.webp +0 -0
  119. createsonline/static/image/icon-64x64.png +0 -0
  120. createsonline/static/image/icon-64x64.webp +0 -0
  121. createsonline/static/image/logo-header-h100.png +0 -0
  122. createsonline/static/image/logo-header-h100.webp +0 -0
  123. createsonline/static/image/logo-header-h200@2x.png +0 -0
  124. createsonline/static/image/logo-header-h200@2x.webp +0 -0
  125. createsonline/static/image/logo.png +0 -0
  126. createsonline/static/js/admin.js +274 -0
  127. createsonline/static/site.webmanifest +35 -0
  128. createsonline/static/templates/admin/base.html +87 -0
  129. createsonline/static/templates/admin/dashboard.html +217 -0
  130. createsonline/static/templates/admin/model_form.html +270 -0
  131. createsonline/static/templates/admin/model_list.html +202 -0
  132. createsonline/static/test_script.js +15 -0
  133. createsonline/static/test_styles.css +59 -0
  134. createsonline/static_files.py +365 -0
  135. createsonline/templates/404.html +100 -0
  136. createsonline/templates/admin_login.html +169 -0
  137. createsonline/templates/base.html +102 -0
  138. createsonline/templates/index.html +151 -0
  139. createsonline/templates.py +205 -0
  140. createsonline/testing.py +322 -0
  141. createsonline/utils.py +448 -0
  142. createsonline/validation/__init__.py +49 -0
  143. createsonline/validation/fields.py +598 -0
  144. createsonline/validation/models.py +504 -0
  145. createsonline/validation/validators.py +561 -0
  146. createsonline/views.py +184 -0
  147. createsonline-0.1.26.dist-info/METADATA +46 -0
  148. createsonline-0.1.26.dist-info/RECORD +152 -0
  149. createsonline-0.1.26.dist-info/WHEEL +5 -0
  150. createsonline-0.1.26.dist-info/entry_points.txt +2 -0
  151. createsonline-0.1.26.dist-info/licenses/LICENSE +21 -0
  152. createsonline-0.1.26.dist-info/top_level.txt +1 -0
@@ -0,0 +1,15 @@
1
+ console.log('🚀 CREATESONLINE v0.1.4 - Dynamic routing active!');
2
+
3
+ // Display feature announcement
4
+ setTimeout(() => {
5
+ const features = [
6
+ '✅ Automatic static file serving',
7
+ '✅ No manual route configuration',
8
+ '✅ Smart MIME type detection',
9
+ '✅ Built-in file caching',
10
+ '✅ Security: Path traversal protection'
11
+ ];
12
+
13
+ console.log('\n🎯 Dynamic Static File Routing Features:');
14
+ features.forEach(feature => console.log(` ${feature}`));
15
+ }, 100);
@@ -0,0 +1,59 @@
1
+ body {
2
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
3
+ max-width: 800px;
4
+ margin: 50px auto;
5
+ padding: 20px;
6
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
7
+ color: #fff;
8
+ }
9
+
10
+ .container {
11
+ background: rgba(255, 255, 255, 0.1);
12
+ backdrop-filter: blur(10px);
13
+ border-radius: 20px;
14
+ padding: 40px;
15
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
16
+ }
17
+
18
+ h1 {
19
+ font-size: 2.5em;
20
+ margin-bottom: 20px;
21
+ text-align: center;
22
+ }
23
+
24
+ h2 {
25
+ color: #ffd700;
26
+ margin-top: 0;
27
+ }
28
+
29
+ .feature-box {
30
+ background: rgba(255, 255, 255, 0.05);
31
+ border-left: 4px solid #ffd700;
32
+ padding: 20px;
33
+ margin-top: 30px;
34
+ border-radius: 10px;
35
+ }
36
+
37
+ ul {
38
+ list-style: none;
39
+ padding-left: 0;
40
+ }
41
+
42
+ li {
43
+ padding: 8px 0;
44
+ padding-left: 30px;
45
+ position: relative;
46
+ }
47
+
48
+ li::before {
49
+ content: "âœ"";
50
+ position: absolute;
51
+ left: 0;
52
+ color: #4ade80;
53
+ font-weight: bold;
54
+ }
55
+
56
+ p {
57
+ font-size: 1.2em;
58
+ line-height: 1.6;
59
+ }
@@ -0,0 +1,365 @@
1
+ # createsonline/static_files.py
2
+ """
3
+ CREATESONLINE Dynamic Static File Serving System
4
+
5
+ Automatically serves HTML, CSS, JS, and other static files
6
+ with intelligent MIME type detection and caching.
7
+ """
8
+
9
+ import os
10
+ import mimetypes
11
+ from pathlib import Path
12
+ from typing import Dict, Optional, Tuple
13
+ import logging
14
+
15
+ logger = logging.getLogger("createsonline.static")
16
+
17
+ # Initialize mimetypes
18
+ mimetypes.init()
19
+
20
+ # Additional MIME types for modern web
21
+ CUSTOM_MIME_TYPES = {
22
+ '.html': 'text/html',
23
+ '.htm': 'text/html',
24
+ '.css': 'text/css',
25
+ '.js': 'application/javascript',
26
+ '.json': 'application/json',
27
+ '.xml': 'application/xml',
28
+ '.svg': 'image/svg+xml',
29
+ '.woff': 'font/woff',
30
+ '.woff2': 'font/woff2',
31
+ '.ttf': 'font/ttf',
32
+ '.eot': 'application/vnd.ms-fontobject',
33
+ '.png': 'image/png',
34
+ '.jpg': 'image/jpeg',
35
+ '.jpeg': 'image/jpeg',
36
+ '.gif': 'image/gif',
37
+ '.ico': 'image/x-icon',
38
+ '.webp': 'image/webp',
39
+ '.mp4': 'video/mp4',
40
+ '.webm': 'video/webm',
41
+ '.mp3': 'audio/mpeg',
42
+ '.wav': 'audio/wav',
43
+ '.pdf': 'application/pdf',
44
+ '.zip': 'application/zip',
45
+ '.txt': 'text/plain',
46
+ '.md': 'text/markdown',
47
+ }
48
+
49
+
50
+ class StaticFileHandler:
51
+ """
52
+ Dynamic static file serving with intelligent routing
53
+ """
54
+
55
+ def __init__(self, static_dirs: list = None, template_dirs: list = None):
56
+ """
57
+ Initialize static file handler
58
+
59
+ Args:
60
+ static_dirs: List of directories to serve static files from
61
+ template_dirs: List of directories to serve templates/HTML from
62
+ """
63
+ self._static_dirs = static_dirs
64
+ self._template_dirs = template_dirs
65
+
66
+ # Cache for file existence checks
67
+ self._file_cache = {}
68
+
69
+ logger.info("Static file handler initialized")
70
+
71
+ @property
72
+ def static_dirs(self):
73
+ """Lazily evaluate static directories using Django-style settings"""
74
+ if self._static_dirs is not None:
75
+ return self._static_dirs
76
+
77
+ # Import settings here to avoid circular imports
78
+ from .config.settings import settings
79
+
80
+ # Use STATICFILES_DIRS from settings (Django-style)
81
+ staticfiles_dirs = settings.STATICFILES_DIRS
82
+
83
+ if staticfiles_dirs:
84
+ # Add subdirectories for better organization
85
+ dirs = []
86
+ for base_dir in staticfiles_dirs:
87
+ dirs.append(base_dir)
88
+ # Also add common subdirectories
89
+ for subdir in ['css', 'js', 'images', 'img', 'icons']:
90
+ sub_path = base_dir / subdir
91
+ if sub_path.exists():
92
+ dirs.append(sub_path)
93
+ return dirs
94
+
95
+ # Fallback to current directory (backward compatibility)
96
+ cwd = Path.cwd()
97
+ dirs = [
98
+ cwd / "static",
99
+ cwd / "static" / "css",
100
+ cwd / "static" / "js",
101
+ cwd / "static" / "images",
102
+ cwd / "static" / "icons",
103
+ ]
104
+ return dirs
105
+
106
+ @property
107
+ def template_dirs(self):
108
+ """Lazily evaluate template directories using Django-style settings"""
109
+ if self._template_dirs is not None:
110
+ return self._template_dirs
111
+
112
+ # Import settings here to avoid circular imports
113
+ from .config.settings import settings
114
+
115
+ # Use TEMPLATE_DIRS from settings
116
+ template_dirs = settings.TEMPLATE_DIRS
117
+
118
+ if template_dirs:
119
+ return template_dirs
120
+
121
+ # Fallback
122
+ cwd = Path.cwd()
123
+ return [cwd / "templates"]
124
+
125
+ def get_mime_type(self, file_path: str) -> str:
126
+ """
127
+ Get MIME type for a file with fallback support
128
+
129
+ Args:
130
+ file_path: Path to the file
131
+
132
+ Returns:
133
+ MIME type string
134
+ """
135
+ ext = os.path.splitext(file_path)[1].lower()
136
+
137
+ # Check custom types first
138
+ if ext in CUSTOM_MIME_TYPES:
139
+ return CUSTOM_MIME_TYPES[ext]
140
+
141
+ # Fall back to system mimetypes
142
+ mime_type, _ = mimetypes.guess_type(file_path)
143
+
144
+ # Default to octet-stream if unknown
145
+ return mime_type or 'application/octet-stream'
146
+
147
+ def find_file(self, relative_path: str) -> Optional[Path]:
148
+ """
149
+ Find a file in static or template directories
150
+
151
+ Args:
152
+ relative_path: Relative path to the file
153
+
154
+ Returns:
155
+ Absolute Path object if found, None otherwise
156
+ """
157
+ # Check cache first
158
+ if relative_path in self._file_cache:
159
+ cached_path = self._file_cache[relative_path]
160
+ if cached_path and cached_path.exists():
161
+ return cached_path
162
+
163
+ # Remove leading slash if present
164
+ relative_path = relative_path.lstrip('/')
165
+
166
+ # Strip /static/ prefix if present (URLs come as /static/css/file.css)
167
+ # but we want to search in static_dirs which already points to static/
168
+ search_path = relative_path
169
+ if search_path.startswith('static/'):
170
+ search_path = search_path[7:] # Remove 'static/' prefix
171
+ logger.debug(f"Stripped 'static/' prefix: '{relative_path}' -> '{search_path}'")
172
+
173
+ # PRIORITY 1: Check project root for root-level static files
174
+ # (favicon.svg, logo.png, site.webmanifest, robots.txt, etc.)
175
+ project_root = Path.cwd()
176
+ root_file = project_root / search_path
177
+ if root_file.exists() and root_file.is_file():
178
+ # Security check: ensure it's a known static file type
179
+ static_extensions = {'.svg', '.ico', '.png', '.jpg', '.jpeg', '.gif',
180
+ '.webp', '.webmanifest', '.json', '.txt', '.xml'}
181
+ if root_file.suffix.lower() in static_extensions:
182
+ self._file_cache[relative_path] = root_file
183
+ logger.debug(f"Found root-level file: {root_file}")
184
+ return root_file
185
+
186
+ # PRIORITY 2: Check static directories
187
+ for static_dir in self.static_dirs:
188
+ file_path = Path(static_dir) / search_path
189
+ logger.debug(f"Checking: {file_path} (exists={file_path.exists()})")
190
+ if file_path.exists() and file_path.is_file():
191
+ self._file_cache[relative_path] = file_path
192
+ logger.debug(f"Found file: {file_path}")
193
+ return file_path
194
+
195
+ # PRIORITY 3: Check template directories
196
+ for template_dir in self.template_dirs:
197
+ file_path = Path(template_dir) / search_path
198
+ if file_path.exists() and file_path.is_file():
199
+ self._file_cache[relative_path] = file_path
200
+ return file_path
201
+
202
+ # Cache miss
203
+ self._file_cache[relative_path] = None
204
+ return None
205
+
206
+ def serve_file(self, relative_path: str) -> Tuple[bytes, int, Dict[str, str]]:
207
+ """
208
+ Serve a static file
209
+
210
+ Args:
211
+ relative_path: Relative path to the file
212
+
213
+ Returns:
214
+ Tuple of (content, status_code, headers)
215
+ """
216
+ file_path = self.find_file(relative_path)
217
+
218
+ if not file_path:
219
+ error_content = f"File not found: {relative_path}".encode()
220
+ return error_content, 404, {'Content-Type': 'text/plain'}
221
+
222
+ try:
223
+ # Security check - ensure file is within allowed directories
224
+ resolved_path = file_path.resolve()
225
+ allowed = False
226
+
227
+ # Allow project root for root-level static files
228
+ project_root = Path.cwd().resolve()
229
+ if str(resolved_path).startswith(str(project_root)):
230
+ # Check if it's a known static file type
231
+ static_extensions = {'.svg', '.ico', '.png', '.jpg', '.jpeg', '.gif',
232
+ '.webp', '.webmanifest', '.json', '.txt', '.xml',
233
+ '.css', '.js', '.woff', '.woff2', '.ttf'}
234
+ if resolved_path.suffix.lower() in static_extensions:
235
+ allowed = True
236
+
237
+ # Also check configured static/template directories
238
+ if not allowed:
239
+ for static_dir in self.static_dirs + self.template_dirs:
240
+ if str(resolved_path).startswith(str(Path(static_dir).resolve())):
241
+ allowed = True
242
+ break
243
+
244
+ if not allowed:
245
+ error_content = b"Access denied"
246
+ return error_content, 403, {'Content-Type': 'text/plain'}
247
+
248
+ # Read file content
249
+ with open(file_path, 'rb') as f:
250
+ content = f.read()
251
+
252
+ # Get MIME type
253
+ mime_type = self.get_mime_type(str(file_path))
254
+
255
+ # Prepare headers
256
+ headers = {
257
+ 'Content-Type': mime_type,
258
+ 'Content-Length': str(len(content)),
259
+ 'Cache-Control': 'public, max-age=3600', # Cache for 1 hour
260
+ }
261
+
262
+ # Add additional headers for specific file types
263
+ if mime_type.startswith('text/'):
264
+ headers['Content-Type'] = f"{mime_type}; charset=utf-8"
265
+
266
+ logger.debug(f"Serving file: {relative_path} ({mime_type}, {len(content)} bytes)")
267
+
268
+ return content, 200, headers
269
+
270
+ except Exception as e:
271
+ logger.error(f"Error serving file {relative_path}: {e}")
272
+ error_content = f"Error reading file: {str(e)}".encode()
273
+ return error_content, 500, {'Content-Type': 'text/plain'}
274
+
275
+ def list_files(self, directory: str = "") -> Dict[str, list]:
276
+ """
277
+ List all files in static directories (for debugging)
278
+
279
+ Args:
280
+ directory: Subdirectory to list (empty for all)
281
+
282
+ Returns:
283
+ Dictionary with file listings
284
+ """
285
+ files = {
286
+ 'static': [],
287
+ 'templates': []
288
+ }
289
+
290
+ # List static files
291
+ for static_dir in self.static_dirs:
292
+ base_dir = Path(static_dir) / directory
293
+ if base_dir.exists():
294
+ for file_path in base_dir.rglob('*'):
295
+ if file_path.is_file():
296
+ rel_path = file_path.relative_to(static_dir)
297
+ files['static'].append(str(rel_path))
298
+
299
+ # List template files
300
+ for template_dir in self.template_dirs:
301
+ base_dir = Path(template_dir) / directory
302
+ if base_dir.exists():
303
+ for file_path in base_dir.rglob('*'):
304
+ if file_path.is_file():
305
+ rel_path = file_path.relative_to(template_dir)
306
+ files['templates'].append(str(rel_path))
307
+
308
+ return files
309
+
310
+
311
+ # Global static file handler instance
312
+ static_handler = StaticFileHandler()
313
+
314
+
315
+ def configure_static_handler(static_dirs: list = None, template_dirs: list = None):
316
+ """
317
+ Manually configure the global static handler (optional).
318
+
319
+ By default, the handler auto-discovers directories using Django-style settings.
320
+ Only use this if you need to override the auto-discovery.
321
+
322
+ Args:
323
+ static_dirs: List of static file directories
324
+ template_dirs: List of template directories
325
+ """
326
+ global static_handler
327
+
328
+ if static_dirs:
329
+ print(f"[DEBUG] Manually configuring static_handler with: {[str(d) for d in static_dirs]}")
330
+ static_handler._static_dirs = static_dirs
331
+
332
+ if template_dirs:
333
+ static_handler._template_dirs = template_dirs
334
+
335
+ static_handler._file_cache = {} # Clear cache
336
+
337
+
338
+ def serve_static(path: str) -> Tuple[bytes, int, Dict[str, str]]:
339
+ """
340
+ Convenience function to serve static files
341
+
342
+ Args:
343
+ path: Path to the file
344
+
345
+ Returns:
346
+ Tuple of (content, status_code, headers)
347
+ """
348
+ return static_handler.serve_file(path)
349
+
350
+
351
+ def serve_template(path: str) -> Tuple[bytes, int, Dict[str, str]]:
352
+ """
353
+ Convenience function to serve HTML templates
354
+
355
+ Args:
356
+ path: Path to the template
357
+
358
+ Returns:
359
+ Tuple of (content, status_code, headers)
360
+ """
361
+ # Ensure .html extension
362
+ if not path.endswith('.html'):
363
+ path = f"{path}.html"
364
+
365
+ return static_handler.serve_file(path)
@@ -0,0 +1,100 @@
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>404 - Page Not Found</title>
7
+
8
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
9
+ <link rel="icon" type="image/x-icon" href="/favicon.ico">
10
+
11
+ <style>
12
+ * {
13
+ margin: 0;
14
+ padding: 0;
15
+ box-sizing: border-box;
16
+ }
17
+
18
+ body {
19
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
20
+ background: #0a0a0a;
21
+ color: #ffffff;
22
+ min-height: 100vh;
23
+ display: flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ padding: 20px;
27
+ }
28
+
29
+ .container {
30
+ max-width: 600px;
31
+ width: 100%;
32
+ text-align: center;
33
+ background: #1a1a1a;
34
+ padding: 60px 40px;
35
+ border-radius: 16px;
36
+ border: 1px solid #2a2a2a;
37
+ }
38
+
39
+ .error-code {
40
+ font-size: 8em;
41
+ font-weight: 700;
42
+ background: linear-gradient(135deg, #ffffff 0%, #666666 100%);
43
+ -webkit-background-clip: text;
44
+ -webkit-text-fill-color: transparent;
45
+ background-clip: text;
46
+ margin-bottom: 20px;
47
+ line-height: 1;
48
+ }
49
+
50
+ h1 {
51
+ font-size: 2em;
52
+ margin-bottom: 15px;
53
+ color: #ffffff;
54
+ }
55
+
56
+ p {
57
+ color: #999999;
58
+ font-size: 1.1em;
59
+ margin-bottom: 40px;
60
+ line-height: 1.6;
61
+ }
62
+
63
+ .btn {
64
+ display: inline-block;
65
+ padding: 15px 35px;
66
+ background: #ffffff;
67
+ color: #000000;
68
+ text-decoration: none;
69
+ border-radius: 8px;
70
+ font-weight: 600;
71
+ transition: all 0.3s ease;
72
+ }
73
+
74
+ .btn:hover {
75
+ background: #f0f0f0;
76
+ transform: translateY(-2px);
77
+ box-shadow: 0 10px 25px rgba(255, 255, 255, 0.2);
78
+ }
79
+
80
+ @media (max-width: 600px) {
81
+ .error-code {
82
+ font-size: 5em;
83
+ }
84
+ h1 {
85
+ font-size: 1.5em;
86
+ }
87
+ }
88
+ </style>
89
+ </head>
90
+ <body>
91
+ <div class="container">
92
+ <div class="error-code">404</div>
93
+ <h1>Page Not Found</h1>
94
+ <p>
95
+ The page you're looking for doesn't exist or has been moved.
96
+ </p>
97
+ <a href="/" class="btn">Go Home</a>
98
+ </div>
99
+ </body>
100
+ </html>
@@ -0,0 +1,169 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Admin Login - CREATESONLINE{% endblock %}
4
+
5
+ {% block extra_style %}
6
+ h1 {
7
+ font-size: 2em;
8
+ color: #000000;
9
+ margin-bottom: 10px;
10
+ text-align: center;
11
+ font-weight: 300;
12
+ letter-spacing: -0.5px;
13
+ }
14
+
15
+ h1::after {
16
+ content: '';
17
+ display: block;
18
+ width: 40px;
19
+ height: 2px;
20
+ background: #000000;
21
+ margin: 15px auto 0;
22
+ }
23
+
24
+ .subtitle {
25
+ text-align: center;
26
+ color: #666666;
27
+ font-size: 0.95em;
28
+ margin-bottom: 45px;
29
+ font-weight: 300;
30
+ line-height: 1.6;
31
+ }
32
+
33
+ .form-group {
34
+ margin-bottom: 30px;
35
+ position: relative;
36
+ }
37
+
38
+ label {
39
+ display: block;
40
+ color: #000000;
41
+ font-size: 0.85em;
42
+ margin-bottom: 10px;
43
+ font-weight: 600;
44
+ text-transform: uppercase;
45
+ letter-spacing: 1px;
46
+ }
47
+
48
+ input[type="text"],
49
+ input[type="password"] {
50
+ width: 100%;
51
+ padding: 15px 18px;
52
+ border: 2px solid #e0e0e0;
53
+ background: #ffffff;
54
+ font-size: 1em;
55
+ transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
56
+ font-family: inherit;
57
+ color: #000000;
58
+ }
59
+
60
+ input[type="text"]:focus,
61
+ input[type="password"]:focus {
62
+ outline: none;
63
+ background: #fafafa;
64
+ border-color: #000000;
65
+ transform: translateY(-2px);
66
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
67
+ }
68
+
69
+ button {
70
+ width: 100%;
71
+ padding: 18px;
72
+ background: #000000;
73
+ color: white;
74
+ border: 2px solid #000000;
75
+ font-size: 1em;
76
+ font-weight: 600;
77
+ cursor: pointer;
78
+ transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
79
+ text-transform: uppercase;
80
+ letter-spacing: 1.5px;
81
+ font-family: inherit;
82
+ margin-top: 10px;
83
+ position: relative;
84
+ overflow: hidden;
85
+ }
86
+
87
+ button::before {
88
+ content: '';
89
+ position: absolute;
90
+ top: 0;
91
+ left: -100%;
92
+ width: 100%;
93
+ height: 100%;
94
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
95
+ transition: left 0.5s;
96
+ }
97
+
98
+ button:hover::before {
99
+ left: 100%;
100
+ }
101
+
102
+ button:hover {
103
+ background: #ffffff;
104
+ color: #000000;
105
+ transform: translateY(-2px);
106
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
107
+ }
108
+
109
+ button:active {
110
+ transform: translateY(0);
111
+ }
112
+
113
+ .back-link {
114
+ text-align: center;
115
+ margin-top: 35px;
116
+ padding-top: 30px;
117
+ border-top: 1px solid #e0e0e0;
118
+ }
119
+
120
+ .back-link a {
121
+ color: #666666;
122
+ text-decoration: none;
123
+ font-size: 0.9em;
124
+ transition: all 0.3s ease;
125
+ font-weight: 300;
126
+ }
127
+
128
+ .back-link a:hover {
129
+ color: #000000;
130
+ }
131
+
132
+ .container {
133
+ max-width: 480px;
134
+ padding: 60px 50px;
135
+ }
136
+
137
+ @media (max-width: 480px) {
138
+ .container {
139
+ padding: 40px 30px;
140
+ }
141
+
142
+ h1 {
143
+ font-size: 1.6em;
144
+ }
145
+ }
146
+ {% endblock %}
147
+
148
+ {% block content %}
149
+ <h1>Admin Login</h1>
150
+ <p class="subtitle">Enter your credentials to access the admin panel</p>
151
+
152
+ <form method="POST" action="/admin/login">
153
+ <div class="form-group">
154
+ <label for="username">Username</label>
155
+ <input type="text" id="username" name="username" required>
156
+ </div>
157
+
158
+ <div class="form-group">
159
+ <label for="password">Password</label>
160
+ <input type="password" id="password" name="password" required>
161
+ </div>
162
+
163
+ <button type="submit">Sign In</button>
164
+ </form>
165
+
166
+ <div class="back-link">
167
+ <a href="/">Back to Home</a>
168
+ </div>
169
+ {% endblock %}