formalconf 2.0.1 → 2.0.2
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/formalconf.js +934 -869
- package/package.json +1 -1
package/dist/formalconf.js
CHANGED
|
@@ -1,78 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// src/cli/formalconf.tsx
|
|
3
|
-
import { useState as
|
|
4
|
-
import { render,
|
|
5
|
-
import { Spinner } from "@inkjs/ui";
|
|
6
|
-
|
|
7
|
-
// src/components/ui/VimSelect.tsx
|
|
8
|
-
import { useState } from "react";
|
|
9
|
-
import { Box, Text, useInput } from "ink";
|
|
10
|
-
|
|
11
|
-
// src/lib/theme.ts
|
|
12
|
-
var colors = {
|
|
13
|
-
primary: "#5eead4",
|
|
14
|
-
primaryDim: "#2dd4bf",
|
|
15
|
-
accent: "#06b6d4",
|
|
16
|
-
success: "#22c55e",
|
|
17
|
-
error: "#ef4444",
|
|
18
|
-
warning: "#f59e0b",
|
|
19
|
-
info: "#3b82f6",
|
|
20
|
-
text: "white",
|
|
21
|
-
textDim: "gray",
|
|
22
|
-
border: "#374151",
|
|
23
|
-
borderLight: "#4b5563"
|
|
24
|
-
};
|
|
25
|
-
var borderStyles = {
|
|
26
|
-
panel: "round",
|
|
27
|
-
header: "round",
|
|
28
|
-
footer: "single"
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// src/components/ui/VimSelect.tsx
|
|
32
|
-
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
33
|
-
function VimSelect({ options, onChange, isDisabled = false }) {
|
|
34
|
-
const [index, setIndex] = useState(0);
|
|
35
|
-
useInput((input, key) => {
|
|
36
|
-
if (isDisabled)
|
|
37
|
-
return;
|
|
38
|
-
if (input === "j" || key.downArrow) {
|
|
39
|
-
setIndex((i) => i < options.length - 1 ? i + 1 : i);
|
|
40
|
-
}
|
|
41
|
-
if (input === "k" || key.upArrow) {
|
|
42
|
-
setIndex((i) => i > 0 ? i - 1 : i);
|
|
43
|
-
}
|
|
44
|
-
if (input === "l" || key.return) {
|
|
45
|
-
onChange(options[index].value);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
return /* @__PURE__ */ jsxDEV(Box, {
|
|
49
|
-
flexDirection: "column",
|
|
50
|
-
children: options.map((opt, i) => /* @__PURE__ */ jsxDEV(Box, {
|
|
51
|
-
children: /* @__PURE__ */ jsxDEV(Text, {
|
|
52
|
-
color: i === index ? colors.primary : undefined,
|
|
53
|
-
children: [
|
|
54
|
-
i === index ? "❯" : " ",
|
|
55
|
-
" ",
|
|
56
|
-
opt.label
|
|
57
|
-
]
|
|
58
|
-
}, undefined, true, undefined, this)
|
|
59
|
-
}, opt.value, false, undefined, this))
|
|
60
|
-
}, undefined, false, undefined, this);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// src/cli/formalconf.tsx
|
|
64
|
-
import { readdirSync as readdirSync5, existsSync as existsSync6 } from "fs";
|
|
65
|
-
import { join as join5 } from "path";
|
|
3
|
+
import { useState as useState9, useEffect as useEffect6 } from "react";
|
|
4
|
+
import { render, useApp as useApp2, useInput as useInput9 } from "ink";
|
|
5
|
+
import { Spinner as Spinner2 } from "@inkjs/ui";
|
|
66
6
|
|
|
67
7
|
// src/components/layout/Layout.tsx
|
|
68
|
-
import { Box as
|
|
8
|
+
import { Box as Box5 } from "ink";
|
|
69
9
|
|
|
70
10
|
// src/hooks/useTerminalSize.ts
|
|
71
11
|
import { useStdout } from "ink";
|
|
72
|
-
import { useState
|
|
12
|
+
import { useState, useEffect } from "react";
|
|
73
13
|
function useTerminalSize() {
|
|
74
14
|
const { stdout } = useStdout();
|
|
75
|
-
const [size, setSize] =
|
|
15
|
+
const [size, setSize] = useState({
|
|
76
16
|
columns: stdout.columns || 80,
|
|
77
17
|
rows: stdout.rows || 24
|
|
78
18
|
});
|
|
@@ -92,10 +32,10 @@ function useTerminalSize() {
|
|
|
92
32
|
}
|
|
93
33
|
|
|
94
34
|
// src/components/Header.tsx
|
|
95
|
-
import { Box as
|
|
35
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
96
36
|
|
|
97
37
|
// src/hooks/useSystemStatus.ts
|
|
98
|
-
import { useState as
|
|
38
|
+
import { useState as useState2, useEffect as useEffect2 } from "react";
|
|
99
39
|
import { existsSync, readlinkSync, readdirSync, lstatSync } from "fs";
|
|
100
40
|
|
|
101
41
|
// src/lib/paths.ts
|
|
@@ -358,7 +298,7 @@ async function ensureConfigDir() {
|
|
|
358
298
|
// src/hooks/useSystemStatus.ts
|
|
359
299
|
import { basename, dirname as dirname2, join as join2 } from "path";
|
|
360
300
|
function useSystemStatus() {
|
|
361
|
-
const [status, setStatus] =
|
|
301
|
+
const [status, setStatus] = useState2({
|
|
362
302
|
currentTheme: null,
|
|
363
303
|
configsLinked: false,
|
|
364
304
|
loading: true
|
|
@@ -395,8 +335,30 @@ function useSystemStatus() {
|
|
|
395
335
|
}
|
|
396
336
|
|
|
397
337
|
// src/components/ui/StatusIndicator.tsx
|
|
398
|
-
import { Box
|
|
399
|
-
|
|
338
|
+
import { Box, Text } from "ink";
|
|
339
|
+
|
|
340
|
+
// src/lib/theme.ts
|
|
341
|
+
var colors = {
|
|
342
|
+
primary: "#5eead4",
|
|
343
|
+
primaryDim: "#2dd4bf",
|
|
344
|
+
accent: "#06b6d4",
|
|
345
|
+
success: "#22c55e",
|
|
346
|
+
error: "#ef4444",
|
|
347
|
+
warning: "#f59e0b",
|
|
348
|
+
info: "#3b82f6",
|
|
349
|
+
text: "white",
|
|
350
|
+
textDim: "gray",
|
|
351
|
+
border: "#374151",
|
|
352
|
+
borderLight: "#4b5563"
|
|
353
|
+
};
|
|
354
|
+
var borderStyles = {
|
|
355
|
+
panel: "round",
|
|
356
|
+
header: "round",
|
|
357
|
+
footer: "single"
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
// src/components/ui/StatusIndicator.tsx
|
|
361
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
400
362
|
function StatusIndicator({
|
|
401
363
|
label,
|
|
402
364
|
value,
|
|
@@ -414,17 +376,17 @@ function StatusIndicator({
|
|
|
414
376
|
error: "●",
|
|
415
377
|
neutral: "○"
|
|
416
378
|
};
|
|
417
|
-
return /* @__PURE__ */
|
|
379
|
+
return /* @__PURE__ */ jsxDEV(Box, {
|
|
418
380
|
gap: 1,
|
|
419
381
|
children: [
|
|
420
|
-
/* @__PURE__ */
|
|
382
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
421
383
|
dimColor: true,
|
|
422
384
|
children: [
|
|
423
385
|
label,
|
|
424
386
|
":"
|
|
425
387
|
]
|
|
426
388
|
}, undefined, true, undefined, this),
|
|
427
|
-
/* @__PURE__ */
|
|
389
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
428
390
|
color: statusColors[status],
|
|
429
391
|
children: [
|
|
430
392
|
icon[status],
|
|
@@ -438,7 +400,7 @@ function StatusIndicator({
|
|
|
438
400
|
// package.json
|
|
439
401
|
var package_default = {
|
|
440
402
|
name: "formalconf",
|
|
441
|
-
version: "2.0.
|
|
403
|
+
version: "2.0.2",
|
|
442
404
|
description: "Dotfiles management TUI for macOS - config management, package sync, and theme switching",
|
|
443
405
|
type: "module",
|
|
444
406
|
main: "./dist/formalconf.js",
|
|
@@ -491,11 +453,11 @@ var package_default = {
|
|
|
491
453
|
};
|
|
492
454
|
|
|
493
455
|
// src/components/Header.tsx
|
|
494
|
-
import { jsxDEV as
|
|
456
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
495
457
|
function Header() {
|
|
496
458
|
const { columns } = useTerminalSize();
|
|
497
459
|
const { currentTheme, configsLinked, loading } = useSystemStatus();
|
|
498
|
-
return /* @__PURE__ */
|
|
460
|
+
return /* @__PURE__ */ jsxDEV2(Box2, {
|
|
499
461
|
flexDirection: "column",
|
|
500
462
|
width: columns - 2,
|
|
501
463
|
borderStyle: borderStyles.header,
|
|
@@ -503,24 +465,24 @@ function Header() {
|
|
|
503
465
|
paddingX: 2,
|
|
504
466
|
marginBottom: 1,
|
|
505
467
|
children: [
|
|
506
|
-
/* @__PURE__ */
|
|
468
|
+
/* @__PURE__ */ jsxDEV2(Box2, {
|
|
507
469
|
justifyContent: "space-between",
|
|
508
470
|
width: "100%",
|
|
509
471
|
children: [
|
|
510
|
-
/* @__PURE__ */
|
|
472
|
+
/* @__PURE__ */ jsxDEV2(Box2, {
|
|
511
473
|
children: [
|
|
512
|
-
/* @__PURE__ */
|
|
474
|
+
/* @__PURE__ */ jsxDEV2(Text2, {
|
|
513
475
|
bold: true,
|
|
514
476
|
color: colors.primary,
|
|
515
477
|
children: "FormalConf"
|
|
516
478
|
}, undefined, false, undefined, this),
|
|
517
|
-
/* @__PURE__ */
|
|
479
|
+
/* @__PURE__ */ jsxDEV2(Text2, {
|
|
518
480
|
dimColor: true,
|
|
519
481
|
children: " - Dotfiles Manager"
|
|
520
482
|
}, undefined, false, undefined, this)
|
|
521
483
|
]
|
|
522
484
|
}, undefined, true, undefined, this),
|
|
523
|
-
/* @__PURE__ */
|
|
485
|
+
/* @__PURE__ */ jsxDEV2(Text2, {
|
|
524
486
|
dimColor: true,
|
|
525
487
|
children: [
|
|
526
488
|
"v",
|
|
@@ -529,16 +491,16 @@ function Header() {
|
|
|
529
491
|
}, undefined, true, undefined, this)
|
|
530
492
|
]
|
|
531
493
|
}, undefined, true, undefined, this),
|
|
532
|
-
!loading && /* @__PURE__ */
|
|
494
|
+
!loading && /* @__PURE__ */ jsxDEV2(Box2, {
|
|
533
495
|
marginTop: 1,
|
|
534
496
|
gap: 4,
|
|
535
497
|
children: [
|
|
536
|
-
/* @__PURE__ */
|
|
498
|
+
/* @__PURE__ */ jsxDEV2(StatusIndicator, {
|
|
537
499
|
label: "Theme",
|
|
538
500
|
value: currentTheme,
|
|
539
501
|
status: currentTheme ? "success" : "neutral"
|
|
540
502
|
}, undefined, false, undefined, this),
|
|
541
|
-
/* @__PURE__ */
|
|
503
|
+
/* @__PURE__ */ jsxDEV2(StatusIndicator, {
|
|
542
504
|
label: "Configs",
|
|
543
505
|
value: configsLinked ? "Linked" : "Not linked",
|
|
544
506
|
status: configsLinked ? "success" : "warning"
|
|
@@ -550,8 +512,8 @@ function Header() {
|
|
|
550
512
|
}
|
|
551
513
|
|
|
552
514
|
// src/components/layout/Footer.tsx
|
|
553
|
-
import { Box as
|
|
554
|
-
import { jsxDEV as
|
|
515
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
516
|
+
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
555
517
|
var defaultShortcuts = [
|
|
556
518
|
{ key: "↑↓/jk", label: "Navigate" },
|
|
557
519
|
{ key: "Enter/l", label: "Select" },
|
|
@@ -560,7 +522,7 @@ var defaultShortcuts = [
|
|
|
560
522
|
];
|
|
561
523
|
function Footer({ shortcuts = defaultShortcuts }) {
|
|
562
524
|
const { columns } = useTerminalSize();
|
|
563
|
-
return /* @__PURE__ */
|
|
525
|
+
return /* @__PURE__ */ jsxDEV3(Box3, {
|
|
564
526
|
width: columns - 2,
|
|
565
527
|
borderStyle: borderStyles.footer,
|
|
566
528
|
borderColor: colors.border,
|
|
@@ -568,15 +530,15 @@ function Footer({ shortcuts = defaultShortcuts }) {
|
|
|
568
530
|
marginTop: 1,
|
|
569
531
|
justifyContent: "center",
|
|
570
532
|
gap: 2,
|
|
571
|
-
children: shortcuts.map((shortcut, index) => /* @__PURE__ */
|
|
533
|
+
children: shortcuts.map((shortcut, index) => /* @__PURE__ */ jsxDEV3(Box3, {
|
|
572
534
|
gap: 1,
|
|
573
535
|
children: [
|
|
574
|
-
/* @__PURE__ */
|
|
536
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
575
537
|
color: colors.primary,
|
|
576
538
|
bold: true,
|
|
577
539
|
children: shortcut.key
|
|
578
540
|
}, undefined, false, undefined, this),
|
|
579
|
-
/* @__PURE__ */
|
|
541
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
580
542
|
dimColor: true,
|
|
581
543
|
children: shortcut.label
|
|
582
544
|
}, undefined, false, undefined, this)
|
|
@@ -586,14 +548,14 @@ function Footer({ shortcuts = defaultShortcuts }) {
|
|
|
586
548
|
}
|
|
587
549
|
|
|
588
550
|
// src/components/layout/Breadcrumb.tsx
|
|
589
|
-
import
|
|
590
|
-
import { Box as
|
|
591
|
-
import { jsxDEV as
|
|
551
|
+
import React from "react";
|
|
552
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
553
|
+
import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
|
|
592
554
|
function Breadcrumb({ path }) {
|
|
593
|
-
return /* @__PURE__ */
|
|
594
|
-
children: path.map((segment, index) => /* @__PURE__ */
|
|
555
|
+
return /* @__PURE__ */ jsxDEV4(Box4, {
|
|
556
|
+
children: path.map((segment, index) => /* @__PURE__ */ jsxDEV4(React.Fragment, {
|
|
595
557
|
children: [
|
|
596
|
-
index > 0 && /* @__PURE__ */
|
|
558
|
+
index > 0 && /* @__PURE__ */ jsxDEV4(Text4, {
|
|
597
559
|
color: colors.textDim,
|
|
598
560
|
children: [
|
|
599
561
|
" ",
|
|
@@ -601,7 +563,7 @@ function Breadcrumb({ path }) {
|
|
|
601
563
|
" "
|
|
602
564
|
]
|
|
603
565
|
}, undefined, true, undefined, this),
|
|
604
|
-
/* @__PURE__ */
|
|
566
|
+
/* @__PURE__ */ jsxDEV4(Text4, {
|
|
605
567
|
color: index === path.length - 1 ? colors.primary : colors.textDim,
|
|
606
568
|
bold: index === path.length - 1,
|
|
607
569
|
children: segment
|
|
@@ -612,39 +574,39 @@ function Breadcrumb({ path }) {
|
|
|
612
574
|
}
|
|
613
575
|
|
|
614
576
|
// src/components/layout/Layout.tsx
|
|
615
|
-
import { jsxDEV as
|
|
577
|
+
import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
|
|
616
578
|
function Layout({
|
|
617
579
|
children,
|
|
618
580
|
breadcrumb = ["Main"],
|
|
619
581
|
showFooter = true
|
|
620
582
|
}) {
|
|
621
583
|
const { columns } = useTerminalSize();
|
|
622
|
-
return /* @__PURE__ */
|
|
584
|
+
return /* @__PURE__ */ jsxDEV5(Box5, {
|
|
623
585
|
flexDirection: "column",
|
|
624
586
|
width: columns,
|
|
625
587
|
padding: 1,
|
|
626
588
|
children: [
|
|
627
|
-
/* @__PURE__ */
|
|
628
|
-
breadcrumb.length > 1 && /* @__PURE__ */
|
|
589
|
+
/* @__PURE__ */ jsxDEV5(Header, {}, undefined, false, undefined, this),
|
|
590
|
+
breadcrumb.length > 1 && /* @__PURE__ */ jsxDEV5(Box5, {
|
|
629
591
|
marginBottom: 1,
|
|
630
592
|
marginLeft: 1,
|
|
631
|
-
children: /* @__PURE__ */
|
|
593
|
+
children: /* @__PURE__ */ jsxDEV5(Breadcrumb, {
|
|
632
594
|
path: breadcrumb
|
|
633
595
|
}, undefined, false, undefined, this)
|
|
634
596
|
}, undefined, false, undefined, this),
|
|
635
|
-
/* @__PURE__ */
|
|
597
|
+
/* @__PURE__ */ jsxDEV5(Box5, {
|
|
636
598
|
flexDirection: "column",
|
|
637
599
|
flexGrow: 1,
|
|
638
600
|
children
|
|
639
601
|
}, undefined, false, undefined, this),
|
|
640
|
-
showFooter && /* @__PURE__ */
|
|
602
|
+
showFooter && /* @__PURE__ */ jsxDEV5(Footer, {}, undefined, false, undefined, this)
|
|
641
603
|
]
|
|
642
604
|
}, undefined, true, undefined, this);
|
|
643
605
|
}
|
|
644
606
|
|
|
645
607
|
// src/components/layout/Panel.tsx
|
|
646
|
-
import { Box as
|
|
647
|
-
import { jsxDEV as
|
|
608
|
+
import { Box as Box6, Text as Text5 } from "ink";
|
|
609
|
+
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
648
610
|
function Panel({
|
|
649
611
|
title,
|
|
650
612
|
children,
|
|
@@ -652,7 +614,7 @@ function Panel({
|
|
|
652
614
|
flexGrow,
|
|
653
615
|
borderColor = colors.border
|
|
654
616
|
}) {
|
|
655
|
-
return /* @__PURE__ */
|
|
617
|
+
return /* @__PURE__ */ jsxDEV6(Box6, {
|
|
656
618
|
flexDirection: "column",
|
|
657
619
|
width,
|
|
658
620
|
flexGrow,
|
|
@@ -660,9 +622,9 @@ function Panel({
|
|
|
660
622
|
borderColor,
|
|
661
623
|
paddingX: 1,
|
|
662
624
|
children: [
|
|
663
|
-
title && /* @__PURE__ */
|
|
625
|
+
title && /* @__PURE__ */ jsxDEV6(Box6, {
|
|
664
626
|
marginBottom: 1,
|
|
665
|
-
children: /* @__PURE__ */
|
|
627
|
+
children: /* @__PURE__ */ jsxDEV6(Text5, {
|
|
666
628
|
bold: true,
|
|
667
629
|
color: colors.primary,
|
|
668
630
|
children: title
|
|
@@ -673,34 +635,144 @@ function Panel({
|
|
|
673
635
|
}, undefined, true, undefined, this);
|
|
674
636
|
}
|
|
675
637
|
|
|
676
|
-
// src/components/
|
|
638
|
+
// src/components/PrerequisiteError.tsx
|
|
639
|
+
import { Box as Box7, Text as Text6, useInput } from "ink";
|
|
640
|
+
import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
|
|
641
|
+
function PrerequisiteError({ missing, onExit }) {
|
|
642
|
+
useInput(() => onExit());
|
|
643
|
+
return /* @__PURE__ */ jsxDEV7(Layout, {
|
|
644
|
+
breadcrumb: ["Error"],
|
|
645
|
+
children: /* @__PURE__ */ jsxDEV7(Panel, {
|
|
646
|
+
title: "Missing Prerequisites",
|
|
647
|
+
borderColor: colors.error,
|
|
648
|
+
children: [
|
|
649
|
+
/* @__PURE__ */ jsxDEV7(Text6, {
|
|
650
|
+
color: colors.error,
|
|
651
|
+
children: "Required tools are not installed:"
|
|
652
|
+
}, undefined, false, undefined, this),
|
|
653
|
+
/* @__PURE__ */ jsxDEV7(Box7, {
|
|
654
|
+
flexDirection: "column",
|
|
655
|
+
marginTop: 1,
|
|
656
|
+
children: missing.map((dep) => /* @__PURE__ */ jsxDEV7(Box7, {
|
|
657
|
+
children: [
|
|
658
|
+
/* @__PURE__ */ jsxDEV7(Text6, {
|
|
659
|
+
color: colors.warning,
|
|
660
|
+
children: [
|
|
661
|
+
"• ",
|
|
662
|
+
dep.name
|
|
663
|
+
]
|
|
664
|
+
}, undefined, true, undefined, this),
|
|
665
|
+
/* @__PURE__ */ jsxDEV7(Text6, {
|
|
666
|
+
dimColor: true,
|
|
667
|
+
children: [
|
|
668
|
+
" — Install: ",
|
|
669
|
+
dep.install
|
|
670
|
+
]
|
|
671
|
+
}, undefined, true, undefined, this)
|
|
672
|
+
]
|
|
673
|
+
}, dep.name, true, undefined, this))
|
|
674
|
+
}, undefined, false, undefined, this),
|
|
675
|
+
/* @__PURE__ */ jsxDEV7(Box7, {
|
|
676
|
+
marginTop: 1,
|
|
677
|
+
children: /* @__PURE__ */ jsxDEV7(Text6, {
|
|
678
|
+
dimColor: true,
|
|
679
|
+
children: "Press any key to exit..."
|
|
680
|
+
}, undefined, false, undefined, this)
|
|
681
|
+
}, undefined, false, undefined, this)
|
|
682
|
+
]
|
|
683
|
+
}, undefined, true, undefined, this)
|
|
684
|
+
}, undefined, false, undefined, this);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// src/components/menus/MainMenu.tsx
|
|
688
|
+
import { useApp } from "ink";
|
|
689
|
+
|
|
690
|
+
// src/components/ui/VimSelect.tsx
|
|
691
|
+
import { useState as useState3 } from "react";
|
|
677
692
|
import { Box as Box8, Text as Text7, useInput as useInput2 } from "ink";
|
|
678
693
|
import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
|
|
694
|
+
function VimSelect({ options, onChange, isDisabled = false }) {
|
|
695
|
+
const [index, setIndex] = useState3(0);
|
|
696
|
+
useInput2((input, key) => {
|
|
697
|
+
if (isDisabled)
|
|
698
|
+
return;
|
|
699
|
+
if (input === "j" || key.downArrow) {
|
|
700
|
+
setIndex((i) => i < options.length - 1 ? i + 1 : i);
|
|
701
|
+
}
|
|
702
|
+
if (input === "k" || key.upArrow) {
|
|
703
|
+
setIndex((i) => i > 0 ? i - 1 : i);
|
|
704
|
+
}
|
|
705
|
+
if (input === "l" || key.return) {
|
|
706
|
+
onChange(options[index].value);
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
return /* @__PURE__ */ jsxDEV8(Box8, {
|
|
710
|
+
flexDirection: "column",
|
|
711
|
+
children: options.map((opt, i) => /* @__PURE__ */ jsxDEV8(Box8, {
|
|
712
|
+
children: /* @__PURE__ */ jsxDEV8(Text7, {
|
|
713
|
+
color: i === index ? colors.primary : undefined,
|
|
714
|
+
children: [
|
|
715
|
+
i === index ? "❯" : " ",
|
|
716
|
+
" ",
|
|
717
|
+
opt.label
|
|
718
|
+
]
|
|
719
|
+
}, undefined, true, undefined, this)
|
|
720
|
+
}, opt.value, false, undefined, this))
|
|
721
|
+
}, undefined, false, undefined, this);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// src/components/menus/MainMenu.tsx
|
|
725
|
+
import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
|
|
726
|
+
function MainMenu({ onSelect }) {
|
|
727
|
+
const { exit } = useApp();
|
|
728
|
+
return /* @__PURE__ */ jsxDEV9(Panel, {
|
|
729
|
+
title: "Main Menu",
|
|
730
|
+
children: /* @__PURE__ */ jsxDEV9(VimSelect, {
|
|
731
|
+
options: [
|
|
732
|
+
{ label: "Config Manager", value: "config" },
|
|
733
|
+
{ label: "Package Sync", value: "packages" },
|
|
734
|
+
{ label: "Set Theme", value: "themes" },
|
|
735
|
+
{ label: "Exit", value: "exit" }
|
|
736
|
+
],
|
|
737
|
+
onChange: (value) => {
|
|
738
|
+
if (value === "exit") {
|
|
739
|
+
exit();
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
onSelect(value);
|
|
743
|
+
}
|
|
744
|
+
}, undefined, false, undefined, this)
|
|
745
|
+
}, undefined, false, undefined, this);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// src/components/CommandOutput.tsx
|
|
749
|
+
import { Box as Box9, Text as Text8, useInput as useInput3 } from "ink";
|
|
750
|
+
import { jsxDEV as jsxDEV10 } from "react/jsx-dev-runtime";
|
|
679
751
|
function CommandOutput({
|
|
680
752
|
title,
|
|
681
753
|
output,
|
|
682
754
|
success = true,
|
|
683
755
|
onDismiss
|
|
684
756
|
}) {
|
|
685
|
-
|
|
757
|
+
useInput3(() => {
|
|
686
758
|
onDismiss();
|
|
687
759
|
});
|
|
688
|
-
return /* @__PURE__ */
|
|
760
|
+
return /* @__PURE__ */ jsxDEV10(Panel, {
|
|
689
761
|
title,
|
|
690
762
|
borderColor: success ? colors.success : colors.error,
|
|
691
763
|
children: [
|
|
692
|
-
output && /* @__PURE__ */
|
|
764
|
+
output && /* @__PURE__ */ jsxDEV10(Box9, {
|
|
693
765
|
flexDirection: "column",
|
|
694
766
|
marginBottom: 1,
|
|
695
|
-
children: /* @__PURE__ */
|
|
767
|
+
children: /* @__PURE__ */ jsxDEV10(Text8, {
|
|
696
768
|
children: output
|
|
697
769
|
}, undefined, false, undefined, this)
|
|
698
770
|
}, undefined, false, undefined, this),
|
|
699
|
-
/* @__PURE__ */
|
|
771
|
+
/* @__PURE__ */ jsxDEV10(Text8, {
|
|
700
772
|
color: success ? colors.success : colors.error,
|
|
701
773
|
children: success ? "Done" : "Failed"
|
|
702
774
|
}, undefined, false, undefined, this),
|
|
703
|
-
/* @__PURE__ */
|
|
775
|
+
/* @__PURE__ */ jsxDEV10(Text8, {
|
|
704
776
|
dimColor: true,
|
|
705
777
|
children: "Press any key to continue..."
|
|
706
778
|
}, undefined, false, undefined, this)
|
|
@@ -708,246 +780,61 @@ function CommandOutput({
|
|
|
708
780
|
}, undefined, true, undefined, this);
|
|
709
781
|
}
|
|
710
782
|
|
|
711
|
-
// src/components/
|
|
712
|
-
import {
|
|
713
|
-
import { jsxDEV as
|
|
714
|
-
function
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
if (theme.isLightMode)
|
|
721
|
-
indicators.push("light");
|
|
722
|
-
const indicatorText = indicators.length > 0 ? ` [${indicators.join(" ")}]` : "";
|
|
723
|
-
return /* @__PURE__ */ jsxDEV9(Box9, {
|
|
724
|
-
flexDirection: "column",
|
|
725
|
-
width,
|
|
726
|
-
borderStyle: borderStyles.panel,
|
|
727
|
-
borderColor,
|
|
728
|
-
paddingX: 1,
|
|
729
|
-
children: /* @__PURE__ */ jsxDEV9(Box9, {
|
|
730
|
-
children: [
|
|
731
|
-
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
732
|
-
color: isSelected ? colors.accent : colors.primaryDim,
|
|
733
|
-
children: isSelected ? "● " : " "
|
|
734
|
-
}, undefined, false, undefined, this),
|
|
735
|
-
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
736
|
-
color: nameColor,
|
|
737
|
-
bold: true,
|
|
738
|
-
wrap: "truncate",
|
|
739
|
-
children: theme.name
|
|
740
|
-
}, undefined, false, undefined, this),
|
|
741
|
-
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
742
|
-
color: colors.primaryDim,
|
|
743
|
-
children: indicatorText
|
|
744
|
-
}, undefined, false, undefined, this)
|
|
745
|
-
]
|
|
746
|
-
}, undefined, true, undefined, this)
|
|
783
|
+
// src/components/LoadingPanel.tsx
|
|
784
|
+
import { Spinner } from "@inkjs/ui";
|
|
785
|
+
import { jsxDEV as jsxDEV11 } from "react/jsx-dev-runtime";
|
|
786
|
+
function LoadingPanel({ title, label = "Processing..." }) {
|
|
787
|
+
return /* @__PURE__ */ jsxDEV11(Panel, {
|
|
788
|
+
title,
|
|
789
|
+
children: /* @__PURE__ */ jsxDEV11(Spinner, {
|
|
790
|
+
label
|
|
791
|
+
}, undefined, false, undefined, this)
|
|
747
792
|
}, undefined, false, undefined, this);
|
|
748
793
|
}
|
|
749
794
|
|
|
750
|
-
// src/
|
|
751
|
-
import { useState as useState4,
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
795
|
+
// src/hooks/useMenuAction.ts
|
|
796
|
+
import { useState as useState4, useCallback } from "react";
|
|
797
|
+
function useMenuAction() {
|
|
798
|
+
const [state, setState] = useState4("menu");
|
|
799
|
+
const [output, setOutput] = useState4("");
|
|
800
|
+
const [success, setSuccess] = useState4(true);
|
|
801
|
+
const execute = useCallback(async (action) => {
|
|
802
|
+
setState("running");
|
|
803
|
+
const result = await action();
|
|
804
|
+
setOutput(result.output);
|
|
805
|
+
setSuccess(result.success);
|
|
806
|
+
setState("result");
|
|
807
|
+
}, []);
|
|
808
|
+
const reset = useCallback(() => {
|
|
809
|
+
setState("menu");
|
|
810
|
+
}, []);
|
|
811
|
+
return {
|
|
812
|
+
state,
|
|
813
|
+
output,
|
|
814
|
+
success,
|
|
815
|
+
isRunning: state === "running",
|
|
816
|
+
isResult: state === "result",
|
|
817
|
+
execute,
|
|
818
|
+
reset
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// src/hooks/useBackNavigation.ts
|
|
823
|
+
import { useInput as useInput4 } from "ink";
|
|
824
|
+
function useBackNavigation({
|
|
825
|
+
enabled = true,
|
|
826
|
+
onBack
|
|
759
827
|
}) {
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
const [isAutoScrolling, setIsAutoScrolling] = useState4(autoScroll);
|
|
764
|
-
const totalLines = lines.length;
|
|
765
|
-
const maxOffset = Math.max(0, totalLines - visibleLines);
|
|
766
|
-
useEffect3(() => {
|
|
767
|
-
if (isAutoScrolling) {
|
|
768
|
-
setScrollOffset(maxOffset);
|
|
769
|
-
}
|
|
770
|
-
}, [totalLines, maxOffset, isAutoScrolling]);
|
|
771
|
-
useInput3((input, key) => {
|
|
772
|
-
if (key.downArrow || input === "j") {
|
|
773
|
-
setIsAutoScrolling(false);
|
|
774
|
-
setScrollOffset((prev) => Math.min(prev + 1, maxOffset));
|
|
775
|
-
}
|
|
776
|
-
if (key.upArrow || input === "k") {
|
|
777
|
-
setIsAutoScrolling(false);
|
|
778
|
-
setScrollOffset((prev) => Math.max(prev - 1, 0));
|
|
779
|
-
}
|
|
780
|
-
if (input === "G") {
|
|
781
|
-
setIsAutoScrolling(true);
|
|
782
|
-
setScrollOffset(maxOffset);
|
|
783
|
-
}
|
|
784
|
-
if (input === "g") {
|
|
785
|
-
setIsAutoScrolling(false);
|
|
786
|
-
setScrollOffset(0);
|
|
787
|
-
}
|
|
788
|
-
});
|
|
789
|
-
const visibleContent = useMemo(() => {
|
|
790
|
-
return lines.slice(scrollOffset, scrollOffset + visibleLines);
|
|
791
|
-
}, [lines, scrollOffset, visibleLines]);
|
|
792
|
-
const showScrollUp = scrollOffset > 0;
|
|
793
|
-
const showScrollDown = scrollOffset < maxOffset;
|
|
794
|
-
return /* @__PURE__ */ jsxDEV10(Box10, {
|
|
795
|
-
flexDirection: "column",
|
|
796
|
-
children: [
|
|
797
|
-
showScrollHint && showScrollUp && /* @__PURE__ */ jsxDEV10(Text9, {
|
|
798
|
-
dimColor: true,
|
|
799
|
-
children: [
|
|
800
|
-
" ↑ ",
|
|
801
|
-
scrollOffset,
|
|
802
|
-
" more line",
|
|
803
|
-
scrollOffset !== 1 ? "s" : ""
|
|
804
|
-
]
|
|
805
|
-
}, undefined, true, undefined, this),
|
|
806
|
-
/* @__PURE__ */ jsxDEV10(Box10, {
|
|
807
|
-
flexDirection: "column",
|
|
808
|
-
height: visibleLines,
|
|
809
|
-
overflow: "hidden",
|
|
810
|
-
children: visibleContent.map((line, i) => /* @__PURE__ */ jsxDEV10(Text9, {
|
|
811
|
-
children: line
|
|
812
|
-
}, scrollOffset + i, false, undefined, this))
|
|
813
|
-
}, undefined, false, undefined, this),
|
|
814
|
-
showScrollHint && showScrollDown && /* @__PURE__ */ jsxDEV10(Text9, {
|
|
815
|
-
dimColor: true,
|
|
816
|
-
children: [
|
|
817
|
-
" ↓ ",
|
|
818
|
-
maxOffset - scrollOffset,
|
|
819
|
-
" more line",
|
|
820
|
-
maxOffset - scrollOffset !== 1 ? "s" : ""
|
|
821
|
-
]
|
|
822
|
-
}, undefined, true, undefined, this),
|
|
823
|
-
showScrollHint && totalLines > visibleLines && /* @__PURE__ */ jsxDEV10(Text9, {
|
|
824
|
-
dimColor: true,
|
|
825
|
-
children: [
|
|
826
|
-
"j/k scroll • g top • G bottom ",
|
|
827
|
-
isAutoScrolling ? "(auto-scroll)" : ""
|
|
828
|
-
]
|
|
829
|
-
}, undefined, true, undefined, this)
|
|
830
|
-
]
|
|
831
|
-
}, undefined, true, undefined, this);
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
// src/components/PromptInput.tsx
|
|
835
|
-
import { Box as Box11, Text as Text10, useInput as useInput4 } from "ink";
|
|
836
|
-
import { jsxDEV as jsxDEV11 } from "react/jsx-dev-runtime";
|
|
837
|
-
function PromptInput({
|
|
838
|
-
question,
|
|
839
|
-
options = ["y", "n"],
|
|
840
|
-
onAnswer
|
|
841
|
-
}) {
|
|
842
|
-
useInput4((input) => {
|
|
843
|
-
const lower = input.toLowerCase();
|
|
844
|
-
if (options.includes(lower)) {
|
|
845
|
-
onAnswer(lower);
|
|
828
|
+
useInput4((input, key) => {
|
|
829
|
+
if (enabled && (key.escape || key.leftArrow || input === "h")) {
|
|
830
|
+
onBack();
|
|
846
831
|
}
|
|
847
832
|
});
|
|
848
|
-
return /* @__PURE__ */ jsxDEV11(Box11, {
|
|
849
|
-
marginTop: 1,
|
|
850
|
-
borderStyle: "single",
|
|
851
|
-
borderColor: colors.accent,
|
|
852
|
-
paddingX: 1,
|
|
853
|
-
children: /* @__PURE__ */ jsxDEV11(Text10, {
|
|
854
|
-
children: [
|
|
855
|
-
question,
|
|
856
|
-
" ",
|
|
857
|
-
/* @__PURE__ */ jsxDEV11(Text10, {
|
|
858
|
-
color: colors.accent,
|
|
859
|
-
children: [
|
|
860
|
-
"[",
|
|
861
|
-
options.join("/"),
|
|
862
|
-
"]"
|
|
863
|
-
]
|
|
864
|
-
}, undefined, true, undefined, this),
|
|
865
|
-
/* @__PURE__ */ jsxDEV11(Text10, {
|
|
866
|
-
dimColor: true,
|
|
867
|
-
children: ": "
|
|
868
|
-
}, undefined, false, undefined, this)
|
|
869
|
-
]
|
|
870
|
-
}, undefined, true, undefined, this)
|
|
871
|
-
}, undefined, false, undefined, this);
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
// src/lib/theme-parser.ts
|
|
875
|
-
import { existsSync as existsSync2, readdirSync as readdirSync2 } from "fs";
|
|
876
|
-
import { join as join3 } from "path";
|
|
877
|
-
function parseYaml(content) {
|
|
878
|
-
const result = {};
|
|
879
|
-
const lines = content.split(`
|
|
880
|
-
`);
|
|
881
|
-
let currentSection = null;
|
|
882
|
-
let currentKey = "";
|
|
883
|
-
for (const line of lines) {
|
|
884
|
-
const trimmed = line.trim();
|
|
885
|
-
if (!trimmed || trimmed.startsWith("#"))
|
|
886
|
-
continue;
|
|
887
|
-
const indentLevel = line.search(/\S/);
|
|
888
|
-
const match = trimmed.match(/^([\w-]+):\s*(.*)$/);
|
|
889
|
-
if (match) {
|
|
890
|
-
const [, key, value] = match;
|
|
891
|
-
if (indentLevel === 0) {
|
|
892
|
-
if (value) {
|
|
893
|
-
result[key] = value.replace(/^["']|["']$/g, "");
|
|
894
|
-
} else {
|
|
895
|
-
currentKey = key;
|
|
896
|
-
currentSection = {};
|
|
897
|
-
result[key] = currentSection;
|
|
898
|
-
}
|
|
899
|
-
} else if (currentSection) {
|
|
900
|
-
currentSection[key] = value.replace(/^["']|["']$/g, "");
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
return result;
|
|
905
|
-
}
|
|
906
|
-
async function parseThemeMetadata(themePath) {
|
|
907
|
-
const yamlPath = join3(themePath, "theme.yaml");
|
|
908
|
-
if (!existsSync2(yamlPath)) {
|
|
909
|
-
return;
|
|
910
|
-
}
|
|
911
|
-
try {
|
|
912
|
-
const content = await readText(yamlPath);
|
|
913
|
-
const parsed = parseYaml(content);
|
|
914
|
-
return {
|
|
915
|
-
name: parsed.name || "",
|
|
916
|
-
author: parsed.author,
|
|
917
|
-
description: parsed.description,
|
|
918
|
-
version: parsed.version,
|
|
919
|
-
source: parsed.source,
|
|
920
|
-
colors: parsed.colors
|
|
921
|
-
};
|
|
922
|
-
} catch {
|
|
923
|
-
return;
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
function parseThemeFiles(themePath) {
|
|
927
|
-
const entries = readdirSync2(themePath, { withFileTypes: true });
|
|
928
|
-
return entries.filter((e) => e.isFile() && !e.name.startsWith(".") && e.name !== "theme.yaml" && e.name !== "light.mode").map((e) => ({
|
|
929
|
-
name: e.name,
|
|
930
|
-
path: join3(themePath, e.name),
|
|
931
|
-
application: e.name.replace(/\.(conf|theme|lua|toml|css|json|ini)$/, "")
|
|
932
|
-
}));
|
|
933
|
-
}
|
|
934
|
-
async function parseTheme(themePath, themeName) {
|
|
935
|
-
const files = parseThemeFiles(themePath);
|
|
936
|
-
const metadata = await parseThemeMetadata(themePath);
|
|
937
|
-
return {
|
|
938
|
-
name: metadata?.name || themeName,
|
|
939
|
-
path: themePath,
|
|
940
|
-
files,
|
|
941
|
-
metadata,
|
|
942
|
-
hasBackgrounds: existsSync2(join3(themePath, "backgrounds")),
|
|
943
|
-
hasPreview: existsSync2(join3(themePath, "preview.png")),
|
|
944
|
-
isLightMode: existsSync2(join3(themePath, "light.mode"))
|
|
945
|
-
};
|
|
946
833
|
}
|
|
947
834
|
|
|
948
835
|
// src/cli/config-manager.ts
|
|
949
836
|
import { parseArgs } from "util";
|
|
950
|
-
import { readdirSync as
|
|
837
|
+
import { readdirSync as readdirSync2, existsSync as existsSync2, lstatSync as lstatSync2, readlinkSync as readlinkSync2 } from "fs";
|
|
951
838
|
var colors2 = {
|
|
952
839
|
red: "\x1B[0;31m",
|
|
953
840
|
green: "\x1B[0;32m",
|
|
@@ -963,7 +850,7 @@ async function checkStow() {
|
|
|
963
850
|
}
|
|
964
851
|
}
|
|
965
852
|
function listPackages() {
|
|
966
|
-
const entries =
|
|
853
|
+
const entries = readdirSync2(CONFIGS_DIR, { withFileTypes: true });
|
|
967
854
|
return entries.filter((e) => e.isDirectory()).map((e) => ({
|
|
968
855
|
name: e.name,
|
|
969
856
|
path: `${CONFIGS_DIR}/${e.name}`,
|
|
@@ -972,12 +859,12 @@ function listPackages() {
|
|
|
972
859
|
}
|
|
973
860
|
function checkPackageStowed(packageName) {
|
|
974
861
|
const packageDir = `${CONFIGS_DIR}/${packageName}`;
|
|
975
|
-
if (!
|
|
862
|
+
if (!existsSync2(packageDir))
|
|
976
863
|
return false;
|
|
977
|
-
const entries =
|
|
864
|
+
const entries = readdirSync2(packageDir, { withFileTypes: true });
|
|
978
865
|
for (const entry of entries) {
|
|
979
866
|
const targetPath = `${HOME_DIR}/${entry.name}`;
|
|
980
|
-
if (!
|
|
867
|
+
if (!existsSync2(targetPath))
|
|
981
868
|
return false;
|
|
982
869
|
try {
|
|
983
870
|
const stat = lstatSync2(targetPath);
|
|
@@ -1242,73 +1129,241 @@ if (isMainModule) {
|
|
|
1242
1129
|
main().catch(console.error);
|
|
1243
1130
|
}
|
|
1244
1131
|
|
|
1245
|
-
// src/
|
|
1246
|
-
import {
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
};
|
|
1261
|
-
async function loadPkgConfig(path) {
|
|
1262
|
-
await ensureConfigDir();
|
|
1263
|
-
const configPath = path || PKG_CONFIG_PATH;
|
|
1264
|
-
if (!existsSync4(configPath)) {
|
|
1265
|
-
await savePkgConfig(DEFAULT_CONFIG, configPath);
|
|
1266
|
-
return DEFAULT_CONFIG;
|
|
1132
|
+
// src/components/menus/ConfigMenu.tsx
|
|
1133
|
+
import { jsxDEV as jsxDEV12 } from "react/jsx-dev-runtime";
|
|
1134
|
+
function ConfigMenu({ onBack }) {
|
|
1135
|
+
const { state, output, success, isRunning, isResult, execute, reset } = useMenuAction();
|
|
1136
|
+
useBackNavigation({ enabled: state === "menu", onBack });
|
|
1137
|
+
const handleAction = async (action) => {
|
|
1138
|
+
if (action === "back") {
|
|
1139
|
+
onBack();
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
await execute(() => runConfigManager([action]));
|
|
1143
|
+
};
|
|
1144
|
+
if (isRunning) {
|
|
1145
|
+
return /* @__PURE__ */ jsxDEV12(LoadingPanel, {
|
|
1146
|
+
title: "Config Manager"
|
|
1147
|
+
}, undefined, false, undefined, this);
|
|
1267
1148
|
}
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
}
|
|
1275
|
-
async function loadPkgLock() {
|
|
1276
|
-
if (!existsSync4(PKG_LOCK_PATH)) {
|
|
1277
|
-
return null;
|
|
1149
|
+
if (isResult) {
|
|
1150
|
+
return /* @__PURE__ */ jsxDEV12(CommandOutput, {
|
|
1151
|
+
title: "Config Manager",
|
|
1152
|
+
output,
|
|
1153
|
+
success,
|
|
1154
|
+
onDismiss: reset
|
|
1155
|
+
}, undefined, false, undefined, this);
|
|
1278
1156
|
}
|
|
1279
|
-
return
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1157
|
+
return /* @__PURE__ */ jsxDEV12(Panel, {
|
|
1158
|
+
title: "Config Manager",
|
|
1159
|
+
children: /* @__PURE__ */ jsxDEV12(VimSelect, {
|
|
1160
|
+
options: [
|
|
1161
|
+
{ label: "Stow all packages", value: "stow-all" },
|
|
1162
|
+
{ label: "Unstow all packages", value: "unstow-all" },
|
|
1163
|
+
{ label: "Check status", value: "status" },
|
|
1164
|
+
{ label: "List packages", value: "list" },
|
|
1165
|
+
{ label: "Back", value: "back" }
|
|
1166
|
+
],
|
|
1167
|
+
onChange: handleAction
|
|
1168
|
+
}, undefined, false, undefined, this)
|
|
1169
|
+
}, undefined, false, undefined, this);
|
|
1284
1170
|
}
|
|
1285
1171
|
|
|
1286
|
-
// src/
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
}
|
|
1172
|
+
// src/components/menus/PackageMenu.tsx
|
|
1173
|
+
import { useState as useState6, useCallback as useCallback2, useMemo as useMemo2, useRef } from "react";
|
|
1174
|
+
import { Box as Box12, Text as Text11, useInput as useInput7 } from "ink";
|
|
1175
|
+
|
|
1176
|
+
// src/components/ScrollableLog.tsx
|
|
1177
|
+
import { useState as useState5, useEffect as useEffect3, useMemo } from "react";
|
|
1178
|
+
import { Box as Box10, Text as Text9, useInput as useInput5 } from "ink";
|
|
1179
|
+
import { jsxDEV as jsxDEV13 } from "react/jsx-dev-runtime";
|
|
1180
|
+
function ScrollableLog({
|
|
1181
|
+
lines,
|
|
1182
|
+
maxHeight,
|
|
1183
|
+
autoScroll = true,
|
|
1184
|
+
showScrollHint = true
|
|
1185
|
+
}) {
|
|
1186
|
+
const { rows } = useTerminalSize();
|
|
1187
|
+
const visibleLines = maxHeight || Math.max(5, rows - 12);
|
|
1188
|
+
const [scrollOffset, setScrollOffset] = useState5(0);
|
|
1189
|
+
const [isAutoScrolling, setIsAutoScrolling] = useState5(autoScroll);
|
|
1190
|
+
const totalLines = lines.length;
|
|
1191
|
+
const maxOffset = Math.max(0, totalLines - visibleLines);
|
|
1192
|
+
useEffect3(() => {
|
|
1193
|
+
if (isAutoScrolling) {
|
|
1194
|
+
setScrollOffset(maxOffset);
|
|
1310
1195
|
}
|
|
1311
|
-
}
|
|
1196
|
+
}, [totalLines, maxOffset, isAutoScrolling]);
|
|
1197
|
+
useInput5((input, key) => {
|
|
1198
|
+
if (key.downArrow || input === "j") {
|
|
1199
|
+
setIsAutoScrolling(false);
|
|
1200
|
+
setScrollOffset((prev) => Math.min(prev + 1, maxOffset));
|
|
1201
|
+
}
|
|
1202
|
+
if (key.upArrow || input === "k") {
|
|
1203
|
+
setIsAutoScrolling(false);
|
|
1204
|
+
setScrollOffset((prev) => Math.max(prev - 1, 0));
|
|
1205
|
+
}
|
|
1206
|
+
if (input === "G") {
|
|
1207
|
+
setIsAutoScrolling(true);
|
|
1208
|
+
setScrollOffset(maxOffset);
|
|
1209
|
+
}
|
|
1210
|
+
if (input === "g") {
|
|
1211
|
+
setIsAutoScrolling(false);
|
|
1212
|
+
setScrollOffset(0);
|
|
1213
|
+
}
|
|
1214
|
+
});
|
|
1215
|
+
const visibleContent = useMemo(() => {
|
|
1216
|
+
return lines.slice(scrollOffset, scrollOffset + visibleLines);
|
|
1217
|
+
}, [lines, scrollOffset, visibleLines]);
|
|
1218
|
+
const showScrollUp = scrollOffset > 0;
|
|
1219
|
+
const showScrollDown = scrollOffset < maxOffset;
|
|
1220
|
+
return /* @__PURE__ */ jsxDEV13(Box10, {
|
|
1221
|
+
flexDirection: "column",
|
|
1222
|
+
children: [
|
|
1223
|
+
showScrollHint && showScrollUp && /* @__PURE__ */ jsxDEV13(Text9, {
|
|
1224
|
+
dimColor: true,
|
|
1225
|
+
children: [
|
|
1226
|
+
" ↑ ",
|
|
1227
|
+
scrollOffset,
|
|
1228
|
+
" more line",
|
|
1229
|
+
scrollOffset !== 1 ? "s" : ""
|
|
1230
|
+
]
|
|
1231
|
+
}, undefined, true, undefined, this),
|
|
1232
|
+
/* @__PURE__ */ jsxDEV13(Box10, {
|
|
1233
|
+
flexDirection: "column",
|
|
1234
|
+
height: visibleLines,
|
|
1235
|
+
overflow: "hidden",
|
|
1236
|
+
children: visibleContent.map((line, i) => /* @__PURE__ */ jsxDEV13(Text9, {
|
|
1237
|
+
children: line
|
|
1238
|
+
}, scrollOffset + i, false, undefined, this))
|
|
1239
|
+
}, undefined, false, undefined, this),
|
|
1240
|
+
showScrollHint && showScrollDown && /* @__PURE__ */ jsxDEV13(Text9, {
|
|
1241
|
+
dimColor: true,
|
|
1242
|
+
children: [
|
|
1243
|
+
" ↓ ",
|
|
1244
|
+
maxOffset - scrollOffset,
|
|
1245
|
+
" more line",
|
|
1246
|
+
maxOffset - scrollOffset !== 1 ? "s" : ""
|
|
1247
|
+
]
|
|
1248
|
+
}, undefined, true, undefined, this),
|
|
1249
|
+
showScrollHint && totalLines > visibleLines && /* @__PURE__ */ jsxDEV13(Text9, {
|
|
1250
|
+
dimColor: true,
|
|
1251
|
+
children: [
|
|
1252
|
+
"j/k scroll • g top • G bottom ",
|
|
1253
|
+
isAutoScrolling ? "(auto-scroll)" : ""
|
|
1254
|
+
]
|
|
1255
|
+
}, undefined, true, undefined, this)
|
|
1256
|
+
]
|
|
1257
|
+
}, undefined, true, undefined, this);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
// src/components/PromptInput.tsx
|
|
1261
|
+
import { Box as Box11, Text as Text10, useInput as useInput6 } from "ink";
|
|
1262
|
+
import { jsxDEV as jsxDEV14 } from "react/jsx-dev-runtime";
|
|
1263
|
+
function PromptInput({
|
|
1264
|
+
question,
|
|
1265
|
+
options = ["y", "n"],
|
|
1266
|
+
onAnswer
|
|
1267
|
+
}) {
|
|
1268
|
+
useInput6((input) => {
|
|
1269
|
+
const lower = input.toLowerCase();
|
|
1270
|
+
if (options.includes(lower)) {
|
|
1271
|
+
onAnswer(lower);
|
|
1272
|
+
}
|
|
1273
|
+
});
|
|
1274
|
+
return /* @__PURE__ */ jsxDEV14(Box11, {
|
|
1275
|
+
marginTop: 1,
|
|
1276
|
+
borderStyle: "single",
|
|
1277
|
+
borderColor: colors.accent,
|
|
1278
|
+
paddingX: 1,
|
|
1279
|
+
children: /* @__PURE__ */ jsxDEV14(Text10, {
|
|
1280
|
+
children: [
|
|
1281
|
+
question,
|
|
1282
|
+
" ",
|
|
1283
|
+
/* @__PURE__ */ jsxDEV14(Text10, {
|
|
1284
|
+
color: colors.accent,
|
|
1285
|
+
children: [
|
|
1286
|
+
"[",
|
|
1287
|
+
options.join("/"),
|
|
1288
|
+
"]"
|
|
1289
|
+
]
|
|
1290
|
+
}, undefined, true, undefined, this),
|
|
1291
|
+
/* @__PURE__ */ jsxDEV14(Text10, {
|
|
1292
|
+
dimColor: true,
|
|
1293
|
+
children: ": "
|
|
1294
|
+
}, undefined, false, undefined, this)
|
|
1295
|
+
]
|
|
1296
|
+
}, undefined, true, undefined, this)
|
|
1297
|
+
}, undefined, false, undefined, this);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// src/cli/pkg-sync.ts
|
|
1301
|
+
import { parseArgs as parseArgs2 } from "util";
|
|
1302
|
+
|
|
1303
|
+
// src/lib/config.ts
|
|
1304
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1305
|
+
var DEFAULT_CONFIG = {
|
|
1306
|
+
config: {
|
|
1307
|
+
purge: false,
|
|
1308
|
+
purgeInteractive: true,
|
|
1309
|
+
autoUpdate: true
|
|
1310
|
+
},
|
|
1311
|
+
taps: [],
|
|
1312
|
+
packages: [],
|
|
1313
|
+
casks: [],
|
|
1314
|
+
mas: {}
|
|
1315
|
+
};
|
|
1316
|
+
async function loadPkgConfig(path) {
|
|
1317
|
+
await ensureConfigDir();
|
|
1318
|
+
const configPath = path || PKG_CONFIG_PATH;
|
|
1319
|
+
if (!existsSync3(configPath)) {
|
|
1320
|
+
await savePkgConfig(DEFAULT_CONFIG, configPath);
|
|
1321
|
+
return DEFAULT_CONFIG;
|
|
1322
|
+
}
|
|
1323
|
+
return readJson(configPath);
|
|
1324
|
+
}
|
|
1325
|
+
async function savePkgConfig(config, path) {
|
|
1326
|
+
await ensureConfigDir();
|
|
1327
|
+
const configPath = path || PKG_CONFIG_PATH;
|
|
1328
|
+
await writeFile(configPath, JSON.stringify(config, null, 2));
|
|
1329
|
+
}
|
|
1330
|
+
async function loadPkgLock() {
|
|
1331
|
+
if (!existsSync3(PKG_LOCK_PATH)) {
|
|
1332
|
+
return null;
|
|
1333
|
+
}
|
|
1334
|
+
return readJson(PKG_LOCK_PATH);
|
|
1335
|
+
}
|
|
1336
|
+
async function savePkgLock(lock) {
|
|
1337
|
+
await ensureConfigDir();
|
|
1338
|
+
await writeFile(PKG_LOCK_PATH, JSON.stringify(lock, null, 2));
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
// src/lib/lockfile.ts
|
|
1342
|
+
async function fetchInstalledVersions() {
|
|
1343
|
+
const config = await loadPkgConfig();
|
|
1344
|
+
const now = new Date().toISOString();
|
|
1345
|
+
const formulas = {};
|
|
1346
|
+
const casks = {};
|
|
1347
|
+
if (config.packages.length > 0) {
|
|
1348
|
+
const result = await exec([
|
|
1349
|
+
"brew",
|
|
1350
|
+
"info",
|
|
1351
|
+
"--json=v2",
|
|
1352
|
+
...config.packages
|
|
1353
|
+
]);
|
|
1354
|
+
if (result.success && result.stdout) {
|
|
1355
|
+
const info = JSON.parse(result.stdout);
|
|
1356
|
+
for (const formula of info.formulae) {
|
|
1357
|
+
if (formula.installed.length > 0) {
|
|
1358
|
+
formulas[formula.name] = {
|
|
1359
|
+
version: formula.installed[0].version,
|
|
1360
|
+
tap: formula.tap,
|
|
1361
|
+
installedAt: now
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1312
1367
|
if (config.casks.length > 0) {
|
|
1313
1368
|
const result = await exec([
|
|
1314
1369
|
"brew",
|
|
@@ -2054,277 +2109,36 @@ if (isMainModule3) {
|
|
|
2054
2109
|
main3().catch(console.error);
|
|
2055
2110
|
}
|
|
2056
2111
|
|
|
2057
|
-
// src/
|
|
2058
|
-
import {
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
async function listThemes() {
|
|
2071
|
-
await ensureConfigDir();
|
|
2072
|
-
if (!existsSync5(THEMES_DIR)) {
|
|
2073
|
-
return [];
|
|
2074
|
-
}
|
|
2075
|
-
const entries = readdirSync4(THEMES_DIR, { withFileTypes: true });
|
|
2076
|
-
const themes = [];
|
|
2077
|
-
for (const entry of entries) {
|
|
2078
|
-
if (entry.isDirectory()) {
|
|
2079
|
-
const themePath = join4(THEMES_DIR, entry.name);
|
|
2080
|
-
const theme = await parseTheme(themePath, entry.name);
|
|
2081
|
-
themes.push(theme);
|
|
2112
|
+
// src/components/menus/PackageMenu.tsx
|
|
2113
|
+
import { jsxDEV as jsxDEV15 } from "react/jsx-dev-runtime";
|
|
2114
|
+
function PackageMenu({ onBack }) {
|
|
2115
|
+
const [state, setState] = useState6("menu");
|
|
2116
|
+
const [lines, setLines] = useState6([]);
|
|
2117
|
+
const [output, setOutput] = useState6("");
|
|
2118
|
+
const [isStreamingOp, setIsStreamingOp] = useState6(true);
|
|
2119
|
+
const [pendingPrompt, setPendingPrompt] = useState6(null);
|
|
2120
|
+
const [success, setSuccess] = useState6(true);
|
|
2121
|
+
const isRunningRef = useRef(false);
|
|
2122
|
+
useInput7((input, key) => {
|
|
2123
|
+
if (state === "menu" && (key.escape || key.leftArrow || input === "h")) {
|
|
2124
|
+
onBack();
|
|
2082
2125
|
}
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
function clearDirectory(dir) {
|
|
2087
|
-
if (existsSync5(dir)) {
|
|
2088
|
-
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
2089
|
-
for (const entry of entries) {
|
|
2090
|
-
const fullPath = join4(dir, entry.name);
|
|
2091
|
-
if (entry.isSymbolicLink() || entry.isFile()) {
|
|
2092
|
-
unlinkSync(fullPath);
|
|
2093
|
-
} else if (entry.isDirectory()) {
|
|
2094
|
-
rmSync(fullPath, { recursive: true, force: true });
|
|
2095
|
-
}
|
|
2126
|
+
if (state === "result") {
|
|
2127
|
+
setState("menu");
|
|
2128
|
+
setLines([]);
|
|
2096
2129
|
}
|
|
2097
|
-
}
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
}
|
|
2105
|
-
|
|
2106
|
-
const themeDir = join4(THEMES_DIR, themeName);
|
|
2107
|
-
if (!existsSync5(themeDir)) {
|
|
2108
|
-
return { output: `Theme '${themeName}' not found`, success: false };
|
|
2109
|
-
}
|
|
2110
|
-
await ensureConfigDir();
|
|
2111
|
-
await ensureDir2(THEME_TARGET_DIR);
|
|
2112
|
-
const theme = await parseTheme(themeDir, themeName);
|
|
2113
|
-
clearDirectory(THEME_TARGET_DIR);
|
|
2114
|
-
if (existsSync5(BACKGROUNDS_TARGET_DIR)) {
|
|
2115
|
-
rmSync(BACKGROUNDS_TARGET_DIR, { recursive: true, force: true });
|
|
2116
|
-
}
|
|
2117
|
-
const entries = readdirSync4(themeDir, { withFileTypes: true });
|
|
2118
|
-
for (const entry of entries) {
|
|
2119
|
-
const source = join4(themeDir, entry.name);
|
|
2120
|
-
if (entry.isFile() && entry.name !== "theme.yaml" && entry.name !== "light.mode") {
|
|
2121
|
-
const target = join4(THEME_TARGET_DIR, entry.name);
|
|
2122
|
-
createSymlink(source, target);
|
|
2123
|
-
}
|
|
2124
|
-
}
|
|
2125
|
-
if (theme.hasBackgrounds) {
|
|
2126
|
-
const backgroundsSource = join4(themeDir, "backgrounds");
|
|
2127
|
-
createSymlink(backgroundsSource, BACKGROUNDS_TARGET_DIR);
|
|
2128
|
-
}
|
|
2129
|
-
let output = `Theme '${theme.name}' applied successfully`;
|
|
2130
|
-
if (theme.metadata?.author) {
|
|
2131
|
-
output += `
|
|
2132
|
-
Author: ${theme.metadata.author}`;
|
|
2133
|
-
}
|
|
2134
|
-
if (theme.hasBackgrounds) {
|
|
2135
|
-
output += `
|
|
2136
|
-
Wallpapers available at: ~/.config/formalconf/current/backgrounds/`;
|
|
2137
|
-
}
|
|
2138
|
-
if (theme.isLightMode) {
|
|
2139
|
-
output += `
|
|
2140
|
-
Note: This is a light mode theme`;
|
|
2141
|
-
}
|
|
2142
|
-
return { output, success: true };
|
|
2143
|
-
}
|
|
2144
|
-
async function showThemeInfo(themeName) {
|
|
2145
|
-
const themeDir = join4(THEMES_DIR, themeName);
|
|
2146
|
-
if (!existsSync5(themeDir)) {
|
|
2147
|
-
console.error(`${colors5.red}Error: Theme '${themeName}' not found${colors5.reset}`);
|
|
2148
|
-
process.exit(1);
|
|
2149
|
-
}
|
|
2150
|
-
const theme = await parseTheme(themeDir, themeName);
|
|
2151
|
-
console.log(`
|
|
2152
|
-
${colors5.cyan}Theme: ${theme.name}${colors5.reset}`);
|
|
2153
|
-
if (theme.metadata) {
|
|
2154
|
-
if (theme.metadata.author)
|
|
2155
|
-
console.log(`Author: ${theme.metadata.author}`);
|
|
2156
|
-
if (theme.metadata.description)
|
|
2157
|
-
console.log(`Description: ${theme.metadata.description}`);
|
|
2158
|
-
if (theme.metadata.version)
|
|
2159
|
-
console.log(`Version: ${theme.metadata.version}`);
|
|
2160
|
-
if (theme.metadata.source)
|
|
2161
|
-
console.log(`Source: ${theme.metadata.source}`);
|
|
2162
|
-
}
|
|
2163
|
-
console.log(`
|
|
2164
|
-
Files (${theme.files.length}):`);
|
|
2165
|
-
for (const file of theme.files) {
|
|
2166
|
-
console.log(` ${colors5.blue}•${colors5.reset} ${file.name}`);
|
|
2167
|
-
}
|
|
2168
|
-
if (theme.hasBackgrounds) {
|
|
2169
|
-
console.log(`
|
|
2170
|
-
${colors5.green}Has wallpapers${colors5.reset}`);
|
|
2171
|
-
}
|
|
2172
|
-
if (theme.hasPreview) {
|
|
2173
|
-
console.log(`${colors5.green}Has preview image${colors5.reset}`);
|
|
2174
|
-
}
|
|
2175
|
-
if (theme.isLightMode) {
|
|
2176
|
-
console.log(`${colors5.yellow}Light mode theme${colors5.reset}`);
|
|
2177
|
-
}
|
|
2178
|
-
}
|
|
2179
|
-
async function runSetTheme(themeName) {
|
|
2180
|
-
return applyTheme(themeName);
|
|
2181
|
-
}
|
|
2182
|
-
async function main4() {
|
|
2183
|
-
const { positionals, values } = parseArgs4({
|
|
2184
|
-
args: process.argv.slice(2),
|
|
2185
|
-
options: {
|
|
2186
|
-
info: { type: "boolean", short: "i" }
|
|
2187
|
-
},
|
|
2188
|
-
allowPositionals: true
|
|
2189
|
-
});
|
|
2190
|
-
const [themeName] = positionals;
|
|
2191
|
-
if (!themeName) {
|
|
2192
|
-
const themes = await listThemes();
|
|
2193
|
-
if (themes.length === 0) {
|
|
2194
|
-
console.log(`${colors5.yellow}No themes available.${colors5.reset}`);
|
|
2195
|
-
console.log(`This system is compatible with omarchy themes.`);
|
|
2196
|
-
console.log(`
|
|
2197
|
-
Add themes to: ${colors5.cyan}~/.config/formalconf/themes/${colors5.reset}`);
|
|
2198
|
-
process.exit(0);
|
|
2199
|
-
}
|
|
2200
|
-
console.log(`${colors5.cyan}Usage: formalconf theme <theme-name>${colors5.reset}`);
|
|
2201
|
-
console.log(` formalconf theme --info <theme-name>
|
|
2202
|
-
`);
|
|
2203
|
-
console.log("Available themes:");
|
|
2204
|
-
for (const theme of themes) {
|
|
2205
|
-
const extras = [];
|
|
2206
|
-
if (theme.hasBackgrounds)
|
|
2207
|
-
extras.push("wallpapers");
|
|
2208
|
-
if (theme.isLightMode)
|
|
2209
|
-
extras.push("light");
|
|
2210
|
-
const suffix = extras.length ? ` ${colors5.dim}(${extras.join(", ")})${colors5.reset}` : "";
|
|
2211
|
-
console.log(` ${colors5.blue}•${colors5.reset} ${theme.name}${suffix}`);
|
|
2212
|
-
}
|
|
2213
|
-
process.exit(0);
|
|
2214
|
-
}
|
|
2215
|
-
if (values.info) {
|
|
2216
|
-
await showThemeInfo(themeName);
|
|
2217
|
-
} else {
|
|
2218
|
-
const result = await applyTheme(themeName);
|
|
2219
|
-
console.log(result.success ? `${colors5.green}${result.output}${colors5.reset}` : `${colors5.red}${result.output}${colors5.reset}`);
|
|
2220
|
-
}
|
|
2221
|
-
}
|
|
2222
|
-
var isMainModule4 = process.argv[1]?.includes("set-theme");
|
|
2223
|
-
if (isMainModule4) {
|
|
2224
|
-
main4().catch(console.error);
|
|
2225
|
-
}
|
|
2226
|
-
|
|
2227
|
-
// src/cli/formalconf.tsx
|
|
2228
|
-
import { jsxDEV as jsxDEV12 } from "react/jsx-dev-runtime";
|
|
2229
|
-
function MainMenu({ onSelect }) {
|
|
2230
|
-
const { exit } = useApp();
|
|
2231
|
-
return /* @__PURE__ */ jsxDEV12(Panel, {
|
|
2232
|
-
title: "Main Menu",
|
|
2233
|
-
children: /* @__PURE__ */ jsxDEV12(VimSelect, {
|
|
2234
|
-
options: [
|
|
2235
|
-
{ label: "Config Manager", value: "config" },
|
|
2236
|
-
{ label: "Package Sync", value: "packages" },
|
|
2237
|
-
{ label: "Set Theme", value: "themes" },
|
|
2238
|
-
{ label: "Exit", value: "exit" }
|
|
2239
|
-
],
|
|
2240
|
-
onChange: (value) => {
|
|
2241
|
-
if (value === "exit") {
|
|
2242
|
-
exit();
|
|
2243
|
-
return;
|
|
2244
|
-
}
|
|
2245
|
-
onSelect(value);
|
|
2246
|
-
}
|
|
2247
|
-
}, undefined, false, undefined, this)
|
|
2248
|
-
}, undefined, false, undefined, this);
|
|
2249
|
-
}
|
|
2250
|
-
function ConfigMenu({ onBack }) {
|
|
2251
|
-
const [state, setState] = useState5("menu");
|
|
2252
|
-
const [output, setOutput] = useState5("");
|
|
2253
|
-
const [success, setSuccess] = useState5(true);
|
|
2254
|
-
useInput5((input, key) => {
|
|
2255
|
-
if (state === "menu" && (key.escape || key.leftArrow || input === "h")) {
|
|
2256
|
-
onBack();
|
|
2257
|
-
}
|
|
2258
|
-
});
|
|
2259
|
-
const handleAction = async (action) => {
|
|
2260
|
-
if (action === "back") {
|
|
2261
|
-
onBack();
|
|
2262
|
-
return;
|
|
2263
|
-
}
|
|
2264
|
-
setState("running");
|
|
2265
|
-
const result = await runConfigManager([action]);
|
|
2266
|
-
setOutput(result.output);
|
|
2267
|
-
setSuccess(result.success);
|
|
2268
|
-
setState("result");
|
|
2269
|
-
};
|
|
2270
|
-
if (state === "running") {
|
|
2271
|
-
return /* @__PURE__ */ jsxDEV12(Panel, {
|
|
2272
|
-
title: "Config Manager",
|
|
2273
|
-
children: /* @__PURE__ */ jsxDEV12(Spinner, {
|
|
2274
|
-
label: "Processing..."
|
|
2275
|
-
}, undefined, false, undefined, this)
|
|
2276
|
-
}, undefined, false, undefined, this);
|
|
2277
|
-
}
|
|
2278
|
-
if (state === "result") {
|
|
2279
|
-
return /* @__PURE__ */ jsxDEV12(CommandOutput, {
|
|
2280
|
-
title: "Config Manager",
|
|
2281
|
-
output,
|
|
2282
|
-
success,
|
|
2283
|
-
onDismiss: () => setState("menu")
|
|
2284
|
-
}, undefined, false, undefined, this);
|
|
2285
|
-
}
|
|
2286
|
-
return /* @__PURE__ */ jsxDEV12(Panel, {
|
|
2287
|
-
title: "Config Manager",
|
|
2288
|
-
children: /* @__PURE__ */ jsxDEV12(VimSelect, {
|
|
2289
|
-
options: [
|
|
2290
|
-
{ label: "Stow all packages", value: "stow-all" },
|
|
2291
|
-
{ label: "Unstow all packages", value: "unstow-all" },
|
|
2292
|
-
{ label: "Check status", value: "status" },
|
|
2293
|
-
{ label: "List packages", value: "list" },
|
|
2294
|
-
{ label: "Back", value: "back" }
|
|
2295
|
-
],
|
|
2296
|
-
onChange: handleAction
|
|
2297
|
-
}, undefined, false, undefined, this)
|
|
2298
|
-
}, undefined, false, undefined, this);
|
|
2299
|
-
}
|
|
2300
|
-
function PackageMenu({ onBack }) {
|
|
2301
|
-
const [state, setState] = useState5("menu");
|
|
2302
|
-
const [lines, setLines] = useState5([]);
|
|
2303
|
-
const [output, setOutput] = useState5("");
|
|
2304
|
-
const [isStreamingOp, setIsStreamingOp] = useState5(true);
|
|
2305
|
-
const [pendingPrompt, setPendingPrompt] = useState5(null);
|
|
2306
|
-
const [success, setSuccess] = useState5(true);
|
|
2307
|
-
const isRunningRef = useRef(false);
|
|
2308
|
-
useInput5((input, key) => {
|
|
2309
|
-
if (state === "menu" && (key.escape || key.leftArrow || input === "h")) {
|
|
2310
|
-
onBack();
|
|
2311
|
-
}
|
|
2312
|
-
if (state === "result") {
|
|
2313
|
-
setState("menu");
|
|
2314
|
-
setLines([]);
|
|
2315
|
-
}
|
|
2316
|
-
});
|
|
2317
|
-
const callbacks = useMemo2(() => ({
|
|
2318
|
-
onLog: (line) => {
|
|
2319
|
-
setLines((prev) => [...prev, line]);
|
|
2320
|
-
},
|
|
2321
|
-
onPrompt: (question, options) => {
|
|
2322
|
-
return new Promise((resolve) => {
|
|
2323
|
-
setPendingPrompt({ question, options, resolve });
|
|
2324
|
-
});
|
|
2130
|
+
});
|
|
2131
|
+
const callbacks = useMemo2(() => ({
|
|
2132
|
+
onLog: (line) => {
|
|
2133
|
+
setLines((prev) => [...prev, line]);
|
|
2134
|
+
},
|
|
2135
|
+
onPrompt: (question, options) => {
|
|
2136
|
+
return new Promise((resolve) => {
|
|
2137
|
+
setPendingPrompt({ question, options, resolve });
|
|
2138
|
+
});
|
|
2325
2139
|
}
|
|
2326
2140
|
}), []);
|
|
2327
|
-
const handlePromptAnswer =
|
|
2141
|
+
const handlePromptAnswer = useCallback2((answer) => {
|
|
2328
2142
|
if (pendingPrompt) {
|
|
2329
2143
|
setLines((prev) => [...prev, `> ${answer}`]);
|
|
2330
2144
|
pendingPrompt.resolve(answer);
|
|
@@ -2382,20 +2196,17 @@ function PackageMenu({ onBack }) {
|
|
|
2382
2196
|
};
|
|
2383
2197
|
if (state === "running") {
|
|
2384
2198
|
if (!isStreamingOp) {
|
|
2385
|
-
return /* @__PURE__ */
|
|
2386
|
-
title: "Package Sync"
|
|
2387
|
-
children: /* @__PURE__ */ jsxDEV12(Spinner, {
|
|
2388
|
-
label: "Processing..."
|
|
2389
|
-
}, undefined, false, undefined, this)
|
|
2199
|
+
return /* @__PURE__ */ jsxDEV15(LoadingPanel, {
|
|
2200
|
+
title: "Package Sync"
|
|
2390
2201
|
}, undefined, false, undefined, this);
|
|
2391
2202
|
}
|
|
2392
|
-
return /* @__PURE__ */
|
|
2203
|
+
return /* @__PURE__ */ jsxDEV15(Panel, {
|
|
2393
2204
|
title: "Package Sync",
|
|
2394
2205
|
children: [
|
|
2395
|
-
/* @__PURE__ */
|
|
2206
|
+
/* @__PURE__ */ jsxDEV15(ScrollableLog, {
|
|
2396
2207
|
lines
|
|
2397
2208
|
}, undefined, false, undefined, this),
|
|
2398
|
-
pendingPrompt && /* @__PURE__ */
|
|
2209
|
+
pendingPrompt && /* @__PURE__ */ jsxDEV15(PromptInput, {
|
|
2399
2210
|
question: pendingPrompt.question,
|
|
2400
2211
|
options: pendingPrompt.options,
|
|
2401
2212
|
onAnswer: handlePromptAnswer
|
|
@@ -2405,38 +2216,38 @@ function PackageMenu({ onBack }) {
|
|
|
2405
2216
|
}
|
|
2406
2217
|
if (state === "result") {
|
|
2407
2218
|
if (!isStreamingOp) {
|
|
2408
|
-
return /* @__PURE__ */
|
|
2219
|
+
return /* @__PURE__ */ jsxDEV15(CommandOutput, {
|
|
2409
2220
|
title: "Package Sync",
|
|
2410
2221
|
output,
|
|
2411
2222
|
success,
|
|
2412
2223
|
onDismiss: () => setState("menu")
|
|
2413
2224
|
}, undefined, false, undefined, this);
|
|
2414
2225
|
}
|
|
2415
|
-
return /* @__PURE__ */
|
|
2226
|
+
return /* @__PURE__ */ jsxDEV15(Panel, {
|
|
2416
2227
|
title: "Package Sync",
|
|
2417
2228
|
borderColor: success ? colors.success : colors.error,
|
|
2418
2229
|
children: [
|
|
2419
|
-
/* @__PURE__ */
|
|
2230
|
+
/* @__PURE__ */ jsxDEV15(ScrollableLog, {
|
|
2420
2231
|
lines,
|
|
2421
2232
|
autoScroll: false
|
|
2422
2233
|
}, undefined, false, undefined, this),
|
|
2423
|
-
/* @__PURE__ */
|
|
2234
|
+
/* @__PURE__ */ jsxDEV15(Box12, {
|
|
2424
2235
|
marginTop: 1,
|
|
2425
|
-
children: /* @__PURE__ */
|
|
2236
|
+
children: /* @__PURE__ */ jsxDEV15(Text11, {
|
|
2426
2237
|
color: success ? colors.success : colors.error,
|
|
2427
2238
|
children: success ? "Done" : "Failed"
|
|
2428
2239
|
}, undefined, false, undefined, this)
|
|
2429
2240
|
}, undefined, false, undefined, this),
|
|
2430
|
-
/* @__PURE__ */
|
|
2241
|
+
/* @__PURE__ */ jsxDEV15(Text11, {
|
|
2431
2242
|
dimColor: true,
|
|
2432
2243
|
children: "Press any key to continue..."
|
|
2433
2244
|
}, undefined, false, undefined, this)
|
|
2434
2245
|
]
|
|
2435
2246
|
}, undefined, true, undefined, this);
|
|
2436
2247
|
}
|
|
2437
|
-
return /* @__PURE__ */
|
|
2248
|
+
return /* @__PURE__ */ jsxDEV15(Panel, {
|
|
2438
2249
|
title: "Package Sync",
|
|
2439
|
-
children: /* @__PURE__ */
|
|
2250
|
+
children: /* @__PURE__ */ jsxDEV15(VimSelect, {
|
|
2440
2251
|
options: [
|
|
2441
2252
|
{ label: "Sync packages", value: "sync" },
|
|
2442
2253
|
{ label: "Sync with purge", value: "sync-purge" },
|
|
@@ -2450,32 +2261,74 @@ function PackageMenu({ onBack }) {
|
|
|
2450
2261
|
}, undefined, false, undefined, this)
|
|
2451
2262
|
}, undefined, false, undefined, this);
|
|
2452
2263
|
}
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2264
|
+
|
|
2265
|
+
// src/components/menus/ThemeMenu.tsx
|
|
2266
|
+
import { useState as useState8, useEffect as useEffect5, useMemo as useMemo4 } from "react";
|
|
2267
|
+
import { Box as Box14, Text as Text13 } from "ink";
|
|
2268
|
+
import { existsSync as existsSync6, readdirSync as readdirSync5 } from "fs";
|
|
2269
|
+
import { join as join5 } from "path";
|
|
2270
|
+
|
|
2271
|
+
// src/components/ThemeCard.tsx
|
|
2272
|
+
import { Box as Box13, Text as Text12 } from "ink";
|
|
2273
|
+
import { jsxDEV as jsxDEV16 } from "react/jsx-dev-runtime";
|
|
2274
|
+
function ThemeCard({ theme, isSelected, width }) {
|
|
2275
|
+
const borderColor = isSelected ? colors.accent : colors.border;
|
|
2276
|
+
const nameColor = isSelected ? colors.primary : colors.text;
|
|
2277
|
+
const indicators = [];
|
|
2278
|
+
if (theme.hasBackgrounds)
|
|
2279
|
+
indicators.push("bg");
|
|
2280
|
+
if (theme.isLightMode)
|
|
2281
|
+
indicators.push("light");
|
|
2282
|
+
const indicatorText = indicators.length > 0 ? ` [${indicators.join(" ")}]` : "";
|
|
2283
|
+
return /* @__PURE__ */ jsxDEV16(Box13, {
|
|
2284
|
+
flexDirection: "column",
|
|
2285
|
+
width,
|
|
2286
|
+
borderStyle: borderStyles.panel,
|
|
2287
|
+
borderColor,
|
|
2288
|
+
paddingX: 1,
|
|
2289
|
+
children: /* @__PURE__ */ jsxDEV16(Box13, {
|
|
2290
|
+
children: [
|
|
2291
|
+
/* @__PURE__ */ jsxDEV16(Text12, {
|
|
2292
|
+
color: isSelected ? colors.accent : colors.primaryDim,
|
|
2293
|
+
children: isSelected ? "● " : " "
|
|
2294
|
+
}, undefined, false, undefined, this),
|
|
2295
|
+
/* @__PURE__ */ jsxDEV16(Text12, {
|
|
2296
|
+
color: nameColor,
|
|
2297
|
+
bold: true,
|
|
2298
|
+
wrap: "truncate",
|
|
2299
|
+
children: theme.name
|
|
2300
|
+
}, undefined, false, undefined, this),
|
|
2301
|
+
/* @__PURE__ */ jsxDEV16(Text12, {
|
|
2302
|
+
color: colors.primaryDim,
|
|
2303
|
+
children: indicatorText
|
|
2304
|
+
}, undefined, false, undefined, this)
|
|
2305
|
+
]
|
|
2306
|
+
}, undefined, true, undefined, this)
|
|
2307
|
+
}, undefined, false, undefined, this);
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
// src/hooks/useThemeGrid.ts
|
|
2311
|
+
import { useState as useState7, useEffect as useEffect4 } from "react";
|
|
2312
|
+
import { useInput as useInput8 } from "ink";
|
|
2313
|
+
function useThemeGrid({
|
|
2314
|
+
itemCount,
|
|
2315
|
+
cardHeight = 3,
|
|
2316
|
+
layoutOverhead = 20,
|
|
2317
|
+
minCardWidth = 28,
|
|
2318
|
+
onSelect,
|
|
2319
|
+
onBack,
|
|
2320
|
+
enabled = true
|
|
2321
|
+
}) {
|
|
2460
2322
|
const { columns, rows } = useTerminalSize();
|
|
2461
|
-
const
|
|
2462
|
-
const
|
|
2463
|
-
const
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
const cardsPerRow = useMemo2(() => {
|
|
2469
|
-
const availableWidth = columns - 6;
|
|
2470
|
-
return Math.max(1, Math.floor(availableWidth / 28));
|
|
2471
|
-
}, [columns]);
|
|
2472
|
-
const visibleRows = useMemo2(() => {
|
|
2473
|
-
const availableHeight = rows - LAYOUT_OVERHEAD;
|
|
2474
|
-
return Math.max(1, Math.floor(availableHeight / CARD_HEIGHT));
|
|
2475
|
-
}, [rows]);
|
|
2323
|
+
const [selectedIndex, setSelectedIndex] = useState7(0);
|
|
2324
|
+
const [scrollOffset, setScrollOffset] = useState7(0);
|
|
2325
|
+
const availableWidth = columns - 6;
|
|
2326
|
+
const cardsPerRow = Math.max(1, Math.floor(availableWidth / minCardWidth));
|
|
2327
|
+
const cardWidth = Math.floor(availableWidth / cardsPerRow);
|
|
2328
|
+
const availableHeight = rows - layoutOverhead;
|
|
2329
|
+
const visibleRows = Math.max(1, Math.floor(availableHeight / cardHeight));
|
|
2476
2330
|
const selectedRow = Math.floor(selectedIndex / cardsPerRow);
|
|
2477
|
-
const totalRows = Math.ceil(
|
|
2478
|
-
const [scrollOffset, setScrollOffset] = useState5(0);
|
|
2331
|
+
const totalRows = Math.ceil(itemCount / cardsPerRow);
|
|
2479
2332
|
useEffect4(() => {
|
|
2480
2333
|
if (selectedRow < scrollOffset) {
|
|
2481
2334
|
setScrollOffset(selectedRow);
|
|
@@ -2483,21 +2336,15 @@ function ThemeMenu({ onBack }) {
|
|
|
2483
2336
|
setScrollOffset(selectedRow - visibleRows + 1);
|
|
2484
2337
|
}
|
|
2485
2338
|
}, [selectedRow, scrollOffset, visibleRows]);
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
const endIdx = (scrollOffset + visibleRows) * cardsPerRow;
|
|
2489
|
-
return themes.slice(startIdx, endIdx);
|
|
2490
|
-
}, [themes, scrollOffset, visibleRows, cardsPerRow]);
|
|
2491
|
-
const visibleStartIndex = scrollOffset * cardsPerRow;
|
|
2492
|
-
useInput5((input, key) => {
|
|
2493
|
-
if (state !== "menu" || loading)
|
|
2339
|
+
useInput8((input, key) => {
|
|
2340
|
+
if (!enabled)
|
|
2494
2341
|
return;
|
|
2495
|
-
if (key.escape) {
|
|
2342
|
+
if (key.escape && onBack) {
|
|
2496
2343
|
onBack();
|
|
2497
2344
|
return;
|
|
2498
2345
|
}
|
|
2499
2346
|
if (key.rightArrow || input === "l") {
|
|
2500
|
-
if (selectedIndex <
|
|
2347
|
+
if (selectedIndex < itemCount - 1) {
|
|
2501
2348
|
setSelectedIndex((i) => i + 1);
|
|
2502
2349
|
}
|
|
2503
2350
|
}
|
|
@@ -2508,7 +2355,7 @@ function ThemeMenu({ onBack }) {
|
|
|
2508
2355
|
}
|
|
2509
2356
|
if (key.downArrow || input === "j") {
|
|
2510
2357
|
const nextIndex = selectedIndex + cardsPerRow;
|
|
2511
|
-
if (nextIndex <
|
|
2358
|
+
if (nextIndex < itemCount) {
|
|
2512
2359
|
setSelectedIndex(nextIndex);
|
|
2513
2360
|
}
|
|
2514
2361
|
}
|
|
@@ -2518,78 +2365,348 @@ function ThemeMenu({ onBack }) {
|
|
|
2518
2365
|
setSelectedIndex(prevIndex);
|
|
2519
2366
|
}
|
|
2520
2367
|
}
|
|
2521
|
-
if (key.return) {
|
|
2522
|
-
|
|
2368
|
+
if (key.return && onSelect) {
|
|
2369
|
+
onSelect(selectedIndex);
|
|
2523
2370
|
}
|
|
2524
2371
|
});
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2372
|
+
const visibleStartIndex = scrollOffset * cardsPerRow;
|
|
2373
|
+
const visibleEndIndex = (scrollOffset + visibleRows) * cardsPerRow;
|
|
2374
|
+
return {
|
|
2375
|
+
cardsPerRow,
|
|
2376
|
+
cardWidth,
|
|
2377
|
+
visibleRows,
|
|
2378
|
+
scrollOffset,
|
|
2379
|
+
selectedIndex,
|
|
2380
|
+
visibleStartIndex,
|
|
2381
|
+
visibleEndIndex,
|
|
2382
|
+
showScrollUp: scrollOffset > 0,
|
|
2383
|
+
showScrollDown: scrollOffset + visibleRows < totalRows,
|
|
2384
|
+
gridHeight: visibleRows * cardHeight,
|
|
2385
|
+
totalRows
|
|
2386
|
+
};
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
// src/lib/theme-parser.ts
|
|
2390
|
+
import { existsSync as existsSync4, readdirSync as readdirSync3 } from "fs";
|
|
2391
|
+
import { join as join3 } from "path";
|
|
2392
|
+
function parseYaml(content) {
|
|
2393
|
+
const result = {};
|
|
2394
|
+
const lines = content.split(`
|
|
2395
|
+
`);
|
|
2396
|
+
let currentSection = null;
|
|
2397
|
+
let currentKey = "";
|
|
2398
|
+
for (const line of lines) {
|
|
2399
|
+
const trimmed = line.trim();
|
|
2400
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
2401
|
+
continue;
|
|
2402
|
+
const indentLevel = line.search(/\S/);
|
|
2403
|
+
const match = trimmed.match(/^([\w-]+):\s*(.*)$/);
|
|
2404
|
+
if (match) {
|
|
2405
|
+
const [, key, value] = match;
|
|
2406
|
+
if (indentLevel === 0) {
|
|
2407
|
+
if (value) {
|
|
2408
|
+
result[key] = value.replace(/^["']|["']$/g, "");
|
|
2409
|
+
} else {
|
|
2410
|
+
currentKey = key;
|
|
2411
|
+
currentSection = {};
|
|
2412
|
+
result[key] = currentSection;
|
|
2539
2413
|
}
|
|
2414
|
+
} else if (currentSection) {
|
|
2415
|
+
currentSection[key] = value.replace(/^["']|["']$/g, "");
|
|
2540
2416
|
}
|
|
2541
|
-
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
return result;
|
|
2420
|
+
}
|
|
2421
|
+
async function parseThemeMetadata(themePath) {
|
|
2422
|
+
const yamlPath = join3(themePath, "theme.yaml");
|
|
2423
|
+
if (!existsSync4(yamlPath)) {
|
|
2424
|
+
return;
|
|
2425
|
+
}
|
|
2426
|
+
try {
|
|
2427
|
+
const content = await readText(yamlPath);
|
|
2428
|
+
const parsed = parseYaml(content);
|
|
2429
|
+
return {
|
|
2430
|
+
name: parsed.name || "",
|
|
2431
|
+
author: parsed.author,
|
|
2432
|
+
description: parsed.description,
|
|
2433
|
+
version: parsed.version,
|
|
2434
|
+
source: parsed.source,
|
|
2435
|
+
colors: parsed.colors
|
|
2436
|
+
};
|
|
2437
|
+
} catch {
|
|
2438
|
+
return;
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
function parseThemeFiles(themePath) {
|
|
2442
|
+
const entries = readdirSync3(themePath, { withFileTypes: true });
|
|
2443
|
+
return entries.filter((e) => e.isFile() && !e.name.startsWith(".") && e.name !== "theme.yaml" && e.name !== "light.mode").map((e) => ({
|
|
2444
|
+
name: e.name,
|
|
2445
|
+
path: join3(themePath, e.name),
|
|
2446
|
+
application: e.name.replace(/\.(conf|theme|lua|toml|css|json|ini)$/, "")
|
|
2447
|
+
}));
|
|
2448
|
+
}
|
|
2449
|
+
async function parseTheme(themePath, themeName) {
|
|
2450
|
+
const files = parseThemeFiles(themePath);
|
|
2451
|
+
const metadata = await parseThemeMetadata(themePath);
|
|
2452
|
+
return {
|
|
2453
|
+
name: metadata?.name || themeName,
|
|
2454
|
+
path: themePath,
|
|
2455
|
+
files,
|
|
2456
|
+
metadata,
|
|
2457
|
+
hasBackgrounds: existsSync4(join3(themePath, "backgrounds")),
|
|
2458
|
+
hasPreview: existsSync4(join3(themePath, "preview.png")),
|
|
2459
|
+
isLightMode: existsSync4(join3(themePath, "light.mode"))
|
|
2460
|
+
};
|
|
2461
|
+
}
|
|
2462
|
+
|
|
2463
|
+
// src/cli/set-theme.ts
|
|
2464
|
+
import { parseArgs as parseArgs4 } from "util";
|
|
2465
|
+
import { readdirSync as readdirSync4, existsSync as existsSync5, rmSync, symlinkSync, unlinkSync } from "fs";
|
|
2466
|
+
import { join as join4 } from "path";
|
|
2467
|
+
var colors5 = {
|
|
2468
|
+
red: "\x1B[0;31m",
|
|
2469
|
+
green: "\x1B[0;32m",
|
|
2470
|
+
blue: "\x1B[0;34m",
|
|
2471
|
+
yellow: "\x1B[1;33m",
|
|
2472
|
+
cyan: "\x1B[0;36m",
|
|
2473
|
+
dim: "\x1B[2m",
|
|
2474
|
+
reset: "\x1B[0m"
|
|
2475
|
+
};
|
|
2476
|
+
async function listThemes() {
|
|
2477
|
+
await ensureConfigDir();
|
|
2478
|
+
if (!existsSync5(THEMES_DIR)) {
|
|
2479
|
+
return [];
|
|
2480
|
+
}
|
|
2481
|
+
const entries = readdirSync4(THEMES_DIR, { withFileTypes: true });
|
|
2482
|
+
const themes = [];
|
|
2483
|
+
for (const entry of entries) {
|
|
2484
|
+
if (entry.isDirectory()) {
|
|
2485
|
+
const themePath = join4(THEMES_DIR, entry.name);
|
|
2486
|
+
const theme = await parseTheme(themePath, entry.name);
|
|
2487
|
+
themes.push(theme);
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
return themes;
|
|
2491
|
+
}
|
|
2492
|
+
function clearDirectory(dir) {
|
|
2493
|
+
if (existsSync5(dir)) {
|
|
2494
|
+
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
2495
|
+
for (const entry of entries) {
|
|
2496
|
+
const fullPath = join4(dir, entry.name);
|
|
2497
|
+
if (entry.isSymbolicLink() || entry.isFile()) {
|
|
2498
|
+
unlinkSync(fullPath);
|
|
2499
|
+
} else if (entry.isDirectory()) {
|
|
2500
|
+
rmSync(fullPath, { recursive: true, force: true });
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
function createSymlink(source, target) {
|
|
2506
|
+
if (existsSync5(target)) {
|
|
2507
|
+
unlinkSync(target);
|
|
2508
|
+
}
|
|
2509
|
+
symlinkSync(source, target);
|
|
2510
|
+
}
|
|
2511
|
+
async function applyTheme(themeName) {
|
|
2512
|
+
const themeDir = join4(THEMES_DIR, themeName);
|
|
2513
|
+
if (!existsSync5(themeDir)) {
|
|
2514
|
+
return { output: `Theme '${themeName}' not found`, success: false };
|
|
2515
|
+
}
|
|
2516
|
+
await ensureConfigDir();
|
|
2517
|
+
await ensureDir2(THEME_TARGET_DIR);
|
|
2518
|
+
const theme = await parseTheme(themeDir, themeName);
|
|
2519
|
+
clearDirectory(THEME_TARGET_DIR);
|
|
2520
|
+
if (existsSync5(BACKGROUNDS_TARGET_DIR)) {
|
|
2521
|
+
rmSync(BACKGROUNDS_TARGET_DIR, { recursive: true, force: true });
|
|
2522
|
+
}
|
|
2523
|
+
const entries = readdirSync4(themeDir, { withFileTypes: true });
|
|
2524
|
+
for (const entry of entries) {
|
|
2525
|
+
const source = join4(themeDir, entry.name);
|
|
2526
|
+
if (entry.isFile() && entry.name !== "theme.yaml" && entry.name !== "light.mode") {
|
|
2527
|
+
const target = join4(THEME_TARGET_DIR, entry.name);
|
|
2528
|
+
createSymlink(source, target);
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
if (theme.hasBackgrounds) {
|
|
2532
|
+
const backgroundsSource = join4(themeDir, "backgrounds");
|
|
2533
|
+
createSymlink(backgroundsSource, BACKGROUNDS_TARGET_DIR);
|
|
2534
|
+
}
|
|
2535
|
+
let output = `Theme '${theme.name}' applied successfully`;
|
|
2536
|
+
if (theme.metadata?.author) {
|
|
2537
|
+
output += `
|
|
2538
|
+
Author: ${theme.metadata.author}`;
|
|
2539
|
+
}
|
|
2540
|
+
if (theme.hasBackgrounds) {
|
|
2541
|
+
output += `
|
|
2542
|
+
Wallpapers available at: ~/.config/formalconf/current/backgrounds/`;
|
|
2543
|
+
}
|
|
2544
|
+
if (theme.isLightMode) {
|
|
2545
|
+
output += `
|
|
2546
|
+
Note: This is a light mode theme`;
|
|
2547
|
+
}
|
|
2548
|
+
return { output, success: true };
|
|
2549
|
+
}
|
|
2550
|
+
async function showThemeInfo(themeName) {
|
|
2551
|
+
const themeDir = join4(THEMES_DIR, themeName);
|
|
2552
|
+
if (!existsSync5(themeDir)) {
|
|
2553
|
+
console.error(`${colors5.red}Error: Theme '${themeName}' not found${colors5.reset}`);
|
|
2554
|
+
process.exit(1);
|
|
2555
|
+
}
|
|
2556
|
+
const theme = await parseTheme(themeDir, themeName);
|
|
2557
|
+
console.log(`
|
|
2558
|
+
${colors5.cyan}Theme: ${theme.name}${colors5.reset}`);
|
|
2559
|
+
if (theme.metadata) {
|
|
2560
|
+
if (theme.metadata.author)
|
|
2561
|
+
console.log(`Author: ${theme.metadata.author}`);
|
|
2562
|
+
if (theme.metadata.description)
|
|
2563
|
+
console.log(`Description: ${theme.metadata.description}`);
|
|
2564
|
+
if (theme.metadata.version)
|
|
2565
|
+
console.log(`Version: ${theme.metadata.version}`);
|
|
2566
|
+
if (theme.metadata.source)
|
|
2567
|
+
console.log(`Source: ${theme.metadata.source}`);
|
|
2568
|
+
}
|
|
2569
|
+
console.log(`
|
|
2570
|
+
Files (${theme.files.length}):`);
|
|
2571
|
+
for (const file of theme.files) {
|
|
2572
|
+
console.log(` ${colors5.blue}•${colors5.reset} ${file.name}`);
|
|
2573
|
+
}
|
|
2574
|
+
if (theme.hasBackgrounds) {
|
|
2575
|
+
console.log(`
|
|
2576
|
+
${colors5.green}Has wallpapers${colors5.reset}`);
|
|
2577
|
+
}
|
|
2578
|
+
if (theme.hasPreview) {
|
|
2579
|
+
console.log(`${colors5.green}Has preview image${colors5.reset}`);
|
|
2580
|
+
}
|
|
2581
|
+
if (theme.isLightMode) {
|
|
2582
|
+
console.log(`${colors5.yellow}Light mode theme${colors5.reset}`);
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
async function runSetTheme(themeName) {
|
|
2586
|
+
return applyTheme(themeName);
|
|
2587
|
+
}
|
|
2588
|
+
async function main4() {
|
|
2589
|
+
const { positionals, values } = parseArgs4({
|
|
2590
|
+
args: process.argv.slice(2),
|
|
2591
|
+
options: {
|
|
2592
|
+
info: { type: "boolean", short: "i" }
|
|
2593
|
+
},
|
|
2594
|
+
allowPositionals: true
|
|
2595
|
+
});
|
|
2596
|
+
const [themeName] = positionals;
|
|
2597
|
+
if (!themeName) {
|
|
2598
|
+
const themes = await listThemes();
|
|
2599
|
+
if (themes.length === 0) {
|
|
2600
|
+
console.log(`${colors5.yellow}No themes available.${colors5.reset}`);
|
|
2601
|
+
console.log(`This system is compatible with omarchy themes.`);
|
|
2602
|
+
console.log(`
|
|
2603
|
+
Add themes to: ${colors5.cyan}~/.config/formalconf/themes/${colors5.reset}`);
|
|
2604
|
+
process.exit(0);
|
|
2605
|
+
}
|
|
2606
|
+
console.log(`${colors5.cyan}Usage: formalconf theme <theme-name>${colors5.reset}`);
|
|
2607
|
+
console.log(` formalconf theme --info <theme-name>
|
|
2608
|
+
`);
|
|
2609
|
+
console.log("Available themes:");
|
|
2610
|
+
for (const theme of themes) {
|
|
2611
|
+
const extras = [];
|
|
2612
|
+
if (theme.hasBackgrounds)
|
|
2613
|
+
extras.push("wallpapers");
|
|
2614
|
+
if (theme.isLightMode)
|
|
2615
|
+
extras.push("light");
|
|
2616
|
+
const suffix = extras.length ? ` ${colors5.dim}(${extras.join(", ")})${colors5.reset}` : "";
|
|
2617
|
+
console.log(` ${colors5.blue}•${colors5.reset} ${theme.name}${suffix}`);
|
|
2618
|
+
}
|
|
2619
|
+
process.exit(0);
|
|
2620
|
+
}
|
|
2621
|
+
if (values.info) {
|
|
2622
|
+
await showThemeInfo(themeName);
|
|
2623
|
+
} else {
|
|
2624
|
+
const result = await applyTheme(themeName);
|
|
2625
|
+
console.log(result.success ? `${colors5.green}${result.output}${colors5.reset}` : `${colors5.red}${result.output}${colors5.reset}`);
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
var isMainModule4 = process.argv[1]?.includes("set-theme");
|
|
2629
|
+
if (isMainModule4) {
|
|
2630
|
+
main4().catch(console.error);
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
// src/components/menus/ThemeMenu.tsx
|
|
2634
|
+
import { jsxDEV as jsxDEV17 } from "react/jsx-dev-runtime";
|
|
2635
|
+
function ThemeMenu({ onBack }) {
|
|
2636
|
+
const [themes, setThemes] = useState8([]);
|
|
2637
|
+
const [loading, setLoading] = useState8(true);
|
|
2638
|
+
const { state, output, success, isRunning, isResult, execute, reset } = useMenuAction();
|
|
2639
|
+
const grid = useThemeGrid({
|
|
2640
|
+
itemCount: themes.length,
|
|
2641
|
+
onSelect: (index) => applyTheme2(themes[index]),
|
|
2642
|
+
onBack,
|
|
2643
|
+
enabled: state === "menu" && !loading && themes.length > 0
|
|
2644
|
+
});
|
|
2645
|
+
useEffect5(() => {
|
|
2646
|
+
async function loadThemes() {
|
|
2647
|
+
if (!existsSync6(THEMES_DIR)) {
|
|
2648
|
+
setThemes([]);
|
|
2649
|
+
setLoading(false);
|
|
2650
|
+
return;
|
|
2651
|
+
}
|
|
2652
|
+
const entries = readdirSync5(THEMES_DIR, { withFileTypes: true });
|
|
2653
|
+
const loadedThemes = [];
|
|
2654
|
+
for (const entry of entries) {
|
|
2655
|
+
if (entry.isDirectory()) {
|
|
2656
|
+
const themePath = join5(THEMES_DIR, entry.name);
|
|
2657
|
+
const theme = await parseTheme(themePath, entry.name);
|
|
2658
|
+
loadedThemes.push(theme);
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
setThemes(loadedThemes);
|
|
2542
2662
|
setLoading(false);
|
|
2543
2663
|
}
|
|
2544
2664
|
loadThemes();
|
|
2545
2665
|
}, []);
|
|
2546
2666
|
const applyTheme2 = async (theme) => {
|
|
2547
|
-
setState("running");
|
|
2548
2667
|
const themeName = theme.path.split("/").pop();
|
|
2549
|
-
|
|
2550
|
-
setOutput(result.output);
|
|
2551
|
-
setSuccess(result.success);
|
|
2552
|
-
setState("result");
|
|
2668
|
+
await execute(() => runSetTheme(themeName));
|
|
2553
2669
|
};
|
|
2554
|
-
|
|
2555
|
-
return
|
|
2670
|
+
const visibleThemes = useMemo4(() => {
|
|
2671
|
+
return themes.slice(grid.visibleStartIndex, grid.visibleEndIndex);
|
|
2672
|
+
}, [themes, grid.visibleStartIndex, grid.visibleEndIndex]);
|
|
2673
|
+
if (loading || isRunning) {
|
|
2674
|
+
return /* @__PURE__ */ jsxDEV17(LoadingPanel, {
|
|
2556
2675
|
title: "Select Theme",
|
|
2557
|
-
|
|
2558
|
-
label: loading ? "Loading themes..." : "Applying theme..."
|
|
2559
|
-
}, undefined, false, undefined, this)
|
|
2676
|
+
label: loading ? "Loading themes..." : "Applying theme..."
|
|
2560
2677
|
}, undefined, false, undefined, this);
|
|
2561
2678
|
}
|
|
2562
|
-
if (
|
|
2563
|
-
return /* @__PURE__ */
|
|
2679
|
+
if (isResult) {
|
|
2680
|
+
return /* @__PURE__ */ jsxDEV17(CommandOutput, {
|
|
2564
2681
|
title: "Select Theme",
|
|
2565
2682
|
output,
|
|
2566
2683
|
success,
|
|
2567
|
-
onDismiss:
|
|
2684
|
+
onDismiss: reset
|
|
2568
2685
|
}, undefined, false, undefined, this);
|
|
2569
2686
|
}
|
|
2570
2687
|
if (themes.length === 0) {
|
|
2571
|
-
return /* @__PURE__ */
|
|
2688
|
+
return /* @__PURE__ */ jsxDEV17(Panel, {
|
|
2572
2689
|
title: "Select Theme",
|
|
2573
2690
|
children: [
|
|
2574
|
-
/* @__PURE__ */
|
|
2691
|
+
/* @__PURE__ */ jsxDEV17(Box14, {
|
|
2575
2692
|
flexDirection: "column",
|
|
2576
2693
|
children: [
|
|
2577
|
-
/* @__PURE__ */
|
|
2694
|
+
/* @__PURE__ */ jsxDEV17(Text13, {
|
|
2578
2695
|
color: colors.warning,
|
|
2579
2696
|
children: "No themes available."
|
|
2580
2697
|
}, undefined, false, undefined, this),
|
|
2581
|
-
/* @__PURE__ */
|
|
2698
|
+
/* @__PURE__ */ jsxDEV17(Text13, {
|
|
2582
2699
|
children: "This system is compatible with omarchy themes."
|
|
2583
2700
|
}, undefined, false, undefined, this),
|
|
2584
|
-
/* @__PURE__ */
|
|
2701
|
+
/* @__PURE__ */ jsxDEV17(Text13, {
|
|
2585
2702
|
dimColor: true,
|
|
2586
2703
|
children: "Add themes to ~/.config/formalconf/themes/"
|
|
2587
2704
|
}, undefined, false, undefined, this)
|
|
2588
2705
|
]
|
|
2589
2706
|
}, undefined, true, undefined, this),
|
|
2590
|
-
/* @__PURE__ */
|
|
2707
|
+
/* @__PURE__ */ jsxDEV17(Box14, {
|
|
2591
2708
|
marginTop: 1,
|
|
2592
|
-
children: /* @__PURE__ */
|
|
2709
|
+
children: /* @__PURE__ */ jsxDEV17(VimSelect, {
|
|
2593
2710
|
options: [{ label: "Back", value: "back" }],
|
|
2594
2711
|
onChange: () => onBack()
|
|
2595
2712
|
}, undefined, false, undefined, this)
|
|
@@ -2597,44 +2714,43 @@ function ThemeMenu({ onBack }) {
|
|
|
2597
2714
|
]
|
|
2598
2715
|
}, undefined, true, undefined, this);
|
|
2599
2716
|
}
|
|
2600
|
-
|
|
2601
|
-
const showScrollDown = scrollOffset + visibleRows < totalRows;
|
|
2602
|
-
const gridHeight = visibleRows * CARD_HEIGHT;
|
|
2603
|
-
return /* @__PURE__ */ jsxDEV12(Panel, {
|
|
2717
|
+
return /* @__PURE__ */ jsxDEV17(Panel, {
|
|
2604
2718
|
title: "Select Theme",
|
|
2605
2719
|
children: [
|
|
2606
|
-
showScrollUp && /* @__PURE__ */
|
|
2720
|
+
grid.showScrollUp && /* @__PURE__ */ jsxDEV17(Text13, {
|
|
2607
2721
|
dimColor: true,
|
|
2608
2722
|
children: [
|
|
2609
|
-
"
|
|
2610
|
-
|
|
2723
|
+
" ",
|
|
2724
|
+
"↑ ",
|
|
2725
|
+
grid.scrollOffset,
|
|
2611
2726
|
" more row",
|
|
2612
|
-
scrollOffset > 1 ? "s" : ""
|
|
2727
|
+
grid.scrollOffset > 1 ? "s" : ""
|
|
2613
2728
|
]
|
|
2614
2729
|
}, undefined, true, undefined, this),
|
|
2615
|
-
/* @__PURE__ */
|
|
2730
|
+
/* @__PURE__ */ jsxDEV17(Box14, {
|
|
2616
2731
|
flexDirection: "row",
|
|
2617
2732
|
flexWrap: "wrap",
|
|
2618
|
-
height: gridHeight,
|
|
2733
|
+
height: grid.gridHeight,
|
|
2619
2734
|
overflow: "hidden",
|
|
2620
|
-
children: visibleThemes.map((theme, index) => /* @__PURE__ */
|
|
2735
|
+
children: visibleThemes.map((theme, index) => /* @__PURE__ */ jsxDEV17(ThemeCard, {
|
|
2621
2736
|
theme,
|
|
2622
|
-
isSelected: visibleStartIndex + index === selectedIndex,
|
|
2623
|
-
width: cardWidth
|
|
2737
|
+
isSelected: grid.visibleStartIndex + index === grid.selectedIndex,
|
|
2738
|
+
width: grid.cardWidth
|
|
2624
2739
|
}, theme.path, false, undefined, this))
|
|
2625
2740
|
}, undefined, false, undefined, this),
|
|
2626
|
-
showScrollDown && /* @__PURE__ */
|
|
2741
|
+
grid.showScrollDown && /* @__PURE__ */ jsxDEV17(Text13, {
|
|
2627
2742
|
dimColor: true,
|
|
2628
2743
|
children: [
|
|
2629
|
-
"
|
|
2630
|
-
|
|
2744
|
+
" ",
|
|
2745
|
+
"↓ ",
|
|
2746
|
+
grid.totalRows - grid.scrollOffset - grid.visibleRows,
|
|
2631
2747
|
" more row",
|
|
2632
|
-
totalRows - scrollOffset - visibleRows > 1 ? "s" : ""
|
|
2748
|
+
grid.totalRows - grid.scrollOffset - grid.visibleRows > 1 ? "s" : ""
|
|
2633
2749
|
]
|
|
2634
2750
|
}, undefined, true, undefined, this),
|
|
2635
|
-
/* @__PURE__ */
|
|
2751
|
+
/* @__PURE__ */ jsxDEV17(Box14, {
|
|
2636
2752
|
marginTop: 1,
|
|
2637
|
-
children: /* @__PURE__ */
|
|
2753
|
+
children: /* @__PURE__ */ jsxDEV17(Text13, {
|
|
2638
2754
|
dimColor: true,
|
|
2639
2755
|
children: "←→↑↓/hjkl navigate • Enter select • Esc back"
|
|
2640
2756
|
}, undefined, false, undefined, this)
|
|
@@ -2642,65 +2758,25 @@ function ThemeMenu({ onBack }) {
|
|
|
2642
2758
|
]
|
|
2643
2759
|
}, undefined, true, undefined, this);
|
|
2644
2760
|
}
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
borderColor: colors.error,
|
|
2655
|
-
children: [
|
|
2656
|
-
/* @__PURE__ */ jsxDEV12(Text11, {
|
|
2657
|
-
color: colors.error,
|
|
2658
|
-
children: "Required tools are not installed:"
|
|
2659
|
-
}, undefined, false, undefined, this),
|
|
2660
|
-
/* @__PURE__ */ jsxDEV12(Box12, {
|
|
2661
|
-
flexDirection: "column",
|
|
2662
|
-
marginTop: 1,
|
|
2663
|
-
children: missing.map((dep) => /* @__PURE__ */ jsxDEV12(Box12, {
|
|
2664
|
-
children: [
|
|
2665
|
-
/* @__PURE__ */ jsxDEV12(Text11, {
|
|
2666
|
-
color: colors.warning,
|
|
2667
|
-
children: [
|
|
2668
|
-
"• ",
|
|
2669
|
-
dep.name
|
|
2670
|
-
]
|
|
2671
|
-
}, undefined, true, undefined, this),
|
|
2672
|
-
/* @__PURE__ */ jsxDEV12(Text11, {
|
|
2673
|
-
dimColor: true,
|
|
2674
|
-
children: [
|
|
2675
|
-
" — Install: ",
|
|
2676
|
-
dep.install
|
|
2677
|
-
]
|
|
2678
|
-
}, undefined, true, undefined, this)
|
|
2679
|
-
]
|
|
2680
|
-
}, dep.name, true, undefined, this))
|
|
2681
|
-
}, undefined, false, undefined, this),
|
|
2682
|
-
/* @__PURE__ */ jsxDEV12(Box12, {
|
|
2683
|
-
marginTop: 1,
|
|
2684
|
-
children: /* @__PURE__ */ jsxDEV12(Text11, {
|
|
2685
|
-
dimColor: true,
|
|
2686
|
-
children: "Press any key to exit..."
|
|
2687
|
-
}, undefined, false, undefined, this)
|
|
2688
|
-
}, undefined, false, undefined, this)
|
|
2689
|
-
]
|
|
2690
|
-
}, undefined, true, undefined, this)
|
|
2691
|
-
}, undefined, false, undefined, this);
|
|
2692
|
-
}
|
|
2761
|
+
|
|
2762
|
+
// src/cli/formalconf.tsx
|
|
2763
|
+
import { jsxDEV as jsxDEV18 } from "react/jsx-dev-runtime";
|
|
2764
|
+
var BREADCRUMBS = {
|
|
2765
|
+
main: ["Main"],
|
|
2766
|
+
config: ["Main", "Config Manager"],
|
|
2767
|
+
packages: ["Main", "Package Sync"],
|
|
2768
|
+
themes: ["Main", "Themes"]
|
|
2769
|
+
};
|
|
2693
2770
|
function App() {
|
|
2694
|
-
const [appState, setAppState] =
|
|
2695
|
-
const [missingDeps, setMissingDeps] =
|
|
2696
|
-
const [screen, setScreen] =
|
|
2697
|
-
const { exit } =
|
|
2698
|
-
|
|
2699
|
-
if (input === "q")
|
|
2771
|
+
const [appState, setAppState] = useState9("loading");
|
|
2772
|
+
const [missingDeps, setMissingDeps] = useState9([]);
|
|
2773
|
+
const [screen, setScreen] = useState9("main");
|
|
2774
|
+
const { exit } = useApp2();
|
|
2775
|
+
useInput9((input) => {
|
|
2776
|
+
if (input === "q")
|
|
2700
2777
|
exit();
|
|
2701
|
-
}
|
|
2702
2778
|
});
|
|
2703
|
-
|
|
2779
|
+
useEffect6(() => {
|
|
2704
2780
|
async function init() {
|
|
2705
2781
|
ensureConfigDir();
|
|
2706
2782
|
const result = await checkPrerequisites();
|
|
@@ -2713,51 +2789,40 @@ function App() {
|
|
|
2713
2789
|
}
|
|
2714
2790
|
init();
|
|
2715
2791
|
}, []);
|
|
2716
|
-
const getBreadcrumb = () => {
|
|
2717
|
-
switch (screen) {
|
|
2718
|
-
case "config":
|
|
2719
|
-
return ["Main", "Config Manager"];
|
|
2720
|
-
case "packages":
|
|
2721
|
-
return ["Main", "Package Sync"];
|
|
2722
|
-
case "themes":
|
|
2723
|
-
return ["Main", "Themes"];
|
|
2724
|
-
default:
|
|
2725
|
-
return ["Main"];
|
|
2726
|
-
}
|
|
2727
|
-
};
|
|
2728
2792
|
if (appState === "loading") {
|
|
2729
|
-
return /* @__PURE__ */
|
|
2793
|
+
return /* @__PURE__ */ jsxDEV18(Layout, {
|
|
2730
2794
|
breadcrumb: ["Loading"],
|
|
2731
|
-
children: /* @__PURE__ */
|
|
2795
|
+
children: /* @__PURE__ */ jsxDEV18(Panel, {
|
|
2732
2796
|
title: "FormalConf",
|
|
2733
|
-
children: /* @__PURE__ */
|
|
2797
|
+
children: /* @__PURE__ */ jsxDEV18(Spinner2, {
|
|
2734
2798
|
label: "Checking prerequisites..."
|
|
2735
2799
|
}, undefined, false, undefined, this)
|
|
2736
2800
|
}, undefined, false, undefined, this)
|
|
2737
2801
|
}, undefined, false, undefined, this);
|
|
2738
2802
|
}
|
|
2739
2803
|
if (appState === "error") {
|
|
2740
|
-
return /* @__PURE__ */
|
|
2804
|
+
return /* @__PURE__ */ jsxDEV18(PrerequisiteError, {
|
|
2741
2805
|
missing: missingDeps,
|
|
2742
2806
|
onExit: exit
|
|
2743
2807
|
}, undefined, false, undefined, this);
|
|
2744
2808
|
}
|
|
2745
|
-
|
|
2746
|
-
|
|
2809
|
+
const goBack = () => setScreen("main");
|
|
2810
|
+
return /* @__PURE__ */ jsxDEV18(Layout, {
|
|
2811
|
+
breadcrumb: BREADCRUMBS[screen],
|
|
2747
2812
|
children: [
|
|
2748
|
-
screen === "main" && /* @__PURE__ */
|
|
2813
|
+
screen === "main" && /* @__PURE__ */ jsxDEV18(MainMenu, {
|
|
2749
2814
|
onSelect: setScreen
|
|
2750
2815
|
}, undefined, false, undefined, this),
|
|
2751
|
-
screen === "config" && /* @__PURE__ */
|
|
2752
|
-
onBack:
|
|
2816
|
+
screen === "config" && /* @__PURE__ */ jsxDEV18(ConfigMenu, {
|
|
2817
|
+
onBack: goBack
|
|
2753
2818
|
}, undefined, false, undefined, this),
|
|
2754
|
-
screen === "packages" && /* @__PURE__ */
|
|
2755
|
-
onBack:
|
|
2819
|
+
screen === "packages" && /* @__PURE__ */ jsxDEV18(PackageMenu, {
|
|
2820
|
+
onBack: goBack
|
|
2756
2821
|
}, undefined, false, undefined, this),
|
|
2757
|
-
screen === "themes" && /* @__PURE__ */
|
|
2758
|
-
onBack:
|
|
2822
|
+
screen === "themes" && /* @__PURE__ */ jsxDEV18(ThemeMenu, {
|
|
2823
|
+
onBack: goBack
|
|
2759
2824
|
}, undefined, false, undefined, this)
|
|
2760
2825
|
]
|
|
2761
2826
|
}, undefined, true, undefined, this);
|
|
2762
2827
|
}
|
|
2763
|
-
render(/* @__PURE__ */
|
|
2828
|
+
render(/* @__PURE__ */ jsxDEV18(App, {}, undefined, false, undefined, this));
|