omnira-ui 0.6.5 → 0.6.6
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/cli/omnira-init.mjs +5 -0
- package/components/ui/ActivityFeed/ActivityFeed.module.css +20 -20
- package/components/ui/AgentThinking/AgentThinking.module.css +7 -0
- package/components/ui/AgentThinking/AgentThinking.tsx +27 -21
- package/components/ui/CodeSnippet/CodeSnippet.module.css +38 -18
- package/components/ui/CodeSnippet/CodeSnippet.tsx +84 -2
- package/components/ui/EmailTemplate/EmailTemplate.module.css +303 -0
- package/components/ui/EmailTemplate/EmailTemplate.tsx +298 -0
- package/components/ui/EmailTemplate/index.ts +2 -0
- package/components/ui/ForgotPassword/ForgotPassword.module.css +332 -0
- package/components/ui/ForgotPassword/ForgotPassword.tsx +387 -0
- package/components/ui/ForgotPassword/index.ts +2 -0
- package/components/ui/Messaging/Messaging.tsx +1 -1
- package/components/ui/NotFoundPage/NotFoundPage.module.css +270 -0
- package/components/ui/NotFoundPage/NotFoundPage.tsx +158 -0
- package/components/ui/NotFoundPage/index.ts +2 -0
- package/components/ui/ProgressSteps/ProgressSteps.module.css +21 -21
- package/components/ui/SlideOut/SlideOut.module.css +17 -13
- package/components/ui/VerificationPage/VerificationPage.module.css +252 -0
- package/components/ui/VerificationPage/VerificationPage.tsx +287 -0
- package/components/ui/VerificationPage/index.ts +2 -0
- package/package.json +1 -1
package/cli/omnira-init.mjs
CHANGED
|
@@ -487,6 +487,11 @@ const PAGE_BUNDLES = {
|
|
|
487
487
|
// ── Shared pages bundles ──
|
|
488
488
|
"login": ["AuthPage", "LoginSimple", "LoginSplitImage", "LoginSplitQuote", "LoginCardSeparated", "SocialButton", "Button", "Input", "Checkbox"],
|
|
489
489
|
"sign-up": ["SignUpSimple", "SignUpSplitImage", "SignUpSplitQuote", "SignUpCardSeparated", "SocialButton", "Button", "Input", "Checkbox"],
|
|
490
|
+
"verification": ["VerificationPage", "Button", "PinInput"],
|
|
491
|
+
"forgot-password": ["ForgotPassword", "Button", "Input", "Checkbox"],
|
|
492
|
+
"not-found-page": ["NotFoundPage", "Button"],
|
|
493
|
+
"404": ["NotFoundPage", "Button"],
|
|
494
|
+
"email-template": ["EmailTemplate"],
|
|
490
495
|
};
|
|
491
496
|
|
|
492
497
|
// ── Add command — copy a single component ───────────────────────────
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
background: var(--color-bg-card);
|
|
9
9
|
border: 1px solid var(--color-border-standard);
|
|
10
10
|
border-radius: var(--radius-xl);
|
|
11
|
-
padding:
|
|
11
|
+
padding: 20px;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/* ── Item ── */
|
|
15
15
|
.item {
|
|
16
16
|
display: flex;
|
|
17
|
-
gap:
|
|
17
|
+
gap: 10px;
|
|
18
18
|
position: relative;
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -32,27 +32,27 @@
|
|
|
32
32
|
flex-direction: column;
|
|
33
33
|
align-items: center;
|
|
34
34
|
flex-shrink: 0;
|
|
35
|
-
width:
|
|
35
|
+
width: 30px;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
.avatar {
|
|
39
|
-
width:
|
|
40
|
-
height:
|
|
39
|
+
width: 30px;
|
|
40
|
+
height: 30px;
|
|
41
41
|
border-radius: 50%;
|
|
42
42
|
object-fit: cover;
|
|
43
43
|
flex-shrink: 0;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
.avatarFallback {
|
|
47
|
-
width:
|
|
48
|
-
height:
|
|
47
|
+
width: 30px;
|
|
48
|
+
height: 30px;
|
|
49
49
|
border-radius: 50%;
|
|
50
50
|
background: var(--color-bg-elevated);
|
|
51
51
|
border: 1px solid var(--color-border-standard);
|
|
52
52
|
display: flex;
|
|
53
53
|
align-items: center;
|
|
54
54
|
justify-content: center;
|
|
55
|
-
font-size:
|
|
55
|
+
font-size: 11px;
|
|
56
56
|
font-weight: 600;
|
|
57
57
|
color: var(--color-text-secondary);
|
|
58
58
|
flex-shrink: 0;
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
.iconBubble {
|
|
63
|
-
width:
|
|
64
|
-
height:
|
|
63
|
+
width: 30px;
|
|
64
|
+
height: 30px;
|
|
65
65
|
border-radius: 50%;
|
|
66
66
|
background: var(--color-bg-lime-subtle);
|
|
67
67
|
display: flex;
|
|
@@ -74,20 +74,20 @@
|
|
|
74
74
|
.connector {
|
|
75
75
|
width: 2px;
|
|
76
76
|
flex: 1;
|
|
77
|
-
min-height:
|
|
77
|
+
min-height: 20px;
|
|
78
78
|
background: var(--color-border-standard);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/* ── Compact ── */
|
|
82
82
|
.compact .timeline {
|
|
83
|
-
width:
|
|
83
|
+
width: 24px;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
.compact .avatar,
|
|
87
87
|
.compact .avatarFallback,
|
|
88
88
|
.compact .iconBubble {
|
|
89
|
-
width:
|
|
90
|
-
height:
|
|
89
|
+
width: 24px;
|
|
90
|
+
height: 24px;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
.compact .avatarFallback {
|
|
@@ -95,18 +95,18 @@
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
.compact .connector {
|
|
98
|
-
min-height:
|
|
98
|
+
min-height: 12px;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/* ── Content Column ── */
|
|
102
102
|
.content {
|
|
103
103
|
flex: 1;
|
|
104
104
|
min-width: 0;
|
|
105
|
-
padding-bottom:
|
|
105
|
+
padding-bottom: 18px;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
.compact .content {
|
|
109
|
-
padding-bottom:
|
|
109
|
+
padding-bottom: 12px;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
.item:last-child .content {
|
|
@@ -122,8 +122,8 @@
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
.userName {
|
|
125
|
-
font-size:
|
|
126
|
-
font-weight:
|
|
125
|
+
font-size: 13px;
|
|
126
|
+
font-weight: 500;
|
|
127
127
|
color: var(--color-text-primary);
|
|
128
128
|
}
|
|
129
129
|
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
.body {
|
|
136
|
-
font-size:
|
|
136
|
+
font-size: 13px;
|
|
137
137
|
color: var(--color-text-secondary);
|
|
138
138
|
line-height: 1.5;
|
|
139
139
|
}
|
|
@@ -120,6 +120,8 @@
|
|
|
120
120
|
position: relative;
|
|
121
121
|
flex-shrink: 0;
|
|
122
122
|
user-select: none;
|
|
123
|
+
min-width: 160px;
|
|
124
|
+
height: 42px;
|
|
123
125
|
}
|
|
124
126
|
|
|
125
127
|
.chip:hover {
|
|
@@ -217,6 +219,10 @@
|
|
|
217
219
|
min-width: 0;
|
|
218
220
|
position: relative;
|
|
219
221
|
z-index: 1;
|
|
222
|
+
flex: 1;
|
|
223
|
+
overflow: hidden;
|
|
224
|
+
height: 28px;
|
|
225
|
+
justify-content: center;
|
|
220
226
|
}
|
|
221
227
|
|
|
222
228
|
.chipName {
|
|
@@ -257,6 +263,7 @@
|
|
|
257
263
|
display: flex;
|
|
258
264
|
align-items: center;
|
|
259
265
|
gap: 0;
|
|
266
|
+
height: 14px;
|
|
260
267
|
}
|
|
261
268
|
|
|
262
269
|
.cursor {
|
|
@@ -7,33 +7,39 @@ import type { AgentConfig, AgentActivity, AgentState } from "./types";
|
|
|
7
7
|
import s from "./AgentThinking.module.css";
|
|
8
8
|
|
|
9
9
|
/* ══════════════════════════════════════════════
|
|
10
|
-
|
|
10
|
+
Text cycling hook — fixed-size status rotation
|
|
11
11
|
══════════════════════════════════════════════ */
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const STATUS_PHRASES = [
|
|
14
|
+
"Analyzing...",
|
|
15
|
+
"Taking action...",
|
|
16
|
+
"Sending emails...",
|
|
17
|
+
"On a phone call...",
|
|
18
|
+
"Reflecting...",
|
|
19
|
+
"Processing data...",
|
|
20
|
+
"Searching...",
|
|
21
|
+
"Composing response...",
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
function useTextCycler(text: string, isActive: boolean, intervalMs = 2400) {
|
|
25
|
+
const [displayed, setDisplayed] = useState(text || STATUS_PHRASES[0]);
|
|
26
|
+
const idxRef = useRef(0);
|
|
16
27
|
|
|
17
28
|
useEffect(() => {
|
|
18
|
-
if (!isActive
|
|
29
|
+
if (!isActive) {
|
|
19
30
|
setDisplayed("");
|
|
20
|
-
indexRef.current = 0;
|
|
21
31
|
return;
|
|
22
32
|
}
|
|
23
|
-
setDisplayed(
|
|
24
|
-
|
|
33
|
+
setDisplayed(text || STATUS_PHRASES[0]);
|
|
34
|
+
idxRef.current = 0;
|
|
25
35
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
} else {
|
|
31
|
-
clearInterval(interval);
|
|
32
|
-
}
|
|
33
|
-
}, speed);
|
|
36
|
+
const timer = setInterval(() => {
|
|
37
|
+
idxRef.current = (idxRef.current + 1) % STATUS_PHRASES.length;
|
|
38
|
+
setDisplayed(STATUS_PHRASES[idxRef.current]);
|
|
39
|
+
}, intervalMs);
|
|
34
40
|
|
|
35
|
-
return () => clearInterval(
|
|
36
|
-
}, [text, isActive,
|
|
41
|
+
return () => clearInterval(timer);
|
|
42
|
+
}, [text, isActive, intervalMs]);
|
|
37
43
|
|
|
38
44
|
return displayed;
|
|
39
45
|
}
|
|
@@ -101,10 +107,10 @@ interface AgentChipProps {
|
|
|
101
107
|
|
|
102
108
|
function AgentChip({ agent, activity, isPopoverOpen, onTogglePopover }: AgentChipProps) {
|
|
103
109
|
const isAnimating = activity.state === "thinking" || activity.state === "active";
|
|
104
|
-
const
|
|
110
|
+
const statusText = useTextCycler(
|
|
105
111
|
activity.currentAction?.text ?? "",
|
|
106
112
|
isAnimating,
|
|
107
|
-
|
|
113
|
+
2400
|
|
108
114
|
);
|
|
109
115
|
|
|
110
116
|
const chipStyle: React.CSSProperties = {
|
|
@@ -158,7 +164,7 @@ function AgentChip({ agent, activity, isPopoverOpen, onTogglePopover }: AgentChi
|
|
|
158
164
|
</span>
|
|
159
165
|
{isAnimating ? (
|
|
160
166
|
<span className={s.activityText}>
|
|
161
|
-
{
|
|
167
|
+
{statusText}
|
|
162
168
|
<span className={s.cursor} style={{ background: agent.color }} />
|
|
163
169
|
</span>
|
|
164
170
|
) : activity.state === "completed" ? (
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
.wrapper {
|
|
6
6
|
border-radius: var(--radius-xl);
|
|
7
7
|
border: 1px solid var(--color-border-subtle);
|
|
8
|
-
background:
|
|
8
|
+
background: #0d1117;
|
|
9
9
|
overflow: hidden;
|
|
10
10
|
font-family: "SF Mono", "Fira Code", "Fira Mono", Menlo, Consolas, monospace;
|
|
11
11
|
}
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
align-items: center;
|
|
18
18
|
justify-content: space-between;
|
|
19
19
|
padding: 10px 16px;
|
|
20
|
-
border-bottom: 1px solid
|
|
21
|
-
background:
|
|
20
|
+
border-bottom: 1px solid rgba(255,255,255,0.06);
|
|
21
|
+
background: #0a0e14;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
.headerLeft {
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
overflow-x: auto;
|
|
78
78
|
font-size: 13px;
|
|
79
79
|
line-height: 1.65;
|
|
80
|
-
color:
|
|
80
|
+
color: #c9d1d9;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
.table {
|
|
@@ -95,8 +95,8 @@
|
|
|
95
95
|
text-align: right;
|
|
96
96
|
padding-right: 16px;
|
|
97
97
|
user-select: none;
|
|
98
|
-
color:
|
|
99
|
-
opacity:
|
|
98
|
+
color: #484f58;
|
|
99
|
+
opacity: 1;
|
|
100
100
|
font-size: 12px;
|
|
101
101
|
min-width: 32px;
|
|
102
102
|
vertical-align: top;
|
|
@@ -116,43 +116,63 @@
|
|
|
116
116
|
padding: 0;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
/* ── Syntax colors ── */
|
|
119
|
+
/* ── Syntax colors (GitHub Dark-inspired) ── */
|
|
120
120
|
|
|
121
121
|
.tokenKeyword {
|
|
122
|
-
color:
|
|
123
|
-
font-weight:
|
|
122
|
+
color: #ff7b72;
|
|
123
|
+
font-weight: 500;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
.tokenString {
|
|
127
|
-
color:
|
|
127
|
+
color: #a5d6ff;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
.tokenComment {
|
|
131
|
-
color:
|
|
131
|
+
color: #8b949e;
|
|
132
132
|
font-style: italic;
|
|
133
|
-
opacity: 0.7;
|
|
134
133
|
}
|
|
135
134
|
|
|
136
135
|
.tokenFunction {
|
|
137
|
-
color:
|
|
136
|
+
color: #d2a8ff;
|
|
138
137
|
}
|
|
139
138
|
|
|
140
139
|
.tokenNumber {
|
|
141
|
-
color:
|
|
140
|
+
color: #79c0ff;
|
|
142
141
|
}
|
|
143
142
|
|
|
144
143
|
.tokenPunctuation {
|
|
145
|
-
color:
|
|
144
|
+
color: #8b949e;
|
|
146
145
|
}
|
|
147
146
|
|
|
148
147
|
.tokenTag {
|
|
149
|
-
color:
|
|
148
|
+
color: #7ee787;
|
|
150
149
|
}
|
|
151
150
|
|
|
152
151
|
.tokenAttr {
|
|
153
|
-
color:
|
|
152
|
+
color: #79c0ff;
|
|
154
153
|
}
|
|
155
154
|
|
|
156
155
|
.tokenAttrValue {
|
|
157
|
-
color:
|
|
156
|
+
color: #a5d6ff;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.tokenType {
|
|
160
|
+
color: #ffa657;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.tokenOperator {
|
|
164
|
+
color: #ff7b72;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.tokenProperty {
|
|
168
|
+
color: #79c0ff;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.tokenConst {
|
|
172
|
+
color: #79c0ff;
|
|
173
|
+
font-weight: 500;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.tokenBool {
|
|
177
|
+
color: #79c0ff;
|
|
158
178
|
}
|
|
@@ -26,6 +26,86 @@ export interface CodeSnippetProps {
|
|
|
26
26
|
className?: string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/* ══════════════════════════════════════════════
|
|
30
|
+
Simple syntax tokenizer
|
|
31
|
+
══════════════════════════════════════════════ */
|
|
32
|
+
|
|
33
|
+
interface Token {
|
|
34
|
+
type: string;
|
|
35
|
+
value: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const KEYWORDS = new Set([
|
|
39
|
+
"import", "export", "from", "const", "let", "var", "function", "return",
|
|
40
|
+
"if", "else", "for", "while", "do", "switch", "case", "break", "continue",
|
|
41
|
+
"class", "extends", "new", "this", "super", "typeof", "instanceof",
|
|
42
|
+
"try", "catch", "finally", "throw", "async", "await", "yield",
|
|
43
|
+
"default", "interface", "type", "enum", "implements", "package",
|
|
44
|
+
"private", "protected", "public", "static", "void", "null", "undefined",
|
|
45
|
+
"def", "print", "elif", "except", "raise", "with", "as", "pass", "lambda",
|
|
46
|
+
"in", "not", "and", "or", "is", "None", "self", "cls",
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
const TYPES = new Set([
|
|
50
|
+
"string", "number", "boolean", "any", "object", "Array", "Promise",
|
|
51
|
+
"Record", "Map", "Set", "React", "HTMLElement", "void",
|
|
52
|
+
"int", "float", "str", "list", "dict", "tuple", "bool",
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
const BOOLEANS = new Set(["true", "false", "True", "False"]);
|
|
56
|
+
|
|
57
|
+
function tokenizeLine(line: string): Token[] {
|
|
58
|
+
const tokens: Token[] = [];
|
|
59
|
+
const regex = /(\/\/.*$|\/\*[\s\S]*?\*\/|#.*$)|("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`)|(\b\d+\.?\d*\b)|(=>|===?|!==?|<=?|>=?|&&|\|\||[+\-*/%]=?|\.\.\.)|(\b[A-Z][a-zA-Z0-9]*\b)|(\b[a-zA-Z_$][a-zA-Z0-9_$]*(?=\s*\())|(\b[a-zA-Z_$][a-zA-Z0-9_$]*\b)|([{}()\[\];:,.])|([^\S]+)|(.)/g;
|
|
60
|
+
let match;
|
|
61
|
+
while ((match = regex.exec(line)) !== null) {
|
|
62
|
+
const [full, comment, str, num, op, pascalCase, fn, word, punct, ws, other] = match;
|
|
63
|
+
if (comment) tokens.push({ type: "comment", value: comment });
|
|
64
|
+
else if (str) tokens.push({ type: "string", value: str });
|
|
65
|
+
else if (num) tokens.push({ type: "number", value: num });
|
|
66
|
+
else if (op) tokens.push({ type: "operator", value: op });
|
|
67
|
+
else if (pascalCase) {
|
|
68
|
+
if (TYPES.has(pascalCase)) tokens.push({ type: "type", value: pascalCase });
|
|
69
|
+
else tokens.push({ type: "type", value: pascalCase });
|
|
70
|
+
}
|
|
71
|
+
else if (fn) {
|
|
72
|
+
if (KEYWORDS.has(fn)) tokens.push({ type: "keyword", value: fn });
|
|
73
|
+
else tokens.push({ type: "function", value: fn });
|
|
74
|
+
}
|
|
75
|
+
else if (word) {
|
|
76
|
+
if (KEYWORDS.has(word)) tokens.push({ type: "keyword", value: word });
|
|
77
|
+
else if (BOOLEANS.has(word)) tokens.push({ type: "bool", value: word });
|
|
78
|
+
else if (TYPES.has(word)) tokens.push({ type: "type", value: word });
|
|
79
|
+
else tokens.push({ type: "plain", value: word });
|
|
80
|
+
}
|
|
81
|
+
else if (punct) tokens.push({ type: "punctuation", value: punct });
|
|
82
|
+
else tokens.push({ type: "plain", value: full });
|
|
83
|
+
}
|
|
84
|
+
return tokens;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const TOKEN_CLASS_MAP: Record<string, string> = {
|
|
88
|
+
keyword: s.tokenKeyword,
|
|
89
|
+
string: s.tokenString,
|
|
90
|
+
comment: s.tokenComment,
|
|
91
|
+
function: s.tokenFunction,
|
|
92
|
+
number: s.tokenNumber,
|
|
93
|
+
punctuation: s.tokenPunctuation,
|
|
94
|
+
type: s.tokenType,
|
|
95
|
+
operator: s.tokenOperator,
|
|
96
|
+
bool: s.tokenBool,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
function renderTokenizedLine(line: string, lineIdx: number) {
|
|
100
|
+
if (!line) return "\n";
|
|
101
|
+
const tokens = tokenizeLine(line);
|
|
102
|
+
return tokens.map((tok, i) => {
|
|
103
|
+
const cls = TOKEN_CLASS_MAP[tok.type];
|
|
104
|
+
if (cls) return <span key={`${lineIdx}-${i}`} className={cls}>{tok.value}</span>;
|
|
105
|
+
return <React.Fragment key={`${lineIdx}-${i}`}>{tok.value}</React.Fragment>;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
29
109
|
/* ══════════════════════════════════════════════
|
|
30
110
|
CodeSnippet
|
|
31
111
|
══════════════════════════════════════════════ */
|
|
@@ -92,13 +172,15 @@ export function CodeSnippet({
|
|
|
92
172
|
{i + 1}
|
|
93
173
|
</span>
|
|
94
174
|
<span className={s.lineContent} role="cell">
|
|
95
|
-
{line
|
|
175
|
+
{renderTokenizedLine(line, i)}
|
|
96
176
|
</span>
|
|
97
177
|
</div>
|
|
98
178
|
))}
|
|
99
179
|
</div>
|
|
100
180
|
) : (
|
|
101
|
-
<pre className={s.codeBlock}>{
|
|
181
|
+
<pre className={s.codeBlock}>{lines.map((line, i) => (
|
|
182
|
+
<React.Fragment key={i}>{renderTokenizedLine(line, i)}{"\n"}</React.Fragment>
|
|
183
|
+
))}</pre>
|
|
102
184
|
)}
|
|
103
185
|
</div>
|
|
104
186
|
</div>
|