styled-hairomin 0.2.2

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 ADDED
@@ -0,0 +1 @@
1
+ npm install styled-hairomin
@@ -0,0 +1,233 @@
1
+ "use client";
2
+
3
+ import styled from "styled-components";
4
+ import { FaCheck, FaChevronRight, FaDownload } from "react-icons/fa";
5
+
6
+ const variantStyles = {
7
+ solid: {
8
+ background: "#0066cc",
9
+ color: "#fff",
10
+ hover: "#0052a3",
11
+ },
12
+ outline: {
13
+ background: "transparent",
14
+ color: "#0066cc",
15
+ border: "#0066cc",
16
+ hover: "#0066cc",
17
+ },
18
+ pill: {
19
+ background: "linear-gradient(135deg, #0066cc 0%, #004080 100%)",
20
+ color: "#fff",
21
+ hover: "linear-gradient(135deg, #0052a3 0%, #003366 100%)",
22
+ },
23
+ };
24
+
25
+ const SolidButton = styled.button`
26
+ display: inline-flex;
27
+ align-items: center;
28
+ justify-content: center;
29
+ gap: 0.8rem;
30
+ padding: 1rem 2.2rem;
31
+ font-size: 16px;
32
+ font-weight: 700;
33
+ border-radius: 12px;
34
+ border: none;
35
+ cursor: pointer;
36
+ transition: all 0.3s ease;
37
+ font-family: "Poppins", sans-serif;
38
+ background: ${variantStyles.solid.background};
39
+ color: ${variantStyles.solid.color};
40
+ box-shadow: 0 4px 15px rgba(0, 102, 204, 0.3);
41
+ text-transform: uppercase;
42
+ letter-spacing: 0.5px;
43
+
44
+ &:hover {
45
+ background: ${variantStyles.solid.hover};
46
+ transform: translateY(-3px);
47
+ box-shadow: 0 6px 20px rgba(0, 102, 204, 0.4);
48
+ }
49
+
50
+ &:active {
51
+ transform: translateY(-1px);
52
+ }
53
+
54
+ svg {
55
+ font-size: 18px;
56
+ transition: transform 0.3s;
57
+ flex-shrink: 0;
58
+ }
59
+
60
+ &:hover svg {
61
+ transform: translateX(5px);
62
+ }
63
+
64
+ @media (max-width: 768px) {
65
+ padding: 0.8rem 1.5rem;
66
+ font-size: 13px;
67
+ gap: 0.5rem;
68
+ width: 100%;
69
+
70
+ svg {
71
+ font-size: 14px;
72
+ }
73
+ }
74
+ `;
75
+
76
+ /* ====== VARIANT OUTLINE: Tombol dengan border dan efek fill saat hover ====== */
77
+ const OutlineButton = styled.button`
78
+ display: inline-flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ gap: 0.6rem;
82
+ padding: 0.9rem 2rem;
83
+ font-size: 15px;
84
+ font-weight: 600;
85
+ border-radius: 8px;
86
+ border: 2px solid ${variantStyles.outline.border};
87
+ background: ${variantStyles.outline.background};
88
+ color: ${variantStyles.outline.color};
89
+ cursor: pointer;
90
+ transition: all 0.3s ease;
91
+ font-family: "Inter", sans-serif;
92
+ position: relative;
93
+ overflow: hidden;
94
+
95
+ &::before {
96
+ content: "";
97
+ position: absolute;
98
+ top: 0;
99
+ left: -100%;
100
+ width: 100%;
101
+ height: 100%;
102
+ background: ${variantStyles.outline.hover};
103
+ transition: left 0.4s ease;
104
+ z-index: 0;
105
+ }
106
+
107
+ &:hover::before {
108
+ left: 0;
109
+ }
110
+
111
+ &:hover {
112
+ color: white;
113
+ border-color: ${variantStyles.outline.hover};
114
+ }
115
+
116
+ span, svg {
117
+ position: relative;
118
+ z-index: 1;
119
+ }
120
+
121
+ svg {
122
+ transition: transform 0.3s;
123
+ flex-shrink: 0;
124
+ }
125
+
126
+ &:hover svg {
127
+ transform: scale(1.2);
128
+ }
129
+
130
+ @media (max-width: 768px) {
131
+ padding: 0.7rem 1.5rem;
132
+ font-size: 13px;
133
+ gap: 0.5rem;
134
+ width: 100%;
135
+ }
136
+ `;
137
+
138
+ /* ====== VARIANT PILL: Tombol bulat dengan gradien ====== */
139
+ const PillButton = styled.button`
140
+ display: inline-flex;
141
+ align-items: center;
142
+ justify-content: center;
143
+ gap: 0.7rem;
144
+ padding: 1.1rem 2.5rem;
145
+ font-size: 15px;
146
+ font-weight: 700;
147
+ border-radius: 50px;
148
+ border: none;
149
+ cursor: pointer;
150
+ transition: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
151
+ font-family: "Poppins", sans-serif;
152
+ background: ${variantStyles.pill.background};
153
+ color: ${variantStyles.pill.color};
154
+ box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
155
+ position: relative;
156
+ overflow: hidden;
157
+
158
+ &::after {
159
+ content: "";
160
+ position: absolute;
161
+ top: 50%;
162
+ left: 50%;
163
+ width: 0;
164
+ height: 0;
165
+ border-radius: 50%;
166
+ background: rgba(255, 255, 255, 0.2);
167
+ transform: translate(-50%, -50%);
168
+ transition: width 0.6s, height 0.6s;
169
+ }
170
+
171
+ &:hover::after {
172
+ width: 300px;
173
+ height: 300px;
174
+ }
175
+
176
+ &:hover {
177
+ transform: scale(1.05);
178
+ box-shadow: 0 12px 35px rgba(0, 102, 204, 0.6);
179
+ }
180
+
181
+ span, svg {
182
+ position: relative;
183
+ z-index: 1;
184
+ }
185
+
186
+ svg {
187
+ animation: bounce 2s infinite;
188
+ flex-shrink: 0;
189
+ }
190
+
191
+ @keyframes bounce {
192
+ 0%, 100% { transform: translateY(0); }
193
+ 50% { transform: translateY(-5px); }
194
+ }
195
+
196
+ @media (max-width: 768px) {
197
+ padding: 0.9rem 2rem;
198
+ font-size: 13px;
199
+ gap: 0.5rem;
200
+ width: 100%;
201
+ }
202
+ `;
203
+
204
+ export default function ButtonVariant({ variant = "solid", onClick, data }) {
205
+ switch (variant) {
206
+ case "solid":
207
+ return (
208
+ <SolidButton onClick={onClick}>
209
+ <span>{data?.label || "Konfirmasi Pemesanan"}</span>
210
+ {data?.icon || <FaChevronRight />}
211
+ </SolidButton>
212
+ );
213
+
214
+ case "outline":
215
+ return (
216
+ <OutlineButton onClick={onClick}>
217
+ {data?.icon || <FaCheck />}
218
+ <span>{data?.label || "Tambah ke Favorit"}</span>
219
+ </OutlineButton>
220
+ );
221
+
222
+ case "pill":
223
+ return (
224
+ <PillButton onClick={onClick}>
225
+ {data?.icon || <FaDownload />}
226
+ <span>{data?.label || "Unduh"}</span>
227
+ </PillButton>
228
+ );
229
+
230
+ default:
231
+ return null;
232
+ }
233
+ }
@@ -0,0 +1,387 @@
1
+ "use client";
2
+
3
+ import styled from "styled-components";
4
+ import { FaStar, FaMapMarkerAlt, FaWifi, FaBed } from "react-icons/fa";
5
+
6
+ const variantStyles = {
7
+ elevated: {
8
+ background: "#fff",
9
+ color: "#0066cc",
10
+ },
11
+ bordered: {
12
+ background: "#f8f9fa",
13
+ color: "#0066cc",
14
+ },
15
+ gradient: {
16
+ background: "linear-gradient(135deg, #0066cc 0%, #004080 100%)",
17
+ color: "#fff",
18
+ },
19
+ };
20
+
21
+ const ElevatedCard = styled.div`
22
+ width: 100%;
23
+ max-width: 350px;
24
+ background: ${variantStyles.elevated.background};
25
+ border-radius: 20px;
26
+ overflow: hidden;
27
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
28
+ transition: all 0.4s ease;
29
+ cursor: pointer;
30
+
31
+ &:hover {
32
+ transform: translateY(-10px);
33
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
34
+ }
35
+
36
+ @media (max-width: 768px) {
37
+ max-width: 100%;
38
+ }
39
+ `;
40
+
41
+ const ElevatedImageWrapper = styled.div`
42
+ position: relative;
43
+ height: 220px;
44
+ overflow: hidden;
45
+ `;
46
+
47
+ const ElevatedImage = styled.img`
48
+ width: 100%;
49
+ height: 100%;
50
+ object-fit: cover;
51
+ transition: transform 0.4s;
52
+
53
+ ${ElevatedCard}:hover & {
54
+ transform: scale(1.1);
55
+ }
56
+ `;
57
+
58
+ const Badge = styled.div`
59
+ position: absolute;
60
+ top: 15px;
61
+ right: 15px;
62
+ background: rgba(0, 102, 204, 0.95);
63
+ color: #fff;
64
+ padding: 0.5rem 1rem;
65
+ border-radius: 25px;
66
+ font-weight: 700;
67
+ font-size: 14px;
68
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
69
+ `;
70
+
71
+ const ElevatedContent = styled.div`
72
+ padding: 1.5rem;
73
+ `;
74
+
75
+ const ElevatedTitle = styled.h3`
76
+ margin: 0 0 0.8rem;
77
+ font-size: 1.5rem;
78
+ font-weight: 700;
79
+ color: #0066cc;
80
+ `;
81
+
82
+ const ElevatedFeatures = styled.div`
83
+ display: flex;
84
+ gap: 1.2rem;
85
+ margin: 1rem 0;
86
+ color: #7f8c8d;
87
+ font-size: 14px;
88
+ `;
89
+
90
+ const Feature = styled.div`
91
+ display: flex;
92
+ align-items: center;
93
+ gap: 0.4rem;
94
+ `;
95
+
96
+ const ElevatedFooter = styled.div`
97
+ display: flex;
98
+ justify-content: space-between;
99
+ align-items: center;
100
+ margin-top: 1.2rem;
101
+ padding-top: 1rem;
102
+ border-top: 1px solid #ecf0f1;
103
+ `;
104
+
105
+ const Price = styled.div`
106
+ font-size: 1.6rem;
107
+ font-weight: 800;
108
+ color: #0066cc;
109
+
110
+ span {
111
+ font-size: 0.9rem;
112
+ font-weight: 400;
113
+ color: #95a5a6;
114
+ }
115
+
116
+ @media (max-width: 768px) {
117
+ font-size: 1.3rem;
118
+
119
+ span {
120
+ font-size: 0.8rem;
121
+ }
122
+ }
123
+ `;
124
+
125
+ const Rating = styled.div`
126
+ display: flex;
127
+ align-items: center;
128
+ gap: 0.3rem;
129
+ color: #f39c12;
130
+ font-weight: 600;
131
+ `;
132
+
133
+ /* ====== VARIANT BORDERED: Card dengan outline dan ikon ====== */
134
+ const BorderedCard = styled.div`
135
+ width: 100%;
136
+ max-width: 380px;
137
+ background: ${variantStyles.bordered.background};
138
+ border: 3px solid #dee2e6;
139
+ border-radius: 16px;
140
+ overflow: hidden;
141
+ transition: all 0.3s ease;
142
+ cursor: pointer;
143
+
144
+ &:hover {
145
+ border-color: #6c757d;
146
+ box-shadow: 0 8px 24px rgba(108, 117, 125, 0.2);
147
+ }
148
+
149
+ @media (max-width: 768px) {
150
+ max-width: 100%;
151
+ }
152
+ `;
153
+
154
+ const BorderedContent = styled.div`
155
+ padding: 1.8rem;
156
+ `;
157
+
158
+ const BorderedHeader = styled.div`
159
+ display: flex;
160
+ justify-content: space-between;
161
+ align-items: start;
162
+ margin-bottom: 1rem;
163
+ `;
164
+
165
+ const BorderedTitle = styled.h3`
166
+ margin: 0;
167
+ font-size: 1.4rem;
168
+ font-weight: 700;
169
+ color: #0066cc;
170
+ `;
171
+
172
+ const BorderedLocation = styled.div`
173
+ display: flex;
174
+ align-items: center;
175
+ gap: 0.4rem;
176
+ color: #6c757d;
177
+ font-size: 14px;
178
+ margin: 0.5rem 0 1rem;
179
+ `;
180
+
181
+ const BorderedImage = styled.img`
182
+ width: 100%;
183
+ height: 200px;
184
+ object-fit: cover;
185
+ border-radius: 12px;
186
+ margin: 1rem 0;
187
+ `;
188
+
189
+ const BorderedDescription = styled.p`
190
+ color: #495057;
191
+ font-size: 14px;
192
+ line-height: 1.6;
193
+ margin: 1rem 0;
194
+ `;
195
+
196
+ const BorderedFooter = styled.div`
197
+ display: flex;
198
+ justify-content: space-between;
199
+ align-items: center;
200
+ margin-top: 1.5rem;
201
+ padding-top: 1rem;
202
+ border-top: 2px solid #dee2e6;
203
+ flex-wrap: wrap;
204
+ gap: 1rem;
205
+
206
+ @media (max-width: 480px) {
207
+ flex-direction: column;
208
+ align-items: stretch;
209
+ text-align: center;
210
+ }
211
+ `;
212
+
213
+ const BorderedPrice = styled.div`
214
+ font-size: 1.8rem;
215
+ font-weight: 800;
216
+ color: #0066cc;
217
+
218
+ @media (max-width: 768px) {
219
+ font-size: 1.5rem;
220
+ }
221
+ `;
222
+
223
+ const BookButton = styled.button`
224
+ background: #0066cc;
225
+ color: white;
226
+ border: none;
227
+ padding: 0.7rem 1.5rem;
228
+ border-radius: 8px;
229
+ font-weight: 600;
230
+ cursor: pointer;
231
+ transition: all 0.3s;
232
+
233
+ &:hover {
234
+ background: #0052a3;
235
+ transform: scale(1.05);
236
+ }
237
+ `;
238
+
239
+ /* ====== VARIANT GRADIENT: Card gradien berwarna ====== */
240
+ const GradientCard = styled.div`
241
+ width: 100%;
242
+ max-width: 320px;
243
+ background: ${variantStyles.gradient.background};
244
+ border-radius: 24px;
245
+ overflow: visible;
246
+ position: relative;
247
+ box-shadow: 0 15px 45px rgba(245, 87, 108, 0.4);
248
+ transition: all 0.4s ease;
249
+ cursor: pointer;
250
+
251
+ &:hover {
252
+ transform: scale(1.05) rotate(2deg);
253
+ }
254
+
255
+ @media (max-width: 768px) {
256
+ max-width: 100%;
257
+
258
+ &:hover {
259
+ transform: none;
260
+ }
261
+ }
262
+ `;
263
+
264
+ const GradientImageWrapper = styled.div`
265
+ padding: 1.5rem 1.5rem 0;
266
+ `;
267
+
268
+ const GradientImage = styled.img`
269
+ width: 100%;
270
+ height: 240px;
271
+ object-fit: cover;
272
+ border-radius: 16px;
273
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
274
+ `;
275
+
276
+ const GradientContent = styled.div`
277
+ padding: 1.5rem;
278
+ color: white;
279
+ `;
280
+
281
+ const GradientTitle = styled.h3`
282
+ margin: 0 0 0.5rem;
283
+ font-size: 1.6rem;
284
+ font-weight: 800;
285
+ text-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
286
+ `;
287
+
288
+ const GradientDescription = styled.p`
289
+ margin: 0.5rem 0 1rem;
290
+ opacity: 0.95;
291
+ font-size: 14px;
292
+ line-height: 1.5;
293
+ `;
294
+
295
+ const GradientFooter = styled.div`
296
+ display: flex;
297
+ justify-content: space-between;
298
+ align-items: center;
299
+ `;
300
+
301
+ const GradientPrice = styled.div`
302
+ font-size: 2rem;
303
+ font-weight: 900;
304
+ text-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
305
+
306
+ @media (max-width: 768px) {
307
+ font-size: 1.5rem;
308
+ }
309
+ `;
310
+
311
+ const GradientRating = styled.div`
312
+ background: rgba(255, 255, 255, 0.25);
313
+ backdrop-filter: blur(10px);
314
+ padding: 0.5rem 1rem;
315
+ border-radius: 20px;
316
+ font-weight: 700;
317
+ display: flex;
318
+ align-items: center;
319
+ gap: 0.3rem;
320
+ `;
321
+
322
+ export default function CardVariant({ variant = "elevated", data }) {
323
+ switch (variant) {
324
+ case "elevated":
325
+ return (
326
+ <ElevatedCard>
327
+ <ElevatedImageWrapper>
328
+ <ElevatedImage src={data.image} alt={data.title} />
329
+ <Badge>{data.badge}</Badge>
330
+ </ElevatedImageWrapper>
331
+ <ElevatedContent>
332
+ <ElevatedTitle>{data.title}</ElevatedTitle>
333
+ <ElevatedFeatures>
334
+ <Feature><FaBed /> Kasur Lembut</Feature>
335
+ <Feature><FaWifi /> WiFi Gratis</Feature>
336
+ </ElevatedFeatures>
337
+ <ElevatedFooter>
338
+ <Price>{data.price}<span>/malam</span></Price>
339
+ <Rating><FaStar /> {data.rating}</Rating>
340
+ </ElevatedFooter>
341
+ </ElevatedContent>
342
+ </ElevatedCard>
343
+ );
344
+
345
+ case "bordered":
346
+ return (
347
+ <BorderedCard>
348
+ <BorderedContent>
349
+ <BorderedHeader>
350
+ <div>
351
+ <BorderedTitle>{data.title}</BorderedTitle>
352
+ <BorderedLocation>
353
+ <FaMapMarkerAlt /> {data.location}
354
+ </BorderedLocation>
355
+ </div>
356
+ </BorderedHeader>
357
+ <BorderedImage src={data.image} alt={data.title} />
358
+ <BorderedDescription>{data.description}</BorderedDescription>
359
+ <BorderedFooter>
360
+ <BorderedPrice>{data.price}</BorderedPrice>
361
+ <BookButton>Pesan Sekarang</BookButton>
362
+ </BorderedFooter>
363
+ </BorderedContent>
364
+ </BorderedCard>
365
+ );
366
+
367
+ case "gradient":
368
+ return (
369
+ <GradientCard>
370
+ <GradientImageWrapper>
371
+ <GradientImage src={data.image} alt={data.title} />
372
+ </GradientImageWrapper>
373
+ <GradientContent>
374
+ <GradientTitle>{data.title}</GradientTitle>
375
+ <GradientDescription>{data.description}</GradientDescription>
376
+ <GradientFooter>
377
+ <GradientPrice>{data.price}</GradientPrice>
378
+ <GradientRating>★ {data.rating}</GradientRating>
379
+ </GradientFooter>
380
+ </GradientContent>
381
+ </GradientCard>
382
+ );
383
+
384
+ default:
385
+ return null;
386
+ }
387
+ }