styled-hairomin 0.2.2 → 0.2.4
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 +5 -1
- package/components/SidebarVariant.jsx +275 -44
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import styled from "styled-components";
|
|
4
|
+
import Link from "next/link";
|
|
4
5
|
import {
|
|
5
6
|
FaHome,
|
|
6
7
|
FaBed,
|
|
@@ -31,6 +32,24 @@ const variantStyles = {
|
|
|
31
32
|
},
|
|
32
33
|
};
|
|
33
34
|
|
|
35
|
+
// Default icons mapping
|
|
36
|
+
const defaultIcons = {
|
|
37
|
+
header: <FaHome />,
|
|
38
|
+
card: <FaBed />,
|
|
39
|
+
button: <FaConciergeBell />,
|
|
40
|
+
footer: <FaInfoCircle />,
|
|
41
|
+
sidebar: <FaUser />,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Default items fallback
|
|
45
|
+
const defaultItems = [
|
|
46
|
+
{ name: "Header", href: "#", icon: <FaHome /> },
|
|
47
|
+
{ name: "Card", href: "#", icon: <FaBed /> },
|
|
48
|
+
{ name: "Button", href: "#", icon: <FaConciergeBell /> },
|
|
49
|
+
{ name: "Footer", href: "#", icon: <FaInfoCircle /> },
|
|
50
|
+
{ name: "Sidebar", href: "#", icon: <FaUser /> },
|
|
51
|
+
];
|
|
52
|
+
|
|
34
53
|
const CompactSidebar = styled.aside`
|
|
35
54
|
font-family: "Inter", sans-serif;
|
|
36
55
|
background: ${variantStyles.compact.background};
|
|
@@ -68,7 +87,65 @@ const CompactTitle = styled.div`
|
|
|
68
87
|
}
|
|
69
88
|
`;
|
|
70
89
|
|
|
71
|
-
const
|
|
90
|
+
const CompactItemLink = styled(Link)`
|
|
91
|
+
width: 50px;
|
|
92
|
+
height: 50px;
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
justify-content: center;
|
|
96
|
+
background: none;
|
|
97
|
+
border: none;
|
|
98
|
+
color: inherit;
|
|
99
|
+
border-radius: 12px;
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
transition: all 0.3s ease;
|
|
102
|
+
position: relative;
|
|
103
|
+
text-decoration: none;
|
|
104
|
+
|
|
105
|
+
svg {
|
|
106
|
+
font-size: 22px;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
&:hover {
|
|
110
|
+
background: ${variantStyles.compact.hover};
|
|
111
|
+
transform: scale(1.1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
&::after {
|
|
115
|
+
content: attr(data-label);
|
|
116
|
+
position: absolute;
|
|
117
|
+
left: 70px;
|
|
118
|
+
background: #2c3e50;
|
|
119
|
+
color: white;
|
|
120
|
+
padding: 0.5rem 1rem;
|
|
121
|
+
border-radius: 6px;
|
|
122
|
+
font-size: 14px;
|
|
123
|
+
white-space: nowrap;
|
|
124
|
+
opacity: 0;
|
|
125
|
+
pointer-events: none;
|
|
126
|
+
transition: opacity 0.3s;
|
|
127
|
+
z-index: 1000;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&:hover::after {
|
|
131
|
+
opacity: 1;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@media (max-width: 768px) {
|
|
135
|
+
width: 40px;
|
|
136
|
+
height: 40px;
|
|
137
|
+
|
|
138
|
+
svg {
|
|
139
|
+
font-size: 18px;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
&::after {
|
|
143
|
+
display: none;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
`;
|
|
147
|
+
|
|
148
|
+
const CompactItemButton = styled.button`
|
|
72
149
|
width: 50px;
|
|
73
150
|
height: 50px;
|
|
74
151
|
display: flex;
|
|
@@ -169,7 +246,47 @@ const SectionLabel = styled.div`
|
|
|
169
246
|
font-weight: 700;
|
|
170
247
|
`;
|
|
171
248
|
|
|
172
|
-
const
|
|
249
|
+
const ExpandedItemLink = styled(Link)`
|
|
250
|
+
width: 100%;
|
|
251
|
+
display: flex;
|
|
252
|
+
align-items: center;
|
|
253
|
+
justify-content: space-between;
|
|
254
|
+
padding: 0.9rem 1.2rem;
|
|
255
|
+
background: none;
|
|
256
|
+
border: none;
|
|
257
|
+
color: inherit;
|
|
258
|
+
border-radius: 12px;
|
|
259
|
+
cursor: pointer;
|
|
260
|
+
transition: all 0.3s ease;
|
|
261
|
+
font-size: 15px;
|
|
262
|
+
font-weight: 500;
|
|
263
|
+
position: relative;
|
|
264
|
+
overflow: hidden;
|
|
265
|
+
text-decoration: none;
|
|
266
|
+
|
|
267
|
+
&::before {
|
|
268
|
+
content: "";
|
|
269
|
+
position: absolute;
|
|
270
|
+
left: 0;
|
|
271
|
+
top: 0;
|
|
272
|
+
height: 100%;
|
|
273
|
+
width: 4px;
|
|
274
|
+
background: linear-gradient(135deg, #667eea, #764ba2);
|
|
275
|
+
opacity: 0;
|
|
276
|
+
transition: opacity 0.3s;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
&:hover::before {
|
|
280
|
+
opacity: 1;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
&:hover {
|
|
284
|
+
background: ${variantStyles.expanded.hover};
|
|
285
|
+
transform: translateX(5px);
|
|
286
|
+
}
|
|
287
|
+
`;
|
|
288
|
+
|
|
289
|
+
const ExpandedItemButton = styled.button`
|
|
173
290
|
width: 100%;
|
|
174
291
|
display: flex;
|
|
175
292
|
align-items: center;
|
|
@@ -248,7 +365,45 @@ const FloatingTitle = styled.h3`
|
|
|
248
365
|
color: #2c3e50;
|
|
249
366
|
`;
|
|
250
367
|
|
|
251
|
-
const
|
|
368
|
+
const FloatingItemLink = styled(Link)`
|
|
369
|
+
width: 100%;
|
|
370
|
+
display: flex;
|
|
371
|
+
align-items: center;
|
|
372
|
+
gap: 1rem;
|
|
373
|
+
padding: 1rem 1.2rem;
|
|
374
|
+
background: none;
|
|
375
|
+
border: none;
|
|
376
|
+
color: inherit;
|
|
377
|
+
border-radius: 14px;
|
|
378
|
+
cursor: pointer;
|
|
379
|
+
transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
|
380
|
+
font-size: 15px;
|
|
381
|
+
font-weight: 600;
|
|
382
|
+
text-decoration: none;
|
|
383
|
+
|
|
384
|
+
svg {
|
|
385
|
+
font-size: 20px;
|
|
386
|
+
padding: 8px;
|
|
387
|
+
background: linear-gradient(135deg, #667eea20, #764ba220);
|
|
388
|
+
border-radius: 10px;
|
|
389
|
+
color: #667eea;
|
|
390
|
+
transition: all 0.3s;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
&:hover {
|
|
394
|
+
background: ${variantStyles.floating.hover};
|
|
395
|
+
transform: scale(1.05);
|
|
396
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
&:hover svg {
|
|
400
|
+
background: linear-gradient(135deg, #667eea, #764ba2);
|
|
401
|
+
color: white;
|
|
402
|
+
transform: rotate(10deg);
|
|
403
|
+
}
|
|
404
|
+
`;
|
|
405
|
+
|
|
406
|
+
const FloatingItemButton = styled.button`
|
|
252
407
|
width: 100%;
|
|
253
408
|
display: flex;
|
|
254
409
|
align-items: center;
|
|
@@ -285,50 +440,134 @@ const FloatingItem = styled.button`
|
|
|
285
440
|
}
|
|
286
441
|
`;
|
|
287
442
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
443
|
+
// Helper function to get icon for an item
|
|
444
|
+
const getItemIcon = (item) => {
|
|
445
|
+
if (item.icon) return item.icon;
|
|
446
|
+
const name = (item.name || item.label || "").toLowerCase();
|
|
447
|
+
return defaultIcons[name] || <FaHome />;
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
// Helper function to get item display name
|
|
451
|
+
const getItemName = (item) => {
|
|
452
|
+
return item.name || item.label || "Menu";
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
export default function SidebarVariant({ variant = "compact", items, onSelect, title }) {
|
|
456
|
+
// Use provided items or fallback to defaults
|
|
457
|
+
const menuItems = items && items.length > 0 ? items : defaultItems;
|
|
458
|
+
|
|
459
|
+
// Get title based on variant or use custom title
|
|
460
|
+
const sidebarTitle = title || variantStyles[variant]?.title || "Menu";
|
|
461
|
+
|
|
462
|
+
const renderCompactItem = (item, index) => {
|
|
463
|
+
const icon = getItemIcon(item);
|
|
464
|
+
const name = getItemName(item);
|
|
465
|
+
const hasHref = item.href && item.href !== "";
|
|
466
|
+
|
|
467
|
+
if (hasHref) {
|
|
468
|
+
return (
|
|
469
|
+
<CompactItemLink
|
|
470
|
+
key={item.name || item.label || index}
|
|
471
|
+
href={item.href}
|
|
472
|
+
data-label={name}
|
|
473
|
+
onClick={() => onSelect?.(name.toLowerCase())}
|
|
474
|
+
>
|
|
475
|
+
{icon}
|
|
476
|
+
</CompactItemLink>
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return (
|
|
481
|
+
<CompactItemButton
|
|
482
|
+
key={item.name || item.label || index}
|
|
483
|
+
data-label={name}
|
|
484
|
+
onClick={() => onSelect?.(name.toLowerCase())}
|
|
485
|
+
>
|
|
486
|
+
{icon}
|
|
487
|
+
</CompactItemButton>
|
|
488
|
+
);
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
const renderExpandedItem = (item, index) => {
|
|
492
|
+
const icon = getItemIcon(item);
|
|
493
|
+
const name = getItemName(item);
|
|
494
|
+
const hasHref = item.href && item.href !== "";
|
|
495
|
+
|
|
496
|
+
if (hasHref) {
|
|
497
|
+
return (
|
|
498
|
+
<ExpandedItemLink
|
|
499
|
+
key={item.name || item.label || index}
|
|
500
|
+
href={item.href}
|
|
501
|
+
onClick={() => onSelect?.(name.toLowerCase())}
|
|
502
|
+
>
|
|
503
|
+
<ItemLeft>
|
|
504
|
+
{icon}
|
|
505
|
+
<span>{name}</span>
|
|
506
|
+
</ItemLeft>
|
|
507
|
+
<FaChevronRight size={14} style={{ opacity: 0.5 }} />
|
|
508
|
+
</ExpandedItemLink>
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return (
|
|
513
|
+
<ExpandedItemButton
|
|
514
|
+
key={item.name || item.label || index}
|
|
515
|
+
onClick={() => onSelect?.(name.toLowerCase())}
|
|
516
|
+
>
|
|
517
|
+
<ItemLeft>
|
|
518
|
+
{icon}
|
|
519
|
+
<span>{name}</span>
|
|
520
|
+
</ItemLeft>
|
|
521
|
+
<FaChevronRight size={14} style={{ opacity: 0.5 }} />
|
|
522
|
+
</ExpandedItemButton>
|
|
523
|
+
);
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
const renderFloatingItem = (item, index) => {
|
|
527
|
+
const icon = getItemIcon(item);
|
|
528
|
+
const name = getItemName(item);
|
|
529
|
+
const hasHref = item.href && item.href !== "";
|
|
530
|
+
|
|
531
|
+
if (hasHref) {
|
|
532
|
+
return (
|
|
533
|
+
<FloatingItemLink
|
|
534
|
+
key={item.name || item.label || index}
|
|
535
|
+
href={item.href}
|
|
536
|
+
onClick={() => onSelect?.(name.toLowerCase())}
|
|
537
|
+
>
|
|
538
|
+
{icon}
|
|
539
|
+
<span>{name}</span>
|
|
540
|
+
</FloatingItemLink>
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
return (
|
|
545
|
+
<FloatingItemButton
|
|
546
|
+
key={item.name || item.label || index}
|
|
547
|
+
onClick={() => onSelect?.(name.toLowerCase())}
|
|
548
|
+
>
|
|
549
|
+
{icon}
|
|
550
|
+
<span>{name}</span>
|
|
551
|
+
</FloatingItemButton>
|
|
552
|
+
);
|
|
553
|
+
};
|
|
296
554
|
|
|
297
555
|
switch (variant) {
|
|
298
556
|
case "compact":
|
|
299
557
|
return (
|
|
300
558
|
<CompactSidebar>
|
|
301
|
-
<CompactTitle>{
|
|
302
|
-
{
|
|
303
|
-
<CompactItem
|
|
304
|
-
key={item.name}
|
|
305
|
-
data-label={item.name}
|
|
306
|
-
onClick={() => onSelect?.(item.name.toLowerCase())}
|
|
307
|
-
>
|
|
308
|
-
{item.icon}
|
|
309
|
-
</CompactItem>
|
|
310
|
-
))}
|
|
559
|
+
<CompactTitle>{sidebarTitle}</CompactTitle>
|
|
560
|
+
{menuItems.map((item, index) => renderCompactItem(item, index))}
|
|
311
561
|
</CompactSidebar>
|
|
312
562
|
);
|
|
313
563
|
|
|
314
564
|
case "expanded":
|
|
315
565
|
return (
|
|
316
566
|
<ExpandedSidebar>
|
|
317
|
-
<ExpandedTitle>{
|
|
567
|
+
<ExpandedTitle>{sidebarTitle}</ExpandedTitle>
|
|
318
568
|
<ExpandedSection>
|
|
319
569
|
<SectionLabel>Components</SectionLabel>
|
|
320
|
-
{
|
|
321
|
-
<ExpandedItem
|
|
322
|
-
key={item.name}
|
|
323
|
-
onClick={() => onSelect?.(item.name.toLowerCase())}
|
|
324
|
-
>
|
|
325
|
-
<ItemLeft>
|
|
326
|
-
{item.icon}
|
|
327
|
-
<span>{item.name}</span>
|
|
328
|
-
</ItemLeft>
|
|
329
|
-
<FaChevronRight size={14} style={{ opacity: 0.5 }} />
|
|
330
|
-
</ExpandedItem>
|
|
331
|
-
))}
|
|
570
|
+
{menuItems.map((item, index) => renderExpandedItem(item, index))}
|
|
332
571
|
</ExpandedSection>
|
|
333
572
|
</ExpandedSidebar>
|
|
334
573
|
);
|
|
@@ -336,16 +575,8 @@ export default function SidebarVariant({ variant = "compact", onSelect }) {
|
|
|
336
575
|
case "floating":
|
|
337
576
|
return (
|
|
338
577
|
<FloatingSidebar>
|
|
339
|
-
<FloatingTitle>{
|
|
340
|
-
{
|
|
341
|
-
<FloatingItem
|
|
342
|
-
key={item.name}
|
|
343
|
-
onClick={() => onSelect?.(item.name.toLowerCase())}
|
|
344
|
-
>
|
|
345
|
-
{item.icon}
|
|
346
|
-
<span>{item.name}</span>
|
|
347
|
-
</FloatingItem>
|
|
348
|
-
))}
|
|
578
|
+
<FloatingTitle>{sidebarTitle}</FloatingTitle>
|
|
579
|
+
{menuItems.map((item, index) => renderFloatingItem(item, index))}
|
|
349
580
|
</FloatingSidebar>
|
|
350
581
|
);
|
|
351
582
|
|