xegavnj 0.1.8

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,407 @@
1
+ "use client";
2
+ import { useState } from 'react';
3
+ import styled, { css } from "styled-components";
4
+ import { Copy, Check, Code as CodeIcon, Sun, Moon } from "lucide-react";
5
+ import { useTheme } from "./ThemeSwitcher.jsx";
6
+
7
+ // =============================================================================
8
+ // REUSABLE HEADER COMPONENT
9
+ // =============================================================================
10
+
11
+ const HeaderWrapper = styled.header`
12
+ width: 100%;
13
+ transition: all 0.3s ease;
14
+ min-height: 90px; /* Ensure sufficient height */
15
+
16
+ /* Primary Variant */
17
+ ${props => props.$variant === 'primary' && css`
18
+ background-color: #6366f1;
19
+ padding: 1.5rem 3rem;
20
+ display: flex;
21
+ align-items: center;
22
+ justify-content: space-between;
23
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
24
+ `}
25
+
26
+ /* Centered Variant */
27
+ ${props => props.$variant === 'centered' && css`
28
+ background-color: #1f2937;
29
+ padding: 3rem 2rem;
30
+ display: flex;
31
+ flex-direction: column;
32
+ align-items: center;
33
+ gap: 2rem;
34
+ `}
35
+
36
+ /* Split Variant */
37
+ ${props => props.$variant === 'split' && css`
38
+ background: linear-gradient(to right, #8b5cf6, #d946ef);
39
+ padding: 1.5rem 4rem;
40
+ display: flex;
41
+ align-items: center;
42
+ justify-content: space-between;
43
+ `}
44
+ `;
45
+
46
+ const Brand = styled.div`
47
+ font-weight: 800;
48
+
49
+ ${props => props.$variant === 'primary' && css`
50
+ font-size: 1.5rem;
51
+ color: white;
52
+ `}
53
+
54
+ ${props => props.$variant === 'centered' && css`
55
+ font-size: 2rem;
56
+ color: white;
57
+ text-transform: uppercase;
58
+ letter-spacing: 0.05em;
59
+ `}
60
+
61
+ ${props => props.$variant === 'split' && css`
62
+ font-size: 1.4rem;
63
+ color: white;
64
+ `}
65
+ `;
66
+
67
+ const Nav = styled.nav`
68
+ display: flex;
69
+ align-items: center;
70
+
71
+ ${props => props.$variant === 'primary' && css`
72
+ gap: 2rem;
73
+ `}
74
+
75
+ ${props => props.$variant === 'centered' && css`
76
+ gap: 2.5rem;
77
+ `}
78
+
79
+ ${props => props.$variant === 'split' && css`
80
+ gap: 2rem;
81
+ `}
82
+ `;
83
+
84
+ const NavLink = styled.a`
85
+ text-decoration: none;
86
+ transition: all 0.2s;
87
+
88
+ /* Primary Variant Links */
89
+ ${props => props.$variant === 'primary' && css`
90
+ color: white;
91
+ font-weight: 500;
92
+ font-size: 0.95rem;
93
+ opacity: 0.9;
94
+ &:hover { opacity: 1; }
95
+ `}
96
+
97
+ /* Centered Variant Links */
98
+ ${props => props.$variant === 'centered' && css`
99
+ color: white; /* Gray-300 */
100
+ font-size: 0.9rem;
101
+ font-weight: 600;
102
+ text-transform: uppercase;
103
+ letter-spacing: 0.05em;
104
+ position: relative;
105
+ opacity: 0.8;
106
+
107
+ &::after {
108
+ content: '';
109
+ position: absolute;
110
+ width: 0;
111
+ height: 2px;
112
+ background: #fbbf24;
113
+ bottom: -4px;
114
+ left: 0;
115
+ transition: width 0.3s ease;
116
+ }
117
+ &:hover { opacity: 1; }
118
+ &:hover::after { width: 100%; }
119
+ `}
120
+
121
+ /* Split Variant Links */
122
+ ${props => props.$variant === 'split' && css`
123
+ color: white;
124
+ font-weight: 500;
125
+ font-size: 0.9rem;
126
+ &:hover { text-decoration: underline; }
127
+ `}
128
+ `;
129
+
130
+ const CtaButton = styled.button`
131
+ border: none;
132
+ cursor: pointer;
133
+
134
+ ${props => props.$variant === 'split' && css`
135
+ background: white;
136
+ color: #9333ea;
137
+ padding: 0.6rem 1.5rem;
138
+ border-radius: 50px;
139
+ font-weight: 700;
140
+ font-size: 0.9rem;
141
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
142
+ transition: transform 0.2s;
143
+
144
+ &:hover {
145
+ transform: translateY(-2px);
146
+ }
147
+ `}
148
+ `;
149
+
150
+ const ToggleBtn = styled.button`
151
+ background: rgba(255, 255, 255, 0.2);
152
+ border: 1px solid rgba(255, 255, 255, 0.3);
153
+ width: 40px;
154
+ height: 40px;
155
+ border-radius: 50%;
156
+ display: flex;
157
+ align-items: center;
158
+ justify-content: center;
159
+ cursor: pointer;
160
+ color: white;
161
+ transition: all 0.2s;
162
+ margin-left: 1rem;
163
+
164
+ &:hover {
165
+ background: rgba(255, 255, 255, 0.3);
166
+ transform: scale(1.05);
167
+ }
168
+
169
+ svg {
170
+ width: 20px;
171
+ height: 20px;
172
+ }
173
+ `;
174
+
175
+ /**
176
+ * Reusable Header Component
177
+ */
178
+ export function Header({
179
+ variant = 'primary',
180
+ logo = 'DapoerRasa',
181
+ menuItems = [],
182
+ ctaLabel,
183
+ onCtaClick,
184
+ showThemeToggle = true
185
+ }) {
186
+ const { theme, setTheme } = useTheme() || {}; // Handle safe access
187
+
188
+ const toggleTheme = () => {
189
+ if (setTheme) {
190
+ setTheme(theme === 'light' ? 'dark' : 'light');
191
+ } else {
192
+ console.warn("ThemeProvider not found. Theme toggle disabled.");
193
+ }
194
+ };
195
+
196
+ return (
197
+ <HeaderWrapper $variant={variant}>
198
+ <Brand $variant={variant}>{logo}</Brand>
199
+
200
+ <Nav $variant={variant}>
201
+ {menuItems.map((item, index) => (
202
+ <NavLink key={index} href={item.href} $variant={variant}>
203
+ {item.label}
204
+ </NavLink>
205
+ ))}
206
+
207
+ {/* Theme Toggle Switch */}
208
+ {showThemeToggle && (
209
+ <ToggleBtn onClick={toggleTheme} title="Toggle Theme">
210
+ {theme === 'dark' ? <Moon /> : <Sun />}
211
+ </ToggleBtn>
212
+ )}
213
+ </Nav>
214
+
215
+ {variant === 'split' && ctaLabel && (
216
+ <CtaButton $variant={variant} onClick={onCtaClick}>
217
+ {ctaLabel}
218
+ </CtaButton>
219
+ )}
220
+ </HeaderWrapper>
221
+ );
222
+ }
223
+
224
+
225
+ // =============================================================================
226
+ // SHOWCASE & DOCUMENTATION WRAPPER
227
+ // =============================================================================
228
+
229
+ const ShowcaseContainer = styled.div`
230
+ width: 100%;
231
+ padding: 2rem 0;
232
+ display: flex;
233
+ flex-direction: column;
234
+ gap: 4rem;
235
+ background-color: #f8fafc;
236
+ min-height: 100vh;
237
+ `;
238
+
239
+ const Title = styled.h2`
240
+ text-align: center;
241
+ font-size: 2rem;
242
+ color: #1e293b;
243
+ margin-bottom: 1rem;
244
+ font-weight: 800;
245
+ `;
246
+
247
+ const HeaderDisplayWrapper = styled.div`
248
+ width: 100%;
249
+ margin-bottom: 2rem;
250
+ `;
251
+
252
+ const CodeControlBar = styled.div`
253
+ display: flex;
254
+ justify-content: center;
255
+ padding: 0.5rem;
256
+ margin-top: 1rem;
257
+ `;
258
+
259
+ const ActionButton = styled.button`
260
+ display: flex;
261
+ align-items: center;
262
+ gap: 0.5rem;
263
+ padding: 0.5rem 1rem;
264
+ border-radius: 6px;
265
+ border: 1px solid #cbd5e1;
266
+ background: white;
267
+ font-size: 0.85rem;
268
+ color: #475569;
269
+ cursor: pointer;
270
+ font-weight: 500;
271
+ transition: all 0.2s;
272
+ box-shadow: 0 1px 2px rgba(0,0,0,0.05);
273
+
274
+ &:hover {
275
+ background: #f8fafc;
276
+ border-color: #94a3b8;
277
+ }
278
+ `;
279
+
280
+ const CodeBlock = styled.div`
281
+ background: #1e1e1e;
282
+ color: #d4d4d4;
283
+ padding: 1rem;
284
+ overflow-x: auto;
285
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
286
+ font-size: 0.85rem;
287
+ line-height: 1.5;
288
+ border-radius: 8px;
289
+ margin: 1rem auto;
290
+ max-width: 800px;
291
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
292
+ `;
293
+
294
+ function HeaderVariantDisplay({ title, code, children }) {
295
+ const [showCode, setShowCode] = useState(false);
296
+ const [copied, setCopied] = useState(false);
297
+
298
+ const handleCopy = () => {
299
+ navigator.clipboard.writeText(code);
300
+ setCopied(true);
301
+ setTimeout(() => setCopied(false), 2000);
302
+ };
303
+
304
+ return (
305
+ <HeaderDisplayWrapper>
306
+ <h3 style={{ textAlign: 'center', marginBottom: '1.5rem', color: '#64748b', textTransform: 'uppercase', letterSpacing: '0.1em', fontSize: '1rem' }}>{title}</h3>
307
+
308
+ <div style={{ boxShadow: "0 2px 4px rgba(0,0,0,0.05)" }}>
309
+ {children}
310
+ </div>
311
+
312
+ <CodeControlBar>
313
+ <div style={{ display: 'flex', gap: '0.5rem' }}>
314
+ <ActionButton onClick={() => setShowCode(!showCode)}>
315
+ <CodeIcon size={16} />
316
+ {showCode ? "Hide Code" : "View Use Code"}
317
+ </ActionButton>
318
+ {showCode && (
319
+ <ActionButton onClick={handleCopy}>
320
+ {copied ? <Check size={16} /> : <Copy size={16} />}
321
+ {copied ? "Copied!" : "Copy"}
322
+ </ActionButton>
323
+ )}
324
+ </div>
325
+ </CodeControlBar>
326
+
327
+ {showCode && (
328
+ <CodeBlock>
329
+ <pre>{code}</pre>
330
+ </CodeBlock>
331
+ )}
332
+ </HeaderDisplayWrapper>
333
+ );
334
+ }
335
+
336
+ const defaultMenuItems = [
337
+ { label: 'Beranda', href: '#' },
338
+ { label: 'Menu', href: '#' },
339
+ { label: 'Tentang', href: '#' },
340
+ { label: 'Kontak', href: '#' },
341
+ ];
342
+
343
+ export function HeaderShowcase() {
344
+ return (
345
+ <ShowcaseContainer>
346
+ <Title>Reusable Header Component</Title>
347
+ <p style={{ textAlign: 'center', marginBottom: '2rem', opacity: 0.8 }}>
348
+ Komponen header yang fleksibel dengan props dan tema toggle.
349
+ </p>
350
+
351
+ <HeaderVariantDisplay
352
+ title="Primary Variant"
353
+ code={`<Header
354
+ variant="primary"
355
+ logo="DapoerRasa"
356
+ menuItems={[
357
+ { label: 'Beranda', href: '#' },
358
+ { label: 'Menu', href: '#' },
359
+ { label: 'Tentang', href: '#' },
360
+ { label: 'Kontak', href: '#' }
361
+ ]}
362
+ />`}
363
+ >
364
+ <Header variant="primary" logo="DapoerRasa" menuItems={defaultMenuItems} showThemeToggle={false} />
365
+ </HeaderVariantDisplay>
366
+
367
+ <HeaderVariantDisplay
368
+ title="Centered Variant"
369
+ code={`<Header
370
+ variant="centered"
371
+ logo="DapoerRasa"
372
+ menuItems={[
373
+ { label: 'Beranda', href: '#' },
374
+ { label: 'Menu', href: '#' },
375
+ { label: 'Tentang', href: '#' },
376
+ { label: 'Kontak', href: '#' }
377
+ ]}
378
+ />`}
379
+ >
380
+ <Header variant="centered" logo="DapoerRasa" menuItems={defaultMenuItems} showThemeToggle={false} />
381
+ </HeaderVariantDisplay>
382
+
383
+ <HeaderVariantDisplay
384
+ title="Split Variant"
385
+ code={`<Header
386
+ variant="split"
387
+ logo="DapoerRasa"
388
+ ctaLabel="Order Now"
389
+ menuItems={[
390
+ { label: 'Beranda', href: '#' },
391
+ { label: 'Menu', href: '#' },
392
+ { label: 'Tentang', href: '#' },
393
+ { label: 'Kontak', href: '#' }
394
+ ]}
395
+ />`}
396
+ >
397
+ <Header variant="split" logo="DapoerRasa" menuItems={defaultMenuItems} ctaLabel="Order Now" showThemeToggle={false} />
398
+ </HeaderVariantDisplay>
399
+
400
+ </ShowcaseContainer>
401
+ );
402
+ }
403
+
404
+ export default function AppHeader(props) {
405
+ const items = props.menuItems || defaultMenuItems;
406
+ return <Header {...props} menuItems={items} />;
407
+ }