@cryptiklemur/lattice 1.9.0 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from "react";
|
|
2
|
+
import { Maximize2, Minimize2 } from "lucide-react";
|
|
1
3
|
import type { ReactNode } from "react";
|
|
2
4
|
|
|
3
5
|
interface ChartCardProps {
|
|
@@ -7,16 +9,156 @@ interface ChartCardProps {
|
|
|
7
9
|
action?: ReactNode;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
|
-
export function ChartCard(
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
export function ChartCard(props: ChartCardProps) {
|
|
13
|
+
var [isFullscreen, setIsFullscreen] = useState(false);
|
|
14
|
+
var cardRef = useRef<HTMLDivElement>(null);
|
|
15
|
+
var [originRect, setOriginRect] = useState<DOMRect | null>(null);
|
|
16
|
+
var [animating, setAnimating] = useState(false);
|
|
17
|
+
|
|
18
|
+
function openFullscreen() {
|
|
19
|
+
if (cardRef.current) {
|
|
20
|
+
setOriginRect(cardRef.current.getBoundingClientRect());
|
|
21
|
+
}
|
|
22
|
+
setAnimating(true);
|
|
23
|
+
setIsFullscreen(true);
|
|
24
|
+
requestAnimationFrame(function () {
|
|
25
|
+
requestAnimationFrame(function () {
|
|
26
|
+
setAnimating(false);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function closeFullscreen() {
|
|
32
|
+
setAnimating(true);
|
|
33
|
+
setTimeout(function () {
|
|
34
|
+
setIsFullscreen(false);
|
|
35
|
+
setAnimating(false);
|
|
36
|
+
setOriginRect(null);
|
|
37
|
+
}, 250);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
useEffect(function () {
|
|
41
|
+
if (!isFullscreen) return;
|
|
42
|
+
function handleKeyDown(e: KeyboardEvent) {
|
|
43
|
+
if (e.key === "Escape") closeFullscreen();
|
|
44
|
+
}
|
|
45
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
46
|
+
return function () { document.removeEventListener("keydown", handleKeyDown); };
|
|
47
|
+
}, [isFullscreen]);
|
|
48
|
+
|
|
49
|
+
useEffect(function () {
|
|
50
|
+
if (isFullscreen) {
|
|
51
|
+
document.body.style.overflow = "hidden";
|
|
52
|
+
} else {
|
|
53
|
+
document.body.style.overflow = "";
|
|
54
|
+
}
|
|
55
|
+
return function () { document.body.style.overflow = ""; };
|
|
56
|
+
}, [isFullscreen]);
|
|
57
|
+
|
|
58
|
+
var cardContent = (
|
|
59
|
+
<>
|
|
13
60
|
<div className="flex items-center justify-between mb-4">
|
|
14
61
|
<span className="text-[10px] font-mono font-bold uppercase tracking-widest text-base-content/35">
|
|
15
|
-
{title}
|
|
62
|
+
{props.title}
|
|
16
63
|
</span>
|
|
17
|
-
|
|
64
|
+
<div className="flex items-center gap-2">
|
|
65
|
+
{props.action && <div>{props.action}</div>}
|
|
66
|
+
<button
|
|
67
|
+
onClick={function () {
|
|
68
|
+
if (isFullscreen) {
|
|
69
|
+
closeFullscreen();
|
|
70
|
+
} else {
|
|
71
|
+
openFullscreen();
|
|
72
|
+
}
|
|
73
|
+
}}
|
|
74
|
+
className="text-base-content/20 hover:text-base-content/50 transition-colors cursor-pointer p-0.5 rounded hover:bg-base-content/5"
|
|
75
|
+
aria-label={isFullscreen ? "Exit fullscreen" : "Fullscreen"}
|
|
76
|
+
title={isFullscreen ? "Exit fullscreen (Esc)" : "Fullscreen"}
|
|
77
|
+
>
|
|
78
|
+
{isFullscreen ? <Minimize2 size={12} /> : <Maximize2 size={12} />}
|
|
79
|
+
</button>
|
|
80
|
+
</div>
|
|
18
81
|
</div>
|
|
19
|
-
{children}
|
|
82
|
+
{props.children}
|
|
83
|
+
</>
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
if (isFullscreen) {
|
|
87
|
+
var overlayStyle: React.CSSProperties = {
|
|
88
|
+
transition: "opacity 250ms cubic-bezier(0.4, 0, 0.2, 1)",
|
|
89
|
+
opacity: animating ? 0 : 1,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
var modalStyle: React.CSSProperties = {
|
|
93
|
+
transition: "all 250ms cubic-bezier(0.4, 0, 0.2, 1)",
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
if (animating && originRect) {
|
|
97
|
+
modalStyle.position = "fixed";
|
|
98
|
+
modalStyle.top = originRect.top + "px";
|
|
99
|
+
modalStyle.left = originRect.left + "px";
|
|
100
|
+
modalStyle.width = originRect.width + "px";
|
|
101
|
+
modalStyle.height = originRect.height + "px";
|
|
102
|
+
modalStyle.opacity = 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<>
|
|
107
|
+
<div
|
|
108
|
+
ref={cardRef}
|
|
109
|
+
className={"rounded-xl border border-base-content/8 bg-base-300/50 p-4 invisible " + (props.className || "")}
|
|
110
|
+
>
|
|
111
|
+
{cardContent}
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<div
|
|
115
|
+
className="fixed inset-0 z-[9998] bg-black/60 backdrop-blur-sm"
|
|
116
|
+
style={overlayStyle}
|
|
117
|
+
onClick={closeFullscreen}
|
|
118
|
+
/>
|
|
119
|
+
<div
|
|
120
|
+
className="fixed inset-0 z-[9999] flex items-center justify-center p-8"
|
|
121
|
+
style={{ pointerEvents: "none" }}
|
|
122
|
+
>
|
|
123
|
+
<div
|
|
124
|
+
className="w-full max-w-[1100px] rounded-2xl border border-base-content/10 bg-base-200 shadow-2xl overflow-hidden flex flex-col"
|
|
125
|
+
style={Object.assign(
|
|
126
|
+
{ maxHeight: "65vh", pointerEvents: "auto" as const },
|
|
127
|
+
animating
|
|
128
|
+
? { opacity: 0, transform: "scale(0.95)", transition: "all 250ms cubic-bezier(0.4, 0, 0.2, 1)" }
|
|
129
|
+
: { opacity: 1, transform: "scale(1)", transition: "all 250ms cubic-bezier(0.4, 0, 0.2, 1)" }
|
|
130
|
+
)}
|
|
131
|
+
>
|
|
132
|
+
<div className="flex items-center justify-between px-6 py-3 border-b border-base-content/8 flex-shrink-0">
|
|
133
|
+
<span className="text-[12px] font-mono font-bold uppercase tracking-widest text-base-content/50">
|
|
134
|
+
{props.title}
|
|
135
|
+
</span>
|
|
136
|
+
<div className="flex items-center gap-3">
|
|
137
|
+
{props.action && <div>{props.action}</div>}
|
|
138
|
+
<button
|
|
139
|
+
onClick={closeFullscreen}
|
|
140
|
+
className="text-base-content/30 hover:text-base-content/60 transition-colors cursor-pointer p-1 rounded-lg hover:bg-base-content/5"
|
|
141
|
+
aria-label="Exit fullscreen"
|
|
142
|
+
>
|
|
143
|
+
<Minimize2 size={16} />
|
|
144
|
+
</button>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
<div className="flex-1 p-6 overflow-auto min-h-0 [&_.recharts-responsive-container]:!h-full [&_.recharts-responsive-container]:!min-h-[350px]">
|
|
148
|
+
{props.children}
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
</>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<div
|
|
158
|
+
ref={cardRef}
|
|
159
|
+
className={"rounded-xl border border-base-content/8 bg-base-300/50 p-4 " + (props.className || "")}
|
|
160
|
+
>
|
|
161
|
+
{cardContent}
|
|
20
162
|
</div>
|
|
21
163
|
);
|
|
22
164
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cryptiklemur/lattice",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.1",
|
|
4
4
|
"description": "Multi-machine agentic dashboard for Claude Code. Monitor sessions, manage MCP servers and skills, orchestrate across mesh-networked nodes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Aaron Scherer <me@aaronscherer.me>",
|