@nadicodeai/ui 12.1.135 → 12.1.137
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 +5 -1
- package/dist/components/agent-orb.d.ts.map +1 -1
- package/dist/components/agent-orb.js +5 -1
- package/dist/components/company-card/renderer.d.ts +8 -0
- package/dist/components/company-card/renderer.d.ts.map +1 -1
- package/dist/components/company-card/renderer.js +122 -53
- package/dist/components/company-card.d.ts.map +1 -1
- package/dist/components/company-card.js +70 -39
- package/dist/components/hive-scene.d.ts.map +1 -1
- package/dist/components/hive-scene.js +46 -8
- package/dist/components/scroll-area.js +3 -3
- package/dist/components/table.d.ts.map +1 -1
- package/dist/components/table.js +2 -2
- package/dist/internal/agent-orb-motion.d.ts +4 -0
- package/dist/internal/agent-orb-motion.d.ts.map +1 -1
- package/dist/internal/agent-orb-motion.js +1 -0
- package/dist/internal/agent-orb.d.ts +1 -0
- package/dist/internal/agent-orb.d.ts.map +1 -1
- package/dist/internal/agent-orb.js +207 -86
- package/dist/internal/table-compact-line.d.ts +4 -0
- package/dist/internal/table-compact-line.d.ts.map +1 -1
- package/dist/internal/table-compact-line.js +5 -1
- package/dist/showcase/usage.generated.js +2 -2
- package/dist/standalone/index.js +1 -1
- package/package.json +2 -2
|
@@ -35,7 +35,9 @@ export type AgentOrbProps = AgentOrbBaseProps & ({
|
|
|
35
35
|
* @family Status
|
|
36
36
|
* @when An Agent, anywhere: 20 in the sidebar, 32 in a row, 64 on her Profile card, 96 in an Agent
|
|
37
37
|
* card, 160 on entry. There is no other Agent picture. The sizes are 20, 24, 32, 40, 64, 96 and
|
|
38
|
-
* 160 px, and no other.
|
|
38
|
+
* 160 px, and no other. Detail follows the size the orb is drawn at: up to 32 px it draws the
|
|
39
|
+
* engine's lightest dot profile, at 40 px the middle one and from 64 px the full one, since a small
|
|
40
|
+
* orb cannot show the full profile's dots apart. On a photograph the orb takes the stronger `presence="over-picture"`
|
|
39
41
|
* weight; everywhere else it is `plain`.
|
|
40
42
|
* @instead A person is an `Avatar`. The system's own wait is the waiting line, never an orb. An orb
|
|
41
43
|
* in artwork, such as a sign-in picture, takes `motion="ambient"` and claims no activity. An orb
|
|
@@ -47,6 +49,8 @@ export type AgentOrbProps = AgentOrbBaseProps & ({
|
|
|
47
49
|
* Done celebrates once over 4.8 s, then rests at 72% of native particle speed with the Idle breath.
|
|
48
50
|
* A state change interrupts the previous gesture; `motionKey` replays it and `paused` freezes it. A surface that only knows a machine checked in draws idle. No state draws
|
|
49
51
|
* a circle around the orb. Ambient motion moves the form at its own pace with no state pose or cue.
|
|
52
|
+
* An orb at rest (idle, ambient, or done after its celebration) paints 15 frames a second; every
|
|
53
|
+
* other state, gesture and the celebration paint 30. The pace is the same at either rate.
|
|
50
54
|
* Reduced motion: movement stops, a thinking or working orb breathes between full ink and 0.45
|
|
51
55
|
* opacity so busy still reads as busy, an ambient orb holds still, and waiting and blocked keep
|
|
52
56
|
* their centered signs without an entrance gesture.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-orb.d.ts","sourceRoot":"","sources":["../../src/components/agent-orb.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAqB,MAAM,OAAO,CAAC;AAE9D,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAElB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EACV,cAAc,EACd,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,YAAY,GACb,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,KAAK,iBAAiB,GAAG;IACvB,4FAA4F;IAC5F,IAAI,EAAE,cAAc,CAAC;IACrB,wFAAwF;IACxF,KAAK,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/B,qEAAqE;IACrE,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,iBAAiB,GAC3C,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,GACrF,CAAC;IAAE,UAAU,EAAE,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,UAAU,CAAC,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEhF
|
|
1
|
+
{"version":3,"file":"agent-orb.d.ts","sourceRoot":"","sources":["../../src/components/agent-orb.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAqB,MAAM,OAAO,CAAC;AAE9D,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAElB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EACV,cAAc,EACd,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,YAAY,GACb,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,KAAK,iBAAiB,GAAG;IACvB,4FAA4F;IAC5F,IAAI,EAAE,cAAc,CAAC;IACrB,wFAAwF;IACxF,KAAK,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/B,qEAAqE;IACrE,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,iBAAiB,GAC3C,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,GACrF,CAAC;IAAE,UAAU,EAAE,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,UAAU,CAAC,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,KAAK,EACL,IAAS,EACT,QAAkB,EAClB,MAAc,EACd,KAAc,EACd,MAAiB,EACjB,SAAa,EACb,UAAkB,EAClB,KAAK,EACL,SAAS,GACV,EAAE,aAAa,+BAyDf"}
|
|
@@ -9,7 +9,9 @@ import { cn } from "../lib/utils.js";
|
|
|
9
9
|
* @family Status
|
|
10
10
|
* @when An Agent, anywhere: 20 in the sidebar, 32 in a row, 64 on her Profile card, 96 in an Agent
|
|
11
11
|
* card, 160 on entry. There is no other Agent picture. The sizes are 20, 24, 32, 40, 64, 96 and
|
|
12
|
-
* 160 px, and no other.
|
|
12
|
+
* 160 px, and no other. Detail follows the size the orb is drawn at: up to 32 px it draws the
|
|
13
|
+
* engine's lightest dot profile, at 40 px the middle one and from 64 px the full one, since a small
|
|
14
|
+
* orb cannot show the full profile's dots apart. On a photograph the orb takes the stronger `presence="over-picture"`
|
|
13
15
|
* weight; everywhere else it is `plain`.
|
|
14
16
|
* @instead A person is an `Avatar`. The system's own wait is the waiting line, never an orb. An orb
|
|
15
17
|
* in artwork, such as a sign-in picture, takes `motion="ambient"` and claims no activity. An orb
|
|
@@ -21,6 +23,8 @@ import { cn } from "../lib/utils.js";
|
|
|
21
23
|
* Done celebrates once over 4.8 s, then rests at 72% of native particle speed with the Idle breath.
|
|
22
24
|
* A state change interrupts the previous gesture; `motionKey` replays it and `paused` freezes it. A surface that only knows a machine checked in draws idle. No state draws
|
|
23
25
|
* a circle around the orb. Ambient motion moves the form at its own pace with no state pose or cue.
|
|
26
|
+
* An orb at rest (idle, ambient, or done after its celebration) paints 15 frames a second; every
|
|
27
|
+
* other state, gesture and the celebration paint 30. The pace is the same at either rate.
|
|
24
28
|
* Reduced motion: movement stops, a thinking or working orb breathes between full ink and 0.45
|
|
25
29
|
* opacity so busy still reads as busy, an ambient orb holds still, and waiting and blocked keep
|
|
26
30
|
* their centered signs without an entrance gesture.
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
import * as webgpu from "vgpu";
|
|
2
|
+
import type { Gpu, Surface, Target } from "vgpu";
|
|
1
3
|
import { type FoilColors } from "./scene.js";
|
|
4
|
+
type Webgpu = Pick<typeof webgpu, "clock" | "frameLoop" | "init"> & {
|
|
5
|
+
surface: (gpu: Gpu, canvas: HTMLCanvasElement, options: {
|
|
6
|
+
dpr: [number, number];
|
|
7
|
+
}) => Target & Pick<Surface, "onResize">;
|
|
8
|
+
};
|
|
2
9
|
type RendererOptions = {
|
|
3
10
|
colors: FoilColors;
|
|
11
|
+
vgpu?: Webgpu;
|
|
4
12
|
/** The card's current turn in radians, for the page to turn the card itself. */
|
|
5
13
|
onTilt: (tiltX: number, tiltY: number) => void;
|
|
6
14
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/components/company-card/renderer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/components/company-card/renderer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,MAAM,MAAM,CAAC;AAC/B,OAAO,KAAK,EAA0B,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEzE,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AASvD,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,MAAM,EAAE,OAAO,GAAG,WAAW,GAAG,MAAM,CAAC,GAAG;IAClE,OAAO,EAAE,CACP,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE;QAAE,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,KAC/B,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;CACzC,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,wBAAgB,cAAc,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,EAAE,eAAe;;;;EA+LjF"}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
// nadicode: vgpu's holographic card renderer (MIT, https://github.com/vercel-labs/vgpu,
|
|
2
|
-
// examples/holographic-card, revision 6fa27bb4), with its WebGPU set-up
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
// within one card width; the turn it computes is handed to the page, which
|
|
6
|
-
// turns the card and its words together.
|
|
7
|
-
import { clock, frameLoop, init, surface } from "vgpu";
|
|
2
|
+
// examples/holographic-card, revision 6fa27bb4), with its WebGPU set-up and
|
|
3
|
+
// cleanup as they are.
|
|
4
|
+
import * as webgpu from "vgpu";
|
|
8
5
|
import { approach, SWEEP_MS, SWEEP_TURN } from "./approach.js";
|
|
9
6
|
import { createScene } from "./scene.js";
|
|
7
|
+
const AT_REST = 1e-4;
|
|
8
|
+
/**
|
|
9
|
+
* The first frame after the loop starts again counts as one frame of the
|
|
10
|
+
* 60 fps it runs at, not the time it was stopped.
|
|
11
|
+
*/
|
|
12
|
+
const FRAME_SECONDS = 1 / 60;
|
|
10
13
|
export function createRenderer(canvas, options) {
|
|
11
|
-
const { colors, onTilt } = options;
|
|
14
|
+
const { colors, onTilt, vgpu = webgpu } = options;
|
|
15
|
+
const { clock, frameLoop, init, surface } = vgpu;
|
|
12
16
|
let disposed = false;
|
|
13
17
|
let gpu;
|
|
14
18
|
let removeInput = () => { };
|
|
@@ -33,6 +37,7 @@ export function createRenderer(canvas, options) {
|
|
|
33
37
|
if (disposed)
|
|
34
38
|
return;
|
|
35
39
|
const motion = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
40
|
+
const time = clock(context);
|
|
36
41
|
let targetHover = 0;
|
|
37
42
|
let pointerX = 0;
|
|
38
43
|
let pointerY = 0;
|
|
@@ -46,52 +51,32 @@ export function createRenderer(canvas, options) {
|
|
|
46
51
|
// from its top-left corner to its bottom-right, then rests. It tells a
|
|
47
52
|
// person at a glance that this is a card that answers the pointer.
|
|
48
53
|
let sweepStart = null;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return;
|
|
57
|
-
const near = approach(canvas.getBoundingClientRect(), event.clientX, event.clientY);
|
|
58
|
-
// A pointer elsewhere on the page leaves a sweep to finish; one that
|
|
59
|
-
// comes near takes the card over.
|
|
60
|
-
if (near.hover > 0)
|
|
61
|
-
sweepStart = null;
|
|
62
|
-
if (sweepStart !== null)
|
|
63
|
-
return;
|
|
64
|
-
pointerX = near.x;
|
|
65
|
-
pointerY = near.y;
|
|
66
|
-
targetHover = near.hover;
|
|
67
|
-
};
|
|
68
|
-
const leave = () => {
|
|
69
|
-
if (sweepStart === null)
|
|
70
|
-
targetHover = 0;
|
|
71
|
-
};
|
|
72
|
-
const up = (event) => {
|
|
73
|
-
if (event.pointerType !== "mouse")
|
|
74
|
-
leave();
|
|
75
|
-
};
|
|
76
|
-
const root = document.documentElement;
|
|
77
|
-
window.addEventListener("pointermove", move, { passive: true });
|
|
78
|
-
window.addEventListener("pointerdown", move, { passive: true });
|
|
79
|
-
window.addEventListener("pointercancel", leave);
|
|
80
|
-
window.addEventListener("pointerup", up);
|
|
81
|
-
root.addEventListener("pointerleave", leave);
|
|
82
|
-
const unsubscribeResize = output.onResize(() => {
|
|
83
|
-
shader.set({ params: { resolution: output.size } });
|
|
84
|
-
});
|
|
85
|
-
removeInput = () => {
|
|
86
|
-
window.removeEventListener("pointermove", move);
|
|
87
|
-
window.removeEventListener("pointerdown", move);
|
|
88
|
-
window.removeEventListener("pointercancel", leave);
|
|
89
|
-
window.removeEventListener("pointerup", up);
|
|
90
|
-
root.removeEventListener("pointerleave", leave);
|
|
91
|
-
unsubscribeResize();
|
|
54
|
+
let pointer = null;
|
|
55
|
+
let needsDraw = true;
|
|
56
|
+
let onScreen = false;
|
|
57
|
+
let loop = null;
|
|
58
|
+
const stop = () => {
|
|
59
|
+
loop?.stop();
|
|
60
|
+
loop = null;
|
|
92
61
|
};
|
|
93
|
-
const
|
|
94
|
-
|
|
62
|
+
const settled = (targetX, targetY, within) => sweepStart === null &&
|
|
63
|
+
Math.abs(targetX - tiltX) <= within &&
|
|
64
|
+
Math.abs(targetY - tiltY) <= within &&
|
|
65
|
+
Math.abs(targetHover - hover) <= within &&
|
|
66
|
+
(targetHover === 0 ||
|
|
67
|
+
(Math.abs(pointerX - lightX) <= within && Math.abs(pointerY - lightY) <= within));
|
|
68
|
+
const draw = (currentFrame) => {
|
|
69
|
+
if (pointer) {
|
|
70
|
+
const near = approach(canvas.getBoundingClientRect(), pointer.clientX, pointer.clientY);
|
|
71
|
+
pointer = null;
|
|
72
|
+
if (near.hover > 0)
|
|
73
|
+
sweepStart = null;
|
|
74
|
+
if (sweepStart === null) {
|
|
75
|
+
pointerX = near.x;
|
|
76
|
+
pointerY = near.y;
|
|
77
|
+
targetHover = near.hover;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
95
80
|
let turn = null;
|
|
96
81
|
if (sweepStart !== null) {
|
|
97
82
|
const progress = (performance.now() - sweepStart) / SWEEP_MS;
|
|
@@ -116,6 +101,11 @@ export function createRenderer(canvas, options) {
|
|
|
116
101
|
const targetY = motion.matches
|
|
117
102
|
? 0
|
|
118
103
|
: (turn?.[1] ?? -Math.max(-1, Math.min(1, pointerY)) * 0.12 * targetHover);
|
|
104
|
+
if (!needsDraw && settled(targetX, targetY, 0)) {
|
|
105
|
+
currentFrame.cancel();
|
|
106
|
+
stop();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
119
109
|
const blend = motion.matches ? 1 : 1 - Math.exp(-10 * Math.min(time.deltaTime, 0.1));
|
|
120
110
|
tiltX += (targetX - tiltX) * blend;
|
|
121
111
|
tiltY += (targetY - tiltY) * blend;
|
|
@@ -124,10 +114,89 @@ export function createRenderer(canvas, options) {
|
|
|
124
114
|
lightX += (pointerX - lightX) * blend;
|
|
125
115
|
lightY += (pointerY - lightY) * blend;
|
|
126
116
|
}
|
|
117
|
+
const resting = settled(targetX, targetY, AT_REST);
|
|
118
|
+
if (resting) {
|
|
119
|
+
tiltX = targetX;
|
|
120
|
+
tiltY = targetY;
|
|
121
|
+
hover = targetHover;
|
|
122
|
+
if (targetHover > 0) {
|
|
123
|
+
lightX = pointerX;
|
|
124
|
+
lightY = pointerY;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
127
|
onTilt(tiltX, tiltY);
|
|
128
128
|
shader.set({ params: { tilt: [tiltX, tiltY], pointer: [lightX, lightY], hover } });
|
|
129
129
|
currentFrame.pass(output, shader);
|
|
130
|
-
|
|
130
|
+
needsDraw = false;
|
|
131
|
+
if (resting)
|
|
132
|
+
stop();
|
|
133
|
+
};
|
|
134
|
+
const play = () => {
|
|
135
|
+
if (disposed || !onScreen || document.hidden) {
|
|
136
|
+
stop();
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (loop)
|
|
140
|
+
return;
|
|
141
|
+
time.advance(FRAME_SECONDS);
|
|
142
|
+
loop = frameLoop(context, draw, { fps: 60 });
|
|
143
|
+
};
|
|
144
|
+
// Under reduced motion the card keeps still: the light moves only with the pointer.
|
|
145
|
+
requestSweep = () => {
|
|
146
|
+
if (motion.matches)
|
|
147
|
+
return;
|
|
148
|
+
sweepStart = performance.now();
|
|
149
|
+
play();
|
|
150
|
+
};
|
|
151
|
+
const move = (event) => {
|
|
152
|
+
if (!event.isPrimary)
|
|
153
|
+
return;
|
|
154
|
+
pointer = { clientX: event.clientX, clientY: event.clientY };
|
|
155
|
+
play();
|
|
156
|
+
};
|
|
157
|
+
const leave = () => {
|
|
158
|
+
pointer = null;
|
|
159
|
+
if (sweepStart === null)
|
|
160
|
+
targetHover = 0;
|
|
161
|
+
play();
|
|
162
|
+
};
|
|
163
|
+
const up = (event) => {
|
|
164
|
+
if (event.pointerType !== "mouse")
|
|
165
|
+
leave();
|
|
166
|
+
};
|
|
167
|
+
const root = document.documentElement;
|
|
168
|
+
window.addEventListener("pointermove", move, { passive: true });
|
|
169
|
+
window.addEventListener("pointerdown", move, { passive: true });
|
|
170
|
+
window.addEventListener("pointercancel", leave);
|
|
171
|
+
window.addEventListener("pointerup", up);
|
|
172
|
+
root.addEventListener("pointerleave", leave);
|
|
173
|
+
document.addEventListener("visibilitychange", play);
|
|
174
|
+
motion.addEventListener("change", play);
|
|
175
|
+
// vgpu sizes the canvas on a frame, so a card whose box changes takes one to be drawn again.
|
|
176
|
+
const unsubscribeResize = output.onResize(() => {
|
|
177
|
+
shader.set({ params: { resolution: output.size } });
|
|
178
|
+
needsDraw = true;
|
|
179
|
+
});
|
|
180
|
+
const box = new ResizeObserver(play);
|
|
181
|
+
box.observe(canvas);
|
|
182
|
+
const visibility = new IntersectionObserver((entries) => {
|
|
183
|
+
onScreen = entries.at(-1)?.isIntersecting ?? false;
|
|
184
|
+
play();
|
|
185
|
+
});
|
|
186
|
+
visibility.observe(canvas);
|
|
187
|
+
removeInput = () => {
|
|
188
|
+
stop();
|
|
189
|
+
window.removeEventListener("pointermove", move);
|
|
190
|
+
window.removeEventListener("pointerdown", move);
|
|
191
|
+
window.removeEventListener("pointercancel", leave);
|
|
192
|
+
window.removeEventListener("pointerup", up);
|
|
193
|
+
root.removeEventListener("pointerleave", leave);
|
|
194
|
+
document.removeEventListener("visibilitychange", play);
|
|
195
|
+
motion.removeEventListener("change", play);
|
|
196
|
+
unsubscribeResize();
|
|
197
|
+
box.disconnect();
|
|
198
|
+
visibility.disconnect();
|
|
199
|
+
};
|
|
131
200
|
})().catch((cause) => {
|
|
132
201
|
if (disposed)
|
|
133
202
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"company-card.d.ts","sourceRoot":"","sources":["../../src/components/company-card.tsx"],"names":[],"mappings":"AASA,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,SAAS,CAAC;AAEvD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;
|
|
1
|
+
{"version":3,"file":"company-card.d.ts","sourceRoot":"","sources":["../../src/components/company-card.tsx"],"names":[],"mappings":"AASA,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,SAAS,CAAC;AAEvD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AA0BF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,MAAM,EACN,OAAO,EACP,MAAM,EACN,MAAM,EACN,IAAI,EACJ,WAAmB,GACpB,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,kBAAkB,CAAC;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,+BAsTA"}
|
|
@@ -17,6 +17,10 @@ const FOIL = {
|
|
|
17
17
|
const STRIPE = 34;
|
|
18
18
|
/** How much of the card must be on screen before it turns, when the caller waits for it. */
|
|
19
19
|
const IN_VIEW = 0.6;
|
|
20
|
+
function setChanged(element, property, value) {
|
|
21
|
+
if (element.style.getPropertyValue(property) !== value)
|
|
22
|
+
element.style.setProperty(property, value);
|
|
23
|
+
}
|
|
20
24
|
function reason(cause) {
|
|
21
25
|
return cause instanceof Error ? cause.message : String(cause);
|
|
22
26
|
}
|
|
@@ -67,7 +71,6 @@ export function CompanyCard({ name, domain, edition, issued, labels, logo, sweep
|
|
|
67
71
|
const cardRef = useRef(null);
|
|
68
72
|
const lightRef = useRef(null);
|
|
69
73
|
const stripesRef = useRef(null);
|
|
70
|
-
const frame = useRef(0);
|
|
71
74
|
const canvasRef = useRef(null);
|
|
72
75
|
const [gpuFoil, setGpuFoil] = useState(false);
|
|
73
76
|
const sweepRef = useRef(() => { });
|
|
@@ -102,8 +105,8 @@ export function CompanyCard({ name, domain, edition, issued, labels, logo, sweep
|
|
|
102
105
|
const created = createRenderer(canvas, {
|
|
103
106
|
colors: foilColors(card, edition),
|
|
104
107
|
onTilt: (tiltX, tiltY) => {
|
|
105
|
-
card
|
|
106
|
-
card
|
|
108
|
+
setChanged(card, "--tilt-x", `${tiltY.toFixed(4)}rad`);
|
|
109
|
+
setChanged(card, "--tilt-y", `${tiltX.toFixed(4)}rad`);
|
|
107
110
|
},
|
|
108
111
|
});
|
|
109
112
|
renderer = created;
|
|
@@ -130,16 +133,17 @@ export function CompanyCard({ name, domain, edition, issued, labels, logo, sweep
|
|
|
130
133
|
setGpuFoil(false);
|
|
131
134
|
};
|
|
132
135
|
}, [edition, seen]);
|
|
133
|
-
// The SVG foil behaves as the shader does: it turns once in the light when it
|
|
134
|
-
// appears and when it is issued, and wakes as the pointer comes within one
|
|
135
|
-
// card width, easing its turn by how near the pointer is.
|
|
136
136
|
useEffect(() => {
|
|
137
137
|
const card = cardRef.current;
|
|
138
138
|
if (!seen || gpuFoil || !card)
|
|
139
139
|
return;
|
|
140
140
|
const motion = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
141
|
+
let onScreen = typeof IntersectionObserver === "undefined";
|
|
142
|
+
let sweepStart = null;
|
|
141
143
|
let sweepFrame = 0;
|
|
142
|
-
let
|
|
144
|
+
let pointer = null;
|
|
145
|
+
let pointerFrame = 0;
|
|
146
|
+
const playing = () => onScreen && !document.hidden;
|
|
143
147
|
const light = (x, y) => {
|
|
144
148
|
lightRef.current?.setAttribute("cx", x.toFixed(3));
|
|
145
149
|
lightRef.current?.setAttribute("cy", y.toFixed(3));
|
|
@@ -162,59 +166,86 @@ export function CompanyCard({ name, domain, edition, issued, labels, logo, sweep
|
|
|
162
166
|
}
|
|
163
167
|
};
|
|
164
168
|
const stopSweep = () => {
|
|
165
|
-
|
|
169
|
+
sweepStart = null;
|
|
166
170
|
cancelAnimationFrame(sweepFrame);
|
|
167
171
|
};
|
|
172
|
+
const step = (now) => {
|
|
173
|
+
if (sweepStart === null)
|
|
174
|
+
return;
|
|
175
|
+
const progress = Math.min(1, (now - sweepStart) / SWEEP_MS);
|
|
176
|
+
const along = progress * progress * (3 - 2 * progress);
|
|
177
|
+
const rise = Math.sin(Math.PI * progress);
|
|
178
|
+
show(-0.05 + along * 1.1, 0.22 + along * 0.56, rise ** 0.6 * 0.95, rise * MAX_TILT_DEGREES * 0.3, -Math.sin(2 * Math.PI * along) * ((SWEEP_TURN * 180) / Math.PI));
|
|
179
|
+
if (progress < 1)
|
|
180
|
+
sweepFrame = requestAnimationFrame(step);
|
|
181
|
+
else {
|
|
182
|
+
sweepStart = null;
|
|
183
|
+
rest();
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
const follow = () => {
|
|
187
|
+
const at = pointer;
|
|
188
|
+
pointer = null;
|
|
189
|
+
if (!at)
|
|
190
|
+
return;
|
|
191
|
+
const near = approach(card.getBoundingClientRect(), at.clientX, at.clientY);
|
|
192
|
+
if (near.hover > 0)
|
|
193
|
+
stopSweep();
|
|
194
|
+
if (sweepStart !== null)
|
|
195
|
+
return;
|
|
196
|
+
if (near.hover === 0)
|
|
197
|
+
return rest();
|
|
198
|
+
const x = Math.min(1, Math.max(0, (near.x + 1) / 2));
|
|
199
|
+
const y = Math.min(1, Math.max(0, (near.y + 1) / 2));
|
|
200
|
+
show(x, y, near.hover, (0.5 - y) * 2 * MAX_TILT_DEGREES * near.hover, (x - 0.5) * 2 * MAX_TILT_DEGREES * near.hover);
|
|
201
|
+
};
|
|
202
|
+
const play = () => {
|
|
203
|
+
cancelAnimationFrame(sweepFrame);
|
|
204
|
+
cancelAnimationFrame(pointerFrame);
|
|
205
|
+
if (!playing())
|
|
206
|
+
return;
|
|
207
|
+
if (sweepStart !== null)
|
|
208
|
+
sweepFrame = requestAnimationFrame(step);
|
|
209
|
+
if (pointer)
|
|
210
|
+
pointerFrame = requestAnimationFrame(follow);
|
|
211
|
+
};
|
|
168
212
|
const sweep = () => {
|
|
169
213
|
if (motion.matches)
|
|
170
214
|
return;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const start = performance.now();
|
|
174
|
-
const step = (now) => {
|
|
175
|
-
const progress = Math.min(1, (now - start) / SWEEP_MS);
|
|
176
|
-
const along = progress * progress * (3 - 2 * progress);
|
|
177
|
-
const rise = Math.sin(Math.PI * progress);
|
|
178
|
-
show(-0.05 + along * 1.1, 0.22 + along * 0.56, rise ** 0.6 * 0.95, rise * MAX_TILT_DEGREES * 0.3, -Math.sin(2 * Math.PI * along) * ((SWEEP_TURN * 180) / Math.PI));
|
|
179
|
-
if (progress < 1)
|
|
180
|
-
sweepFrame = requestAnimationFrame(step);
|
|
181
|
-
else {
|
|
182
|
-
sweeping = false;
|
|
183
|
-
rest();
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
sweepFrame = requestAnimationFrame(step);
|
|
215
|
+
sweepStart = performance.now();
|
|
216
|
+
play();
|
|
187
217
|
};
|
|
188
218
|
const move = (event) => {
|
|
189
219
|
if (!event.isPrimary)
|
|
190
220
|
return;
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
return;
|
|
196
|
-
cancelAnimationFrame(frame.current);
|
|
197
|
-
frame.current = requestAnimationFrame(() => {
|
|
198
|
-
if (near.hover === 0)
|
|
199
|
-
return rest();
|
|
200
|
-
const x = Math.min(1, Math.max(0, (near.x + 1) / 2));
|
|
201
|
-
const y = Math.min(1, Math.max(0, (near.y + 1) / 2));
|
|
202
|
-
show(x, y, near.hover, (0.5 - y) * 2 * MAX_TILT_DEGREES * near.hover, (x - 0.5) * 2 * MAX_TILT_DEGREES * near.hover);
|
|
203
|
-
});
|
|
221
|
+
pointer = { clientX: event.clientX, clientY: event.clientY };
|
|
222
|
+
cancelAnimationFrame(pointerFrame);
|
|
223
|
+
if (playing())
|
|
224
|
+
pointerFrame = requestAnimationFrame(follow);
|
|
204
225
|
};
|
|
205
226
|
const leave = () => {
|
|
206
|
-
if (
|
|
227
|
+
if (sweepStart === null)
|
|
207
228
|
rest();
|
|
208
229
|
};
|
|
209
230
|
window.addEventListener("pointermove", move, { passive: true });
|
|
210
231
|
document.documentElement.addEventListener("pointerleave", leave);
|
|
232
|
+
document.addEventListener("visibilitychange", play);
|
|
233
|
+
const visibility = onScreen
|
|
234
|
+
? undefined
|
|
235
|
+
: new IntersectionObserver((entries) => {
|
|
236
|
+
onScreen = entries.at(-1)?.isIntersecting ?? false;
|
|
237
|
+
play();
|
|
238
|
+
});
|
|
239
|
+
visibility?.observe(card);
|
|
211
240
|
sweepRef.current = sweep;
|
|
212
241
|
sweep();
|
|
213
242
|
return () => {
|
|
214
243
|
window.removeEventListener("pointermove", move);
|
|
215
244
|
document.documentElement.removeEventListener("pointerleave", leave);
|
|
245
|
+
document.removeEventListener("visibilitychange", play);
|
|
246
|
+
visibility?.disconnect();
|
|
216
247
|
stopSweep();
|
|
217
|
-
cancelAnimationFrame(
|
|
248
|
+
cancelAnimationFrame(pointerFrame);
|
|
218
249
|
sweepRef.current = () => { };
|
|
219
250
|
rest();
|
|
220
251
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hive-scene.d.ts","sourceRoot":"","sources":["../../src/components/hive-scene.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,MAAM,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,mFAAmF;AACnF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IAC9B,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IAC3E,IAAI,EAAE,aAAa,CAAC;IACpB,qFAAqF;IACrF,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,kFAAkF;IAClF,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,mFAAmF;IACnF,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,QAAQ,CAAC;IAC7D,iEAAiE;IACjE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AAmLF;;;;;;;;;;;;;GAaG;AACH,iBAAS,SAAS,CAAC,EACjB,IAAI,EACJ,MAAkB,EAClB,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,MAAM,EACN,KAAK,EACL,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"hive-scene.d.ts","sourceRoot":"","sources":["../../src/components/hive-scene.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,MAAM,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,mFAAmF;AACnF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IAC9B,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IAC3E,IAAI,EAAE,aAAa,CAAC;IACpB,qFAAqF;IACrF,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,kFAAkF;IAClF,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,mFAAmF;IACnF,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,QAAQ,CAAC;IAC7D,iEAAiE;IACjE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AAmLF;;;;;;;;;;;;;GAaG;AACH,iBAAS,SAAS,CAAC,EACjB,IAAI,EACJ,MAAkB,EAClB,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,MAAM,EACN,KAAK,EACL,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,cAAc,qBA8PhB;AAED,2DAA2D;AAC3D,iBAAS,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,qBAM9E;AAED,iEAAiE;AACjE,iBAAS,QAAQ,CAAC,EAChB,QAAQ,EACR,EAAE,EACF,IAAa,GACd,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACzB,qBAMA;AAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -239,18 +239,25 @@ function HiveScene({ mode, column = "default", logo, picture, work, chrome, labe
|
|
|
239
239
|
drawComb(comb, width, height);
|
|
240
240
|
context = sizeCanvas(flow, width, height);
|
|
241
241
|
};
|
|
242
|
+
const observeLayout = (onLayout) => {
|
|
243
|
+
const resize = new ResizeObserver(onLayout);
|
|
244
|
+
resize.observe(scene);
|
|
245
|
+
if (wordsColumn)
|
|
246
|
+
resize.observe(wordsColumn);
|
|
247
|
+
return resize;
|
|
248
|
+
};
|
|
242
249
|
place();
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (wordsColumn)
|
|
246
|
-
resize.observe(wordsColumn);
|
|
247
|
-
if (still)
|
|
250
|
+
if (still) {
|
|
251
|
+
const resize = observeLayout(place);
|
|
248
252
|
return () => resize.disconnect();
|
|
253
|
+
}
|
|
249
254
|
const colours = orbRefs.current.map((canvas) => canvas ? getComputedStyle(canvas).color : "white");
|
|
250
255
|
const particles = [];
|
|
251
256
|
let frame = 0;
|
|
252
|
-
let last =
|
|
257
|
+
let last = null;
|
|
253
258
|
let nextSpawn = 0;
|
|
259
|
+
// A browser that cannot tell whether the scene is seen shows it as seen.
|
|
260
|
+
let onScreen = typeof IntersectionObserver === "undefined";
|
|
254
261
|
const spawn = () => {
|
|
255
262
|
const source = Math.floor(Math.random() * AGENTS.length);
|
|
256
263
|
const seat = seats[source];
|
|
@@ -287,8 +294,11 @@ function HiveScene({ mode, column = "default", logo, picture, work, chrome, labe
|
|
|
287
294
|
trail: [],
|
|
288
295
|
});
|
|
289
296
|
};
|
|
297
|
+
const flowing = () => context !== null && !reduced.matches && seats.some((seat) => seat !== null);
|
|
298
|
+
const running = () => onScreen && !document.hidden && (particles.length > 0 || flowing());
|
|
290
299
|
const tick = (now) => {
|
|
291
|
-
|
|
300
|
+
frame = 0;
|
|
301
|
+
const dt = last === null ? 0 : Math.min(0.05, (now - last) / 1000);
|
|
292
302
|
last = now;
|
|
293
303
|
nextSpawn -= dt;
|
|
294
304
|
const paint = context;
|
|
@@ -322,12 +332,40 @@ function HiveScene({ mode, column = "default", logo, picture, work, chrome, labe
|
|
|
322
332
|
}
|
|
323
333
|
paint.globalAlpha = 1;
|
|
324
334
|
}
|
|
335
|
+
if (running())
|
|
336
|
+
frame = requestAnimationFrame(tick);
|
|
337
|
+
};
|
|
338
|
+
const play = () => {
|
|
339
|
+
if (!running()) {
|
|
340
|
+
cancelAnimationFrame(frame);
|
|
341
|
+
frame = 0;
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (frame)
|
|
345
|
+
return;
|
|
346
|
+
last = null;
|
|
325
347
|
frame = requestAnimationFrame(tick);
|
|
326
348
|
};
|
|
327
|
-
|
|
349
|
+
const resize = observeLayout(() => {
|
|
350
|
+
place();
|
|
351
|
+
play();
|
|
352
|
+
});
|
|
353
|
+
const visibility = onScreen
|
|
354
|
+
? undefined
|
|
355
|
+
: new IntersectionObserver((entries) => {
|
|
356
|
+
onScreen = entries.at(-1)?.isIntersecting ?? false;
|
|
357
|
+
play();
|
|
358
|
+
});
|
|
359
|
+
visibility?.observe(scene);
|
|
360
|
+
document.addEventListener("visibilitychange", play);
|
|
361
|
+
reduced.addEventListener("change", play);
|
|
362
|
+
play();
|
|
328
363
|
return () => {
|
|
329
364
|
cancelAnimationFrame(frame);
|
|
330
365
|
resize.disconnect();
|
|
366
|
+
visibility?.disconnect();
|
|
367
|
+
document.removeEventListener("visibilitychange", play);
|
|
368
|
+
reduced.removeEventListener("change", play);
|
|
331
369
|
};
|
|
332
370
|
}, [mode, still, wordsColumn]);
|
|
333
371
|
return (_jsxs("div", { ...props, className: cn("nc-hive dark", className), "data-mode": mode, "data-slot": "hive-scene", ref: sceneRef, ...(mode === "loading" ? { "aria-label": label, role: "status" } : {}), children: [chrome, _jsx("img", { alt: logo.label, className: "nc-hive-logo", "data-slot": "hive-logo", src: logo.src }), picture, _jsx("canvas", { "aria-hidden": "true", className: "nc-hive-comb", ref: combRef }), _jsx("canvas", { "aria-hidden": "true", className: "nc-hive-flow", ref: flowRef }), still
|
|
@@ -6,9 +6,9 @@ import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon } fro
|
|
|
6
6
|
import { Button } from "./button.js";
|
|
7
7
|
import { cn } from "../lib/utils.js";
|
|
8
8
|
const viewportAxis = {
|
|
9
|
-
y: "overflow-x-hidden! [mask-image:linear-gradient(to_bottom,transparent,
|
|
10
|
-
x: "overflow-y-hidden! [mask-image:linear-gradient(to_right,transparent,
|
|
11
|
-
both: "[
|
|
9
|
+
y: "overflow-x-hidden! data-overflow-y-start:[mask-image:linear-gradient(to_bottom,transparent,black_2.5rem)] data-overflow-y-end:[mask-image:linear-gradient(to_top,transparent,black_2.5rem)] data-overflow-y-start:data-overflow-y-end:[mask-image:linear-gradient(to_bottom,transparent,black_2.5rem,black_calc(100%_-_2.5rem),transparent)]",
|
|
10
|
+
x: "overflow-y-hidden! data-overflow-x-start:[mask-image:linear-gradient(to_right,transparent,black_2.5rem)] data-overflow-x-end:[mask-image:linear-gradient(to_left,transparent,black_2.5rem)] data-overflow-x-start:data-overflow-x-end:[mask-image:linear-gradient(to_right,transparent,black_2.5rem,black_calc(100%_-_2.5rem),transparent)]",
|
|
11
|
+
both: "[--fade-x:linear-gradient(black,black)] [--fade-y:linear-gradient(black,black)] data-overflow-x-start:[--fade-x:linear-gradient(to_right,transparent,black_2.5rem)] data-overflow-x-end:[--fade-x:linear-gradient(to_left,transparent,black_2.5rem)] data-overflow-x-start:data-overflow-x-end:[--fade-x:linear-gradient(to_right,transparent,black_2.5rem,black_calc(100%_-_2.5rem),transparent)] data-overflow-y-start:[--fade-y:linear-gradient(to_bottom,transparent,black_2.5rem)] data-overflow-y-end:[--fade-y:linear-gradient(to_top,transparent,black_2.5rem)] data-overflow-y-start:data-overflow-y-end:[--fade-y:linear-gradient(to_bottom,transparent,black_2.5rem,black_calc(100%_-_2.5rem),transparent)] [mask-composite:intersect] [mask-image:var(--fade-y),var(--fade-x)]",
|
|
12
12
|
};
|
|
13
13
|
function scrollToNeighbour(viewport, content, axis, direction) {
|
|
14
14
|
const edges = (box) => axis === "y" ? { start: box.top, end: box.bottom } : { start: box.left, end: box.right };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/components/table.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,
|
|
1
|
+
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/components/table.tsx"],"names":[],"mappings":"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"}
|
package/dist/components/table.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { cn } from "../lib/utils.js";
|
|
4
|
-
import { DetailFacts } from "../internal/table-compact-line.js";
|
|
4
|
+
import { DetailFacts, detailFactsLine, detailFactsWrap, } from "../internal/table-compact-line.js";
|
|
5
5
|
import { tableCompactLayouts } from "./table-layouts.js";
|
|
6
6
|
import { titleWhenCut } from "../internal/title-when-cut.js";
|
|
7
7
|
/**
|
|
@@ -86,7 +86,7 @@ function TableCell({ className, ...props }) {
|
|
|
86
86
|
}
|
|
87
87
|
function TableDetailRow({ colSpan, facts, layout = "standard", }) {
|
|
88
88
|
const wraps = facts.some((fact) => fact.wraps);
|
|
89
|
-
return (_jsx(TableRow, { "data-slot": "table-detail-row", className: cn("h-auto!", tableCompactLayouts[layout].details), children: _jsx(TableCell, { colSpan: colSpan, className: "pt-0! pb-3! whitespace-normal text-muted-foreground last:text-left", children: _jsx("div", { className: cn("relative min-w-0 in-[[data-slot=table-record-group]:has([data-slot=record-identity])]:pl-12
|
|
89
|
+
return (_jsx(TableRow, { "data-slot": "table-detail-row", className: cn("h-auto!", tableCompactLayouts[layout].details), children: _jsx(TableCell, { colSpan: colSpan, className: "pt-0! pb-3! whitespace-normal text-muted-foreground last:text-left", children: _jsx("div", { className: cn("relative min-w-0 in-[[data-slot=table-record-group]:has([data-slot=record-identity])]:pl-12", detailFactsLine, wraps ? ["break-words", detailFactsWrap] : "w-0 min-w-full truncate"), "data-slot": "table-detail-line", onFocus: wraps ? undefined : titleWhenCut, onPointerEnter: wraps ? undefined : titleWhenCut, children: _jsx(DetailFacts, { facts: facts }) }) }) }));
|
|
90
90
|
}
|
|
91
91
|
function TableCaption({ className, ...props }) {
|
|
92
92
|
return (_jsx("caption", { "data-slot": "table-caption", className: cn("mt-4 text-sm text-muted-foreground", className), ...props }));
|
|
@@ -10,6 +10,10 @@ export declare function stateSpeed(state: AgentOrbState, form: AgentOrbFigure, a
|
|
|
10
10
|
gestureAge: (age: number) => number;
|
|
11
11
|
settle: (age: number, delay?: number) => number;
|
|
12
12
|
}): number;
|
|
13
|
+
export declare const ORB_FRAME_RATE: {
|
|
14
|
+
readonly resting: 15;
|
|
15
|
+
readonly busy: 30;
|
|
16
|
+
};
|
|
13
17
|
/**
|
|
14
18
|
* Reduced motion turns movement off and keeps opacity and colour, so a
|
|
15
19
|
* thinking or working orb breathes between full ink and 0.45 over 1.6 s,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-orb-motion.d.ts","sourceRoot":"","sources":["../../src/internal/agent-orb-motion.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAc7F,wBAAgB,WAAW,CAAC,IAAI,EAAE,cAAc,UAE/C;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,cAAc,EACpB,GAAG,SAAI,EACP,MAAM;;;;;;
|
|
1
|
+
{"version":3,"file":"agent-orb-motion.d.ts","sourceRoot":"","sources":["../../src/internal/agent-orb-motion.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAc7F,wBAAgB,WAAW,CAAC,IAAI,EAAE,cAAc,UAE/C;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,cAAc,EACpB,GAAG,SAAI,EACP,MAAM;;;;;;sBA6Cc,MAAM;kBACV,MAAM;CA9CA,UAWvB;AAED,eAAO,MAAM,cAAc;;;CAAqC,CAAC;AAKjE;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,UAIlE;AAED,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,mBAAmB;;;;;;sBAgBnC,MAAM;kBACV,MAAM;EAGvB;AAUD,wBAAgB,UAAU,CACxB,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,MAAM,EACX,MAAM;;;;;;sBAjBc,MAAM;kBACV,MAAM;CAgBA,EACtB,OAAO,UAAQ;;;;;;EA+ChB;AA6ED,wBAAgB,WAAW,CACzB,OAAO,EAAE,wBAAwB,EACjC,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,KAAK,EAAE,MAAM,GAAG,OAAO;AACvB,mFAAmF;AACnF,GAAG,SAAI,EACP,MAAM;;;;;;sBAxJc,MAAM;kBACV,MAAM;CAuJA,EACtB,WAAW,SAA8B,QA4E1C"}
|
|
@@ -24,6 +24,7 @@ export function stateSpeed(state, form, age = 0, timing = defaultTiming) {
|
|
|
24
24
|
};
|
|
25
25
|
return speed[state] * nativeSpeed(form);
|
|
26
26
|
}
|
|
27
|
+
export const ORB_FRAME_RATE = { resting: 15, busy: 30 };
|
|
27
28
|
/** The breath's period, in seconds. */
|
|
28
29
|
const BREATH_SECONDS = 1.6;
|
|
29
30
|
/**
|