···
15
15
const [statusFilter, setStatusFilter] = useState('all');
16
16
const [searchQuery, setSearchQuery] = useState('');
17
17
const [completenessFilter, setCompletenessFilter] = useState(0);
18
18
-
const [darkMode, setDarkMode] = useState(false);
19
18
20
19
// Login state
21
20
const [email, setEmail] = useState('');
···
36
35
37
36
// Alert state
38
37
const [alert, setAlert] = useState({ show: false, message: '', type: '' });
39
39
-
40
40
-
// Check for dark mode preference on component mount
41
41
-
useEffect(() => {
42
42
-
// Check if dark mode is stored in localStorage
43
43
-
const storedDarkMode = localStorage.getItem('darkMode');
44
44
-
if (storedDarkMode) {
45
45
-
setDarkMode(storedDarkMode === 'true');
46
46
-
} else {
47
47
-
// Check system preference
48
48
-
const prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
49
49
-
setDarkMode(prefersDarkMode);
50
50
-
}
51
51
-
}, []);
52
52
-
53
53
-
// Apply dark mode class when darkMode state changes
54
54
-
useEffect(() => {
55
55
-
if (darkMode) {
56
56
-
document.body.classList.add('dark-mode');
57
57
-
} else {
58
58
-
document.body.classList.remove('dark-mode');
59
59
-
}
60
60
-
}, [darkMode]);
61
61
-
62
62
-
// Toggle dark mode
63
63
-
const toggleDarkMode = () => {
64
64
-
const newDarkMode = !darkMode;
65
65
-
setDarkMode(newDarkMode);
66
66
-
localStorage.setItem('darkMode', newDarkMode.toString());
67
67
-
};
68
38
69
39
// Fetch all required data from Supabase
70
40
const fetchAllData = useCallback(async () => {
···
554
524
// Render loading spinner
555
525
if (isLoading) {
556
526
return (
557
557
-
<div className={`admin-loading ${darkMode ? 'dark-mode' : ''}`}>
527
527
+
<div className="admin-loading">
558
528
<div className="loading-spinner"></div>
559
529
<p>Loading...</p>
560
530
</div>
···
564
534
// Render login form if not authenticated
565
535
if (!isAuthenticated) {
566
536
return (
567
567
-
<div className={`admin-login-container ${darkMode ? 'dark-mode' : ''}`}>
537
537
+
<div className="admin-login-container">
568
538
<div className="admin-login-card">
569
539
<h2>Admin Login</h2>
570
540
{authError && <div className="auth-error">{authError}</div>}
···
591
561
</div>
592
562
<button type="submit" className="login-button">Login</button>
593
563
</form>
594
594
-
<div style={{ marginTop: '20px', textAlign: 'center' }}>
595
595
-
<button
596
596
-
onClick={toggleDarkMode}
597
597
-
style={{
598
598
-
background: 'none',
599
599
-
border: 'none',
600
600
-
cursor: 'pointer',
601
601
-
fontSize: '1em',
602
602
-
color: 'var(--text)'
603
603
-
}}
604
604
-
>
605
605
-
{darkMode ? '☀️ Light Mode' : '🌙 Dark Mode'}
606
606
-
</button>
607
607
-
</div>
608
564
</div>
609
565
</div>
610
566
);
···
612
568
613
569
// Main admin panel UI
614
570
return (
615
615
-
<div className={`admin-panel ${darkMode ? 'dark-mode' : ''}`}>
571
571
+
<div className="admin-panel">
616
572
{/* Header */}
617
573
<header className="admin-header">
618
574
<h1>Resources Admin Panel</h1>
619
619
-
<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
620
620
-
<button
621
621
-
onClick={toggleDarkMode}
622
622
-
style={{
623
623
-
background: 'none',
624
624
-
border: '1px solid var(--card-border)',
625
625
-
borderRadius: '6px',
626
626
-
padding: '8px 12px',
627
627
-
cursor: 'pointer',
628
628
-
fontSize: '0.9em',
629
629
-
color: 'var(--text)',
630
630
-
display: 'flex',
631
631
-
alignItems: 'center',
632
632
-
gap: '5px'
633
633
-
}}
634
634
-
>
635
635
-
{darkMode ? '☀️ Light' : '🌙 Dark'}
636
636
-
</button>
637
637
-
<button onClick={handleLogout} className="logout-button">Logout</button>
638
638
-
</div>
575
575
+
<button onClick={handleLogout} className="logout-button">Logout</button>
639
576
</header>
640
577
641
578
{/* Alert message */}
···
727
664
</div>
728
665
))
729
666
) : (
730
730
-
<div style={{ padding: '20px', textAlign: 'center', color: 'var(--text)', opacity: 0.7 }}>
731
731
-
No resources match your filters
667
667
+
<div className="no-resources-message">
668
668
+
<p>No resources match your filters.</p>
732
669
</div>
733
670
)}
734
671
</div>
···
785
722
value={formData.name}
786
723
onChange={handleInputChange}
787
724
required
725
725
+
placeholder="Resource name"
788
726
/>
789
727
</div>
790
728
<div className="form-group">
···
795
733
name="domain"
796
734
value={formData.domain}
797
735
onChange={handleInputChange}
736
736
+
placeholder="e.g., design, development, marketing"
798
737
/>
799
738
</div>
800
739
</div>
···
808
747
value={formData.url}
809
748
onChange={handleInputChange}
810
749
required
750
750
+
placeholder="https://example.com"
811
751
/>
812
752
</div>
813
753
···
820
760
onChange={handleInputChange}
821
761
rows="4"
822
762
required
763
763
+
placeholder="Brief description of the resource..."
823
764
></textarea>
824
765
</div>
825
766
···
876
817
</div>
877
818
))
878
819
) : (
879
879
-
<div style={{ padding: '10px', color: 'var(--text)', opacity: 0.7 }}>
880
880
-
No categories available
881
881
-
</div>
820
820
+
<p className="no-items-message">No categories available. Create one!</p>
882
821
)}
883
822
</div>
884
823
</div>
···
911
850
</div>
912
851
))
913
852
) : (
914
914
-
<div style={{ padding: '10px', color: 'var(--text)', opacity: 0.7 }}>
915
915
-
No tags available
916
916
-
</div>
853
853
+
<p className="no-items-message">No tags available. Create one!</p>
917
854
)}
918
855
</div>
919
856
</div>