@ultrst-armada/floks 1.2.1 → 1.2.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultrst-armada/floks",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -14,18 +14,6 @@ import {
14
14
  skipoDarkTheme,
15
15
  useMonaco
16
16
  } from "./chunk-QTTWWBNN.js";
17
- import {
18
- Tile,
19
- TileCreateButton,
20
- TileGrid,
21
- useTileMenu
22
- } from "./chunk-SA3JADUG.js";
23
- import {
24
- PredictiveGhostNodeCard,
25
- PredictiveHudToolbar,
26
- PredictiveLayer2D,
27
- usePredictiveGraph2D
28
- } from "./chunk-OOTTFWXA.js";
29
17
  import {
30
18
  BIOME_CONFIGS,
31
19
  COORD_SCALE,
@@ -42,6 +30,18 @@ import {
42
30
  useCanvas2DCoordinates,
43
31
  useCanvas2DMagnetic
44
32
  } from "./chunk-XVAHT5WE.js";
33
+ import {
34
+ Tile,
35
+ TileCreateButton,
36
+ TileGrid,
37
+ useTileMenu
38
+ } from "./chunk-SA3JADUG.js";
39
+ import {
40
+ PredictiveGhostNodeCard,
41
+ PredictiveHudToolbar,
42
+ PredictiveLayer2D,
43
+ usePredictiveGraph2D
44
+ } from "./chunk-OOTTFWXA.js";
45
45
  import {
46
46
  NODE_CARD_WIDTH,
47
47
  Node2DBase,
@@ -0,0 +1,266 @@
1
+ import {
2
+ BaseInput
3
+ } from "./chunk-W42SJGOJ.js";
4
+ import {
5
+ BaseButton
6
+ } from "./chunk-A2CDQISJ.js";
7
+
8
+ // src/components/auth/AuthPage.tsx
9
+ import { useState } from "react";
10
+ import { LogIn, UserPlus, Eye, EyeOff, Shield, ArrowRight, AlertCircle } from "lucide-react";
11
+ import { jsx, jsxs } from "react/jsx-runtime";
12
+ var AuthPage = ({
13
+ appName = "SKIPO",
14
+ appSubtitle = "WORKSPACE",
15
+ footerText,
16
+ onLogin,
17
+ onRegister,
18
+ onSuccess,
19
+ onSwitchToAdmin
20
+ }) => {
21
+ const [mode, setMode] = useState("login");
22
+ const [name, setName] = useState("");
23
+ const [email, setEmail] = useState("");
24
+ const [password, setPassword] = useState("");
25
+ const [showPassword, setShowPassword] = useState(false);
26
+ const [loading, setLoading] = useState(false);
27
+ const [error, setError] = useState(null);
28
+ const submit = async (e) => {
29
+ e.preventDefault();
30
+ setError(null);
31
+ const cleanEmail = email.trim();
32
+ if (!cleanEmail) return setError("Email address is required.");
33
+ if (!password) return setError("Password is required.");
34
+ if (mode === "register" && !name.trim()) return setError("Please enter your full name or display name.");
35
+ if (mode === "register" && password.length < 4) return setError("Password must be at least 4 characters long.");
36
+ setLoading(true);
37
+ try {
38
+ const result = mode === "login" ? await onLogin(cleanEmail, password) : await onRegister({ name: name.trim(), email: cleanEmail, password });
39
+ if (!result.success) throw new Error(result.error || "Authentication failed.");
40
+ onSuccess?.(result);
41
+ } catch (err) {
42
+ setError(err?.message || "An unexpected error occurred.");
43
+ } finally {
44
+ setLoading(false);
45
+ }
46
+ };
47
+ return /* @__PURE__ */ jsxs("div", { className: "min-h-screen w-full bg-[var(--skipo-bg)] text-[var(--skipo-text)] font-mono flex flex-col justify-between select-none", children: [
48
+ /* @__PURE__ */ jsxs("header", { className: "border-b-2 border-[var(--skipo-border-color)] bg-[var(--skipo-surface)] px-6 py-3.5 flex items-center justify-between", children: [
49
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
50
+ /* @__PURE__ */ jsx("div", { className: "w-8 h-8 bg-[var(--skipo-accent)] text-black font-black flex items-center justify-center border border-[var(--skipo-border-color)]", children: "\u25B2" }),
51
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
52
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-black uppercase tracking-wider", children: appName }),
53
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-[var(--skipo-text-muted)] font-bold", children: appSubtitle })
54
+ ] }) })
55
+ ] }),
56
+ onSwitchToAdmin && /* @__PURE__ */ jsxs("button", { type: "button", onClick: onSwitchToAdmin, className: "px-3 py-1.5 text-xs font-black uppercase tracking-wider border-2 border-[#D4AF37] bg-[#D4AF37]/10 text-[#D4AF37] hover:bg-[#D4AF37] hover:text-black flex items-center gap-1.5 shadow-[2px_2px_0px_#D4AF37]", children: [
57
+ /* @__PURE__ */ jsx(Shield, { size: 13 }),
58
+ " ADMIN LOGIN ",
59
+ /* @__PURE__ */ jsx(ArrowRight, { size: 13 })
60
+ ] })
61
+ ] }),
62
+ /* @__PURE__ */ jsx("main", { className: "flex-1 flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-md border-2 border-[var(--skipo-border-color)] bg-[var(--skipo-surface)] shadow-[6px_6px_0px_var(--skipo-border-color)] p-6", children: [
63
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2 mb-6 border-b border-[var(--skipo-border-color)] pb-3", children: ["login", "register"].map((next) => /* @__PURE__ */ jsxs(
64
+ "button",
65
+ {
66
+ type: "button",
67
+ onClick: () => {
68
+ setMode(next);
69
+ setError(null);
70
+ },
71
+ className: `py-2 text-xs font-black uppercase tracking-wider flex items-center justify-center gap-1.5 border ${mode === next ? "bg-[var(--skipo-accent)] text-black border-[var(--skipo-border-color)]" : "bg-[var(--skipo-bg)] text-[var(--skipo-text-muted)] border-transparent"}`,
72
+ children: [
73
+ next === "login" ? /* @__PURE__ */ jsx(LogIn, { size: 13 }) : /* @__PURE__ */ jsx(UserPlus, { size: 13 }),
74
+ next === "login" ? "SIGN IN" : "CREATE ACCOUNT"
75
+ ]
76
+ },
77
+ next
78
+ )) }),
79
+ /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
80
+ /* @__PURE__ */ jsx("h2", { className: "text-sm font-black uppercase tracking-wider", children: mode === "login" ? "WORKSPACE SIGN IN" : "NEW DEVELOPER ACCOUNT" }),
81
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--skipo-text-muted)] mt-1", children: mode === "login" ? "Sign in to access your workspaces and application control plane." : "Create an account to manage your workspaces and applications." })
82
+ ] }),
83
+ error && /* @__PURE__ */ jsxs("div", { className: "mb-4 p-3 border-2 border-red-500/80 bg-red-950/40 text-red-300 text-xs flex items-start gap-2", children: [
84
+ /* @__PURE__ */ jsx(AlertCircle, { size: 15, className: "shrink-0 mt-0.5" }),
85
+ /* @__PURE__ */ jsx("div", { children: error })
86
+ ] }),
87
+ /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "space-y-4", children: [
88
+ mode === "register" && /* @__PURE__ */ jsxs("div", { children: [
89
+ /* @__PURE__ */ jsx("label", { className: "block text-[11px] font-bold text-[var(--skipo-text-muted)] uppercase tracking-wider mb-1", children: "Full Name" }),
90
+ /* @__PURE__ */ jsx("input", { value: name, onChange: (e) => setName(e.target.value), placeholder: "e.g. Jane Developer", required: true, className: "w-full bg-[var(--skipo-bg)] border border-[var(--skipo-border-color)] focus:border-[var(--skipo-accent)] text-[var(--skipo-text)] text-xs px-3 py-2.5 outline-none font-mono" })
91
+ ] }),
92
+ /* @__PURE__ */ jsxs("div", { children: [
93
+ /* @__PURE__ */ jsx("label", { className: "block text-[11px] font-bold text-[var(--skipo-text-muted)] uppercase tracking-wider mb-1", children: "Email Address or Username" }),
94
+ /* @__PURE__ */ jsx("input", { value: email, onChange: (e) => setEmail(e.target.value), placeholder: "e.g. developer@example.com", autoComplete: "username", required: true, className: "w-full bg-[var(--skipo-bg)] border border-[var(--skipo-border-color)] focus:border-[var(--skipo-accent)] text-[var(--skipo-text)] text-xs px-3 py-2.5 outline-none font-mono" })
95
+ ] }),
96
+ /* @__PURE__ */ jsxs("div", { children: [
97
+ /* @__PURE__ */ jsx("label", { className: "block text-[11px] font-bold text-[var(--skipo-text-muted)] uppercase tracking-wider mb-1", children: "Password" }),
98
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
99
+ /* @__PURE__ */ jsx("input", { type: showPassword ? "text" : "password", value: password, onChange: (e) => setPassword(e.target.value), autoComplete: mode === "login" ? "current-password" : "new-password", required: true, className: "w-full bg-[var(--skipo-bg)] border border-[var(--skipo-border-color)] focus:border-[var(--skipo-accent)] text-[var(--skipo-text)] text-xs px-3 py-2.5 outline-none font-mono pr-10" }),
100
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setShowPassword((v) => !v), className: "absolute right-3 top-2.5 text-[var(--skipo-text-muted)]", children: showPassword ? /* @__PURE__ */ jsx(EyeOff, { size: 14 }) : /* @__PURE__ */ jsx(Eye, { size: 14 }) })
101
+ ] })
102
+ ] }),
103
+ /* @__PURE__ */ jsxs("button", { type: "submit", disabled: loading, className: "w-full py-2.5 bg-[var(--skipo-accent)] hover:opacity-90 text-black font-black text-xs uppercase tracking-wider flex items-center justify-center gap-2 shadow-[2px_2px_0px_#000] disabled:opacity-50", children: [
104
+ /* @__PURE__ */ jsx(LogIn, { size: 14 }),
105
+ " ",
106
+ loading ? "PROCESSING..." : mode === "login" ? "SIGN IN TO WORKSPACE" : "CREATE ACCOUNT"
107
+ ] })
108
+ ] }),
109
+ onSwitchToAdmin && /* @__PURE__ */ jsxs("div", { className: "mt-6 pt-4 border-t border-[var(--skipo-border-color)] flex items-center justify-between text-[11px] text-[var(--skipo-text-muted)]", children: [
110
+ /* @__PURE__ */ jsx("span", { children: "System Administrator?" }),
111
+ /* @__PURE__ */ jsxs("button", { type: "button", onClick: onSwitchToAdmin, className: "text-[#D4AF37] hover:underline font-bold flex items-center gap-1", children: [
112
+ "Switch to Admin Portal ",
113
+ /* @__PURE__ */ jsx(ArrowRight, { size: 11 })
114
+ ] })
115
+ ] })
116
+ ] }) }),
117
+ /* @__PURE__ */ jsx("footer", { className: "border-t border-[var(--skipo-border-color)] py-2 px-4 text-center text-[10px] text-[var(--skipo-text-muted)]", children: footerText || `${appName} WORKSPACE SYSTEM` })
118
+ ] });
119
+ };
120
+
121
+ // src/components/auth/LoginModal.tsx
122
+ import { useState as useState2 } from "react";
123
+ import { ArrowRight as ArrowRight2, ShieldCheck, AlertCircle as AlertCircle2 } from "lucide-react";
124
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
125
+ var LoginModal = ({
126
+ appName = "Ecosystem App",
127
+ onSuccess,
128
+ defaultEmail = ""
129
+ }) => {
130
+ const [email, setEmail] = useState2(defaultEmail);
131
+ const [password, setPassword] = useState2("");
132
+ const [isRegister, setIsRegister] = useState2(false);
133
+ const [name, setName] = useState2("");
134
+ const [loading, setLoading] = useState2(false);
135
+ const [error, setError] = useState2(null);
136
+ const handleSubmit = async (e) => {
137
+ e.preventDefault();
138
+ setError(null);
139
+ setLoading(true);
140
+ try {
141
+ const endpoint = isRegister ? "/api/auth/register" : "/api/auth/login";
142
+ const payload = isRegister ? { email, password, name } : { email, password };
143
+ const res = await fetch(endpoint, {
144
+ method: "POST",
145
+ headers: { "Content-Type": "application/json" },
146
+ body: JSON.stringify(payload)
147
+ });
148
+ const data = await res.json().catch(() => ({}));
149
+ if (!res.ok || !data.success || !data.user) {
150
+ throw new Error(data.error || "Authentication failed. Please verify credentials.");
151
+ }
152
+ const token = data.token || `usr_${Date.now()}`;
153
+ if (typeof window !== "undefined") {
154
+ localStorage.setItem("skipo_auth_token", token);
155
+ localStorage.setItem("skipo_user", JSON.stringify(data.user));
156
+ }
157
+ onSuccess(data.user, token);
158
+ } catch (err) {
159
+ setError(err.message || "Server error. Authentication failed.");
160
+ } finally {
161
+ setLoading(false);
162
+ }
163
+ };
164
+ return /* @__PURE__ */ jsx2(
165
+ "div",
166
+ {
167
+ className: "fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-xs font-mono p-4",
168
+ onWheel: (e) => e.stopPropagation(),
169
+ onPointerDown: (e) => e.stopPropagation(),
170
+ children: /* @__PURE__ */ jsxs2("div", { className: "w-full max-w-md p-6 border-2 border-[var(--skipo-border-color)] bg-[var(--skipo-surface)] text-[var(--skipo-text)] shadow-2xl rounded-lg space-y-4", children: [
171
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between pb-3 border-b border-[var(--skipo-border-color)]", children: [
172
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
173
+ /* @__PURE__ */ jsx2("div", { className: "w-7 h-7 bg-[var(--skipo-accent)] text-black font-black flex items-center justify-center text-xs rounded", children: "\u25B2" }),
174
+ /* @__PURE__ */ jsxs2("span", { className: "font-black text-sm tracking-wider uppercase text-[var(--skipo-text)]", children: [
175
+ appName,
176
+ " Authentication"
177
+ ] })
178
+ ] }),
179
+ /* @__PURE__ */ jsxs2("span", { className: "text-[9px] px-2 py-0.5 border border-emerald-500/50 bg-emerald-500/10 text-emerald-300 font-bold rounded flex items-center gap-1", children: [
180
+ /* @__PURE__ */ jsx2(ShieldCheck, { size: 10 }),
181
+ " SYSTEM DB"
182
+ ] })
183
+ ] }),
184
+ error && /* @__PURE__ */ jsxs2("div", { className: "p-3 border border-red-500/60 bg-red-500/10 text-red-300 text-xs rounded flex items-start gap-2", children: [
185
+ /* @__PURE__ */ jsx2(AlertCircle2, { size: 14, className: "shrink-0 mt-0.5" }),
186
+ /* @__PURE__ */ jsx2("span", { children: error })
187
+ ] }),
188
+ /* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, className: "space-y-3", children: [
189
+ isRegister && /* @__PURE__ */ jsxs2("div", { children: [
190
+ /* @__PURE__ */ jsx2("label", { className: "block text-[10px] font-black uppercase mb-1", children: "Full Name *" }),
191
+ /* @__PURE__ */ jsx2(
192
+ BaseInput,
193
+ {
194
+ type: "text",
195
+ value: name,
196
+ onChange: (e) => setName(e.target.value),
197
+ placeholder: "Developer Name",
198
+ required: isRegister
199
+ }
200
+ )
201
+ ] }),
202
+ /* @__PURE__ */ jsxs2("div", { children: [
203
+ /* @__PURE__ */ jsx2("label", { className: "block text-[10px] font-black uppercase mb-1", children: "Email Address *" }),
204
+ /* @__PURE__ */ jsx2(
205
+ BaseInput,
206
+ {
207
+ type: "email",
208
+ value: email,
209
+ onChange: (e) => setEmail(e.target.value),
210
+ placeholder: "user@example.com",
211
+ required: true
212
+ }
213
+ )
214
+ ] }),
215
+ /* @__PURE__ */ jsxs2("div", { children: [
216
+ /* @__PURE__ */ jsx2("label", { className: "block text-[10px] font-black uppercase mb-1", children: "Password *" }),
217
+ /* @__PURE__ */ jsx2(
218
+ BaseInput,
219
+ {
220
+ type: "password",
221
+ value: password,
222
+ onChange: (e) => setPassword(e.target.value),
223
+ placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
224
+ required: true
225
+ }
226
+ )
227
+ ] }),
228
+ /* @__PURE__ */ jsx2("div", { className: "pt-2", children: /* @__PURE__ */ jsxs2(
229
+ BaseButton,
230
+ {
231
+ variant: "accent",
232
+ size: "md",
233
+ type: "submit",
234
+ disabled: loading,
235
+ className: "w-full flex items-center justify-center gap-2",
236
+ children: [
237
+ /* @__PURE__ */ jsx2("span", { children: loading ? "AUTHENTICATING..." : isRegister ? "REGISTER & ENTER" : "SIGN IN" }),
238
+ /* @__PURE__ */ jsx2(ArrowRight2, { size: 14 })
239
+ ]
240
+ }
241
+ ) })
242
+ ] }),
243
+ /* @__PURE__ */ jsxs2("div", { className: "pt-2 border-t border-[var(--skipo-border-color)]/60 flex items-center justify-between text-[11px]", children: [
244
+ /* @__PURE__ */ jsx2(
245
+ "button",
246
+ {
247
+ type: "button",
248
+ onClick: () => {
249
+ setIsRegister(!isRegister);
250
+ setError(null);
251
+ },
252
+ className: "text-[var(--skipo-accent)] hover:underline cursor-pointer",
253
+ children: isRegister ? "Already have an account? Sign In" : "Create new account"
254
+ }
255
+ ),
256
+ /* @__PURE__ */ jsx2("span", { className: "text-[10px] text-[var(--skipo-text-muted)]", children: "ULTRST Identity" })
257
+ ] })
258
+ ] })
259
+ }
260
+ );
261
+ };
262
+
263
+ export {
264
+ AuthPage,
265
+ LoginModal
266
+ };
@@ -415,140 +415,166 @@ var WorkspaceSecondaryClonesPanel = ({ workspace, onClonesUpdated, onClose }) =>
415
415
 
416
416
  // src/components/workspace/WorkspaceTilesMenu.tsx
417
417
  import React5 from "react";
418
+ import { Search, Plus as Plus2, Trash2 as Trash22, Edit3, LogOut, ArrowRight, FolderOpen, Cloud as Cloud5, HardDrive as HardDrive5, FolderPlus, X } from "lucide-react";
418
419
  import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
419
420
  var WorkspaceTilesMenu = ({
420
421
  workspaces,
421
- activeWorkspaceId,
422
+ activeWorkspaceId = null,
423
+ currentUser = null,
422
424
  onSelectWorkspace,
423
425
  onCreateWorkspace,
426
+ onUpdateWorkspace,
424
427
  onDeleteWorkspace,
425
- appName = "app",
426
- currentUser = null,
427
- mode = "working-workspace"
428
+ onLogout,
429
+ appName = "APP",
430
+ mode = "working-workspace",
431
+ loading = false,
432
+ error = null,
433
+ onDismissError
428
434
  }) => {
429
- const [isCreating, setIsCreating] = React5.useState(false);
430
- const [newWsName, setNewWsName] = React5.useState("");
431
- const [storageConfig, setStorageConfig] = React5.useState({
432
- provider: "backblaze_b2",
433
- b2BucketName: "ultrst-apps"
434
- });
435
- const [activeTab, setActiveTab] = React5.useState("workspaces");
436
- const [activeWorkspaceForClones, setActiveWorkspaceForClones] = React5.useState(null);
437
- const activeWs = workspaces.find((w) => w.id === activeWorkspaceId);
438
- const handleCreate = async (e) => {
435
+ const [search, setSearch] = React5.useState("");
436
+ const [creating, setCreating] = React5.useState(false);
437
+ const [editing, setEditing] = React5.useState(null);
438
+ const [name, setName] = React5.useState("");
439
+ const [description, setDescription] = React5.useState("");
440
+ const [storage, setStorage] = React5.useState({ provider: "local_fs", localFolderName: "Local-Vault" });
441
+ const filtered = workspaces.filter(
442
+ (w) => w.name.toLowerCase().includes(search.toLowerCase()) || (w.description || "").toLowerCase().includes(search.toLowerCase())
443
+ );
444
+ const create = async (e) => {
439
445
  e.preventDefault();
440
- if (!newWsName.trim()) return;
441
- await onCreateWorkspace(newWsName.trim(), storageConfig);
442
- setNewWsName("");
443
- setIsCreating(false);
446
+ if (!name.trim()) return;
447
+ await onCreateWorkspace({ name: name.trim(), description: description.trim(), storage });
448
+ setName("");
449
+ setDescription("");
450
+ setCreating(false);
444
451
  };
445
- return /* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: "column", height: "100%", background: "var(--skipo-bg-app, #0f172a)", color: "var(--skipo-text-primary, #f8fafc)", padding: "24px" }, children: [
446
- /* @__PURE__ */ jsxs6("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }, children: [
447
- /* @__PURE__ */ jsxs6("div", { children: [
448
- /* @__PURE__ */ jsxs6("h2", { style: { fontSize: "18px", fontWeight: 600, margin: 0 }, children: [
449
- "Workspaces (",
450
- mode,
451
- ")"
452
+ const update = async (e) => {
453
+ e.preventDefault();
454
+ if (!editing || !onUpdateWorkspace || !name.trim()) return;
455
+ await onUpdateWorkspace(editing.id, { name: name.trim(), description: description.trim() });
456
+ setEditing(null);
457
+ };
458
+ const beginEdit = (w) => {
459
+ setEditing(w);
460
+ setName(w.name);
461
+ setDescription(w.description || "");
462
+ };
463
+ return /* @__PURE__ */ jsxs6("div", { className: "fixed inset-0 z-50 overflow-y-auto bg-black/85 p-4 sm:p-8 backdrop-blur-md font-mono flex flex-col items-center select-none", children: [
464
+ /* @__PURE__ */ jsxs6("div", { className: "w-full max-w-5xl my-4 sm:my-8", children: [
465
+ /* @__PURE__ */ jsxs6("div", { className: "p-4 sm:p-5 mb-5 border-2 border-[var(--skipo-border-color)] bg-[var(--skipo-surface)] rounded-lg shadow-2xl", children: [
466
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-4", children: [
467
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2.5", children: [
468
+ /* @__PURE__ */ jsx6("div", { className: "w-8 h-8 rounded bg-[var(--skipo-accent)] text-black font-black flex items-center justify-center text-sm", children: appName.slice(0, 2).toUpperCase() }),
469
+ /* @__PURE__ */ jsxs6("div", { children: [
470
+ /* @__PURE__ */ jsxs6("span", { className: "text-lg sm:text-xl font-black text-[var(--skipo-accent)] tracking-wider", children: [
471
+ appName.toUpperCase(),
472
+ " WORKSPACES"
473
+ ] }),
474
+ /* @__PURE__ */ jsxs6("div", { className: "text-[10px] text-[var(--skipo-text-muted)]", children: [
475
+ currentUser?.email || "user",
476
+ " \xB7 ",
477
+ mode
478
+ ] })
479
+ ] })
480
+ ] }),
481
+ onLogout && /* @__PURE__ */ jsxs6("button", { type: "button", onClick: onLogout, className: "text-xs flex items-center gap-1.5 text-red-400 hover:bg-red-500/20 border border-red-500/50 px-2.5 py-1.5 rounded", children: [
482
+ /* @__PURE__ */ jsx6(LogOut, { size: 14 }),
483
+ " LOGOUT"
484
+ ] })
452
485
  ] }),
453
- /* @__PURE__ */ jsxs6("span", { style: { fontSize: "12px", color: "var(--skipo-text-muted, #94a3b8)" }, children: [
454
- currentUser?.email || "user",
455
- " \u2022 ",
456
- appName
486
+ /* @__PURE__ */ jsxs6("div", { className: "mt-4 pt-4 border-t border-[var(--skipo-border-color)] flex flex-col sm:flex-row gap-3", children: [
487
+ /* @__PURE__ */ jsxs6("div", { className: "relative flex-1", children: [
488
+ /* @__PURE__ */ jsx6(Search, { size: 14, className: "absolute left-3 top-1/2 -translate-y-1/2 text-[var(--skipo-text-muted)]" }),
489
+ /* @__PURE__ */ jsx6("input", { value: search, onChange: (e) => setSearch(e.target.value), placeholder: "Search workspaces by name or description...", className: "w-full bg-[var(--skipo-bg)] border border-[var(--skipo-border-color)] rounded pl-9 pr-3 py-1.5 text-xs text-[var(--skipo-text)] outline-none focus:border-[var(--skipo-accent)]" })
490
+ ] }),
491
+ /* @__PURE__ */ jsxs6("button", { type: "button", onClick: () => {
492
+ setName("");
493
+ setDescription("");
494
+ setCreating(true);
495
+ }, className: "text-xs flex items-center justify-center gap-1.5 font-bold px-3 py-1.5 bg-[var(--skipo-accent)] text-black rounded", children: [
496
+ /* @__PURE__ */ jsx6(Plus2, { size: 14 }),
497
+ " NEW WORKSPACE"
498
+ ] })
457
499
  ] })
458
500
  ] }),
459
- /* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: "8px" }, children: [
460
- /* @__PURE__ */ jsx6(
461
- "button",
462
- {
463
- onClick: () => setActiveTab("workspaces"),
464
- style: { padding: "6px 14px", borderRadius: "6px", border: "1px solid #334155", background: activeTab === "workspaces" ? "#38bdf8" : "transparent", color: activeTab === "workspaces" ? "#0f172a" : "inherit", cursor: "pointer" },
465
- children: "List"
466
- }
467
- ),
468
- activeWs && /* @__PURE__ */ jsxs6(
469
- "button",
470
- {
471
- onClick: () => {
472
- setActiveWorkspaceForClones(activeWs);
473
- setActiveTab("clones");
474
- },
475
- style: { padding: "6px 14px", borderRadius: "6px", border: "1px solid #334155", background: activeTab === "clones" ? "#38bdf8" : "transparent", color: activeTab === "clones" ? "#0f172a" : "inherit", cursor: "pointer" },
476
- children: [
477
- "Clones (",
478
- activeWs.secondaryClones?.length || 0,
479
- ")"
480
- ]
481
- }
482
- ),
483
- /* @__PURE__ */ jsx6(
484
- "button",
485
- {
486
- onClick: () => setIsCreating(!isCreating),
487
- style: { padding: "6px 14px", borderRadius: "6px", border: "1px solid #38bdf8", background: isCreating ? "transparent" : "#38bdf8", color: isCreating ? "#38bdf8" : "#0f172a", cursor: "pointer" },
488
- children: isCreating ? "Cancel" : "+ New Workspace"
489
- }
490
- )
491
- ] })
492
- ] }),
493
- isCreating ? /* @__PURE__ */ jsxs6("form", { onSubmit: handleCreate, style: { display: "flex", flexDirection: "column", gap: "16px", background: "#1e293b", padding: "20px", borderRadius: "8px" }, children: [
494
- /* @__PURE__ */ jsxs6("div", { children: [
495
- /* @__PURE__ */ jsx6("label", { style: { display: "block", fontSize: "12px", marginBottom: "6px", color: "#94a3b8" }, children: "Workspace Name" }),
496
- /* @__PURE__ */ jsx6(
497
- "input",
498
- {
499
- type: "text",
500
- value: newWsName,
501
- onChange: (e) => setNewWsName(e.target.value),
502
- placeholder: "e.g. Production Vault",
503
- style: { width: "100%", padding: "8px 12px", background: "#0f172a", border: "1px solid #334155", borderRadius: "6px", color: "#fff" },
504
- autoFocus: true
505
- }
506
- )
501
+ error && /* @__PURE__ */ jsxs6("div", { className: "mb-4 p-3 bg-red-500/15 border-2 border-red-500 text-red-400 text-xs flex items-center justify-between rounded", children: [
502
+ /* @__PURE__ */ jsx6("b", { children: error }),
503
+ onDismissError && /* @__PURE__ */ jsx6("button", { type: "button", onClick: onDismissError, className: "underline", children: "DISMISS" })
507
504
  ] }),
508
- /* @__PURE__ */ jsx6(StorageOptionTiles, { currentUser, onSelectStorage: setStorageConfig }),
509
- /* @__PURE__ */ jsx6("button", { type: "submit", style: { padding: "10px", background: "#38bdf8", color: "#0f172a", border: "none", borderRadius: "6px", fontWeight: 600, cursor: "pointer" }, children: "Create Workspace" })
510
- ] }) : activeTab === "clones" && activeWorkspaceForClones ? /* @__PURE__ */ jsx6(
511
- WorkspaceSecondaryClonesPanel,
512
- {
513
- workspace: activeWorkspaceForClones,
514
- onClose: () => setActiveTab("workspaces")
515
- }
516
- ) : /* @__PURE__ */ jsx6("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))", gap: "16px", overflowY: "auto" }, children: workspaces.map((ws) => {
517
- const isActive = ws.id === activeWorkspaceId;
518
- return /* @__PURE__ */ jsxs6(
519
- "div",
520
- {
521
- onClick: () => onSelectWorkspace(ws),
522
- style: { padding: "16px", borderRadius: "8px", background: isActive ? "rgba(56, 189, 248, 0.08)" : "#1e293b", border: isActive ? "1px solid #38bdf8" : "1px solid #334155", cursor: "pointer" },
523
- children: [
524
- /* @__PURE__ */ jsxs6("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
525
- /* @__PURE__ */ jsx6("span", { style: { fontWeight: 600, fontSize: "14px" }, children: ws.name }),
526
- /* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: "6px" }, children: [
527
- ws.secondaryClones && ws.secondaryClones.length > 0 && /* @__PURE__ */ jsxs6("span", { style: { fontSize: "10px", padding: "2px 6px", borderRadius: "4px", background: "rgba(56, 189, 248, 0.2)", color: "#38bdf8" }, children: [
528
- "+",
529
- ws.secondaryClones.length,
530
- " CLONES"
531
- ] }),
532
- isActive && /* @__PURE__ */ jsx6("span", { style: { fontSize: "10px", padding: "2px 6px", borderRadius: "4px", background: "#38bdf8", color: "#0f172a", fontWeight: 600 }, children: "ACTIVE" })
505
+ loading && /* @__PURE__ */ jsx6("div", { className: "mb-4 p-8 border border-dashed border-[var(--skipo-border-color)] text-center text-xs text-[var(--skipo-text-muted)]", children: "LOADING WORKSPACES..." }),
506
+ /* @__PURE__ */ jsxs6("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [
507
+ filtered.map((w) => {
508
+ const active = w.id === activeWorkspaceId;
509
+ const isB2 = w.storageProvider === "backblaze_b2";
510
+ return /* @__PURE__ */ jsxs6("div", { onClick: () => onSelectWorkspace(w), className: `group p-4 border-2 bg-[var(--skipo-surface)] rounded-lg transition-all cursor-pointer ${active ? "border-[var(--skipo-accent)] shadow-[4px_4px_0px_var(--skipo-accent)]" : "border-[var(--skipo-border-color)] hover:border-[var(--skipo-accent)]"}`, children: [
511
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-2", children: [
512
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 text-[10px] font-bold uppercase text-[var(--skipo-text-muted)]", children: [
513
+ isB2 ? /* @__PURE__ */ jsx6(Cloud5, { size: 12 }) : /* @__PURE__ */ jsx6(HardDrive5, { size: 12 }),
514
+ " ",
515
+ w.storageProvider || "local_fs",
516
+ " ",
517
+ active && /* @__PURE__ */ jsx6("span", { className: "text-[var(--skipo-accent)]", children: "\u2605 ACTIVE" })
518
+ ] }),
519
+ /* @__PURE__ */ jsxs6("div", { className: "flex gap-1", children: [
520
+ onUpdateWorkspace && /* @__PURE__ */ jsx6("button", { type: "button", onClick: (e) => {
521
+ e.stopPropagation();
522
+ beginEdit(w);
523
+ }, className: "p-1.5 border border-[var(--skipo-border-color)] rounded hover:bg-[var(--skipo-accent)] hover:text-black", children: /* @__PURE__ */ jsx6(Edit3, { size: 13 }) }),
524
+ onDeleteWorkspace && /* @__PURE__ */ jsx6("button", { type: "button", onClick: (e) => {
525
+ e.stopPropagation();
526
+ if (confirm(`Delete workspace "${w.name}"?`)) onDeleteWorkspace(w.id);
527
+ }, className: "p-1.5 border border-[var(--skipo-border-color)] rounded hover:bg-red-600 hover:text-white", children: /* @__PURE__ */ jsx6(Trash22, { size: 13 }) })
533
528
  ] })
534
529
  ] }),
535
- /* @__PURE__ */ jsx6("div", { style: { marginTop: "10px" }, children: /* @__PURE__ */ jsx6(WorkspaceStorageReadonlyPanel, { workspace: ws }) }),
536
- onDeleteWorkspace && /* @__PURE__ */ jsx6("div", { style: { display: "flex", justifyContent: "flex-end", marginTop: "12px" }, children: /* @__PURE__ */ jsx6(
537
- "button",
538
- {
539
- onClick: (e) => {
540
- e.stopPropagation();
541
- if (confirm(`Delete workspace "${ws.name}"?`)) onDeleteWorkspace(ws.id);
542
- },
543
- style: { background: "transparent", border: "none", color: "#f87171", fontSize: "11px", cursor: "pointer" },
544
- children: "Delete"
545
- }
546
- ) })
547
- ]
548
- },
549
- ws.id
550
- );
551
- }) })
530
+ /* @__PURE__ */ jsx6("h3", { className: "mt-3 text-sm font-black uppercase text-[var(--skipo-text)] truncate", children: w.name }),
531
+ /* @__PURE__ */ jsxs6("div", { className: "mt-1 text-[10px] text-[var(--skipo-accent)] flex items-center gap-1 truncate", children: [
532
+ /* @__PURE__ */ jsx6(FolderOpen, { size: 11 }),
533
+ w.workspacePath || w.localFolderName || w.b2BucketName || w.id
534
+ ] }),
535
+ /* @__PURE__ */ jsx6("p", { className: "text-xs text-[var(--skipo-text-muted)] mt-2 line-clamp-2", children: w.description || "Workspace deployment and application control plane." }),
536
+ /* @__PURE__ */ jsx6("div", { className: "mt-3 pt-3 border-t border-[var(--skipo-border-color)]", children: /* @__PURE__ */ jsx6(WorkspaceStorageReadonlyPanel, { workspace: w }) }),
537
+ /* @__PURE__ */ jsx6("div", { className: "mt-3 flex justify-end", children: /* @__PURE__ */ jsxs6("button", { type: "button", onClick: (e) => {
538
+ e.stopPropagation();
539
+ onSelectWorkspace(w);
540
+ }, className: "flex items-center gap-1.5 px-3 py-1.5 text-xs font-black uppercase border rounded bg-[var(--skipo-bg)] hover:bg-[var(--skipo-accent)] hover:text-black", children: [
541
+ /* @__PURE__ */ jsx6("span", { children: "ENTER WORKSPACE" }),
542
+ /* @__PURE__ */ jsx6(ArrowRight, { size: 14 })
543
+ ] }) })
544
+ ] }, w.id);
545
+ }),
546
+ /* @__PURE__ */ jsxs6("button", { type: "button", onClick: () => {
547
+ setName("");
548
+ setDescription("");
549
+ setCreating(true);
550
+ }, className: "min-h-[220px] flex flex-col items-center justify-center p-6 border-2 border-dashed border-[var(--skipo-border-color)] bg-[var(--skipo-surface)]/50 hover:border-[var(--skipo-accent)] rounded-lg", children: [
551
+ /* @__PURE__ */ jsx6(FolderPlus, { size: 22, className: "mb-3 text-[var(--skipo-accent)]" }),
552
+ /* @__PURE__ */ jsx6("b", { className: "text-xs", children: "ADD NEW WORKSPACE" }),
553
+ /* @__PURE__ */ jsx6("span", { className: "text-[11px] text-[var(--skipo-text-muted)] mt-1 text-center", children: "Create an isolated workspace with dedicated storage." })
554
+ ] })
555
+ ] })
556
+ ] }),
557
+ (creating || editing) && /* @__PURE__ */ jsx6("div", { className: "fixed inset-0 z-[60] flex items-center justify-center bg-black/75 p-4 backdrop-blur-sm", children: /* @__PURE__ */ jsxs6("div", { className: "w-full max-w-2xl p-6 border-2 border-[var(--skipo-border-color)] bg-[var(--skipo-surface)] rounded-lg shadow-2xl font-mono", children: [
558
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between pb-3 border-b border-[var(--skipo-border-color)] mb-4", children: [
559
+ /* @__PURE__ */ jsx6("b", { className: "text-sm uppercase", children: creating ? "CREATE NEW WORKSPACE" : "EDIT WORKSPACE SETTINGS" }),
560
+ /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => {
561
+ setCreating(false);
562
+ setEditing(null);
563
+ }, children: /* @__PURE__ */ jsx6(X, { size: 16 }) })
564
+ ] }),
565
+ /* @__PURE__ */ jsxs6("form", { onSubmit: creating ? create : update, className: "space-y-4", children: [
566
+ /* @__PURE__ */ jsx6("input", { value: name, onChange: (e) => setName(e.target.value), placeholder: "Workspace Name", required: true, className: "w-full bg-[var(--skipo-bg)] border border-[var(--skipo-border-color)] rounded px-3 py-2 text-xs" }),
567
+ /* @__PURE__ */ jsx6("textarea", { value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Description", rows: 2, className: "w-full bg-[var(--skipo-bg)] border border-[var(--skipo-border-color)] rounded px-3 py-2 text-xs" }),
568
+ creating && /* @__PURE__ */ jsx6(StorageOptionTiles, { currentUser, onSelectStorage: setStorage }),
569
+ /* @__PURE__ */ jsxs6("div", { className: "flex justify-end gap-2", children: [
570
+ /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => {
571
+ setCreating(false);
572
+ setEditing(null);
573
+ }, className: "px-3 py-1.5 text-xs border rounded", children: "CANCEL" }),
574
+ /* @__PURE__ */ jsx6("button", { type: "submit", className: "px-3 py-1.5 text-xs font-black bg-[var(--skipo-accent)] text-black rounded", children: creating ? "CREATE & ENTER WORKSPACE" : "SAVE SETTINGS" })
575
+ ] })
576
+ ] })
577
+ ] }) })
552
578
  ] });
553
579
  };
554
580
 
@@ -1,5 +1,26 @@
1
1
  import React__default from 'react';
2
2
 
3
+ interface AuthResult {
4
+ success: boolean;
5
+ error?: string;
6
+ user?: unknown;
7
+ token?: string;
8
+ }
9
+ interface AuthPageProps {
10
+ appName?: string;
11
+ appSubtitle?: string;
12
+ footerText?: string;
13
+ onLogin: (email: string, password: string) => Promise<AuthResult>;
14
+ onRegister: (input: {
15
+ name: string;
16
+ email: string;
17
+ password: string;
18
+ }) => Promise<AuthResult>;
19
+ onSuccess?: (result: AuthResult) => void;
20
+ onSwitchToAdmin?: () => void;
21
+ }
22
+ declare const AuthPage: React__default.FC<AuthPageProps>;
23
+
3
24
  interface LoginModalProps {
4
25
  appName?: string;
5
26
  onSuccess: (user: any, token: string) => void;
@@ -7,4 +28,4 @@ interface LoginModalProps {
7
28
  }
8
29
  declare const LoginModal: React__default.FC<LoginModalProps>;
9
30
 
10
- export { LoginModal, type LoginModalProps };
31
+ export { AuthPage, type AuthPageProps, type AuthResult, LoginModal, type LoginModalProps };
@@ -1,8 +1,10 @@
1
1
  import {
2
+ AuthPage,
2
3
  LoginModal
3
- } from "../../chunk-S227WJ5E.js";
4
+ } from "../../chunk-2SFOC7KZ.js";
4
5
  import "../../chunk-W42SJGOJ.js";
5
6
  import "../../chunk-A2CDQISJ.js";
6
7
  export {
8
+ AuthPage,
7
9
  LoginModal
8
10
  };
@@ -75,26 +75,39 @@ declare const WorkspaceSecondaryClonesPanel: React__default.FC<Props>;
75
75
  interface WorkspaceRecord {
76
76
  id: string;
77
77
  name: string;
78
+ description?: string;
79
+ workspacePath?: string;
78
80
  storageProvider?: string;
79
81
  localFolderName?: string;
82
+ localFolderKey?: string;
80
83
  b2BucketName?: string;
81
- secondaryClones?: WorkspaceSecondaryClone[];
82
- createdAt?: string;
83
- updatedAt?: string;
84
+ secondaryClones?: unknown[];
84
85
  }
85
86
  interface WorkspaceTilesMenuProps {
86
87
  workspaces: WorkspaceRecord[];
87
- activeWorkspaceId: string | null;
88
- onSelectWorkspace: (workspace: WorkspaceRecord) => void;
89
- onCreateWorkspace: (name: string, storage: StorageSelection) => Promise<void>;
90
- onDeleteWorkspace?: (workspaceId: string) => Promise<void>;
91
- appName?: string;
88
+ activeWorkspaceId?: string | null;
92
89
  currentUser?: {
93
90
  id: string;
94
91
  email: string;
95
92
  name?: string;
96
93
  } | null;
94
+ onSelectWorkspace: (workspace: WorkspaceRecord) => void;
95
+ onCreateWorkspace: (input: {
96
+ name: string;
97
+ description?: string;
98
+ storage: StorageSelection;
99
+ }) => Promise<void>;
100
+ onUpdateWorkspace?: (workspaceId: string, patch: {
101
+ name: string;
102
+ description?: string;
103
+ }) => Promise<void>;
104
+ onDeleteWorkspace?: (workspaceId: string) => Promise<void>;
105
+ onLogout?: () => void;
106
+ appName?: string;
97
107
  mode?: 'direct-vault' | 'working-workspace';
108
+ loading?: boolean;
109
+ error?: string | null;
110
+ onDismissError?: () => void;
98
111
  }
99
112
  declare const WorkspaceTilesMenu: React__default.FC<WorkspaceTilesMenuProps>;
100
113
 
@@ -5,7 +5,7 @@ import {
5
5
  WorkspaceSecondaryClonesPanel,
6
6
  WorkspaceStorageReadonlyPanel,
7
7
  WorkspaceTilesMenu
8
- } from "../../chunk-ELZOBTWX.js";
8
+ } from "../../chunk-DT6DZU63.js";
9
9
  export {
10
10
  SrklBackblazeTile,
11
11
  StorageOptionTiles,
@@ -7,7 +7,7 @@ export { AppShell, AppShellProps, BreadcrumbNav, BreadcrumbNavProps, HeaderBar,
7
7
  export { ApiCallIndicator, ApiCallIndicatorProps, AutoSaveStatus, AutoSaveToggle, AutoSaveToggleProps, BottomStripContextValue, BottomStripProvider, BottomStripProviderProps, StatusLight, StatusLightProps, SystemMessage, SystemMessageDisplay, SystemMessageDisplayProps, SystemMessageType, useBottomStrip } from './components/bottom-strip/index.js';
8
8
  export { B as BottomStrip, a as BottomStripProps } from './BottomStrip-DYhAUQR4.js';
9
9
  export { AccountsSettingsSection, AccountsSettingsSectionProps, SettingsTab, SettingsTabProps, ThemeSettingsSection } from './components/settings/index.js';
10
- export { LoginModal, LoginModalProps } from './components/auth/index.js';
10
+ export { AuthPage, AuthPageProps, AuthResult, LoginModal, LoginModalProps } from './components/auth/index.js';
11
11
  export { SrklBackblazeAccount, SrklBackblazeTile, StorageOptionTiles, StoragePresetTile, StorageSelection, WorkspaceRecord, WorkspaceSecondaryClone, WorkspaceSecondaryClonesPanel, WorkspaceStorageReadonlyPanel, WorkspaceTilesMenu, WorkspaceTilesMenuProps } from './components/workspace/index.js';
12
12
  export { DEFAULT_PALETTE_ID, THEME_STORAGE_KEY, ThemeContextValue, ThemeProvider, ThemeProviderProps, applyPaletteToDocument, getActivePalette, paletteToSkipoThemePack, subscribeToPalette, usePalette, useTheme } from './palette/index.js';
13
13
  export { ActionButton, Badge, BadgeModel, BadgeProps, BadgeTone, ButtonModel, ButtonParent, ButtonParentProps, ButtonProps, ButtonSize, ButtonVariant, CardPanel, CategoryCardTile, ChannelStripTile, ClipCardTile, DangerButton, GhostButton, IconButton, InputModel, InspectorPanel, ModalPanel, PanelModel, PanelParent, PanelParentProps, PanelProps, PanelVariant, SelectInput, SelectInputProps, SliderInput, SliderInputProps, SpawnOptionTile, StatusDot, StatusDotProps, TelemetryPill, TelemetryPillProps, TextInput, TextInputProps, TileModel, TileParent, TileParentProps, TileVariant, ToggleButton, ToggleInput, ToggleInputProps, ToolbarPanel, TooltipDirection, UIBaseProps, UIElementBase, UIInteractionState, UIModel, UIParent, UIParentProps, UIProps, UIRole, UISize, UIStyleTokens, UIVariant, registerPaletteResolver } from './hierarchy/index.js';
@@ -30,7 +30,7 @@ import {
30
30
  WorkspaceSecondaryClonesPanel,
31
31
  WorkspaceStorageReadonlyPanel,
32
32
  WorkspaceTilesMenu
33
- } from "./chunk-ELZOBTWX.js";
33
+ } from "./chunk-DT6DZU63.js";
34
34
  import {
35
35
  ActionButton,
36
36
  Badge,
@@ -128,8 +128,9 @@ import {
128
128
  BUILTIN_PALETTES
129
129
  } from "./chunk-XXIH2HWI.js";
130
130
  import {
131
+ AuthPage,
131
132
  LoginModal
132
- } from "./chunk-S227WJ5E.js";
133
+ } from "./chunk-2SFOC7KZ.js";
133
134
  import {
134
135
  BaseSelect,
135
136
  BaseTextarea,
@@ -184,6 +185,7 @@ export {
184
185
  ActionButton,
185
186
  ApiCallIndicator,
186
187
  AppShell,
188
+ AuthPage,
187
189
  AutoSaveToggle,
188
190
  BUILTIN_PALETTES,
189
191
  Badge,
@@ -1,152 +0,0 @@
1
- import {
2
- BaseInput
3
- } from "./chunk-W42SJGOJ.js";
4
- import {
5
- BaseButton
6
- } from "./chunk-A2CDQISJ.js";
7
-
8
- // src/components/auth/LoginModal.tsx
9
- import { useState } from "react";
10
- import { ArrowRight, ShieldCheck, AlertCircle } from "lucide-react";
11
- import { jsx, jsxs } from "react/jsx-runtime";
12
- var LoginModal = ({
13
- appName = "Ecosystem App",
14
- onSuccess,
15
- defaultEmail = ""
16
- }) => {
17
- const [email, setEmail] = useState(defaultEmail);
18
- const [password, setPassword] = useState("");
19
- const [isRegister, setIsRegister] = useState(false);
20
- const [name, setName] = useState("");
21
- const [loading, setLoading] = useState(false);
22
- const [error, setError] = useState(null);
23
- const handleSubmit = async (e) => {
24
- e.preventDefault();
25
- setError(null);
26
- setLoading(true);
27
- try {
28
- const endpoint = isRegister ? "/api/auth/register" : "/api/auth/login";
29
- const payload = isRegister ? { email, password, name } : { email, password };
30
- const res = await fetch(endpoint, {
31
- method: "POST",
32
- headers: { "Content-Type": "application/json" },
33
- body: JSON.stringify(payload)
34
- });
35
- const data = await res.json().catch(() => ({}));
36
- if (!res.ok || !data.success || !data.user) {
37
- throw new Error(data.error || "Authentication failed. Please verify credentials.");
38
- }
39
- const token = data.token || `usr_${Date.now()}`;
40
- if (typeof window !== "undefined") {
41
- localStorage.setItem("skipo_auth_token", token);
42
- localStorage.setItem("skipo_user", JSON.stringify(data.user));
43
- }
44
- onSuccess(data.user, token);
45
- } catch (err) {
46
- setError(err.message || "Server error. Authentication failed.");
47
- } finally {
48
- setLoading(false);
49
- }
50
- };
51
- return /* @__PURE__ */ jsx(
52
- "div",
53
- {
54
- className: "fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-xs font-mono p-4",
55
- onWheel: (e) => e.stopPropagation(),
56
- onPointerDown: (e) => e.stopPropagation(),
57
- children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-md p-6 border-2 border-[var(--skipo-border-color)] bg-[var(--skipo-surface)] text-[var(--skipo-text)] shadow-2xl rounded-lg space-y-4", children: [
58
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pb-3 border-b border-[var(--skipo-border-color)]", children: [
59
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
60
- /* @__PURE__ */ jsx("div", { className: "w-7 h-7 bg-[var(--skipo-accent)] text-black font-black flex items-center justify-center text-xs rounded", children: "\u25B2" }),
61
- /* @__PURE__ */ jsxs("span", { className: "font-black text-sm tracking-wider uppercase text-[var(--skipo-text)]", children: [
62
- appName,
63
- " Authentication"
64
- ] })
65
- ] }),
66
- /* @__PURE__ */ jsxs("span", { className: "text-[9px] px-2 py-0.5 border border-emerald-500/50 bg-emerald-500/10 text-emerald-300 font-bold rounded flex items-center gap-1", children: [
67
- /* @__PURE__ */ jsx(ShieldCheck, { size: 10 }),
68
- " SYSTEM DB"
69
- ] })
70
- ] }),
71
- error && /* @__PURE__ */ jsxs("div", { className: "p-3 border border-red-500/60 bg-red-500/10 text-red-300 text-xs rounded flex items-start gap-2", children: [
72
- /* @__PURE__ */ jsx(AlertCircle, { size: 14, className: "shrink-0 mt-0.5" }),
73
- /* @__PURE__ */ jsx("span", { children: error })
74
- ] }),
75
- /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-3", children: [
76
- isRegister && /* @__PURE__ */ jsxs("div", { children: [
77
- /* @__PURE__ */ jsx("label", { className: "block text-[10px] font-black uppercase mb-1", children: "Full Name *" }),
78
- /* @__PURE__ */ jsx(
79
- BaseInput,
80
- {
81
- type: "text",
82
- value: name,
83
- onChange: (e) => setName(e.target.value),
84
- placeholder: "Developer Name",
85
- required: isRegister
86
- }
87
- )
88
- ] }),
89
- /* @__PURE__ */ jsxs("div", { children: [
90
- /* @__PURE__ */ jsx("label", { className: "block text-[10px] font-black uppercase mb-1", children: "Email Address *" }),
91
- /* @__PURE__ */ jsx(
92
- BaseInput,
93
- {
94
- type: "email",
95
- value: email,
96
- onChange: (e) => setEmail(e.target.value),
97
- placeholder: "user@example.com",
98
- required: true
99
- }
100
- )
101
- ] }),
102
- /* @__PURE__ */ jsxs("div", { children: [
103
- /* @__PURE__ */ jsx("label", { className: "block text-[10px] font-black uppercase mb-1", children: "Password *" }),
104
- /* @__PURE__ */ jsx(
105
- BaseInput,
106
- {
107
- type: "password",
108
- value: password,
109
- onChange: (e) => setPassword(e.target.value),
110
- placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
111
- required: true
112
- }
113
- )
114
- ] }),
115
- /* @__PURE__ */ jsx("div", { className: "pt-2", children: /* @__PURE__ */ jsxs(
116
- BaseButton,
117
- {
118
- variant: "accent",
119
- size: "md",
120
- type: "submit",
121
- disabled: loading,
122
- className: "w-full flex items-center justify-center gap-2",
123
- children: [
124
- /* @__PURE__ */ jsx("span", { children: loading ? "AUTHENTICATING..." : isRegister ? "REGISTER & ENTER" : "SIGN IN" }),
125
- /* @__PURE__ */ jsx(ArrowRight, { size: 14 })
126
- ]
127
- }
128
- ) })
129
- ] }),
130
- /* @__PURE__ */ jsxs("div", { className: "pt-2 border-t border-[var(--skipo-border-color)]/60 flex items-center justify-between text-[11px]", children: [
131
- /* @__PURE__ */ jsx(
132
- "button",
133
- {
134
- type: "button",
135
- onClick: () => {
136
- setIsRegister(!isRegister);
137
- setError(null);
138
- },
139
- className: "text-[var(--skipo-accent)] hover:underline cursor-pointer",
140
- children: isRegister ? "Already have an account? Sign In" : "Create new account"
141
- }
142
- ),
143
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-[var(--skipo-text-muted)]", children: "ULTRST Identity" })
144
- ] })
145
- ] })
146
- }
147
- );
148
- };
149
-
150
- export {
151
- LoginModal
152
- };