@howssatoshi/quantumcss 1.5.1 → 1.6.0
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.
- package/README.md +1 -1
- package/dist/quantum.min.css +1 -4885
- package/examples/admin-panel.html +834 -0
- package/examples/analytics-dashboard.html +949 -0
- package/examples/chat-messaging.html +264 -0
- package/examples/email-template.html +697 -0
- package/examples/index.html +129 -1
- package/examples/music-streaming.html +1239 -0
- package/examples/portfolio-resume.html +653 -0
- package/examples/starlight.html +56 -3
- package/examples/travel/index.html +0 -4
- package/examples/video-streaming.html +564 -0
- package/package.json +1 -1
- package/src/styles/quantum-base.css +1 -1
- package/src/styles/quantum-components.css +954 -0
|
@@ -0,0 +1,949 @@
|
|
|
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>Starlight Analytics - Dashboard</title>
|
|
7
|
+
<link rel="stylesheet" href="../dist/quantum.min.css">
|
|
8
|
+
<link rel="stylesheet" href="../src/styles/quantum-components.css">
|
|
9
|
+
<script src="../src/starlight.js"></script>
|
|
10
|
+
<style>
|
|
11
|
+
/* Dashboard Layout overrides */
|
|
12
|
+
.logo {
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
gap: 0.75rem;
|
|
16
|
+
margin-bottom: 2rem;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.logo-icon {
|
|
20
|
+
width: 40px;
|
|
21
|
+
height: 40px;
|
|
22
|
+
background: linear-gradient(135deg, var(--color-starlight, #00d4ff), #3b82f6);
|
|
23
|
+
border-radius: 10px;
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Header */
|
|
30
|
+
.header {
|
|
31
|
+
display: flex;
|
|
32
|
+
justify-content: space-between;
|
|
33
|
+
align-items: center;
|
|
34
|
+
margin-bottom: 2rem;
|
|
35
|
+
padding-bottom: 1rem;
|
|
36
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.header-title h1 {
|
|
40
|
+
font-size: 1.75rem;
|
|
41
|
+
font-weight: 700;
|
|
42
|
+
color: var(--text-primary, #f1f5f9);
|
|
43
|
+
margin-bottom: 0.25rem;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.header-title p {
|
|
47
|
+
font-size: 0.875rem;
|
|
48
|
+
color: var(--text-muted, #64748b);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.header-actions {
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
gap: 1rem;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.date-selector {
|
|
58
|
+
display: flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
gap: 0.5rem;
|
|
61
|
+
padding: 0.5rem 1rem;
|
|
62
|
+
background: rgba(255, 255, 255, 0.05);
|
|
63
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
64
|
+
border-radius: 0.5rem;
|
|
65
|
+
color: var(--text-secondary, #94a3b8);
|
|
66
|
+
font-size: 0.875rem;
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
transition: all 0.2s ease;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.date-selector:hover {
|
|
72
|
+
background: rgba(255, 255, 255, 0.08);
|
|
73
|
+
border-color: rgba(255, 255, 255, 0.15);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Charts Section */
|
|
77
|
+
.charts-section {
|
|
78
|
+
display: grid;
|
|
79
|
+
grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
|
|
80
|
+
gap: 1.5rem;
|
|
81
|
+
margin-bottom: 2rem;
|
|
82
|
+
overflow: hidden;
|
|
83
|
+
width: 100%;
|
|
84
|
+
max-width: 100%;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Bottom section grid */
|
|
88
|
+
.bottom-section {
|
|
89
|
+
display: grid;
|
|
90
|
+
grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
|
|
91
|
+
gap: 1.5rem;
|
|
92
|
+
overflow: hidden;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Prevent body overflow */
|
|
96
|
+
html, body {
|
|
97
|
+
overflow-x: hidden;
|
|
98
|
+
max-width: 100vw;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* Ensure main content doesn't overflow */
|
|
102
|
+
.main-content {
|
|
103
|
+
max-width: 100%;
|
|
104
|
+
box-sizing: border-box;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.chart-card {
|
|
108
|
+
background: rgba(255, 255, 255, 0.03);
|
|
109
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
110
|
+
border-radius: 1rem;
|
|
111
|
+
padding: 1.5rem;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.chart-header {
|
|
115
|
+
display: flex;
|
|
116
|
+
justify-content: space-between;
|
|
117
|
+
align-items: center;
|
|
118
|
+
margin-bottom: 1.5rem;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.chart-title {
|
|
122
|
+
font-size: 1rem;
|
|
123
|
+
font-weight: 600;
|
|
124
|
+
color: var(--text-primary, #f1f5f9);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.chart-tabs {
|
|
128
|
+
display: flex;
|
|
129
|
+
gap: 0.5rem;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.chart-tab {
|
|
133
|
+
padding: 0.375rem 0.75rem;
|
|
134
|
+
border-radius: 0.375rem;
|
|
135
|
+
font-size: 0.75rem;
|
|
136
|
+
font-weight: 500;
|
|
137
|
+
color: var(--text-muted, #64748b);
|
|
138
|
+
cursor: pointer;
|
|
139
|
+
transition: all 0.2s ease;
|
|
140
|
+
border: none;
|
|
141
|
+
background: transparent;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.chart-tab:hover {
|
|
145
|
+
color: var(--text-primary, #f1f5f9);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.chart-tab.active {
|
|
149
|
+
background: rgba(0, 212, 255, 0.15);
|
|
150
|
+
color: var(--color-starlight, #00d4ff);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* Canvas Charts */
|
|
154
|
+
.chart-container {
|
|
155
|
+
position: relative;
|
|
156
|
+
height: 280px;
|
|
157
|
+
width: 100%;
|
|
158
|
+
overflow: hidden;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
canvas {
|
|
162
|
+
width: 100% !important;
|
|
163
|
+
height: 100% !important;
|
|
164
|
+
max-width: 100%;
|
|
165
|
+
display: block;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* Donut Chart Legend */
|
|
169
|
+
.donut-legend {
|
|
170
|
+
margin-top: 1.5rem;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.legend-item {
|
|
174
|
+
display: flex;
|
|
175
|
+
align-items: center;
|
|
176
|
+
justify-content: space-between;
|
|
177
|
+
padding: 0.75rem 0;
|
|
178
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.legend-item:last-child {
|
|
182
|
+
border-bottom: none;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.legend-info {
|
|
186
|
+
display: flex;
|
|
187
|
+
align-items: center;
|
|
188
|
+
gap: 0.75rem;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.legend-dot {
|
|
192
|
+
width: 10px;
|
|
193
|
+
height: 10px;
|
|
194
|
+
border-radius: 50%;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.legend-label {
|
|
198
|
+
font-size: 0.875rem;
|
|
199
|
+
color: var(--text-secondary, #94a3b8);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.legend-value {
|
|
203
|
+
font-size: 0.875rem;
|
|
204
|
+
font-weight: 600;
|
|
205
|
+
color: var(--text-primary, #f1f5f9);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* Bottom Section */
|
|
209
|
+
.bottom-section {
|
|
210
|
+
display: grid;
|
|
211
|
+
grid-template-columns: 1.5fr 1fr;
|
|
212
|
+
gap: 1.5rem;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* Activity Feed */
|
|
216
|
+
.activity-item {
|
|
217
|
+
display: flex;
|
|
218
|
+
align-items: flex-start;
|
|
219
|
+
gap: 1rem;
|
|
220
|
+
padding: 1rem 0;
|
|
221
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.activity-item:last-child {
|
|
225
|
+
border-bottom: none;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.activity-icon {
|
|
229
|
+
width: 36px;
|
|
230
|
+
height: 36px;
|
|
231
|
+
border-radius: 50%;
|
|
232
|
+
display: flex;
|
|
233
|
+
align-items: center;
|
|
234
|
+
justify-content: center;
|
|
235
|
+
flex-shrink: 0;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.activity-content {
|
|
239
|
+
flex: 1;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.activity-text {
|
|
243
|
+
font-size: 0.875rem;
|
|
244
|
+
color: var(--text-primary, #f1f5f9);
|
|
245
|
+
margin-bottom: 0.25rem;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.activity-text span {
|
|
249
|
+
color: var(--color-starlight, #00d4ff);
|
|
250
|
+
font-weight: 500;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.activity-time {
|
|
254
|
+
font-size: 0.75rem;
|
|
255
|
+
color: var(--text-muted, #64748b);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* Top Products Table */
|
|
259
|
+
.product-row {
|
|
260
|
+
display: flex;
|
|
261
|
+
align-items: center;
|
|
262
|
+
gap: 1rem;
|
|
263
|
+
padding: 0.875rem 0;
|
|
264
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.product-row:last-child {
|
|
268
|
+
border-bottom: none;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.product-rank {
|
|
272
|
+
width: 28px;
|
|
273
|
+
height: 28px;
|
|
274
|
+
border-radius: 50%;
|
|
275
|
+
background: rgba(255, 255, 255, 0.05);
|
|
276
|
+
display: flex;
|
|
277
|
+
align-items: center;
|
|
278
|
+
justify-content: center;
|
|
279
|
+
font-size: 0.75rem;
|
|
280
|
+
font-weight: 600;
|
|
281
|
+
color: var(--text-muted, #64748b);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.product-rank.top {
|
|
285
|
+
background: rgba(0, 212, 255, 0.15);
|
|
286
|
+
color: var(--color-starlight, #00d4ff);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.product-info {
|
|
290
|
+
flex: 1;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.product-name {
|
|
294
|
+
font-size: 0.875rem;
|
|
295
|
+
font-weight: 500;
|
|
296
|
+
color: var(--text-primary, #f1f5f9);
|
|
297
|
+
margin-bottom: 0.125rem;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.product-category {
|
|
301
|
+
font-size: 0.75rem;
|
|
302
|
+
color: var(--text-muted, #64748b);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.product-revenue {
|
|
306
|
+
font-size: 0.875rem;
|
|
307
|
+
font-weight: 600;
|
|
308
|
+
color: var(--text-primary, #f1f5f9);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* Sun/Moon icons */
|
|
312
|
+
.sun-icon { display: none; }
|
|
313
|
+
body.light-mode .sun-icon { display: inline; }
|
|
314
|
+
body.light-mode .moon-icon { display: none; }
|
|
315
|
+
|
|
316
|
+
/* Light Mode Overrides */
|
|
317
|
+
body.light-mode {
|
|
318
|
+
--bg-primary: #f8fafc;
|
|
319
|
+
--text-primary: #0f172a;
|
|
320
|
+
--text-secondary: #475569;
|
|
321
|
+
--text-muted: #64748b;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
body.light-mode .chart-card {
|
|
325
|
+
background: #ffffff;
|
|
326
|
+
border-color: #e2e8f0;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
body.light-mode .date-selector {
|
|
330
|
+
background: #ffffff;
|
|
331
|
+
border-color: #e2e8f0;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
body.light-mode .header {
|
|
335
|
+
border-bottom-color: #e2e8f0;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
body.light-mode .legend-item,
|
|
339
|
+
body.light-mode .activity-item,
|
|
340
|
+
body.light-mode .product-row {
|
|
341
|
+
border-bottom-color: #f1f5f9;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/* Responsive */
|
|
345
|
+
@media (max-width: 1280px) {
|
|
346
|
+
.stats-grid {
|
|
347
|
+
grid-template-columns: repeat(2, 1fr);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.charts-section {
|
|
351
|
+
grid-template-columns: 1fr;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.bottom-section {
|
|
355
|
+
grid-template-columns: 1fr;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
@media (max-width: 768px) {
|
|
360
|
+
.app-layout {
|
|
361
|
+
grid-template-columns: 1fr;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.sidebar {
|
|
365
|
+
display: none;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.main-content {
|
|
369
|
+
padding: 1rem;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.stats-grid {
|
|
373
|
+
grid-template-columns: 1fr;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.header {
|
|
377
|
+
flex-direction: column;
|
|
378
|
+
align-items: flex-start;
|
|
379
|
+
gap: 1rem;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/* Animations */
|
|
384
|
+
@keyframes fadeIn {
|
|
385
|
+
from { opacity: 0; transform: translateY(10px); }
|
|
386
|
+
to { opacity: 1; transform: translateY(0); }
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.stat-card, .chart-card {
|
|
390
|
+
animation: fadeIn 0.5s ease-out forwards;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.stat-card:nth-child(1) { animation-delay: 0.1s; }
|
|
394
|
+
.stat-card:nth-child(2) { animation-delay: 0.2s; }
|
|
395
|
+
.stat-card:nth-child(3) { animation-delay: 0.3s; }
|
|
396
|
+
.stat-card:nth-child(4) { animation-delay: 0.4s; }
|
|
397
|
+
</style>
|
|
398
|
+
</head>
|
|
399
|
+
<body>
|
|
400
|
+
<div class="app-layout">
|
|
401
|
+
<!-- Sidebar -->
|
|
402
|
+
<aside class="sidebar">
|
|
403
|
+
<div class="logo">
|
|
404
|
+
<div class="logo-icon">
|
|
405
|
+
<svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
406
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
|
407
|
+
</svg>
|
|
408
|
+
</div>
|
|
409
|
+
<span class="text-xl font-bold text-gradient-starlight">Starlight</span>
|
|
410
|
+
</div>
|
|
411
|
+
|
|
412
|
+
<div class="nav-section">
|
|
413
|
+
<div class="nav-section-title">Analytics</div>
|
|
414
|
+
<nav>
|
|
415
|
+
<button class="nav-item active">
|
|
416
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
417
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"></path>
|
|
418
|
+
</svg>
|
|
419
|
+
<span>Dashboard</span>
|
|
420
|
+
</button>
|
|
421
|
+
<button class="nav-item">
|
|
422
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
423
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
|
|
424
|
+
</svg>
|
|
425
|
+
<span>Reports</span>
|
|
426
|
+
</button>
|
|
427
|
+
<button class="nav-item">
|
|
428
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
429
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 8v8m-4-5v5m-4-2v2m-2 4h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
|
430
|
+
</svg>
|
|
431
|
+
<span>Real-time</span>
|
|
432
|
+
</button>
|
|
433
|
+
<button class="nav-item">
|
|
434
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
435
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 3.055A9.001 9.001 0 1020.945 13H11V3.055z"></path>
|
|
436
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.488 9H15V3.512A9.025 9.025 0 0120.488 9z"></path>
|
|
437
|
+
</svg>
|
|
438
|
+
<span>Segments</span>
|
|
439
|
+
</button>
|
|
440
|
+
</nav>
|
|
441
|
+
</div>
|
|
442
|
+
|
|
443
|
+
<div class="nav-section">
|
|
444
|
+
<div class="nav-section-title">Management</div>
|
|
445
|
+
<nav>
|
|
446
|
+
<button class="nav-item">
|
|
447
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
448
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path>
|
|
449
|
+
</svg>
|
|
450
|
+
<span>Users</span>
|
|
451
|
+
</button>
|
|
452
|
+
<button class="nav-item">
|
|
453
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
454
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"></path>
|
|
455
|
+
</svg>
|
|
456
|
+
<span>Products</span>
|
|
457
|
+
</button>
|
|
458
|
+
<button class="nav-item">
|
|
459
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
460
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
|
|
461
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
|
462
|
+
</svg>
|
|
463
|
+
<span>Settings</span>
|
|
464
|
+
</button>
|
|
465
|
+
</nav>
|
|
466
|
+
</div>
|
|
467
|
+
|
|
468
|
+
<div class="theme-toggle-wrapper">
|
|
469
|
+
<button class="theme-btn" onclick="toggleTheme()">
|
|
470
|
+
<svg class="w-4 h-4 sun-icon" fill="currentColor" viewBox="0 0 20 20">
|
|
471
|
+
<path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"></path>
|
|
472
|
+
</svg>
|
|
473
|
+
<svg class="w-4 h-4 moon-icon" fill="currentColor" viewBox="0 0 20 20">
|
|
474
|
+
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
|
|
475
|
+
</svg>
|
|
476
|
+
<span class="theme-label">Toggle Theme</span>
|
|
477
|
+
</button>
|
|
478
|
+
</div>
|
|
479
|
+
</aside>
|
|
480
|
+
|
|
481
|
+
<!-- Main Content -->
|
|
482
|
+
<main class="main-content">
|
|
483
|
+
<!-- Header -->
|
|
484
|
+
<header class="header">
|
|
485
|
+
<div class="header-title">
|
|
486
|
+
<h1>Dashboard Overview</h1>
|
|
487
|
+
<p>Welcome back! Here's what's happening with your business.</p>
|
|
488
|
+
</div>
|
|
489
|
+
<div class="header-actions">
|
|
490
|
+
<div class="date-selector">
|
|
491
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
492
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
|
493
|
+
</svg>
|
|
494
|
+
<span>Last 30 days</span>
|
|
495
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
496
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
|
497
|
+
</svg>
|
|
498
|
+
</div>
|
|
499
|
+
<button class="notification-btn">
|
|
500
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
501
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"></path>
|
|
502
|
+
</svg>
|
|
503
|
+
<span class="notification-badge"></span>
|
|
504
|
+
</button>
|
|
505
|
+
<div class="user-avatar">JD</div>
|
|
506
|
+
</div>
|
|
507
|
+
</header>
|
|
508
|
+
|
|
509
|
+
<!-- Stats Grid -->
|
|
510
|
+
<div class="stats-grid">
|
|
511
|
+
<div class="stat-card">
|
|
512
|
+
<div class="stat-header">
|
|
513
|
+
<div class="stat-icon stat-icon-blue">
|
|
514
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
515
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
516
|
+
</svg>
|
|
517
|
+
</div>
|
|
518
|
+
<div class="stat-trend stat-trend-up">
|
|
519
|
+
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
|
|
520
|
+
<path fill-rule="evenodd" d="M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L11 7.414V15a1 1 0 11-2 0V7.414L6.707 9.707a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
|
521
|
+
</svg>
|
|
522
|
+
+12.5%
|
|
523
|
+
</div>
|
|
524
|
+
</div>
|
|
525
|
+
<div class="stat-value">$48,294</div>
|
|
526
|
+
<div class="stat-label">Total Revenue</div>
|
|
527
|
+
</div>
|
|
528
|
+
|
|
529
|
+
<div class="stat-card">
|
|
530
|
+
<div class="stat-header">
|
|
531
|
+
<div class="stat-icon stat-icon-green">
|
|
532
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
533
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path>
|
|
534
|
+
</svg>
|
|
535
|
+
</div>
|
|
536
|
+
<div class="stat-trend stat-trend-up">
|
|
537
|
+
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
|
|
538
|
+
<path fill-rule="evenodd" d="M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L11 7.414V15a1 1 0 11-2 0V7.414L6.707 9.707a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
|
539
|
+
</svg>
|
|
540
|
+
+8.2%
|
|
541
|
+
</div>
|
|
542
|
+
</div>
|
|
543
|
+
<div class="stat-value">2,847</div>
|
|
544
|
+
<div class="stat-label">Active Users</div>
|
|
545
|
+
</div>
|
|
546
|
+
|
|
547
|
+
<div class="stat-card">
|
|
548
|
+
<div class="stat-header">
|
|
549
|
+
<div class="stat-icon stat-icon-orange">
|
|
550
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
551
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"></path>
|
|
552
|
+
</svg>
|
|
553
|
+
</div>
|
|
554
|
+
<div class="stat-trend stat-trend-up">
|
|
555
|
+
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
|
|
556
|
+
<path fill-rule="evenodd" d="M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L11 7.414V15a1 1 0 11-2 0V7.414L6.707 9.707a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
|
557
|
+
</svg>
|
|
558
|
+
+23.1%
|
|
559
|
+
</div>
|
|
560
|
+
</div>
|
|
561
|
+
<div class="stat-value">1,429</div>
|
|
562
|
+
<div class="stat-label">Total Orders</div>
|
|
563
|
+
</div>
|
|
564
|
+
|
|
565
|
+
<div class="stat-card">
|
|
566
|
+
<div class="stat-header">
|
|
567
|
+
<div class="stat-icon stat-icon-purple">
|
|
568
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
569
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path>
|
|
570
|
+
</svg>
|
|
571
|
+
</div>
|
|
572
|
+
<div class="stat-trend stat-trend-down">
|
|
573
|
+
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
|
|
574
|
+
<path fill-rule="evenodd" d="M14.707 10.293a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L9 12.586V5a1 1 0 012 0v7.586l2.293-2.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
|
|
575
|
+
</svg>
|
|
576
|
+
-2.4%
|
|
577
|
+
</div>
|
|
578
|
+
</div>
|
|
579
|
+
<div class="stat-value">$33.80</div>
|
|
580
|
+
<div class="stat-label">Avg. Order Value</div>
|
|
581
|
+
</div>
|
|
582
|
+
</div>
|
|
583
|
+
|
|
584
|
+
<!-- Charts Section -->
|
|
585
|
+
<div class="charts-section">
|
|
586
|
+
<div class="chart-card">
|
|
587
|
+
<div class="chart-header">
|
|
588
|
+
<h3 class="chart-title">Revenue Overview</h3>
|
|
589
|
+
<div class="chart-tabs">
|
|
590
|
+
<button class="chart-tab active">Weekly</button>
|
|
591
|
+
<button class="chart-tab">Monthly</button>
|
|
592
|
+
<button class="chart-tab">Yearly</button>
|
|
593
|
+
</div>
|
|
594
|
+
</div>
|
|
595
|
+
<div class="chart-container">
|
|
596
|
+
<canvas id="revenueChart"></canvas>
|
|
597
|
+
</div>
|
|
598
|
+
</div>
|
|
599
|
+
|
|
600
|
+
<div class="chart-card">
|
|
601
|
+
<div class="chart-header">
|
|
602
|
+
<h3 class="chart-title">Sales by Category</h3>
|
|
603
|
+
</div>
|
|
604
|
+
<div class="chart-container" style="height: 200px;">
|
|
605
|
+
<canvas id="categoryChart"></canvas>
|
|
606
|
+
</div>
|
|
607
|
+
<div class="donut-legend">
|
|
608
|
+
<div class="legend-item">
|
|
609
|
+
<div class="legend-info">
|
|
610
|
+
<div class="legend-dot" style="background: #3b82f6;"></div>
|
|
611
|
+
<span class="legend-label">Electronics</span>
|
|
612
|
+
</div>
|
|
613
|
+
<span class="legend-value">42%</span>
|
|
614
|
+
</div>
|
|
615
|
+
<div class="legend-item">
|
|
616
|
+
<div class="legend-info">
|
|
617
|
+
<div class="legend-dot" style="background: #10b981;"></div>
|
|
618
|
+
<span class="legend-label">Clothing</span>
|
|
619
|
+
</div>
|
|
620
|
+
<span class="legend-value">28%</span>
|
|
621
|
+
</div>
|
|
622
|
+
<div class="legend-item">
|
|
623
|
+
<div class="legend-info">
|
|
624
|
+
<div class="legend-dot" style="background: #f59e0b;"></div>
|
|
625
|
+
<span class="legend-label">Home & Garden</span>
|
|
626
|
+
</div>
|
|
627
|
+
<span class="legend-value">18%</span>
|
|
628
|
+
</div>
|
|
629
|
+
<div class="legend-item">
|
|
630
|
+
<div class="legend-info">
|
|
631
|
+
<div class="legend-dot" style="background: #8b5cf6;"></div>
|
|
632
|
+
<span class="legend-label">Sports</span>
|
|
633
|
+
</div>
|
|
634
|
+
<span class="legend-value">12%</span>
|
|
635
|
+
</div>
|
|
636
|
+
</div>
|
|
637
|
+
</div>
|
|
638
|
+
</div>
|
|
639
|
+
|
|
640
|
+
<!-- Bottom Section -->
|
|
641
|
+
<div class="bottom-section">
|
|
642
|
+
<div class="chart-card">
|
|
643
|
+
<div class="chart-header">
|
|
644
|
+
<h3 class="chart-title">Recent Activity</h3>
|
|
645
|
+
</div>
|
|
646
|
+
<div class="activity-list">
|
|
647
|
+
<div class="activity-item">
|
|
648
|
+
<div class="activity-icon" style="background: rgba(59, 130, 246, 0.15); color: #60a5fa;">
|
|
649
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
650
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"></path>
|
|
651
|
+
</svg>
|
|
652
|
+
</div>
|
|
653
|
+
<div class="activity-content">
|
|
654
|
+
<div class="activity-text">New order <span>#ORD-7523</span> from Sarah Chen</div>
|
|
655
|
+
<div class="activity-time">2 minutes ago</div>
|
|
656
|
+
</div>
|
|
657
|
+
</div>
|
|
658
|
+
<div class="activity-item">
|
|
659
|
+
<div class="activity-icon" style="background: rgba(16, 185, 129, 0.15); color: #34d399;">
|
|
660
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
661
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"></path>
|
|
662
|
+
</svg>
|
|
663
|
+
</div>
|
|
664
|
+
<div class="activity-content">
|
|
665
|
+
<div class="activity-text">New user <span>alex.rivera</span> registered</div>
|
|
666
|
+
<div class="activity-time">15 minutes ago</div>
|
|
667
|
+
</div>
|
|
668
|
+
</div>
|
|
669
|
+
<div class="activity-item">
|
|
670
|
+
<div class="activity-icon" style="background: rgba(245, 158, 11, 0.15); color: #fbbf24;">
|
|
671
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
672
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z"></path>
|
|
673
|
+
</svg>
|
|
674
|
+
</div>
|
|
675
|
+
<div class="activity-content">
|
|
676
|
+
<div class="activity-text">Product <span>Starlight Pro</span> received 5-star review</div>
|
|
677
|
+
<div class="activity-time">1 hour ago</div>
|
|
678
|
+
</div>
|
|
679
|
+
</div>
|
|
680
|
+
<div class="activity-item">
|
|
681
|
+
<div class="activity-icon" style="background: rgba(139, 92, 246, 0.15); color: #a78bfa;">
|
|
682
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
683
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
|
|
684
|
+
</svg>
|
|
685
|
+
</div>
|
|
686
|
+
<div class="activity-content">
|
|
687
|
+
<div class="activity-text">Inventory updated for <span>Wireless Headphones</span></div>
|
|
688
|
+
<div class="activity-time">2 hours ago</div>
|
|
689
|
+
</div>
|
|
690
|
+
</div>
|
|
691
|
+
<div class="activity-item">
|
|
692
|
+
<div class="activity-icon" style="background: rgba(239, 68, 68, 0.15); color: #f87171;">
|
|
693
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
694
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
|
|
695
|
+
</svg>
|
|
696
|
+
</div>
|
|
697
|
+
<div class="activity-content">
|
|
698
|
+
<div class="activity-text">Low stock alert: <span>USB-C Cables</span> (5 remaining)</div>
|
|
699
|
+
<div class="activity-time">3 hours ago</div>
|
|
700
|
+
</div>
|
|
701
|
+
</div>
|
|
702
|
+
</div>
|
|
703
|
+
</div>
|
|
704
|
+
|
|
705
|
+
<div class="chart-card">
|
|
706
|
+
<div class="chart-header">
|
|
707
|
+
<h3 class="chart-title">Top Products</h3>
|
|
708
|
+
</div>
|
|
709
|
+
<div class="products-list">
|
|
710
|
+
<div class="product-row">
|
|
711
|
+
<div class="product-rank top">1</div>
|
|
712
|
+
<div class="product-info">
|
|
713
|
+
<div class="product-name">Starlight Pro Max</div>
|
|
714
|
+
<div class="product-category">Electronics</div>
|
|
715
|
+
</div>
|
|
716
|
+
<div class="product-revenue">$12,420</div>
|
|
717
|
+
</div>
|
|
718
|
+
<div class="product-row">
|
|
719
|
+
<div class="product-rank top">2</div>
|
|
720
|
+
<div class="product-info">
|
|
721
|
+
<div class="product-name">Quantum Keyboard</div>
|
|
722
|
+
<div class="product-category">Electronics</div>
|
|
723
|
+
</div>
|
|
724
|
+
<div class="product-revenue">$8,940</div>
|
|
725
|
+
</div>
|
|
726
|
+
<div class="product-row">
|
|
727
|
+
<div class="product-rank top">3</div>
|
|
728
|
+
<div class="product-info">
|
|
729
|
+
<div class="product-name">Nebula Monitor</div>
|
|
730
|
+
<div class="product-category">Electronics</div>
|
|
731
|
+
</div>
|
|
732
|
+
<div class="product-revenue">$7,320</div>
|
|
733
|
+
</div>
|
|
734
|
+
<div class="product-row">
|
|
735
|
+
<div class="product-rank">4</div>
|
|
736
|
+
<div class="product-info">
|
|
737
|
+
<div class="product-name">Cosmic Mousepad</div>
|
|
738
|
+
<div class="product-category">Accessories</div>
|
|
739
|
+
</div>
|
|
740
|
+
<div class="product-revenue">$4,180</div>
|
|
741
|
+
</div>
|
|
742
|
+
<div class="product-row">
|
|
743
|
+
<div class="product-rank">5</div>
|
|
744
|
+
<div class="product-info">
|
|
745
|
+
<div class="product-name">Stellar Webcam</div>
|
|
746
|
+
<div class="product-category">Electronics</div>
|
|
747
|
+
</div>
|
|
748
|
+
<div class="product-revenue">$3,850</div>
|
|
749
|
+
</div>
|
|
750
|
+
</div>
|
|
751
|
+
</div>
|
|
752
|
+
</div>
|
|
753
|
+
</main>
|
|
754
|
+
</div>
|
|
755
|
+
|
|
756
|
+
<script>
|
|
757
|
+
// Theme toggle
|
|
758
|
+
function toggleTheme() {
|
|
759
|
+
document.body.classList.toggle('light-mode');
|
|
760
|
+
localStorage.setItem('theme', document.body.classList.contains('light-mode') ? 'light' : 'dark');
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Check saved theme
|
|
764
|
+
const savedTheme = localStorage.getItem('theme');
|
|
765
|
+
if (savedTheme === 'light') {
|
|
766
|
+
document.body.classList.add('light-mode');
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// Chart drawing functions
|
|
770
|
+
function drawLineChart() {
|
|
771
|
+
const canvas = document.getElementById('revenueChart');
|
|
772
|
+
if (!canvas) return;
|
|
773
|
+
|
|
774
|
+
const ctx = canvas.getContext('2d');
|
|
775
|
+
const dpr = window.devicePixelRatio || 1;
|
|
776
|
+
const rect = canvas.getBoundingClientRect();
|
|
777
|
+
|
|
778
|
+
canvas.width = rect.width * dpr;
|
|
779
|
+
canvas.height = rect.height * dpr;
|
|
780
|
+
ctx.scale(dpr, dpr);
|
|
781
|
+
|
|
782
|
+
const width = rect.width;
|
|
783
|
+
const height = rect.height;
|
|
784
|
+
const padding = 40;
|
|
785
|
+
const chartWidth = width - padding * 2;
|
|
786
|
+
const chartHeight = height - padding * 2;
|
|
787
|
+
|
|
788
|
+
// Clear canvas
|
|
789
|
+
ctx.clearRect(0, 0, width, height);
|
|
790
|
+
|
|
791
|
+
// Sample data
|
|
792
|
+
const data = [3200, 4500, 3800, 5200, 4800, 6100, 5800, 7200, 6800, 8500, 8200, 9400];
|
|
793
|
+
const labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
794
|
+
|
|
795
|
+
const maxValue = Math.max(...data);
|
|
796
|
+
const minValue = Math.min(...data);
|
|
797
|
+
const range = maxValue - minValue;
|
|
798
|
+
|
|
799
|
+
// Draw grid lines
|
|
800
|
+
ctx.strokeStyle = document.body.classList.contains('light-mode') ? '#e2e8f0' : 'rgba(255,255,255,0.05)';
|
|
801
|
+
ctx.lineWidth = 1;
|
|
802
|
+
|
|
803
|
+
for (let i = 0; i <= 5; i++) {
|
|
804
|
+
const y = padding + (chartHeight / 5) * i;
|
|
805
|
+
ctx.beginPath();
|
|
806
|
+
ctx.moveTo(padding, y);
|
|
807
|
+
ctx.lineTo(width - padding, y);
|
|
808
|
+
ctx.stroke();
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// Draw line
|
|
812
|
+
const gradient = ctx.createLinearGradient(0, padding, 0, height - padding);
|
|
813
|
+
gradient.addColorStop(0, 'rgba(0, 212, 255, 0.3)');
|
|
814
|
+
gradient.addColorStop(1, 'rgba(0, 212, 255, 0)');
|
|
815
|
+
|
|
816
|
+
ctx.beginPath();
|
|
817
|
+
data.forEach((value, index) => {
|
|
818
|
+
const x = padding + (chartWidth / (data.length - 1)) * index;
|
|
819
|
+
const y = padding + chartHeight - ((value - minValue) / range) * chartHeight;
|
|
820
|
+
|
|
821
|
+
if (index === 0) {
|
|
822
|
+
ctx.moveTo(x, y);
|
|
823
|
+
} else {
|
|
824
|
+
ctx.lineTo(x, y);
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
// Fill area under line
|
|
829
|
+
ctx.lineTo(width - padding, height - padding);
|
|
830
|
+
ctx.lineTo(padding, height - padding);
|
|
831
|
+
ctx.closePath();
|
|
832
|
+
ctx.fillStyle = gradient;
|
|
833
|
+
ctx.fill();
|
|
834
|
+
|
|
835
|
+
// Draw line stroke
|
|
836
|
+
ctx.beginPath();
|
|
837
|
+
data.forEach((value, index) => {
|
|
838
|
+
const x = padding + (chartWidth / (data.length - 1)) * index;
|
|
839
|
+
const y = padding + chartHeight - ((value - minValue) / range) * chartHeight;
|
|
840
|
+
|
|
841
|
+
if (index === 0) {
|
|
842
|
+
ctx.moveTo(x, y);
|
|
843
|
+
} else {
|
|
844
|
+
ctx.lineTo(x, y);
|
|
845
|
+
}
|
|
846
|
+
});
|
|
847
|
+
ctx.strokeStyle = '#00d4ff';
|
|
848
|
+
ctx.lineWidth = 3;
|
|
849
|
+
ctx.stroke();
|
|
850
|
+
|
|
851
|
+
// Draw points
|
|
852
|
+
data.forEach((value, index) => {
|
|
853
|
+
const x = padding + (chartWidth / (data.length - 1)) * index;
|
|
854
|
+
const y = padding + chartHeight - ((value - minValue) / range) * chartHeight;
|
|
855
|
+
|
|
856
|
+
ctx.beginPath();
|
|
857
|
+
ctx.arc(x, y, 5, 0, Math.PI * 2);
|
|
858
|
+
ctx.fillStyle = '#08081a';
|
|
859
|
+
ctx.fill();
|
|
860
|
+
ctx.strokeStyle = '#00d4ff';
|
|
861
|
+
ctx.lineWidth = 2;
|
|
862
|
+
ctx.stroke();
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
// Draw labels
|
|
866
|
+
ctx.fillStyle = document.body.classList.contains('light-mode') ? '#64748b' : '#64748b';
|
|
867
|
+
ctx.font = '12px Inter, system-ui, sans-serif';
|
|
868
|
+
ctx.textAlign = 'center';
|
|
869
|
+
|
|
870
|
+
labels.forEach((label, index) => {
|
|
871
|
+
const x = padding + (chartWidth / (labels.length - 1)) * index;
|
|
872
|
+
ctx.fillText(label, x, height - 15);
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
function drawDonutChart() {
|
|
877
|
+
const canvas = document.getElementById('categoryChart');
|
|
878
|
+
if (!canvas) return;
|
|
879
|
+
|
|
880
|
+
const ctx = canvas.getContext('2d');
|
|
881
|
+
const dpr = window.devicePixelRatio || 1;
|
|
882
|
+
const rect = canvas.getBoundingClientRect();
|
|
883
|
+
|
|
884
|
+
canvas.width = rect.width * dpr;
|
|
885
|
+
canvas.height = rect.height * dpr;
|
|
886
|
+
ctx.scale(dpr, dpr);
|
|
887
|
+
|
|
888
|
+
const centerX = rect.width / 2;
|
|
889
|
+
const centerY = rect.height / 2;
|
|
890
|
+
const radius = Math.min(centerX, centerY) - 20;
|
|
891
|
+
const innerRadius = radius * 0.6;
|
|
892
|
+
|
|
893
|
+
// Data
|
|
894
|
+
const data = [
|
|
895
|
+
{ value: 42, color: '#3b82f6' },
|
|
896
|
+
{ value: 28, color: '#10b981' },
|
|
897
|
+
{ value: 18, color: '#f59e0b' },
|
|
898
|
+
{ value: 12, color: '#8b5cf6' }
|
|
899
|
+
];
|
|
900
|
+
|
|
901
|
+
let currentAngle = -Math.PI / 2;
|
|
902
|
+
const total = data.reduce((sum, item) => sum + item.value, 0);
|
|
903
|
+
|
|
904
|
+
data.forEach(item => {
|
|
905
|
+
const sliceAngle = (item.value / total) * Math.PI * 2;
|
|
906
|
+
|
|
907
|
+
ctx.beginPath();
|
|
908
|
+
ctx.arc(centerX, centerY, radius, currentAngle, currentAngle + sliceAngle);
|
|
909
|
+
ctx.arc(centerX, centerY, innerRadius, currentAngle + sliceAngle, currentAngle, true);
|
|
910
|
+
ctx.closePath();
|
|
911
|
+
ctx.fillStyle = item.color;
|
|
912
|
+
ctx.fill();
|
|
913
|
+
|
|
914
|
+
currentAngle += sliceAngle;
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
// Draw center text
|
|
918
|
+
ctx.fillStyle = document.body.classList.contains('light-mode') ? '#0f172a' : '#f1f5f9';
|
|
919
|
+
ctx.font = 'bold 20px Inter, system-ui, sans-serif';
|
|
920
|
+
ctx.textAlign = 'center';
|
|
921
|
+
ctx.textBaseline = 'middle';
|
|
922
|
+
ctx.fillText('100%', centerX, centerY);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// Initial draw
|
|
926
|
+
window.addEventListener('load', () => {
|
|
927
|
+
drawLineChart();
|
|
928
|
+
drawDonutChart();
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
// Redraw on resize
|
|
932
|
+
window.addEventListener('resize', () => {
|
|
933
|
+
drawLineChart();
|
|
934
|
+
drawDonutChart();
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
// Redraw on theme change
|
|
938
|
+
const observer = new MutationObserver((mutations) => {
|
|
939
|
+
mutations.forEach((mutation) => {
|
|
940
|
+
if (mutation.attributeName === 'class') {
|
|
941
|
+
drawLineChart();
|
|
942
|
+
drawDonutChart();
|
|
943
|
+
}
|
|
944
|
+
});
|
|
945
|
+
});
|
|
946
|
+
observer.observe(document.body, { attributes: true });
|
|
947
|
+
</script>
|
|
948
|
+
</body>
|
|
949
|
+
</html>
|