@marlinjai/clearify 1.11.2 → 1.12.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.
@@ -0,0 +1,240 @@
1
+ import React from 'react';
2
+ import { Link, Outlet, useLocation } from 'react-router-dom';
3
+ import { ThemeProvider } from '../ThemeProvider.js';
4
+ import { useTheme } from '../ThemeProvider.js';
5
+
6
+ const navItems = [
7
+ {
8
+ label: 'Projects',
9
+ to: '/admin/projects',
10
+ icon: (
11
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
12
+ <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" />
13
+ <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" />
14
+ </svg>
15
+ ),
16
+ },
17
+ {
18
+ label: 'Sections',
19
+ to: '/admin/sections',
20
+ icon: (
21
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
22
+ <line x1="8" y1="6" x2="21" y2="6" />
23
+ <line x1="8" y1="12" x2="21" y2="12" />
24
+ <line x1="8" y1="18" x2="21" y2="18" />
25
+ <line x1="3" y1="6" x2="3.01" y2="6" />
26
+ <line x1="3" y1="12" x2="3.01" y2="12" />
27
+ <line x1="3" y1="18" x2="3.01" y2="18" />
28
+ </svg>
29
+ ),
30
+ },
31
+ {
32
+ label: 'Settings',
33
+ to: '/admin/settings',
34
+ icon: (
35
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
36
+ <circle cx="12" cy="12" r="3" />
37
+ <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" />
38
+ </svg>
39
+ ),
40
+ },
41
+ ];
42
+
43
+ function AdminLayoutInner() {
44
+ const location = useLocation();
45
+ const { theme, toggleTheme } = useTheme();
46
+
47
+ return (
48
+ <>
49
+ <div className="clearify-bg-mesh" aria-hidden="true" />
50
+ <div style={{ display: 'flex', flexDirection: 'column', minHeight: '100vh' }}>
51
+ {/* Admin Header */}
52
+ <header
53
+ style={{
54
+ height: 'var(--clearify-header-height)',
55
+ borderBottom: '1px solid var(--clearify-border)',
56
+ backgroundColor: 'var(--clearify-surface)',
57
+ display: 'flex',
58
+ alignItems: 'center',
59
+ padding: '0 1.5rem',
60
+ position: 'sticky',
61
+ top: 0,
62
+ zIndex: 50,
63
+ backdropFilter: 'blur(16px) saturate(180%)',
64
+ WebkitBackdropFilter: 'blur(16px) saturate(180%)',
65
+ }}
66
+ >
67
+ <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', marginRight: 'auto' }}>
68
+ <div
69
+ style={{
70
+ width: 28,
71
+ height: 28,
72
+ borderRadius: 'var(--clearify-radius-sm)',
73
+ background: 'var(--clearify-gradient)',
74
+ display: 'flex',
75
+ alignItems: 'center',
76
+ justifyContent: 'center',
77
+ color: '#fff',
78
+ }}
79
+ >
80
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
81
+ <circle cx="12" cy="12" r="3" />
82
+ <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" />
83
+ </svg>
84
+ </div>
85
+ <span style={{ fontWeight: 700, fontSize: '1rem', color: 'var(--clearify-text)', letterSpacing: '-0.02em' }}>
86
+ Clearify Admin
87
+ </span>
88
+ </div>
89
+
90
+ <div style={{ display: 'flex', alignItems: 'center', gap: '0.375rem' }}>
91
+ <Link
92
+ to="/"
93
+ style={{
94
+ display: 'inline-flex',
95
+ alignItems: 'center',
96
+ gap: '0.375rem',
97
+ padding: '0.375rem 0.75rem',
98
+ borderRadius: 'var(--clearify-radius-sm)',
99
+ fontSize: '0.8125rem',
100
+ fontWeight: 500,
101
+ color: 'var(--clearify-text-secondary)',
102
+ textDecoration: 'none',
103
+ transition: 'color 0.15s, background-color 0.15s',
104
+ }}
105
+ onMouseEnter={(e) => {
106
+ e.currentTarget.style.color = 'var(--clearify-text)';
107
+ e.currentTarget.style.backgroundColor = 'var(--clearify-bg-secondary)';
108
+ }}
109
+ onMouseLeave={(e) => {
110
+ e.currentTarget.style.color = 'var(--clearify-text-secondary)';
111
+ e.currentTarget.style.backgroundColor = 'transparent';
112
+ }}
113
+ >
114
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
115
+ <line x1="19" y1="12" x2="5" y2="12" />
116
+ <polyline points="12 19 5 12 12 5" />
117
+ </svg>
118
+ Back to docs
119
+ </Link>
120
+
121
+ <button
122
+ onClick={toggleTheme}
123
+ style={{
124
+ display: 'inline-flex',
125
+ alignItems: 'center',
126
+ justifyContent: 'center',
127
+ width: 36,
128
+ height: 36,
129
+ background: 'none',
130
+ border: 'none',
131
+ cursor: 'pointer',
132
+ borderRadius: 'var(--clearify-radius-sm)',
133
+ color: 'var(--clearify-text-secondary)',
134
+ transition: 'color 0.15s, background-color 0.15s',
135
+ }}
136
+ aria-label={`Switch to ${theme === 'light' ? 'dark' : 'light'} mode`}
137
+ onMouseEnter={(e) => {
138
+ e.currentTarget.style.color = 'var(--clearify-text)';
139
+ e.currentTarget.style.backgroundColor = 'var(--clearify-bg-secondary)';
140
+ }}
141
+ onMouseLeave={(e) => {
142
+ e.currentTarget.style.color = 'var(--clearify-text-secondary)';
143
+ e.currentTarget.style.backgroundColor = 'transparent';
144
+ }}
145
+ >
146
+ {theme === 'light' ? (
147
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
148
+ <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
149
+ </svg>
150
+ ) : (
151
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
152
+ <circle cx="12" cy="12" r="5" />
153
+ <line x1="12" y1="1" x2="12" y2="3" />
154
+ <line x1="12" y1="21" x2="12" y2="23" />
155
+ <line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
156
+ <line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
157
+ <line x1="1" y1="12" x2="3" y2="12" />
158
+ <line x1="21" y1="12" x2="23" y2="12" />
159
+ <line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
160
+ <line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
161
+ </svg>
162
+ )}
163
+ </button>
164
+ </div>
165
+ </header>
166
+
167
+ {/* Body: sidebar + content */}
168
+ <div style={{ display: 'flex', flex: 1 }}>
169
+ {/* Sidebar */}
170
+ <nav
171
+ style={{
172
+ width: 'var(--clearify-sidebar-width)',
173
+ borderRight: '1px solid var(--clearify-border)',
174
+ padding: '1rem 0.75rem',
175
+ flexShrink: 0,
176
+ backgroundColor: 'var(--clearify-bg)',
177
+ }}
178
+ >
179
+ <div style={{ fontSize: '0.6875rem', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.05em', color: 'var(--clearify-text-tertiary)', padding: '0.5rem 0.75rem', marginBottom: '0.25rem' }}>
180
+ Navigation
181
+ </div>
182
+ {navItems.map((item) => {
183
+ const isActive = location.pathname === item.to;
184
+ return (
185
+ <Link
186
+ key={item.to}
187
+ to={item.to}
188
+ style={{
189
+ display: 'flex',
190
+ alignItems: 'center',
191
+ gap: '0.625rem',
192
+ padding: '0.5rem 0.75rem',
193
+ borderRadius: 'var(--clearify-radius-sm)',
194
+ fontSize: '0.875rem',
195
+ fontWeight: isActive ? 600 : 450,
196
+ color: isActive ? 'var(--clearify-primary)' : 'var(--clearify-text-secondary)',
197
+ backgroundColor: isActive ? 'var(--clearify-primary-soft)' : 'transparent',
198
+ textDecoration: 'none',
199
+ transition: 'background-color 0.15s, color 0.15s',
200
+ marginBottom: '2px',
201
+ }}
202
+ onMouseEnter={(e) => {
203
+ if (!isActive) {
204
+ e.currentTarget.style.backgroundColor = 'var(--clearify-bg-secondary)';
205
+ e.currentTarget.style.color = 'var(--clearify-text)';
206
+ }
207
+ }}
208
+ onMouseLeave={(e) => {
209
+ if (!isActive) {
210
+ e.currentTarget.style.backgroundColor = 'transparent';
211
+ e.currentTarget.style.color = 'var(--clearify-text-secondary)';
212
+ }
213
+ }}
214
+ >
215
+ {item.icon}
216
+ {item.label}
217
+ </Link>
218
+ );
219
+ })}
220
+ </nav>
221
+
222
+ {/* Main content */}
223
+ <main style={{ flex: 1, overflow: 'auto' }}>
224
+ <Outlet />
225
+ </main>
226
+ </div>
227
+ </div>
228
+ </>
229
+ );
230
+ }
231
+
232
+ export function AdminLayout() {
233
+ return (
234
+ <ThemeProvider mode="auto">
235
+ <AdminLayoutInner />
236
+ </ThemeProvider>
237
+ );
238
+ }
239
+
240
+ export default AdminLayout;