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.
- package/README.md +36 -0
- package/components/AppFooter.jsx +294 -0
- package/components/AppHeader.jsx +407 -0
- package/components/AppSidebar.jsx +405 -0
- package/components/Button.jsx +244 -0
- package/components/Card.jsx +388 -0
- package/components/DemoSidebar.jsx +112 -0
- package/components/ThemeSwitcher.jsx +29 -0
- package/index.js +8 -0
- package/package.json +45 -0
- package/theme/ThemeContext.js +42 -0
- package/theme.js +23 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import styled, { css } from "styled-components";
|
|
3
|
+
import React, { useState } from "react";
|
|
4
|
+
import { Copy, Check, Code as CodeIcon, Clock, ArrowRight, Heart } from "lucide-react";
|
|
5
|
+
|
|
6
|
+
// =============================================================================
|
|
7
|
+
// REUSABLE CARD COMPONENT
|
|
8
|
+
// =============================================================================
|
|
9
|
+
|
|
10
|
+
const CardWrapper = styled.div`
|
|
11
|
+
background: white;
|
|
12
|
+
border-radius: 12px;
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
15
|
+
transition: all 0.3s ease;
|
|
16
|
+
border: 1px solid #e5e7eb;
|
|
17
|
+
|
|
18
|
+
&:hover {
|
|
19
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
|
20
|
+
transform: translateY(-2px);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Basic Variant */
|
|
24
|
+
${props => props.$variant === 'basic' && css`
|
|
25
|
+
width: 300px;
|
|
26
|
+
padding: 1.5rem;
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
gap: 1rem;
|
|
30
|
+
border-top: 4px solid #6366f1;
|
|
31
|
+
`}
|
|
32
|
+
|
|
33
|
+
/* Image Variant */
|
|
34
|
+
${props => props.$variant === 'image' && css`
|
|
35
|
+
width: 320px;
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
`}
|
|
39
|
+
|
|
40
|
+
/* Horizontal Variant */
|
|
41
|
+
${props => props.$variant === 'horizontal' && css`
|
|
42
|
+
width: 100%;
|
|
43
|
+
max-width: 500px;
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: row;
|
|
46
|
+
align-items: center;
|
|
47
|
+
padding: 1rem;
|
|
48
|
+
gap: 1.5rem;
|
|
49
|
+
|
|
50
|
+
@media (max-width: 480px) {
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
}
|
|
53
|
+
`}
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
const CardImage = styled.img`
|
|
57
|
+
object-fit: cover;
|
|
58
|
+
|
|
59
|
+
${props => props.$variant === 'image' && css`
|
|
60
|
+
width: 100%;
|
|
61
|
+
height: 180px;
|
|
62
|
+
`}
|
|
63
|
+
|
|
64
|
+
${props => props.$variant === 'horizontal' && css`
|
|
65
|
+
width: 120px;
|
|
66
|
+
height: 120px;
|
|
67
|
+
border-radius: 8px;
|
|
68
|
+
`}
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
const CardBody = styled.div`
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-direction: column;
|
|
74
|
+
|
|
75
|
+
${props => props.$variant === 'image' && css`
|
|
76
|
+
padding: 1.5rem;
|
|
77
|
+
gap: 0.8rem;
|
|
78
|
+
`}
|
|
79
|
+
|
|
80
|
+
${props => props.$variant === 'horizontal' && css`
|
|
81
|
+
flex: 1;
|
|
82
|
+
gap: 0.5rem;
|
|
83
|
+
`}
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
const CardTitle = styled.h3`
|
|
87
|
+
font-size: 1.2rem;
|
|
88
|
+
font-weight: 700;
|
|
89
|
+
color: #1f2937;
|
|
90
|
+
margin: 0;
|
|
91
|
+
`;
|
|
92
|
+
|
|
93
|
+
const CardText = styled.p`
|
|
94
|
+
font-size: 0.95rem;
|
|
95
|
+
color: #6b7280;
|
|
96
|
+
line-height: 1.5;
|
|
97
|
+
margin: 0;
|
|
98
|
+
`;
|
|
99
|
+
|
|
100
|
+
const CardMeta = styled.div`
|
|
101
|
+
display: flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
gap: 0.5rem;
|
|
104
|
+
font-size: 0.85rem;
|
|
105
|
+
color: #9ca3af;
|
|
106
|
+
margin-top: 0.5rem;
|
|
107
|
+
`;
|
|
108
|
+
|
|
109
|
+
const CardAction = styled.button`
|
|
110
|
+
margin-top: auto;
|
|
111
|
+
padding: 0.6rem 1rem;
|
|
112
|
+
background-color: #4f46e5;
|
|
113
|
+
color: white;
|
|
114
|
+
border: none;
|
|
115
|
+
border-radius: 8px;
|
|
116
|
+
font-weight: 600;
|
|
117
|
+
cursor: pointer;
|
|
118
|
+
width: fit-content;
|
|
119
|
+
align-self: flex-start;
|
|
120
|
+
display: flex;
|
|
121
|
+
align-items: center;
|
|
122
|
+
gap: 0.5rem;
|
|
123
|
+
transition: background-color 0.2s;
|
|
124
|
+
|
|
125
|
+
&:hover {
|
|
126
|
+
background-color: #4338ca;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
${props => props.$outline && css`
|
|
130
|
+
background-color: transparent;
|
|
131
|
+
color: #4f46e5;
|
|
132
|
+
border: 1px solid #4f46e5;
|
|
133
|
+
|
|
134
|
+
&:hover {
|
|
135
|
+
background-color: #eef2ff;
|
|
136
|
+
}
|
|
137
|
+
`}
|
|
138
|
+
`;
|
|
139
|
+
|
|
140
|
+
export function Card({
|
|
141
|
+
variant = 'basic',
|
|
142
|
+
title,
|
|
143
|
+
description,
|
|
144
|
+
image,
|
|
145
|
+
meta,
|
|
146
|
+
buttonLabel,
|
|
147
|
+
onButtonClick,
|
|
148
|
+
outlineButton = false
|
|
149
|
+
}) {
|
|
150
|
+
const isHorizontal = variant === 'horizontal';
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<CardWrapper $variant={variant}>
|
|
154
|
+
{/* For Image/Horizontal variants, render image first if present */}
|
|
155
|
+
{(variant === 'image' || variant === 'horizontal') && image && (
|
|
156
|
+
<CardImage src={image} alt={title} $variant={variant} />
|
|
157
|
+
)}
|
|
158
|
+
|
|
159
|
+
{variant === 'basic' && (
|
|
160
|
+
<>
|
|
161
|
+
<CardTitle>{title}</CardTitle>
|
|
162
|
+
<CardText>{description}</CardText>
|
|
163
|
+
{meta && <CardMeta><Clock size={16} /> {meta}</CardMeta>}
|
|
164
|
+
{buttonLabel && (
|
|
165
|
+
<CardAction onClick={onButtonClick} $outline={outlineButton}>
|
|
166
|
+
{buttonLabel} <ArrowRight size={16} />
|
|
167
|
+
</CardAction>
|
|
168
|
+
)}
|
|
169
|
+
</>
|
|
170
|
+
)}
|
|
171
|
+
|
|
172
|
+
{(variant === 'image' || variant === 'horizontal') && (
|
|
173
|
+
<CardBody $variant={variant}>
|
|
174
|
+
<CardTitle>{title}</CardTitle>
|
|
175
|
+
<CardText>{description}</CardText>
|
|
176
|
+
{meta && <CardMeta><Clock size={16} /> {meta}</CardMeta>}
|
|
177
|
+
|
|
178
|
+
{buttonLabel && (
|
|
179
|
+
<div style={{ marginTop: '0.5rem' }}>
|
|
180
|
+
<CardAction onClick={onButtonClick} $outline={outlineButton}>
|
|
181
|
+
{buttonLabel}
|
|
182
|
+
</CardAction>
|
|
183
|
+
</div>
|
|
184
|
+
)}
|
|
185
|
+
</CardBody>
|
|
186
|
+
)}
|
|
187
|
+
</CardWrapper>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// =============================================================================
|
|
192
|
+
// SHOWCASE & DOCUMENTATION WRAPPER
|
|
193
|
+
// =============================================================================
|
|
194
|
+
|
|
195
|
+
const ShowcaseContainer = styled.div`
|
|
196
|
+
width: 100%;
|
|
197
|
+
padding: 2rem;
|
|
198
|
+
display: flex;
|
|
199
|
+
flex-direction: column;
|
|
200
|
+
gap: 3rem;
|
|
201
|
+
background-color: #f8fafc;
|
|
202
|
+
min-height: 100vh;
|
|
203
|
+
`;
|
|
204
|
+
|
|
205
|
+
const Title = styled.h2`
|
|
206
|
+
text-align: center;
|
|
207
|
+
font-size: 2rem;
|
|
208
|
+
color: #1e293b;
|
|
209
|
+
margin-bottom: 2rem;
|
|
210
|
+
font-weight: 800;
|
|
211
|
+
`;
|
|
212
|
+
|
|
213
|
+
const ShowcaseBlock = styled.div`
|
|
214
|
+
background: white;
|
|
215
|
+
border-radius: 16px;
|
|
216
|
+
overflow: hidden;
|
|
217
|
+
box-shadow: 0 4px 20px rgba(0,0,0,0.05);
|
|
218
|
+
border: 1px solid #e2e8f0;
|
|
219
|
+
`;
|
|
220
|
+
|
|
221
|
+
const PreviewArea = styled.div`
|
|
222
|
+
width: 100%;
|
|
223
|
+
padding: 2rem;
|
|
224
|
+
display: flex;
|
|
225
|
+
justify-content: center;
|
|
226
|
+
align-items: center;
|
|
227
|
+
background-color: #f3f4f6;
|
|
228
|
+
`;
|
|
229
|
+
|
|
230
|
+
const ActionSelect = styled.div`
|
|
231
|
+
display: flex;
|
|
232
|
+
justify-content: flex-end;
|
|
233
|
+
padding: 0.5rem;
|
|
234
|
+
background: #f1f5f9;
|
|
235
|
+
border-top: 1px solid #e2e8f0;
|
|
236
|
+
`;
|
|
237
|
+
|
|
238
|
+
const ActionButton = styled.button`
|
|
239
|
+
display: flex;
|
|
240
|
+
align-items: center;
|
|
241
|
+
gap: 0.5rem;
|
|
242
|
+
padding: 0.5rem 1rem;
|
|
243
|
+
border-radius: 6px;
|
|
244
|
+
border: 1px solid #cbd5e1;
|
|
245
|
+
background: white;
|
|
246
|
+
font-size: 0.85rem;
|
|
247
|
+
color: #475569;
|
|
248
|
+
cursor: pointer;
|
|
249
|
+
font-weight: 500;
|
|
250
|
+
transition: all 0.2s;
|
|
251
|
+
|
|
252
|
+
&:hover {
|
|
253
|
+
background: #f8fafc;
|
|
254
|
+
border-color: #94a3b8;
|
|
255
|
+
}
|
|
256
|
+
`;
|
|
257
|
+
|
|
258
|
+
const CodeBlock = styled.div`
|
|
259
|
+
background: #1e1e1e;
|
|
260
|
+
color: #d4d4d4;
|
|
261
|
+
padding: 1rem;
|
|
262
|
+
overflow-x: auto;
|
|
263
|
+
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
|
264
|
+
font-size: 0.85rem;
|
|
265
|
+
line-height: 1.5;
|
|
266
|
+
border-top: 1px solid #333;
|
|
267
|
+
`;
|
|
268
|
+
|
|
269
|
+
function CardVariantDisplay({ title, code, children }) {
|
|
270
|
+
const [showCode, setShowCode] = useState(false);
|
|
271
|
+
const [copied, setCopied] = useState(false);
|
|
272
|
+
|
|
273
|
+
const handleCopy = () => {
|
|
274
|
+
navigator.clipboard.writeText(code);
|
|
275
|
+
setCopied(true);
|
|
276
|
+
setTimeout(() => setCopied(false), 2000);
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<div>
|
|
281
|
+
<h3 style={{ textAlign: 'center', marginBottom: '1rem', color: '#64748b', textTransform: 'uppercase', letterSpacing: '0.1em', fontSize: '1rem' }}>{title}</h3>
|
|
282
|
+
<ShowcaseBlock>
|
|
283
|
+
<PreviewArea>
|
|
284
|
+
{children}
|
|
285
|
+
</PreviewArea>
|
|
286
|
+
<ActionSelect>
|
|
287
|
+
<div style={{ display: 'flex', gap: '0.5rem' }}>
|
|
288
|
+
<ActionButton onClick={() => setShowCode(!showCode)}>
|
|
289
|
+
<CodeIcon size={16} />
|
|
290
|
+
{showCode ? "Sembunyikan Kode" : "Lihat Kode"}
|
|
291
|
+
</ActionButton>
|
|
292
|
+
{showCode && (
|
|
293
|
+
<ActionButton onClick={handleCopy}>
|
|
294
|
+
{copied ? <Check size={16} /> : <Copy size={16} />}
|
|
295
|
+
{copied ? "Disalin!" : "Salin"}
|
|
296
|
+
</ActionButton>
|
|
297
|
+
)}
|
|
298
|
+
</div>
|
|
299
|
+
</ActionSelect>
|
|
300
|
+
{showCode && (
|
|
301
|
+
<CodeBlock>
|
|
302
|
+
<pre>{code}</pre>
|
|
303
|
+
</CodeBlock>
|
|
304
|
+
)}
|
|
305
|
+
</ShowcaseBlock>
|
|
306
|
+
</div>
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function CardShowcase() {
|
|
311
|
+
return (
|
|
312
|
+
<ShowcaseContainer>
|
|
313
|
+
<Title>Card Variants</Title>
|
|
314
|
+
<p style={{ textAlign: 'center', color: '#666', marginBottom: '2rem' }}>
|
|
315
|
+
Komponen kartu serbaguna untuk berbagai kebutuhan konten.
|
|
316
|
+
</p>
|
|
317
|
+
|
|
318
|
+
<CardVariantDisplay
|
|
319
|
+
title="1. Kartu Dasar (Teks Saja)"
|
|
320
|
+
code={`<Card
|
|
321
|
+
variant="basic"
|
|
322
|
+
title="Promo Mingguan"
|
|
323
|
+
description="Dapatkan diskon 20% untuk semua menu pasta setiap hari Jumat. Jangan lewatkan kesempatan ini!"
|
|
324
|
+
buttonLabel="Lihat Menu"
|
|
325
|
+
meta="Berakhir dalam 2 hari"
|
|
326
|
+
/>`}
|
|
327
|
+
>
|
|
328
|
+
<Card
|
|
329
|
+
variant="basic"
|
|
330
|
+
title="Promo Mingguan"
|
|
331
|
+
description="Dapatkan diskon 20% untuk semua menu pasta setiap hari Jumat. Jangan lewatkan kesempatan ini!"
|
|
332
|
+
buttonLabel="Lihat Menu"
|
|
333
|
+
meta="Berakhir dalam 2 hari"
|
|
334
|
+
/>
|
|
335
|
+
</CardVariantDisplay>
|
|
336
|
+
|
|
337
|
+
<CardVariantDisplay
|
|
338
|
+
title="2. Kartu dengan Gambar"
|
|
339
|
+
code={`<Card
|
|
340
|
+
variant="image"
|
|
341
|
+
image="https://images.unsplash.com/photo-1546069901-ba9599a7e63c"
|
|
342
|
+
title="Nasi Goreng Spesial"
|
|
343
|
+
description="Nasi goreng kampung dengan bumbu rahasia, dilengkapi telur mata sapi dan sate ayam."
|
|
344
|
+
buttonLabel="Pesan Sekarang"
|
|
345
|
+
outlineButton={true}
|
|
346
|
+
/>`}
|
|
347
|
+
>
|
|
348
|
+
<Card
|
|
349
|
+
variant="image"
|
|
350
|
+
image="https://images.unsplash.com/photo-1546069901-ba9599a7e63c?auto=format&fit=crop&w=400&q=80"
|
|
351
|
+
title="Nasi Goreng Spesial"
|
|
352
|
+
description="Nasi goreng kampung dengan bumbu rahasia, dilengkapi telur mata sapi dan sate ayam."
|
|
353
|
+
buttonLabel="Pesan Sekarang"
|
|
354
|
+
outlineButton={true}
|
|
355
|
+
/>
|
|
356
|
+
</CardVariantDisplay>
|
|
357
|
+
|
|
358
|
+
<CardVariantDisplay
|
|
359
|
+
title="3. Kartu Horizontal"
|
|
360
|
+
code={`<Card
|
|
361
|
+
variant="horizontal"
|
|
362
|
+
image="https://images.unsplash.com/photo-1555939594-58d7cb561ad1"
|
|
363
|
+
title="Paket Katering"
|
|
364
|
+
description="Layanan katering untuk acara kantor dan pesta keluarga."
|
|
365
|
+
buttonLabel="Hubungi Kami"
|
|
366
|
+
/>`}
|
|
367
|
+
>
|
|
368
|
+
<Card
|
|
369
|
+
variant="horizontal"
|
|
370
|
+
image="https://images.unsplash.com/photo-1555939594-58d7cb561ad1?auto=format&fit=crop&w=200&q=80"
|
|
371
|
+
title="Paket Katering"
|
|
372
|
+
description="Layanan katering untuk acara kantor dan pesta keluarga."
|
|
373
|
+
buttonLabel="Hubungi Kami"
|
|
374
|
+
/>
|
|
375
|
+
</CardVariantDisplay>
|
|
376
|
+
|
|
377
|
+
</ShowcaseContainer>
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Support legacy imports or default usage
|
|
382
|
+
export default function AppCard(props) {
|
|
383
|
+
if (props.variant) {
|
|
384
|
+
return <Card {...props} />;
|
|
385
|
+
}
|
|
386
|
+
// Backward compatibility wrapper for old props
|
|
387
|
+
return <Card variant="image" {...props} />;
|
|
388
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import styled, { keyframes, css } from "styled-components";
|
|
3
|
+
import { FaHome, FaUser, FaCog, FaPhone } from "react-icons/fa";
|
|
4
|
+
|
|
5
|
+
export const DemoSidebar = ({ variant = "primary" }) => {
|
|
6
|
+
return (
|
|
7
|
+
<SidebarContainer $variant={variant}>
|
|
8
|
+
<h3>
|
|
9
|
+
{variant === "dark"
|
|
10
|
+
? "Menu Navigation"
|
|
11
|
+
: variant === "outline"
|
|
12
|
+
? "Sidebar Menu"
|
|
13
|
+
: variant === "slide"
|
|
14
|
+
? "Animated Sidebar"
|
|
15
|
+
: "Sidebar Menu"}
|
|
16
|
+
</h3>
|
|
17
|
+
|
|
18
|
+
<SidebarList>
|
|
19
|
+
<SidebarItem>{variant !== "primary" && <FaHome />} Home</SidebarItem>
|
|
20
|
+
<SidebarItem>{variant !== "primary" && <FaUser />} About</SidebarItem>
|
|
21
|
+
<SidebarItem>{variant !== "primary" && <FaCog />} Services</SidebarItem>
|
|
22
|
+
<SidebarItem>{variant !== "primary" && <FaPhone />} Contact</SidebarItem>
|
|
23
|
+
</SidebarList>
|
|
24
|
+
|
|
25
|
+
{variant === "outline" && <ActionButton>Get in Touch</ActionButton>}
|
|
26
|
+
</SidebarContainer>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// 🎬 Animations khusus untuk varian SLIDE
|
|
31
|
+
const fadeSlideIn = keyframes`
|
|
32
|
+
0% { transform: translateX(-40px); opacity: 0; }
|
|
33
|
+
100% { transform: translateX(0); opacity: 1; }
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
const shimmer = keyframes`
|
|
37
|
+
0% { background-position: 200% 0; }
|
|
38
|
+
100% { background-position: -200% 0; }
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
const SidebarContainer = styled.aside`
|
|
42
|
+
width: 200px;
|
|
43
|
+
padding: 20px;
|
|
44
|
+
border-radius: 16px;
|
|
45
|
+
color: #fff;
|
|
46
|
+
transition: all 0.4s ease;
|
|
47
|
+
box-shadow: 0 6px 14px rgba(0, 0, 0, 0.2);
|
|
48
|
+
|
|
49
|
+
${({ $variant }) =>
|
|
50
|
+
$variant === "slide"
|
|
51
|
+
? css`
|
|
52
|
+
background: linear-gradient(
|
|
53
|
+
120deg,
|
|
54
|
+
#6548f5 0%,
|
|
55
|
+
#8e6dfc 50%,
|
|
56
|
+
#6548f5 100%
|
|
57
|
+
);
|
|
58
|
+
background-size: 300% 300%;
|
|
59
|
+
animation: ${fadeSlideIn} 0.8s ease forwards,
|
|
60
|
+
${shimmer} 2.8s linear infinite;
|
|
61
|
+
`
|
|
62
|
+
: css`
|
|
63
|
+
background: ${() =>
|
|
64
|
+
$variant === "dark"
|
|
65
|
+
? "linear-gradient(180deg, #1b1a2e, #0e0d17)"
|
|
66
|
+
: $variant === "outline"
|
|
67
|
+
? "linear-gradient(180deg, #2c1e6b, #402c87)"
|
|
68
|
+
: "linear-gradient(180deg, #3d2d7c, #5a3ec5)"};
|
|
69
|
+
`}
|
|
70
|
+
|
|
71
|
+
h3 {
|
|
72
|
+
margin-bottom: 16px;
|
|
73
|
+
font-size: 1.1rem;
|
|
74
|
+
}
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
const SidebarList = styled.ul`
|
|
78
|
+
list-style: none;
|
|
79
|
+
padding: 0;
|
|
80
|
+
margin: 0;
|
|
81
|
+
display: flex;
|
|
82
|
+
flex-direction: column;
|
|
83
|
+
gap: 10px;
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
const SidebarItem = styled.li`
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
gap: 10px;
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
transition: 0.2s ease;
|
|
92
|
+
|
|
93
|
+
&:hover {
|
|
94
|
+
transform: translateX(5px);
|
|
95
|
+
opacity: 0.85;
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
|
|
99
|
+
const ActionButton = styled.button`
|
|
100
|
+
width: 100%;
|
|
101
|
+
margin-top: 18px;
|
|
102
|
+
padding: 8px 14px;
|
|
103
|
+
border-radius: 8px;
|
|
104
|
+
border: none;
|
|
105
|
+
background: #b28aff;
|
|
106
|
+
cursor: pointer;
|
|
107
|
+
transition: 0.3s;
|
|
108
|
+
|
|
109
|
+
&:hover {
|
|
110
|
+
background: #a379ff;
|
|
111
|
+
}
|
|
112
|
+
`;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContext, useContext, useState } from "react";
|
|
3
|
+
|
|
4
|
+
import { themes } from "../theme.js";
|
|
5
|
+
|
|
6
|
+
const ThemeContext = createContext();
|
|
7
|
+
|
|
8
|
+
export function ThemeProvider({ children }) {
|
|
9
|
+
const [theme, setTheme] = useState("light");
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<ThemeContext.Provider value={{ theme, setTheme }}>
|
|
13
|
+
<div
|
|
14
|
+
style={{
|
|
15
|
+
minHeight: "100vh",
|
|
16
|
+
background: themes[theme].background,
|
|
17
|
+
color: themes[theme].text,
|
|
18
|
+
transition: "0.3s",
|
|
19
|
+
}}
|
|
20
|
+
>
|
|
21
|
+
{children}
|
|
22
|
+
</div>
|
|
23
|
+
</ThemeContext.Provider>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function useTheme() {
|
|
28
|
+
return useContext(ThemeContext);
|
|
29
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import Button, { ButtonShowcase } from "./components/Button";
|
|
2
|
+
import Card, { CardShowcase } from "./components/Card";
|
|
3
|
+
import AppHeader, { HeaderShowcase } from "./components/AppHeader";
|
|
4
|
+
import AppSidebar, { SidebarShowcase } from "./components/AppSidebar";
|
|
5
|
+
import AppFooter, { FooterShowcase } from "./components/AppFooter";
|
|
6
|
+
import { ThemeProvider, useTheme } from "./components/ThemeSwitcher";
|
|
7
|
+
|
|
8
|
+
export { Button, ButtonShowcase, Card, CardShowcase, AppHeader, HeaderShowcase, AppSidebar, SidebarShowcase, AppFooter, FooterShowcase, ThemeProvider, useTheme };
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "xegavnj",
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./index.js"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"components",
|
|
13
|
+
"index.js",
|
|
14
|
+
"theme.js",
|
|
15
|
+
"theme"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"dev": "next dev --webpack",
|
|
19
|
+
"build": "next build --webpack",
|
|
20
|
+
"start": "next start",
|
|
21
|
+
"lint": "eslint"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"next": ">=15.0.0",
|
|
25
|
+
"react": ">=19.1.0",
|
|
26
|
+
"react-dom": ">=19.1.0",
|
|
27
|
+
"styled-components": "^6.1.19"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"lucide-react": "^0.553.0",
|
|
31
|
+
"next": " 16.0.1",
|
|
32
|
+
"react": "19.2.0",
|
|
33
|
+
"react-dom": "19.2.0",
|
|
34
|
+
"react-icons": "^5.5.0",
|
|
35
|
+
"styled-components": "^6.1.19"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"autoprefixer": "^10.4.21",
|
|
39
|
+
"babel-plugin-styled-components": "^2.1.4",
|
|
40
|
+
"eslint": "^9",
|
|
41
|
+
"eslint-config-next": "16.0.1",
|
|
42
|
+
"postcss": "^8.5.6",
|
|
43
|
+
"tailwindcss": "^4.1.17"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContext, useContext, useState } from "react";
|
|
3
|
+
|
|
4
|
+
const themes = {
|
|
5
|
+
light: {
|
|
6
|
+
background: "#ffffff",
|
|
7
|
+
text: "#111827",
|
|
8
|
+
},
|
|
9
|
+
dark: {
|
|
10
|
+
background: "#111827",
|
|
11
|
+
text: "#f9fafb",
|
|
12
|
+
},
|
|
13
|
+
colorful: {
|
|
14
|
+
background: "#fdf2f8",
|
|
15
|
+
text: "#831843",
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const ThemeContext = createContext();
|
|
20
|
+
|
|
21
|
+
export function ThemeProvider({ children }) {
|
|
22
|
+
const [themeName, setThemeName] = useState("light");
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<ThemeContext.Provider value={{ themeName, setThemeName }}>
|
|
26
|
+
<div
|
|
27
|
+
style={{
|
|
28
|
+
minHeight: "100vh",
|
|
29
|
+
backgroundColor: themes[themeName].background,
|
|
30
|
+
color: themes[themeName].text,
|
|
31
|
+
transition: "0.3s ease",
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
{children}
|
|
35
|
+
</div>
|
|
36
|
+
</ThemeContext.Provider>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function useTheme() {
|
|
41
|
+
return useContext(ThemeContext);
|
|
42
|
+
}
|
package/theme.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const themes = {
|
|
2
|
+
light: {
|
|
3
|
+
background: "#ffffff",
|
|
4
|
+
text: "#111827",
|
|
5
|
+
primary: "#2563eb",
|
|
6
|
+
secondary: "#4b5563",
|
|
7
|
+
border: "#e5e7eb",
|
|
8
|
+
},
|
|
9
|
+
dark: {
|
|
10
|
+
background: "#0f172a",
|
|
11
|
+
text: "#f8fafc",
|
|
12
|
+
primary: "#3b82f6",
|
|
13
|
+
secondary: "#94a3b8",
|
|
14
|
+
border: "#1e293b",
|
|
15
|
+
},
|
|
16
|
+
colorful: {
|
|
17
|
+
background: "#fff7ed",
|
|
18
|
+
text: "#7c2d12",
|
|
19
|
+
primary: "#ea580c",
|
|
20
|
+
secondary: "#fdba74",
|
|
21
|
+
border: "#fed7aa",
|
|
22
|
+
},
|
|
23
|
+
};
|