@nadicodeai/ui 12.1.132 → 12.1.134
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/dist/components/agent-orb.d.ts +8 -5
- package/dist/components/agent-orb.d.ts.map +1 -1
- package/dist/components/agent-orb.js +8 -5
- package/dist/components/avatar.d.ts +3 -3
- package/dist/components/avatar.js +3 -3
- package/dist/components/form-dialog.d.ts +8 -4
- package/dist/components/form-dialog.d.ts.map +1 -1
- package/dist/components/form-dialog.js +5 -5
- package/dist/components/identity-mark.d.ts +2 -4
- package/dist/components/identity-mark.d.ts.map +1 -1
- package/dist/components/identity-mark.js +10 -27
- package/dist/components/object-page.d.ts +4 -7
- package/dist/components/object-page.d.ts.map +1 -1
- package/dist/components/object-page.js +2 -2
- package/dist/internal/agent-orb-motion.d.ts +36 -5
- package/dist/internal/agent-orb-motion.d.ts.map +1 -1
- package/dist/internal/agent-orb-motion.js +153 -37
- package/dist/internal/agent-orb.d.ts.map +1 -1
- package/dist/internal/agent-orb.js +38 -20
- package/dist/internal/company-mark.d.ts +13 -0
- package/dist/internal/company-mark.d.ts.map +1 -0
- package/dist/internal/company-mark.js +8 -0
- package/dist/internal/form-submit.d.ts +2 -1
- package/dist/internal/form-submit.d.ts.map +1 -1
- package/dist/internal/form-submit.js +2 -2
- package/dist/showcase/specimens/other.js +1 -1
- package/dist/showcase/specimens/status.d.ts +2 -1
- package/dist/showcase/specimens/status.d.ts.map +1 -1
- package/dist/showcase/specimens/status.js +17 -3
- package/dist/showcase/usage.generated.js +8 -8
- package/dist/standalone/index.js +1 -1
- package/package.json +2 -2
- package/dist/internal/company-logo.d.ts +0 -17
- package/dist/internal/company-logo.d.ts.map +0 -1
- package/dist/internal/company-logo.js +0 -13
|
@@ -1,19 +1,27 @@
|
|
|
1
|
+
import { spring } from "motion";
|
|
1
2
|
const personalities = {
|
|
2
|
-
ribbon: { speed: 0.55
|
|
3
|
-
nadia: { speed: 0.55
|
|
4
|
-
sofia: { speed: 0.55
|
|
5
|
-
lattice: { speed: 0.28
|
|
6
|
-
orbit: { speed: 0.7
|
|
7
|
-
globe: { speed: 0.35
|
|
8
|
-
network: { speed: 0.55
|
|
9
|
-
braid: { speed: 0.65
|
|
10
|
-
morph: { speed: 0.9
|
|
3
|
+
ribbon: { speed: 0.55 },
|
|
4
|
+
nadia: { speed: 0.55 },
|
|
5
|
+
sofia: { speed: 0.55 },
|
|
6
|
+
lattice: { speed: 0.28 },
|
|
7
|
+
orbit: { speed: 0.7 },
|
|
8
|
+
globe: { speed: 0.35 },
|
|
9
|
+
network: { speed: 0.55 },
|
|
10
|
+
braid: { speed: 0.65 },
|
|
11
|
+
morph: { speed: 0.9 },
|
|
11
12
|
};
|
|
12
13
|
export function nativeSpeed(form) {
|
|
13
14
|
return personalities[form].speed;
|
|
14
15
|
}
|
|
15
|
-
export function stateSpeed(state, form) {
|
|
16
|
-
const speed = {
|
|
16
|
+
export function stateSpeed(state, form, age = 0, timing = defaultTiming) {
|
|
17
|
+
const speed = {
|
|
18
|
+
idle: 0.864,
|
|
19
|
+
working: 1,
|
|
20
|
+
thinking: 0.55,
|
|
21
|
+
waiting: 0,
|
|
22
|
+
blocked: 0,
|
|
23
|
+
done: age >= timing.doneDuration ? 0.72 : 0.65,
|
|
24
|
+
};
|
|
17
25
|
return speed[state] * nativeSpeed(form);
|
|
18
26
|
}
|
|
19
27
|
/** The breath's period, in seconds. */
|
|
@@ -29,58 +37,166 @@ export function reducedBreath(state, seconds) {
|
|
|
29
37
|
const phase = (1 - Math.cos((seconds * Math.PI * 2) / BREATH_SECONDS)) / 2;
|
|
30
38
|
return 1 - 0.55 * phase;
|
|
31
39
|
}
|
|
32
|
-
export function
|
|
33
|
-
const
|
|
40
|
+
export function readOrbTiming(style) {
|
|
41
|
+
const seconds = (name, fallback) => {
|
|
42
|
+
const token = style?.getPropertyValue(`--nc-duration-${name}`).trim() ?? "";
|
|
43
|
+
return token ? Number.parseFloat(token) * (token.endsWith("ms") ? 0.001 : 1) : fallback;
|
|
44
|
+
};
|
|
45
|
+
const wait = seconds("wait", 1.6);
|
|
46
|
+
const confirm = seconds("confirm", 0.18);
|
|
47
|
+
const transition = seconds("transition", 0.24);
|
|
48
|
+
const period = (beats) => Math.round(wait * beats * 1000) / 1000;
|
|
49
|
+
const gesture = spring({ keyframes: [0, 1], duration: transition * 2000, bounce: 0.1 });
|
|
50
|
+
return {
|
|
51
|
+
wait,
|
|
52
|
+
confirm,
|
|
53
|
+
transition,
|
|
54
|
+
doneDuration: period(3),
|
|
55
|
+
blockedDuration: period(1.25),
|
|
56
|
+
gestureAge: (age) => (age * transition * 2) / wait,
|
|
57
|
+
settle: (age, delay = 0) => age < delay ? 0 : gesture.next((age - delay) * 1000).value,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const defaultTiming = readOrbTiming();
|
|
61
|
+
const clamp = (value) => Math.min(1, Math.max(0, value));
|
|
62
|
+
const smooth = (value) => {
|
|
63
|
+
const t = clamp(value);
|
|
64
|
+
return t * t * (3 - 2 * t);
|
|
65
|
+
};
|
|
66
|
+
export function motionPose(state, age, timing = defaultTiming, reduced = false) {
|
|
34
67
|
let sx = 0.82;
|
|
35
68
|
let sy = 0.82;
|
|
36
69
|
let y = 0;
|
|
37
|
-
|
|
70
|
+
let x = 0;
|
|
38
71
|
let rotation = 0;
|
|
39
|
-
const split = 0;
|
|
40
|
-
let opacity = 1;
|
|
41
72
|
if (state === "idle") {
|
|
42
|
-
const breath = Math.sin((age * Math.PI) /
|
|
73
|
+
const breath = Math.sin(((reduced ? 0.6 : age) * Math.PI * 2) / (timing.wait * 4));
|
|
43
74
|
sx += breath * 0.01;
|
|
44
75
|
sy += breath * 0.01;
|
|
45
76
|
y = -breath * 0.004;
|
|
46
77
|
}
|
|
47
|
-
else if (state === "waiting") {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
78
|
+
else if (!reduced && state === "waiting") {
|
|
79
|
+
const gestureAge = timing.gestureAge(age);
|
|
80
|
+
const breath = Math.sin((age * Math.PI * 2) / (timing.wait * 3));
|
|
81
|
+
const anticipation = Math.sin(clamp(gestureAge / timing.confirm) * Math.PI);
|
|
82
|
+
const lean = timing.settle(gestureAge, timing.confirm * 0.55);
|
|
83
|
+
const scale = 1 - anticipation * 0.018 + breath * 0.006;
|
|
84
|
+
sx *= scale;
|
|
85
|
+
sy *= scale;
|
|
86
|
+
y = -lean * 0.018;
|
|
87
|
+
rotation = (-lean * 4.5 * Math.PI) / 180;
|
|
52
88
|
}
|
|
53
|
-
else if (state === "blocked") {
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
89
|
+
else if (!reduced && state === "blocked") {
|
|
90
|
+
const gestureAge = timing.gestureAge(age);
|
|
91
|
+
const strikeAt = timing.confirm * 0.85;
|
|
92
|
+
const recoil = smooth(gestureAge / strikeAt) * (1 - timing.settle(gestureAge, strikeAt));
|
|
93
|
+
sx *= 1 - recoil * 0.018;
|
|
94
|
+
sy *= 1 + recoil * 0.012;
|
|
95
|
+
x = -recoil * 0.034;
|
|
96
|
+
y = recoil * 0.014;
|
|
97
|
+
rotation = (-recoil * 4 * Math.PI) / 180;
|
|
61
98
|
}
|
|
62
|
-
else if (state === "done") {
|
|
63
|
-
|
|
64
|
-
|
|
99
|
+
else if (!reduced && state === "done") {
|
|
100
|
+
const phase = (age * 1.3) / (timing.wait * 2.25);
|
|
101
|
+
if (phase < 0.18) {
|
|
102
|
+
const anticipation = Math.sin((Math.PI * phase) / 0.18);
|
|
65
103
|
sx += 0.03 * anticipation;
|
|
66
104
|
sy -= 0.04 * anticipation;
|
|
67
105
|
y = 0.012 * anticipation;
|
|
68
106
|
}
|
|
69
|
-
else if (
|
|
70
|
-
const leap = (
|
|
107
|
+
else if (phase < 1.3) {
|
|
108
|
+
const leap = (phase - 0.18) / 1.12;
|
|
71
109
|
y = -0.07 * Math.sin(Math.PI * leap);
|
|
72
110
|
sx += 0.025 * Math.sin(Math.PI * leap);
|
|
73
111
|
sy += 0.035 * Math.sin(Math.PI * leap);
|
|
74
112
|
rotation = Math.sin(leap * Math.PI * 2) * 0.07;
|
|
75
113
|
}
|
|
76
114
|
}
|
|
77
|
-
return { sx, sy, x, y, rotation
|
|
115
|
+
return { sx, sy, x, y, rotation };
|
|
116
|
+
}
|
|
117
|
+
// Lucide Pause and Ban geometry, lucide-static 1.58.0, ISC licence.
|
|
118
|
+
function paintHeldCue(context, state, size, age, reduced, color, timing) {
|
|
119
|
+
const gestureAge = timing.gestureAge(age);
|
|
120
|
+
const enter = reduced ? 1 : smooth((gestureAge - timing.confirm * 0.35) / timing.confirm);
|
|
121
|
+
const landed = reduced ? 1 : timing.settle(gestureAge, timing.confirm * 0.35);
|
|
122
|
+
const side = Math.max(7, Math.min(36, size * 0.26));
|
|
123
|
+
context.save();
|
|
124
|
+
context.fillStyle = color;
|
|
125
|
+
context.strokeStyle = color;
|
|
126
|
+
context.globalAlpha = enter * 0.95;
|
|
127
|
+
context.translate(size / 2, size / 2);
|
|
128
|
+
if (state === "waiting") {
|
|
129
|
+
const lean = reduced ? 0 : timing.settle(gestureAge, timing.confirm * 0.55);
|
|
130
|
+
const breath = reduced ? 0 : Math.sin((age * Math.PI * 2) / (timing.wait * 3));
|
|
131
|
+
context.translate(0, (1 - landed) * -0.12 * side);
|
|
132
|
+
context.rotate((-lean * 2 * Math.PI) / 180);
|
|
133
|
+
const scale = 0.94 + landed * 0.06;
|
|
134
|
+
context.scale(scale, scale);
|
|
135
|
+
context.scale(side / 24, side / 24);
|
|
136
|
+
for (const [index, x] of [14, 5].entries()) {
|
|
137
|
+
const arrival = reduced
|
|
138
|
+
? 1
|
|
139
|
+
: timing.settle(gestureAge, timing.confirm * (index === 0 ? 0.65 : 0.2));
|
|
140
|
+
const direction = index === 0 ? 1 : -1;
|
|
141
|
+
context.save();
|
|
142
|
+
context.globalAlpha = enter * 0.95 * clamp(arrival) * (reduced ? 1 : 0.96 + breath * 0.04);
|
|
143
|
+
context.translate(x - 9.5 + direction * (1 - arrival) * 1.45 * 5, (1 - arrival) * -0.24 * 18);
|
|
144
|
+
context.rotate((direction * (1 - arrival) * 14 * Math.PI) / 180);
|
|
145
|
+
context.scale(1, 1 + (1 - arrival) * 0.12);
|
|
146
|
+
context.beginPath();
|
|
147
|
+
context.roundRect(-2.5, -9, 5, 18, 1);
|
|
148
|
+
context.fill();
|
|
149
|
+
context.restore();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
context.translate(0, (1 - landed) * -0.1 * side);
|
|
154
|
+
context.rotate(((1 - landed) * -12 * Math.PI) / 180);
|
|
155
|
+
const scale = 1 + (1 - landed) * 0.18;
|
|
156
|
+
context.scale(scale, scale);
|
|
157
|
+
context.scale(side / 24, side / 24);
|
|
158
|
+
context.lineWidth = Math.max(1.6, 24 / side);
|
|
159
|
+
context.lineCap = "round";
|
|
160
|
+
context.beginPath();
|
|
161
|
+
context.arc(0, 0, 10, 0, Math.PI * 2);
|
|
162
|
+
context.stroke();
|
|
163
|
+
const slash = reduced ? 1 : smooth((gestureAge - timing.confirm * 0.8) / timing.confirm);
|
|
164
|
+
context.beginPath();
|
|
165
|
+
context.moveTo(-7.071, -7.071);
|
|
166
|
+
context.lineTo(-7.071 + 14.141 * slash, -7.071 + 14.142 * slash);
|
|
167
|
+
context.stroke();
|
|
168
|
+
if (!reduced && size >= 40) {
|
|
169
|
+
const impact = clamp((gestureAge - timing.confirm * 0.85) / timing.transition);
|
|
170
|
+
context.globalAlpha *= Math.sin(impact * Math.PI) * 0.65;
|
|
171
|
+
context.lineWidth = (1.4 * 24) / side;
|
|
172
|
+
for (const direction of [-1, 1]) {
|
|
173
|
+
context.beginPath();
|
|
174
|
+
const x = direction * (14.52 + impact * 5.472);
|
|
175
|
+
const y = direction * (10.34 + impact * 1.68);
|
|
176
|
+
context.moveTo(x - 1.612, y - 1.612);
|
|
177
|
+
context.lineTo(x + 1.612, y + 1.612);
|
|
178
|
+
context.stroke();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
context.restore();
|
|
78
183
|
}
|
|
79
184
|
export function paintOrbCue(context, state, size, seconds, reduced, colors, depth,
|
|
80
185
|
/** The orb's whole ink, so the cue breathes with the body under reduced motion. */
|
|
81
|
-
ink = 1) {
|
|
186
|
+
ink = 1, timing = defaultTiming, statusColor = colors[0] ?? "currentColor") {
|
|
187
|
+
if (state === "waiting" || state === "blocked") {
|
|
188
|
+
if (depth === "front")
|
|
189
|
+
paintHeldCue(context, state, size, seconds, reduced, statusColor, timing);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
82
192
|
if (state !== "working" && state !== "thinking" && state !== "done")
|
|
83
193
|
return;
|
|
194
|
+
seconds *=
|
|
195
|
+
state === "done"
|
|
196
|
+
? 3.1 / timing.doneDuration
|
|
197
|
+
: state === "working"
|
|
198
|
+
? 7.2 / (timing.wait * 2)
|
|
199
|
+
: 3.6 / (timing.wait * 1.5);
|
|
84
200
|
context.save();
|
|
85
201
|
if (state === "thinking") {
|
|
86
202
|
if (depth === "front") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-orb.d.ts","sourceRoot":"","sources":["../../src/internal/agent-orb.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAEb,KAAK,QAAQ,EAId,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,KAAK,aAAa,
|
|
1
|
+
{"version":3,"file":"agent-orb.d.ts","sourceRoot":"","sources":["../../src/internal/agent-orb.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAEb,KAAK,QAAQ,EAId,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,KAAK,aAAa,EAOnB,MAAM,oBAAoB,CAAC;AAE5B,QAAA,MAAM,aAAa;;;;;;;;CAQ0B,CAAC;AAE9C,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,aAAa,CAAC;AACtD;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,OAAO,GAAG,OAAO,CAAC;AAC9D,MAAM,MAAM,YAAY,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;AAE7D,kDAAkD;AAClD,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,cAAc,CAAC;AACxD,+FAA+F;AAC/F,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;AAyDlD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAuDpF;AA6HD,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,cAAc,CAAC;IACrB;;;OAGG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,iBAAiB,GAClD,CAAC;IAAE,MAAM,CAAC,EAAE,QAAQ,CAAC;IAAC,KAAK,CAAC,EAAE,aAAa,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAExF,wBAAgB,aAAa,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,EAAE,oBAAoB;;sBAIzC,OAAO;qBAAuB,aAAa;EA0MvF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { finalizeFrame, MODE_FRAMES, makeProj, radiusScale, resolvePreset, } from "thinking-orbs/engine";
|
|
2
|
-
import { motionPose, nativeSpeed, paintOrbCue, reducedBreath, stateSpeed, } from "./agent-orb-motion.js";
|
|
2
|
+
import { motionPose, nativeSpeed, paintOrbCue, reducedBreath, readOrbTiming, stateSpeed, } from "./agent-orb-motion.js";
|
|
3
3
|
const agentOrbForms = {
|
|
4
4
|
orbit: "working",
|
|
5
5
|
globe: "searching",
|
|
@@ -27,7 +27,15 @@ const presenceWeights = {
|
|
|
27
27
|
*/
|
|
28
28
|
const nadiaStripes = ["--nc-identity-azzurro", "--nc-identity-verde", null, "--nc-identity-rosso"];
|
|
29
29
|
const celebrationTokens = ["--nc-acqua-700", "--nc-viola-700", "--nc-warning", "--nc-rosso-700"];
|
|
30
|
-
const
|
|
30
|
+
const statusTokens = { waiting: "--nc-warning-deep", blocked: "--nc-error" };
|
|
31
|
+
const appearanceTokens = [
|
|
32
|
+
...celebrationTokens,
|
|
33
|
+
...nadiaStripes.filter((token) => token !== null),
|
|
34
|
+
...Object.values(statusTokens),
|
|
35
|
+
"--nc-duration-wait",
|
|
36
|
+
"--nc-duration-confirm",
|
|
37
|
+
"--nc-duration-transition",
|
|
38
|
+
];
|
|
31
39
|
/**
|
|
32
40
|
* Sofia's four stripes: cobalto, giallo, the orb's own pigment and arancio, the
|
|
33
41
|
* identity hues Nadia does not wear, so side by side the two carry all six.
|
|
@@ -122,22 +130,25 @@ function paintAgentOrb(context, input) {
|
|
|
122
130
|
? facing(stripedRibbonFrame(size, seconds, preset.opts), size)
|
|
123
131
|
: MODE_FRAMES[preset.mode](size, seconds, preset.opts);
|
|
124
132
|
context.clearRect(0, 0, size, size);
|
|
125
|
-
const
|
|
126
|
-
const
|
|
133
|
+
const done = state === "done" && age >= input.timing.doneDuration;
|
|
134
|
+
const visualState = input.motion === "ambient" || done ? "idle" : state;
|
|
135
|
+
const poseAge = input.motion === "ambient" ? 0 : done ? age - input.timing.doneDuration : age;
|
|
136
|
+
const pose = motionPose(visualState, poseAge, input.timing, reduced);
|
|
137
|
+
const cueAge = done ? age - input.timing.doneDuration : age;
|
|
138
|
+
const statusColor = visualState === "waiting" || visualState === "blocked"
|
|
139
|
+
? input.statusColors[visualState]
|
|
140
|
+
: color;
|
|
127
141
|
const project = (x, y) => {
|
|
128
142
|
const dx = (x - size / 2) * pose.sx;
|
|
129
143
|
const dy = (y - size / 2) * pose.sy;
|
|
130
144
|
return [
|
|
131
|
-
size / 2 +
|
|
132
|
-
dx * Math.cos(pose.rotation) -
|
|
133
|
-
dy * Math.sin(pose.rotation) +
|
|
134
|
-
(pose.x + Math.sign(dx) * pose.split) * size,
|
|
145
|
+
size / 2 + dx * Math.cos(pose.rotation) - dy * Math.sin(pose.rotation) + pose.x * size,
|
|
135
146
|
size / 2 + dx * Math.sin(pose.rotation) + dy * Math.cos(pose.rotation) + pose.y * size,
|
|
136
147
|
];
|
|
137
148
|
};
|
|
138
|
-
const ink =
|
|
149
|
+
const ink = breath;
|
|
139
150
|
if (input.motion === "status") {
|
|
140
|
-
paintOrbCue(context,
|
|
151
|
+
paintOrbCue(context, visualState, size, cueAge, reduced, celebrationColors, "back", breath, input.timing, statusColor);
|
|
141
152
|
}
|
|
142
153
|
context.fillStyle = color;
|
|
143
154
|
context.strokeStyle = color;
|
|
@@ -159,7 +170,7 @@ function paintAgentOrb(context, input) {
|
|
|
159
170
|
}
|
|
160
171
|
context.globalAlpha = 1;
|
|
161
172
|
if (input.motion === "status") {
|
|
162
|
-
paintOrbCue(context,
|
|
173
|
+
paintOrbCue(context, visualState, size, cueAge, reduced, celebrationColors, "front", breath, input.timing, statusColor);
|
|
163
174
|
}
|
|
164
175
|
}
|
|
165
176
|
export function mountAgentOrb(canvas, options) {
|
|
@@ -185,6 +196,8 @@ export function mountAgentOrb(canvas, options) {
|
|
|
185
196
|
let celebrationColors = [color];
|
|
186
197
|
let stripeColors = [color];
|
|
187
198
|
let appearanceKey = "";
|
|
199
|
+
let timing = readOrbTiming();
|
|
200
|
+
let statusColors = { waiting: color, blocked: color };
|
|
188
201
|
/**
|
|
189
202
|
* The box the orb is displayed at, in CSS pixels. A canvas stretched by
|
|
190
203
|
* layout reads as pixels unless the engine paints at that size, so the box
|
|
@@ -213,6 +226,8 @@ export function mountAgentOrb(canvas, options) {
|
|
|
213
226
|
motion: orbMotion,
|
|
214
227
|
celebrationColors,
|
|
215
228
|
stripeColors,
|
|
229
|
+
statusColors,
|
|
230
|
+
timing,
|
|
216
231
|
});
|
|
217
232
|
}
|
|
218
233
|
function running() {
|
|
@@ -223,7 +238,7 @@ export function mountAgentOrb(canvas, options) {
|
|
|
223
238
|
return orbMotion === "status" && (state === "thinking" || state === "working");
|
|
224
239
|
if (orbMotion === "ambient")
|
|
225
240
|
return true;
|
|
226
|
-
return
|
|
241
|
+
return !(state === "blocked" && age >= timing.blockedDuration);
|
|
227
242
|
}
|
|
228
243
|
function tick(now) {
|
|
229
244
|
request = 0;
|
|
@@ -235,21 +250,19 @@ export function mountAgentOrb(canvas, options) {
|
|
|
235
250
|
breath += elapsed;
|
|
236
251
|
else {
|
|
237
252
|
seconds +=
|
|
238
|
-
elapsed *
|
|
253
|
+
elapsed *
|
|
254
|
+
(orbMotion === "ambient" ? nativeSpeed(form) : stateSpeed(state, form, age, timing));
|
|
239
255
|
if (orbMotion === "status")
|
|
240
|
-
age += elapsed
|
|
241
|
-
if (state === "done" && age >= 1.8) {
|
|
242
|
-
state = "idle";
|
|
243
|
-
age = 0;
|
|
244
|
-
}
|
|
256
|
+
age += elapsed;
|
|
245
257
|
}
|
|
246
258
|
}
|
|
247
259
|
previous = now;
|
|
248
|
-
if (now - lastPaint >= 1000 / 30) {
|
|
260
|
+
if (now - lastPaint >= 1000 / 30 || !running()) {
|
|
249
261
|
paint();
|
|
250
262
|
lastPaint = now;
|
|
251
263
|
}
|
|
252
|
-
|
|
264
|
+
if (running())
|
|
265
|
+
request = requestAnimationFrame(tick);
|
|
253
266
|
}
|
|
254
267
|
function play() {
|
|
255
268
|
cancelAnimationFrame(request);
|
|
@@ -293,6 +306,11 @@ export function mountAgentOrb(canvas, options) {
|
|
|
293
306
|
const appearance = getComputedStyle(canvas);
|
|
294
307
|
appearanceKey = readAppearanceKey(appearance, painted);
|
|
295
308
|
color = appearance.color;
|
|
309
|
+
timing = readOrbTiming(appearance);
|
|
310
|
+
statusColors = {
|
|
311
|
+
waiting: computedColor(appearance.getPropertyValue(statusTokens.waiting).trim() || color),
|
|
312
|
+
blocked: computedColor(appearance.getPropertyValue(statusTokens.blocked).trim() || color),
|
|
313
|
+
};
|
|
296
314
|
celebrationColors = celebrationTokens.map((token) => computedColor(`color-mix(in oklch, ${appearance.getPropertyValue(token).trim() || color} 75%, white)`));
|
|
297
315
|
stripeColors = (figureStripes[form] ?? []).map((token) => (token && appearance.getPropertyValue(token).trim()) || color);
|
|
298
316
|
play();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function CompanyMark({ name, logo, size, initialsSize, naming, }: {
|
|
2
|
+
name: string;
|
|
3
|
+
logo: string | undefined;
|
|
4
|
+
size: number;
|
|
5
|
+
initialsSize: number;
|
|
6
|
+
naming: {
|
|
7
|
+
role: "img";
|
|
8
|
+
"aria-label": string;
|
|
9
|
+
} | {
|
|
10
|
+
"aria-hidden": true;
|
|
11
|
+
};
|
|
12
|
+
}): import("react").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=company-mark.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"company-mark.d.ts","sourceRoot":"","sources":["../../src/internal/company-mark.tsx"],"names":[],"mappings":"AAMA,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,YAAY,EACZ,MAAM,GACP,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE;QAAE,IAAI,EAAE,KAAK,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,aAAa,EAAE,IAAI,CAAA;KAAE,CAAC;CACzE,+BA6BA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { avatarInitials } from "../components/avatar.js";
|
|
5
|
+
export function CompanyMark({ name, logo, size, initialsSize, naming, }) {
|
|
6
|
+
const [failedLogo, setFailedLogo] = useState(null);
|
|
7
|
+
return (_jsx("span", { className: "inline-flex shrink-0 items-center justify-center overflow-hidden rounded-md bg-nc-card-graphite text-nc-identity-white ring-1 ring-border ring-inset", "data-kind": "company", "data-slot": "identity-mark", style: { width: size, height: size }, ...naming, children: logo && failedLogo !== logo ? (_jsx("img", { alt: "", className: "size-full object-contain", "data-slot": "identity-mark-logo", onError: () => setFailedLogo(logo), src: logo })) : (_jsx("span", { "aria-hidden": "true", className: "leading-none font-semibold", style: { fontSize: initialsSize }, children: avatarInitials(name) })) }));
|
|
8
|
+
}
|
|
@@ -22,7 +22,8 @@ export type FormProps = Omit<ComponentProps<"form">, "children" | "className"> &
|
|
|
22
22
|
notice?: ReactNode;
|
|
23
23
|
children: ReactNode;
|
|
24
24
|
};
|
|
25
|
-
export declare function FormSubmitButton({ submit }: {
|
|
25
|
+
export declare function FormSubmitButton({ submit, destructive, }: {
|
|
26
26
|
submit: FormSubmit;
|
|
27
|
+
destructive?: boolean;
|
|
27
28
|
}): import("react").JSX.Element;
|
|
28
29
|
//# sourceMappingURL=form-submit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-submit.d.ts","sourceRoot":"","sources":["../../src/internal/form-submit.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvD,0DAA0D;AAC1D,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,CACA;IAAE,OAAO,CAAC,EAAE,SAAS,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C;IACE,uFAAuF;IACvF,OAAO,EAAE,OAAO,CAAC;IACjB,kFAAkF;IAClF,YAAY,EAAE,MAAM,CAAC;CACtB,CACJ,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC,GAAG;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,iFAAiF;IACjF,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAoCF,wBAAgB,gBAAgB,CAAC,
|
|
1
|
+
{"version":3,"file":"form-submit.d.ts","sourceRoot":"","sources":["../../src/internal/form-submit.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvD,0DAA0D;AAC1D,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,CACA;IAAE,OAAO,CAAC,EAAE,SAAS,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C;IACE,uFAAuF;IACvF,OAAO,EAAE,OAAO,CAAC;IACjB,kFAAkF;IAClF,YAAY,EAAE,MAAM,CAAC;CACtB,CACJ,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC,GAAG;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,iFAAiF;IACjF,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAoCF,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,WAAmB,GACpB,EAAE;IACD,MAAM,EAAE,UAAU,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,+BAeA"}
|
|
@@ -31,7 +31,7 @@ function trimTextFields(form) {
|
|
|
31
31
|
replaceValue(field, trimmed);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
export function FormSubmitButton({ submit }) {
|
|
34
|
+
export function FormSubmitButton({ submit, destructive = false, }) {
|
|
35
35
|
const pending = submit.pending === true;
|
|
36
|
-
return (_jsx(Button, { "aria-describedby": submit.describedBy, disabled: submit.disabled, loading: pending, loadingLabel: submit.pendingLabel ?? submit.label, onClick: (event) => trimTextFields(event.currentTarget.form), type: "submit", children: submit.label }));
|
|
36
|
+
return (_jsx(Button, { "aria-describedby": submit.describedBy, disabled: submit.disabled, loading: pending, loadingLabel: submit.pendingLabel ?? submit.label, onClick: (event) => trimTextFields(event.currentTarget.form), type: "submit", variant: destructive ? "destructive" : "default", children: submit.label }));
|
|
37
37
|
}
|
|
@@ -37,7 +37,7 @@ function CompanyCardSpecimen() {
|
|
|
37
37
|
}
|
|
38
38
|
function HiveSceneSpecimen() {
|
|
39
39
|
const art = useEmptyArt();
|
|
40
|
-
return (_jsx("div", { className: "h-96 overflow-hidden rounded-md", children: _jsx(HiveScene, { className: "size-full", logo: { src: HIVE_LOGO, label: "Alveare" }, mode: "join", picture: _jsx("img", { alt: "", className: "size-full object-cover", src: art.teams }), children: _jsx("p", { className: "text-lg font-semibold", children: "Join Acme's workspace" }) }) }));
|
|
40
|
+
return (_jsx("div", { className: "h-96 overflow-hidden rounded-md", style: { contain: "paint" }, children: _jsx(HiveScene, { className: "size-full", logo: { src: HIVE_LOGO, label: "Alveare" }, mode: "join", picture: _jsx("img", { alt: "", className: "size-full object-cover", src: art.teams }), children: _jsx("p", { className: "text-lg font-semibold", children: "Join Acme's workspace" }) }) }));
|
|
41
41
|
}
|
|
42
42
|
function NadiaPresenceSpecimen() {
|
|
43
43
|
const [reveal, setReveal] = useState(0.6);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
declare function ActionStatusSpecimen(): import("react").JSX.Element;
|
|
2
2
|
declare function GaugeSpecimen(): import("react").JSX.Element;
|
|
3
|
+
declare function AgentOrbSpecimen(): import("react").JSX.Element;
|
|
3
4
|
export declare const STATUS: {
|
|
4
5
|
ActionStatus: typeof ActionStatusSpecimen;
|
|
5
|
-
AgentOrb:
|
|
6
|
+
AgentOrb: typeof AgentOrbSpecimen;
|
|
6
7
|
AppMark: () => import("react").JSX.Element;
|
|
7
8
|
ArchIcon: () => import("react").JSX.Element;
|
|
8
9
|
Avatar: () => import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/showcase/specimens/status.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/showcase/specimens/status.tsx"],"names":[],"mappings":"AAyDA,iBAAS,oBAAoB,gCAiB5B;AAYD,iBAAS,aAAa,gCA2DrB;AAWD,iBAAS,gBAAgB,gCAkExB;AAED,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;CAuPQ,CAAC"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useId } from "react";
|
|
3
|
+
import { useId, useState } from "react";
|
|
4
4
|
import { Building2, Check, Clock, CreditCard, Database, Lock, Mail, MonitorDown, Pause, Save, Wrench, } from "lucide-react";
|
|
5
5
|
import { ActionStatus } from "../../components/action-status.js";
|
|
6
6
|
import { AgentOrb } from "../../components/agent-orb.js";
|
|
7
7
|
import { AppMark, composioLogo } from "../../components/app-mark.js";
|
|
8
8
|
import { Avatar, AvatarFallback, AvatarGroup, AvatarWithIcon } from "../../components/avatar.js";
|
|
9
9
|
import { Badge } from "../../components/badge.js";
|
|
10
|
+
import { Button } from "../../components/button.js";
|
|
10
11
|
import { BrandMark, BrandWordmark } from "../../components/brand.js";
|
|
11
12
|
import { CheckCounts, CheckState } from "../../components/check-counts.js";
|
|
12
13
|
import { FileTypeIcon } from "../../components/file-type-icon.js";
|
|
@@ -21,7 +22,7 @@ import { RecordIdentity } from "../../components/record-identity.js";
|
|
|
21
22
|
import { StatusBadge } from "../../components/status-badge.js";
|
|
22
23
|
import { Tag } from "../../components/tag.js";
|
|
23
24
|
import { ObjectFactValue } from "../../components/object-fact-value.js";
|
|
24
|
-
import {
|
|
25
|
+
import { COBALTO, nothing } from "../samples.js";
|
|
25
26
|
const SAMPLE_LOGO = `data:image/svg+xml,${encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 16"><rect width="64" height="16" fill="white"/><text x="0" y="13" fill="navy" font-family="sans-serif" font-size="14" font-weight="700">ROSSI</text></svg>')}`;
|
|
26
27
|
const SAMPLE_ICON = `data:image/svg+xml,${encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="7" fill="royalblue"/><path d="M10 9h8a5 5 0 0 1 0 10h-4v5h-4z" fill="white"/></svg>')}`;
|
|
27
28
|
const MEMBERS = [
|
|
@@ -41,9 +42,22 @@ function GaugeRow({ label, gauge }) {
|
|
|
41
42
|
function GaugeSpecimen() {
|
|
42
43
|
return (_jsxs("div", { className: "grid gap-6", children: [_jsxs("div", { className: "flex flex-wrap items-end gap-6", children: [_jsx(GaugeRow, { gauge: (id) => _jsx(Gauge, { "aria-labelledby": id, size: "xs", value: 42 }), label: "Storage used" }), _jsx(GaugeRow, { gauge: (id) => _jsx(Gauge, { "aria-labelledby": id, size: "sm", value: 64 }), label: "Plan used" }), _jsx(GaugeRow, { gauge: (id) => _jsx(Gauge, { "aria-labelledby": id, size: "md", value: 87 }), label: "Tasks done" }), _jsx(GaugeRow, { gauge: (id) => _jsx(Gauge, { "aria-labelledby": id, size: "lg", value: 99.97 }), label: "Cache hit rate" })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-6", children: [_jsx(GaugeRow, { gauge: (id) => _jsx(Gauge, { "aria-labelledby": id, showValue: true, size: "sm", value: 64 }), label: "Plan used, 64%" }), _jsx(GaugeRow, { gauge: (id) => _jsx(Gauge, { "aria-labelledby": id, showValue: true, size: "md", value: 87 }), label: "Tasks done, 87%" }), _jsx(GaugeRow, { gauge: (id) => _jsx(Gauge, { "aria-labelledby": id, showValue: true, size: "lg", value: 99.97 }), label: "Cache hit rate, 99.97%" })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-6", children: [_jsx(GaugeRow, { gauge: (id) => (_jsx(Gauge, { "aria-labelledby": id, showValue: true, size: "md", tone: "warning", value: 82 })), label: "Model budget, 82%: close to the limit" }), _jsx(GaugeRow, { gauge: (id) => (_jsx(Gauge, { "aria-labelledby": id, showValue: true, size: "md", tone: "critical", value: 97 })), label: "Mailbox space, 97%: almost full" }), _jsx(GaugeRow, { gauge: (id) => (_jsx(Gauge, { "aria-labelledby": id, size: "md", value: 58, children: _jsx(Database, { "aria-hidden": "true" }) })), label: "Memory used" })] })] }));
|
|
43
44
|
}
|
|
45
|
+
const ORB_STATES = [
|
|
46
|
+
"idle",
|
|
47
|
+
"working",
|
|
48
|
+
"thinking",
|
|
49
|
+
"waiting",
|
|
50
|
+
"blocked",
|
|
51
|
+
"done",
|
|
52
|
+
];
|
|
53
|
+
function AgentOrbSpecimen() {
|
|
54
|
+
const [replay, setReplay] = useState(0);
|
|
55
|
+
const [state, setState] = useState("waiting");
|
|
56
|
+
return (_jsxs("div", { className: "grid gap-6", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [ORB_STATES.map((option) => (_jsx(Button, { variant: state === option ? "default" : "outline", size: "sm", "aria-pressed": state === option, onClick: () => setState(option), children: option }, option))), _jsx(Button, { variant: "outline", size: "sm", onClick: () => setReplay((value) => value + 1), children: "Replay motion" })] }), _jsx("div", { className: "flex flex-wrap items-end gap-6", children: ORB_STATES.map((status) => (_jsxs("div", { className: "grid justify-items-center gap-2 text-sm", children: [_jsx(AgentOrb, { form: "nadia", label: `Nadia, ${status}`, size: 96, state: status, motionKey: replay }), _jsx("span", { children: status })] }, status))) }), _jsx("div", { className: "flex flex-wrap items-end gap-6", children: [20, 24, 32, 40, 64, 96, 160].map((size) => (_jsxs("div", { className: "grid justify-items-center gap-2 text-sm", children: [_jsx(AgentOrb, { form: "nadia", label: `Nadia, ${state}, ${size} px`, size: size, state: state, motionKey: replay }), _jsxs("span", { children: [size, " px"] })] }, size))) }), _jsx("div", { className: "flex flex-wrap items-end gap-6", children: ["sofia", "ribbon", "lattice", "orbit", "globe", "network", "braid", "morph"].map((form) => (_jsx(AgentOrb, { form: form, label: `${form}, ${state}`, color: form === "sofia" ? undefined : COBALTO, size: 64, state: state, motionKey: replay }, form))) })] }));
|
|
57
|
+
}
|
|
44
58
|
export const STATUS = {
|
|
45
59
|
ActionStatus: ActionStatusSpecimen,
|
|
46
|
-
AgentOrb:
|
|
60
|
+
AgentOrb: AgentOrbSpecimen,
|
|
47
61
|
AppMark: () => (_jsxs("div", { className: "flex flex-wrap items-center gap-3 text-sm", children: [_jsx(AppMark, { app: "gmail", logo: composioLogo("gmail") }), "Gmail", _jsx(AppMark, { app: "telegram", platform: "telegram" }), "Telegram", _jsx(AppMark, { app: "Fatture in Cloud" }), "Fatture in Cloud"] })),
|
|
48
62
|
ArchIcon: () => (_jsxs("div", { className: "flex flex-wrap items-center gap-4 text-sm", children: [_jsxs("span", { className: "flex items-center gap-2", children: [_jsx(ArchIcon, { "aria-hidden": "true", className: "size-5" }), "Company"] }), _jsxs("span", { className: "flex items-center gap-2", children: [_jsx(ApprovalsIcon, { "aria-hidden": "true", className: "size-5" }), "Approvals"] }), _jsxs("span", { className: "flex items-center gap-2", children: [_jsx(AgentIcon, { "aria-hidden": "true", className: "size-5" }), "Agents"] })] })),
|
|
49
63
|
Avatar: () => (_jsxs("div", { className: "grid gap-6", children: [_jsx("div", { className: "flex flex-wrap items-center gap-4", children: ["xs", "sm", "default", "lg"].map((size) => (_jsx(Avatar, { label: "Ada Rossi", size: size, children: _jsx(AvatarFallback, { children: size === "xs" ? "A" : "AR" }) }, size))) }), _jsxs("div", { className: "flex flex-wrap items-center gap-6", children: [_jsx(AvatarGroup, { label: "5 members", limit: 3, members: MEMBERS }), _jsx(AvatarGroup, { label: "5 members, last on top", limit: 3, members: MEMBERS, reverse: true }), _jsx(AvatarGroup, { label: "5 members, tight", limit: 3, members: MEMBERS, overlap: 6 })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-6 text-sm", children: [_jsxs("span", { className: "flex items-center gap-2", children: [_jsx(AvatarWithIcon, { icon: _jsx(Check, {}), iconBackground: true, label: "Ada Rossi, approved", name: "Ada Rossi" }), "Ada Rossi"] }), _jsxs("span", { className: "flex items-center gap-2", children: [_jsx(AvatarWithIcon, { icon: _jsx(Pause, {}), iconBackground: true, label: "Marco Bianchi, paused", name: "Marco Bianchi" }), "Marco Bianchi"] }), _jsx(AvatarWithIcon, { icon: _jsx(Clock, {}), iconBackground: true, label: "Luca Conti, waiting for approval", name: "Luca Conti" })] })] })),
|