next-helios-fe 1.0.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.
Files changed (112) hide show
  1. package/@types/index.d.ts +2 -0
  2. package/dist/components/button/index.d.ts +15 -0
  3. package/dist/components/calendar/big-calendar/event.d.ts +7 -0
  4. package/dist/components/calendar/big-calendar/index.d.ts +14 -0
  5. package/dist/components/calendar/big-calendar/toolbar.d.ts +8 -0
  6. package/dist/components/calendar/calendar/index.d.ts +11 -0
  7. package/dist/components/chart/index.d.ts +17 -0
  8. package/dist/components/chip/index.d.ts +12 -0
  9. package/dist/components/content-container/accordion/index.d.ts +10 -0
  10. package/dist/components/content-container/accordion/item.d.ts +6 -0
  11. package/dist/components/content-container/card.d.ts +10 -0
  12. package/dist/components/content-container/carousel.d.ts +10 -0
  13. package/dist/components/content-container/drawer.d.ts +8 -0
  14. package/dist/components/content-container/modal/index.d.ts +21 -0
  15. package/dist/components/content-container/sortable/index.d.ts +14 -0
  16. package/dist/components/content-container/sortable/item.d.ts +8 -0
  17. package/dist/components/content-container/sortable/knob.d.ts +5 -0
  18. package/dist/components/content-container/tab/index.d.ts +17 -0
  19. package/dist/components/content-container/tab/window.d.ts +5 -0
  20. package/dist/components/data-tree/index.d.ts +6 -0
  21. package/dist/components/dialog/index.d.ts +16 -0
  22. package/dist/components/dropdown/header.d.ts +5 -0
  23. package/dist/components/dropdown/index.d.ts +15 -0
  24. package/dist/components/dropdown/item.d.ts +7 -0
  25. package/dist/components/form/index.d.ts +44 -0
  26. package/dist/components/form/input/checkbox.d.ts +9 -0
  27. package/dist/components/form/input/color.d.ts +10 -0
  28. package/dist/components/form/input/email.d.ts +9 -0
  29. package/dist/components/form/input/file.d.ts +14 -0
  30. package/dist/components/form/input/number.d.ts +9 -0
  31. package/dist/components/form/input/password.d.ts +9 -0
  32. package/dist/components/form/input/radio.d.ts +9 -0
  33. package/dist/components/form/input/range.d.ts +9 -0
  34. package/dist/components/form/input/search.d.ts +8 -0
  35. package/dist/components/form/input/text.d.ts +9 -0
  36. package/dist/components/form/input/time.d.ts +9 -0
  37. package/dist/components/form/other/autocomplete.d.ts +15 -0
  38. package/dist/components/form/other/multipleSelect.d.ts +23 -0
  39. package/dist/components/form/other/phoneNumber.d.ts +10 -0
  40. package/dist/components/form/other/pin.d.ts +10 -0
  41. package/dist/components/form/other/secret.d.ts +11 -0
  42. package/dist/components/form/other/select.d.ts +15 -0
  43. package/dist/components/form/other/textarea.d.ts +9 -0
  44. package/dist/components/index.d.ts +19 -0
  45. package/dist/components/map/index.d.ts +13 -0
  46. package/dist/components/map/marker.d.ts +8 -0
  47. package/dist/components/syntax-highlighter/index.d.ts +9 -0
  48. package/dist/components/table/action.d.ts +5 -0
  49. package/dist/components/table/index.d.ts +24 -0
  50. package/dist/components/timeline/index.d.ts +10 -0
  51. package/dist/components/timeline/item.d.ts +7 -0
  52. package/dist/index.d.ts +2 -0
  53. package/dist/index.js +2 -0
  54. package/dist/index.js.LICENSE.txt +62 -0
  55. package/package.json +72 -0
  56. package/src/components/button/index.tsx +74 -0
  57. package/src/components/calendar/big-calendar/event.tsx +46 -0
  58. package/src/components/calendar/big-calendar/index.tsx +102 -0
  59. package/src/components/calendar/big-calendar/toolbar.tsx +98 -0
  60. package/src/components/calendar/calendar/index.tsx +26 -0
  61. package/src/components/chart/index.tsx +121 -0
  62. package/src/components/chip/index.tsx +47 -0
  63. package/src/components/content-container/accordion/index.tsx +28 -0
  64. package/src/components/content-container/accordion/item.tsx +40 -0
  65. package/src/components/content-container/card.tsx +21 -0
  66. package/src/components/content-container/carousel.tsx +35 -0
  67. package/src/components/content-container/drawer.tsx +78 -0
  68. package/src/components/content-container/modal/index.tsx +127 -0
  69. package/src/components/content-container/sortable/index.tsx +47 -0
  70. package/src/components/content-container/sortable/item.tsx +20 -0
  71. package/src/components/content-container/sortable/knob.tsx +11 -0
  72. package/src/components/content-container/tab/index.tsx +94 -0
  73. package/src/components/content-container/tab/window.tsx +10 -0
  74. package/src/components/data-tree/index.tsx +60 -0
  75. package/src/components/dialog/index.tsx +88 -0
  76. package/src/components/dropdown/header.tsx +11 -0
  77. package/src/components/dropdown/index.tsx +69 -0
  78. package/src/components/dropdown/item.tsx +22 -0
  79. package/src/components/form/index.tsx +81 -0
  80. package/src/components/form/input/checkbox.tsx +49 -0
  81. package/src/components/form/input/color.tsx +104 -0
  82. package/src/components/form/input/email.tsx +40 -0
  83. package/src/components/form/input/file.tsx +189 -0
  84. package/src/components/form/input/number.tsx +93 -0
  85. package/src/components/form/input/password.tsx +57 -0
  86. package/src/components/form/input/radio.tsx +49 -0
  87. package/src/components/form/input/range.tsx +67 -0
  88. package/src/components/form/input/search.tsx +50 -0
  89. package/src/components/form/input/text.tsx +39 -0
  90. package/src/components/form/input/time.tsx +315 -0
  91. package/src/components/form/other/autocomplete.tsx +199 -0
  92. package/src/components/form/other/multipleSelect.tsx +211 -0
  93. package/src/components/form/other/phoneNumber.tsx +1668 -0
  94. package/src/components/form/other/pin.tsx +56 -0
  95. package/src/components/form/other/secret.tsx +74 -0
  96. package/src/components/form/other/select.tsx +187 -0
  97. package/src/components/form/other/textarea.tsx +44 -0
  98. package/src/components/index.ts +29 -0
  99. package/src/components/map/index.tsx +72 -0
  100. package/src/components/map/marker.tsx +40 -0
  101. package/src/components/syntax-highlighter/index.tsx +45 -0
  102. package/src/components/table/action.tsx +22 -0
  103. package/src/components/table/index.tsx +431 -0
  104. package/src/components/timeline/index.tsx +28 -0
  105. package/src/components/timeline/item.tsx +25 -0
  106. package/src/index.css +1 -0
  107. package/src/index.ts +3 -0
  108. package/src/styles/big-calendar.scss +810 -0
  109. package/src/styles/calendar.scss +195 -0
  110. package/src/styles/index.css +2 -0
  111. package/tsconfig.json +17 -0
  112. package/webpack.config.js +35 -0
@@ -0,0 +1,431 @@
1
+ "use client";
2
+ import React, { useState, useEffect, useMemo } from "react";
3
+ import { Icon } from "@iconify/react";
4
+ import { Form, Button, Dropdown } from "../../components";
5
+ import { exportToExcel } from "react-json-to-excel";
6
+ import dayjs from "dayjs";
7
+ import { Action, type ActionProps } from "./action";
8
+
9
+ interface TableProps {
10
+ title?: string;
11
+ header: { title: string; key: string }[];
12
+ data: any[];
13
+ options?: {
14
+ hideToolbar?: boolean;
15
+ hideNumber?: boolean;
16
+ checkbox?: boolean;
17
+ height?: "full" | "fit" | "20" | "40" | "80";
18
+ maxRow?: 10 | 20 | 50 | 100;
19
+ border?: boolean;
20
+ };
21
+ actions?: (e: any) => React.ReactNode;
22
+ }
23
+
24
+ interface TableComponentProps extends React.FC<TableProps> {
25
+ Action: React.FC<ActionProps>;
26
+ }
27
+
28
+ export const Table: TableComponentProps = ({
29
+ title,
30
+ header,
31
+ data,
32
+ options,
33
+ actions,
34
+ }) => {
35
+ const [search, setSearch] = useState<string>("");
36
+ const [filter, setFilter] = useState<any[]>([]);
37
+ const [maxRow, setMaxRow] = useState<number>(options?.maxRow || 10);
38
+ const [page, setPage] = useState<number>(1);
39
+ const [selected, setSelected] = useState<number[]>([]);
40
+ const [sortBy, setSortBy] = useState<string[]>(["", ""]);
41
+ const [excluded, setExcluded] = useState<string[]>([]);
42
+
43
+ const height =
44
+ options?.height === "fit"
45
+ ? "h-fit"
46
+ : options?.height === "20"
47
+ ? "h-20"
48
+ : options?.height === "40"
49
+ ? "h-40"
50
+ : options?.height === "80"
51
+ ? "h-80"
52
+ : "flex-1 h-full";
53
+
54
+ useEffect(() => {
55
+ setFilter(
56
+ header.map((item) => {
57
+ return { key: item.key, value: "" };
58
+ })
59
+ );
60
+ }, [header]);
61
+
62
+ const filteredData = useMemo(() => {
63
+ return data
64
+ ?.filter((item) => {
65
+ if (search === "") {
66
+ return item;
67
+ } else if (
68
+ header.some((headerItem) => {
69
+ if (headerItem.title !== header[1].title) {
70
+ return item[headerItem.key as keyof typeof item]
71
+ ?.toString()
72
+ .toLowerCase()
73
+ .includes(search.toLowerCase());
74
+ }
75
+ })
76
+ ) {
77
+ return item;
78
+ }
79
+ })
80
+ ?.filter((item) => {
81
+ return filter.every((filterItem) => {
82
+ return item[filterItem.key as keyof typeof item]
83
+ .toString()
84
+ .toLowerCase()
85
+ .includes(filterItem.value.toLowerCase());
86
+ });
87
+ });
88
+ }, [data, filter, search]);
89
+
90
+ const headerArr = header
91
+ ?.filter((item) => !excluded.includes(item.key))
92
+ ?.map((item) => {
93
+ return (
94
+ <th
95
+ key={item.key}
96
+ className="px-4 py-2 bg-secondary-bg font-medium text-left whitespace-nowrap"
97
+ >
98
+ <div className="flex flex-col">
99
+ <button
100
+ type="button"
101
+ className="group/header flex justify-between items-center gap-4 w-full"
102
+ onClick={() => {
103
+ setSortBy([
104
+ sortBy[0] !== item.key
105
+ ? item.key
106
+ : sortBy[0] === item.key && sortBy[1] === "asc"
107
+ ? item.key
108
+ : "",
109
+ sortBy[0] !== item.key
110
+ ? "asc"
111
+ : sortBy[0] === item.key && sortBy[1] === "asc"
112
+ ? "desc"
113
+ : "",
114
+ ]);
115
+ }}
116
+ >
117
+ {item.title}
118
+ <Icon
119
+ icon={`mi:${
120
+ item.key === sortBy[0] && sortBy[1] === "asc"
121
+ ? "arrow-up"
122
+ : item.key === sortBy[0] && sortBy[1] === "desc"
123
+ ? "arrow-down"
124
+ : "sort"
125
+ }`}
126
+ className={`group-hover/header:visible ${
127
+ item.key === sortBy[0] ? "visible" : "invisible"
128
+ }`}
129
+ />
130
+ </button>
131
+ <input
132
+ type="search"
133
+ className="w-full px-0 pt-0 pb-0.5 border-default border-t-0 border-b border-x-0 bg-secondary-bg text-sm font-normal placeholder:duration-300 placeholder:translate-x-0 [&::-webkit-search-cancel-button]:appearance-none focus:placeholder:translate-x-1 placeholder:text-slate-300 focus:outline-none focus:ring-0 focus:border-primary-dark disabled:bg-secondary-light disabled:text-slate-400"
134
+ value={
135
+ filter.find((filterItem) => filterItem.key === item.key)?.value
136
+ }
137
+ onChange={(e) => {
138
+ setFilter(
139
+ filter.map((filterItem) => {
140
+ return filterItem.key === item.key
141
+ ? { ...filterItem, value: e.target.value }
142
+ : filterItem;
143
+ })
144
+ );
145
+ }}
146
+ />
147
+ </div>
148
+ </th>
149
+ );
150
+ });
151
+
152
+ const dataArr = filteredData
153
+ ?.sort((a, b) => {
154
+ if (sortBy[1] === "asc") {
155
+ return a[sortBy[0] as keyof typeof a] > b[sortBy[0] as keyof typeof b]
156
+ ? 1
157
+ : -1;
158
+ } else if (sortBy[1] === "desc") {
159
+ return a[sortBy[0] as keyof typeof a] < b[sortBy[0] as keyof typeof b]
160
+ ? 1
161
+ : -1;
162
+ } else {
163
+ return a.id > b.id ? 1 : -1;
164
+ }
165
+ })
166
+ ?.slice((page - 1) * maxRow, page * maxRow)
167
+ ?.map((item, index) => {
168
+ return (
169
+ <tr key={item.id}>
170
+ {options?.checkbox && (
171
+ <td className="sticky left-0 w-8 px-4 py-1 border-b bg-secondary-bg">
172
+ <Form.Checkbox
173
+ options={{ disableHover: true }}
174
+ checked={selected.includes(item.id)}
175
+ onChange={(e) => {
176
+ if (selected.includes(item.id)) {
177
+ setSelected(selected.filter((prev) => prev !== item.id));
178
+ } else {
179
+ setSelected([...selected, item.id]);
180
+ }
181
+ }}
182
+ />
183
+ </td>
184
+ )}
185
+ {!options?.hideNumber && (
186
+ <td className="sticky left-0 px-4 py-1 border-b bg-secondary-bg text-center">
187
+ {(page - 1) * maxRow + index + 1}
188
+ </td>
189
+ )}
190
+ {header
191
+ ?.filter((headerItem) => !excluded.includes(headerItem.key))
192
+ ?.map((headerItem) => {
193
+ return (
194
+ <td
195
+ key={headerItem.key}
196
+ className="px-4 py-1 border-b bg-secondary-bg whitespace-nowrap"
197
+ >
198
+ {item[headerItem.key as keyof typeof item]}
199
+ </td>
200
+ );
201
+ })}
202
+ {actions && (
203
+ <td className="px-4 py-1 border-b bg-secondary-bg text-center">
204
+ {actions(item)}
205
+ </td>
206
+ )}
207
+ </tr>
208
+ );
209
+ });
210
+
211
+ return (
212
+ <div className="flex flex-col gap-6 h-full">
213
+ {!options?.hideToolbar && (
214
+ <div className="flex justify-between items-center gap-4 w-full h-fit">
215
+ <span className="text-lg">{title}</span>
216
+ <div className="flex items-center gap-4">
217
+ <Dropdown
218
+ trigger={
219
+ <button
220
+ type="button"
221
+ className="px-2 py-2 rounded-full hover:bg-secondary-light"
222
+ >
223
+ <Icon icon="mage:filter" className="text-xl" />
224
+ </button>
225
+ }
226
+ >
227
+ {header.map((item) => {
228
+ return (
229
+ <Dropdown.Item
230
+ key={item.key}
231
+ onClick={() => {
232
+ if (excluded.includes(item.key)) {
233
+ setExcluded(
234
+ excluded.filter((prev) => prev !== item.key)
235
+ );
236
+ } else {
237
+ setExcluded([...excluded, item.key]);
238
+ }
239
+ }}
240
+ >
241
+ <Form.Checkbox
242
+ options={{ disableHover: true }}
243
+ label={item.title}
244
+ checked={!excluded.includes(item.key)}
245
+ />
246
+ </Dropdown.Item>
247
+ );
248
+ })}
249
+ </Dropdown>
250
+ <Form.Search
251
+ options={{ width: "fit" }}
252
+ placeholder="search.."
253
+ value={search}
254
+ onChange={(e) => {
255
+ setSearch(e.target.value);
256
+ }}
257
+ />
258
+ <Button
259
+ options={{ variant: "primary", width: "fit" }}
260
+ onClick={() => {
261
+ exportToExcel(
262
+ data,
263
+ `${title}-data_${dayjs().format("YYYY-MM-DD_HH-mm-ss")}`
264
+ );
265
+ }}
266
+ >
267
+ Export
268
+ </Button>
269
+ </div>
270
+ </div>
271
+ )}
272
+ <div
273
+ className={`overflow-auto ${height} ${
274
+ options?.border && "border rounded-md"
275
+ }`}
276
+ >
277
+ <table className="w-full text-sm overflow-x-auto">
278
+ <thead className="sticky top-0 z-10 border-b">
279
+ <tr>
280
+ {options?.checkbox && (
281
+ <th className="sticky left-0 w-8 px-4 py-2 bg-secondary-bg">
282
+ <div className="flex flex-col">
283
+ <Form.Checkbox
284
+ options={{ disableHover: true }}
285
+ checked={selected.length === data.length}
286
+ onChange={(e) => {
287
+ if (selected.length === data.length) {
288
+ setSelected([]);
289
+ } else {
290
+ setSelected(data.map((item) => item.id));
291
+ }
292
+ }}
293
+ />
294
+ <div className="invisible w-0 overflow-hidden">
295
+ <input
296
+ type="search"
297
+ className="w-full px-0 pt-0 pb-0.5 border-default border-t-0 border-b border-x-0 bg-secondary-bg text-sm font-normal placeholder:duration-300 placeholder:translate-x-0 [&::-webkit-search-cancel-button]:appearance-none focus:placeholder:translate-x-1 placeholder:text-slate-300 focus:outline-none focus:ring-0 focus:border-primary-dark disabled:bg-secondary-light disabled:text-slate-400"
298
+ />
299
+ </div>
300
+ </div>
301
+ </th>
302
+ )}
303
+ {!options?.hideNumber && (
304
+ <th className="sticky left-0 w-min px-4 py-2 bg-secondary-bg font-medium text-center whitespace-nowrap">
305
+ <div className="flex flex-col">
306
+ <span>NO.</span>
307
+ <div className="invisible w-0 overflow-hidden">
308
+ <input
309
+ type="search"
310
+ className="w-full px-0 pt-0 pb-0.5 border-default border-t-0 border-b border-x-0 bg-secondary-bg text-sm font-normal placeholder:duration-300 placeholder:translate-x-0 [&::-webkit-search-cancel-button]:appearance-none focus:placeholder:translate-x-1 placeholder:text-slate-300 focus:outline-none focus:ring-0 focus:border-primary-dark disabled:bg-secondary-light disabled:text-slate-400"
311
+ />
312
+ </div>
313
+ </div>
314
+ </th>
315
+ )}
316
+ {headerArr}
317
+ {actions && (
318
+ <th className="w-min px-4 py-2 bg-secondary-bg font-medium text-center">
319
+ <div className="flex flex-col">
320
+ <span>Actions</span>
321
+ <div className="invisible w-0 overflow-hidden">
322
+ <input
323
+ type="search"
324
+ className="w-full px-0 pt-0 pb-0.5 border-default border-t-0 border-b border-x-0 bg-secondary-bg text-sm font-normal placeholder:duration-300 placeholder:translate-x-0 [&::-webkit-search-cancel-button]:appearance-none focus:placeholder:translate-x-1 placeholder:text-slate-300 focus:outline-none focus:ring-0 focus:border-primary-dark disabled:bg-secondary-light disabled:text-slate-400"
325
+ />
326
+ </div>
327
+ </div>
328
+ </th>
329
+ )}
330
+ </tr>
331
+ </thead>
332
+ <tbody>{dataArr}</tbody>
333
+ </table>
334
+ </div>
335
+ {!options?.hideToolbar && (
336
+ <div className="flex justify-between items-end gap-2 w-full h-fit">
337
+ <div className="!text-sm">
338
+ <Form.Select
339
+ options={{
340
+ width: "fit",
341
+ height: "short",
342
+ }}
343
+ label="Data per page:"
344
+ menus={[
345
+ { label: "10", value: "10" },
346
+ { label: "20", value: "20" },
347
+ { label: "50", value: "50" },
348
+ { label: "100", value: "100" },
349
+ ]}
350
+ value={maxRow.toString()}
351
+ onChange={(e) => {
352
+ setMaxRow(Number(e.target.value));
353
+ }}
354
+ />
355
+ </div>
356
+ <span className="hidden md:block text-sm text-slate-400">{`Showing ${
357
+ (page - 1) * maxRow + 1
358
+ } to ${
359
+ page * maxRow > data.length ? data.length : page * maxRow
360
+ } of ${data.length} entries`}</span>
361
+ <div className="flex items-center gap-2 text-xs font-light">
362
+ <button
363
+ type="button"
364
+ className="flex justify-center items-center border rounded-md min-w-9 h-9 bg-secondary-bg hover:bg-secondary-light disabled:bg-secondary-light disabled:text-slate-400 disabled:pointer-events-none"
365
+ disabled={page === 1}
366
+ onClick={() => {
367
+ setPage(1);
368
+ }}
369
+ >
370
+ <Icon icon="gravity-ui:chevrons-left" />
371
+ </button>
372
+ <button
373
+ type="button"
374
+ className="hidden md:flex justify-center items-center border rounded-md min-w-9 h-9 bg-secondary-bg hover:bg-secondary-light disabled:bg-secondary-light disabled:text-slate-400 disabled:pointer-events-none"
375
+ disabled={page === 1}
376
+ onClick={() => {
377
+ setPage((prev) => prev - 1);
378
+ }}
379
+ >
380
+ <Icon icon="gravity-ui:chevron-left" />
381
+ </button>
382
+ <div className="flex gap-2 max-w-20 overflow-auto [&::-webkit-scrollbar]:hidden">
383
+ {Array.from({ length: Math.ceil(data.length / maxRow) }).map(
384
+ (_, index) => {
385
+ return (
386
+ <button
387
+ key={index}
388
+ type="button"
389
+ className={`flex justify-center items-center border rounded-md min-w-9 h-9 ${
390
+ page === index + 1
391
+ ? "bg-primary-light text-primary"
392
+ : "bg-secondary-bg hover:bg-secondary-light"
393
+ }`}
394
+ onClick={() => {
395
+ setPage(index + 1);
396
+ }}
397
+ >
398
+ {index + 1}
399
+ </button>
400
+ );
401
+ }
402
+ )}
403
+ </div>
404
+ <button
405
+ type="button"
406
+ className="hidden md:flex justify-center items-center border rounded-md min-w-9 h-9 bg-secondary-bg hover:bg-secondary-light disabled:bg-secondary-light disabled:text-slate-400 disabled:pointer-events-none"
407
+ disabled={data.length <= page * maxRow}
408
+ onClick={() => {
409
+ setPage((prev) => prev + 1);
410
+ }}
411
+ >
412
+ <Icon icon="gravity-ui:chevron-right" />
413
+ </button>
414
+ <button
415
+ type="button"
416
+ className="flex justify-center items-center border rounded-md min-w-9 h-9 bg-secondary-bg hover:bg-secondary-light disabled:bg-secondary-light disabled:text-slate-400 disabled:pointer-events-none"
417
+ disabled={data.length <= page * maxRow}
418
+ onClick={() => {
419
+ setPage(Math.ceil(data.length / maxRow));
420
+ }}
421
+ >
422
+ <Icon icon="gravity-ui:chevrons-right" />
423
+ </button>
424
+ </div>
425
+ </div>
426
+ )}
427
+ </div>
428
+ );
429
+ };
430
+
431
+ Table.Action = Action;
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import React from "react";
3
+ import { Item, type ItemProps } from "./item";
4
+
5
+ interface TimelineProps {
6
+ children?: React.ReactNode;
7
+ }
8
+
9
+ interface TimelineComponent extends React.FC<TimelineProps> {
10
+ Item: React.FC<ItemProps>;
11
+ }
12
+
13
+ export const Timeline: TimelineComponent = ({ children }) => {
14
+ const childrenList = React.Children.toArray(children);
15
+ const itemList = childrenList.filter((child) => {
16
+ return (child as React.ReactElement).type === Timeline.Item;
17
+ });
18
+
19
+ return (
20
+ <div className="space-y-8 relative before:absolute before:inset-0 before:ml-4 before:-translate-x-px md:before:mx-auto md:before:translate-x-0 before:h-full before:w-0.5 before:bg-gradient-to-b before:from-transparent before:via-primary before:to-transparent">
21
+ {itemList.map((item) => {
22
+ return item;
23
+ })}
24
+ </div>
25
+ );
26
+ };
27
+
28
+ Timeline.Item = Item;
@@ -0,0 +1,25 @@
1
+ "use client";
2
+ import React from "react";
3
+
4
+ export interface ItemProps {
5
+ children: React.ReactNode;
6
+ icon?: React.ReactNode;
7
+ isActive?: boolean;
8
+ }
9
+
10
+ export const Item: React.FC<ItemProps> = ({ children, icon, isActive }) => {
11
+ return (
12
+ <div
13
+ className={`relative flex items-center justify-between md:justify-normal md:odd:flex-row-reverse group ${
14
+ isActive && "is-active"
15
+ }`}
16
+ >
17
+ <div className="flex items-center justify-center w-8 h-8 rounded-full border border-white bg-slate-300 group-[.is-active]:bg-primary group-[.is-active]:text-white shadow shrink-0 md:order-1 md:group-odd:-translate-x-1/2 md:group-even:translate-x-1/2">
18
+ {icon}
19
+ </div>
20
+ <div className="w-[calc(100%-4rem)] md:w-[calc(50%-2rem)]">
21
+ {children}
22
+ </div>
23
+ </div>
24
+ );
25
+ };
package/src/index.css ADDED
@@ -0,0 +1 @@
1
+ @import "./styles/index.css";
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ import "./index.css";
2
+
3
+ export * from "./components";