@trops/dash-core 0.1.131 → 0.1.132

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/index.js CHANGED
@@ -36166,6 +36166,717 @@ var ProvidersSection = function ProvidersSection(_ref) {
36166
36166
  });
36167
36167
  };
36168
36168
 
36169
+ var THEME_TAGS = ["dark", "light", "colorful", "minimal", "professional", "vibrant", "pastel", "high-contrast", "warm", "cool"];
36170
+
36171
+ /**
36172
+ * PublishThemeModal — multi-step stepper for publishing a theme
36173
+ * to the Dash Registry.
36174
+ *
36175
+ * Steps:
36176
+ * 0. Account — Auth check, sign-in prompt, profile display
36177
+ * 1. Details — Author name (pre-filled from profile) + description
36178
+ * 2. Tags — Predefined theme tag selection
36179
+ * 3. Publish — Review summary with color swatches, publish action
36180
+ */
36181
+ var PublishThemeModal = function PublishThemeModal(_ref) {
36182
+ var _result$registryResul, _result$registryResul2;
36183
+ var isOpen = _ref.isOpen,
36184
+ setIsOpen = _ref.setIsOpen,
36185
+ appId = _ref.appId,
36186
+ themeKey = _ref.themeKey,
36187
+ themeName = _ref.themeName;
36188
+ var _useContext = React.useContext(DashReact.ThemeContext),
36189
+ currentTheme = _useContext.currentTheme;
36190
+ var panelStyles = DashReact.getStylesForItem(DashReact.themeObjects.PANEL, currentTheme, {
36191
+ grow: false
36192
+ });
36193
+
36194
+ // Stepper state
36195
+ var _useState = React.useState(0),
36196
+ _useState2 = _slicedToArray(_useState, 2),
36197
+ step = _useState2[0],
36198
+ setStep = _useState2[1];
36199
+
36200
+ // Step 0: Account / Auth
36201
+ var _useState3 = React.useState("loading"),
36202
+ _useState4 = _slicedToArray(_useState3, 2),
36203
+ authStatus = _useState4[0],
36204
+ setAuthStatus = _useState4[1];
36205
+ var _useState5 = React.useState(null),
36206
+ _useState6 = _slicedToArray(_useState5, 2),
36207
+ profile = _useState6[0],
36208
+ setProfile = _useState6[1];
36209
+ var _useState7 = React.useState(null),
36210
+ _useState8 = _slicedToArray(_useState7, 2),
36211
+ authFlow = _useState8[0],
36212
+ setAuthFlow = _useState8[1];
36213
+ var _useState9 = React.useState(false),
36214
+ _useState0 = _slicedToArray(_useState9, 2),
36215
+ isPolling = _useState0[0],
36216
+ setIsPolling = _useState0[1];
36217
+ var _useState1 = React.useState(null),
36218
+ _useState10 = _slicedToArray(_useState1, 2),
36219
+ authError = _useState10[0],
36220
+ setAuthError = _useState10[1];
36221
+
36222
+ // Step 1: Details
36223
+ var _useState11 = React.useState(""),
36224
+ _useState12 = _slicedToArray(_useState11, 2),
36225
+ authorName = _useState12[0],
36226
+ setAuthorName = _useState12[1];
36227
+ var _useState13 = React.useState(""),
36228
+ _useState14 = _slicedToArray(_useState13, 2),
36229
+ description = _useState14[0],
36230
+ setDescription = _useState14[1];
36231
+
36232
+ // Step 2: Tags
36233
+ var _useState15 = React.useState([]),
36234
+ _useState16 = _slicedToArray(_useState15, 2),
36235
+ selectedTags = _useState16[0],
36236
+ setSelectedTags = _useState16[1];
36237
+
36238
+ // Publish preview (colors)
36239
+ var _useState17 = React.useState(null),
36240
+ _useState18 = _slicedToArray(_useState17, 2),
36241
+ preview = _useState18[0],
36242
+ setPreview = _useState18[1];
36243
+
36244
+ // Step 3: Publish
36245
+ var _useState19 = React.useState(false),
36246
+ _useState20 = _slicedToArray(_useState19, 2),
36247
+ isPublishing = _useState20[0],
36248
+ setIsPublishing = _useState20[1];
36249
+ var _useState21 = React.useState(null),
36250
+ _useState22 = _slicedToArray(_useState21, 2),
36251
+ result = _useState22[0],
36252
+ setResult = _useState22[1];
36253
+
36254
+ // Fetch publish preview on open
36255
+ React.useEffect(function () {
36256
+ if (!isOpen || !appId || !themeKey) return;
36257
+ window.mainApi.themes.getThemePublishPreview(appId, themeKey).then(function (res) {
36258
+ if (res.success) setPreview(res);
36259
+ })["catch"](console.error);
36260
+ }, [isOpen, appId, themeKey]);
36261
+
36262
+ // Check auth status on mount
36263
+ React.useEffect(function () {
36264
+ if (!isOpen) return;
36265
+ var cancelled = false;
36266
+ function checkAuth() {
36267
+ return _checkAuth.apply(this, arguments);
36268
+ }
36269
+ function _checkAuth() {
36270
+ _checkAuth = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
36271
+ var status, userProfile;
36272
+ return _regeneratorRuntime.wrap(function (_context) {
36273
+ while (1) switch (_context.prev = _context.next) {
36274
+ case 0:
36275
+ _context.prev = 0;
36276
+ _context.next = 1;
36277
+ return window.mainApi.registryAuth.getStatus();
36278
+ case 1:
36279
+ status = _context.sent;
36280
+ if (!cancelled) {
36281
+ _context.next = 2;
36282
+ break;
36283
+ }
36284
+ return _context.abrupt("return");
36285
+ case 2:
36286
+ if (!status.authenticated) {
36287
+ _context.next = 5;
36288
+ break;
36289
+ }
36290
+ _context.next = 3;
36291
+ return window.mainApi.registryAuth.getProfile();
36292
+ case 3:
36293
+ userProfile = _context.sent;
36294
+ if (!cancelled) {
36295
+ _context.next = 4;
36296
+ break;
36297
+ }
36298
+ return _context.abrupt("return");
36299
+ case 4:
36300
+ if (userProfile) {
36301
+ setProfile(userProfile);
36302
+ setAuthStatus("authenticated");
36303
+ setAuthorName(userProfile.displayName || userProfile.username || "");
36304
+ } else {
36305
+ setAuthStatus("unauthenticated");
36306
+ }
36307
+ _context.next = 6;
36308
+ break;
36309
+ case 5:
36310
+ setAuthStatus("unauthenticated");
36311
+ case 6:
36312
+ _context.next = 8;
36313
+ break;
36314
+ case 7:
36315
+ _context.prev = 7;
36316
+ _context["catch"](0);
36317
+ if (!cancelled) setAuthStatus("unauthenticated");
36318
+ case 8:
36319
+ case "end":
36320
+ return _context.stop();
36321
+ }
36322
+ }, _callee, null, [[0, 7]]);
36323
+ }));
36324
+ return _checkAuth.apply(this, arguments);
36325
+ }
36326
+ checkAuth();
36327
+ return function () {
36328
+ cancelled = true;
36329
+ };
36330
+ }, [isOpen]);
36331
+ function resetState() {
36332
+ setStep(0);
36333
+ setAuthStatus("loading");
36334
+ setProfile(null);
36335
+ setAuthFlow(null);
36336
+ setIsPolling(false);
36337
+ setAuthError(null);
36338
+ setAuthorName("");
36339
+ setDescription("");
36340
+ setSelectedTags([]);
36341
+ setPreview(null);
36342
+ setIsPublishing(false);
36343
+ setResult(null);
36344
+ }
36345
+ function handleClose() {
36346
+ setIsOpen(false);
36347
+ setTimeout(resetState, 200);
36348
+ }
36349
+ function handleStepChange(nextStep) {
36350
+ if (step === 0 && nextStep > 0 && authStatus !== "authenticated") return;
36351
+ if (step === 1 && nextStep > 1 && !authorName.trim()) return;
36352
+ if (step === 2 && nextStep > 2 && selectedTags.length === 0) return;
36353
+ setStep(nextStep);
36354
+ }
36355
+ function toggleTag(tag) {
36356
+ setSelectedTags(function (prev) {
36357
+ return prev.includes(tag) ? prev.filter(function (t) {
36358
+ return t !== tag;
36359
+ }) : [].concat(_toConsumableArray(prev), [tag]);
36360
+ });
36361
+ }
36362
+ function handlePublish() {
36363
+ return _handlePublish.apply(this, arguments);
36364
+ }
36365
+ function _handlePublish() {
36366
+ _handlePublish = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
36367
+ var options, res, _t2;
36368
+ return _regeneratorRuntime.wrap(function (_context2) {
36369
+ while (1) switch (_context2.prev = _context2.next) {
36370
+ case 0:
36371
+ if (!(!appId || !themeKey)) {
36372
+ _context2.next = 1;
36373
+ break;
36374
+ }
36375
+ return _context2.abrupt("return");
36376
+ case 1:
36377
+ setIsPublishing(true);
36378
+ setResult(null);
36379
+ _context2.prev = 2;
36380
+ options = {
36381
+ authorName: authorName.trim(),
36382
+ description: description.trim() || undefined,
36383
+ tags: selectedTags
36384
+ };
36385
+ _context2.next = 3;
36386
+ return window.mainApi.themes.publishTheme(appId, themeKey, options);
36387
+ case 3:
36388
+ res = _context2.sent;
36389
+ setResult(res);
36390
+ _context2.next = 5;
36391
+ break;
36392
+ case 4:
36393
+ _context2.prev = 4;
36394
+ _t2 = _context2["catch"](2);
36395
+ setResult({
36396
+ success: false,
36397
+ error: _t2.message || "Failed to prepare theme for publish."
36398
+ });
36399
+ case 5:
36400
+ _context2.prev = 5;
36401
+ setIsPublishing(false);
36402
+ return _context2.finish(5);
36403
+ case 6:
36404
+ case "end":
36405
+ return _context2.stop();
36406
+ }
36407
+ }, _callee2, null, [[2, 4, 5, 6]]);
36408
+ }));
36409
+ return _handlePublish.apply(this, arguments);
36410
+ }
36411
+ function handleSignIn() {
36412
+ return _handleSignIn.apply(this, arguments);
36413
+ }
36414
+ function _handleSignIn() {
36415
+ _handleSignIn = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
36416
+ var flow, interval, poll;
36417
+ return _regeneratorRuntime.wrap(function (_context4) {
36418
+ while (1) switch (_context4.prev = _context4.next) {
36419
+ case 0:
36420
+ setAuthError(null);
36421
+ _context4.prev = 1;
36422
+ _context4.next = 2;
36423
+ return window.mainApi.registryAuth.initiateLogin();
36424
+ case 2:
36425
+ flow = _context4.sent;
36426
+ setAuthFlow(flow);
36427
+ if (flow.verificationUrlComplete) {
36428
+ window.mainApi.shell.openExternal(flow.verificationUrlComplete);
36429
+ }
36430
+ setIsPolling(true);
36431
+ interval = (flow.interval || 5) * 1000;
36432
+ poll = setInterval(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
36433
+ var pollResult, userProfile;
36434
+ return _regeneratorRuntime.wrap(function (_context3) {
36435
+ while (1) switch (_context3.prev = _context3.next) {
36436
+ case 0:
36437
+ _context3.prev = 0;
36438
+ _context3.next = 1;
36439
+ return window.mainApi.registryAuth.pollToken(flow.deviceCode);
36440
+ case 1:
36441
+ pollResult = _context3.sent;
36442
+ if (!(pollResult.status === "authorized")) {
36443
+ _context3.next = 3;
36444
+ break;
36445
+ }
36446
+ clearInterval(poll);
36447
+ setIsPolling(false);
36448
+ setAuthFlow(null);
36449
+ _context3.next = 2;
36450
+ return window.mainApi.registryAuth.getProfile();
36451
+ case 2:
36452
+ userProfile = _context3.sent;
36453
+ setProfile(userProfile);
36454
+ setAuthStatus("authenticated");
36455
+ if (userProfile !== null && userProfile !== void 0 && userProfile.displayName && !authorName) {
36456
+ setAuthorName(userProfile.displayName);
36457
+ }
36458
+ _context3.next = 4;
36459
+ break;
36460
+ case 3:
36461
+ if (pollResult.status === "expired") {
36462
+ clearInterval(poll);
36463
+ setIsPolling(false);
36464
+ setAuthFlow(null);
36465
+ }
36466
+ case 4:
36467
+ _context3.next = 6;
36468
+ break;
36469
+ case 5:
36470
+ _context3.prev = 5;
36471
+ _context3["catch"](0);
36472
+ clearInterval(poll);
36473
+ setIsPolling(false);
36474
+ case 6:
36475
+ case "end":
36476
+ return _context3.stop();
36477
+ }
36478
+ }, _callee3, null, [[0, 5]]);
36479
+ })), interval);
36480
+ _context4.next = 4;
36481
+ break;
36482
+ case 3:
36483
+ _context4.prev = 3;
36484
+ _context4["catch"](1);
36485
+ setAuthError("Could not reach the registry. Check your connection and try again.");
36486
+ case 4:
36487
+ case "end":
36488
+ return _context4.stop();
36489
+ }
36490
+ }, _callee4, null, [[1, 3]]);
36491
+ }));
36492
+ return _handleSignIn.apply(this, arguments);
36493
+ }
36494
+ function handleSignOut() {
36495
+ return _handleSignOut.apply(this, arguments);
36496
+ }
36497
+ function _handleSignOut() {
36498
+ _handleSignOut = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
36499
+ return _regeneratorRuntime.wrap(function (_context5) {
36500
+ while (1) switch (_context5.prev = _context5.next) {
36501
+ case 0:
36502
+ _context5.prev = 0;
36503
+ _context5.next = 1;
36504
+ return window.mainApi.registryAuth.logout();
36505
+ case 1:
36506
+ setAuthStatus("unauthenticated");
36507
+ setProfile(null);
36508
+ _context5.next = 3;
36509
+ break;
36510
+ case 2:
36511
+ _context5.prev = 2;
36512
+ _context5["catch"](0);
36513
+ case 3:
36514
+ case "end":
36515
+ return _context5.stop();
36516
+ }
36517
+ }, _callee5, null, [[0, 2]]);
36518
+ }));
36519
+ return _handleSignOut.apply(this, arguments);
36520
+ }
36521
+ var isLastStep = step === 3;
36522
+ var canAdvance = step === 0 ? authStatus === "authenticated" : step === 1 ? !!authorName.trim() : step === 2 ? selectedTags.length > 0 : true;
36523
+ var previewColors = (preview === null || preview === void 0 ? void 0 : preview.colors) || {};
36524
+ var colorEntries = [{
36525
+ label: "Primary",
36526
+ value: previewColors.primary
36527
+ }, {
36528
+ label: "Secondary",
36529
+ value: previewColors.secondary
36530
+ }, {
36531
+ label: "Tertiary",
36532
+ value: previewColors.tertiary
36533
+ }, {
36534
+ label: "Neutral",
36535
+ value: previewColors.neutral
36536
+ }].filter(function (c) {
36537
+ return c.value;
36538
+ });
36539
+ return /*#__PURE__*/jsxRuntime.jsx(DashReact.Modal, {
36540
+ isOpen: isOpen,
36541
+ setIsOpen: handleClose,
36542
+ width: "w-full max-w-2xl",
36543
+ height: "h-[70vh]",
36544
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
36545
+ className: "flex flex-col h-full rounded-lg overflow-clip border ".concat(panelStyles.backgroundColor || "", " ").concat(panelStyles.borderColor || "", " ").concat(panelStyles.textColor || ""),
36546
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
36547
+ className: "flex-shrink-0 flex flex-row items-center justify-between p-4 border-b border-white/10",
36548
+ children: [/*#__PURE__*/jsxRuntime.jsxs("span", {
36549
+ className: "text-lg font-semibold",
36550
+ children: ["Publish \"", themeName || themeKey || "Theme", "\""]
36551
+ }), /*#__PURE__*/jsxRuntime.jsx("button", {
36552
+ type: "button",
36553
+ onClick: handleClose,
36554
+ className: "opacity-50 hover:opacity-100 transition-opacity cursor-pointer",
36555
+ children: /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
36556
+ icon: "xmark",
36557
+ className: "h-5 w-5"
36558
+ })
36559
+ })]
36560
+ }), /*#__PURE__*/jsxRuntime.jsxs(DashReact.Stepper, {
36561
+ activeStep: step,
36562
+ onStepChange: handleStepChange,
36563
+ showNavigation: false,
36564
+ className: "flex-1 min-h-0 flex flex-col px-6 pt-2",
36565
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Stepper.Step, {
36566
+ label: "Account",
36567
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
36568
+ className: "flex-1 min-h-0 overflow-y-auto pb-4 space-y-5",
36569
+ children: [authStatus === "loading" && /*#__PURE__*/jsxRuntime.jsx("div", {
36570
+ className: "flex items-center justify-center py-12",
36571
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
36572
+ className: "flex items-center gap-3 text-sm opacity-60",
36573
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
36574
+ icon: "spinner",
36575
+ className: "h-4 w-4 animate-spin"
36576
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
36577
+ children: "Checking account status..."
36578
+ })]
36579
+ })
36580
+ }), authStatus === "authenticated" && profile && /*#__PURE__*/jsxRuntime.jsxs("div", {
36581
+ className: "space-y-4",
36582
+ children: [/*#__PURE__*/jsxRuntime.jsx("p", {
36583
+ className: "text-sm opacity-70",
36584
+ children: "You're signed in and ready to publish."
36585
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
36586
+ className: "bg-white/5 border border-white/10 rounded-lg p-4 flex items-center gap-4",
36587
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
36588
+ className: "flex items-center justify-center h-10 w-10 rounded-full bg-green-500/20 border border-green-500/30",
36589
+ children: /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
36590
+ icon: "circle-check",
36591
+ className: "h-5 w-5 text-green-400"
36592
+ })
36593
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
36594
+ className: "flex-1 min-w-0",
36595
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
36596
+ className: "text-sm font-medium truncate",
36597
+ children: profile.displayName || profile.username
36598
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
36599
+ className: "text-xs opacity-50 truncate",
36600
+ children: ["@", profile.username]
36601
+ })]
36602
+ })]
36603
+ }), /*#__PURE__*/jsxRuntime.jsx("button", {
36604
+ type: "button",
36605
+ onClick: handleSignOut,
36606
+ className: "text-xs opacity-40 hover:opacity-70 transition-opacity cursor-pointer",
36607
+ children: "Sign out"
36608
+ })]
36609
+ }), authStatus === "unauthenticated" && /*#__PURE__*/jsxRuntime.jsxs("div", {
36610
+ className: "space-y-4",
36611
+ children: [/*#__PURE__*/jsxRuntime.jsx("p", {
36612
+ className: "text-sm opacity-70",
36613
+ children: "Sign in to the Dash Registry to publish your theme."
36614
+ }), !authFlow && !isPolling && /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
36615
+ children: [/*#__PURE__*/jsxRuntime.jsx("button", {
36616
+ type: "button",
36617
+ onClick: handleSignIn,
36618
+ className: "px-4 py-2 rounded-lg text-sm bg-blue-500/20 border border-blue-500/30 text-blue-300 hover:bg-blue-500/30 transition-colors cursor-pointer",
36619
+ children: "Sign in to Registry"
36620
+ }), authError && /*#__PURE__*/jsxRuntime.jsx("div", {
36621
+ className: "bg-red-500/10 border border-red-500/20 rounded-lg p-3",
36622
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
36623
+ className: "flex items-start gap-2",
36624
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
36625
+ icon: "circle-xmark",
36626
+ className: "h-3.5 w-3.5 text-red-400 mt-0.5 flex-shrink-0"
36627
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
36628
+ className: "text-xs text-red-300/90",
36629
+ children: authError
36630
+ })]
36631
+ })
36632
+ })]
36633
+ }), authFlow && isPolling && /*#__PURE__*/jsxRuntime.jsxs("div", {
36634
+ className: "bg-blue-500/10 border border-blue-500/20 rounded-lg p-4 space-y-3",
36635
+ children: [/*#__PURE__*/jsxRuntime.jsx("p", {
36636
+ className: "text-xs text-blue-300/90",
36637
+ children: "Enter this code in your browser:"
36638
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
36639
+ className: "text-center",
36640
+ children: /*#__PURE__*/jsxRuntime.jsx("span", {
36641
+ className: "text-2xl font-mono font-bold tracking-widest text-white",
36642
+ children: authFlow.userCode
36643
+ })
36644
+ }), /*#__PURE__*/jsxRuntime.jsx("p", {
36645
+ className: "text-xs text-blue-300/70 text-center",
36646
+ children: "Waiting for authorization..."
36647
+ })]
36648
+ })]
36649
+ })]
36650
+ })
36651
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Stepper.Step, {
36652
+ label: "Details",
36653
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
36654
+ className: "flex-1 min-h-0 overflow-y-auto pb-4 space-y-5",
36655
+ children: [/*#__PURE__*/jsxRuntime.jsx("p", {
36656
+ className: "text-sm opacity-70",
36657
+ children: "Provide details about your theme for the registry listing."
36658
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
36659
+ children: [/*#__PURE__*/jsxRuntime.jsx("label", {
36660
+ className: "block text-sm font-medium opacity-70 mb-1",
36661
+ children: "Author Name"
36662
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
36663
+ className: "px-3 py-2 rounded-lg bg-white/5 border border-white/10 text-sm opacity-80",
36664
+ children: authorName || "\u2014"
36665
+ })]
36666
+ }), colorEntries.length > 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
36667
+ children: [/*#__PURE__*/jsxRuntime.jsx("label", {
36668
+ className: "block text-sm font-medium opacity-70 mb-2",
36669
+ children: "Theme Colors"
36670
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
36671
+ className: "flex flex-row gap-3",
36672
+ children: colorEntries.map(function (_ref2) {
36673
+ var label = _ref2.label,
36674
+ value = _ref2.value;
36675
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
36676
+ className: "flex flex-col items-center gap-1",
36677
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
36678
+ className: "h-8 w-8 rounded-full border-2 border-white/20",
36679
+ style: {
36680
+ backgroundColor: value
36681
+ }
36682
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
36683
+ className: "text-[10px] opacity-50",
36684
+ children: label
36685
+ })]
36686
+ }, label);
36687
+ })
36688
+ })]
36689
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.TextArea, {
36690
+ label: "Description",
36691
+ value: description,
36692
+ onChange: setDescription,
36693
+ placeholder: "A brief description of this theme...",
36694
+ rows: 3
36695
+ })]
36696
+ })
36697
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Stepper.Step, {
36698
+ label: "Tags",
36699
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
36700
+ className: "flex-1 min-h-0 overflow-y-auto pb-4 space-y-5",
36701
+ children: [/*#__PURE__*/jsxRuntime.jsx("p", {
36702
+ className: "text-sm opacity-70",
36703
+ children: "Select at least one tag to categorize your theme."
36704
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
36705
+ className: "grid grid-cols-3 gap-2",
36706
+ children: THEME_TAGS.map(function (tag) {
36707
+ var isSelected = selectedTags.includes(tag);
36708
+ return /*#__PURE__*/jsxRuntime.jsx("button", {
36709
+ type: "button",
36710
+ onClick: function onClick() {
36711
+ return toggleTag(tag);
36712
+ },
36713
+ className: "px-3 py-1.5 rounded-full text-sm border transition-colors cursor-pointer ".concat(isSelected ? "bg-white/15 border-white/30 text-white" : "bg-transparent border-white/10 text-white/60 hover:border-white/20 hover:text-white/80"),
36714
+ children: tag
36715
+ }, tag);
36716
+ })
36717
+ })]
36718
+ })
36719
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Stepper.Step, {
36720
+ label: "Publish",
36721
+ children: /*#__PURE__*/jsxRuntime.jsx("div", {
36722
+ className: "flex-1 min-h-0 overflow-y-auto pb-4 space-y-4",
36723
+ children: !result ? /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
36724
+ children: [/*#__PURE__*/jsxRuntime.jsx("p", {
36725
+ className: "text-sm opacity-70",
36726
+ children: "Review your theme details before publishing."
36727
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
36728
+ className: "bg-white/5 border border-white/10 rounded-lg p-4 space-y-2 text-sm",
36729
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
36730
+ className: "flex gap-2",
36731
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
36732
+ className: "opacity-50 w-20 flex-shrink-0",
36733
+ children: "Author"
36734
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
36735
+ children: authorName
36736
+ })]
36737
+ }), description.trim() && /*#__PURE__*/jsxRuntime.jsxs("div", {
36738
+ className: "flex gap-2",
36739
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
36740
+ className: "opacity-50 w-20 flex-shrink-0",
36741
+ children: "Description"
36742
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
36743
+ children: description
36744
+ })]
36745
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
36746
+ className: "flex gap-2",
36747
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
36748
+ className: "opacity-50 w-20 flex-shrink-0",
36749
+ children: "Tags"
36750
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
36751
+ children: selectedTags.length > 0 ? selectedTags.join(", ") : "None"
36752
+ })]
36753
+ }), colorEntries.length > 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
36754
+ className: "flex gap-2 items-center",
36755
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
36756
+ className: "opacity-50 w-20 flex-shrink-0",
36757
+ children: "Colors"
36758
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
36759
+ className: "flex gap-1.5",
36760
+ children: colorEntries.map(function (_ref3) {
36761
+ var label = _ref3.label,
36762
+ value = _ref3.value;
36763
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
36764
+ className: "h-5 w-5 rounded-full border border-white/20",
36765
+ style: {
36766
+ backgroundColor: value
36767
+ },
36768
+ title: "".concat(label, ": ").concat(value)
36769
+ }, label);
36770
+ })
36771
+ })]
36772
+ })]
36773
+ })]
36774
+ }) : result.success ? /*#__PURE__*/jsxRuntime.jsxs("div", {
36775
+ className: "space-y-3",
36776
+ children: [(_result$registryResul = result.registryResult) !== null && _result$registryResul !== void 0 && _result$registryResul.success ? /*#__PURE__*/jsxRuntime.jsxs("div", {
36777
+ className: "space-y-3",
36778
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
36779
+ className: "flex items-center gap-2",
36780
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
36781
+ icon: "circle-check",
36782
+ className: "h-4 w-4 text-green-400"
36783
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
36784
+ className: "text-sm",
36785
+ children: "Published to Dash Registry"
36786
+ })]
36787
+ }), result.registryResult.registryUrl && /*#__PURE__*/jsxRuntime.jsxs("div", {
36788
+ className: "bg-white/5 border border-white/10 rounded-lg p-3",
36789
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
36790
+ className: "text-xs opacity-50 mb-1",
36791
+ children: "Shareable Link"
36792
+ }), /*#__PURE__*/jsxRuntime.jsx("button", {
36793
+ type: "button",
36794
+ onClick: function onClick() {
36795
+ return window.mainApi.shell.openExternal(result.registryResult.registryUrl);
36796
+ },
36797
+ className: "text-sm text-blue-400 hover:underline cursor-pointer break-all text-left",
36798
+ children: result.registryResult.registryUrl
36799
+ })]
36800
+ })]
36801
+ }) : /*#__PURE__*/jsxRuntime.jsxs("div", {
36802
+ className: "space-y-3",
36803
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
36804
+ className: "flex items-center gap-2",
36805
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
36806
+ icon: "circle-check",
36807
+ className: "h-4 w-4 text-green-400"
36808
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
36809
+ className: "text-sm",
36810
+ children: "Theme prepared for publishing."
36811
+ })]
36812
+ }), ((_result$registryResul2 = result.registryResult) === null || _result$registryResul2 === void 0 ? void 0 : _result$registryResul2.error) && /*#__PURE__*/jsxRuntime.jsx("div", {
36813
+ className: "bg-amber-500/10 border border-amber-500/20 rounded-lg p-3",
36814
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
36815
+ className: "flex items-start gap-2",
36816
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
36817
+ icon: "triangle-exclamation",
36818
+ className: "h-3.5 w-3.5 text-amber-400 mt-0.5 flex-shrink-0"
36819
+ }), /*#__PURE__*/jsxRuntime.jsxs("span", {
36820
+ className: "text-xs text-amber-300/90",
36821
+ children: ["Registry upload failed:", " ", result.registryResult.error, ". Your theme was saved locally."]
36822
+ })]
36823
+ })
36824
+ })]
36825
+ }), result.filePath && /*#__PURE__*/jsxRuntime.jsxs("div", {
36826
+ className: "text-xs opacity-50 break-all",
36827
+ children: ["Saved to: ", result.filePath]
36828
+ })]
36829
+ }) : /*#__PURE__*/jsxRuntime.jsxs("div", {
36830
+ className: "flex items-center gap-2",
36831
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
36832
+ icon: "circle-xmark",
36833
+ className: "h-4 w-4 text-red-400"
36834
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
36835
+ className: "text-sm text-red-400",
36836
+ children: result.error || "Publish preparation failed."
36837
+ })]
36838
+ })
36839
+ })
36840
+ })]
36841
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
36842
+ className: "flex-shrink-0 flex flex-row items-center px-6 py-4 border-t border-white/10",
36843
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
36844
+ className: "flex flex-row gap-2",
36845
+ children: /*#__PURE__*/jsxRuntime.jsx(DashReact.Button3, {
36846
+ title: step === 0 ? "Cancel" : "Back",
36847
+ onClick: step === 0 ? handleClose : function () {
36848
+ return setStep(step - 1);
36849
+ },
36850
+ disabled: isPublishing
36851
+ })
36852
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
36853
+ className: "flex-1 text-center",
36854
+ children: /*#__PURE__*/jsxRuntime.jsxs("span", {
36855
+ className: "text-xs opacity-40",
36856
+ children: ["Step ", step + 1, " of 4"]
36857
+ })
36858
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
36859
+ className: "flex flex-row gap-2",
36860
+ children: result !== null && result !== void 0 && result.success ? /*#__PURE__*/jsxRuntime.jsx(DashReact.Button2, {
36861
+ title: "Done",
36862
+ onClick: handleClose
36863
+ }) : isLastStep ? /*#__PURE__*/jsxRuntime.jsx(DashReact.Button2, {
36864
+ title: isPublishing ? "Publishing..." : "Publish",
36865
+ onClick: handlePublish,
36866
+ disabled: isPublishing
36867
+ }) : /*#__PURE__*/jsxRuntime.jsx(DashReact.Button2, {
36868
+ title: "Next",
36869
+ onClick: function onClick() {
36870
+ return handleStepChange(step + 1);
36871
+ },
36872
+ disabled: !canAdvance
36873
+ })
36874
+ })]
36875
+ })]
36876
+ })
36877
+ });
36878
+ };
36879
+
36169
36880
  var TOKEN_TYPES = ["bg", "text", "border"];
36170
36881
 
36171
36882
  // --- Color Swatch Grid ---
@@ -36344,8 +37055,15 @@ var ThemeDetail = function ThemeDetail(_ref6) {
36344
37055
  onActivate = _ref6.onActivate,
36345
37056
  onOpenThemeEditor = _ref6.onOpenThemeEditor,
36346
37057
  _ref6$onDelete = _ref6.onDelete,
36347
- onDelete = _ref6$onDelete === void 0 ? null : _ref6$onDelete;
37058
+ onDelete = _ref6$onDelete === void 0 ? null : _ref6$onDelete,
37059
+ _ref6$appId = _ref6.appId,
37060
+ appId = _ref6$appId === void 0 ? null : _ref6$appId;
36348
37061
  var theme = themeKey && themes ? themes[themeKey] : null;
37062
+ var _useState = React.useState(false),
37063
+ _useState2 = _slicedToArray(_useState, 2),
37064
+ publishOpen = _useState2[0],
37065
+ setPublishOpen = _useState2[1];
37066
+ var canPublish = theme && !theme._registryMeta;
36349
37067
  var displayTheme = React.useMemo(function () {
36350
37068
  return theme ? theme[themeVariant] || {} : {};
36351
37069
  }, [theme, themeVariant]);
@@ -36412,28 +37130,440 @@ var ThemeDetail = function ThemeDetail(_ref6) {
36412
37130
  })]
36413
37131
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
36414
37132
  className: "flex-shrink-0 flex flex-row justify-between px-6 py-4 border-t border-white/10",
37133
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
37134
+ className: "flex flex-row gap-2",
37135
+ children: [!isActive && onDelete && /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
37136
+ title: "Delete",
37137
+ onClick: function onClick() {
37138
+ return onDelete(themeKey);
37139
+ },
37140
+ size: "sm"
37141
+ }), canPublish && /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
37142
+ title: "Publish",
37143
+ onClick: function onClick() {
37144
+ return setPublishOpen(true);
37145
+ },
37146
+ size: "sm"
37147
+ })]
37148
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
37149
+ className: "flex flex-row gap-2",
37150
+ children: [!isActive && /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
37151
+ title: "Activate",
37152
+ onClick: function onClick() {
37153
+ return onActivate(themeKey);
37154
+ },
37155
+ size: "sm"
37156
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
37157
+ title: "Edit",
37158
+ onClick: onOpenThemeEditor,
37159
+ size: "sm"
37160
+ })]
37161
+ })]
37162
+ }), canPublish && /*#__PURE__*/jsxRuntime.jsx(PublishThemeModal, {
37163
+ isOpen: publishOpen,
37164
+ setIsOpen: setPublishOpen,
37165
+ appId: appId,
37166
+ themeKey: themeKey,
37167
+ themeName: theme.name || themeKey
37168
+ })]
37169
+ });
37170
+ };
37171
+
37172
+ var RegistryThemeDetail = function RegistryThemeDetail(_ref) {
37173
+ var themePackage = _ref.themePackage,
37174
+ appId = _ref.appId,
37175
+ onInstallComplete = _ref.onInstallComplete;
37176
+ var _useContext = React.useContext(DashReact.ThemeContext),
37177
+ currentTheme = _useContext.currentTheme,
37178
+ changeThemesForApplication = _useContext.changeThemesForApplication;
37179
+ var panelStyles = DashReact.getStylesForItem(DashReact.themeObjects.PANEL, currentTheme, {
37180
+ grow: false
37181
+ });
37182
+ var _useState = React.useState(false),
37183
+ _useState2 = _slicedToArray(_useState, 2),
37184
+ isInstalling = _useState2[0],
37185
+ setIsInstalling = _useState2[1];
37186
+ var _useState3 = React.useState(null),
37187
+ _useState4 = _slicedToArray(_useState3, 2),
37188
+ installResult = _useState4[0],
37189
+ setInstallResult = _useState4[1];
37190
+ var pkg = themePackage;
37191
+ if (!pkg) return null;
37192
+ var colors = pkg.colors || {};
37193
+ function handleInstall() {
37194
+ return _handleInstall.apply(this, arguments);
37195
+ }
37196
+ function _handleInstall() {
37197
+ _handleInstall = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
37198
+ var result, _t;
37199
+ return _regeneratorRuntime.wrap(function (_context) {
37200
+ while (1) switch (_context.prev = _context.next) {
37201
+ case 0:
37202
+ if (!(!appId || !pkg.name)) {
37203
+ _context.next = 1;
37204
+ break;
37205
+ }
37206
+ return _context.abrupt("return");
37207
+ case 1:
37208
+ setIsInstalling(true);
37209
+ setInstallResult(null);
37210
+ _context.prev = 2;
37211
+ _context.next = 3;
37212
+ return window.mainApi.themes.installThemeFromRegistry(appId, pkg.name);
37213
+ case 3:
37214
+ result = _context.sent;
37215
+ setInstallResult({
37216
+ status: result !== null && result !== void 0 && result.success ? "success" : "error",
37217
+ message: result !== null && result !== void 0 && result.success ? "Theme \"".concat(result.themeKey || pkg.displayName || pkg.name, "\" installed successfully.") : (result === null || result === void 0 ? void 0 : result.error) || "Installation failed."
37218
+ });
37219
+ if (result !== null && result !== void 0 && result.success) {
37220
+ // Refresh ThemeContext with updated themes
37221
+ if (result.themes) {
37222
+ changeThemesForApplication(result.themes);
37223
+ }
37224
+ if (onInstallComplete) {
37225
+ onInstallComplete(result);
37226
+ }
37227
+ }
37228
+ _context.next = 5;
37229
+ break;
37230
+ case 4:
37231
+ _context.prev = 4;
37232
+ _t = _context["catch"](2);
37233
+ setInstallResult({
37234
+ status: "error",
37235
+ message: _t.message || "Failed to install theme."
37236
+ });
37237
+ case 5:
37238
+ _context.prev = 5;
37239
+ setIsInstalling(false);
37240
+ return _context.finish(5);
37241
+ case 6:
37242
+ case "end":
37243
+ return _context.stop();
37244
+ }
37245
+ }, _callee, null, [[2, 4, 5, 6]]);
37246
+ }));
37247
+ return _handleInstall.apply(this, arguments);
37248
+ }
37249
+ var colorEntries = [{
37250
+ label: "Primary",
37251
+ value: colors.primary
37252
+ }, {
37253
+ label: "Secondary",
37254
+ value: colors.secondary
37255
+ }, {
37256
+ label: "Tertiary",
37257
+ value: colors.tertiary
37258
+ }, {
37259
+ label: "Neutral",
37260
+ value: colors.neutral
37261
+ }].filter(function (c) {
37262
+ return c.value;
37263
+ });
37264
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
37265
+ className: "flex flex-col flex-1 min-h-0",
37266
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
37267
+ className: "flex-1 min-h-0 overflow-y-auto p-6 space-y-6 ".concat(panelStyles.textColor || "text-gray-200"),
37268
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
37269
+ className: "flex flex-row items-center gap-3",
37270
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
37271
+ className: "h-5 w-5 flex-shrink-0 flex items-center justify-center",
37272
+ children: /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
37273
+ icon: "palette",
37274
+ className: "h-5 w-5"
37275
+ })
37276
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
37277
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.SubHeading3, {
37278
+ title: pkg.displayName || pkg.name,
37279
+ padding: false
37280
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
37281
+ className: "flex items-center gap-2 mt-0.5",
37282
+ children: [/*#__PURE__*/jsxRuntime.jsxs("span", {
37283
+ className: "text-sm opacity-60",
37284
+ children: ["by ", pkg.author || "Unknown"]
37285
+ }), pkg.version && /*#__PURE__*/jsxRuntime.jsxs("span", {
37286
+ className: "text-xs px-2 py-0.5 rounded ".concat(currentTheme["bg-primary-medium"], " opacity-70"),
37287
+ children: ["v", pkg.version]
37288
+ })]
37289
+ })]
37290
+ })]
37291
+ }), /*#__PURE__*/jsxRuntime.jsx("hr", {
37292
+ className: currentTheme["border-primary-medium"]
37293
+ }), colorEntries.length > 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
37294
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
37295
+ className: "text-xs font-semibold opacity-50 mb-2 block",
37296
+ children: "COLORS"
37297
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
37298
+ className: "flex flex-row gap-3",
37299
+ children: colorEntries.map(function (_ref2) {
37300
+ var label = _ref2.label,
37301
+ value = _ref2.value;
37302
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
37303
+ className: "flex flex-col items-center gap-1",
37304
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
37305
+ className: "h-10 w-10 rounded-full border-2 border-white/20",
37306
+ style: {
37307
+ backgroundColor: value
37308
+ }
37309
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
37310
+ className: "text-[10px] opacity-50",
37311
+ children: label
37312
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
37313
+ className: "text-[10px] opacity-30 font-mono",
37314
+ children: value
37315
+ })]
37316
+ }, label);
37317
+ })
37318
+ })]
37319
+ }), pkg.description && /*#__PURE__*/jsxRuntime.jsx("p", {
37320
+ className: "text-sm",
37321
+ children: pkg.description
37322
+ }), pkg.tags && pkg.tags.length > 0 && /*#__PURE__*/jsxRuntime.jsx("div", {
37323
+ className: "flex flex-wrap gap-1",
37324
+ children: pkg.tags.map(function (tag) {
37325
+ return /*#__PURE__*/jsxRuntime.jsx("span", {
37326
+ className: "text-xs px-2 py-0.5 rounded ".concat(currentTheme["bg-primary-medium"], " opacity-60"),
37327
+ children: tag
37328
+ }, tag);
37329
+ })
37330
+ }), installResult && /*#__PURE__*/jsxRuntime.jsx("div", {
37331
+ className: "p-2 rounded border ".concat(installResult.status === "success" ? "bg-green-900/20 border-green-700" : "bg-red-900/30 border-red-700"),
37332
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
37333
+ className: "flex items-center gap-2",
37334
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
37335
+ icon: installResult.status === "success" ? "circle-check" : "circle-xmark",
37336
+ className: "h-4 w-4 ".concat(installResult.status === "success" ? "text-green-400" : "text-red-400")
37337
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
37338
+ className: "text-sm ".concat(installResult.status === "error" ? "text-red-400" : ""),
37339
+ children: installResult.message
37340
+ })]
37341
+ })
37342
+ })]
37343
+ }), (installResult === null || installResult === void 0 ? void 0 : installResult.status) !== "success" && /*#__PURE__*/jsxRuntime.jsx("div", {
37344
+ className: "flex items-center justify-end px-6 py-3 border-t ".concat(currentTheme["border-primary-medium"]),
37345
+ children: /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
37346
+ title: isInstalling ? "Installing..." : "Install Theme",
37347
+ bgColor: "bg-blue-600",
37348
+ hoverBackgroundColor: isInstalling ? "" : "hover:bg-blue-700",
37349
+ textSize: "text-sm",
37350
+ padding: "py-1.5 px-4",
37351
+ onClick: handleInstall,
37352
+ disabled: isInstalling
37353
+ })
37354
+ })]
37355
+ });
37356
+ };
37357
+
37358
+ var DiscoverThemesDetail = function DiscoverThemesDetail(_ref) {
37359
+ var onBack = _ref.onBack,
37360
+ appId = _ref.appId,
37361
+ onInstallComplete = _ref.onInstallComplete;
37362
+ var _useContext = React.useContext(DashReact.ThemeContext),
37363
+ currentTheme = _useContext.currentTheme;
37364
+ var panelStyles = DashReact.getStylesForItem(DashReact.themeObjects.PANEL, currentTheme, {
37365
+ grow: false
37366
+ });
37367
+ var _useState = React.useState([]),
37368
+ _useState2 = _slicedToArray(_useState, 2),
37369
+ packages = _useState2[0],
37370
+ setPackages = _useState2[1];
37371
+ var _useState3 = React.useState(false),
37372
+ _useState4 = _slicedToArray(_useState3, 2),
37373
+ isLoading = _useState4[0],
37374
+ setIsLoading = _useState4[1];
37375
+ var _useState5 = React.useState(null),
37376
+ _useState6 = _slicedToArray(_useState5, 2),
37377
+ error = _useState6[0],
37378
+ setError = _useState6[1];
37379
+ var _useState7 = React.useState(""),
37380
+ _useState8 = _slicedToArray(_useState7, 2),
37381
+ searchQuery = _useState8[0],
37382
+ setSearchQuery = _useState8[1];
37383
+ var _useState9 = React.useState(null),
37384
+ _useState0 = _slicedToArray(_useState9, 2),
37385
+ selectedPackageName = _useState0[0],
37386
+ setSelectedPackageName = _useState0[1];
37387
+ var search = React.useCallback(/*#__PURE__*/function () {
37388
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(query) {
37389
+ var _window$mainApi;
37390
+ var result, _t;
37391
+ return _regeneratorRuntime.wrap(function (_context) {
37392
+ while (1) switch (_context.prev = _context.next) {
37393
+ case 0:
37394
+ if ((_window$mainApi = window.mainApi) !== null && _window$mainApi !== void 0 && (_window$mainApi = _window$mainApi.registry) !== null && _window$mainApi !== void 0 && _window$mainApi.searchThemes) {
37395
+ _context.next = 1;
37396
+ break;
37397
+ }
37398
+ setPackages([]);
37399
+ return _context.abrupt("return");
37400
+ case 1:
37401
+ setIsLoading(true);
37402
+ setError(null);
37403
+ _context.prev = 2;
37404
+ _context.next = 3;
37405
+ return window.mainApi.registry.searchThemes(query || "", {});
37406
+ case 3:
37407
+ result = _context.sent;
37408
+ setPackages((result === null || result === void 0 ? void 0 : result.packages) || []);
37409
+ _context.next = 5;
37410
+ break;
37411
+ case 4:
37412
+ _context.prev = 4;
37413
+ _t = _context["catch"](2);
37414
+ setError(_t.message || "Failed to search theme registry");
37415
+ setPackages([]);
37416
+ case 5:
37417
+ _context.prev = 5;
37418
+ setIsLoading(false);
37419
+ return _context.finish(5);
37420
+ case 6:
37421
+ case "end":
37422
+ return _context.stop();
37423
+ }
37424
+ }, _callee, null, [[2, 4, 5, 6]]);
37425
+ }));
37426
+ return function (_x) {
37427
+ return _ref2.apply(this, arguments);
37428
+ };
37429
+ }(), []);
37430
+
37431
+ // Debounce search on query changes
37432
+ React.useEffect(function () {
37433
+ var timer = setTimeout(function () {
37434
+ search(searchQuery);
37435
+ }, 300);
37436
+ return function () {
37437
+ return clearTimeout(timer);
37438
+ };
37439
+ // eslint-disable-next-line react-hooks/exhaustive-deps
37440
+ }, [searchQuery]);
37441
+ var retry = function retry() {
37442
+ return search(searchQuery);
37443
+ };
37444
+ var selectedPackage = selectedPackageName ? packages.find(function (p) {
37445
+ return p.name === selectedPackageName;
37446
+ }) : null;
37447
+
37448
+ // If a package is selected, show its detail inline
37449
+ if (selectedPackage) {
37450
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
37451
+ className: "flex flex-col flex-1 min-h-0",
36415
37452
  children: [/*#__PURE__*/jsxRuntime.jsx("div", {
36416
- children: !isActive && onDelete && /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
36417
- title: "Delete",
37453
+ className: "flex-shrink-0 px-4 pt-4",
37454
+ children: /*#__PURE__*/jsxRuntime.jsxs("button", {
37455
+ type: "button",
36418
37456
  onClick: function onClick() {
36419
- return onDelete(themeKey);
37457
+ return setSelectedPackageName(null);
36420
37458
  },
36421
- size: "sm"
37459
+ className: "flex items-center gap-1.5 text-sm opacity-60 hover:opacity-100 transition-opacity",
37460
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
37461
+ icon: "arrow-left",
37462
+ className: "h-3 w-3"
37463
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
37464
+ children: "Back"
37465
+ })]
36422
37466
  })
36423
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
36424
- className: "flex flex-row gap-2",
36425
- children: [!isActive && /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
36426
- title: "Activate",
37467
+ }), /*#__PURE__*/jsxRuntime.jsx(RegistryThemeDetail, {
37468
+ themePackage: selectedPackage,
37469
+ appId: appId,
37470
+ onInstallComplete: onInstallComplete
37471
+ })]
37472
+ });
37473
+ }
37474
+
37475
+ // Package list view
37476
+ var listBody;
37477
+ if (isLoading) {
37478
+ listBody = /*#__PURE__*/jsxRuntime.jsx("div", {
37479
+ className: "flex items-center justify-center py-12",
37480
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
37481
+ className: "text-center",
37482
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
37483
+ className: "animate-spin rounded-full h-6 w-6 border-b-2 border-blue-500 mx-auto mb-3"
37484
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
37485
+ className: "text-sm opacity-50",
37486
+ children: "Loading themes..."
37487
+ })]
37488
+ })
37489
+ });
37490
+ } else if (error) {
37491
+ listBody = /*#__PURE__*/jsxRuntime.jsxs("div", {
37492
+ className: "px-4 py-8 text-center",
37493
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
37494
+ className: "text-sm text-red-400 mb-3",
37495
+ children: error
37496
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
37497
+ title: "Retry",
37498
+ bgColor: "bg-gray-700",
37499
+ hoverBackgroundColor: "hover:bg-gray-600",
37500
+ textSize: "text-sm",
37501
+ padding: "py-1 px-3",
37502
+ onClick: retry
37503
+ })]
37504
+ });
37505
+ } else if (packages.length === 0) {
37506
+ listBody = /*#__PURE__*/jsxRuntime.jsx("div", {
37507
+ className: "px-4 py-8 text-center",
37508
+ children: /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
37509
+ className: "text-sm opacity-50",
37510
+ children: searchQuery ? "No themes match your search." : "No theme packages available."
37511
+ })
37512
+ });
37513
+ } else {
37514
+ listBody = /*#__PURE__*/jsxRuntime.jsx("div", {
37515
+ className: "space-y-1",
37516
+ children: packages.map(function (pkg) {
37517
+ var colors = pkg.colors || {};
37518
+ return /*#__PURE__*/jsxRuntime.jsx(DashReact.Sidebar.Item, {
37519
+ icon: /*#__PURE__*/jsxRuntime.jsx("div", {
37520
+ className: "flex items-center gap-0.5",
37521
+ children: [colors.primary, colors.secondary, colors.tertiary].filter(Boolean).map(function (color, i) {
37522
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
37523
+ className: "h-3 w-3 rounded-full border border-white/20",
37524
+ style: {
37525
+ backgroundColor: color
37526
+ }
37527
+ }, i);
37528
+ })
37529
+ }),
36427
37530
  onClick: function onClick() {
36428
- return onActivate(themeKey);
37531
+ return setSelectedPackageName(pkg.name);
36429
37532
  },
36430
- size: "sm"
36431
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
36432
- title: "Edit",
36433
- onClick: onOpenThemeEditor,
36434
- size: "sm"
37533
+ children: pkg.displayName || pkg.name
37534
+ }, pkg.name);
37535
+ })
37536
+ });
37537
+ }
37538
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
37539
+ className: "flex flex-col flex-1 min-h-0 ".concat(panelStyles.textColor || "text-gray-200"),
37540
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
37541
+ className: "flex-shrink-0 px-4 pt-4",
37542
+ children: /*#__PURE__*/jsxRuntime.jsxs("button", {
37543
+ type: "button",
37544
+ onClick: onBack,
37545
+ className: "flex items-center gap-1.5 text-sm opacity-60 hover:opacity-100 transition-opacity",
37546
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
37547
+ icon: "arrow-left",
37548
+ className: "h-3 w-3"
37549
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
37550
+ children: "Back"
36435
37551
  })]
36436
- })]
37552
+ })
37553
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
37554
+ className: "flex-shrink-0 px-4 py-3",
37555
+ children: /*#__PURE__*/jsxRuntime.jsx(DashReact.SearchInput, {
37556
+ value: searchQuery,
37557
+ onChange: setSearchQuery,
37558
+ placeholder: "Search themes...",
37559
+ inputClassName: "py-1.5 text-xs"
37560
+ })
37561
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
37562
+ className: "flex-1 min-h-0 overflow-y-auto px-2",
37563
+ children: listBody
37564
+ }), !isLoading && !error && packages.length > 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
37565
+ className: "flex-shrink-0 px-4 py-2 text-[10px] opacity-40 border-t border-white/10",
37566
+ children: [packages.length, " theme", packages.length !== 1 ? "s" : ""]
36437
37567
  })]
36438
37568
  });
36439
37569
  };
@@ -36479,18 +37609,31 @@ var ThemesSection = function ThemesSection(_ref) {
36479
37609
  _useState0 = _slicedToArray(_useState9, 2),
36480
37610
  wizardTheme = _useState0[0],
36481
37611
  setWizardTheme = _useState0[1];
37612
+ // null | "marketplace"
37613
+ var _useState1 = React.useState(null),
37614
+ _useState10 = _slicedToArray(_useState1, 2),
37615
+ installMode = _useState10[0],
37616
+ setInstallMode = _useState10[1];
36482
37617
  var themeEntries = themes ? Object.entries(themes) : [];
36483
37618
  var appId = credentials === null || credentials === void 0 ? void 0 : credentials.appId;
37619
+ var rowStyles = DashReact.getStylesForItem(DashReact.themeObjects.PANEL_HEADER, currentTheme, {
37620
+ grow: false
37621
+ });
36484
37622
 
36485
37623
  // Handle create request from parent — enter wizard mode
37624
+ var prevCreateRequested = React.useRef(false);
36486
37625
  React.useEffect(function () {
36487
- if (createRequested) {
37626
+ if (createRequested && !prevCreateRequested.current) {
36488
37627
  setGenerateMode(GENERATE_MODES.WIZARD);
36489
37628
  setWizardName("");
36490
37629
  setWizardMethod(null);
36491
37630
  setWizardTheme(null);
36492
37631
  setSelectedThemeKey(null);
36493
- onCreateAcknowledged && onCreateAcknowledged();
37632
+ setInstallMode(null);
37633
+ }
37634
+ prevCreateRequested.current = createRequested;
37635
+ if (createRequested && onCreateAcknowledged) {
37636
+ onCreateAcknowledged();
36494
37637
  }
36495
37638
  // eslint-disable-next-line react-hooks/exhaustive-deps
36496
37639
  }, [createRequested]);
@@ -36561,63 +37704,109 @@ var ThemesSection = function ThemesSection(_ref) {
36561
37704
  function handleEdit() {
36562
37705
  if (onOpenThemeEditor) onOpenThemeEditor();
36563
37706
  }
36564
- var rowStyles = DashReact.getStylesForItem(DashReact.themeObjects.PANEL_HEADER, currentTheme, {
36565
- grow: false
36566
- });
36567
37707
  var listContent = /*#__PURE__*/jsxRuntime.jsxs("div", {
36568
- className: "flex flex-col",
37708
+ className: "flex flex-col h-full",
36569
37709
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
36570
- className: "flex flex-row items-center justify-between px-3 py-3 border-b ".concat(rowStyles.borderColor || ""),
37710
+ className: "flex-shrink-0 flex flex-col gap-2 px-3 py-2 ".concat(rowStyles.backgroundColor || ""),
36571
37711
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
36572
- className: "flex flex-row items-center gap-2",
36573
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
36574
- icon: "sun",
36575
- className: "h-3 w-3 opacity-50"
36576
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Switch, {
36577
- checked: themeVariant === "dark",
36578
- onChange: handleToggleVariant
36579
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
36580
- icon: "moon",
36581
- className: "h-3 w-3 opacity-50"
37712
+ className: "flex flex-row items-center justify-between",
37713
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
37714
+ className: "flex flex-row items-center gap-2",
37715
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
37716
+ icon: "sun",
37717
+ className: "h-3 w-3 opacity-50"
37718
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Switch, {
37719
+ checked: themeVariant === "dark",
37720
+ onChange: handleToggleVariant
37721
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
37722
+ icon: "moon",
37723
+ className: "h-3 w-3 opacity-50"
37724
+ })]
37725
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
37726
+ className: "text-xs opacity-50",
37727
+ children: themeVariant === "dark" ? "Dark" : "Light"
36582
37728
  })]
36583
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
36584
- className: "text-xs opacity-50",
36585
- children: themeVariant === "dark" ? "Dark" : "Light"
36586
- })]
36587
- }), /*#__PURE__*/jsxRuntime.jsxs(DashReact.Sidebar.Content, {
36588
- children: [themeEntries.map(function (_ref4) {
36589
- var _ref5 = _slicedToArray(_ref4, 2),
36590
- key = _ref5[0],
36591
- theme = _ref5[1];
36592
- var isActive = key === currentThemeKey;
36593
- var isSelected = selectedThemeKey === key && generateMode === GENERATE_MODES.NONE;
36594
- return /*#__PURE__*/jsxRuntime.jsx(DashReact.Sidebar.Item, {
36595
- icon: isActive ? /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
36596
- icon: "check",
36597
- className: "h-3 w-3 text-green-500"
36598
- }) : /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
36599
- icon: "palette",
36600
- className: "h-3.5 w-3.5"
36601
- }),
36602
- active: isSelected,
36603
- onClick: function onClick() {
36604
- setSelectedThemeKey(key);
36605
- setGenerateMode(GENERATE_MODES.NONE);
36606
- },
36607
- badge: isActive ? "active" : null,
36608
- className: isSelected ? "bg-white/10 opacity-100" : "",
36609
- children: theme.name || key
36610
- }, key);
36611
- }), themeEntries.length === 0 && /*#__PURE__*/jsxRuntime.jsx("span", {
36612
- className: "text-sm opacity-40 py-8 text-center",
36613
- children: "No themes available"
37729
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
37730
+ className: "flex bg-white/5 rounded-md p-0.5",
37731
+ children: [{
37732
+ key: "themes",
37733
+ label: "My Themes"
37734
+ }, {
37735
+ key: "marketplace",
37736
+ label: "Marketplace"
37737
+ }].map(function (tab) {
37738
+ var currentTab = installMode === "marketplace" ? "marketplace" : "themes";
37739
+ return /*#__PURE__*/jsxRuntime.jsx("button", {
37740
+ type: "button",
37741
+ onClick: function onClick() {
37742
+ if (tab.key === "marketplace") {
37743
+ setInstallMode("marketplace");
37744
+ setSelectedThemeKey(null);
37745
+ setGenerateMode(GENERATE_MODES.NONE);
37746
+ } else {
37747
+ setInstallMode(null);
37748
+ }
37749
+ },
37750
+ className: "flex-1 px-2 py-0.5 rounded text-[11px] transition-colors ".concat(currentTab === tab.key ? "bg-white/10 font-medium opacity-90" : "opacity-50 hover:opacity-70"),
37751
+ children: tab.label
37752
+ }, tab.key);
37753
+ })
36614
37754
  })]
37755
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
37756
+ className: "flex-1 overflow-y-auto min-h-0",
37757
+ children: /*#__PURE__*/jsxRuntime.jsxs(DashReact.Sidebar.Content, {
37758
+ children: [themeEntries.map(function (_ref4) {
37759
+ var _ref5 = _slicedToArray(_ref4, 2),
37760
+ key = _ref5[0],
37761
+ theme = _ref5[1];
37762
+ var isActive = key === currentThemeKey;
37763
+ var isSelected = selectedThemeKey === key && generateMode === GENERATE_MODES.NONE && installMode !== "marketplace";
37764
+ return /*#__PURE__*/jsxRuntime.jsx(DashReact.Sidebar.Item, {
37765
+ icon: isActive ? /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
37766
+ icon: "check",
37767
+ className: "h-3 w-3 text-green-500"
37768
+ }) : /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
37769
+ icon: "palette",
37770
+ className: "h-3.5 w-3.5"
37771
+ }),
37772
+ active: isSelected,
37773
+ onClick: function onClick() {
37774
+ setSelectedThemeKey(key);
37775
+ setGenerateMode(GENERATE_MODES.NONE);
37776
+ setInstallMode(null);
37777
+ },
37778
+ badge: isActive ? "active" : null,
37779
+ className: isSelected ? "bg-white/10 opacity-100" : "",
37780
+ children: theme.name || key
37781
+ }, key);
37782
+ }), themeEntries.length === 0 && /*#__PURE__*/jsxRuntime.jsx("span", {
37783
+ className: "text-sm opacity-40 py-8 text-center",
37784
+ children: "No themes available"
37785
+ })]
37786
+ })
36615
37787
  })]
36616
37788
  });
36617
37789
 
36618
37790
  // Determine detail content based on mode
36619
37791
  var detailContent = null;
36620
- if (generateMode === GENERATE_MODES.WIZARD) {
37792
+ if (installMode === "marketplace") {
37793
+ detailContent = /*#__PURE__*/jsxRuntime.jsx(DiscoverThemesDetail, {
37794
+ onBack: function onBack() {
37795
+ setInstallMode(null);
37796
+ },
37797
+ appId: appId,
37798
+ onInstallComplete: function onInstallComplete() {
37799
+ // Refresh themes after install
37800
+ if (dashApi && appId) {
37801
+ dashApi.listThemes(appId, function (e, message) {
37802
+ if (message && message.themes) {
37803
+ changeThemesForApplication(message.themes);
37804
+ }
37805
+ });
37806
+ }
37807
+ }
37808
+ });
37809
+ } else if (generateMode === GENERATE_MODES.WIZARD) {
36621
37810
  detailContent = /*#__PURE__*/jsxRuntime.jsx(ThemeQuickCreate, {
36622
37811
  wizardName: wizardName,
36623
37812
  setWizardName: setWizardName,
@@ -36643,7 +37832,8 @@ var ThemesSection = function ThemesSection(_ref) {
36643
37832
  themeVariant: themeVariant,
36644
37833
  onActivate: handleActivate,
36645
37834
  onOpenThemeEditor: handleEdit,
36646
- onDelete: handleDeleteTheme
37835
+ onDelete: handleDeleteTheme,
37836
+ appId: appId
36647
37837
  });
36648
37838
  }
36649
37839
  return /*#__PURE__*/jsxRuntime.jsx(SectionLayout, {