tio-design-make-experiments 0.0.1

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 (108) hide show
  1. package/ATTRIBUTIONS.md +3 -0
  2. package/README.md +11 -0
  3. package/guidelines/Guidelines.md +61 -0
  4. package/index.html +15 -0
  5. package/package.json +91 -0
  6. package/postcss.config.mjs +15 -0
  7. package/src/app/App.tsx +6 -0
  8. package/src/app/components/design-system/Buttons.tsx +623 -0
  9. package/src/app/components/design-system/Cards.tsx +123 -0
  10. package/src/app/components/design-system/Charts.tsx +135 -0
  11. package/src/app/components/design-system/ColorPalette.tsx +86 -0
  12. package/src/app/components/design-system/CopyButton.tsx +102 -0
  13. package/src/app/components/design-system/Forms.tsx +409 -0
  14. package/src/app/components/design-system/Icons.tsx +140 -0
  15. package/src/app/components/design-system/ListItems.tsx +234 -0
  16. package/src/app/components/design-system/Navigation.tsx +344 -0
  17. package/src/app/components/design-system/Patterns.tsx +235 -0
  18. package/src/app/components/design-system/PopoverMenu.tsx +81 -0
  19. package/src/app/components/design-system/SectionHeader.tsx +22 -0
  20. package/src/app/components/design-system/Spacing.tsx +109 -0
  21. package/src/app/components/design-system/StatusIndicators.tsx +194 -0
  22. package/src/app/components/design-system/Typography.tsx +88 -0
  23. package/src/app/components/figma/ImageWithFallback.tsx +27 -0
  24. package/src/app/components/ui/accordion.tsx +66 -0
  25. package/src/app/components/ui/alert-dialog.tsx +157 -0
  26. package/src/app/components/ui/alert.tsx +66 -0
  27. package/src/app/components/ui/aspect-ratio.tsx +11 -0
  28. package/src/app/components/ui/avatar.tsx +53 -0
  29. package/src/app/components/ui/badge.tsx +46 -0
  30. package/src/app/components/ui/breadcrumb.tsx +109 -0
  31. package/src/app/components/ui/button.tsx +58 -0
  32. package/src/app/components/ui/calendar.tsx +75 -0
  33. package/src/app/components/ui/card.tsx +92 -0
  34. package/src/app/components/ui/carousel.tsx +241 -0
  35. package/src/app/components/ui/chart.tsx +353 -0
  36. package/src/app/components/ui/checkbox.tsx +32 -0
  37. package/src/app/components/ui/collapsible.tsx +33 -0
  38. package/src/app/components/ui/command.tsx +177 -0
  39. package/src/app/components/ui/context-menu.tsx +252 -0
  40. package/src/app/components/ui/dialog.tsx +135 -0
  41. package/src/app/components/ui/drawer.tsx +132 -0
  42. package/src/app/components/ui/dropdown-menu.tsx +257 -0
  43. package/src/app/components/ui/form.tsx +168 -0
  44. package/src/app/components/ui/hover-card.tsx +44 -0
  45. package/src/app/components/ui/input-otp.tsx +77 -0
  46. package/src/app/components/ui/input.tsx +21 -0
  47. package/src/app/components/ui/label.tsx +24 -0
  48. package/src/app/components/ui/menubar.tsx +276 -0
  49. package/src/app/components/ui/navigation-menu.tsx +168 -0
  50. package/src/app/components/ui/pagination.tsx +127 -0
  51. package/src/app/components/ui/popover.tsx +48 -0
  52. package/src/app/components/ui/progress.tsx +31 -0
  53. package/src/app/components/ui/radio-group.tsx +45 -0
  54. package/src/app/components/ui/resizable.tsx +56 -0
  55. package/src/app/components/ui/scroll-area.tsx +58 -0
  56. package/src/app/components/ui/select.tsx +189 -0
  57. package/src/app/components/ui/separator.tsx +28 -0
  58. package/src/app/components/ui/sheet.tsx +139 -0
  59. package/src/app/components/ui/sidebar.tsx +726 -0
  60. package/src/app/components/ui/skeleton.tsx +13 -0
  61. package/src/app/components/ui/slider.tsx +63 -0
  62. package/src/app/components/ui/sonner.tsx +25 -0
  63. package/src/app/components/ui/switch.tsx +31 -0
  64. package/src/app/components/ui/table.tsx +116 -0
  65. package/src/app/components/ui/tabs.tsx +66 -0
  66. package/src/app/components/ui/textarea.tsx +18 -0
  67. package/src/app/components/ui/toggle-group.tsx +73 -0
  68. package/src/app/components/ui/toggle.tsx +47 -0
  69. package/src/app/components/ui/tooltip.tsx +61 -0
  70. package/src/app/components/ui/use-mobile.ts +21 -0
  71. package/src/app/components/ui/utils.ts +6 -0
  72. package/src/app/pages/DesignSystem.tsx +189 -0
  73. package/src/app/pages/Team.tsx +168 -0
  74. package/src/app/routes.tsx +14 -0
  75. package/src/assets/6276cd19433d265f363bddc7f52f4937da9b1dd4.png +0 -0
  76. package/src/assets/9d7a018c9a6938d439d9059f82753d232ce63804.png +0 -0
  77. package/src/imports/Buttons-3-409.tsx +46 -0
  78. package/src/imports/Buttons-3-962.tsx +155 -0
  79. package/src/imports/ButtonsAndActions.tsx +139 -0
  80. package/src/imports/Dashboard.tsx +1914 -0
  81. package/src/imports/DesignSystem.tsx +6008 -0
  82. package/src/imports/Forms.tsx +1088 -0
  83. package/src/imports/Navigation-17-3259.tsx +564 -0
  84. package/src/imports/Navigation-18-957.tsx +873 -0
  85. package/src/imports/Wireframe.tsx +112 -0
  86. package/src/imports/svg-1ifosis1tx.ts +3 -0
  87. package/src/imports/svg-5spfd.tsx +1 -0
  88. package/src/imports/svg-6180by7m37.ts +3 -0
  89. package/src/imports/svg-guy0p.tsx +1 -0
  90. package/src/imports/svg-hm2n0.tsx +2 -0
  91. package/src/imports/svg-j8o95ccqq7.ts +26 -0
  92. package/src/imports/svg-liuy2nykz3.ts +10 -0
  93. package/src/imports/svg-pp9c3.tsx +1 -0
  94. package/src/imports/svg-pr0k9194w9.ts +33 -0
  95. package/src/imports/svg-umftvfphsk.ts +48 -0
  96. package/src/imports/svg-vbi95q76mb.ts +23 -0
  97. package/src/imports/svg-vxjpl.tsx +1 -0
  98. package/src/imports/svg-wl30wxxv53.ts +3 -0
  99. package/src/main.tsx +7 -0
  100. package/src/styles/fonts.css +1 -0
  101. package/src/styles/forms.css +181 -0
  102. package/src/styles/header.css +48 -0
  103. package/src/styles/index.css +7 -0
  104. package/src/styles/navlinks.css +112 -0
  105. package/src/styles/popover.css +48 -0
  106. package/src/styles/tailwind.css +4 -0
  107. package/src/styles/theme.css +312 -0
  108. package/vite.config.ts +38 -0
@@ -0,0 +1,123 @@
1
+ import React from "react";
2
+ import svgPaths from "../../../imports/svg-umftvfphsk";
3
+ import { SectionHeader } from "./SectionHeader";
4
+ import { CopyButton } from "./CopyButton";
5
+
6
+ export function Cards() {
7
+ return (
8
+ <section>
9
+ <SectionHeader
10
+ title="Cards"
11
+ description="Card containers used for grouping related content"
12
+ />
13
+
14
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
15
+ {/* Basic Card */}
16
+ <div>
17
+ <p className="font-['Source_Sans_3',sans-serif] text-xs text-muted-foreground uppercase tracking-wider mb-3">
18
+ Basic Card
19
+ </p>
20
+ <div className="group/card bg-card rounded-xl p-8 relative">
21
+ <div className="absolute top-2 right-2 opacity-0 group-hover/card:opacity-100 transition-opacity">
22
+ <CopyButton token="bg-card rounded-xl p-8" />
23
+ </div>
24
+ <p className="font-['Source_Sans_3',sans-serif] text-lg text-foreground uppercase" style={{ fontWeight: 300 }}>
25
+ Card Title
26
+ </p>
27
+ <div className="h-5" />
28
+ <p className="font-['Source_Sans_3',sans-serif] text-sm text-muted-foreground">
29
+ Card content goes here. Uses background #1D1D1D with 15px border radius and 30px padding.
30
+ </p>
31
+ </div>
32
+ </div>
33
+
34
+ {/* Card with Header */}
35
+ <div>
36
+ <p className="font-['Source_Sans_3',sans-serif] text-xs text-muted-foreground uppercase tracking-wider mb-3">
37
+ Session Details Card
38
+ </p>
39
+ <div className="group/card bg-card rounded-xl p-8 relative">
40
+ <div className="absolute top-2 right-12 opacity-0 group-hover/card:opacity-100 transition-opacity z-10">
41
+ <CopyButton token="bg-card rounded-xl p-8 | header: text-lg uppercase | title: text-2xl" />
42
+ </div>
43
+ <div className="flex items-start justify-between">
44
+ <div>
45
+ <p className="font-['Source_Sans_3',sans-serif] text-lg text-foreground uppercase" style={{ fontWeight: 300 }}>
46
+ Session Details
47
+ </p>
48
+ <div className="h-1" />
49
+ <p className="font-['Source_Sans_3',sans-serif] text-2xl text-foreground" style={{ fontWeight: 300 }}>
50
+ Test session title
51
+ </p>
52
+ </div>
53
+ <button className="btn-icon">
54
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none">
55
+ <path d={svgPaths.p5e64f80} fill="currentColor" />
56
+ </svg>
57
+ </button>
58
+ </div>
59
+ <div className="h-4" />
60
+ <div className="flex flex-wrap gap-x-12 gap-y-2 text-muted-foreground">
61
+ <div className="flex gap-5 items-center">
62
+ <span className="font-['Source_Sans_3',sans-serif] text-xs uppercase" style={{ fontWeight: 600 }}>Created on:</span>
63
+ <span className="font-['Source_Sans_3',sans-serif] text-base">2025-07-23 19:11</span>
64
+ </div>
65
+ <div className="flex gap-5 items-center">
66
+ <span className="font-['Source_Sans_3',sans-serif] text-xs uppercase" style={{ fontWeight: 600 }}>Status:</span>
67
+ <span className="font-['Source_Sans_3',sans-serif] text-base text-foreground">draft</span>
68
+ </div>
69
+ </div>
70
+ </div>
71
+ </div>
72
+ </div>
73
+
74
+ {/* XL Buttons */}
75
+ <div className="mt-8">
76
+ <p className="font-['Source_Sans_3',sans-serif] text-xs text-muted-foreground uppercase tracking-wider mb-3">
77
+ XL Buttons
78
+ </p>
79
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
80
+ {/* Create New Session Card */}
81
+ <div className="group/card relative">
82
+ <button className="btn-xl-outline w-full">
83
+ <div className="pb-4">
84
+ <svg width="60" height="60" viewBox="0 0 60 60" fill="none">
85
+ <g clipPath="url(#clip_plus_action)">
86
+ <path d={svgPaths.p2455100} fill="currentColor" />
87
+ </g>
88
+ <defs>
89
+ <clipPath id="clip_plus_action"><rect fill="white" height="60" width="60" /></clipPath>
90
+ </defs>
91
+ </svg>
92
+ </div>
93
+ <span>Create New Test Session</span>
94
+ </button>
95
+ <div className="absolute top-2 right-2 opacity-0 group-hover/card:opacity-100 transition-opacity z-10">
96
+ <CopyButton token="btn-xl-outline" />
97
+ </div>
98
+ </div>
99
+
100
+ {/* Placeholder for other action cards */}
101
+ <div className="group/card relative">
102
+ <button className="btn-xl-filled w-full">
103
+ <div className="pb-4">
104
+ <svg width="60" height="60" viewBox="0 0 60 60" fill="none">
105
+ <g clipPath="url(#clip_test_action)">
106
+ <path d={svgPaths.p2af2dd00} fill="currentColor" />
107
+ </g>
108
+ <defs>
109
+ <clipPath id="clip_test_action"><rect fill="white" height="60" width="60" /></clipPath>
110
+ </defs>
111
+ </svg>
112
+ </div>
113
+ <span>Start test</span>
114
+ </button>
115
+ <div className="absolute top-2 right-2 opacity-0 group-hover/card:opacity-100 transition-opacity z-10">
116
+ <CopyButton token="btn-xl-filled" />
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </div>
121
+ </section>
122
+ );
123
+ }
@@ -0,0 +1,135 @@
1
+ import React from "react";
2
+ import svgPaths from "../../../imports/svg-umftvfphsk";
3
+ import { SectionHeader } from "./SectionHeader";
4
+ import { CopyButton } from "./CopyButton";
5
+
6
+ export function Charts() {
7
+ return (
8
+ <section>
9
+ <SectionHeader
10
+ title="Charts & Data Visualization"
11
+ description="Donut charts, line charts, and data nodes"
12
+ />
13
+
14
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
15
+ {/* Donut Chart */}
16
+ <div>
17
+ <p className="font-['Source_Sans_3',sans-serif] text-xs text-muted-foreground uppercase tracking-wider mb-3">
18
+ Donut Chart (Large)
19
+ </p>
20
+ <div className="group/chart bg-card rounded-xl p-8 flex flex-col items-center relative">
21
+ <div className="absolute top-2 right-2 opacity-0 group-hover/chart:opacity-100 transition-opacity z-10">
22
+ <CopyButton token="donut: 180x180 | ring: var(--secondary) | segments: var(--chart-1/2/3) | center: text-6xl" />
23
+ </div>
24
+ <div className="relative size-[180px] flex items-center justify-center">
25
+ {/* Base ring */}
26
+ <svg className="absolute inset-0" viewBox="0 0 180 180" fill="none">
27
+ <path clipRule="evenodd" d={svgPaths.p3f48ef30} fill="var(--secondary)" fillRule="evenodd" />
28
+ </svg>
29
+ {/* Color segments */}
30
+ <svg className="absolute inset-0" viewBox="0 0 180 180" fill="none">
31
+ <mask height="180" id="mask_donut_demo" maskUnits="userSpaceOnUse" style={{ maskType: "alpha" }} width="180" x="0" y="0">
32
+ <path clipRule="evenodd" d={svgPaths.p3f48ef30} fill="var(--secondary)" fillRule="evenodd" />
33
+ </mask>
34
+ <g mask="url(#mask_donut_demo)">
35
+ <rect fill="var(--chart-2)" height="90" width="90" x="90" />
36
+ <rect fill="var(--chart-3)" height="90" width="90" x="90" y="90" />
37
+ <rect fill="var(--chart-1)" height="90" width="90" y="90" />
38
+ </g>
39
+ </svg>
40
+ {/* Center content */}
41
+ <div className="relative z-10 text-center">
42
+ <p className="font-['Source_Sans_3',sans-serif] text-6xl text-foreground leading-10" style={{ fontWeight: 300 }}>999</p>
43
+ <p className="font-['Source_Sans_3',sans-serif] text-xs text-muted-foreground mt-2.5">Total check executions</p>
44
+ </div>
45
+ </div>
46
+ <div className="h-5" />
47
+ {/* Legend */}
48
+ <div className="flex gap-2.5 items-center justify-center">
49
+ {[
50
+ { color: "var(--chart-1)", label: "12 passed" },
51
+ { color: "var(--chart-2)", label: "12 failed" },
52
+ { color: "var(--chart-3)", label: "12 blocked" },
53
+ ].map((item) => (
54
+ <div key={item.label} className="flex items-center gap-1.5">
55
+ <svg width="5" height="5" viewBox="0 0 5 5" fill="none">
56
+ <circle cx="2.5" cy="2.5" r="2.5" fill={item.color} />
57
+ </svg>
58
+ <span className="font-['Source_Sans_3',sans-serif] text-xs text-muted-foreground">{item.label}</span>
59
+ </div>
60
+ ))}
61
+ </div>
62
+ </div>
63
+ </div>
64
+
65
+ {/* Line Chart Data Points */}
66
+ <div>
67
+ <p className="font-['Source_Sans_3',sans-serif] text-xs text-muted-foreground uppercase tracking-wider mb-3">
68
+ Line Chart Data Nodes
69
+ </p>
70
+ <div className="group/chart bg-card rounded-xl p-8 relative">
71
+ <div className="absolute top-2 right-2 opacity-0 group-hover/chart:opacity-100 transition-opacity z-10">
72
+ <CopyButton token="data-nodes: circle 10x10 | colors: var(--chart-1/2/3) | labels: text-xs text-muted-foreground" />
73
+ </div>
74
+ <p className="font-['Source_Sans_3',sans-serif] text-lg text-foreground uppercase mb-5" style={{ fontWeight: 300 }}>
75
+ Test Session Results
76
+ </p>
77
+ {/* Data columns */}
78
+ <div className="flex items-end justify-between px-4">
79
+ {[
80
+ { passed: 5, blocked: 3, failed: 0 },
81
+ { passed: 7, blocked: 4, failed: 2 },
82
+ { passed: 6, blocked: 4, failed: 0 },
83
+ { passed: 9, blocked: 3, failed: 2 },
84
+ { passed: 8, blocked: 3, failed: 0 },
85
+ { passed: 5, blocked: 4, failed: 0 },
86
+ { passed: 5, blocked: 4, failed: 0 },
87
+ ].map((col, i) => (
88
+ <div key={i} className="flex flex-col items-center gap-2">
89
+ <div className="flex flex-col items-center gap-1">
90
+ <span className="font-['Source_Sans_3',sans-serif] text-sm text-foreground">{col.passed}</span>
91
+ <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
92
+ <circle cx="5" cy="5" r="5" fill="var(--chart-1)" />
93
+ </svg>
94
+ </div>
95
+ <div className="flex flex-col items-center gap-1">
96
+ <span className="font-['Source_Sans_3',sans-serif] text-sm text-foreground">{col.blocked}</span>
97
+ <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
98
+ <circle cx="5" cy="5" r="5" fill="var(--chart-3)" />
99
+ </svg>
100
+ </div>
101
+ <div className="flex flex-col items-center gap-1">
102
+ <span className="font-['Source_Sans_3',sans-serif] text-sm text-foreground">{col.failed}</span>
103
+ <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
104
+ <circle cx="5" cy="5" r="5" fill="var(--chart-2)" />
105
+ </svg>
106
+ </div>
107
+ <div className="mt-2 text-center">
108
+ <p className="font-['Source_Sans_3',sans-serif] text-xs text-muted-foreground">19-09</p>
109
+ <p className="font-['Source_Sans_3',sans-serif] text-xs text-muted-foreground">10:00</p>
110
+ </div>
111
+ </div>
112
+ ))}
113
+ </div>
114
+ <div className="h-5" />
115
+ {/* Legend */}
116
+ <div className="flex gap-2.5 items-center justify-center">
117
+ {[
118
+ { color: "var(--chart-5)", label: "passed" },
119
+ { color: "var(--chart-2)", label: "failed" },
120
+ { color: "var(--chart-3)", label: "blocked" },
121
+ ].map((item) => (
122
+ <div key={item.label} className="flex items-center gap-1.5">
123
+ <svg width="5" height="5" viewBox="0 0 5 5" fill="none">
124
+ <circle cx="2.5" cy="2.5" r="2.5" fill={item.color} />
125
+ </svg>
126
+ <span className="font-['Source_Sans_3',sans-serif] text-xs text-muted-foreground">{item.label}</span>
127
+ </div>
128
+ ))}
129
+ </div>
130
+ </div>
131
+ </div>
132
+ </div>
133
+ </section>
134
+ );
135
+ }
@@ -0,0 +1,86 @@
1
+ import React from "react";
2
+ import { SectionHeader } from "./SectionHeader";
3
+ import { CopyButton } from "./CopyButton";
4
+
5
+ const colors = [
6
+ {
7
+ group: "Backgrounds",
8
+ items: [
9
+ { name: "Background", value: "#181818", css: "--background" },
10
+ { name: "Card", value: "#1D1D1D", css: "--card" },
11
+ { name: "Secondary", value: "#262626", css: "--secondary" },
12
+ { name: "Muted", value: "#2E2E2E", css: "--muted" },
13
+ ],
14
+ },
15
+ {
16
+ group: "Brand",
17
+ items: [
18
+ { name: "Primary (Teal)", value: "#78EAC1", css: "--primary" },
19
+ { name: "Accent (Purple)", value: "#7954FF", css: "--accent" },
20
+ ],
21
+ },
22
+ {
23
+ group: "Status",
24
+ items: [
25
+ { name: "Passed / Success", value: "#33BA9E", css: "--chart-1" },
26
+ { name: "Failed / Error", value: "#FF3131", css: "--destructive" },
27
+ { name: "Blocked / Warning", value: "#F48D21", css: "--chart-3" },
28
+ ],
29
+ },
30
+ {
31
+ group: "Text",
32
+ items: [
33
+ { name: "Primary Text", value: "#FFFFFF", css: "--foreground" },
34
+ { name: "Muted Text", value: "#888888", css: "--muted-foreground" },
35
+ { name: "Subtle Text", value: "#595959", css: "n/a" },
36
+ ],
37
+ },
38
+ ];
39
+
40
+ export function ColorPalette() {
41
+ return (
42
+ <section>
43
+ <SectionHeader
44
+ title="Color Palette"
45
+ description="Core colors used throughout the application"
46
+ />
47
+ <div className="space-y-8">
48
+ {colors.map((group) => (
49
+ <div key={group.group}>
50
+ <p className="font-['Source_Sans_3',sans-serif] text-[14px] text-[#888] uppercase tracking-wider mb-4">
51
+ {group.group}
52
+ </p>
53
+ <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4">
54
+ {group.items.map((color) => (
55
+ <div key={color.name} className="space-y-2">
56
+ <div
57
+ className="group/swatch h-20 rounded-[10px] border border-[#2e2e2e] relative"
58
+ style={{ backgroundColor: color.value }}
59
+ >
60
+ <div className="absolute top-1.5 right-1.5 opacity-0 group-hover/swatch:opacity-100 transition-opacity flex gap-1">
61
+ <CopyButton token={color.value} />
62
+ {color.css !== "n/a" && <CopyButton token={`var(${color.css})`} />}
63
+ </div>
64
+ </div>
65
+ <p className="font-['Source_Sans_3',sans-serif] text-[14px] text-white">
66
+ {color.name}
67
+ </p>
68
+ <div className="flex items-center gap-1.5">
69
+ <p className="font-['Source_Sans_3',sans-serif] text-[12px] text-[#888] font-mono">
70
+ {color.value}
71
+ </p>
72
+ {color.css !== "n/a" && (
73
+ <span className="font-['Source_Sans_3',sans-serif] text-[11px] text-[#555] font-mono">
74
+ {color.css}
75
+ </span>
76
+ )}
77
+ </div>
78
+ </div>
79
+ ))}
80
+ </div>
81
+ </div>
82
+ ))}
83
+ </div>
84
+ </section>
85
+ );
86
+ }
@@ -0,0 +1,102 @@
1
+ import React, { useState, useCallback } from "react";
2
+
3
+ interface CopyButtonProps {
4
+ token: string;
5
+ className?: string;
6
+ }
7
+
8
+ export function CopyButton({ token, className = "" }: CopyButtonProps) {
9
+ const [copied, setCopied] = useState(false);
10
+
11
+ const handleCopy = useCallback(
12
+ async (e: React.MouseEvent) => {
13
+ e.stopPropagation();
14
+ try {
15
+ await navigator.clipboard.writeText(token);
16
+ setCopied(true);
17
+ setTimeout(() => setCopied(false), 1500);
18
+ } catch {
19
+ // Fallback
20
+ const textarea = document.createElement("textarea");
21
+ textarea.value = token;
22
+ document.body.appendChild(textarea);
23
+ textarea.select();
24
+ document.execCommand("copy");
25
+ document.body.removeChild(textarea);
26
+ setCopied(true);
27
+ setTimeout(() => setCopied(false), 1500);
28
+ }
29
+ },
30
+ [token]
31
+ );
32
+
33
+ return (
34
+ <button
35
+ onClick={handleCopy}
36
+ title={copied ? "Copied!" : `Copy: ${token}`}
37
+ className={`inline-flex items-center justify-center size-[26px] rounded-[6px] cursor-pointer transition-all ${
38
+ copied
39
+ ? "bg-chart-1/20 text-chart-1"
40
+ : "bg-muted text-muted-foreground hover:text-foreground hover:bg-muted/80"
41
+ } ${className}`}
42
+ >
43
+ {copied ? (
44
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
45
+ <path
46
+ d="M2.5 7.5L5.5 10.5L11.5 3.5"
47
+ stroke="currentColor"
48
+ strokeWidth="1.5"
49
+ strokeLinecap="round"
50
+ strokeLinejoin="round"
51
+ />
52
+ </svg>
53
+ ) : (
54
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
55
+ <rect
56
+ x="4.5"
57
+ y="4.5"
58
+ width="7"
59
+ height="7"
60
+ rx="1.5"
61
+ stroke="currentColor"
62
+ strokeWidth="1.2"
63
+ />
64
+ <path
65
+ d="M9.5 4.5V3C9.5 2.17157 8.82843 1.5 8 1.5H3C2.17157 1.5 1.5 2.17157 1.5 3V8C1.5 8.82843 2.17157 9.5 3 9.5H4.5"
66
+ stroke="currentColor"
67
+ strokeWidth="1.2"
68
+ />
69
+ </svg>
70
+ )}
71
+ </button>
72
+ );
73
+ }
74
+
75
+ interface CopyTokenWrapperProps {
76
+ token: string;
77
+ children: React.ReactNode;
78
+ className?: string;
79
+ inline?: boolean;
80
+ }
81
+
82
+ export function CopyTokenWrapper({
83
+ token,
84
+ children,
85
+ className = "",
86
+ inline = false,
87
+ }: CopyTokenWrapperProps) {
88
+ return (
89
+ <div
90
+ className={`group/copy relative ${inline ? "inline-flex items-center" : ""} ${className}`}
91
+ >
92
+ {children}
93
+ <div
94
+ className={`opacity-0 group-hover/copy:opacity-100 transition-opacity ${
95
+ inline ? "ml-1.5" : "absolute top-1 right-1"
96
+ }`}
97
+ >
98
+ <CopyButton token={token} />
99
+ </div>
100
+ </div>
101
+ );
102
+ }