omnira-ui 0.1.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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +145 -0
  3. package/cli/omnira-init.mjs +260 -0
  4. package/cli/presets.mjs +386 -0
  5. package/components/ui/AppStoreButton/AppStoreButton.module.css +87 -0
  6. package/components/ui/AppStoreButton/AppStoreButton.tsx +114 -0
  7. package/components/ui/AppStoreButton/index.ts +2 -0
  8. package/components/ui/Avatar/Avatar.module.css +76 -0
  9. package/components/ui/Avatar/Avatar.tsx +102 -0
  10. package/components/ui/Avatar/index.ts +2 -0
  11. package/components/ui/Badge/Badge.module.css +120 -0
  12. package/components/ui/Badge/Badge.tsx +25 -0
  13. package/components/ui/Badge/index.ts +2 -0
  14. package/components/ui/BadgeGroup/BadgeGroup.module.css +214 -0
  15. package/components/ui/BadgeGroup/BadgeGroup.tsx +88 -0
  16. package/components/ui/BadgeGroup/index.ts +2 -0
  17. package/components/ui/Browser/Browser.module.css +105 -0
  18. package/components/ui/Browser/Browser.tsx +54 -0
  19. package/components/ui/Browser/index.ts +2 -0
  20. package/components/ui/Button/Button.module.css +188 -0
  21. package/components/ui/Button/Button.tsx +74 -0
  22. package/components/ui/Button/index.ts +2 -0
  23. package/components/ui/ButtonUtility/ButtonUtility.module.css +154 -0
  24. package/components/ui/ButtonUtility/ButtonUtility.tsx +65 -0
  25. package/components/ui/ButtonUtility/index.ts +2 -0
  26. package/components/ui/Card/Card.module.css +80 -0
  27. package/components/ui/Card/Card.tsx +39 -0
  28. package/components/ui/Card/index.ts +2 -0
  29. package/components/ui/Checkbox/Checkbox.module.css +92 -0
  30. package/components/ui/Checkbox/Checkbox.tsx +95 -0
  31. package/components/ui/Checkbox/index.ts +2 -0
  32. package/components/ui/Collapse/Collapse.module.css +60 -0
  33. package/components/ui/Collapse/Collapse.tsx +100 -0
  34. package/components/ui/Collapse/index.ts +2 -0
  35. package/components/ui/CreditCard/CreditCard.module.css +117 -0
  36. package/components/ui/CreditCard/CreditCard.tsx +86 -0
  37. package/components/ui/CreditCard/index.ts +2 -0
  38. package/components/ui/Dropdown/Dropdown.module.css +269 -0
  39. package/components/ui/Dropdown/Dropdown.tsx +419 -0
  40. package/components/ui/Dropdown/index.ts +31 -0
  41. package/components/ui/GridLines/GridLines.module.css +95 -0
  42. package/components/ui/GridLines/GridLines.tsx +10 -0
  43. package/components/ui/GridLines/index.ts +1 -0
  44. package/components/ui/Illustration/Illustration.module.css +10 -0
  45. package/components/ui/Illustration/Illustration.tsx +96 -0
  46. package/components/ui/Illustration/index.ts +2 -0
  47. package/components/ui/Input/Input.module.css +217 -0
  48. package/components/ui/Input/Input.tsx +93 -0
  49. package/components/ui/Input/index.ts +2 -0
  50. package/components/ui/Phone/Phone.module.css +104 -0
  51. package/components/ui/Phone/Phone.tsx +54 -0
  52. package/components/ui/Phone/index.ts +2 -0
  53. package/components/ui/PinInput/PinInput.module.css +104 -0
  54. package/components/ui/PinInput/PinInput.tsx +210 -0
  55. package/components/ui/PinInput/index.ts +1 -0
  56. package/components/ui/ProgressBar/ProgressBar.module.css +180 -0
  57. package/components/ui/ProgressBar/ProgressBar.tsx +206 -0
  58. package/components/ui/ProgressBar/index.ts +2 -0
  59. package/components/ui/QRCode/QRCode.module.css +13 -0
  60. package/components/ui/QRCode/QRCode.tsx +128 -0
  61. package/components/ui/QRCode/index.ts +2 -0
  62. package/components/ui/RadioButton/RadioButton.module.css +92 -0
  63. package/components/ui/RadioButton/RadioButton.tsx +134 -0
  64. package/components/ui/RadioButton/index.ts +2 -0
  65. package/components/ui/RadioGroup/RadioGroup.module.css +382 -0
  66. package/components/ui/RadioGroup/RadioGroup.tsx +292 -0
  67. package/components/ui/RadioGroup/index.ts +1 -0
  68. package/components/ui/Rating/Rating.module.css +99 -0
  69. package/components/ui/Rating/Rating.tsx +123 -0
  70. package/components/ui/Rating/index.ts +2 -0
  71. package/components/ui/Select/Select.module.css +371 -0
  72. package/components/ui/Select/Select.tsx +507 -0
  73. package/components/ui/Select/index.ts +2 -0
  74. package/components/ui/SidebarNavigation/SidebarDual.tsx +71 -0
  75. package/components/ui/SidebarNavigation/SidebarFeatureCard.module.css +351 -0
  76. package/components/ui/SidebarNavigation/SidebarFeatureCard.tsx +388 -0
  77. package/components/ui/SidebarNavigation/SidebarNavigation.module.css +610 -0
  78. package/components/ui/SidebarNavigation/SidebarParts.tsx +215 -0
  79. package/components/ui/SidebarNavigation/SidebarSectionDividers.tsx +46 -0
  80. package/components/ui/SidebarNavigation/SidebarSectionHeadings.tsx +52 -0
  81. package/components/ui/SidebarNavigation/SidebarSimple.tsx +46 -0
  82. package/components/ui/SidebarNavigation/SidebarSlim.tsx +48 -0
  83. package/components/ui/SidebarNavigation/index.ts +29 -0
  84. package/components/ui/SidebarNavigation/types.ts +27 -0
  85. package/components/ui/Slider/Slider.module.css +93 -0
  86. package/components/ui/Slider/Slider.tsx +118 -0
  87. package/components/ui/Slider/index.ts +2 -0
  88. package/components/ui/SocialButton/SocialButton.module.css +223 -0
  89. package/components/ui/SocialButton/SocialButton.tsx +185 -0
  90. package/components/ui/SocialButton/index.ts +2 -0
  91. package/components/ui/Tag/Tag.module.css +203 -0
  92. package/components/ui/Tag/Tag.tsx +161 -0
  93. package/components/ui/Tag/index.ts +2 -0
  94. package/components/ui/TextEditor/TextEditor.module.css +182 -0
  95. package/components/ui/TextEditor/TextEditor.tsx +323 -0
  96. package/components/ui/TextEditor/index.ts +1 -0
  97. package/components/ui/Textarea/Textarea.module.css +75 -0
  98. package/components/ui/Textarea/Textarea.tsx +59 -0
  99. package/components/ui/Textarea/index.ts +2 -0
  100. package/components/ui/Toggle/Toggle.module.css +118 -0
  101. package/components/ui/Toggle/Toggle.tsx +77 -0
  102. package/components/ui/Toggle/index.ts +2 -0
  103. package/components/ui/Tooltip/Tooltip.module.css +95 -0
  104. package/components/ui/Tooltip/Tooltip.tsx +55 -0
  105. package/components/ui/Tooltip/index.ts +2 -0
  106. package/components/ui/VideoPlayer/VideoPlayer.module.css +120 -0
  107. package/components/ui/VideoPlayer/VideoPlayer.tsx +229 -0
  108. package/components/ui/VideoPlayer/index.ts +2 -0
  109. package/lib/cn.ts +3 -0
  110. package/lib/copy-to-clipboard.ts +21 -0
  111. package/package.json +61 -0
@@ -0,0 +1,102 @@
1
+ "use client";
2
+
3
+ import { useState, forwardRef } from "react";
4
+ import { cn } from "@/lib/cn";
5
+ import styles from "./Avatar.module.css";
6
+
7
+ export interface AvatarProps {
8
+ src?: string;
9
+ alt?: string;
10
+ fallback?: string;
11
+ size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
12
+ shape?: "circle" | "rounded";
13
+ status?: "online" | "offline" | "away" | "busy";
14
+ className?: string;
15
+ }
16
+
17
+ export const Avatar = forwardRef<HTMLDivElement, AvatarProps>(
18
+ (
19
+ {
20
+ src,
21
+ alt = "",
22
+ fallback,
23
+ size = "md",
24
+ shape = "circle",
25
+ status,
26
+ className,
27
+ },
28
+ ref,
29
+ ) => {
30
+ const [imgError, setImgError] = useState(false);
31
+
32
+ const initials = fallback
33
+ ? fallback
34
+ : alt
35
+ ? alt
36
+ .split(" ")
37
+ .map((w) => w[0])
38
+ .join("")
39
+ .slice(0, 2)
40
+ .toUpperCase()
41
+ : "?";
42
+
43
+ return (
44
+ <div
45
+ ref={ref}
46
+ className={cn(
47
+ styles.avatar,
48
+ styles[`avatar_${size}`],
49
+ styles[`avatar_${shape}`],
50
+ className,
51
+ )}
52
+ >
53
+ {src && !imgError ? (
54
+ <img
55
+ src={src}
56
+ alt={alt}
57
+ className={styles.img}
58
+ onError={() => setImgError(true)}
59
+ />
60
+ ) : (
61
+ <span className={styles.fallback}>{initials}</span>
62
+ )}
63
+ {status && (
64
+ <span
65
+ className={cn(
66
+ styles.status,
67
+ styles[`status_${status}`],
68
+ styles[`statusPos_${size}`],
69
+ )}
70
+ />
71
+ )}
72
+ </div>
73
+ );
74
+ },
75
+ );
76
+
77
+ Avatar.displayName = "Avatar";
78
+
79
+ /* ── Avatar Group ── */
80
+ export interface AvatarGroupProps {
81
+ children: React.ReactNode;
82
+ max?: number;
83
+ size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
84
+ className?: string;
85
+ }
86
+
87
+ export function AvatarGroup({ children, max, size = "md", className }: AvatarGroupProps) {
88
+ const items = Array.isArray(children) ? children : [children];
89
+ const visible = max ? items.slice(0, max) : items;
90
+ const remaining = max ? items.length - max : 0;
91
+
92
+ return (
93
+ <div className={cn(styles.group, className)}>
94
+ {visible}
95
+ {remaining > 0 && (
96
+ <div className={cn(styles.avatar, styles[`avatar_${size}`], styles.avatar_circle, styles.overflow)}>
97
+ <span className={styles.fallback}>+{remaining}</span>
98
+ </div>
99
+ )}
100
+ </div>
101
+ );
102
+ }
@@ -0,0 +1,2 @@
1
+ export { Avatar, AvatarGroup } from "./Avatar";
2
+ export type { AvatarProps, AvatarGroupProps } from "./Avatar";
@@ -0,0 +1,120 @@
1
+ .badge {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ gap: 6px;
5
+ font-family: inherit;
6
+ white-space: nowrap;
7
+ transition: all 0.2s;
8
+ }
9
+
10
+ /* Variants */
11
+ .section {
12
+ padding: 6px 16px;
13
+ border-radius: var(--radius-full);
14
+ background: var(--color-bg-hover);
15
+ border: 1.5px solid var(--color-border-medium);
16
+ font-size: 12px;
17
+ font-weight: 600;
18
+ text-transform: uppercase;
19
+ letter-spacing: 0.05em;
20
+ color: var(--color-text-tertiary);
21
+ }
22
+
23
+ .accent {
24
+ padding: 6px 18px;
25
+ border-radius: var(--radius-full);
26
+ font-size: 12px;
27
+ font-weight: 700;
28
+ text-transform: uppercase;
29
+ letter-spacing: 0.06em;
30
+ color: var(--color-lime);
31
+ background: var(--color-bg-lime-medium);
32
+ border: 1px solid var(--color-border-lime-medium);
33
+ }
34
+
35
+ .success {
36
+ padding: 4px 12px;
37
+ border-radius: var(--radius-full);
38
+ font-size: 12px;
39
+ font-weight: 600;
40
+ color: var(--color-success);
41
+ background: var(--color-success-bg);
42
+ border: 1px solid var(--color-success-border);
43
+ }
44
+
45
+ .error {
46
+ padding: 4px 12px;
47
+ border-radius: var(--radius-full);
48
+ font-size: 12px;
49
+ font-weight: 600;
50
+ color: var(--color-error);
51
+ background: var(--color-error-bg);
52
+ border: 1px solid var(--color-error-border);
53
+ }
54
+
55
+ .warning {
56
+ padding: 4px 12px;
57
+ border-radius: var(--radius-full);
58
+ font-size: 12px;
59
+ font-weight: 600;
60
+ color: var(--color-warning);
61
+ background: var(--color-warning-bg);
62
+ border: 1px solid var(--color-warning-border);
63
+ }
64
+
65
+ .info {
66
+ padding: 4px 12px;
67
+ border-radius: var(--radius-full);
68
+ font-size: 12px;
69
+ font-weight: 600;
70
+ color: var(--color-info);
71
+ background: var(--color-info-bg);
72
+ border: 1px solid var(--color-info-border);
73
+ }
74
+
75
+ /* Sizes */
76
+ .sm {
77
+ font-size: 10px;
78
+ padding: 2px 8px;
79
+ }
80
+
81
+ .md {
82
+ font-size: 12px;
83
+ }
84
+
85
+ .lg {
86
+ font-size: 14px;
87
+ padding: 8px 20px;
88
+ }
89
+
90
+ /* Dot */
91
+ .dot {
92
+ width: 6px;
93
+ height: 6px;
94
+ border-radius: 50%;
95
+ flex-shrink: 0;
96
+ }
97
+
98
+ .section .dot {
99
+ background: var(--color-text-tertiary);
100
+ }
101
+
102
+ .accent .dot {
103
+ background: var(--color-lime);
104
+ }
105
+
106
+ .success .dot {
107
+ background: var(--color-success);
108
+ }
109
+
110
+ .error .dot {
111
+ background: var(--color-error);
112
+ }
113
+
114
+ .warning .dot {
115
+ background: var(--color-warning);
116
+ }
117
+
118
+ .info .dot {
119
+ background: var(--color-info);
120
+ }
@@ -0,0 +1,25 @@
1
+ import { cn } from "@/lib/cn";
2
+ import styles from "./Badge.module.css";
3
+
4
+ export interface BadgeProps {
5
+ variant?: "section" | "accent" | "success" | "error" | "warning" | "info";
6
+ size?: "sm" | "md" | "lg";
7
+ dot?: boolean;
8
+ children: React.ReactNode;
9
+ className?: string;
10
+ }
11
+
12
+ export function Badge({
13
+ variant = "section",
14
+ size = "md",
15
+ dot = false,
16
+ children,
17
+ className,
18
+ }: BadgeProps) {
19
+ return (
20
+ <span className={cn(styles.badge, styles[variant], styles[size], className)}>
21
+ {dot && <span className={styles.dot} />}
22
+ {children}
23
+ </span>
24
+ );
25
+ }
@@ -0,0 +1,2 @@
1
+ export { Badge } from "./Badge";
2
+ export type { BadgeProps } from "./Badge";
@@ -0,0 +1,214 @@
1
+ /* --- Base BadgeGroup --- */
2
+ .badgeGroup {
3
+ display: inline-flex;
4
+ align-items: center;
5
+ gap: 8px;
6
+ border-radius: var(--radius-full);
7
+ font-family: inherit;
8
+ transition: all 0.2s;
9
+ white-space: nowrap;
10
+ }
11
+
12
+ .clickable {
13
+ cursor: pointer;
14
+ }
15
+
16
+ .clickable:hover {
17
+ opacity: 0.85;
18
+ }
19
+
20
+ /* --- Sizes --- */
21
+ .size-sm {
22
+ padding: 4px 10px 4px 4px;
23
+ font-size: 12px;
24
+ line-height: 1.4;
25
+ }
26
+
27
+ .size-md {
28
+ padding: 4px 12px 4px 4px;
29
+ font-size: 13px;
30
+ line-height: 1.5;
31
+ }
32
+
33
+ .size-lg {
34
+ padding: 4px 14px 4px 4px;
35
+ font-size: 14px;
36
+ line-height: 1.5;
37
+ }
38
+
39
+ /* --- Message text --- */
40
+ .message {
41
+ font-weight: 500;
42
+ color: inherit;
43
+ }
44
+
45
+ /* --- Addon badge (inner pill) --- */
46
+ .addon {
47
+ display: inline-flex;
48
+ align-items: center;
49
+ gap: 4px;
50
+ padding: 2px 10px;
51
+ border-radius: var(--radius-full);
52
+ font-size: 12px;
53
+ font-weight: 600;
54
+ white-space: nowrap;
55
+ }
56
+
57
+ .addonIcon {
58
+ display: inline-flex;
59
+ align-items: center;
60
+ line-height: 0;
61
+ }
62
+
63
+ /* --- Theme: Modern (solid inner badge) --- */
64
+ .addon-modern {
65
+ font-weight: 600;
66
+ }
67
+
68
+ /* --- Theme: Light (lighter inner badge) --- */
69
+ .addon-light {
70
+ font-weight: 500;
71
+ }
72
+
73
+ /* ═══════════════════════════════════════════
74
+ COLOR VARIANTS — Outer container
75
+ ═══════════════════════════════════════════ */
76
+
77
+ /* Gray */
78
+ .color-gray.theme-modern {
79
+ background: var(--color-bg-hover);
80
+ border: 1px solid var(--color-border-standard);
81
+ color: var(--color-text-secondary);
82
+ }
83
+
84
+ .color-gray.theme-light {
85
+ background: var(--color-bg-hover);
86
+ border: 1px solid var(--color-border-standard);
87
+ color: var(--color-text-secondary);
88
+ }
89
+
90
+ /* Brand */
91
+ .color-brand.theme-modern {
92
+ background: var(--color-bg-lime-medium);
93
+ border: 1px solid var(--color-border-lime-medium);
94
+ color: var(--color-lime);
95
+ }
96
+
97
+ .color-brand.theme-light {
98
+ background: var(--color-bg-lime-medium);
99
+ border: 1px solid var(--color-border-lime-medium);
100
+ color: var(--color-lime);
101
+ }
102
+
103
+ /* Error */
104
+ .color-error.theme-modern {
105
+ background: var(--color-error-bg);
106
+ border: 1px solid var(--color-error-border);
107
+ color: var(--color-error);
108
+ }
109
+
110
+ .color-error.theme-light {
111
+ background: var(--color-error-bg);
112
+ border: 1px solid var(--color-error-border);
113
+ color: var(--color-error);
114
+ }
115
+
116
+ /* Warning */
117
+ .color-warning.theme-modern {
118
+ background: var(--color-warning-bg);
119
+ border: 1px solid var(--color-warning-border);
120
+ color: var(--color-warning);
121
+ }
122
+
123
+ .color-warning.theme-light {
124
+ background: var(--color-warning-bg);
125
+ border: 1px solid var(--color-warning-border);
126
+ color: var(--color-warning);
127
+ }
128
+
129
+ /* Success */
130
+ .color-success.theme-modern {
131
+ background: var(--color-success-bg);
132
+ border: 1px solid var(--color-success-border);
133
+ color: var(--color-success);
134
+ }
135
+
136
+ .color-success.theme-light {
137
+ background: var(--color-success-bg);
138
+ border: 1px solid var(--color-success-border);
139
+ color: var(--color-success);
140
+ }
141
+
142
+ /* ═══════════════════════════════════════════
143
+ COLOR VARIANTS — Inner addon badge
144
+ ═══════════════════════════════════════════ */
145
+
146
+ /* Gray — Modern: solid dark badge */
147
+ .addon-gray.addon-modern {
148
+ background: var(--color-bg-elevated);
149
+ color: var(--color-text-primary);
150
+ border: 1px solid var(--color-border-medium);
151
+ }
152
+
153
+ /* Gray — Light: subtle badge */
154
+ .addon-gray.addon-light {
155
+ background: var(--color-bg-card);
156
+ color: var(--color-text-secondary);
157
+ border: 1px solid var(--color-border-standard);
158
+ }
159
+
160
+ /* Brand — Modern: solid lime badge */
161
+ .addon-brand.addon-modern {
162
+ background: var(--color-lime);
163
+ color: var(--color-lime-text);
164
+ border: 1px solid transparent;
165
+ }
166
+
167
+ /* Brand — Light: subtle lime badge */
168
+ .addon-brand.addon-light {
169
+ background: var(--color-bg-lime-medium);
170
+ color: var(--color-lime);
171
+ border: 1px solid var(--color-border-lime-medium);
172
+ }
173
+
174
+ /* Error — Modern: solid red badge */
175
+ .addon-error.addon-modern {
176
+ background: var(--color-error);
177
+ color: #fff;
178
+ border: 1px solid transparent;
179
+ }
180
+
181
+ /* Error — Light: subtle red badge */
182
+ .addon-error.addon-light {
183
+ background: var(--color-error-bg);
184
+ color: var(--color-error);
185
+ border: 1px solid var(--color-error-border);
186
+ }
187
+
188
+ /* Warning — Modern: solid amber badge */
189
+ .addon-warning.addon-modern {
190
+ background: var(--color-warning);
191
+ color: #1a1a1a;
192
+ border: 1px solid transparent;
193
+ }
194
+
195
+ /* Warning — Light: subtle amber badge */
196
+ .addon-warning.addon-light {
197
+ background: var(--color-warning-bg);
198
+ color: var(--color-warning);
199
+ border: 1px solid var(--color-warning-border);
200
+ }
201
+
202
+ /* Success — Modern: solid green badge */
203
+ .addon-success.addon-modern {
204
+ background: var(--color-success);
205
+ color: #fff;
206
+ border: 1px solid transparent;
207
+ }
208
+
209
+ /* Success — Light: subtle green badge */
210
+ .addon-success.addon-light {
211
+ background: var(--color-success-bg);
212
+ color: var(--color-success);
213
+ border: 1px solid var(--color-success-border);
214
+ }
@@ -0,0 +1,88 @@
1
+ "use client";
2
+
3
+ import { forwardRef } from "react";
4
+ import { cn } from "@/lib/cn";
5
+ import { ArrowRight2 } from "iconsax-react";
6
+ import styles from "./BadgeGroup.module.css";
7
+
8
+ export type BadgeGroupColor = "gray" | "brand" | "error" | "warning" | "success";
9
+ export type BadgeGroupTheme = "modern" | "light";
10
+ export type BadgeGroupAlign = "leading" | "trailing";
11
+ export type BadgeGroupSize = "sm" | "md" | "lg";
12
+
13
+ export interface BadgeGroupProps {
14
+ children: React.ReactNode;
15
+ addonText: string;
16
+ color?: BadgeGroupColor;
17
+ theme?: BadgeGroupTheme;
18
+ align?: BadgeGroupAlign;
19
+ size?: BadgeGroupSize;
20
+ icon?: React.ReactNode;
21
+ className?: string;
22
+ onClick?: () => void;
23
+ }
24
+
25
+ export const BadgeGroup = forwardRef<HTMLDivElement, BadgeGroupProps>(
26
+ (
27
+ {
28
+ children,
29
+ addonText,
30
+ color = "gray",
31
+ theme = "modern",
32
+ align = "leading",
33
+ size = "md",
34
+ icon,
35
+ className,
36
+ onClick,
37
+ },
38
+ ref
39
+ ) => {
40
+ const addonBadge = (
41
+ <span className={cn(styles.addon, styles[`addon-${color}`], styles[`addon-${theme}`])}>
42
+ {icon && <span className={styles.addonIcon}>{icon}</span>}
43
+ {addonText}
44
+ </span>
45
+ );
46
+
47
+ const messageText = (
48
+ <span className={styles.message}>{children}</span>
49
+ );
50
+
51
+ const arrow = (
52
+ <ArrowRight2 size={size === "sm" ? 12 : size === "md" ? 14 : 16} color="currentColor" variant="Bold" />
53
+ );
54
+
55
+ return (
56
+ <div
57
+ ref={ref}
58
+ className={cn(
59
+ styles.badgeGroup,
60
+ styles[`color-${color}`],
61
+ styles[`theme-${theme}`],
62
+ styles[`size-${size}`],
63
+ onClick && styles.clickable,
64
+ className
65
+ )}
66
+ onClick={onClick}
67
+ role={onClick ? "button" : undefined}
68
+ tabIndex={onClick ? 0 : undefined}
69
+ >
70
+ {align === "leading" ? (
71
+ <>
72
+ {addonBadge}
73
+ {messageText}
74
+ {arrow}
75
+ </>
76
+ ) : (
77
+ <>
78
+ {messageText}
79
+ {addonBadge}
80
+ {arrow}
81
+ </>
82
+ )}
83
+ </div>
84
+ );
85
+ }
86
+ );
87
+
88
+ BadgeGroup.displayName = "BadgeGroup";
@@ -0,0 +1,2 @@
1
+ export { BadgeGroup } from "./BadgeGroup";
2
+ export type { BadgeGroupProps, BadgeGroupColor, BadgeGroupTheme, BadgeGroupAlign, BadgeGroupSize } from "./BadgeGroup";
@@ -0,0 +1,105 @@
1
+ .browser {
2
+ border-radius: var(--radius-xl);
3
+ border: 1px solid var(--color-border-standard);
4
+ background: var(--color-bg-card);
5
+ overflow: hidden;
6
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12);
7
+ }
8
+
9
+ /* ── Chrome bar ── */
10
+ .chrome {
11
+ display: flex;
12
+ align-items: center;
13
+ gap: 12px;
14
+ padding: 12px 16px;
15
+ border-bottom: 1px solid var(--color-border-subtle);
16
+ background: var(--color-bg-elevated);
17
+ }
18
+
19
+ .trafficLights {
20
+ display: flex;
21
+ align-items: center;
22
+ gap: 6px;
23
+ flex-shrink: 0;
24
+ }
25
+
26
+ .dot {
27
+ width: 10px;
28
+ height: 10px;
29
+ border-radius: 50%;
30
+ }
31
+
32
+ .dotRed { background: #ff5f57; }
33
+ .dotYellow { background: #febc2e; }
34
+ .dotGreen { background: #28c840; }
35
+
36
+ .nav {
37
+ display: flex;
38
+ align-items: center;
39
+ gap: 4px;
40
+ flex-shrink: 0;
41
+ }
42
+
43
+ .navBtn {
44
+ display: flex;
45
+ align-items: center;
46
+ justify-content: center;
47
+ width: 24px;
48
+ height: 24px;
49
+ border: none;
50
+ background: none;
51
+ color: var(--color-text-tertiary);
52
+ cursor: pointer;
53
+ border-radius: var(--radius-sm);
54
+ transition: color 0.15s, background 0.15s;
55
+ }
56
+
57
+ .navBtn:hover {
58
+ color: var(--color-text-secondary);
59
+ background: var(--color-bg-hover);
60
+ }
61
+
62
+ /* ── Address bar ── */
63
+ .addressBar {
64
+ flex: 1;
65
+ display: flex;
66
+ align-items: center;
67
+ justify-content: center;
68
+ gap: 8px;
69
+ height: 32px;
70
+ padding: 0 12px;
71
+ border-radius: var(--radius-sm);
72
+ background: var(--color-bg-input);
73
+ border: 1px solid var(--color-border-subtle);
74
+ }
75
+
76
+ .addressText {
77
+ font-size: 12px;
78
+ font-weight: 500;
79
+ color: var(--color-text-secondary);
80
+ white-space: nowrap;
81
+ overflow: hidden;
82
+ text-overflow: ellipsis;
83
+ }
84
+
85
+ .copyBtn {
86
+ display: flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ background: none;
90
+ border: none;
91
+ color: var(--color-text-tertiary);
92
+ cursor: pointer;
93
+ flex-shrink: 0;
94
+ transition: color 0.15s;
95
+ }
96
+
97
+ .copyBtn:hover {
98
+ color: var(--color-text-primary);
99
+ }
100
+
101
+ /* ── Content ── */
102
+ .content {
103
+ min-height: 120px;
104
+ padding: 24px;
105
+ }