mbkbucket 3.8.2 → 4.0.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.
Files changed (38) hide show
  1. package/.env.example +15 -14
  2. package/README.md +561 -377
  3. package/index.js +32 -30
  4. package/lib/cli.js +154 -565
  5. package/lib/public/bucketadmin.css +2042 -1708
  6. package/lib/public/bucketadmin.js +1622 -1286
  7. package/lib/public/mbkbucket-helper-demo.html +4 -24
  8. package/lib/public/mbkbucket-helper.css +28 -34
  9. package/lib/public/mbkbucket-helper.js +4 -3
  10. package/lib/src/config/validation.js +86 -73
  11. package/lib/src/controllers/api.controller.js +459 -410
  12. package/lib/src/controllers/dashboard.controller.js +69 -49
  13. package/lib/src/controllers/info.controller.js +34 -3
  14. package/lib/src/controllers/view.controller.js +233 -231
  15. package/lib/src/core/storage/errors.js +62 -0
  16. package/lib/src/core/storage/gdrive-auth.js +193 -0
  17. package/lib/src/core/storage/gdrive-provider.js +656 -0
  18. package/lib/src/core/storage/index.js +14 -0
  19. package/lib/src/core/storage/models.js +80 -0
  20. package/lib/src/core/storage/path-strategy.js +65 -0
  21. package/lib/src/core/storage/s3-provider.js +491 -0
  22. package/lib/src/core/storage/storage-manager.js +203 -0
  23. package/lib/src/core/storage/storage-provider.js +217 -0
  24. package/lib/src/middleware/bucket-resolver.js +37 -37
  25. package/lib/src/routes/api.routes.js +5 -1
  26. package/lib/src/routes/index.js +60 -60
  27. package/lib/src/routes/view.routes.js +28 -25
  28. package/lib/src/services/s3.service.js +42 -594
  29. package/lib/src/services/storage.service.js +213 -0
  30. package/lib/src/utils/errors.js +56 -46
  31. package/package.json +11 -12
  32. package/views/bucket.hbs +47 -71
  33. package/views/bucketadmin_move_modal.hbs +35 -0
  34. package/views/bucketadmin_preview_modal.hbs +108 -40
  35. package/views/bucketadmincontent.hbs +193 -144
  36. package/views/mbkbucket_info.hbs +134 -232
  37. package/.mbkbucket.config.example.json +0 -14
  38. package/lib/src/cli/auth-helper.js +0 -141
@@ -1,1708 +1,2042 @@
1
- /* ==========================================================================
2
- MBKBucket File Manager - Original Theme Palette + Gentelella v4 Layout
3
- ========================================================================== */
4
-
5
- :root {
6
- --primary-color-ml: #0f766e;
7
- --primary-light-color-ml: #d7f4ee;
8
- --primary-dark-color-ml: #0b4f4a;
9
- --secondary-color-ml: #1f8f84;
10
- --dark-color-ml: #1f2a2a;
11
- --light-color-ml: #f4f7f3;
12
- --gray-color-ml: #667c79;
13
- --gray-light-color-ml: #dce8e3;
14
- --danger-color-ml: #dc2626;
15
- --warning-color-ml: #d97706;
16
- --success-color-ml: #16a34a;
17
- --info-color-ml: #3b82f6;
18
-
19
- --primary: var(--primary-color-ml);
20
- --primary-lt: var(--primary-light-color-ml);
21
- --primary-dk: var(--primary-dark-color-ml);
22
- --primary-hover: #0d635c;
23
-
24
- --body-bg: var(--light-color-ml);
25
- --bg-surface: rgba(255, 255, 255, 0.82);
26
- --bg-surface-secondary: rgba(244, 247, 243, 0.85);
27
- --bg-surface-tertiary: #e2ede8;
28
-
29
- --border-color: rgba(15, 118, 110, 0.16);
30
- --border-color-light: rgba(15, 118, 110, 0.08);
31
-
32
- --text: var(--dark-color-ml);
33
- --text-secondary: #425855;
34
- --text-muted: var(--gray-color-ml);
35
- --text-disabled: #a0b2af;
36
-
37
- --blue: #066fd1;
38
- --azure: #1f8f84;
39
- --green: #16a34a;
40
- --yellow: #d97706;
41
- --orange: #ea580c;
42
- --red: #dc2626;
43
- --purple: #7c3aed;
44
- --cyan: #0f766e;
45
-
46
- --green-lt: rgba(22, 163, 74, 0.12);
47
- --red-lt: rgba(220, 38, 38, 0.1);
48
- --yellow-lt: rgba(217, 119, 6, 0.12);
49
- --blue-lt: rgba(6, 111, 209, 0.1);
50
- --azure-lt: rgba(31, 143, 132, 0.12);
51
- --purple-lt: rgba(124, 58, 237, 0.1);
52
- --cyan-lt: rgba(15, 118, 110, 0.12);
53
-
54
- --radius-sm: 6px;
55
- --radius: 8px;
56
- --radius-lg: 14px;
57
- --radius-xl: 18px;
58
-
59
- --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.04);
60
- --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);
61
- --shadow-md: 0 10px 15px -3px rgba(15, 118, 110, 0.08), 0 4px 6px -2px rgba(0, 0, 0, 0.04);
62
- --shadow-lg: 0 20px 25px -5px rgba(15, 118, 110, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
63
- --shadow-dropdown: 0 12px 30px rgba(15, 42, 42, 0.14), 0 4px 10px rgba(0, 0, 0, 0.05);
64
-
65
- --font: "IBM Plex Sans", "Segoe UI", sans-serif;
66
- --font-headings: "Sora", "Segoe UI", sans-serif;
67
- --font-mono: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
68
- }
69
-
70
- /* Base Layout & Page Header */
71
- .page-wrapper,
72
- .page-wrapper *,
73
- .page-wrapper *::before,
74
- .page-wrapper *::after {
75
- box-sizing: border-box;
76
- }
77
-
78
- .page-wrapper {
79
- max-width: 1600px;
80
- margin: 0 auto;
81
- width: 100%;
82
- max-width: 100%;
83
- }
84
-
85
- .page-header {
86
- display: flex;
87
- align-items: center;
88
- justify-content: space-between;
89
- margin-bottom: 1.2rem;
90
- padding: 0.9rem 1.3rem;
91
- border: 1px solid rgba(255, 255, 255, 0.9);
92
- border-radius: 1rem;
93
- background: rgba(255, 255, 255, 0.74);
94
- backdrop-filter: blur(10px);
95
- box-shadow: 0 12px 34px rgba(15, 23, 42, 0.05);
96
- }
97
-
98
- .page-header-row {
99
- display: flex;
100
- align-items: center;
101
- justify-content: space-between;
102
- width: 100%;
103
- gap: 1rem;
104
- }
105
-
106
- .page-pretitle {
107
- font-size: 11px;
108
- font-weight: 700;
109
- text-transform: uppercase;
110
- letter-spacing: 0.6px;
111
- color: var(--primary-color-ml);
112
- margin-bottom: 2px;
113
- }
114
-
115
- .page-title {
116
- font-family: var(--font-headings);
117
- font-size: 1.45rem;
118
- font-weight: 700;
119
- color: var(--dark-color-ml);
120
- margin: 0;
121
- line-height: 1.2;
122
- }
123
-
124
- .page-actions {
125
- display: flex;
126
- align-items: center;
127
- gap: 0.65rem;
128
- }
129
-
130
- /* Button System */
131
- .btn {
132
- display: inline-flex;
133
- align-items: center;
134
- justify-content: center;
135
- gap: 0.45rem;
136
- font-family: var(--font);
137
- font-size: 13px;
138
- font-weight: 600;
139
- line-height: 1.4;
140
- padding: 7px 15px;
141
- border-radius: var(--radius);
142
- border: 1px solid transparent;
143
- cursor: pointer;
144
- transition: all 0.15s ease-in-out;
145
- text-decoration: none;
146
- white-space: nowrap;
147
- }
148
-
149
- .btn svg {
150
- flex-shrink: 0;
151
- }
152
-
153
- .btn-primary {
154
- background: var(--primary-color-ml);
155
- color: #ffffff;
156
- border-color: var(--primary-color-ml);
157
- box-shadow: 0 2px 4px rgba(15, 118, 110, 0.2);
158
- }
159
-
160
- .btn-primary:hover {
161
- background: var(--primary-dark-color-ml);
162
- border-color: var(--primary-dark-color-ml);
163
- color: #ffffff;
164
- transform: translateY(-1px);
165
- }
166
-
167
- .btn-outline {
168
- background: rgba(255, 255, 255, 0.9);
169
- color: var(--dark-color-ml);
170
- border-color: var(--border-color);
171
- }
172
-
173
- .btn-outline:hover {
174
- background: var(--primary-light-color-ml);
175
- color: var(--primary-dark-color-ml);
176
- border-color: var(--primary-color-ml);
177
- }
178
-
179
- .btn-danger {
180
- background: var(--danger-color-ml);
181
- color: #ffffff;
182
- border-color: var(--danger-color-ml);
183
- }
184
-
185
- .btn-danger:hover {
186
- background: #b91c1c;
187
- border-color: #b91c1c;
188
- color: #ffffff;
189
- }
190
-
191
- .btn-sm {
192
- padding: 5px 11px;
193
- font-size: 12px;
194
- }
195
-
196
- .btn-icon {
197
- width: 32px;
198
- height: 32px;
199
- padding: 0;
200
- display: inline-flex;
201
- align-items: center;
202
- justify-content: center;
203
- }
204
-
205
- /* File Manager Card Layout */
206
- .card.file-manager {
207
- background: rgba(255, 255, 255, 0.85);
208
- backdrop-filter: blur(14px);
209
- border: 1px solid rgba(255, 255, 255, 0.9);
210
- border-radius: var(--radius-lg);
211
- box-shadow: 0 14px 38px rgba(15, 23, 42, 0.06);
212
- overflow: hidden;
213
- }
214
-
215
- .fm-layout {
216
- display: grid;
217
- grid-template-columns: 260px minmax(0, 1fr);
218
- height: calc(100vh - 180px);
219
- min-height: 580px;
220
- max-height: 900px;
221
- }
222
-
223
- /* Left Sidebar Tree */
224
- .fm-tree-wrap {
225
- border-right: 1px solid var(--border-color);
226
- background: rgba(244, 247, 243, 0.65);
227
- display: flex;
228
- flex-direction: column;
229
- padding: 12px 10px;
230
- min-height: 0;
231
- }
232
-
233
- .fm-tree-header {
234
- padding: 4px 10px 8px;
235
- display: flex;
236
- align-items: center;
237
- justify-content: space-between;
238
- }
239
-
240
- .fm-tree-title {
241
- font-family: var(--font-headings);
242
- font-size: 11px;
243
- font-weight: 700;
244
- text-transform: uppercase;
245
- letter-spacing: 0.6px;
246
- color: var(--primary-dark-color-ml);
247
- }
248
-
249
- .fm-tree {
250
- flex: 1 1 auto;
251
- overflow-y: auto;
252
- padding-right: 4px;
253
- }
254
-
255
- .fm-tree::-webkit-scrollbar {
256
- width: 5px;
257
- }
258
- .fm-tree::-webkit-scrollbar-thumb {
259
- background: var(--gray-light-color-ml);
260
- border-radius: 3px;
261
- }
262
-
263
- .tree-group {
264
- margin-bottom: 3px;
265
- }
266
-
267
- .tree-link {
268
- display: flex;
269
- align-items: center;
270
- gap: 8px;
271
- width: 100%;
272
- padding: 7px 11px;
273
- background: transparent;
274
- border: none;
275
- border-radius: var(--radius-sm);
276
- font-family: var(--font);
277
- font-size: 13px;
278
- color: var(--text-secondary);
279
- text-align: left;
280
- cursor: pointer;
281
- transition: all 0.12s ease;
282
- user-select: none;
283
- font-weight: 500;
284
- }
285
-
286
- .tree-link:hover {
287
- background: rgba(255, 255, 255, 0.8);
288
- color: var(--primary-dark-color-ml);
289
- }
290
-
291
- .tree-link.active {
292
- background: var(--primary-light-color-ml);
293
- color: var(--primary-dark-color-ml);
294
- font-weight: 600;
295
- }
296
-
297
- .tree-link svg {
298
- color: var(--gray-color-ml);
299
- flex-shrink: 0;
300
- }
301
-
302
- .tree-link.active svg {
303
- color: var(--primary-color-ml);
304
- }
305
-
306
- .tree-link span {
307
- flex: 1 1 auto;
308
- min-width: 0;
309
- overflow: hidden;
310
- text-overflow: ellipsis;
311
- white-space: nowrap;
312
- color: inherit;
313
- font-size: 13px;
314
- }
315
-
316
- .tree-subs {
317
- display: flex;
318
- flex-direction: column;
319
- margin-left: 12px;
320
- padding-left: 6px;
321
- border-left: 1px solid var(--border-color);
322
- }
323
-
324
- .tree-sub {
325
- padding-left: 12px;
326
- }
327
-
328
- .tree-badge {
329
- font-size: 10.5px;
330
- padding: 1px 7px;
331
- border-radius: 99px;
332
- background: var(--primary-light-color-ml);
333
- color: var(--primary-dark-color-ml);
334
- font-weight: 600;
335
- }
336
-
337
- /* Sidebar Storage & Bucket Section */
338
- .fm-storage {
339
- margin-top: auto;
340
- padding: 12px;
341
- border-top: 1px solid var(--border-color);
342
- background: rgba(255, 255, 255, 0.85);
343
- border-radius: var(--radius);
344
- box-shadow: 0 2px 8px rgba(15, 118, 110, 0.05);
345
- }
346
-
347
- .fm-storage-label {
348
- font-size: 10.5px;
349
- font-weight: 700;
350
- text-transform: uppercase;
351
- letter-spacing: 0.5px;
352
- color: var(--primary-dark-color-ml);
353
- margin-bottom: 6px;
354
- }
355
-
356
- .bucket-switcher-wrap {
357
- position: relative;
358
- }
359
-
360
- .bucket-switcher-control {
361
- position: relative;
362
- display: flex;
363
- align-items: center;
364
- }
365
-
366
- .bucket-switcher-icon {
367
- position: absolute;
368
- left: 10px;
369
- color: var(--primary-color-ml);
370
- pointer-events: none;
371
- }
372
-
373
- .bucket-switcher-select {
374
- width: 100%;
375
- padding: 6px 10px 6px 30px;
376
- font-family: var(--font);
377
- font-size: 12.5px;
378
- font-weight: 600;
379
- color: var(--dark-color-ml);
380
- background: var(--light-color-ml);
381
- border: 1px solid var(--border-color);
382
- border-radius: var(--radius-sm);
383
- outline: none;
384
- cursor: pointer;
385
- appearance: auto;
386
- transition: border-color 0.15s ease;
387
- }
388
-
389
- .bucket-switcher-select:focus {
390
- border-color: var(--primary-color-ml);
391
- }
392
-
393
- .bucket-switcher-status {
394
- font-size: 11px;
395
- color: var(--primary-color-ml);
396
- margin-top: 4px;
397
- display: block;
398
- }
399
-
400
- .storage-bar {
401
- height: 5px;
402
- background: var(--gray-light-color-ml);
403
- border-radius: 3px;
404
- overflow: hidden;
405
- margin: 8px 0 6px;
406
- }
407
-
408
- .fm-storage-meta {
409
- font-size: 11.5px;
410
- color: var(--gray-color-ml);
411
- font-weight: 600;
412
- }
413
-
414
- .fm-storage-subinfo {
415
- font-size: 10.5px;
416
- color: var(--gray-color-ml);
417
- margin-top: 2px;
418
- white-space: nowrap;
419
- overflow: hidden;
420
- text-overflow: ellipsis;
421
- }
422
-
423
- /* Main Content Area */
424
- .fm-main {
425
- display: flex;
426
- flex-direction: column;
427
- min-height: 0;
428
- background: rgba(255, 255, 255, 0.9);
429
- }
430
-
431
- /* Toolbar */
432
- .fm-toolbar {
433
- display: flex;
434
- align-items: center;
435
- justify-content: space-between;
436
- gap: 12px;
437
- padding: 10px 16px;
438
- border-bottom: 1px solid var(--border-color);
439
- flex-shrink: 0;
440
- background: rgba(255, 255, 255, 0.7);
441
- flex-wrap: wrap;
442
- }
443
-
444
- .fm-breadcrumb {
445
- display: flex;
446
- align-items: center;
447
- gap: 5px;
448
- flex-wrap: wrap;
449
- min-height: 32px;
450
- }
451
-
452
- .bc-link {
453
- background: transparent;
454
- border: none;
455
- font-family: var(--font);
456
- font-size: 13px;
457
- color: var(--gray-color-ml);
458
- cursor: pointer;
459
- padding: 3px 8px;
460
- border-radius: var(--radius-sm);
461
- transition: all 0.12s ease;
462
- display: inline-flex;
463
- align-items: center;
464
- gap: 4px;
465
- font-weight: 500;
466
- }
467
-
468
- .bc-link:hover {
469
- background: var(--primary-light-color-ml);
470
- color: var(--primary-dark-color-ml);
471
- }
472
-
473
- .bc-link.current {
474
- color: var(--dark-color-ml);
475
- font-weight: 700;
476
- cursor: default;
477
- }
478
-
479
- .bc-link.current:hover {
480
- background: transparent;
481
- }
482
-
483
- .fm-breadcrumb .sep {
484
- color: var(--gray-color-ml);
485
- font-size: 13px;
486
- user-select: none;
487
- }
488
-
489
- .fm-toolbar-actions {
490
- display: flex;
491
- align-items: center;
492
- gap: 10px;
493
- margin-left: auto;
494
- }
495
-
496
- /* Quick Filters */
497
- .quick-filter-group {
498
- display: inline-flex;
499
- background: rgba(15, 118, 110, 0.06);
500
- border: 1px solid var(--border-color);
501
- border-radius: var(--radius);
502
- padding: 2px;
503
- }
504
-
505
- .quick-filter-btn {
506
- background: transparent;
507
- border: none;
508
- font-family: var(--font);
509
- font-size: 12px;
510
- font-weight: 600;
511
- color: var(--text-secondary);
512
- padding: 4px 11px;
513
- border-radius: var(--radius-sm);
514
- cursor: pointer;
515
- transition: all 0.12s ease;
516
- }
517
-
518
- .quick-filter-btn:hover {
519
- color: var(--primary-dark-color-ml);
520
- }
521
-
522
- .quick-filter-btn.active {
523
- background: #ffffff;
524
- color: var(--primary-color-ml);
525
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
526
- }
527
-
528
- /* Search Box */
529
- .search-box {
530
- position: relative;
531
- width: 210px;
532
- display: flex;
533
- align-items: center;
534
- }
535
-
536
- .search-box .s-icon {
537
- position: absolute;
538
- left: 9px;
539
- width: 14px;
540
- height: 14px;
541
- color: var(--gray-color-ml);
542
- pointer-events: none;
543
- }
544
-
545
- .search-box input {
546
- width: 100%;
547
- padding: 6px 26px 6px 28px;
548
- font-family: var(--font);
549
- font-size: 12.5px;
550
- border: 1px solid var(--border-color);
551
- border-radius: var(--radius);
552
- background: rgba(255, 255, 255, 0.85);
553
- color: var(--dark-color-ml);
554
- outline: none;
555
- transition: all 0.15s ease;
556
- }
557
-
558
- .search-box input:focus {
559
- border-color: var(--primary-color-ml);
560
- background: #ffffff;
561
- box-shadow: 0 0 0 3px var(--primary-light-color-ml);
562
- }
563
-
564
- .search-clear-btn {
565
- position: absolute;
566
- right: 6px;
567
- background: transparent;
568
- border: none;
569
- color: var(--gray-color-ml);
570
- cursor: pointer;
571
- font-size: 16px;
572
- line-height: 1;
573
- padding: 2px 4px;
574
- }
575
-
576
- /* View Switcher */
577
- .fm-view-toggle {
578
- display: inline-flex;
579
- border: 1px solid var(--border-color);
580
- border-radius: var(--radius);
581
- overflow: hidden;
582
- background: #ffffff;
583
- }
584
-
585
- .view-btn {
586
- width: 32px;
587
- height: 30px;
588
- border: none;
589
- background: transparent;
590
- cursor: pointer;
591
- color: var(--gray-color-ml);
592
- display: flex;
593
- align-items: center;
594
- justify-content: center;
595
- transition: all 0.12s ease;
596
- }
597
-
598
- .view-btn:hover {
599
- background: var(--light-color-ml);
600
- color: var(--dark-color-ml);
601
- }
602
-
603
- .view-btn.active {
604
- background: var(--primary-light-color-ml);
605
- color: var(--primary-dark-color-ml);
606
- }
607
-
608
- /* File Grid Wrap & Items */
609
- .fm-grid-wrap {
610
- flex: 1 1 auto;
611
- overflow-y: auto;
612
- padding: 16px;
613
- position: relative;
614
- }
615
-
616
- .fm-grid-wrap::-webkit-scrollbar {
617
- width: 6px;
618
- }
619
- .fm-grid-wrap::-webkit-scrollbar-thumb {
620
- background: var(--gray-light-color-ml);
621
- border-radius: 3px;
622
- }
623
-
624
- /* Grid View */
625
- .fm-grid.view-grid {
626
- display: grid;
627
- grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
628
- grid-auto-rows: max-content;
629
- align-content: start;
630
- gap: 14px;
631
- }
632
-
633
- .fm-item {
634
- position: relative;
635
- background: rgba(255, 255, 255, 0.95);
636
- border: 1px solid rgba(15, 118, 110, 0.15);
637
- border-radius: var(--radius-lg);
638
- cursor: pointer;
639
- font-family: var(--font);
640
- text-align: left;
641
- transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
642
- user-select: none;
643
- }
644
-
645
- .fm-item:hover {
646
- border-color: var(--primary-color-ml);
647
- transform: translateY(-2px);
648
- box-shadow: 0 8px 20px rgba(15, 118, 110, 0.1);
649
- }
650
-
651
- .fm-item.is-selected {
652
- border-color: var(--primary-color-ml);
653
- background: var(--primary-light-color-ml);
654
- }
655
-
656
- /* Item styling in Grid View */
657
- .fm-grid.view-grid .fm-item {
658
- padding: 12px;
659
- display: flex;
660
- flex-direction: column;
661
- align-items: flex-start;
662
- gap: 8px;
663
- }
664
-
665
- .fm-grid.view-grid .fm-item-icon {
666
- width: 100%;
667
- aspect-ratio: 16 / 10;
668
- border-radius: var(--radius);
669
- display: flex;
670
- align-items: center;
671
- justify-content: center;
672
- flex-shrink: 0;
673
- background: var(--light-color-ml);
674
- overflow: hidden;
675
- position: relative;
676
- }
677
-
678
- .view-btn#view-thumbs {
679
- border-left: 1px solid var(--border-color);
680
- }
681
-
682
- .fm-item-thumb {
683
- width: 100%;
684
- height: 100%;
685
- object-fit: cover;
686
- transition: opacity 0.25s ease-in-out;
687
- }
688
-
689
- .fm-item-thumb.fm-lazy-thumb {
690
- opacity: 0;
691
- }
692
-
693
- .fm-item-thumb.fm-lazy-thumb.is-loaded {
694
- opacity: 1;
695
- }
696
-
697
- .fm-item-icon .ext {
698
- font-size: 13px;
699
- font-weight: 700;
700
- letter-spacing: 0.6px;
701
- text-transform: uppercase;
702
- }
703
-
704
- .fm-item-icon .folder-svg {
705
- width: 42px;
706
- height: 42px;
707
- }
708
-
709
- .fm-grid.view-grid .fm-item-details {
710
- width: 100%;
711
- min-width: 0;
712
- }
713
-
714
- .fm-item-name {
715
- font-size: 13px;
716
- font-weight: 600;
717
- color: var(--dark-color-ml);
718
- overflow: hidden;
719
- text-overflow: ellipsis;
720
- white-space: nowrap;
721
- min-width: 0;
722
- }
723
-
724
- .fm-item-meta {
725
- font-size: 11.5px;
726
- color: var(--gray-color-ml);
727
- margin-top: 2px;
728
- white-space: nowrap;
729
- overflow: hidden;
730
- text-overflow: ellipsis;
731
- }
732
-
733
- /* Star & Context Menu Buttons */
734
- .fm-star {
735
- position: absolute;
736
- top: 8px;
737
- left: 8px;
738
- width: 24px;
739
- height: 24px;
740
- display: flex;
741
- align-items: center;
742
- justify-content: center;
743
- cursor: pointer;
744
- border-radius: 50%;
745
- color: var(--text-disabled);
746
- opacity: 0;
747
- background: rgba(255, 255, 255, 0.9);
748
- backdrop-filter: blur(4px);
749
- transition: opacity 0.12s ease, color 0.12s ease;
750
- z-index: 2;
751
- border: none;
752
- }
753
-
754
- .fm-item:hover .fm-star,
755
- .fm-item.starred .fm-star {
756
- opacity: 1;
757
- }
758
-
759
- .fm-star.on {
760
- color: var(--yellow);
761
- opacity: 1;
762
- }
763
-
764
- .fm-star:hover {
765
- color: var(--yellow);
766
- transform: scale(1.1);
767
- }
768
-
769
- .fm-item-menu {
770
- position: absolute;
771
- top: 8px;
772
- right: 8px;
773
- width: 24px;
774
- height: 24px;
775
- border: none;
776
- background: rgba(255, 255, 255, 0.9);
777
- backdrop-filter: blur(4px);
778
- border-radius: 50%;
779
- display: flex;
780
- align-items: center;
781
- justify-content: center;
782
- cursor: pointer;
783
- color: var(--gray-color-ml);
784
- opacity: 0;
785
- transition: opacity 0.12s ease, background 0.12s ease, color 0.12s ease;
786
- z-index: 2;
787
- }
788
-
789
- .fm-item:hover .fm-item-menu {
790
- opacity: 1;
791
- }
792
-
793
- .fm-item-menu:hover {
794
- background: #ffffff;
795
- color: var(--primary-dark-color-ml);
796
- box-shadow: var(--shadow-sm);
797
- }
798
-
799
- /* List View */
800
- .fm-grid.view-list {
801
- display: flex;
802
- flex-direction: column;
803
- gap: 4px;
804
- }
805
-
806
- .fm-grid.view-list .fm-item {
807
- padding: 8px 14px;
808
- display: grid;
809
- grid-template-columns: 20px 32px 1fr 110px 140px 32px 32px;
810
- gap: 12px;
811
- align-items: center;
812
- border-radius: var(--radius);
813
- }
814
-
815
- .fm-grid.view-list .fm-item-icon {
816
- width: 32px;
817
- height: 32px;
818
- border-radius: var(--radius-sm);
819
- display: flex;
820
- align-items: center;
821
- justify-content: center;
822
- background: var(--light-color-ml);
823
- }
824
-
825
- .fm-grid.view-list .fm-item-icon .ext {
826
- font-size: 10.5px;
827
- font-weight: 700;
828
- }
829
-
830
- .fm-grid.view-list .fm-item-icon .folder-svg {
831
- width: 22px;
832
- height: 22px;
833
- }
834
-
835
- .fm-grid.view-list .fm-star,
836
- .fm-grid.view-list .fm-item-menu {
837
- position: static;
838
- opacity: 1;
839
- background: transparent;
840
- }
841
-
842
- .fm-grid.view-list .fm-item-meta {
843
- font-size: 12px;
844
- margin-top: 0;
845
- }
846
-
847
- /* Header row for list view */
848
- .fm-list-header {
849
- display: grid;
850
- grid-template-columns: 20px 32px 1fr 110px 140px 32px 32px;
851
- gap: 12px;
852
- align-items: center;
853
- padding: 6px 14px;
854
- font-size: 11px;
855
- font-weight: 700;
856
- text-transform: uppercase;
857
- letter-spacing: 0.5px;
858
- color: var(--primary-dark-color-ml);
859
- border-bottom: 1px solid var(--border-color);
860
- margin-bottom: 4px;
861
- }
862
-
863
- /* Empty State */
864
- .fm-empty {
865
- padding: 80px 20px;
866
- text-align: center;
867
- color: var(--gray-color-ml);
868
- display: flex;
869
- flex-direction: column;
870
- align-items: center;
871
- justify-content: center;
872
- }
873
-
874
- .fm-empty[hidden],
875
- [hidden] {
876
- display: none !important;
877
- }
878
-
879
- .fm-empty svg {
880
- color: var(--text-disabled);
881
- margin-bottom: 12px;
882
- }
883
-
884
- .fm-empty .empty-title {
885
- font-family: var(--font-headings);
886
- font-size: 15px;
887
- font-weight: 700;
888
- color: var(--dark-color-ml);
889
- margin-bottom: 4px;
890
- }
891
-
892
- .fm-empty .empty-desc {
893
- font-size: 13px;
894
- max-width: 360px;
895
- }
896
-
897
- /* Skeletons */
898
- .fm-skeleton-grid {
899
- display: grid;
900
- grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
901
- gap: 14px;
902
- width: 100%;
903
- }
904
-
905
- .fm-skeleton-card {
906
- background: rgba(255, 255, 255, 0.8);
907
- border: 1px solid var(--border-color-light);
908
- border-radius: var(--radius-lg);
909
- padding: 12px;
910
- display: flex;
911
- flex-direction: column;
912
- gap: 8px;
913
- }
914
-
915
- .fm-skeleton-icon {
916
- width: 100%;
917
- aspect-ratio: 16 / 10;
918
- border-radius: var(--radius);
919
- background: linear-gradient(90deg, #eaf2ee 25%, #dce8e3 50%, #eaf2ee 75%);
920
- background-size: 200% 100%;
921
- animation: fm-shimmer 1.5s infinite;
922
- }
923
-
924
- .fm-skeleton-line {
925
- height: 12px;
926
- border-radius: 4px;
927
- background: linear-gradient(90deg, #eaf2ee 25%, #dce8e3 50%, #eaf2ee 75%);
928
- background-size: 200% 100%;
929
- animation: fm-shimmer 1.5s infinite;
930
- }
931
-
932
- .fm-skeleton-line.w-75 { width: 75%; }
933
- .fm-skeleton-line.w-50 { width: 50%; }
934
-
935
- @keyframes fm-shimmer {
936
- 0% { background-position: 200% 0; }
937
- 100% { background-position: -200% 0; }
938
- }
939
-
940
- /* Context Menu */
941
- .fm-context-menu {
942
- position: fixed;
943
- z-index: 1000;
944
- background: rgba(255, 255, 255, 0.95);
945
- backdrop-filter: blur(12px);
946
- border: 1px solid var(--border-color);
947
- border-radius: var(--radius-lg);
948
- box-shadow: var(--shadow-dropdown);
949
- padding: 6px;
950
- min-width: 175px;
951
- animation: fm-menu-pop 0.12s cubic-bezier(0.16, 1, 0.3, 1);
952
- }
953
-
954
- @keyframes fm-menu-pop {
955
- from { opacity: 0; transform: scale(0.95); }
956
- to { opacity: 1; transform: scale(1); }
957
- }
958
-
959
- .fm-context-item {
960
- display: flex;
961
- align-items: center;
962
- gap: 8px;
963
- width: 100%;
964
- padding: 7px 11px;
965
- border: none;
966
- background: transparent;
967
- font-family: var(--font);
968
- font-size: 12.5px;
969
- font-weight: 500;
970
- color: var(--dark-color-ml);
971
- border-radius: var(--radius-sm);
972
- cursor: pointer;
973
- text-align: left;
974
- transition: background 0.1s ease, color 0.1s ease;
975
- }
976
-
977
- .fm-context-item:hover {
978
- background: var(--primary-light-color-ml);
979
- color: var(--primary-dark-color-ml);
980
- }
981
-
982
- .fm-context-item.danger:hover {
983
- background: var(--red-lt);
984
- color: var(--danger-color-ml);
985
- }
986
-
987
- .fm-context-divider {
988
- height: 1px;
989
- background: var(--border-color-light);
990
- margin: 4px 0;
991
- }
992
-
993
- /* Modals */
994
- .modal {
995
- display: none;
996
- position: fixed;
997
- inset: 0;
998
- z-index: 1050;
999
- overflow-x: hidden;
1000
- overflow-y: auto;
1001
- background: rgba(15, 42, 42, 0.45);
1002
- backdrop-filter: blur(6px);
1003
- align-items: center;
1004
- justify-content: center;
1005
- padding: 1rem;
1006
- }
1007
-
1008
- .modal.show {
1009
- display: flex;
1010
- }
1011
-
1012
- .modal-dialog {
1013
- position: relative;
1014
- width: 100%;
1015
- max-width: 480px;
1016
- margin: auto;
1017
- animation: modal-enter 0.2s cubic-bezier(0.16, 1, 0.3, 1);
1018
- }
1019
-
1020
- .modal-dialog.modal-lg {
1021
- max-width: 680px;
1022
- }
1023
-
1024
- .modal-dialog.preview-modal-dialog {
1025
- max-width: 900px;
1026
- }
1027
-
1028
- .preview-modal-dialog.is-fullscreen {
1029
- max-width: 98vw;
1030
- height: 96vh;
1031
- }
1032
-
1033
- .preview-modal-dialog.is-fullscreen .modal-content {
1034
- height: 100%;
1035
- }
1036
-
1037
- .preview-modal-dialog.is-fullscreen .preview-content {
1038
- max-height: calc(96vh - 120px);
1039
- }
1040
-
1041
- @keyframes modal-enter {
1042
- from { opacity: 0; transform: translateY(-12px) scale(0.98); }
1043
- to { opacity: 1; transform: translateY(0) scale(1); }
1044
- }
1045
-
1046
- .modal-content {
1047
- position: relative;
1048
- display: flex;
1049
- flex-direction: column;
1050
- width: 100%;
1051
- background: #ffffff;
1052
- border: 1px solid var(--border-color);
1053
- border-radius: var(--radius-xl);
1054
- box-shadow: 0 20px 40px rgba(15, 42, 42, 0.16);
1055
- outline: 0;
1056
- }
1057
-
1058
- .modal-header {
1059
- display: flex;
1060
- align-items: center;
1061
- justify-content: space-between;
1062
- padding: 14px 18px;
1063
- border-bottom: 1px solid var(--border-color);
1064
- }
1065
-
1066
- .modal-title {
1067
- font-family: var(--font-headings);
1068
- display: flex;
1069
- align-items: center;
1070
- gap: 8px;
1071
- font-size: 15px;
1072
- font-weight: 700;
1073
- color: var(--primary-dark-color-ml);
1074
- margin: 0;
1075
- }
1076
-
1077
- .modal-title-icon {
1078
- color: var(--primary-color-ml);
1079
- }
1080
-
1081
- .btn-close {
1082
- background: transparent;
1083
- border: none;
1084
- font-size: 20px;
1085
- line-height: 1;
1086
- color: var(--gray-color-ml);
1087
- cursor: pointer;
1088
- padding: 4px;
1089
- border-radius: var(--radius-sm);
1090
- transition: all 0.12s ease;
1091
- }
1092
-
1093
- .btn-close:hover {
1094
- color: var(--dark-color-ml);
1095
- background: var(--light-color-ml);
1096
- }
1097
-
1098
- .modal-body {
1099
- position: relative;
1100
- flex: 1 1 auto;
1101
- padding: 18px;
1102
- }
1103
-
1104
- .modal-footer {
1105
- display: flex;
1106
- align-items: center;
1107
- justify-content: flex-end;
1108
- gap: 8px;
1109
- padding: 12px 18px;
1110
- border-top: 1px solid var(--border-color);
1111
- background: var(--light-color-ml);
1112
- border-bottom-left-radius: var(--radius-xl);
1113
- border-bottom-right-radius: var(--radius-xl);
1114
- }
1115
-
1116
- /* Upload Dropzone & Queue */
1117
- .upload-drop-zone {
1118
- border: 2px dashed var(--primary-color-ml);
1119
- border-radius: var(--radius-lg);
1120
- padding: 32px 20px;
1121
- text-align: center;
1122
- background: var(--primary-light-color-ml);
1123
- cursor: pointer;
1124
- transition: all 0.15s ease;
1125
- }
1126
-
1127
- .upload-drop-zone:hover,
1128
- .upload-drop-zone.dragover {
1129
- border-color: var(--primary-dark-color-ml);
1130
- background: #c5efe7;
1131
- }
1132
-
1133
- .drop-icon {
1134
- color: var(--primary-color-ml);
1135
- margin-bottom: 10px;
1136
- }
1137
-
1138
- .drop-text {
1139
- font-size: 14px;
1140
- font-weight: 600;
1141
- color: var(--dark-color-ml);
1142
- }
1143
-
1144
- .drop-browse-link {
1145
- color: var(--primary-color-ml);
1146
- text-decoration: underline;
1147
- cursor: pointer;
1148
- }
1149
-
1150
- .drop-hint {
1151
- font-size: 12px;
1152
- color: var(--gray-color-ml);
1153
- margin-top: 4px;
1154
- }
1155
-
1156
- .upload-queue {
1157
- max-height: 200px;
1158
- overflow-y: auto;
1159
- display: flex;
1160
- flex-direction: column;
1161
- gap: 6px;
1162
- }
1163
-
1164
- .upload-queue-item {
1165
- display: flex;
1166
- align-items: center;
1167
- justify-content: space-between;
1168
- padding: 8px 12px;
1169
- background: var(--light-color-ml);
1170
- border: 1px solid var(--border-color);
1171
- border-radius: var(--radius);
1172
- font-size: 12.5px;
1173
- }
1174
-
1175
- .upload-queue-meta {
1176
- color: var(--gray-color-ml);
1177
- font-size: 11.5px;
1178
- }
1179
-
1180
- .progress-bar-wrap {
1181
- height: 6px;
1182
- background: var(--gray-light-color-ml);
1183
- border-radius: 3px;
1184
- overflow: hidden;
1185
- }
1186
-
1187
- .progress-bar-inner {
1188
- height: 100%;
1189
- background: var(--primary-color-ml);
1190
- transition: width 0.2s ease;
1191
- }
1192
-
1193
- .upload-percent {
1194
- font-size: 12px;
1195
- font-weight: 700;
1196
- color: var(--primary-color-ml);
1197
- }
1198
-
1199
- /* Modal Form Inputs */
1200
- .form-label {
1201
- font-size: 12.5px;
1202
- font-weight: 600;
1203
- color: var(--dark-color-ml);
1204
- margin-bottom: 6px;
1205
- display: block;
1206
- }
1207
-
1208
- .form-control {
1209
- width: 100%;
1210
- padding: 8px 12px;
1211
- font-family: var(--font);
1212
- font-size: 13px;
1213
- color: var(--dark-color-ml);
1214
- background: #ffffff;
1215
- border: 1px solid var(--border-color);
1216
- border-radius: var(--radius);
1217
- outline: none;
1218
- transition: border-color 0.15s ease, box-shadow 0.15s ease;
1219
- }
1220
-
1221
- .form-control:focus {
1222
- border-color: var(--primary-color-ml);
1223
- box-shadow: 0 0 0 3px var(--primary-light-color-ml);
1224
- }
1225
-
1226
- .form-text {
1227
- font-size: 11.5px;
1228
- color: var(--gray-color-ml);
1229
- margin-top: 4px;
1230
- }
1231
-
1232
- /* Preview Modal Content */
1233
- .preview-content {
1234
- max-height: 70vh;
1235
- overflow: auto;
1236
- display: flex;
1237
- align-items: center;
1238
- justify-content: center;
1239
- background: #152222;
1240
- min-height: 280px;
1241
- }
1242
-
1243
- .preview-content img {
1244
- max-width: 100%;
1245
- max-height: 70vh;
1246
- object-fit: contain;
1247
- }
1248
-
1249
- .preview-content video,
1250
- .preview-content audio {
1251
- max-width: 100%;
1252
- max-height: 70vh;
1253
- }
1254
-
1255
- .preview-code-block {
1256
- width: 100%;
1257
- height: 100%;
1258
- max-height: 70vh;
1259
- margin: 0;
1260
- padding: 16px;
1261
- background: #1a2828;
1262
- color: #f4f7f3;
1263
- font-family: var(--font-mono);
1264
- font-size: 12.5px;
1265
- overflow: auto;
1266
- line-height: 1.5;
1267
- }
1268
-
1269
- .preview-iframe {
1270
- width: 100%;
1271
- height: 70vh;
1272
- border: none;
1273
- }
1274
-
1275
- .preview-actions {
1276
- display: flex;
1277
- align-items: center;
1278
- gap: 8px;
1279
- }
1280
-
1281
- /* Toast Container & Notifications */
1282
- .toast-container {
1283
- position: fixed;
1284
- bottom: 20px;
1285
- right: 20px;
1286
- z-index: 1100;
1287
- display: flex;
1288
- flex-direction: column;
1289
- gap: 8px;
1290
- pointer-events: none;
1291
- }
1292
-
1293
- .toast-notification {
1294
- pointer-events: auto;
1295
- display: flex;
1296
- align-items: center;
1297
- gap: 10px;
1298
- padding: 10px 16px;
1299
- border-radius: var(--radius);
1300
- background: var(--dark-color-ml);
1301
- color: #ffffff;
1302
- font-family: var(--font);
1303
- font-size: 13px;
1304
- font-weight: 500;
1305
- box-shadow: var(--shadow-lg);
1306
- min-width: 260px;
1307
- max-width: 400px;
1308
- transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease;
1309
- }
1310
-
1311
- .toast-notification.success {
1312
- background: linear-gradient(135deg, #10b981, #059669);
1313
- }
1314
-
1315
- .toast-notification.error {
1316
- background: linear-gradient(135deg, #ef4444, #dc2626);
1317
- }
1318
-
1319
- .toast-notification.warning {
1320
- background: linear-gradient(135deg, #f59e0b, #d97706);
1321
- }
1322
-
1323
- .toast-close-btn {
1324
- margin-left: auto;
1325
- background: transparent;
1326
- border: none;
1327
- color: rgba(255, 255, 255, 0.85);
1328
- cursor: pointer;
1329
- font-size: 16px;
1330
- line-height: 1;
1331
- }
1332
-
1333
- /* Pagination */
1334
- .pagination-container {
1335
- padding: 12px 16px;
1336
- border-top: 1px solid var(--border-color);
1337
- display: flex;
1338
- align-items: center;
1339
- justify-content: flex-end;
1340
- }
1341
-
1342
- .pagination {
1343
- display: flex;
1344
- align-items: center;
1345
- gap: 4px;
1346
- list-style: none;
1347
- margin: 0;
1348
- padding: 0;
1349
- }
1350
-
1351
- .page-item .page-link {
1352
- display: flex;
1353
- align-items: center;
1354
- justify-content: center;
1355
- min-width: 28px;
1356
- height: 28px;
1357
- padding: 0 6px;
1358
- border-radius: var(--radius-sm);
1359
- border: 1px solid var(--border-color);
1360
- background: #ffffff;
1361
- color: var(--text-secondary);
1362
- font-size: 12px;
1363
- font-weight: 600;
1364
- text-decoration: none;
1365
- cursor: pointer;
1366
- transition: all 0.12s ease;
1367
- }
1368
-
1369
- .page-item .page-link:hover {
1370
- background: var(--primary-light-color-ml);
1371
- color: var(--primary-dark-color-ml);
1372
- }
1373
-
1374
- .page-item.active .page-link {
1375
- background: var(--primary-color-ml);
1376
- border-color: var(--primary-color-ml);
1377
- color: #ffffff;
1378
- }
1379
-
1380
- .page-item.disabled .page-link {
1381
- opacity: 0.4;
1382
- cursor: not-allowed;
1383
- }
1384
-
1385
- /* Mobile & Tablet Responsiveness */
1386
- @media (max-width: 900px) {
1387
- .page-wrapper {
1388
- padding: 0;
1389
- max-width: 100%;
1390
- overflow-x: hidden;
1391
- }
1392
-
1393
- .card.file-manager {
1394
- border-radius: var(--radius-md);
1395
- width: 100%;
1396
- max-width: 100%;
1397
- overflow: hidden;
1398
- }
1399
-
1400
- .fm-layout {
1401
- grid-template-columns: 100%;
1402
- height: auto;
1403
- min-height: 0;
1404
- max-height: none;
1405
- width: 100%;
1406
- max-width: 100%;
1407
- overflow: hidden;
1408
- }
1409
-
1410
- .fm-tree-wrap {
1411
- display: flex;
1412
- border-right: none;
1413
- border-bottom: 1px solid var(--border-color);
1414
- padding: 10px 14px;
1415
- background: rgba(244, 247, 243, 0.85);
1416
- width: 100%;
1417
- max-width: 100%;
1418
- box-sizing: border-box;
1419
- }
1420
-
1421
- .fm-tree-header,
1422
- .fm-tree {
1423
- display: none;
1424
- }
1425
-
1426
- .fm-storage {
1427
- margin-top: 0;
1428
- padding: 8px 12px;
1429
- background: rgba(255, 255, 255, 0.95);
1430
- border: 1px solid var(--border-color);
1431
- border-radius: var(--radius-sm);
1432
- box-shadow: 0 1px 4px rgba(15, 118, 110, 0.05);
1433
- width: 100%;
1434
- max-width: 100%;
1435
- box-sizing: border-box;
1436
- }
1437
-
1438
- .fm-main {
1439
- width: 100%;
1440
- max-width: 100%;
1441
- min-width: 0;
1442
- overflow: hidden;
1443
- }
1444
-
1445
- .fm-grid-wrap {
1446
- min-height: 400px;
1447
- padding: 12px;
1448
- width: 100%;
1449
- max-width: 100%;
1450
- box-sizing: border-box;
1451
- overflow-x: hidden;
1452
- }
1453
-
1454
- .fm-grid.view-grid {
1455
- grid-template-columns: repeat(auto-fill, minmax(135px, 1fr));
1456
- gap: 10px;
1457
- width: 100%;
1458
- max-width: 100%;
1459
- }
1460
-
1461
- .fm-item {
1462
- -webkit-tap-highlight-color: transparent;
1463
- width: 100%;
1464
- max-width: 100%;
1465
- min-width: 0;
1466
- box-sizing: border-box;
1467
- }
1468
-
1469
- .fm-item-details {
1470
- width: 100%;
1471
- max-width: 100%;
1472
- min-width: 0;
1473
- overflow: hidden;
1474
- }
1475
-
1476
- .fm-item-name {
1477
- width: 100%;
1478
- max-width: 100%;
1479
- min-width: 0;
1480
- overflow: hidden;
1481
- text-overflow: ellipsis;
1482
- white-space: nowrap;
1483
- }
1484
-
1485
- .fm-item:active {
1486
- transform: scale(0.98);
1487
- background: var(--primary-light-color-ml);
1488
- }
1489
-
1490
- .fm-item-menu {
1491
- opacity: 1;
1492
- background: rgba(255, 255, 255, 0.92);
1493
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
1494
- }
1495
-
1496
- .fm-star.on {
1497
- opacity: 1;
1498
- }
1499
- }
1500
-
1501
- @media (max-width: 640px) {
1502
- .page-header {
1503
- padding: 0.75rem 1rem;
1504
- margin-bottom: 0.75rem;
1505
- border-radius: var(--radius);
1506
- width: 100%;
1507
- max-width: 100%;
1508
- }
1509
-
1510
- .page-header-row {
1511
- flex-direction: column;
1512
- align-items: stretch;
1513
- gap: 10px;
1514
- width: 100%;
1515
- }
1516
-
1517
- .page-actions {
1518
- width: 100%;
1519
- display: flex;
1520
- justify-content: stretch;
1521
- gap: 8px;
1522
- }
1523
-
1524
- .page-actions .btn {
1525
- flex: 1 1 0;
1526
- min-width: 0;
1527
- justify-content: center;
1528
- padding: 7px 8px;
1529
- font-size: 12px;
1530
- }
1531
-
1532
- .fm-toolbar {
1533
- flex-direction: column;
1534
- align-items: stretch;
1535
- gap: 8px;
1536
- padding: 8px 10px;
1537
- width: 100%;
1538
- max-width: 100%;
1539
- overflow: hidden;
1540
- }
1541
-
1542
- .fm-breadcrumb {
1543
- max-width: 100%;
1544
- overflow-x: auto;
1545
- white-space: nowrap;
1546
- padding-bottom: 2px;
1547
- scrollbar-width: none;
1548
- }
1549
-
1550
- .fm-breadcrumb::-webkit-scrollbar {
1551
- display: none;
1552
- }
1553
-
1554
- .fm-toolbar-actions {
1555
- width: 100%;
1556
- display: flex;
1557
- flex-direction: column;
1558
- align-items: stretch;
1559
- gap: 8px;
1560
- max-width: 100%;
1561
- }
1562
-
1563
- .quick-filter-group {
1564
- width: 100%;
1565
- display: flex;
1566
- overflow-x: auto;
1567
- scrollbar-width: none;
1568
- max-width: 100%;
1569
- }
1570
-
1571
- .quick-filter-group::-webkit-scrollbar {
1572
- display: none;
1573
- }
1574
-
1575
- .quick-filter-btn {
1576
- flex: 1 1 0;
1577
- text-align: center;
1578
- padding: 5px 6px;
1579
- font-size: 11.5px;
1580
- white-space: nowrap;
1581
- }
1582
-
1583
- .search-box {
1584
- width: 100%;
1585
- max-width: 100%;
1586
- }
1587
-
1588
- .search-box input {
1589
- width: 100%;
1590
- box-sizing: border-box;
1591
- }
1592
-
1593
- /* Grid Mode on Small Phones */
1594
- .fm-grid.view-grid {
1595
- grid-template-columns: repeat(2, minmax(0, 1fr));
1596
- gap: 8px;
1597
- width: 100%;
1598
- max-width: 100%;
1599
- }
1600
-
1601
- .fm-grid.view-grid .fm-item {
1602
- padding: 8px;
1603
- border-radius: var(--radius-md);
1604
- gap: 6px;
1605
- width: 100%;
1606
- max-width: 100%;
1607
- min-width: 0;
1608
- }
1609
-
1610
- .fm-grid.view-grid .fm-item-icon {
1611
- aspect-ratio: 16 / 11;
1612
- width: 100%;
1613
- }
1614
-
1615
- .fm-item-name {
1616
- font-size: 12px;
1617
- line-height: 1.35;
1618
- }
1619
-
1620
- .fm-item-meta {
1621
- font-size: 10px;
1622
- }
1623
-
1624
- .fm-item-menu {
1625
- top: 5px;
1626
- right: 5px;
1627
- width: 26px;
1628
- height: 26px;
1629
- }
1630
-
1631
- .fm-star {
1632
- top: 5px;
1633
- left: 5px;
1634
- width: 22px;
1635
- height: 22px;
1636
- }
1637
-
1638
- /* List Mode on Mobile */
1639
- .fm-grid.view-list {
1640
- gap: 6px;
1641
- width: 100%;
1642
- max-width: 100%;
1643
- }
1644
-
1645
- .fm-grid.view-list .fm-item {
1646
- display: flex;
1647
- align-items: center;
1648
- gap: 8px;
1649
- padding: 8px 10px;
1650
- border-radius: var(--radius-md);
1651
- width: 100%;
1652
- max-width: 100%;
1653
- min-width: 0;
1654
- }
1655
-
1656
- .fm-grid.view-list .fm-item-checkbox {
1657
- display: flex;
1658
- align-items: center;
1659
- justify-content: center;
1660
- flex-shrink: 0;
1661
- }
1662
-
1663
- .fm-grid.view-list .fm-item-icon {
1664
- width: 32px;
1665
- height: 32px;
1666
- flex-shrink: 0;
1667
- border-radius: var(--radius-sm);
1668
- }
1669
-
1670
- .fm-grid.view-list .fm-item-name {
1671
- flex: 1 1 auto;
1672
- min-width: 0;
1673
- font-size: 12.5px;
1674
- font-weight: 600;
1675
- color: var(--dark-color-ml);
1676
- overflow: hidden;
1677
- text-overflow: ellipsis;
1678
- white-space: nowrap;
1679
- }
1680
-
1681
- .fm-grid.view-list .fm-item-size,
1682
- .fm-grid.view-list .fm-item-date,
1683
- .fm-grid.view-list .fm-star-wrap {
1684
- display: none;
1685
- }
1686
-
1687
- .fm-grid.view-list .fm-item-menu {
1688
- flex-shrink: 0;
1689
- width: 28px;
1690
- height: 28px;
1691
- display: flex;
1692
- align-items: center;
1693
- justify-content: center;
1694
- opacity: 1;
1695
- color: var(--gray-color-ml);
1696
- border-radius: 6px;
1697
- background: transparent;
1698
- box-shadow: none;
1699
- }
1700
-
1701
- .fm-grid.view-list .fm-item-menu:active {
1702
- background: var(--light-color-ml);
1703
- }
1704
-
1705
- .fm-list-header {
1706
- display: none;
1707
- }
1708
- }
1
+ /* ==========================================================================
2
+ MBKBucket File Manager - Clean, Modern Storage Dashboard
3
+ Design System: Refined Slate & Deep Teal Palette
4
+ ========================================================================== */
5
+
6
+ :root {
7
+ /* Brand / Primary Palette */
8
+ --primary-color-ml: #0f766e;
9
+ --primary-light-color-ml: #f0fdfa;
10
+ --primary-dark-color-ml: #115e59;
11
+ --secondary-color-ml: #14b8a6;
12
+ --dark-color-ml: #0f172a;
13
+ --light-color-ml: #f8fafc;
14
+ --gray-color-ml: #64748b;
15
+ --gray-light-color-ml: #e2e8f0;
16
+ --danger-color-ml: #ef4444;
17
+ --warning-color-ml: #f59e0b;
18
+ --success-color-ml: #10b981;
19
+ --info-color-ml: #0284c7;
20
+
21
+ /* Aliases */
22
+ --primary: var(--primary-color-ml);
23
+ --primary-lt: var(--primary-light-color-ml);
24
+ --primary-dk: var(--primary-dark-color-ml);
25
+ --primary-hover: #134e4a;
26
+ --primary-active: #084c47;
27
+
28
+ /* Surfaces & Backgrounds */
29
+ --body-bg: #f8fafc;
30
+ --bg-surface: #ffffff;
31
+ --bg-surface-secondary: #f8fafc;
32
+ --bg-surface-tertiary: #f1f5f9;
33
+ --bg-surface-hover: #f1f5f9;
34
+
35
+ /* Borders */
36
+ --border-color: #e2e8f0;
37
+ --border-color-light: #f1f5f9;
38
+ --border-color-focus: #0f766e;
39
+
40
+ /* Text */
41
+ --text: #0f172a;
42
+ --text-secondary: #475569;
43
+ --text-muted: #64748b;
44
+ --text-disabled: #94a3b8;
45
+
46
+ /* Accent Colors */
47
+ --blue: #2563eb;
48
+ --azure: #0891b2;
49
+ --green: #10b981;
50
+ --yellow: #d97706;
51
+ --orange: #ea580c;
52
+ --red: #ef4444;
53
+ --purple: #7c3aed;
54
+ --cyan: #0f766e;
55
+
56
+ /* Light Accent Tints */
57
+ --green-lt: #ecfdf5;
58
+ --red-lt: #fef2f2;
59
+ --yellow-lt: #fffbeb;
60
+ --blue-lt: #eff6ff;
61
+ --azure-lt: #ecfeff;
62
+ --purple-lt: #f5f3ff;
63
+ --cyan-lt: #f0fdfa;
64
+
65
+ /* Geometry */
66
+ --radius-sm: 6px;
67
+ --radius: 8px;
68
+ --radius-lg: 12px;
69
+ --radius-xl: 16px;
70
+
71
+ /* Modern Subtle Shadows */
72
+ --shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.05);
73
+ --shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.06), 0 1px 2px rgba(15, 23, 42, 0.04);
74
+ --shadow: 0 4px 6px -1px rgba(15, 23, 42, 0.06), 0 2px 4px -2px rgba(15, 23, 42, 0.04);
75
+ --shadow-md: 0 10px 15px -3px rgba(15, 23, 42, 0.07), 0 4px 6px -4px rgba(15, 23, 42, 0.03);
76
+ --shadow-lg: 0 20px 25px -5px rgba(15, 23, 42, 0.08), 0 8px 10px -6px rgba(15, 23, 42, 0.04);
77
+ --shadow-dropdown: 0 10px 25px -5px rgba(15, 23, 42, 0.12), 0 8px 10px -6px rgba(15, 23, 42, 0.04);
78
+
79
+ /* Fonts */
80
+ --font: "Segoe UI", -apple-system, BlinkMacSystemFont, system-ui, Roboto, sans-serif;
81
+ --font-headings: "Segoe UI", -apple-system, BlinkMacSystemFont, system-ui, Roboto, sans-serif;
82
+ --font-mono: "Segoe UI Mono", "Cascadia Code", Consolas, "Courier New", monospace;
83
+ }
84
+
85
+ /* ==========================================================================
86
+ Base Layout & Reset
87
+ ========================================================================== */
88
+ .page-wrapper,
89
+ .page-wrapper *,
90
+ .page-wrapper *::before,
91
+ .page-wrapper *::after,
92
+ .modal,
93
+ .modal * {
94
+ box-sizing: border-box;
95
+ }
96
+
97
+ body,
98
+ button,
99
+ input,
100
+ optgroup,
101
+ select,
102
+ textarea,
103
+ .page-wrapper,
104
+ .modal,
105
+ .modal-content,
106
+ .info-card,
107
+ .info-value,
108
+ .info-label,
109
+ .file-info-pane,
110
+ .fm-context-menu,
111
+ .toast-notification,
112
+ .batch-bar-inner {
113
+ font-family: var(--font);
114
+ }
115
+
116
+ .page-wrapper {
117
+ max-width: 1600px;
118
+ margin: 0 auto;
119
+ width: 100%;
120
+ }
121
+
122
+ /* ==========================================================================
123
+ Page Header
124
+ ========================================================================== */
125
+ .page-header {
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: space-between;
129
+ margin-bottom: 1rem;
130
+ padding: 0.85rem 1.25rem;
131
+ border: 1px solid var(--border-color);
132
+ border-radius: var(--radius-lg);
133
+ background: #ffffff;
134
+ box-shadow: var(--shadow-xs);
135
+ }
136
+
137
+ .page-header-row {
138
+ display: flex;
139
+ align-items: center;
140
+ justify-content: space-between;
141
+ width: 100%;
142
+ gap: 1rem;
143
+ }
144
+
145
+ .page-pretitle {
146
+ font-size: 11px;
147
+ font-weight: 700;
148
+ text-transform: uppercase;
149
+ letter-spacing: 0.06em;
150
+ color: var(--primary);
151
+ margin-bottom: 3px;
152
+ }
153
+
154
+ .page-title {
155
+ font-family: var(--font-headings);
156
+ font-size: 1.35rem;
157
+ font-weight: 700;
158
+ color: var(--text);
159
+ margin: 0;
160
+ line-height: 1.25;
161
+ letter-spacing: -0.015em;
162
+ display: flex;
163
+ align-items: center;
164
+ gap: 0.5rem;
165
+ }
166
+
167
+ .page-actions {
168
+ display: flex;
169
+ align-items: center;
170
+ gap: 0.5rem;
171
+ }
172
+
173
+ /* ==========================================================================
174
+ Button System
175
+ ========================================================================== */
176
+ .btn {
177
+ display: inline-flex;
178
+ align-items: center;
179
+ justify-content: center;
180
+ gap: 0.45rem;
181
+ font-family: var(--font);
182
+ font-size: 13px;
183
+ font-weight: 600;
184
+ line-height: 1.4;
185
+ padding: 7px 14px;
186
+ border-radius: var(--radius-sm);
187
+ border: 1px solid transparent;
188
+ cursor: pointer;
189
+ transition: background-color 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease, color 0.12s ease;
190
+ text-decoration: none;
191
+ white-space: nowrap;
192
+ user-select: none;
193
+ }
194
+
195
+ .btn svg {
196
+ flex-shrink: 0;
197
+ }
198
+
199
+ .btn:focus-visible {
200
+ outline: none;
201
+ box-shadow: 0 0 0 2px var(--primary-light-color-ml), 0 0 0 4px var(--primary);
202
+ }
203
+
204
+ .btn-primary {
205
+ background: var(--primary);
206
+ color: #ffffff;
207
+ border-color: var(--primary-dark-color-ml);
208
+ box-shadow: var(--shadow-xs);
209
+ }
210
+
211
+ .btn-primary:hover {
212
+ background: var(--primary-hover);
213
+ border-color: var(--primary-hover);
214
+ color: #ffffff;
215
+ }
216
+
217
+ .btn-primary:active {
218
+ background: var(--primary-active);
219
+ }
220
+
221
+ .btn-outline {
222
+ background: #ffffff;
223
+ color: var(--text);
224
+ border-color: var(--border-color);
225
+ box-shadow: var(--shadow-xs);
226
+ }
227
+
228
+ .btn-outline:hover {
229
+ background: #f8fafc;
230
+ color: var(--text);
231
+ border-color: #cbd5e1;
232
+ }
233
+
234
+ .btn-outline:active {
235
+ background: #f1f5f9;
236
+ }
237
+
238
+ .btn-danger {
239
+ background: var(--danger-color-ml);
240
+ color: #ffffff;
241
+ border-color: var(--danger-color-ml);
242
+ box-shadow: var(--shadow-xs);
243
+ }
244
+
245
+ .btn-danger:hover {
246
+ background: #dc2626;
247
+ border-color: #dc2626;
248
+ color: #ffffff;
249
+ }
250
+
251
+ .btn-danger:active {
252
+ background: #b91c1c;
253
+ }
254
+
255
+ .btn-sm {
256
+ padding: 5px 10px;
257
+ font-size: 12px;
258
+ border-radius: var(--radius-sm);
259
+ }
260
+
261
+ .btn-icon {
262
+ width: 32px;
263
+ height: 32px;
264
+ padding: 0;
265
+ display: inline-flex;
266
+ align-items: center;
267
+ justify-content: center;
268
+ }
269
+
270
+ /* ==========================================================================
271
+ Main File Manager Card & Layout
272
+ ========================================================================== */
273
+ .card.file-manager {
274
+ background: #ffffff;
275
+ border: 1px solid var(--border-color);
276
+ border-radius: var(--radius-lg);
277
+ box-shadow: var(--shadow-sm);
278
+ overflow: hidden;
279
+ }
280
+
281
+ .fm-layout {
282
+ display: grid;
283
+ grid-template-columns: 260px minmax(0, 1fr);
284
+ height: calc(100vh - 170px);
285
+ min-height: 580px;
286
+ max-height: 900px;
287
+ }
288
+
289
+ /* ==========================================================================
290
+ Left Sidebar Tree (Explorer)
291
+ ========================================================================== */
292
+ .fm-tree-wrap {
293
+ border-right: 1px solid var(--border-color);
294
+ background: #f8fafc;
295
+ display: flex;
296
+ flex-direction: column;
297
+ padding: 12px 10px;
298
+ min-height: 0;
299
+ }
300
+
301
+ .fm-tree-header {
302
+ padding: 4px 8px 8px;
303
+ display: flex;
304
+ align-items: center;
305
+ justify-content: space-between;
306
+ }
307
+
308
+ .fm-tree-title {
309
+ font-family: var(--font-headings);
310
+ font-size: 11px;
311
+ font-weight: 700;
312
+ text-transform: uppercase;
313
+ letter-spacing: 0.06em;
314
+ color: var(--text-muted);
315
+ }
316
+
317
+ .fm-tree {
318
+ flex: 1 1 auto;
319
+ overflow-y: auto;
320
+ padding-right: 4px;
321
+ }
322
+
323
+ .fm-tree::-webkit-scrollbar {
324
+ width: 4px;
325
+ }
326
+
327
+ .fm-tree::-webkit-scrollbar-thumb {
328
+ background: #cbd5e1;
329
+ border-radius: 2px;
330
+ }
331
+
332
+ .tree-group {
333
+ margin-bottom: 2px;
334
+ }
335
+
336
+ .tree-link {
337
+ display: flex;
338
+ align-items: center;
339
+ gap: 8px;
340
+ width: 100%;
341
+ padding: 6px 10px;
342
+ background: transparent;
343
+ border: none;
344
+ border-radius: var(--radius-sm);
345
+ font-family: var(--font);
346
+ font-size: 13px;
347
+ color: var(--text-secondary);
348
+ text-align: left;
349
+ cursor: pointer;
350
+ transition: background-color 0.12s ease, color 0.12s ease;
351
+ user-select: none;
352
+ font-weight: 500;
353
+ }
354
+
355
+ .tree-link:hover {
356
+ background: #f1f5f9;
357
+ color: var(--text);
358
+ }
359
+
360
+ .tree-link.active {
361
+ background: var(--primary-light-color-ml);
362
+ color: var(--primary-dark-color-ml);
363
+ font-weight: 600;
364
+ }
365
+
366
+ .tree-link svg {
367
+ color: var(--text-muted);
368
+ flex-shrink: 0;
369
+ }
370
+
371
+ .tree-link.active svg {
372
+ color: var(--primary);
373
+ }
374
+
375
+ .tree-link span {
376
+ flex: 1 1 auto;
377
+ min-width: 0;
378
+ overflow: hidden;
379
+ text-overflow: ellipsis;
380
+ white-space: nowrap;
381
+ font-size: 13px;
382
+ }
383
+
384
+ .tree-subs {
385
+ display: flex;
386
+ flex-direction: column;
387
+ margin-left: 12px;
388
+ padding-left: 6px;
389
+ border-left: 1px solid var(--border-color);
390
+ }
391
+
392
+ .tree-sub {
393
+ padding-left: 10px;
394
+ }
395
+
396
+ .tree-badge {
397
+ font-size: 10.5px;
398
+ padding: 1px 6px;
399
+ border-radius: 99px;
400
+ background: #e2e8f0;
401
+ color: var(--text-secondary);
402
+ font-weight: 600;
403
+ }
404
+
405
+ .tree-link.active .tree-badge {
406
+ background: #ccfbf1;
407
+ color: var(--primary-dark-color-ml);
408
+ }
409
+
410
+ /* ==========================================================================
411
+ Sidebar Storage & Bucket Switcher
412
+ ========================================================================== */
413
+ .fm-storage {
414
+ margin-top: auto;
415
+ padding: 12px;
416
+ border-top: 1px solid var(--border-color);
417
+ background: #ffffff;
418
+ border-radius: var(--radius-sm);
419
+ border: 1px solid var(--border-color);
420
+ box-shadow: var(--shadow-xs);
421
+ }
422
+
423
+ .fm-storage-label {
424
+ font-size: 11px;
425
+ font-weight: 700;
426
+ text-transform: uppercase;
427
+ letter-spacing: 0.05em;
428
+ color: var(--text-muted);
429
+ margin-bottom: 6px;
430
+ }
431
+
432
+ .bucket-switcher-wrap {
433
+ position: relative;
434
+ }
435
+
436
+ .bucket-switcher-control {
437
+ position: relative;
438
+ display: flex;
439
+ align-items: center;
440
+ }
441
+
442
+ .bucket-switcher-icon {
443
+ position: absolute;
444
+ left: 9px;
445
+ color: var(--primary);
446
+ pointer-events: none;
447
+ }
448
+
449
+ .bucket-switcher-select {
450
+ width: 100%;
451
+ padding: 6px 10px 6px 28px;
452
+ font-family: var(--font);
453
+ font-size: 12.5px;
454
+ font-weight: 600;
455
+ color: var(--text);
456
+ background: #ffffff;
457
+ border: 1px solid var(--border-color);
458
+ border-radius: var(--radius-sm);
459
+ outline: none;
460
+ cursor: pointer;
461
+ appearance: auto;
462
+ transition: border-color 0.12s ease, box-shadow 0.12s ease;
463
+ }
464
+
465
+ .bucket-switcher-select:focus {
466
+ border-color: var(--primary);
467
+ box-shadow: 0 0 0 2px rgba(15, 118, 110, 0.15);
468
+ }
469
+
470
+ .bucket-switcher-status {
471
+ font-size: 11px;
472
+ color: var(--primary);
473
+ margin-top: 4px;
474
+ display: block;
475
+ }
476
+
477
+ .bucket-switcher-status.is-hidden {
478
+ display: none;
479
+ }
480
+
481
+ .storage-bar {
482
+ height: 4px;
483
+ background: #f1f5f9;
484
+ border-radius: 2px;
485
+ overflow: hidden;
486
+ margin: 8px 0 6px;
487
+ }
488
+
489
+ .fm-storage-meta {
490
+ font-size: 11.5px;
491
+ color: var(--text-muted);
492
+ font-weight: 500;
493
+ }
494
+
495
+ .fm-storage-subinfo {
496
+ font-size: 11px;
497
+ color: var(--text-muted);
498
+ margin-top: 2px;
499
+ white-space: nowrap;
500
+ overflow: hidden;
501
+ text-overflow: ellipsis;
502
+ }
503
+
504
+ /* ==========================================================================
505
+ Main Content Area & Toolbar
506
+ ========================================================================== */
507
+ .fm-main {
508
+ display: flex;
509
+ flex-direction: column;
510
+ min-height: 0;
511
+ background: #ffffff;
512
+ }
513
+
514
+ .fm-toolbar {
515
+ display: flex;
516
+ align-items: center;
517
+ justify-content: space-between;
518
+ gap: 12px;
519
+ padding: 10px 16px;
520
+ border-bottom: 1px solid var(--border-color);
521
+ flex-shrink: 0;
522
+ background: #ffffff;
523
+ flex-wrap: wrap;
524
+ }
525
+
526
+ .fm-breadcrumb {
527
+ display: flex;
528
+ align-items: center;
529
+ gap: 4px;
530
+ flex-wrap: wrap;
531
+ min-height: 32px;
532
+ }
533
+
534
+ .bc-link {
535
+ background: transparent;
536
+ border: none;
537
+ font-family: var(--font);
538
+ font-size: 13px;
539
+ color: var(--text-muted);
540
+ cursor: pointer;
541
+ padding: 3px 6px;
542
+ border-radius: var(--radius-sm);
543
+ transition: background-color 0.12s ease, color 0.12s ease;
544
+ display: inline-flex;
545
+ align-items: center;
546
+ gap: 4px;
547
+ font-weight: 500;
548
+ }
549
+
550
+ .bc-link:hover {
551
+ background: #f1f5f9;
552
+ color: var(--text);
553
+ }
554
+
555
+ .bc-link.current {
556
+ color: var(--text);
557
+ font-weight: 600;
558
+ cursor: default;
559
+ }
560
+
561
+ .bc-link.current:hover {
562
+ background: transparent;
563
+ }
564
+
565
+ .fm-breadcrumb .sep {
566
+ color: #cbd5e1;
567
+ font-size: 12px;
568
+ user-select: none;
569
+ }
570
+
571
+ .fm-toolbar-actions {
572
+ display: flex;
573
+ align-items: center;
574
+ gap: 8px;
575
+ margin-left: auto;
576
+ }
577
+
578
+ /* Quick Filters - Segmented Control */
579
+ .quick-filter-group {
580
+ display: inline-flex;
581
+ background: #f1f5f9;
582
+ border: 1px solid var(--border-color);
583
+ border-radius: var(--radius-sm);
584
+ padding: 2px;
585
+ gap: 2px;
586
+ }
587
+
588
+ .quick-filter-btn {
589
+ background: transparent;
590
+ border: none;
591
+ font-family: var(--font);
592
+ font-size: 12px;
593
+ font-weight: 500;
594
+ color: var(--text-secondary);
595
+ padding: 3px 9px;
596
+ border-radius: 4px;
597
+ cursor: pointer;
598
+ transition: background-color 0.12s ease, color 0.12s ease;
599
+ }
600
+
601
+ .quick-filter-btn:hover {
602
+ color: var(--text);
603
+ }
604
+
605
+ .quick-filter-btn.active {
606
+ background: #ffffff;
607
+ color: var(--primary-dark-color-ml);
608
+ font-weight: 600;
609
+ box-shadow: var(--shadow-xs);
610
+ }
611
+
612
+ /* Search Box */
613
+ .search-box {
614
+ position: relative;
615
+ width: 200px;
616
+ display: flex;
617
+ align-items: center;
618
+ }
619
+
620
+ .search-box .s-icon {
621
+ position: absolute;
622
+ left: 9px;
623
+ width: 14px;
624
+ height: 14px;
625
+ color: var(--text-muted);
626
+ pointer-events: none;
627
+ }
628
+
629
+ .search-box input {
630
+ width: 100%;
631
+ padding: 5px 24px 5px 28px;
632
+ font-family: var(--font);
633
+ font-size: 12.5px;
634
+ border: 1px solid var(--border-color);
635
+ border-radius: var(--radius-sm);
636
+ background: #ffffff;
637
+ color: var(--text);
638
+ outline: none;
639
+ transition: border-color 0.12s ease, box-shadow 0.12s ease;
640
+ }
641
+
642
+ .search-box input:focus {
643
+ border-color: var(--primary);
644
+ box-shadow: 0 0 0 2px rgba(15, 118, 110, 0.15);
645
+ }
646
+
647
+ .search-clear-btn {
648
+ position: absolute;
649
+ right: 6px;
650
+ background: transparent;
651
+ border: none;
652
+ color: var(--text-muted);
653
+ cursor: pointer;
654
+ font-size: 15px;
655
+ line-height: 1;
656
+ padding: 2px;
657
+ }
658
+
659
+ .search-clear-btn:hover {
660
+ color: var(--text);
661
+ }
662
+
663
+ /* View Switcher */
664
+ .fm-view-toggle {
665
+ display: inline-flex;
666
+ border: 1px solid var(--border-color);
667
+ border-radius: var(--radius-sm);
668
+ overflow: hidden;
669
+ background: #ffffff;
670
+ }
671
+
672
+ .view-btn {
673
+ width: 30px;
674
+ height: 28px;
675
+ border: none;
676
+ background: transparent;
677
+ cursor: pointer;
678
+ color: var(--text-muted);
679
+ display: flex;
680
+ align-items: center;
681
+ justify-content: center;
682
+ transition: background-color 0.12s ease, color 0.12s ease;
683
+ }
684
+
685
+ .view-btn:hover {
686
+ background: #f1f5f9;
687
+ color: var(--text);
688
+ }
689
+
690
+ .view-btn.active {
691
+ background: var(--primary-light-color-ml);
692
+ color: var(--primary-dark-color-ml);
693
+ }
694
+
695
+ .view-btn#view-thumbs {
696
+ border-left: 1px solid var(--border-color);
697
+ }
698
+
699
+ /* ==========================================================================
700
+ File Grid Container & Grid Items
701
+ ========================================================================== */
702
+ .fm-grid-wrap {
703
+ flex: 1 1 auto;
704
+ overflow-y: auto;
705
+ padding: 16px;
706
+ position: relative;
707
+ background: #ffffff;
708
+ }
709
+
710
+ .fm-grid-wrap::-webkit-scrollbar {
711
+ width: 6px;
712
+ }
713
+
714
+ .fm-grid-wrap::-webkit-scrollbar-thumb {
715
+ background: #cbd5e1;
716
+ border-radius: 3px;
717
+ }
718
+
719
+ /* Grid View */
720
+ .fm-grid.view-grid {
721
+ display: grid;
722
+ grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
723
+ grid-auto-rows: max-content;
724
+ align-content: start;
725
+ gap: 12px;
726
+ }
727
+
728
+ .fm-item {
729
+ position: relative;
730
+ background: #ffffff;
731
+ border: 1px solid var(--border-color);
732
+ border-radius: var(--radius);
733
+ cursor: pointer;
734
+ font-family: var(--font);
735
+ text-align: left;
736
+ transition: border-color 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease;
737
+ user-select: none;
738
+ }
739
+
740
+ .fm-item:hover {
741
+ border-color: #cbd5e1;
742
+ box-shadow: var(--shadow-sm);
743
+ }
744
+
745
+ .fm-item.is-selected {
746
+ border-color: var(--primary);
747
+ background: var(--primary-light-color-ml);
748
+ }
749
+
750
+ /* Item in Grid View */
751
+ .fm-grid.view-grid .fm-item {
752
+ padding: 10px;
753
+ display: flex;
754
+ flex-direction: column;
755
+ align-items: flex-start;
756
+ gap: 8px;
757
+ }
758
+
759
+ .fm-grid.view-grid .fm-item-icon {
760
+ width: 100%;
761
+ aspect-ratio: 16 / 10;
762
+ border-radius: var(--radius-sm);
763
+ display: flex;
764
+ align-items: center;
765
+ justify-content: center;
766
+ flex-shrink: 0;
767
+ background: #f8fafc;
768
+ border: 1px solid var(--border-color-light);
769
+ overflow: hidden;
770
+ position: relative;
771
+ }
772
+
773
+ .fm-item-thumb {
774
+ width: 100%;
775
+ height: 100%;
776
+ object-fit: cover;
777
+ transition: opacity 0.2s ease;
778
+ }
779
+
780
+ .fm-item-thumb.fm-lazy-thumb {
781
+ opacity: 0;
782
+ }
783
+
784
+ .fm-item-thumb.fm-lazy-thumb.is-loaded {
785
+ opacity: 1;
786
+ }
787
+
788
+ .fm-item-icon .ext {
789
+ font-size: 11px;
790
+ font-weight: 700;
791
+ letter-spacing: 0.04em;
792
+ text-transform: uppercase;
793
+ padding: 2px 7px;
794
+ border-radius: 4px;
795
+ }
796
+
797
+ .fm-item-icon .folder-svg {
798
+ width: 40px;
799
+ height: 40px;
800
+ }
801
+
802
+ .fm-grid.view-grid .fm-item-details {
803
+ width: 100%;
804
+ min-width: 0;
805
+ }
806
+
807
+ .fm-item-name {
808
+ font-size: 12.5px;
809
+ font-weight: 600;
810
+ color: var(--text);
811
+ overflow: hidden;
812
+ text-overflow: ellipsis;
813
+ white-space: nowrap;
814
+ min-width: 0;
815
+ line-height: 1.35;
816
+ }
817
+
818
+ .fm-item-meta {
819
+ font-size: 11px;
820
+ color: var(--text-muted);
821
+ margin-top: 2px;
822
+ white-space: nowrap;
823
+ overflow: hidden;
824
+ text-overflow: ellipsis;
825
+ }
826
+
827
+ /* Star & Menu Action Triggers */
828
+ .fm-star {
829
+ position: absolute;
830
+ top: 6px;
831
+ left: 6px;
832
+ width: 22px;
833
+ height: 22px;
834
+ display: flex;
835
+ align-items: center;
836
+ justify-content: center;
837
+ cursor: pointer;
838
+ border-radius: 50%;
839
+ color: var(--text-disabled);
840
+ opacity: 0;
841
+ background: #ffffff;
842
+ border: 1px solid var(--border-color);
843
+ box-shadow: var(--shadow-xs);
844
+ transition: opacity 0.12s ease, color 0.12s ease;
845
+ z-index: 2;
846
+ }
847
+
848
+ .fm-item:hover .fm-star,
849
+ .fm-item.starred .fm-star {
850
+ opacity: 1;
851
+ }
852
+
853
+ .fm-star.on {
854
+ color: #eab308;
855
+ opacity: 1;
856
+ }
857
+
858
+ .fm-star:hover {
859
+ color: #eab308;
860
+ }
861
+
862
+ .fm-item-menu {
863
+ position: absolute;
864
+ top: 6px;
865
+ right: 6px;
866
+ width: 22px;
867
+ height: 22px;
868
+ border: 1px solid var(--border-color);
869
+ background: #ffffff;
870
+ border-radius: 50%;
871
+ display: flex;
872
+ align-items: center;
873
+ justify-content: center;
874
+ cursor: pointer;
875
+ color: var(--text-muted);
876
+ opacity: 0;
877
+ box-shadow: var(--shadow-xs);
878
+ transition: opacity 0.12s ease, color 0.12s ease, background-color 0.12s ease;
879
+ z-index: 2;
880
+ }
881
+
882
+ .fm-item:hover .fm-item-menu {
883
+ opacity: 1;
884
+ }
885
+
886
+ .fm-item-menu:hover {
887
+ background: #f8fafc;
888
+ color: var(--text);
889
+ }
890
+
891
+ /* ==========================================================================
892
+ List View
893
+ ========================================================================== */
894
+ .fm-grid.view-list {
895
+ display: flex;
896
+ flex-direction: column;
897
+ gap: 2px;
898
+ }
899
+
900
+ .fm-grid.view-list .fm-item {
901
+ padding: 6px 12px;
902
+ display: grid;
903
+ grid-template-columns: 20px 30px 1fr 110px 140px 28px 28px;
904
+ gap: 10px;
905
+ align-items: center;
906
+ border-radius: var(--radius-sm);
907
+ border: 1px solid transparent;
908
+ }
909
+
910
+ .fm-grid.view-list .fm-item:hover {
911
+ background: #f8fafc;
912
+ border-color: var(--border-color);
913
+ }
914
+
915
+ .fm-grid.view-list .fm-item.is-selected {
916
+ background: var(--primary-light-color-ml);
917
+ border-color: #ccfbf1;
918
+ }
919
+
920
+ .fm-grid.view-list .fm-item-icon {
921
+ width: 28px;
922
+ height: 28px;
923
+ border-radius: 4px;
924
+ display: flex;
925
+ align-items: center;
926
+ justify-content: center;
927
+ background: #f8fafc;
928
+ border: 1px solid var(--border-color-light);
929
+ }
930
+
931
+ .fm-grid.view-list .fm-item-icon .ext {
932
+ font-size: 10px;
933
+ font-weight: 700;
934
+ padding: 1px 4px;
935
+ }
936
+
937
+ .fm-grid.view-list .fm-item-icon .folder-svg {
938
+ width: 20px;
939
+ height: 20px;
940
+ }
941
+
942
+ .fm-grid.view-list .fm-star,
943
+ .fm-grid.view-list .fm-item-menu {
944
+ position: static;
945
+ opacity: 1;
946
+ background: transparent;
947
+ border: none;
948
+ box-shadow: none;
949
+ }
950
+
951
+ .fm-grid.view-list .fm-item-meta {
952
+ font-size: 12px;
953
+ margin-top: 0;
954
+ }
955
+
956
+ .fm-list-header {
957
+ display: grid;
958
+ grid-template-columns: 20px 30px 1fr 110px 140px 28px 28px;
959
+ gap: 10px;
960
+ align-items: center;
961
+ padding: 6px 12px;
962
+ font-size: 11px;
963
+ font-weight: 700;
964
+ text-transform: uppercase;
965
+ letter-spacing: 0.05em;
966
+ color: var(--text-muted);
967
+ border-bottom: 1px solid var(--border-color);
968
+ margin-bottom: 2px;
969
+ }
970
+
971
+ /* ==========================================================================
972
+ Empty State & Skeletons
973
+ ========================================================================== */
974
+ .fm-empty {
975
+ padding: 64px 20px;
976
+ text-align: center;
977
+ color: var(--text-muted);
978
+ display: flex;
979
+ flex-direction: column;
980
+ align-items: center;
981
+ justify-content: center;
982
+ }
983
+
984
+ .fm-empty[hidden],
985
+ [hidden] {
986
+ display: none !important;
987
+ }
988
+
989
+ .fm-empty svg {
990
+ color: #cbd5e1;
991
+ margin-bottom: 12px;
992
+ }
993
+
994
+ .fm-empty .empty-title {
995
+ font-family: var(--font-headings);
996
+ font-size: 15px;
997
+ font-weight: 700;
998
+ color: var(--text);
999
+ margin-bottom: 4px;
1000
+ }
1001
+
1002
+ .fm-empty .empty-desc {
1003
+ font-size: 13px;
1004
+ max-width: 360px;
1005
+ color: var(--text-secondary);
1006
+ }
1007
+
1008
+ .fm-skeleton-grid {
1009
+ display: grid;
1010
+ grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
1011
+ gap: 12px;
1012
+ width: 100%;
1013
+ }
1014
+
1015
+ .fm-skeleton-card {
1016
+ background: #ffffff;
1017
+ border: 1px solid var(--border-color);
1018
+ border-radius: var(--radius);
1019
+ padding: 10px;
1020
+ display: flex;
1021
+ flex-direction: column;
1022
+ gap: 8px;
1023
+ }
1024
+
1025
+ .fm-skeleton-icon {
1026
+ width: 100%;
1027
+ aspect-ratio: 16 / 10;
1028
+ border-radius: var(--radius-sm);
1029
+ background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);
1030
+ background-size: 200% 100%;
1031
+ animation: fm-shimmer 1.5s infinite;
1032
+ }
1033
+
1034
+ .fm-skeleton-line {
1035
+ height: 10px;
1036
+ border-radius: 4px;
1037
+ background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);
1038
+ background-size: 200% 100%;
1039
+ animation: fm-shimmer 1.5s infinite;
1040
+ }
1041
+
1042
+ .fm-skeleton-line.w-75 { width: 75%; }
1043
+ .fm-skeleton-line.w-50 { width: 50%; }
1044
+
1045
+ @keyframes fm-shimmer {
1046
+ 0% { background-position: 200% 0; }
1047
+ 100% { background-position: -200% 0; }
1048
+ }
1049
+
1050
+ /* ==========================================================================
1051
+ Context Menu
1052
+ ========================================================================== */
1053
+ .fm-context-menu {
1054
+ position: fixed;
1055
+ z-index: 1000;
1056
+ background: #ffffff;
1057
+ border: 1px solid var(--border-color);
1058
+ border-radius: var(--radius-sm);
1059
+ box-shadow: var(--shadow-dropdown);
1060
+ padding: 4px;
1061
+ min-width: 165px;
1062
+ animation: fm-menu-pop 0.1s cubic-bezier(0.16, 1, 0.3, 1);
1063
+ }
1064
+
1065
+ @keyframes fm-menu-pop {
1066
+ from { opacity: 0; transform: scale(0.96); }
1067
+ to { opacity: 1; transform: scale(1); }
1068
+ }
1069
+
1070
+ .fm-context-item {
1071
+ display: flex;
1072
+ align-items: center;
1073
+ gap: 8px;
1074
+ width: 100%;
1075
+ padding: 6px 10px;
1076
+ border: none;
1077
+ background: transparent;
1078
+ font-family: var(--font);
1079
+ font-size: 12.5px;
1080
+ font-weight: 500;
1081
+ color: var(--text);
1082
+ border-radius: 4px;
1083
+ cursor: pointer;
1084
+ text-align: left;
1085
+ transition: background-color 0.1s ease, color 0.1s ease;
1086
+ }
1087
+
1088
+ .fm-context-item:hover {
1089
+ background: #f1f5f9;
1090
+ color: var(--primary-dark-color-ml);
1091
+ }
1092
+
1093
+ .fm-context-item.danger:hover {
1094
+ background: var(--red-lt);
1095
+ color: var(--danger-color-ml);
1096
+ }
1097
+
1098
+ .fm-context-divider {
1099
+ height: 1px;
1100
+ background: var(--border-color);
1101
+ margin: 3px 0;
1102
+ }
1103
+
1104
+ /* ==========================================================================
1105
+ Modals & Dialogs
1106
+ ========================================================================== */
1107
+ .modal {
1108
+ display: none;
1109
+ position: fixed;
1110
+ inset: 0;
1111
+ z-index: 1050;
1112
+ overflow-x: hidden;
1113
+ overflow-y: auto;
1114
+ background: rgba(15, 23, 42, 0.5);
1115
+ backdrop-filter: blur(4px);
1116
+ align-items: center;
1117
+ justify-content: center;
1118
+ padding: 1rem;
1119
+ }
1120
+
1121
+ .modal.show {
1122
+ display: flex;
1123
+ }
1124
+
1125
+ .modal-dialog {
1126
+ position: relative;
1127
+ width: 100%;
1128
+ max-width: 480px;
1129
+ margin: auto;
1130
+ animation: modal-enter 0.18s cubic-bezier(0.16, 1, 0.3, 1);
1131
+ }
1132
+
1133
+ .modal-dialog.modal-lg {
1134
+ max-width: 680px;
1135
+ }
1136
+
1137
+ .modal-dialog.preview-modal-dialog {
1138
+ max-width: 900px;
1139
+ }
1140
+
1141
+ .preview-modal-dialog.is-fullscreen {
1142
+ max-width: 98vw;
1143
+ height: 96vh;
1144
+ }
1145
+
1146
+ .preview-modal-dialog.is-fullscreen .modal-content {
1147
+ height: 100%;
1148
+ }
1149
+
1150
+ .preview-modal-dialog.is-fullscreen .preview-content {
1151
+ max-height: calc(96vh - 120px);
1152
+ }
1153
+
1154
+ @keyframes modal-enter {
1155
+ from { opacity: 0; transform: translateY(-8px) scale(0.98); }
1156
+ to { opacity: 1; transform: translateY(0) scale(1); }
1157
+ }
1158
+
1159
+ .modal-content {
1160
+ position: relative;
1161
+ display: flex;
1162
+ flex-direction: column;
1163
+ width: 100%;
1164
+ background: #ffffff;
1165
+ border: 1px solid var(--border-color);
1166
+ border-radius: var(--radius-xl);
1167
+ box-shadow: var(--shadow-dropdown);
1168
+ outline: 0;
1169
+ overflow: hidden;
1170
+ }
1171
+
1172
+ .modal-header {
1173
+ display: flex;
1174
+ align-items: center;
1175
+ justify-content: space-between;
1176
+ padding: 12px 18px;
1177
+ border-bottom: 1px solid var(--border-color);
1178
+ background: #ffffff;
1179
+ }
1180
+
1181
+ .modal-title {
1182
+ font-family: var(--font-headings);
1183
+ display: flex;
1184
+ align-items: center;
1185
+ gap: 8px;
1186
+ font-size: 15px;
1187
+ font-weight: 700;
1188
+ color: var(--text);
1189
+ margin: 0;
1190
+ }
1191
+
1192
+ .modal-title-icon {
1193
+ color: var(--primary);
1194
+ }
1195
+
1196
+ .btn-close {
1197
+ background: transparent;
1198
+ border: none;
1199
+ font-size: 20px;
1200
+ line-height: 1;
1201
+ color: var(--text-muted);
1202
+ cursor: pointer;
1203
+ padding: 4px;
1204
+ border-radius: var(--radius-sm);
1205
+ transition: color 0.12s ease, background-color 0.12s ease;
1206
+ }
1207
+
1208
+ .btn-close:hover {
1209
+ color: var(--text);
1210
+ background: #f1f5f9;
1211
+ }
1212
+
1213
+ .modal-body {
1214
+ position: relative;
1215
+ flex: 1 1 auto;
1216
+ padding: 18px;
1217
+ }
1218
+
1219
+ .modal-footer {
1220
+ display: flex;
1221
+ align-items: center;
1222
+ justify-content: flex-end;
1223
+ gap: 8px;
1224
+ padding: 12px 18px;
1225
+ border-top: 1px solid var(--border-color);
1226
+ background: #f8fafc;
1227
+ }
1228
+
1229
+ /* ==========================================================================
1230
+ Upload Dropzone & Queue
1231
+ ========================================================================== */
1232
+ .upload-drop-zone {
1233
+ border: 1.5px dashed #cbd5e1;
1234
+ border-radius: var(--radius);
1235
+ padding: 28px 16px;
1236
+ text-align: center;
1237
+ background: #f8fafc;
1238
+ cursor: pointer;
1239
+ transition: border-color 0.12s ease, background-color 0.12s ease;
1240
+ }
1241
+
1242
+ .upload-drop-zone:hover,
1243
+ .upload-drop-zone.dragover {
1244
+ border-color: var(--primary);
1245
+ background: var(--primary-light-color-ml);
1246
+ }
1247
+
1248
+ .drop-icon {
1249
+ color: var(--primary);
1250
+ margin-bottom: 8px;
1251
+ }
1252
+
1253
+ .drop-text {
1254
+ font-size: 13.5px;
1255
+ font-weight: 600;
1256
+ color: var(--text);
1257
+ }
1258
+
1259
+ .drop-browse-link {
1260
+ color: var(--primary);
1261
+ text-decoration: underline;
1262
+ cursor: pointer;
1263
+ }
1264
+
1265
+ .drop-hint {
1266
+ font-size: 11.5px;
1267
+ color: var(--text-muted);
1268
+ margin-top: 4px;
1269
+ }
1270
+
1271
+ .upload-queue {
1272
+ max-height: 200px;
1273
+ overflow-y: auto;
1274
+ display: flex;
1275
+ flex-direction: column;
1276
+ gap: 6px;
1277
+ margin-top: 12px;
1278
+ }
1279
+
1280
+ .upload-queue-item {
1281
+ display: flex;
1282
+ align-items: center;
1283
+ justify-content: space-between;
1284
+ padding: 8px 12px;
1285
+ background: #f8fafc;
1286
+ border: 1px solid var(--border-color);
1287
+ border-radius: var(--radius-sm);
1288
+ font-size: 12.5px;
1289
+ }
1290
+
1291
+ .upload-queue-meta {
1292
+ color: var(--text-muted);
1293
+ font-size: 11.5px;
1294
+ }
1295
+
1296
+ .progress-bar-wrap {
1297
+ height: 4px;
1298
+ background: #e2e8f0;
1299
+ border-radius: 2px;
1300
+ overflow: hidden;
1301
+ }
1302
+
1303
+ .progress-bar-inner {
1304
+ height: 100%;
1305
+ background: var(--primary);
1306
+ transition: width 0.18s ease;
1307
+ }
1308
+
1309
+ .upload-percent {
1310
+ font-size: 12px;
1311
+ font-weight: 700;
1312
+ color: var(--primary);
1313
+ }
1314
+
1315
+ /* Form Controls in Modals */
1316
+ .form-label {
1317
+ font-size: 12.5px;
1318
+ font-weight: 600;
1319
+ color: var(--text);
1320
+ margin-bottom: 5px;
1321
+ display: block;
1322
+ }
1323
+
1324
+ .form-control {
1325
+ width: 100%;
1326
+ padding: 7px 11px;
1327
+ font-family: var(--font);
1328
+ font-size: 13px;
1329
+ color: var(--text);
1330
+ background: #ffffff;
1331
+ border: 1px solid var(--border-color);
1332
+ border-radius: var(--radius-sm);
1333
+ outline: none;
1334
+ transition: border-color 0.12s ease, box-shadow 0.12s ease;
1335
+ }
1336
+
1337
+ .form-control:focus {
1338
+ border-color: var(--primary);
1339
+ box-shadow: 0 0 0 2px rgba(15, 118, 110, 0.15);
1340
+ }
1341
+
1342
+ .form-text {
1343
+ font-size: 11.5px;
1344
+ color: var(--text-muted);
1345
+ margin-top: 4px;
1346
+ }
1347
+
1348
+ /* ==========================================================================
1349
+ Preview Modal Content
1350
+ ========================================================================== */
1351
+ .preview-modal-header {
1352
+ display: flex;
1353
+ align-items: center;
1354
+ justify-content: space-between;
1355
+ padding: 10px 16px;
1356
+ background: #ffffff;
1357
+ color: var(--text);
1358
+ border-bottom: 1px solid var(--border-color);
1359
+ }
1360
+
1361
+ .preview-header-left {
1362
+ display: flex;
1363
+ align-items: center;
1364
+ gap: 12px;
1365
+ }
1366
+
1367
+ .preview-tabs {
1368
+ display: inline-flex;
1369
+ background: #f1f5f9;
1370
+ padding: 2px;
1371
+ border-radius: var(--radius-sm);
1372
+ gap: 2px;
1373
+ }
1374
+
1375
+ .preview-tab {
1376
+ background: transparent;
1377
+ border: none;
1378
+ color: var(--text-secondary);
1379
+ font-size: 12px;
1380
+ font-weight: 500;
1381
+ padding: 3px 9px;
1382
+ border-radius: 4px;
1383
+ cursor: pointer;
1384
+ transition: background-color 0.12s ease, color 0.12s ease;
1385
+ font-family: var(--font);
1386
+ }
1387
+
1388
+ .preview-tab.active {
1389
+ background: #ffffff;
1390
+ color: var(--primary-dark-color-ml);
1391
+ font-weight: 600;
1392
+ box-shadow: var(--shadow-xs);
1393
+ }
1394
+
1395
+ .preview-content {
1396
+ max-height: 70vh;
1397
+ overflow: auto;
1398
+ display: flex;
1399
+ align-items: center;
1400
+ justify-content: center;
1401
+ background: #09090b;
1402
+ min-height: 280px;
1403
+ }
1404
+
1405
+ .preview-content img {
1406
+ max-width: 100%;
1407
+ max-height: 70vh;
1408
+ object-fit: contain;
1409
+ }
1410
+
1411
+ .preview-content video,
1412
+ .preview-content audio {
1413
+ max-width: 100%;
1414
+ max-height: 70vh;
1415
+ }
1416
+
1417
+ .preview-code-block {
1418
+ width: 100%;
1419
+ height: 100%;
1420
+ max-height: 70vh;
1421
+ margin: 0;
1422
+ padding: 16px;
1423
+ background: #18181b;
1424
+ color: #f4f4f5;
1425
+ font-family: var(--font-mono);
1426
+ font-size: 12.5px;
1427
+ overflow: auto;
1428
+ line-height: 1.55;
1429
+ tab-size: 2;
1430
+ }
1431
+
1432
+ .preview-code-block code {
1433
+ color: inherit;
1434
+ background: transparent;
1435
+ font-family: inherit;
1436
+ font-size: inherit;
1437
+ }
1438
+
1439
+ .preview-iframe {
1440
+ width: 100%;
1441
+ height: 70vh;
1442
+ border: none;
1443
+ }
1444
+
1445
+ .rendered-markdown {
1446
+ padding: 1.5rem;
1447
+ color: var(--text);
1448
+ background: #ffffff;
1449
+ line-height: 1.65;
1450
+ max-height: 70vh;
1451
+ overflow-y: auto;
1452
+ font-family: var(--font);
1453
+ }
1454
+
1455
+ .rendered-markdown h1,
1456
+ .rendered-markdown h2,
1457
+ .rendered-markdown h3 {
1458
+ color: var(--text);
1459
+ font-family: var(--font-headings);
1460
+ font-weight: 700;
1461
+ margin-top: 1.25rem;
1462
+ margin-bottom: 0.5rem;
1463
+ }
1464
+
1465
+ .rendered-markdown code {
1466
+ background: #f1f5f9;
1467
+ color: var(--primary-dark-color-ml);
1468
+ padding: 2px 5px;
1469
+ border-radius: 4px;
1470
+ font-family: var(--font-mono);
1471
+ font-size: 12px;
1472
+ }
1473
+
1474
+ .rendered-markdown pre {
1475
+ background: #18181b;
1476
+ color: #f4f4f5;
1477
+ padding: 1rem;
1478
+ border-radius: var(--radius);
1479
+ overflow-x: auto;
1480
+ }
1481
+
1482
+ .rendered-markdown table {
1483
+ width: 100%;
1484
+ border-collapse: collapse;
1485
+ margin: 1rem 0;
1486
+ }
1487
+
1488
+ .rendered-markdown th,
1489
+ .rendered-markdown td {
1490
+ border: 1px solid var(--border-color);
1491
+ padding: 8px 12px;
1492
+ text-align: left;
1493
+ }
1494
+
1495
+ .rendered-markdown th {
1496
+ background: #f8fafc;
1497
+ font-weight: 600;
1498
+ color: var(--text);
1499
+ }
1500
+
1501
+ /* Metadata Info Cards */
1502
+ .file-info-pane {
1503
+ background: #f8fafc;
1504
+ padding: 1.25rem;
1505
+ }
1506
+
1507
+ .info-card {
1508
+ background: #ffffff;
1509
+ border: 1px solid var(--border-color);
1510
+ border-radius: var(--radius-sm);
1511
+ padding: 10px 12px;
1512
+ font-family: var(--font);
1513
+ }
1514
+
1515
+ .info-label {
1516
+ font-size: 11px;
1517
+ font-weight: 700;
1518
+ text-transform: uppercase;
1519
+ letter-spacing: 0.04em;
1520
+ color: var(--text-muted);
1521
+ margin-bottom: 3px;
1522
+ font-family: var(--font-headings);
1523
+ }
1524
+
1525
+ .info-value {
1526
+ font-size: 13px;
1527
+ color: var(--text);
1528
+ word-break: break-all;
1529
+ font-family: var(--font);
1530
+ line-height: 1.45;
1531
+ }
1532
+
1533
+ .info-value.font-mono,
1534
+ .font-mono {
1535
+ font-family: var(--font-mono) !important;
1536
+ font-size: 12px;
1537
+ }
1538
+
1539
+ .font-semibold {
1540
+ font-weight: 600 !important;
1541
+ }
1542
+
1543
+ .text-break {
1544
+ word-break: break-all !important;
1545
+ overflow-wrap: break-word !important;
1546
+ }
1547
+
1548
+ .text-truncate {
1549
+ overflow: hidden !important;
1550
+ text-overflow: ellipsis !important;
1551
+ white-space: nowrap !important;
1552
+ }
1553
+
1554
+ .small {
1555
+ font-size: 12px !important;
1556
+ }
1557
+
1558
+ /* ==========================================================================
1559
+ Floating Batch Action Bar
1560
+ ========================================================================== */
1561
+ .batch-action-bar {
1562
+ position: fixed;
1563
+ bottom: 24px;
1564
+ left: 50%;
1565
+ transform: translateX(-50%);
1566
+ z-index: 1000;
1567
+ animation: batch-slide 0.18s cubic-bezier(0.16, 1, 0.3, 1);
1568
+ }
1569
+
1570
+ @keyframes batch-slide {
1571
+ from { opacity: 0; transform: translate(-50%, 12px); }
1572
+ to { opacity: 1; transform: translate(-50%, 0); }
1573
+ }
1574
+
1575
+ .batch-bar-inner {
1576
+ display: flex;
1577
+ align-items: center;
1578
+ gap: 12px;
1579
+ padding: 8px 14px;
1580
+ background: #0f172a;
1581
+ color: #ffffff;
1582
+ border-radius: var(--radius-lg);
1583
+ box-shadow: var(--shadow-lg);
1584
+ border: 1px solid rgba(255, 255, 255, 0.12);
1585
+ }
1586
+
1587
+ .batch-selection-info {
1588
+ display: flex;
1589
+ align-items: center;
1590
+ gap: 8px;
1591
+ font-size: 12.5px;
1592
+ font-weight: 500;
1593
+ }
1594
+
1595
+ .batch-count-badge {
1596
+ background: var(--primary);
1597
+ color: #ffffff;
1598
+ font-weight: 700;
1599
+ font-size: 11px;
1600
+ padding: 1px 7px;
1601
+ border-radius: 999px;
1602
+ }
1603
+
1604
+ .batch-actions {
1605
+ display: flex;
1606
+ align-items: center;
1607
+ gap: 6px;
1608
+ }
1609
+
1610
+ .batch-actions .btn-outline-light {
1611
+ background: rgba(255, 255, 255, 0.1);
1612
+ color: #ffffff;
1613
+ border: 1px solid rgba(255, 255, 255, 0.2);
1614
+ }
1615
+
1616
+ .batch-actions .btn-outline-light:hover {
1617
+ background: rgba(255, 255, 255, 0.2);
1618
+ }
1619
+
1620
+ /* ==========================================================================
1621
+ Toasts & Alerts
1622
+ ========================================================================== */
1623
+ .toast-container {
1624
+ position: fixed;
1625
+ bottom: 20px;
1626
+ right: 20px;
1627
+ z-index: 1100;
1628
+ display: flex;
1629
+ flex-direction: column;
1630
+ gap: 8px;
1631
+ pointer-events: none;
1632
+ }
1633
+
1634
+ .toast-notification {
1635
+ pointer-events: auto;
1636
+ display: flex;
1637
+ align-items: center;
1638
+ gap: 10px;
1639
+ padding: 9px 14px;
1640
+ border-radius: var(--radius-sm);
1641
+ background: #0f172a;
1642
+ color: #ffffff;
1643
+ font-family: var(--font);
1644
+ font-size: 13px;
1645
+ font-weight: 500;
1646
+ box-shadow: var(--shadow-lg);
1647
+ min-width: 260px;
1648
+ max-width: 400px;
1649
+ transition: transform 0.2s ease, opacity 0.2s ease;
1650
+ border: 1px solid rgba(255, 255, 255, 0.1);
1651
+ }
1652
+
1653
+ .toast-notification.success {
1654
+ background: #065f46;
1655
+ border-color: #047857;
1656
+ }
1657
+
1658
+ .toast-notification.error {
1659
+ background: #991b1b;
1660
+ border-color: #b91c1c;
1661
+ }
1662
+
1663
+ .toast-notification.warning {
1664
+ background: #92400e;
1665
+ border-color: #b45309;
1666
+ }
1667
+
1668
+ .toast-close-btn {
1669
+ margin-left: auto;
1670
+ background: transparent;
1671
+ border: none;
1672
+ color: rgba(255, 255, 255, 0.8);
1673
+ cursor: pointer;
1674
+ font-size: 16px;
1675
+ line-height: 1;
1676
+ }
1677
+
1678
+ .toast-close-btn:hover {
1679
+ color: #ffffff;
1680
+ }
1681
+
1682
+ /* Flash alerts */
1683
+ .alert {
1684
+ padding: 10px 14px;
1685
+ border-radius: var(--radius-sm);
1686
+ margin-bottom: 1rem;
1687
+ display: flex;
1688
+ align-items: center;
1689
+ gap: 8px;
1690
+ font-size: 13px;
1691
+ border: 1px solid transparent;
1692
+ }
1693
+
1694
+ .alert-success {
1695
+ background: #ecfdf5;
1696
+ color: #065f46;
1697
+ border-color: #a7f3d0;
1698
+ }
1699
+
1700
+ .alert-danger {
1701
+ background: #fef2f2;
1702
+ color: #991b1b;
1703
+ border-color: #fecaca;
1704
+ }
1705
+
1706
+ /* ==========================================================================
1707
+ Pagination
1708
+ ========================================================================== */
1709
+ .pagination-container {
1710
+ padding: 10px 16px;
1711
+ border-top: 1px solid var(--border-color);
1712
+ display: flex;
1713
+ align-items: center;
1714
+ justify-content: flex-end;
1715
+ background: #ffffff;
1716
+ }
1717
+
1718
+ .pagination {
1719
+ display: flex;
1720
+ align-items: center;
1721
+ gap: 4px;
1722
+ list-style: none;
1723
+ margin: 0;
1724
+ padding: 0;
1725
+ }
1726
+
1727
+ .page-item .page-link {
1728
+ display: flex;
1729
+ align-items: center;
1730
+ justify-content: center;
1731
+ min-width: 28px;
1732
+ height: 28px;
1733
+ padding: 0 6px;
1734
+ border-radius: var(--radius-sm);
1735
+ border: 1px solid var(--border-color);
1736
+ background: #ffffff;
1737
+ color: var(--text-secondary);
1738
+ font-size: 12px;
1739
+ font-weight: 600;
1740
+ text-decoration: none;
1741
+ cursor: pointer;
1742
+ transition: background-color 0.12s ease, color 0.12s ease, border-color 0.12s ease;
1743
+ }
1744
+
1745
+ .page-item .page-link:hover {
1746
+ background: #f1f5f9;
1747
+ color: var(--text);
1748
+ }
1749
+
1750
+ .page-item.active .page-link {
1751
+ background: var(--primary);
1752
+ border-color: var(--primary);
1753
+ color: #ffffff;
1754
+ }
1755
+
1756
+ .page-item.disabled .page-link {
1757
+ opacity: 0.4;
1758
+ cursor: not-allowed;
1759
+ }
1760
+
1761
+ /* ==========================================================================
1762
+ Provider Badges & Connection Status
1763
+ ========================================================================== */
1764
+ .provider-badge {
1765
+ display: inline-flex;
1766
+ align-items: center;
1767
+ gap: 4px;
1768
+ font-size: 11px;
1769
+ font-weight: 700;
1770
+ text-transform: uppercase;
1771
+ letter-spacing: 0.04em;
1772
+ padding: 2px 7px;
1773
+ border-radius: 4px;
1774
+ background: #f1f5f9;
1775
+ color: var(--text-secondary);
1776
+ border: 1px solid var(--border-color);
1777
+ vertical-align: middle;
1778
+ font-family: var(--font-headings);
1779
+ }
1780
+
1781
+ .provider-badge.provider-gdrive,
1782
+ .provider-badge.provider-googledrive,
1783
+ .provider-badge.provider-google-drive {
1784
+ background: #eff6ff;
1785
+ color: #1d4ed8;
1786
+ border-color: #bfdbfe;
1787
+ }
1788
+
1789
+ .provider-badge.provider-s3 {
1790
+ background: #fff7ed;
1791
+ color: #c2410c;
1792
+ border-color: #fed7aa;
1793
+ }
1794
+
1795
+ .provider-badge.provider-r2 {
1796
+ background: #fff7ed;
1797
+ color: #c2410c;
1798
+ border-color: #fed7aa;
1799
+ }
1800
+
1801
+ .provider-badge.provider-minio {
1802
+ background: #fef2f2;
1803
+ color: #b91c1c;
1804
+ border-color: #fecaca;
1805
+ }
1806
+
1807
+ .health-status-badge {
1808
+ display: inline-flex;
1809
+ align-items: center;
1810
+ gap: 5px;
1811
+ font-size: 11px;
1812
+ font-weight: 600;
1813
+ padding: 2px 7px;
1814
+ border-radius: 4px;
1815
+ background: #ecfdf5;
1816
+ color: #047857;
1817
+ border: 1px solid #a7f3d0;
1818
+ }
1819
+
1820
+ .health-status-badge.unhealthy {
1821
+ background: #fef2f2;
1822
+ color: #b91c1c;
1823
+ border-color: #fecaca;
1824
+ }
1825
+
1826
+ .health-status-badge.checking {
1827
+ background: #fffbeb;
1828
+ color: #b45309;
1829
+ border-color: #fde68a;
1830
+ }
1831
+
1832
+ .health-dot {
1833
+ width: 6px;
1834
+ height: 6px;
1835
+ border-radius: 50%;
1836
+ background: #10b981;
1837
+ }
1838
+
1839
+ .health-status-badge.unhealthy .health-dot {
1840
+ background: #ef4444;
1841
+ }
1842
+
1843
+ .health-status-badge.checking .health-dot {
1844
+ background: #f59e0b;
1845
+ }
1846
+
1847
+ .health-check-btn {
1848
+ background: transparent;
1849
+ border: none;
1850
+ cursor: pointer;
1851
+ color: var(--text-muted);
1852
+ padding: 2px 4px;
1853
+ border-radius: var(--radius-sm);
1854
+ transition: color 0.12s ease, background-color 0.12s ease;
1855
+ }
1856
+
1857
+ .health-check-btn:hover {
1858
+ color: var(--primary);
1859
+ background: var(--primary-light-color-ml);
1860
+ }
1861
+
1862
+ .storage-latency-tag {
1863
+ font-size: 11px;
1864
+ font-family: var(--font-mono);
1865
+ color: var(--text-muted);
1866
+ }
1867
+
1868
+ /* ==========================================================================
1869
+ Mobile & Responsive Adaptations
1870
+ ========================================================================== */
1871
+ @media (max-width: 900px) {
1872
+ .page-wrapper {
1873
+ padding: 0;
1874
+ max-width: 100%;
1875
+ overflow-x: hidden;
1876
+ }
1877
+
1878
+ .card.file-manager {
1879
+ border-radius: var(--radius);
1880
+ width: 100%;
1881
+ }
1882
+
1883
+ .fm-layout {
1884
+ grid-template-columns: 100%;
1885
+ height: auto;
1886
+ min-height: 0;
1887
+ max-height: none;
1888
+ }
1889
+
1890
+ .fm-tree-wrap {
1891
+ border-right: none;
1892
+ border-bottom: 1px solid var(--border-color);
1893
+ padding: 10px 14px;
1894
+ background: #f8fafc;
1895
+ }
1896
+
1897
+ .fm-tree-header,
1898
+ .fm-tree {
1899
+ display: none;
1900
+ }
1901
+
1902
+ .fm-storage {
1903
+ margin-top: 0;
1904
+ padding: 8px 12px;
1905
+ background: #ffffff;
1906
+ border: 1px solid var(--border-color);
1907
+ }
1908
+
1909
+ .fm-main {
1910
+ width: 100%;
1911
+ min-width: 0;
1912
+ }
1913
+
1914
+ .fm-grid-wrap {
1915
+ min-height: 380px;
1916
+ padding: 12px;
1917
+ }
1918
+
1919
+ .fm-grid.view-grid {
1920
+ grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
1921
+ gap: 8px;
1922
+ }
1923
+
1924
+ .fm-item-menu {
1925
+ opacity: 1;
1926
+ }
1927
+
1928
+ .fm-star.on {
1929
+ opacity: 1;
1930
+ }
1931
+ }
1932
+
1933
+ @media (max-width: 640px) {
1934
+ .page-header {
1935
+ padding: 0.75rem 1rem;
1936
+ margin-bottom: 0.75rem;
1937
+ border-radius: var(--radius);
1938
+ }
1939
+
1940
+ .page-header-row {
1941
+ flex-direction: column;
1942
+ align-items: stretch;
1943
+ gap: 10px;
1944
+ }
1945
+
1946
+ .page-actions {
1947
+ width: 100%;
1948
+ display: flex;
1949
+ justify-content: stretch;
1950
+ gap: 6px;
1951
+ }
1952
+
1953
+ .page-actions .btn {
1954
+ flex: 1 1 0;
1955
+ min-width: 0;
1956
+ justify-content: center;
1957
+ padding: 6px 8px;
1958
+ font-size: 12px;
1959
+ }
1960
+
1961
+ .fm-toolbar {
1962
+ flex-direction: column;
1963
+ align-items: stretch;
1964
+ gap: 8px;
1965
+ padding: 8px 10px;
1966
+ }
1967
+
1968
+ .fm-breadcrumb {
1969
+ max-width: 100%;
1970
+ overflow-x: auto;
1971
+ white-space: nowrap;
1972
+ padding-bottom: 2px;
1973
+ scrollbar-width: none;
1974
+ }
1975
+
1976
+ .fm-breadcrumb::-webkit-scrollbar {
1977
+ display: none;
1978
+ }
1979
+
1980
+ .fm-toolbar-actions {
1981
+ width: 100%;
1982
+ display: flex;
1983
+ flex-direction: column;
1984
+ align-items: stretch;
1985
+ gap: 8px;
1986
+ }
1987
+
1988
+ .quick-filter-group {
1989
+ width: 100%;
1990
+ display: flex;
1991
+ }
1992
+
1993
+ .quick-filter-btn {
1994
+ flex: 1 1 0;
1995
+ text-align: center;
1996
+ padding: 4px 6px;
1997
+ font-size: 11.5px;
1998
+ }
1999
+
2000
+ .search-box {
2001
+ width: 100%;
2002
+ }
2003
+
2004
+ .fm-grid.view-grid {
2005
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2006
+ gap: 8px;
2007
+ }
2008
+
2009
+ .fm-grid.view-grid .fm-item {
2010
+ padding: 8px;
2011
+ gap: 6px;
2012
+ }
2013
+
2014
+ .fm-item-name {
2015
+ font-size: 12px;
2016
+ }
2017
+
2018
+ .fm-item-meta {
2019
+ font-size: 10.5px;
2020
+ }
2021
+
2022
+ .fm-grid.view-list {
2023
+ gap: 4px;
2024
+ }
2025
+
2026
+ .fm-grid.view-list .fm-item {
2027
+ display: flex;
2028
+ align-items: center;
2029
+ gap: 8px;
2030
+ padding: 8px 10px;
2031
+ }
2032
+
2033
+ .fm-grid.view-list .fm-item-size,
2034
+ .fm-grid.view-list .fm-item-date,
2035
+ .fm-grid.view-list .fm-star-wrap {
2036
+ display: none;
2037
+ }
2038
+
2039
+ .fm-list-header {
2040
+ display: none;
2041
+ }
2042
+ }