formalconf 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/formalconf.js +1444 -865
- 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 useState10, useEffect as useEffect6 } from "react";
|
|
4
|
+
import { render, useApp as useApp2, useInput as useInput10 } 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,15 +32,16 @@ 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
|
|
102
42
|
import { homedir } from "os";
|
|
103
43
|
import { join } from "path";
|
|
44
|
+
import { readdir } from "fs/promises";
|
|
104
45
|
|
|
105
46
|
// src/lib/runtime.ts
|
|
106
47
|
import { spawn as nodeSpawn } from "child_process";
|
|
@@ -354,11 +295,24 @@ async function ensureConfigDir() {
|
|
|
354
295
|
await ensureDir2(THEME_TARGET_DIR);
|
|
355
296
|
await ensureDir2(BACKGROUNDS_TARGET_DIR);
|
|
356
297
|
}
|
|
298
|
+
async function dirHasContents(path) {
|
|
299
|
+
try {
|
|
300
|
+
const entries = await readdir(path);
|
|
301
|
+
return entries.length > 0;
|
|
302
|
+
} catch {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
async function isFirstRun() {
|
|
307
|
+
const configsExist = await dirHasContents(CONFIGS_DIR);
|
|
308
|
+
const themesExist = await dirHasContents(THEMES_DIR);
|
|
309
|
+
return !configsExist && !themesExist;
|
|
310
|
+
}
|
|
357
311
|
|
|
358
312
|
// src/hooks/useSystemStatus.ts
|
|
359
313
|
import { basename, dirname as dirname2, join as join2 } from "path";
|
|
360
314
|
function useSystemStatus() {
|
|
361
|
-
const [status, setStatus] =
|
|
315
|
+
const [status, setStatus] = useState2({
|
|
362
316
|
currentTheme: null,
|
|
363
317
|
configsLinked: false,
|
|
364
318
|
loading: true
|
|
@@ -395,8 +349,30 @@ function useSystemStatus() {
|
|
|
395
349
|
}
|
|
396
350
|
|
|
397
351
|
// src/components/ui/StatusIndicator.tsx
|
|
398
|
-
import { Box
|
|
399
|
-
|
|
352
|
+
import { Box, Text } from "ink";
|
|
353
|
+
|
|
354
|
+
// src/lib/theme.ts
|
|
355
|
+
var colors = {
|
|
356
|
+
primary: "#5eead4",
|
|
357
|
+
primaryDim: "#2dd4bf",
|
|
358
|
+
accent: "#06b6d4",
|
|
359
|
+
success: "#22c55e",
|
|
360
|
+
error: "#ef4444",
|
|
361
|
+
warning: "#f59e0b",
|
|
362
|
+
info: "#3b82f6",
|
|
363
|
+
text: "white",
|
|
364
|
+
textDim: "gray",
|
|
365
|
+
border: "#374151",
|
|
366
|
+
borderLight: "#4b5563"
|
|
367
|
+
};
|
|
368
|
+
var borderStyles = {
|
|
369
|
+
panel: "round",
|
|
370
|
+
header: "round",
|
|
371
|
+
footer: "single"
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
// src/components/ui/StatusIndicator.tsx
|
|
375
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
400
376
|
function StatusIndicator({
|
|
401
377
|
label,
|
|
402
378
|
value,
|
|
@@ -414,17 +390,17 @@ function StatusIndicator({
|
|
|
414
390
|
error: "●",
|
|
415
391
|
neutral: "○"
|
|
416
392
|
};
|
|
417
|
-
return /* @__PURE__ */
|
|
393
|
+
return /* @__PURE__ */ jsxDEV(Box, {
|
|
418
394
|
gap: 1,
|
|
419
395
|
children: [
|
|
420
|
-
/* @__PURE__ */
|
|
396
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
421
397
|
dimColor: true,
|
|
422
398
|
children: [
|
|
423
399
|
label,
|
|
424
400
|
":"
|
|
425
401
|
]
|
|
426
402
|
}, undefined, true, undefined, this),
|
|
427
|
-
/* @__PURE__ */
|
|
403
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
428
404
|
color: statusColors[status],
|
|
429
405
|
children: [
|
|
430
406
|
icon[status],
|
|
@@ -438,7 +414,7 @@ function StatusIndicator({
|
|
|
438
414
|
// package.json
|
|
439
415
|
var package_default = {
|
|
440
416
|
name: "formalconf",
|
|
441
|
-
version: "2.0.
|
|
417
|
+
version: "2.0.3",
|
|
442
418
|
description: "Dotfiles management TUI for macOS - config management, package sync, and theme switching",
|
|
443
419
|
type: "module",
|
|
444
420
|
main: "./dist/formalconf.js",
|
|
@@ -491,11 +467,11 @@ var package_default = {
|
|
|
491
467
|
};
|
|
492
468
|
|
|
493
469
|
// src/components/Header.tsx
|
|
494
|
-
import { jsxDEV as
|
|
470
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
495
471
|
function Header() {
|
|
496
472
|
const { columns } = useTerminalSize();
|
|
497
473
|
const { currentTheme, configsLinked, loading } = useSystemStatus();
|
|
498
|
-
return /* @__PURE__ */
|
|
474
|
+
return /* @__PURE__ */ jsxDEV2(Box2, {
|
|
499
475
|
flexDirection: "column",
|
|
500
476
|
width: columns - 2,
|
|
501
477
|
borderStyle: borderStyles.header,
|
|
@@ -503,24 +479,24 @@ function Header() {
|
|
|
503
479
|
paddingX: 2,
|
|
504
480
|
marginBottom: 1,
|
|
505
481
|
children: [
|
|
506
|
-
/* @__PURE__ */
|
|
482
|
+
/* @__PURE__ */ jsxDEV2(Box2, {
|
|
507
483
|
justifyContent: "space-between",
|
|
508
484
|
width: "100%",
|
|
509
485
|
children: [
|
|
510
|
-
/* @__PURE__ */
|
|
486
|
+
/* @__PURE__ */ jsxDEV2(Box2, {
|
|
511
487
|
children: [
|
|
512
|
-
/* @__PURE__ */
|
|
488
|
+
/* @__PURE__ */ jsxDEV2(Text2, {
|
|
513
489
|
bold: true,
|
|
514
490
|
color: colors.primary,
|
|
515
491
|
children: "FormalConf"
|
|
516
492
|
}, undefined, false, undefined, this),
|
|
517
|
-
/* @__PURE__ */
|
|
493
|
+
/* @__PURE__ */ jsxDEV2(Text2, {
|
|
518
494
|
dimColor: true,
|
|
519
495
|
children: " - Dotfiles Manager"
|
|
520
496
|
}, undefined, false, undefined, this)
|
|
521
497
|
]
|
|
522
498
|
}, undefined, true, undefined, this),
|
|
523
|
-
/* @__PURE__ */
|
|
499
|
+
/* @__PURE__ */ jsxDEV2(Text2, {
|
|
524
500
|
dimColor: true,
|
|
525
501
|
children: [
|
|
526
502
|
"v",
|
|
@@ -529,16 +505,16 @@ function Header() {
|
|
|
529
505
|
}, undefined, true, undefined, this)
|
|
530
506
|
]
|
|
531
507
|
}, undefined, true, undefined, this),
|
|
532
|
-
!loading && /* @__PURE__ */
|
|
508
|
+
!loading && /* @__PURE__ */ jsxDEV2(Box2, {
|
|
533
509
|
marginTop: 1,
|
|
534
510
|
gap: 4,
|
|
535
511
|
children: [
|
|
536
|
-
/* @__PURE__ */
|
|
512
|
+
/* @__PURE__ */ jsxDEV2(StatusIndicator, {
|
|
537
513
|
label: "Theme",
|
|
538
514
|
value: currentTheme,
|
|
539
515
|
status: currentTheme ? "success" : "neutral"
|
|
540
516
|
}, undefined, false, undefined, this),
|
|
541
|
-
/* @__PURE__ */
|
|
517
|
+
/* @__PURE__ */ jsxDEV2(StatusIndicator, {
|
|
542
518
|
label: "Configs",
|
|
543
519
|
value: configsLinked ? "Linked" : "Not linked",
|
|
544
520
|
status: configsLinked ? "success" : "warning"
|
|
@@ -550,8 +526,8 @@ function Header() {
|
|
|
550
526
|
}
|
|
551
527
|
|
|
552
528
|
// src/components/layout/Footer.tsx
|
|
553
|
-
import { Box as
|
|
554
|
-
import { jsxDEV as
|
|
529
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
530
|
+
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
555
531
|
var defaultShortcuts = [
|
|
556
532
|
{ key: "↑↓/jk", label: "Navigate" },
|
|
557
533
|
{ key: "Enter/l", label: "Select" },
|
|
@@ -560,7 +536,7 @@ var defaultShortcuts = [
|
|
|
560
536
|
];
|
|
561
537
|
function Footer({ shortcuts = defaultShortcuts }) {
|
|
562
538
|
const { columns } = useTerminalSize();
|
|
563
|
-
return /* @__PURE__ */
|
|
539
|
+
return /* @__PURE__ */ jsxDEV3(Box3, {
|
|
564
540
|
width: columns - 2,
|
|
565
541
|
borderStyle: borderStyles.footer,
|
|
566
542
|
borderColor: colors.border,
|
|
@@ -568,15 +544,15 @@ function Footer({ shortcuts = defaultShortcuts }) {
|
|
|
568
544
|
marginTop: 1,
|
|
569
545
|
justifyContent: "center",
|
|
570
546
|
gap: 2,
|
|
571
|
-
children: shortcuts.map((shortcut, index) => /* @__PURE__ */
|
|
547
|
+
children: shortcuts.map((shortcut, index) => /* @__PURE__ */ jsxDEV3(Box3, {
|
|
572
548
|
gap: 1,
|
|
573
549
|
children: [
|
|
574
|
-
/* @__PURE__ */
|
|
550
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
575
551
|
color: colors.primary,
|
|
576
552
|
bold: true,
|
|
577
553
|
children: shortcut.key
|
|
578
554
|
}, undefined, false, undefined, this),
|
|
579
|
-
/* @__PURE__ */
|
|
555
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
580
556
|
dimColor: true,
|
|
581
557
|
children: shortcut.label
|
|
582
558
|
}, undefined, false, undefined, this)
|
|
@@ -586,14 +562,14 @@ function Footer({ shortcuts = defaultShortcuts }) {
|
|
|
586
562
|
}
|
|
587
563
|
|
|
588
564
|
// src/components/layout/Breadcrumb.tsx
|
|
589
|
-
import
|
|
590
|
-
import { Box as
|
|
591
|
-
import { jsxDEV as
|
|
565
|
+
import React from "react";
|
|
566
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
567
|
+
import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
|
|
592
568
|
function Breadcrumb({ path }) {
|
|
593
|
-
return /* @__PURE__ */
|
|
594
|
-
children: path.map((segment, index) => /* @__PURE__ */
|
|
569
|
+
return /* @__PURE__ */ jsxDEV4(Box4, {
|
|
570
|
+
children: path.map((segment, index) => /* @__PURE__ */ jsxDEV4(React.Fragment, {
|
|
595
571
|
children: [
|
|
596
|
-
index > 0 && /* @__PURE__ */
|
|
572
|
+
index > 0 && /* @__PURE__ */ jsxDEV4(Text4, {
|
|
597
573
|
color: colors.textDim,
|
|
598
574
|
children: [
|
|
599
575
|
" ",
|
|
@@ -601,7 +577,7 @@ function Breadcrumb({ path }) {
|
|
|
601
577
|
" "
|
|
602
578
|
]
|
|
603
579
|
}, undefined, true, undefined, this),
|
|
604
|
-
/* @__PURE__ */
|
|
580
|
+
/* @__PURE__ */ jsxDEV4(Text4, {
|
|
605
581
|
color: index === path.length - 1 ? colors.primary : colors.textDim,
|
|
606
582
|
bold: index === path.length - 1,
|
|
607
583
|
children: segment
|
|
@@ -612,39 +588,39 @@ function Breadcrumb({ path }) {
|
|
|
612
588
|
}
|
|
613
589
|
|
|
614
590
|
// src/components/layout/Layout.tsx
|
|
615
|
-
import { jsxDEV as
|
|
591
|
+
import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
|
|
616
592
|
function Layout({
|
|
617
593
|
children,
|
|
618
594
|
breadcrumb = ["Main"],
|
|
619
595
|
showFooter = true
|
|
620
596
|
}) {
|
|
621
597
|
const { columns } = useTerminalSize();
|
|
622
|
-
return /* @__PURE__ */
|
|
598
|
+
return /* @__PURE__ */ jsxDEV5(Box5, {
|
|
623
599
|
flexDirection: "column",
|
|
624
600
|
width: columns,
|
|
625
601
|
padding: 1,
|
|
626
602
|
children: [
|
|
627
|
-
/* @__PURE__ */
|
|
628
|
-
breadcrumb.length > 1 && /* @__PURE__ */
|
|
603
|
+
/* @__PURE__ */ jsxDEV5(Header, {}, undefined, false, undefined, this),
|
|
604
|
+
breadcrumb.length > 1 && /* @__PURE__ */ jsxDEV5(Box5, {
|
|
629
605
|
marginBottom: 1,
|
|
630
606
|
marginLeft: 1,
|
|
631
|
-
children: /* @__PURE__ */
|
|
607
|
+
children: /* @__PURE__ */ jsxDEV5(Breadcrumb, {
|
|
632
608
|
path: breadcrumb
|
|
633
609
|
}, undefined, false, undefined, this)
|
|
634
610
|
}, undefined, false, undefined, this),
|
|
635
|
-
/* @__PURE__ */
|
|
611
|
+
/* @__PURE__ */ jsxDEV5(Box5, {
|
|
636
612
|
flexDirection: "column",
|
|
637
613
|
flexGrow: 1,
|
|
638
614
|
children
|
|
639
615
|
}, undefined, false, undefined, this),
|
|
640
|
-
showFooter && /* @__PURE__ */
|
|
616
|
+
showFooter && /* @__PURE__ */ jsxDEV5(Footer, {}, undefined, false, undefined, this)
|
|
641
617
|
]
|
|
642
618
|
}, undefined, true, undefined, this);
|
|
643
619
|
}
|
|
644
620
|
|
|
645
621
|
// src/components/layout/Panel.tsx
|
|
646
|
-
import { Box as
|
|
647
|
-
import { jsxDEV as
|
|
622
|
+
import { Box as Box6, Text as Text5 } from "ink";
|
|
623
|
+
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
648
624
|
function Panel({
|
|
649
625
|
title,
|
|
650
626
|
children,
|
|
@@ -652,7 +628,7 @@ function Panel({
|
|
|
652
628
|
flexGrow,
|
|
653
629
|
borderColor = colors.border
|
|
654
630
|
}) {
|
|
655
|
-
return /* @__PURE__ */
|
|
631
|
+
return /* @__PURE__ */ jsxDEV6(Box6, {
|
|
656
632
|
flexDirection: "column",
|
|
657
633
|
width,
|
|
658
634
|
flexGrow,
|
|
@@ -660,9 +636,9 @@ function Panel({
|
|
|
660
636
|
borderColor,
|
|
661
637
|
paddingX: 1,
|
|
662
638
|
children: [
|
|
663
|
-
title && /* @__PURE__ */
|
|
639
|
+
title && /* @__PURE__ */ jsxDEV6(Box6, {
|
|
664
640
|
marginBottom: 1,
|
|
665
|
-
children: /* @__PURE__ */
|
|
641
|
+
children: /* @__PURE__ */ jsxDEV6(Text5, {
|
|
666
642
|
bold: true,
|
|
667
643
|
color: colors.primary,
|
|
668
644
|
children: title
|
|
@@ -673,281 +649,696 @@ function Panel({
|
|
|
673
649
|
}, undefined, true, undefined, this);
|
|
674
650
|
}
|
|
675
651
|
|
|
676
|
-
// src/components/
|
|
677
|
-
import { Box as
|
|
678
|
-
import { jsxDEV as
|
|
679
|
-
function
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
onDismiss();
|
|
687
|
-
});
|
|
688
|
-
return /* @__PURE__ */ jsxDEV8(Panel, {
|
|
689
|
-
title,
|
|
690
|
-
borderColor: success ? colors.success : colors.error,
|
|
691
|
-
children: [
|
|
692
|
-
output && /* @__PURE__ */ jsxDEV8(Box8, {
|
|
693
|
-
flexDirection: "column",
|
|
694
|
-
marginBottom: 1,
|
|
695
|
-
children: /* @__PURE__ */ jsxDEV8(Text7, {
|
|
696
|
-
children: output
|
|
697
|
-
}, undefined, false, undefined, this)
|
|
698
|
-
}, undefined, false, undefined, this),
|
|
699
|
-
/* @__PURE__ */ jsxDEV8(Text7, {
|
|
700
|
-
color: success ? colors.success : colors.error,
|
|
701
|
-
children: success ? "Done" : "Failed"
|
|
702
|
-
}, undefined, false, undefined, this),
|
|
703
|
-
/* @__PURE__ */ jsxDEV8(Text7, {
|
|
704
|
-
dimColor: true,
|
|
705
|
-
children: "Press any key to continue..."
|
|
706
|
-
}, undefined, false, undefined, this)
|
|
707
|
-
]
|
|
708
|
-
}, undefined, true, undefined, this);
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
// src/components/ThemeCard.tsx
|
|
712
|
-
import { Box as Box9, Text as Text8 } from "ink";
|
|
713
|
-
import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
|
|
714
|
-
function ThemeCard({ theme, isSelected, width }) {
|
|
715
|
-
const borderColor = isSelected ? colors.accent : colors.border;
|
|
716
|
-
const nameColor = isSelected ? colors.primary : colors.text;
|
|
717
|
-
const indicators = [];
|
|
718
|
-
if (theme.hasBackgrounds)
|
|
719
|
-
indicators.push("bg");
|
|
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, {
|
|
652
|
+
// src/components/PrerequisiteError.tsx
|
|
653
|
+
import { Box as Box7, Text as Text6, useInput } from "ink";
|
|
654
|
+
import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
|
|
655
|
+
function PrerequisiteError({ missing, onExit }) {
|
|
656
|
+
useInput(() => onExit());
|
|
657
|
+
return /* @__PURE__ */ jsxDEV7(Layout, {
|
|
658
|
+
breadcrumb: ["Error"],
|
|
659
|
+
children: /* @__PURE__ */ jsxDEV7(Panel, {
|
|
660
|
+
title: "Missing Prerequisites",
|
|
661
|
+
borderColor: colors.error,
|
|
730
662
|
children: [
|
|
731
|
-
/* @__PURE__ */
|
|
732
|
-
color:
|
|
733
|
-
children:
|
|
663
|
+
/* @__PURE__ */ jsxDEV7(Text6, {
|
|
664
|
+
color: colors.error,
|
|
665
|
+
children: "Required tools are not installed:"
|
|
734
666
|
}, undefined, false, undefined, this),
|
|
735
|
-
/* @__PURE__ */
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
667
|
+
/* @__PURE__ */ jsxDEV7(Box7, {
|
|
668
|
+
flexDirection: "column",
|
|
669
|
+
marginTop: 1,
|
|
670
|
+
children: missing.map((dep) => /* @__PURE__ */ jsxDEV7(Box7, {
|
|
671
|
+
children: [
|
|
672
|
+
/* @__PURE__ */ jsxDEV7(Text6, {
|
|
673
|
+
color: colors.warning,
|
|
674
|
+
children: [
|
|
675
|
+
"• ",
|
|
676
|
+
dep.name
|
|
677
|
+
]
|
|
678
|
+
}, undefined, true, undefined, this),
|
|
679
|
+
/* @__PURE__ */ jsxDEV7(Text6, {
|
|
680
|
+
dimColor: true,
|
|
681
|
+
children: [
|
|
682
|
+
" — Install: ",
|
|
683
|
+
dep.install
|
|
684
|
+
]
|
|
685
|
+
}, undefined, true, undefined, this)
|
|
686
|
+
]
|
|
687
|
+
}, dep.name, true, undefined, this))
|
|
740
688
|
}, undefined, false, undefined, this),
|
|
741
|
-
/* @__PURE__ */
|
|
742
|
-
|
|
743
|
-
children:
|
|
689
|
+
/* @__PURE__ */ jsxDEV7(Box7, {
|
|
690
|
+
marginTop: 1,
|
|
691
|
+
children: /* @__PURE__ */ jsxDEV7(Text6, {
|
|
692
|
+
dimColor: true,
|
|
693
|
+
children: "Press any key to exit..."
|
|
694
|
+
}, undefined, false, undefined, this)
|
|
744
695
|
}, undefined, false, undefined, this)
|
|
745
696
|
]
|
|
746
697
|
}, undefined, true, undefined, this)
|
|
747
698
|
}, undefined, false, undefined, this);
|
|
748
699
|
}
|
|
749
700
|
|
|
750
|
-
// src/components/
|
|
751
|
-
import { useState as useState4
|
|
752
|
-
import { Box as
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
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));
|
|
701
|
+
// src/components/Onboarding.tsx
|
|
702
|
+
import { useState as useState4 } from "react";
|
|
703
|
+
import { Box as Box9, Text as Text8, useInput as useInput3 } from "ink";
|
|
704
|
+
|
|
705
|
+
// src/components/ui/VimSelect.tsx
|
|
706
|
+
import { useState as useState3 } from "react";
|
|
707
|
+
import { Box as Box8, Text as Text7, useInput as useInput2 } from "ink";
|
|
708
|
+
import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
|
|
709
|
+
function VimSelect({ options, onChange, isDisabled = false }) {
|
|
710
|
+
const [index, setIndex] = useState3(0);
|
|
711
|
+
useInput2((input, key) => {
|
|
712
|
+
if (isDisabled)
|
|
713
|
+
return;
|
|
714
|
+
if (input === "j" || key.downArrow) {
|
|
715
|
+
setIndex((i) => i < options.length - 1 ? i + 1 : i);
|
|
779
716
|
}
|
|
780
|
-
if (input === "
|
|
781
|
-
|
|
782
|
-
setScrollOffset(maxOffset);
|
|
717
|
+
if (input === "k" || key.upArrow) {
|
|
718
|
+
setIndex((i) => i > 0 ? i - 1 : i);
|
|
783
719
|
}
|
|
784
|
-
if (input === "
|
|
785
|
-
|
|
786
|
-
setScrollOffset(0);
|
|
720
|
+
if (input === "l" || key.return) {
|
|
721
|
+
onChange(options[index].value);
|
|
787
722
|
}
|
|
788
723
|
});
|
|
789
|
-
|
|
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, {
|
|
724
|
+
return /* @__PURE__ */ jsxDEV8(Box8, {
|
|
795
725
|
flexDirection: "column",
|
|
796
|
-
children:
|
|
797
|
-
|
|
798
|
-
|
|
726
|
+
children: options.map((opt, i) => /* @__PURE__ */ jsxDEV8(Box8, {
|
|
727
|
+
children: /* @__PURE__ */ jsxDEV8(Text7, {
|
|
728
|
+
color: i === index ? colors.primary : undefined,
|
|
799
729
|
children: [
|
|
800
|
-
"
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
scrollOffset !== 1 ? "s" : ""
|
|
730
|
+
i === index ? "❯" : " ",
|
|
731
|
+
" ",
|
|
732
|
+
opt.label
|
|
804
733
|
]
|
|
805
|
-
}, undefined, true, undefined, this)
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
734
|
+
}, undefined, true, undefined, this)
|
|
735
|
+
}, opt.value, false, undefined, this))
|
|
736
|
+
}, undefined, false, undefined, this);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// src/lib/templates.ts
|
|
740
|
+
import { join as join3 } from "path";
|
|
741
|
+
import { existsSync as existsSync2 } from "fs";
|
|
742
|
+
var EXAMPLE_CONFIG_README = `# Example Stow Config Package
|
|
743
|
+
|
|
744
|
+
This is an example dotfiles package for use with GNU Stow.
|
|
745
|
+
|
|
746
|
+
## Structure
|
|
747
|
+
Files are organized to mirror your home directory:
|
|
748
|
+
- \`.config/example-app/config.toml\` -> \`~/.config/example-app/config.toml\`
|
|
749
|
+
- \`.example-app-rc\` -> \`~/.example-app-rc\`
|
|
750
|
+
|
|
751
|
+
## Usage
|
|
752
|
+
1. Place your dotfiles in this directory structure
|
|
753
|
+
2. Run \`formalconf\` and use Config Manager -> Stow
|
|
754
|
+
3. Symlinks will be created from your home directory
|
|
755
|
+
|
|
756
|
+
## Creating Your Own
|
|
757
|
+
1. Copy this directory and rename it (e.g., \`git\`, \`zsh\`, \`nvim\`)
|
|
758
|
+
2. Add your dotfiles mirroring your home directory structure
|
|
759
|
+
3. Stow the package to create symlinks
|
|
760
|
+
`;
|
|
761
|
+
var EXAMPLE_CONFIG_TOML = `# Example configuration file
|
|
762
|
+
# This will be symlinked to ~/.config/example-app/config.toml
|
|
763
|
+
|
|
764
|
+
[settings]
|
|
765
|
+
theme = "default"
|
|
766
|
+
auto_save = true
|
|
767
|
+
|
|
768
|
+
[keybindings]
|
|
769
|
+
quit = "q"
|
|
770
|
+
save = "ctrl+s"
|
|
771
|
+
`;
|
|
772
|
+
var EXAMPLE_RC = `# Example rc file
|
|
773
|
+
# This will be symlinked to ~/.example-app-rc
|
|
774
|
+
export EXAMPLE_VAR="hello"
|
|
775
|
+
`;
|
|
776
|
+
var EXAMPLE_THEME_YAML = `name: Example Theme
|
|
777
|
+
author: Your Name
|
|
778
|
+
description: A template theme for FormalConf
|
|
779
|
+
version: 1.0.0
|
|
780
|
+
|
|
781
|
+
colors:
|
|
782
|
+
primary: "#5eead4"
|
|
783
|
+
secondary: "#2dd4bf"
|
|
784
|
+
background: "#1a1a2e"
|
|
785
|
+
foreground: "#e4e4e7"
|
|
786
|
+
accent: "#06b6d4"
|
|
787
|
+
`;
|
|
788
|
+
var EXAMPLE_NEOVIM_LUA = `-- Neovim colorscheme configuration
|
|
789
|
+
-- This file is symlinked when the theme is applied
|
|
790
|
+
return {
|
|
791
|
+
{
|
|
792
|
+
"your-colorscheme/nvim",
|
|
793
|
+
name = "example-theme",
|
|
794
|
+
priority = 1000,
|
|
795
|
+
},
|
|
796
|
+
{
|
|
797
|
+
"LazyVim/LazyVim",
|
|
798
|
+
opts = {
|
|
799
|
+
colorscheme = "example-theme",
|
|
800
|
+
},
|
|
801
|
+
},
|
|
802
|
+
}
|
|
803
|
+
`;
|
|
804
|
+
var EXAMPLE_GHOSTTY_CONF = `# Ghostty terminal theme
|
|
805
|
+
# Add your terminal colors here
|
|
806
|
+
theme = example-theme
|
|
807
|
+
`;
|
|
808
|
+
var THEME_README = `# Example Theme
|
|
809
|
+
|
|
810
|
+
This is a template theme for FormalConf.
|
|
811
|
+
|
|
812
|
+
## Structure
|
|
813
|
+
- \`theme.yaml\` - Theme metadata and color definitions
|
|
814
|
+
- \`neovim.lua\` - Neovim colorscheme config
|
|
815
|
+
- \`ghostty.conf\` - Ghostty terminal theme
|
|
816
|
+
- \`backgrounds/\` - Wallpaper images (optional)
|
|
817
|
+
|
|
818
|
+
## Creating Your Own Theme
|
|
819
|
+
1. Copy this directory and rename it
|
|
820
|
+
2. Update \`theme.yaml\` with your theme info
|
|
821
|
+
3. Add config files for your applications
|
|
822
|
+
4. Files are symlinked to ~/.config/formalconf/current/theme/
|
|
823
|
+
`;
|
|
824
|
+
var BACKGROUNDS_README = `# Backgrounds
|
|
825
|
+
|
|
826
|
+
Place wallpaper images here:
|
|
827
|
+
- Supported formats: PNG, JPG
|
|
828
|
+
- These will be available at ~/.config/formalconf/current/backgrounds/
|
|
829
|
+
`;
|
|
830
|
+
var CONFIGS_README = `# Configs Directory
|
|
831
|
+
|
|
832
|
+
This directory contains your stow packages - collections of dotfiles
|
|
833
|
+
that are symlinked to your home directory.
|
|
834
|
+
|
|
835
|
+
## Creating a Config Package
|
|
836
|
+
|
|
837
|
+
1. Create a new directory: \`mkdir my-app\`
|
|
838
|
+
2. Add files mirroring your home directory structure
|
|
839
|
+
3. Use FormalConf to stow the package
|
|
840
|
+
|
|
841
|
+
## Example Structure
|
|
842
|
+
\`\`\`
|
|
843
|
+
my-app/
|
|
844
|
+
.config/
|
|
845
|
+
my-app/
|
|
846
|
+
config.toml -> ~/.config/my-app/config.toml
|
|
847
|
+
.my-app-rc -> ~/.my-app-rc
|
|
848
|
+
\`\`\`
|
|
849
|
+
|
|
850
|
+
## Commands
|
|
851
|
+
- Stow: Creates symlinks from home directory to these files
|
|
852
|
+
- Unstow: Removes the symlinks
|
|
853
|
+
- Status: Shows which packages are stowed
|
|
854
|
+
`;
|
|
855
|
+
var THEMES_README = `# Themes Directory
|
|
856
|
+
|
|
857
|
+
Themes contain application-specific config files that define colors and styling.
|
|
858
|
+
|
|
859
|
+
## Theme Structure
|
|
860
|
+
\`\`\`
|
|
861
|
+
my-theme/
|
|
862
|
+
theme.yaml # Theme metadata (required)
|
|
863
|
+
neovim.lua # Neovim colorscheme
|
|
864
|
+
ghostty.conf # Terminal theme
|
|
865
|
+
backgrounds/ # Wallpaper images
|
|
866
|
+
\`\`\`
|
|
867
|
+
|
|
868
|
+
## Applying Themes
|
|
869
|
+
Select a theme in FormalConf to symlink its files to:
|
|
870
|
+
\`~/.config/formalconf/current/theme/\`
|
|
871
|
+
|
|
872
|
+
Your applications should source files from this location.
|
|
873
|
+
`;
|
|
874
|
+
async function installExampleConfig() {
|
|
875
|
+
const dest = join3(CONFIGS_DIR, "example-config");
|
|
876
|
+
if (existsSync2(dest))
|
|
877
|
+
return;
|
|
878
|
+
await ensureDir2(dest);
|
|
879
|
+
await ensureDir2(join3(dest, ".config", "example-app"));
|
|
880
|
+
await writeFile(join3(dest, "README.md"), EXAMPLE_CONFIG_README);
|
|
881
|
+
await writeFile(join3(dest, ".config", "example-app", "config.toml"), EXAMPLE_CONFIG_TOML);
|
|
882
|
+
await writeFile(join3(dest, ".example-app-rc"), EXAMPLE_RC);
|
|
883
|
+
}
|
|
884
|
+
async function installExampleTheme() {
|
|
885
|
+
const dest = join3(THEMES_DIR, "example-theme");
|
|
886
|
+
if (existsSync2(dest))
|
|
887
|
+
return;
|
|
888
|
+
await ensureDir2(dest);
|
|
889
|
+
await ensureDir2(join3(dest, "backgrounds"));
|
|
890
|
+
await writeFile(join3(dest, "theme.yaml"), EXAMPLE_THEME_YAML);
|
|
891
|
+
await writeFile(join3(dest, "neovim.lua"), EXAMPLE_NEOVIM_LUA);
|
|
892
|
+
await writeFile(join3(dest, "ghostty.conf"), EXAMPLE_GHOSTTY_CONF);
|
|
893
|
+
await writeFile(join3(dest, "backgrounds", "README.md"), BACKGROUNDS_README);
|
|
894
|
+
await writeFile(join3(dest, "README.md"), THEME_README);
|
|
895
|
+
}
|
|
896
|
+
async function installReadmes() {
|
|
897
|
+
const configsReadme = join3(CONFIGS_DIR, "README.md");
|
|
898
|
+
const themesReadme = join3(THEMES_DIR, "README.md");
|
|
899
|
+
if (!existsSync2(configsReadme)) {
|
|
900
|
+
await writeFile(configsReadme, CONFIGS_README);
|
|
901
|
+
}
|
|
902
|
+
if (!existsSync2(themesReadme)) {
|
|
903
|
+
await writeFile(themesReadme, THEMES_README);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
var DEFAULT_PKG_CONFIG = {
|
|
907
|
+
config: {
|
|
908
|
+
purge: false,
|
|
909
|
+
purgeInteractive: true,
|
|
910
|
+
autoUpdate: true
|
|
911
|
+
},
|
|
912
|
+
taps: [],
|
|
913
|
+
packages: [],
|
|
914
|
+
casks: [],
|
|
915
|
+
mas: {}
|
|
916
|
+
};
|
|
917
|
+
async function installPkgConfig() {
|
|
918
|
+
if (existsSync2(PKG_CONFIG_PATH))
|
|
919
|
+
return;
|
|
920
|
+
await writeFile(PKG_CONFIG_PATH, JSON.stringify(DEFAULT_PKG_CONFIG, null, 2));
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// src/components/Onboarding.tsx
|
|
924
|
+
import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
|
|
925
|
+
function Onboarding({ onComplete }) {
|
|
926
|
+
const [step, setStep] = useState4("welcome");
|
|
927
|
+
const [createdItems, setCreatedItems] = useState4([]);
|
|
928
|
+
const addCreatedItem = (item) => {
|
|
929
|
+
setCreatedItems((prev) => [...prev, item]);
|
|
930
|
+
};
|
|
931
|
+
switch (step) {
|
|
932
|
+
case "welcome":
|
|
933
|
+
return /* @__PURE__ */ jsxDEV9(WelcomeStep, {
|
|
934
|
+
onNext: () => setStep("configs")
|
|
935
|
+
}, undefined, false, undefined, this);
|
|
936
|
+
case "configs":
|
|
937
|
+
return /* @__PURE__ */ jsxDEV9(ConfigsStep, {
|
|
938
|
+
onNext: () => setStep("themes"),
|
|
939
|
+
onCreate: async () => {
|
|
940
|
+
await installExampleConfig();
|
|
941
|
+
addCreatedItem("Example config package");
|
|
942
|
+
}
|
|
943
|
+
}, undefined, false, undefined, this);
|
|
944
|
+
case "themes":
|
|
945
|
+
return /* @__PURE__ */ jsxDEV9(ThemesStep, {
|
|
946
|
+
onNext: () => setStep("packages"),
|
|
947
|
+
onCreate: async () => {
|
|
948
|
+
await installExampleTheme();
|
|
949
|
+
addCreatedItem("Example theme");
|
|
950
|
+
}
|
|
951
|
+
}, undefined, false, undefined, this);
|
|
952
|
+
case "packages":
|
|
953
|
+
return /* @__PURE__ */ jsxDEV9(PackagesStep, {
|
|
954
|
+
onNext: async () => {
|
|
955
|
+
await installPkgConfig();
|
|
956
|
+
setStep("complete");
|
|
957
|
+
}
|
|
958
|
+
}, undefined, false, undefined, this);
|
|
959
|
+
case "complete":
|
|
960
|
+
return /* @__PURE__ */ jsxDEV9(CompleteStep, {
|
|
961
|
+
createdItems,
|
|
962
|
+
onComplete: async () => {
|
|
963
|
+
await installReadmes();
|
|
964
|
+
onComplete();
|
|
965
|
+
}
|
|
966
|
+
}, undefined, false, undefined, this);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
function WelcomeStep({ onNext }) {
|
|
970
|
+
useInput3((_, key) => {
|
|
971
|
+
if (key.return)
|
|
972
|
+
onNext();
|
|
973
|
+
});
|
|
974
|
+
return /* @__PURE__ */ jsxDEV9(Layout, {
|
|
975
|
+
breadcrumb: ["Setup"],
|
|
976
|
+
showFooter: false,
|
|
977
|
+
children: /* @__PURE__ */ jsxDEV9(Panel, {
|
|
978
|
+
title: "Welcome to FormalConf",
|
|
979
|
+
children: /* @__PURE__ */ jsxDEV9(Box9, {
|
|
980
|
+
flexDirection: "column",
|
|
981
|
+
gap: 1,
|
|
816
982
|
children: [
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
983
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
984
|
+
children: "FormalConf helps you manage your dotfiles and system configuration."
|
|
985
|
+
}, undefined, false, undefined, this),
|
|
986
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
987
|
+
dimColor: true,
|
|
988
|
+
children: "This setup will walk you through the basics and optionally create example files to get you started."
|
|
989
|
+
}, undefined, false, undefined, this),
|
|
990
|
+
/* @__PURE__ */ jsxDEV9(Box9, {
|
|
991
|
+
marginTop: 1,
|
|
992
|
+
children: /* @__PURE__ */ jsxDEV9(Text8, {
|
|
993
|
+
color: colors.primary,
|
|
994
|
+
children: "Press Enter to continue..."
|
|
995
|
+
}, undefined, false, undefined, this)
|
|
996
|
+
}, undefined, false, undefined, this)
|
|
821
997
|
]
|
|
822
|
-
}, undefined, true, undefined, this)
|
|
823
|
-
|
|
824
|
-
|
|
998
|
+
}, undefined, true, undefined, this)
|
|
999
|
+
}, undefined, false, undefined, this)
|
|
1000
|
+
}, undefined, false, undefined, this);
|
|
1001
|
+
}
|
|
1002
|
+
function ConfigsStep({
|
|
1003
|
+
onNext,
|
|
1004
|
+
onCreate
|
|
1005
|
+
}) {
|
|
1006
|
+
const [isCreating, setIsCreating] = useState4(false);
|
|
1007
|
+
const handleSelect = async (value) => {
|
|
1008
|
+
if (value === "create") {
|
|
1009
|
+
setIsCreating(true);
|
|
1010
|
+
await onCreate();
|
|
1011
|
+
}
|
|
1012
|
+
onNext();
|
|
1013
|
+
};
|
|
1014
|
+
return /* @__PURE__ */ jsxDEV9(Layout, {
|
|
1015
|
+
breadcrumb: ["Setup", "Config Packages"],
|
|
1016
|
+
showFooter: false,
|
|
1017
|
+
children: /* @__PURE__ */ jsxDEV9(Panel, {
|
|
1018
|
+
title: "Config Packages",
|
|
1019
|
+
children: /* @__PURE__ */ jsxDEV9(Box9, {
|
|
1020
|
+
flexDirection: "column",
|
|
1021
|
+
gap: 1,
|
|
825
1022
|
children: [
|
|
826
|
-
|
|
827
|
-
|
|
1023
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1024
|
+
children: "Config packages are directories containing your dotfiles."
|
|
1025
|
+
}, undefined, false, undefined, this),
|
|
1026
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1027
|
+
dimColor: true,
|
|
1028
|
+
children: "FormalConf uses GNU Stow to create symlinks from your home directory."
|
|
1029
|
+
}, undefined, false, undefined, this),
|
|
1030
|
+
/* @__PURE__ */ jsxDEV9(Box9, {
|
|
1031
|
+
marginTop: 1,
|
|
1032
|
+
flexDirection: "column",
|
|
1033
|
+
children: [
|
|
1034
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1035
|
+
dimColor: true,
|
|
1036
|
+
children: "Example structure:"
|
|
1037
|
+
}, undefined, false, undefined, this),
|
|
1038
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1039
|
+
children: " my-config/"
|
|
1040
|
+
}, undefined, false, undefined, this),
|
|
1041
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1042
|
+
children: " .config/"
|
|
1043
|
+
}, undefined, false, undefined, this),
|
|
1044
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1045
|
+
children: " app/config.toml"
|
|
1046
|
+
}, undefined, false, undefined, this)
|
|
1047
|
+
]
|
|
1048
|
+
}, undefined, true, undefined, this),
|
|
1049
|
+
/* @__PURE__ */ jsxDEV9(Box9, {
|
|
1050
|
+
marginTop: 1,
|
|
1051
|
+
children: /* @__PURE__ */ jsxDEV9(VimSelect, {
|
|
1052
|
+
options: [
|
|
1053
|
+
{ label: "Create example config package", value: "create" },
|
|
1054
|
+
{ label: "Skip", value: "skip" }
|
|
1055
|
+
],
|
|
1056
|
+
onChange: handleSelect,
|
|
1057
|
+
isDisabled: isCreating
|
|
1058
|
+
}, undefined, false, undefined, this)
|
|
1059
|
+
}, undefined, false, undefined, this)
|
|
828
1060
|
]
|
|
829
1061
|
}, undefined, true, undefined, this)
|
|
830
|
-
|
|
831
|
-
}, undefined,
|
|
1062
|
+
}, undefined, false, undefined, this)
|
|
1063
|
+
}, undefined, false, undefined, this);
|
|
832
1064
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
import { jsxDEV as jsxDEV11 } from "react/jsx-dev-runtime";
|
|
837
|
-
function PromptInput({
|
|
838
|
-
question,
|
|
839
|
-
options = ["y", "n"],
|
|
840
|
-
onAnswer
|
|
1065
|
+
function ThemesStep({
|
|
1066
|
+
onNext,
|
|
1067
|
+
onCreate
|
|
841
1068
|
}) {
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
if (
|
|
845
|
-
|
|
1069
|
+
const [isCreating, setIsCreating] = useState4(false);
|
|
1070
|
+
const handleSelect = async (value) => {
|
|
1071
|
+
if (value === "create") {
|
|
1072
|
+
setIsCreating(true);
|
|
1073
|
+
await onCreate();
|
|
1074
|
+
}
|
|
1075
|
+
onNext();
|
|
1076
|
+
};
|
|
1077
|
+
return /* @__PURE__ */ jsxDEV9(Layout, {
|
|
1078
|
+
breadcrumb: ["Setup", "Themes"],
|
|
1079
|
+
showFooter: false,
|
|
1080
|
+
children: /* @__PURE__ */ jsxDEV9(Panel, {
|
|
1081
|
+
title: "Themes",
|
|
1082
|
+
children: /* @__PURE__ */ jsxDEV9(Box9, {
|
|
1083
|
+
flexDirection: "column",
|
|
1084
|
+
gap: 1,
|
|
1085
|
+
children: [
|
|
1086
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1087
|
+
children: "Themes contain application configs for colors and styling."
|
|
1088
|
+
}, undefined, false, undefined, this),
|
|
1089
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1090
|
+
dimColor: true,
|
|
1091
|
+
children: "When applied, theme files are symlinked to a central location your apps can source from."
|
|
1092
|
+
}, undefined, false, undefined, this),
|
|
1093
|
+
/* @__PURE__ */ jsxDEV9(Box9, {
|
|
1094
|
+
marginTop: 1,
|
|
1095
|
+
flexDirection: "column",
|
|
1096
|
+
children: [
|
|
1097
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1098
|
+
dimColor: true,
|
|
1099
|
+
children: "Theme structure:"
|
|
1100
|
+
}, undefined, false, undefined, this),
|
|
1101
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1102
|
+
children: " my-theme/"
|
|
1103
|
+
}, undefined, false, undefined, this),
|
|
1104
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1105
|
+
children: " theme.yaml"
|
|
1106
|
+
}, undefined, false, undefined, this),
|
|
1107
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1108
|
+
children: " neovim.lua"
|
|
1109
|
+
}, undefined, false, undefined, this),
|
|
1110
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1111
|
+
children: " backgrounds/"
|
|
1112
|
+
}, undefined, false, undefined, this)
|
|
1113
|
+
]
|
|
1114
|
+
}, undefined, true, undefined, this),
|
|
1115
|
+
/* @__PURE__ */ jsxDEV9(Box9, {
|
|
1116
|
+
marginTop: 1,
|
|
1117
|
+
children: /* @__PURE__ */ jsxDEV9(VimSelect, {
|
|
1118
|
+
options: [
|
|
1119
|
+
{ label: "Create example theme", value: "create" },
|
|
1120
|
+
{ label: "Skip", value: "skip" }
|
|
1121
|
+
],
|
|
1122
|
+
onChange: handleSelect,
|
|
1123
|
+
isDisabled: isCreating
|
|
1124
|
+
}, undefined, false, undefined, this)
|
|
1125
|
+
}, undefined, false, undefined, this)
|
|
1126
|
+
]
|
|
1127
|
+
}, undefined, true, undefined, this)
|
|
1128
|
+
}, undefined, false, undefined, this)
|
|
1129
|
+
}, undefined, false, undefined, this);
|
|
1130
|
+
}
|
|
1131
|
+
function PackagesStep({ onNext }) {
|
|
1132
|
+
const [isCreating, setIsCreating] = useState4(false);
|
|
1133
|
+
useInput3(async (_, key) => {
|
|
1134
|
+
if (key.return && !isCreating) {
|
|
1135
|
+
setIsCreating(true);
|
|
1136
|
+
await onNext();
|
|
846
1137
|
}
|
|
847
1138
|
});
|
|
848
|
-
return /* @__PURE__ */
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
"
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
1139
|
+
return /* @__PURE__ */ jsxDEV9(Layout, {
|
|
1140
|
+
breadcrumb: ["Setup", "Package Sync"],
|
|
1141
|
+
showFooter: false,
|
|
1142
|
+
children: /* @__PURE__ */ jsxDEV9(Panel, {
|
|
1143
|
+
title: "Package Sync",
|
|
1144
|
+
children: /* @__PURE__ */ jsxDEV9(Box9, {
|
|
1145
|
+
flexDirection: "column",
|
|
1146
|
+
gap: 1,
|
|
1147
|
+
children: [
|
|
1148
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1149
|
+
children: "FormalConf can sync your Homebrew packages from a config file."
|
|
1150
|
+
}, undefined, false, undefined, this),
|
|
1151
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1152
|
+
dimColor: true,
|
|
1153
|
+
children: "Edit ~/.config/formalconf/pkg-config.json to define your packages, then run Package Sync from the main menu."
|
|
1154
|
+
}, undefined, false, undefined, this),
|
|
1155
|
+
/* @__PURE__ */ jsxDEV9(Box9, {
|
|
1156
|
+
marginTop: 1,
|
|
1157
|
+
children: /* @__PURE__ */ jsxDEV9(Text8, {
|
|
1158
|
+
color: colors.primary,
|
|
1159
|
+
children: "Press Enter to continue..."
|
|
1160
|
+
}, undefined, false, undefined, this)
|
|
1161
|
+
}, undefined, false, undefined, this)
|
|
1162
|
+
]
|
|
1163
|
+
}, undefined, true, undefined, this)
|
|
1164
|
+
}, undefined, false, undefined, this)
|
|
1165
|
+
}, undefined, false, undefined, this);
|
|
1166
|
+
}
|
|
1167
|
+
function CompleteStep({
|
|
1168
|
+
createdItems,
|
|
1169
|
+
onComplete
|
|
1170
|
+
}) {
|
|
1171
|
+
const [isFinishing, setIsFinishing] = useState4(false);
|
|
1172
|
+
useInput3(async (_, key) => {
|
|
1173
|
+
if (key.return && !isFinishing) {
|
|
1174
|
+
setIsFinishing(true);
|
|
1175
|
+
await onComplete();
|
|
1176
|
+
}
|
|
1177
|
+
});
|
|
1178
|
+
return /* @__PURE__ */ jsxDEV9(Layout, {
|
|
1179
|
+
breadcrumb: ["Setup", "Complete"],
|
|
1180
|
+
showFooter: false,
|
|
1181
|
+
children: /* @__PURE__ */ jsxDEV9(Panel, {
|
|
1182
|
+
title: "Setup Complete",
|
|
1183
|
+
children: /* @__PURE__ */ jsxDEV9(Box9, {
|
|
1184
|
+
flexDirection: "column",
|
|
1185
|
+
gap: 1,
|
|
1186
|
+
children: [
|
|
1187
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1188
|
+
color: colors.success,
|
|
1189
|
+
children: "You're all set!"
|
|
1190
|
+
}, undefined, false, undefined, this),
|
|
1191
|
+
createdItems.length > 0 && /* @__PURE__ */ jsxDEV9(Box9, {
|
|
1192
|
+
flexDirection: "column",
|
|
1193
|
+
marginTop: 1,
|
|
1194
|
+
children: [
|
|
1195
|
+
/* @__PURE__ */ jsxDEV9(Text8, {
|
|
1196
|
+
dimColor: true,
|
|
1197
|
+
children: "Created:"
|
|
1198
|
+
}, undefined, false, undefined, this),
|
|
1199
|
+
createdItems.map((item, i) => /* @__PURE__ */ jsxDEV9(Text8, {
|
|
1200
|
+
children: [
|
|
1201
|
+
" - ",
|
|
1202
|
+
item
|
|
1203
|
+
]
|
|
1204
|
+
}, i, true, undefined, this))
|
|
1205
|
+
]
|
|
1206
|
+
}, undefined, true, undefined, this),
|
|
1207
|
+
/* @__PURE__ */ jsxDEV9(Box9, {
|
|
1208
|
+
marginTop: 1,
|
|
1209
|
+
children: /* @__PURE__ */ jsxDEV9(Text8, {
|
|
1210
|
+
dimColor: true,
|
|
1211
|
+
children: "README files have been added to help you get started."
|
|
1212
|
+
}, undefined, false, undefined, this)
|
|
1213
|
+
}, undefined, false, undefined, this),
|
|
1214
|
+
/* @__PURE__ */ jsxDEV9(Box9, {
|
|
1215
|
+
marginTop: 1,
|
|
1216
|
+
children: /* @__PURE__ */ jsxDEV9(Text8, {
|
|
1217
|
+
color: colors.primary,
|
|
1218
|
+
children: "Press Enter to start..."
|
|
1219
|
+
}, undefined, false, undefined, this)
|
|
1220
|
+
}, undefined, false, undefined, this)
|
|
1221
|
+
]
|
|
1222
|
+
}, undefined, true, undefined, this)
|
|
1223
|
+
}, undefined, false, undefined, this)
|
|
871
1224
|
}, undefined, false, undefined, this);
|
|
872
1225
|
}
|
|
873
1226
|
|
|
874
|
-
// src/
|
|
875
|
-
import {
|
|
876
|
-
import {
|
|
877
|
-
function
|
|
878
|
-
const
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
if (value) {
|
|
893
|
-
result[key] = value.replace(/^["']|["']$/g, "");
|
|
894
|
-
} else {
|
|
895
|
-
currentKey = key;
|
|
896
|
-
currentSection = {};
|
|
897
|
-
result[key] = currentSection;
|
|
1227
|
+
// src/components/menus/MainMenu.tsx
|
|
1228
|
+
import { useApp } from "ink";
|
|
1229
|
+
import { jsxDEV as jsxDEV10 } from "react/jsx-dev-runtime";
|
|
1230
|
+
function MainMenu({ onSelect }) {
|
|
1231
|
+
const { exit } = useApp();
|
|
1232
|
+
return /* @__PURE__ */ jsxDEV10(Panel, {
|
|
1233
|
+
title: "Main Menu",
|
|
1234
|
+
children: /* @__PURE__ */ jsxDEV10(VimSelect, {
|
|
1235
|
+
options: [
|
|
1236
|
+
{ label: "Config Manager", value: "config" },
|
|
1237
|
+
{ label: "Package Sync", value: "packages" },
|
|
1238
|
+
{ label: "Set Theme", value: "themes" },
|
|
1239
|
+
{ label: "Exit", value: "exit" }
|
|
1240
|
+
],
|
|
1241
|
+
onChange: (value) => {
|
|
1242
|
+
if (value === "exit") {
|
|
1243
|
+
exit();
|
|
1244
|
+
return;
|
|
898
1245
|
}
|
|
899
|
-
|
|
900
|
-
currentSection[key] = value.replace(/^["']|["']$/g, "");
|
|
1246
|
+
onSelect(value);
|
|
901
1247
|
}
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
return result;
|
|
1248
|
+
}, undefined, false, undefined, this)
|
|
1249
|
+
}, undefined, false, undefined, this);
|
|
905
1250
|
}
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1251
|
+
|
|
1252
|
+
// src/components/CommandOutput.tsx
|
|
1253
|
+
import { Box as Box10, Text as Text9, useInput as useInput4 } from "ink";
|
|
1254
|
+
import { jsxDEV as jsxDEV11 } from "react/jsx-dev-runtime";
|
|
1255
|
+
function CommandOutput({
|
|
1256
|
+
title,
|
|
1257
|
+
output,
|
|
1258
|
+
success = true,
|
|
1259
|
+
onDismiss
|
|
1260
|
+
}) {
|
|
1261
|
+
useInput4(() => {
|
|
1262
|
+
onDismiss();
|
|
1263
|
+
});
|
|
1264
|
+
return /* @__PURE__ */ jsxDEV11(Panel, {
|
|
1265
|
+
title,
|
|
1266
|
+
borderColor: success ? colors.success : colors.error,
|
|
1267
|
+
children: [
|
|
1268
|
+
output && /* @__PURE__ */ jsxDEV11(Box10, {
|
|
1269
|
+
flexDirection: "column",
|
|
1270
|
+
marginBottom: 1,
|
|
1271
|
+
children: /* @__PURE__ */ jsxDEV11(Text9, {
|
|
1272
|
+
children: output
|
|
1273
|
+
}, undefined, false, undefined, this)
|
|
1274
|
+
}, undefined, false, undefined, this),
|
|
1275
|
+
/* @__PURE__ */ jsxDEV11(Text9, {
|
|
1276
|
+
color: success ? colors.success : colors.error,
|
|
1277
|
+
children: success ? "Done" : "Failed"
|
|
1278
|
+
}, undefined, false, undefined, this),
|
|
1279
|
+
/* @__PURE__ */ jsxDEV11(Text9, {
|
|
1280
|
+
dimColor: true,
|
|
1281
|
+
children: "Press any key to continue..."
|
|
1282
|
+
}, undefined, false, undefined, this)
|
|
1283
|
+
]
|
|
1284
|
+
}, undefined, true, undefined, this);
|
|
925
1285
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
1286
|
+
|
|
1287
|
+
// src/components/LoadingPanel.tsx
|
|
1288
|
+
import { Spinner } from "@inkjs/ui";
|
|
1289
|
+
import { jsxDEV as jsxDEV12 } from "react/jsx-dev-runtime";
|
|
1290
|
+
function LoadingPanel({ title, label = "Processing..." }) {
|
|
1291
|
+
return /* @__PURE__ */ jsxDEV12(Panel, {
|
|
1292
|
+
title,
|
|
1293
|
+
children: /* @__PURE__ */ jsxDEV12(Spinner, {
|
|
1294
|
+
label
|
|
1295
|
+
}, undefined, false, undefined, this)
|
|
1296
|
+
}, undefined, false, undefined, this);
|
|
933
1297
|
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1298
|
+
|
|
1299
|
+
// src/hooks/useMenuAction.ts
|
|
1300
|
+
import { useState as useState5, useCallback } from "react";
|
|
1301
|
+
function useMenuAction() {
|
|
1302
|
+
const [state, setState] = useState5("menu");
|
|
1303
|
+
const [output, setOutput] = useState5("");
|
|
1304
|
+
const [success, setSuccess] = useState5(true);
|
|
1305
|
+
const execute = useCallback(async (action) => {
|
|
1306
|
+
setState("running");
|
|
1307
|
+
const result = await action();
|
|
1308
|
+
setOutput(result.output);
|
|
1309
|
+
setSuccess(result.success);
|
|
1310
|
+
setState("result");
|
|
1311
|
+
}, []);
|
|
1312
|
+
const reset = useCallback(() => {
|
|
1313
|
+
setState("menu");
|
|
1314
|
+
}, []);
|
|
937
1315
|
return {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1316
|
+
state,
|
|
1317
|
+
output,
|
|
1318
|
+
success,
|
|
1319
|
+
isRunning: state === "running",
|
|
1320
|
+
isResult: state === "result",
|
|
1321
|
+
execute,
|
|
1322
|
+
reset
|
|
945
1323
|
};
|
|
946
1324
|
}
|
|
947
1325
|
|
|
1326
|
+
// src/hooks/useBackNavigation.ts
|
|
1327
|
+
import { useInput as useInput5 } from "ink";
|
|
1328
|
+
function useBackNavigation({
|
|
1329
|
+
enabled = true,
|
|
1330
|
+
onBack
|
|
1331
|
+
}) {
|
|
1332
|
+
useInput5((input, key) => {
|
|
1333
|
+
if (enabled && (key.escape || key.leftArrow || input === "h")) {
|
|
1334
|
+
onBack();
|
|
1335
|
+
}
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
|
|
948
1339
|
// src/cli/config-manager.ts
|
|
949
1340
|
import { parseArgs } from "util";
|
|
950
|
-
import { readdirSync as
|
|
1341
|
+
import { readdirSync as readdirSync2, existsSync as existsSync3, lstatSync as lstatSync2, readlinkSync as readlinkSync2 } from "fs";
|
|
951
1342
|
var colors2 = {
|
|
952
1343
|
red: "\x1B[0;31m",
|
|
953
1344
|
green: "\x1B[0;32m",
|
|
@@ -963,7 +1354,7 @@ async function checkStow() {
|
|
|
963
1354
|
}
|
|
964
1355
|
}
|
|
965
1356
|
function listPackages() {
|
|
966
|
-
const entries =
|
|
1357
|
+
const entries = readdirSync2(CONFIGS_DIR, { withFileTypes: true });
|
|
967
1358
|
return entries.filter((e) => e.isDirectory()).map((e) => ({
|
|
968
1359
|
name: e.name,
|
|
969
1360
|
path: `${CONFIGS_DIR}/${e.name}`,
|
|
@@ -974,7 +1365,7 @@ function checkPackageStowed(packageName) {
|
|
|
974
1365
|
const packageDir = `${CONFIGS_DIR}/${packageName}`;
|
|
975
1366
|
if (!existsSync3(packageDir))
|
|
976
1367
|
return false;
|
|
977
|
-
const entries =
|
|
1368
|
+
const entries = readdirSync2(packageDir, { withFileTypes: true });
|
|
978
1369
|
for (const entry of entries) {
|
|
979
1370
|
const targetPath = `${HOME_DIR}/${entry.name}`;
|
|
980
1371
|
if (!existsSync3(targetPath))
|
|
@@ -1237,9 +1628,177 @@ ${colors2.cyan}Available packages:${colors2.reset}`);
|
|
|
1237
1628
|
break;
|
|
1238
1629
|
}
|
|
1239
1630
|
}
|
|
1240
|
-
var isMainModule = process.argv[1]?.includes("config-manager");
|
|
1241
|
-
if (isMainModule) {
|
|
1242
|
-
main().catch(console.error);
|
|
1631
|
+
var isMainModule = process.argv[1]?.includes("config-manager");
|
|
1632
|
+
if (isMainModule) {
|
|
1633
|
+
main().catch(console.error);
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
// src/components/menus/ConfigMenu.tsx
|
|
1637
|
+
import { jsxDEV as jsxDEV13 } from "react/jsx-dev-runtime";
|
|
1638
|
+
function ConfigMenu({ onBack }) {
|
|
1639
|
+
const { state, output, success, isRunning, isResult, execute, reset } = useMenuAction();
|
|
1640
|
+
useBackNavigation({ enabled: state === "menu", onBack });
|
|
1641
|
+
const handleAction = async (action) => {
|
|
1642
|
+
if (action === "back") {
|
|
1643
|
+
onBack();
|
|
1644
|
+
return;
|
|
1645
|
+
}
|
|
1646
|
+
await execute(() => runConfigManager([action]));
|
|
1647
|
+
};
|
|
1648
|
+
if (isRunning) {
|
|
1649
|
+
return /* @__PURE__ */ jsxDEV13(LoadingPanel, {
|
|
1650
|
+
title: "Config Manager"
|
|
1651
|
+
}, undefined, false, undefined, this);
|
|
1652
|
+
}
|
|
1653
|
+
if (isResult) {
|
|
1654
|
+
return /* @__PURE__ */ jsxDEV13(CommandOutput, {
|
|
1655
|
+
title: "Config Manager",
|
|
1656
|
+
output,
|
|
1657
|
+
success,
|
|
1658
|
+
onDismiss: reset
|
|
1659
|
+
}, undefined, false, undefined, this);
|
|
1660
|
+
}
|
|
1661
|
+
return /* @__PURE__ */ jsxDEV13(Panel, {
|
|
1662
|
+
title: "Config Manager",
|
|
1663
|
+
children: /* @__PURE__ */ jsxDEV13(VimSelect, {
|
|
1664
|
+
options: [
|
|
1665
|
+
{ label: "Stow all packages", value: "stow-all" },
|
|
1666
|
+
{ label: "Unstow all packages", value: "unstow-all" },
|
|
1667
|
+
{ label: "Check status", value: "status" },
|
|
1668
|
+
{ label: "List packages", value: "list" },
|
|
1669
|
+
{ label: "Back", value: "back" }
|
|
1670
|
+
],
|
|
1671
|
+
onChange: handleAction
|
|
1672
|
+
}, undefined, false, undefined, this)
|
|
1673
|
+
}, undefined, false, undefined, this);
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
// src/components/menus/PackageMenu.tsx
|
|
1677
|
+
import { useState as useState7, useCallback as useCallback2, useMemo as useMemo2, useRef } from "react";
|
|
1678
|
+
import { Box as Box13, Text as Text12, useInput as useInput8 } from "ink";
|
|
1679
|
+
|
|
1680
|
+
// src/components/ScrollableLog.tsx
|
|
1681
|
+
import { useState as useState6, useEffect as useEffect3, useMemo } from "react";
|
|
1682
|
+
import { Box as Box11, Text as Text10, useInput as useInput6 } from "ink";
|
|
1683
|
+
import { jsxDEV as jsxDEV14 } from "react/jsx-dev-runtime";
|
|
1684
|
+
function ScrollableLog({
|
|
1685
|
+
lines,
|
|
1686
|
+
maxHeight,
|
|
1687
|
+
autoScroll = true,
|
|
1688
|
+
showScrollHint = true
|
|
1689
|
+
}) {
|
|
1690
|
+
const { rows } = useTerminalSize();
|
|
1691
|
+
const visibleLines = maxHeight || Math.max(5, rows - 12);
|
|
1692
|
+
const [scrollOffset, setScrollOffset] = useState6(0);
|
|
1693
|
+
const [isAutoScrolling, setIsAutoScrolling] = useState6(autoScroll);
|
|
1694
|
+
const totalLines = lines.length;
|
|
1695
|
+
const maxOffset = Math.max(0, totalLines - visibleLines);
|
|
1696
|
+
useEffect3(() => {
|
|
1697
|
+
if (isAutoScrolling) {
|
|
1698
|
+
setScrollOffset(maxOffset);
|
|
1699
|
+
}
|
|
1700
|
+
}, [totalLines, maxOffset, isAutoScrolling]);
|
|
1701
|
+
useInput6((input, key) => {
|
|
1702
|
+
if (key.downArrow || input === "j") {
|
|
1703
|
+
setIsAutoScrolling(false);
|
|
1704
|
+
setScrollOffset((prev) => Math.min(prev + 1, maxOffset));
|
|
1705
|
+
}
|
|
1706
|
+
if (key.upArrow || input === "k") {
|
|
1707
|
+
setIsAutoScrolling(false);
|
|
1708
|
+
setScrollOffset((prev) => Math.max(prev - 1, 0));
|
|
1709
|
+
}
|
|
1710
|
+
if (input === "G") {
|
|
1711
|
+
setIsAutoScrolling(true);
|
|
1712
|
+
setScrollOffset(maxOffset);
|
|
1713
|
+
}
|
|
1714
|
+
if (input === "g") {
|
|
1715
|
+
setIsAutoScrolling(false);
|
|
1716
|
+
setScrollOffset(0);
|
|
1717
|
+
}
|
|
1718
|
+
});
|
|
1719
|
+
const visibleContent = useMemo(() => {
|
|
1720
|
+
return lines.slice(scrollOffset, scrollOffset + visibleLines);
|
|
1721
|
+
}, [lines, scrollOffset, visibleLines]);
|
|
1722
|
+
const showScrollUp = scrollOffset > 0;
|
|
1723
|
+
const showScrollDown = scrollOffset < maxOffset;
|
|
1724
|
+
return /* @__PURE__ */ jsxDEV14(Box11, {
|
|
1725
|
+
flexDirection: "column",
|
|
1726
|
+
children: [
|
|
1727
|
+
showScrollHint && showScrollUp && /* @__PURE__ */ jsxDEV14(Text10, {
|
|
1728
|
+
dimColor: true,
|
|
1729
|
+
children: [
|
|
1730
|
+
" ↑ ",
|
|
1731
|
+
scrollOffset,
|
|
1732
|
+
" more line",
|
|
1733
|
+
scrollOffset !== 1 ? "s" : ""
|
|
1734
|
+
]
|
|
1735
|
+
}, undefined, true, undefined, this),
|
|
1736
|
+
/* @__PURE__ */ jsxDEV14(Box11, {
|
|
1737
|
+
flexDirection: "column",
|
|
1738
|
+
height: visibleLines,
|
|
1739
|
+
overflow: "hidden",
|
|
1740
|
+
children: visibleContent.map((line, i) => /* @__PURE__ */ jsxDEV14(Text10, {
|
|
1741
|
+
children: line
|
|
1742
|
+
}, scrollOffset + i, false, undefined, this))
|
|
1743
|
+
}, undefined, false, undefined, this),
|
|
1744
|
+
showScrollHint && showScrollDown && /* @__PURE__ */ jsxDEV14(Text10, {
|
|
1745
|
+
dimColor: true,
|
|
1746
|
+
children: [
|
|
1747
|
+
" ↓ ",
|
|
1748
|
+
maxOffset - scrollOffset,
|
|
1749
|
+
" more line",
|
|
1750
|
+
maxOffset - scrollOffset !== 1 ? "s" : ""
|
|
1751
|
+
]
|
|
1752
|
+
}, undefined, true, undefined, this),
|
|
1753
|
+
showScrollHint && totalLines > visibleLines && /* @__PURE__ */ jsxDEV14(Text10, {
|
|
1754
|
+
dimColor: true,
|
|
1755
|
+
children: [
|
|
1756
|
+
"j/k scroll • g top • G bottom ",
|
|
1757
|
+
isAutoScrolling ? "(auto-scroll)" : ""
|
|
1758
|
+
]
|
|
1759
|
+
}, undefined, true, undefined, this)
|
|
1760
|
+
]
|
|
1761
|
+
}, undefined, true, undefined, this);
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
// src/components/PromptInput.tsx
|
|
1765
|
+
import { Box as Box12, Text as Text11, useInput as useInput7 } from "ink";
|
|
1766
|
+
import { jsxDEV as jsxDEV15 } from "react/jsx-dev-runtime";
|
|
1767
|
+
function PromptInput({
|
|
1768
|
+
question,
|
|
1769
|
+
options = ["y", "n"],
|
|
1770
|
+
onAnswer
|
|
1771
|
+
}) {
|
|
1772
|
+
useInput7((input) => {
|
|
1773
|
+
const lower = input.toLowerCase();
|
|
1774
|
+
if (options.includes(lower)) {
|
|
1775
|
+
onAnswer(lower);
|
|
1776
|
+
}
|
|
1777
|
+
});
|
|
1778
|
+
return /* @__PURE__ */ jsxDEV15(Box12, {
|
|
1779
|
+
marginTop: 1,
|
|
1780
|
+
borderStyle: "single",
|
|
1781
|
+
borderColor: colors.accent,
|
|
1782
|
+
paddingX: 1,
|
|
1783
|
+
children: /* @__PURE__ */ jsxDEV15(Text11, {
|
|
1784
|
+
children: [
|
|
1785
|
+
question,
|
|
1786
|
+
" ",
|
|
1787
|
+
/* @__PURE__ */ jsxDEV15(Text11, {
|
|
1788
|
+
color: colors.accent,
|
|
1789
|
+
children: [
|
|
1790
|
+
"[",
|
|
1791
|
+
options.join("/"),
|
|
1792
|
+
"]"
|
|
1793
|
+
]
|
|
1794
|
+
}, undefined, true, undefined, this),
|
|
1795
|
+
/* @__PURE__ */ jsxDEV15(Text11, {
|
|
1796
|
+
dimColor: true,
|
|
1797
|
+
children: ": "
|
|
1798
|
+
}, undefined, false, undefined, this)
|
|
1799
|
+
]
|
|
1800
|
+
}, undefined, true, undefined, this)
|
|
1801
|
+
}, undefined, false, undefined, this);
|
|
1243
1802
|
}
|
|
1244
1803
|
|
|
1245
1804
|
// src/cli/pkg-sync.ts
|
|
@@ -2025,287 +2584,46 @@ async function main3() {
|
|
|
2025
2584
|
case "update": {
|
|
2026
2585
|
console.log(`${colors4.cyan}Updating lockfile...${colors4.reset}`);
|
|
2027
2586
|
const lock = await updateLockfile();
|
|
2028
|
-
const total = Object.keys(lock.formulas).length + Object.keys(lock.casks).length;
|
|
2029
|
-
console.log(`${colors4.green}Lockfile updated with ${total} packages.${colors4.reset}`);
|
|
2030
|
-
break;
|
|
2031
|
-
}
|
|
2032
|
-
case "status":
|
|
2033
|
-
await showStatus2();
|
|
2034
|
-
break;
|
|
2035
|
-
case "reset": {
|
|
2036
|
-
console.log(`${colors4.cyan}Regenerating lockfile...${colors4.reset}`);
|
|
2037
|
-
const lock = await generateLockfile();
|
|
2038
|
-
await savePkgLock(lock);
|
|
2039
|
-
const total = Object.keys(lock.formulas).length + Object.keys(lock.casks).length;
|
|
2040
|
-
console.log(`${colors4.green}Lockfile regenerated with ${total} packages.${colors4.reset}`);
|
|
2041
|
-
break;
|
|
2042
|
-
}
|
|
2043
|
-
case "show":
|
|
2044
|
-
await showLockfile();
|
|
2045
|
-
break;
|
|
2046
|
-
default:
|
|
2047
|
-
console.error(`${colors4.red}Unknown command: ${command}${colors4.reset}`);
|
|
2048
|
-
printUsage3();
|
|
2049
|
-
process.exit(1);
|
|
2050
|
-
}
|
|
2051
|
-
}
|
|
2052
|
-
var isMainModule3 = process.argv[1]?.includes("pkg-lock");
|
|
2053
|
-
if (isMainModule3) {
|
|
2054
|
-
main3().catch(console.error);
|
|
2055
|
-
}
|
|
2056
|
-
|
|
2057
|
-
// src/cli/set-theme.ts
|
|
2058
|
-
import { parseArgs as parseArgs4 } from "util";
|
|
2059
|
-
import { readdirSync as readdirSync4, existsSync as existsSync5, rmSync, symlinkSync, unlinkSync } from "fs";
|
|
2060
|
-
import { join as join4 } from "path";
|
|
2061
|
-
var colors5 = {
|
|
2062
|
-
red: "\x1B[0;31m",
|
|
2063
|
-
green: "\x1B[0;32m",
|
|
2064
|
-
blue: "\x1B[0;34m",
|
|
2065
|
-
yellow: "\x1B[1;33m",
|
|
2066
|
-
cyan: "\x1B[0;36m",
|
|
2067
|
-
dim: "\x1B[2m",
|
|
2068
|
-
reset: "\x1B[0m"
|
|
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);
|
|
2082
|
-
}
|
|
2083
|
-
}
|
|
2084
|
-
return themes;
|
|
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
|
-
}
|
|
2096
|
-
}
|
|
2097
|
-
}
|
|
2098
|
-
}
|
|
2099
|
-
function createSymlink(source, target) {
|
|
2100
|
-
if (existsSync5(target)) {
|
|
2101
|
-
unlinkSync(target);
|
|
2102
|
-
}
|
|
2103
|
-
symlinkSync(source, target);
|
|
2104
|
-
}
|
|
2105
|
-
async function applyTheme(themeName) {
|
|
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();
|
|
2587
|
+
const total = Object.keys(lock.formulas).length + Object.keys(lock.casks).length;
|
|
2588
|
+
console.log(`${colors4.green}Lockfile updated with ${total} packages.${colors4.reset}`);
|
|
2589
|
+
break;
|
|
2257
2590
|
}
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2591
|
+
case "status":
|
|
2592
|
+
await showStatus2();
|
|
2593
|
+
break;
|
|
2594
|
+
case "reset": {
|
|
2595
|
+
console.log(`${colors4.cyan}Regenerating lockfile...${colors4.reset}`);
|
|
2596
|
+
const lock = await generateLockfile();
|
|
2597
|
+
await savePkgLock(lock);
|
|
2598
|
+
const total = Object.keys(lock.formulas).length + Object.keys(lock.casks).length;
|
|
2599
|
+
console.log(`${colors4.green}Lockfile regenerated with ${total} packages.${colors4.reset}`);
|
|
2600
|
+
break;
|
|
2263
2601
|
}
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
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);
|
|
2602
|
+
case "show":
|
|
2603
|
+
await showLockfile();
|
|
2604
|
+
break;
|
|
2605
|
+
default:
|
|
2606
|
+
console.error(`${colors4.red}Unknown command: ${command}${colors4.reset}`);
|
|
2607
|
+
printUsage3();
|
|
2608
|
+
process.exit(1);
|
|
2285
2609
|
}
|
|
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
2610
|
}
|
|
2611
|
+
var isMainModule3 = process.argv[1]?.includes("pkg-lock");
|
|
2612
|
+
if (isMainModule3) {
|
|
2613
|
+
main3().catch(console.error);
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2616
|
+
// src/components/menus/PackageMenu.tsx
|
|
2617
|
+
import { jsxDEV as jsxDEV16 } from "react/jsx-dev-runtime";
|
|
2300
2618
|
function PackageMenu({ onBack }) {
|
|
2301
|
-
const [state, setState] =
|
|
2302
|
-
const [lines, setLines] =
|
|
2303
|
-
const [output, setOutput] =
|
|
2304
|
-
const [isStreamingOp, setIsStreamingOp] =
|
|
2305
|
-
const [pendingPrompt, setPendingPrompt] =
|
|
2306
|
-
const [success, setSuccess] =
|
|
2619
|
+
const [state, setState] = useState7("menu");
|
|
2620
|
+
const [lines, setLines] = useState7([]);
|
|
2621
|
+
const [output, setOutput] = useState7("");
|
|
2622
|
+
const [isStreamingOp, setIsStreamingOp] = useState7(true);
|
|
2623
|
+
const [pendingPrompt, setPendingPrompt] = useState7(null);
|
|
2624
|
+
const [success, setSuccess] = useState7(true);
|
|
2307
2625
|
const isRunningRef = useRef(false);
|
|
2308
|
-
|
|
2626
|
+
useInput8((input, key) => {
|
|
2309
2627
|
if (state === "menu" && (key.escape || key.leftArrow || input === "h")) {
|
|
2310
2628
|
onBack();
|
|
2311
2629
|
}
|
|
@@ -2324,7 +2642,7 @@ function PackageMenu({ onBack }) {
|
|
|
2324
2642
|
});
|
|
2325
2643
|
}
|
|
2326
2644
|
}), []);
|
|
2327
|
-
const handlePromptAnswer =
|
|
2645
|
+
const handlePromptAnswer = useCallback2((answer) => {
|
|
2328
2646
|
if (pendingPrompt) {
|
|
2329
2647
|
setLines((prev) => [...prev, `> ${answer}`]);
|
|
2330
2648
|
pendingPrompt.resolve(answer);
|
|
@@ -2382,20 +2700,17 @@ function PackageMenu({ onBack }) {
|
|
|
2382
2700
|
};
|
|
2383
2701
|
if (state === "running") {
|
|
2384
2702
|
if (!isStreamingOp) {
|
|
2385
|
-
return /* @__PURE__ */
|
|
2386
|
-
title: "Package Sync"
|
|
2387
|
-
children: /* @__PURE__ */ jsxDEV12(Spinner, {
|
|
2388
|
-
label: "Processing..."
|
|
2389
|
-
}, undefined, false, undefined, this)
|
|
2703
|
+
return /* @__PURE__ */ jsxDEV16(LoadingPanel, {
|
|
2704
|
+
title: "Package Sync"
|
|
2390
2705
|
}, undefined, false, undefined, this);
|
|
2391
2706
|
}
|
|
2392
|
-
return /* @__PURE__ */
|
|
2707
|
+
return /* @__PURE__ */ jsxDEV16(Panel, {
|
|
2393
2708
|
title: "Package Sync",
|
|
2394
2709
|
children: [
|
|
2395
|
-
/* @__PURE__ */
|
|
2710
|
+
/* @__PURE__ */ jsxDEV16(ScrollableLog, {
|
|
2396
2711
|
lines
|
|
2397
2712
|
}, undefined, false, undefined, this),
|
|
2398
|
-
pendingPrompt && /* @__PURE__ */
|
|
2713
|
+
pendingPrompt && /* @__PURE__ */ jsxDEV16(PromptInput, {
|
|
2399
2714
|
question: pendingPrompt.question,
|
|
2400
2715
|
options: pendingPrompt.options,
|
|
2401
2716
|
onAnswer: handlePromptAnswer
|
|
@@ -2405,126 +2720,435 @@ function PackageMenu({ onBack }) {
|
|
|
2405
2720
|
}
|
|
2406
2721
|
if (state === "result") {
|
|
2407
2722
|
if (!isStreamingOp) {
|
|
2408
|
-
return /* @__PURE__ */
|
|
2723
|
+
return /* @__PURE__ */ jsxDEV16(CommandOutput, {
|
|
2409
2724
|
title: "Package Sync",
|
|
2410
2725
|
output,
|
|
2411
2726
|
success,
|
|
2412
2727
|
onDismiss: () => setState("menu")
|
|
2413
2728
|
}, undefined, false, undefined, this);
|
|
2414
2729
|
}
|
|
2415
|
-
return /* @__PURE__ */
|
|
2416
|
-
title: "Package Sync",
|
|
2417
|
-
borderColor: success ? colors.success : colors.error,
|
|
2418
|
-
children: [
|
|
2419
|
-
/* @__PURE__ */
|
|
2420
|
-
lines,
|
|
2421
|
-
autoScroll: false
|
|
2422
|
-
}, undefined, false, undefined, this),
|
|
2423
|
-
/* @__PURE__ */
|
|
2424
|
-
marginTop: 1,
|
|
2425
|
-
children: /* @__PURE__ */
|
|
2426
|
-
color: success ? colors.success : colors.error,
|
|
2427
|
-
children: success ? "Done" : "Failed"
|
|
2428
|
-
}, undefined, false, undefined, this)
|
|
2429
|
-
}, undefined, false, undefined, this),
|
|
2430
|
-
/* @__PURE__ */
|
|
2431
|
-
dimColor: true,
|
|
2432
|
-
children: "Press any key to continue..."
|
|
2433
|
-
}, undefined, false, undefined, this)
|
|
2434
|
-
]
|
|
2435
|
-
}, undefined, true, undefined, this);
|
|
2730
|
+
return /* @__PURE__ */ jsxDEV16(Panel, {
|
|
2731
|
+
title: "Package Sync",
|
|
2732
|
+
borderColor: success ? colors.success : colors.error,
|
|
2733
|
+
children: [
|
|
2734
|
+
/* @__PURE__ */ jsxDEV16(ScrollableLog, {
|
|
2735
|
+
lines,
|
|
2736
|
+
autoScroll: false
|
|
2737
|
+
}, undefined, false, undefined, this),
|
|
2738
|
+
/* @__PURE__ */ jsxDEV16(Box13, {
|
|
2739
|
+
marginTop: 1,
|
|
2740
|
+
children: /* @__PURE__ */ jsxDEV16(Text12, {
|
|
2741
|
+
color: success ? colors.success : colors.error,
|
|
2742
|
+
children: success ? "Done" : "Failed"
|
|
2743
|
+
}, undefined, false, undefined, this)
|
|
2744
|
+
}, undefined, false, undefined, this),
|
|
2745
|
+
/* @__PURE__ */ jsxDEV16(Text12, {
|
|
2746
|
+
dimColor: true,
|
|
2747
|
+
children: "Press any key to continue..."
|
|
2748
|
+
}, undefined, false, undefined, this)
|
|
2749
|
+
]
|
|
2750
|
+
}, undefined, true, undefined, this);
|
|
2751
|
+
}
|
|
2752
|
+
return /* @__PURE__ */ jsxDEV16(Panel, {
|
|
2753
|
+
title: "Package Sync",
|
|
2754
|
+
children: /* @__PURE__ */ jsxDEV16(VimSelect, {
|
|
2755
|
+
options: [
|
|
2756
|
+
{ label: "Sync packages", value: "sync" },
|
|
2757
|
+
{ label: "Sync with purge", value: "sync-purge" },
|
|
2758
|
+
{ label: "Upgrade all (with verification)", value: "upgrade" },
|
|
2759
|
+
{ label: "Upgrade interactive", value: "upgrade-interactive" },
|
|
2760
|
+
{ label: "Update lockfile", value: "lock-update" },
|
|
2761
|
+
{ label: "Lockfile status", value: "lock-status" },
|
|
2762
|
+
{ label: "Back", value: "back" }
|
|
2763
|
+
],
|
|
2764
|
+
onChange: handleAction
|
|
2765
|
+
}, undefined, false, undefined, this)
|
|
2766
|
+
}, undefined, false, undefined, this);
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
// src/components/menus/ThemeMenu.tsx
|
|
2770
|
+
import { useState as useState9, useEffect as useEffect5, useMemo as useMemo4 } from "react";
|
|
2771
|
+
import { Box as Box15, Text as Text14 } from "ink";
|
|
2772
|
+
import { existsSync as existsSync7, readdirSync as readdirSync5 } from "fs";
|
|
2773
|
+
import { join as join6 } from "path";
|
|
2774
|
+
|
|
2775
|
+
// src/components/ThemeCard.tsx
|
|
2776
|
+
import { Box as Box14, Text as Text13 } from "ink";
|
|
2777
|
+
import { jsxDEV as jsxDEV17 } from "react/jsx-dev-runtime";
|
|
2778
|
+
function ThemeCard({ theme, isSelected, width }) {
|
|
2779
|
+
const borderColor = isSelected ? colors.accent : colors.border;
|
|
2780
|
+
const nameColor = isSelected ? colors.primary : colors.text;
|
|
2781
|
+
const indicators = [];
|
|
2782
|
+
if (theme.hasBackgrounds)
|
|
2783
|
+
indicators.push("bg");
|
|
2784
|
+
if (theme.isLightMode)
|
|
2785
|
+
indicators.push("light");
|
|
2786
|
+
const indicatorText = indicators.length > 0 ? ` [${indicators.join(" ")}]` : "";
|
|
2787
|
+
return /* @__PURE__ */ jsxDEV17(Box14, {
|
|
2788
|
+
flexDirection: "column",
|
|
2789
|
+
width,
|
|
2790
|
+
borderStyle: borderStyles.panel,
|
|
2791
|
+
borderColor,
|
|
2792
|
+
paddingX: 1,
|
|
2793
|
+
children: /* @__PURE__ */ jsxDEV17(Box14, {
|
|
2794
|
+
children: [
|
|
2795
|
+
/* @__PURE__ */ jsxDEV17(Text13, {
|
|
2796
|
+
color: isSelected ? colors.accent : colors.primaryDim,
|
|
2797
|
+
children: isSelected ? "● " : " "
|
|
2798
|
+
}, undefined, false, undefined, this),
|
|
2799
|
+
/* @__PURE__ */ jsxDEV17(Text13, {
|
|
2800
|
+
color: nameColor,
|
|
2801
|
+
bold: true,
|
|
2802
|
+
wrap: "truncate",
|
|
2803
|
+
children: theme.name
|
|
2804
|
+
}, undefined, false, undefined, this),
|
|
2805
|
+
/* @__PURE__ */ jsxDEV17(Text13, {
|
|
2806
|
+
color: colors.primaryDim,
|
|
2807
|
+
children: indicatorText
|
|
2808
|
+
}, undefined, false, undefined, this)
|
|
2809
|
+
]
|
|
2810
|
+
}, undefined, true, undefined, this)
|
|
2811
|
+
}, undefined, false, undefined, this);
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
// src/hooks/useThemeGrid.ts
|
|
2815
|
+
import { useState as useState8, useEffect as useEffect4 } from "react";
|
|
2816
|
+
import { useInput as useInput9 } from "ink";
|
|
2817
|
+
function useThemeGrid({
|
|
2818
|
+
itemCount,
|
|
2819
|
+
cardHeight = 3,
|
|
2820
|
+
layoutOverhead = 20,
|
|
2821
|
+
minCardWidth = 28,
|
|
2822
|
+
onSelect,
|
|
2823
|
+
onBack,
|
|
2824
|
+
enabled = true
|
|
2825
|
+
}) {
|
|
2826
|
+
const { columns, rows } = useTerminalSize();
|
|
2827
|
+
const [selectedIndex, setSelectedIndex] = useState8(0);
|
|
2828
|
+
const [scrollOffset, setScrollOffset] = useState8(0);
|
|
2829
|
+
const availableWidth = columns - 6;
|
|
2830
|
+
const cardsPerRow = Math.max(1, Math.floor(availableWidth / minCardWidth));
|
|
2831
|
+
const cardWidth = Math.floor(availableWidth / cardsPerRow);
|
|
2832
|
+
const availableHeight = rows - layoutOverhead;
|
|
2833
|
+
const visibleRows = Math.max(1, Math.floor(availableHeight / cardHeight));
|
|
2834
|
+
const selectedRow = Math.floor(selectedIndex / cardsPerRow);
|
|
2835
|
+
const totalRows = Math.ceil(itemCount / cardsPerRow);
|
|
2836
|
+
useEffect4(() => {
|
|
2837
|
+
if (selectedRow < scrollOffset) {
|
|
2838
|
+
setScrollOffset(selectedRow);
|
|
2839
|
+
} else if (selectedRow >= scrollOffset + visibleRows) {
|
|
2840
|
+
setScrollOffset(selectedRow - visibleRows + 1);
|
|
2841
|
+
}
|
|
2842
|
+
}, [selectedRow, scrollOffset, visibleRows]);
|
|
2843
|
+
useInput9((input, key) => {
|
|
2844
|
+
if (!enabled)
|
|
2845
|
+
return;
|
|
2846
|
+
if (key.escape && onBack) {
|
|
2847
|
+
onBack();
|
|
2848
|
+
return;
|
|
2849
|
+
}
|
|
2850
|
+
if (key.rightArrow || input === "l") {
|
|
2851
|
+
if (selectedIndex < itemCount - 1) {
|
|
2852
|
+
setSelectedIndex((i) => i + 1);
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
if (key.leftArrow || input === "h") {
|
|
2856
|
+
if (selectedIndex > 0) {
|
|
2857
|
+
setSelectedIndex((i) => i - 1);
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
if (key.downArrow || input === "j") {
|
|
2861
|
+
const nextIndex = selectedIndex + cardsPerRow;
|
|
2862
|
+
if (nextIndex < itemCount) {
|
|
2863
|
+
setSelectedIndex(nextIndex);
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
if (key.upArrow || input === "k") {
|
|
2867
|
+
const prevIndex = selectedIndex - cardsPerRow;
|
|
2868
|
+
if (prevIndex >= 0) {
|
|
2869
|
+
setSelectedIndex(prevIndex);
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
if (key.return && onSelect) {
|
|
2873
|
+
onSelect(selectedIndex);
|
|
2874
|
+
}
|
|
2875
|
+
});
|
|
2876
|
+
const visibleStartIndex = scrollOffset * cardsPerRow;
|
|
2877
|
+
const visibleEndIndex = (scrollOffset + visibleRows) * cardsPerRow;
|
|
2878
|
+
return {
|
|
2879
|
+
cardsPerRow,
|
|
2880
|
+
cardWidth,
|
|
2881
|
+
visibleRows,
|
|
2882
|
+
scrollOffset,
|
|
2883
|
+
selectedIndex,
|
|
2884
|
+
visibleStartIndex,
|
|
2885
|
+
visibleEndIndex,
|
|
2886
|
+
showScrollUp: scrollOffset > 0,
|
|
2887
|
+
showScrollDown: scrollOffset + visibleRows < totalRows,
|
|
2888
|
+
gridHeight: visibleRows * cardHeight,
|
|
2889
|
+
totalRows
|
|
2890
|
+
};
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
// src/lib/theme-parser.ts
|
|
2894
|
+
import { existsSync as existsSync5, readdirSync as readdirSync3 } from "fs";
|
|
2895
|
+
import { join as join4 } from "path";
|
|
2896
|
+
function parseYaml(content) {
|
|
2897
|
+
const result = {};
|
|
2898
|
+
const lines = content.split(`
|
|
2899
|
+
`);
|
|
2900
|
+
let currentSection = null;
|
|
2901
|
+
let currentKey = "";
|
|
2902
|
+
for (const line of lines) {
|
|
2903
|
+
const trimmed = line.trim();
|
|
2904
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
2905
|
+
continue;
|
|
2906
|
+
const indentLevel = line.search(/\S/);
|
|
2907
|
+
const match = trimmed.match(/^([\w-]+):\s*(.*)$/);
|
|
2908
|
+
if (match) {
|
|
2909
|
+
const [, key, value] = match;
|
|
2910
|
+
if (indentLevel === 0) {
|
|
2911
|
+
if (value) {
|
|
2912
|
+
result[key] = value.replace(/^["']|["']$/g, "");
|
|
2913
|
+
} else {
|
|
2914
|
+
currentKey = key;
|
|
2915
|
+
currentSection = {};
|
|
2916
|
+
result[key] = currentSection;
|
|
2917
|
+
}
|
|
2918
|
+
} else if (currentSection) {
|
|
2919
|
+
currentSection[key] = value.replace(/^["']|["']$/g, "");
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
return result;
|
|
2924
|
+
}
|
|
2925
|
+
async function parseThemeMetadata(themePath) {
|
|
2926
|
+
const yamlPath = join4(themePath, "theme.yaml");
|
|
2927
|
+
if (!existsSync5(yamlPath)) {
|
|
2928
|
+
return;
|
|
2929
|
+
}
|
|
2930
|
+
try {
|
|
2931
|
+
const content = await readText(yamlPath);
|
|
2932
|
+
const parsed = parseYaml(content);
|
|
2933
|
+
return {
|
|
2934
|
+
name: parsed.name || "",
|
|
2935
|
+
author: parsed.author,
|
|
2936
|
+
description: parsed.description,
|
|
2937
|
+
version: parsed.version,
|
|
2938
|
+
source: parsed.source,
|
|
2939
|
+
colors: parsed.colors
|
|
2940
|
+
};
|
|
2941
|
+
} catch {
|
|
2942
|
+
return;
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
function parseThemeFiles(themePath) {
|
|
2946
|
+
const entries = readdirSync3(themePath, { withFileTypes: true });
|
|
2947
|
+
return entries.filter((e) => e.isFile() && !e.name.startsWith(".") && e.name !== "theme.yaml" && e.name !== "light.mode").map((e) => ({
|
|
2948
|
+
name: e.name,
|
|
2949
|
+
path: join4(themePath, e.name),
|
|
2950
|
+
application: e.name.replace(/\.(conf|theme|lua|toml|css|json|ini)$/, "")
|
|
2951
|
+
}));
|
|
2952
|
+
}
|
|
2953
|
+
async function parseTheme(themePath, themeName) {
|
|
2954
|
+
const files = parseThemeFiles(themePath);
|
|
2955
|
+
const metadata = await parseThemeMetadata(themePath);
|
|
2956
|
+
return {
|
|
2957
|
+
name: metadata?.name || themeName,
|
|
2958
|
+
path: themePath,
|
|
2959
|
+
files,
|
|
2960
|
+
metadata,
|
|
2961
|
+
hasBackgrounds: existsSync5(join4(themePath, "backgrounds")),
|
|
2962
|
+
hasPreview: existsSync5(join4(themePath, "preview.png")),
|
|
2963
|
+
isLightMode: existsSync5(join4(themePath, "light.mode"))
|
|
2964
|
+
};
|
|
2965
|
+
}
|
|
2966
|
+
|
|
2967
|
+
// src/cli/set-theme.ts
|
|
2968
|
+
import { parseArgs as parseArgs4 } from "util";
|
|
2969
|
+
import { readdirSync as readdirSync4, existsSync as existsSync6, rmSync, symlinkSync, unlinkSync } from "fs";
|
|
2970
|
+
import { join as join5 } from "path";
|
|
2971
|
+
var colors5 = {
|
|
2972
|
+
red: "\x1B[0;31m",
|
|
2973
|
+
green: "\x1B[0;32m",
|
|
2974
|
+
blue: "\x1B[0;34m",
|
|
2975
|
+
yellow: "\x1B[1;33m",
|
|
2976
|
+
cyan: "\x1B[0;36m",
|
|
2977
|
+
dim: "\x1B[2m",
|
|
2978
|
+
reset: "\x1B[0m"
|
|
2979
|
+
};
|
|
2980
|
+
async function listThemes() {
|
|
2981
|
+
await ensureConfigDir();
|
|
2982
|
+
if (!existsSync6(THEMES_DIR)) {
|
|
2983
|
+
return [];
|
|
2984
|
+
}
|
|
2985
|
+
const entries = readdirSync4(THEMES_DIR, { withFileTypes: true });
|
|
2986
|
+
const themes = [];
|
|
2987
|
+
for (const entry of entries) {
|
|
2988
|
+
if (entry.isDirectory()) {
|
|
2989
|
+
const themePath = join5(THEMES_DIR, entry.name);
|
|
2990
|
+
const theme = await parseTheme(themePath, entry.name);
|
|
2991
|
+
themes.push(theme);
|
|
2992
|
+
}
|
|
2436
2993
|
}
|
|
2437
|
-
return
|
|
2438
|
-
title: "Package Sync",
|
|
2439
|
-
children: /* @__PURE__ */ jsxDEV12(VimSelect, {
|
|
2440
|
-
options: [
|
|
2441
|
-
{ label: "Sync packages", value: "sync" },
|
|
2442
|
-
{ label: "Sync with purge", value: "sync-purge" },
|
|
2443
|
-
{ label: "Upgrade all (with verification)", value: "upgrade" },
|
|
2444
|
-
{ label: "Upgrade interactive", value: "upgrade-interactive" },
|
|
2445
|
-
{ label: "Update lockfile", value: "lock-update" },
|
|
2446
|
-
{ label: "Lockfile status", value: "lock-status" },
|
|
2447
|
-
{ label: "Back", value: "back" }
|
|
2448
|
-
],
|
|
2449
|
-
onChange: handleAction
|
|
2450
|
-
}, undefined, false, undefined, this)
|
|
2451
|
-
}, undefined, false, undefined, this);
|
|
2994
|
+
return themes;
|
|
2452
2995
|
}
|
|
2453
|
-
function
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
const LAYOUT_OVERHEAD = 20;
|
|
2463
|
-
const cardWidth = useMemo2(() => {
|
|
2464
|
-
const availableWidth = columns - 6;
|
|
2465
|
-
const cardsPerRow2 = Math.max(1, Math.floor(availableWidth / 28));
|
|
2466
|
-
return Math.floor(availableWidth / cardsPerRow2);
|
|
2467
|
-
}, [columns]);
|
|
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]);
|
|
2476
|
-
const selectedRow = Math.floor(selectedIndex / cardsPerRow);
|
|
2477
|
-
const totalRows = Math.ceil(themes.length / cardsPerRow);
|
|
2478
|
-
const [scrollOffset, setScrollOffset] = useState5(0);
|
|
2479
|
-
useEffect4(() => {
|
|
2480
|
-
if (selectedRow < scrollOffset) {
|
|
2481
|
-
setScrollOffset(selectedRow);
|
|
2482
|
-
} else if (selectedRow >= scrollOffset + visibleRows) {
|
|
2483
|
-
setScrollOffset(selectedRow - visibleRows + 1);
|
|
2484
|
-
}
|
|
2485
|
-
}, [selectedRow, scrollOffset, visibleRows]);
|
|
2486
|
-
const visibleThemes = useMemo2(() => {
|
|
2487
|
-
const startIdx = scrollOffset * cardsPerRow;
|
|
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)
|
|
2494
|
-
return;
|
|
2495
|
-
if (key.escape) {
|
|
2496
|
-
onBack();
|
|
2497
|
-
return;
|
|
2498
|
-
}
|
|
2499
|
-
if (key.rightArrow || input === "l") {
|
|
2500
|
-
if (selectedIndex < themes.length - 1) {
|
|
2501
|
-
setSelectedIndex((i) => i + 1);
|
|
2502
|
-
}
|
|
2503
|
-
}
|
|
2504
|
-
if (key.leftArrow || input === "h") {
|
|
2505
|
-
if (selectedIndex > 0) {
|
|
2506
|
-
setSelectedIndex((i) => i - 1);
|
|
2996
|
+
function clearDirectory(dir) {
|
|
2997
|
+
if (existsSync6(dir)) {
|
|
2998
|
+
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
2999
|
+
for (const entry of entries) {
|
|
3000
|
+
const fullPath = join5(dir, entry.name);
|
|
3001
|
+
if (entry.isSymbolicLink() || entry.isFile()) {
|
|
3002
|
+
unlinkSync(fullPath);
|
|
3003
|
+
} else if (entry.isDirectory()) {
|
|
3004
|
+
rmSync(fullPath, { recursive: true, force: true });
|
|
2507
3005
|
}
|
|
2508
3006
|
}
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
function createSymlink(source, target) {
|
|
3010
|
+
if (existsSync6(target)) {
|
|
3011
|
+
unlinkSync(target);
|
|
3012
|
+
}
|
|
3013
|
+
symlinkSync(source, target);
|
|
3014
|
+
}
|
|
3015
|
+
async function applyTheme(themeName) {
|
|
3016
|
+
const themeDir = join5(THEMES_DIR, themeName);
|
|
3017
|
+
if (!existsSync6(themeDir)) {
|
|
3018
|
+
return { output: `Theme '${themeName}' not found`, success: false };
|
|
3019
|
+
}
|
|
3020
|
+
await ensureConfigDir();
|
|
3021
|
+
await ensureDir2(THEME_TARGET_DIR);
|
|
3022
|
+
const theme = await parseTheme(themeDir, themeName);
|
|
3023
|
+
clearDirectory(THEME_TARGET_DIR);
|
|
3024
|
+
if (existsSync6(BACKGROUNDS_TARGET_DIR)) {
|
|
3025
|
+
rmSync(BACKGROUNDS_TARGET_DIR, { recursive: true, force: true });
|
|
3026
|
+
}
|
|
3027
|
+
const entries = readdirSync4(themeDir, { withFileTypes: true });
|
|
3028
|
+
for (const entry of entries) {
|
|
3029
|
+
const source = join5(themeDir, entry.name);
|
|
3030
|
+
if (entry.isFile() && entry.name !== "theme.yaml" && entry.name !== "light.mode") {
|
|
3031
|
+
const target = join5(THEME_TARGET_DIR, entry.name);
|
|
3032
|
+
createSymlink(source, target);
|
|
2514
3033
|
}
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
3034
|
+
}
|
|
3035
|
+
if (theme.hasBackgrounds) {
|
|
3036
|
+
const backgroundsSource = join5(themeDir, "backgrounds");
|
|
3037
|
+
createSymlink(backgroundsSource, BACKGROUNDS_TARGET_DIR);
|
|
3038
|
+
}
|
|
3039
|
+
let output = `Theme '${theme.name}' applied successfully`;
|
|
3040
|
+
if (theme.metadata?.author) {
|
|
3041
|
+
output += `
|
|
3042
|
+
Author: ${theme.metadata.author}`;
|
|
3043
|
+
}
|
|
3044
|
+
if (theme.hasBackgrounds) {
|
|
3045
|
+
output += `
|
|
3046
|
+
Wallpapers available at: ~/.config/formalconf/current/backgrounds/`;
|
|
3047
|
+
}
|
|
3048
|
+
if (theme.isLightMode) {
|
|
3049
|
+
output += `
|
|
3050
|
+
Note: This is a light mode theme`;
|
|
3051
|
+
}
|
|
3052
|
+
return { output, success: true };
|
|
3053
|
+
}
|
|
3054
|
+
async function showThemeInfo(themeName) {
|
|
3055
|
+
const themeDir = join5(THEMES_DIR, themeName);
|
|
3056
|
+
if (!existsSync6(themeDir)) {
|
|
3057
|
+
console.error(`${colors5.red}Error: Theme '${themeName}' not found${colors5.reset}`);
|
|
3058
|
+
process.exit(1);
|
|
3059
|
+
}
|
|
3060
|
+
const theme = await parseTheme(themeDir, themeName);
|
|
3061
|
+
console.log(`
|
|
3062
|
+
${colors5.cyan}Theme: ${theme.name}${colors5.reset}`);
|
|
3063
|
+
if (theme.metadata) {
|
|
3064
|
+
if (theme.metadata.author)
|
|
3065
|
+
console.log(`Author: ${theme.metadata.author}`);
|
|
3066
|
+
if (theme.metadata.description)
|
|
3067
|
+
console.log(`Description: ${theme.metadata.description}`);
|
|
3068
|
+
if (theme.metadata.version)
|
|
3069
|
+
console.log(`Version: ${theme.metadata.version}`);
|
|
3070
|
+
if (theme.metadata.source)
|
|
3071
|
+
console.log(`Source: ${theme.metadata.source}`);
|
|
3072
|
+
}
|
|
3073
|
+
console.log(`
|
|
3074
|
+
Files (${theme.files.length}):`);
|
|
3075
|
+
for (const file of theme.files) {
|
|
3076
|
+
console.log(` ${colors5.blue}•${colors5.reset} ${file.name}`);
|
|
3077
|
+
}
|
|
3078
|
+
if (theme.hasBackgrounds) {
|
|
3079
|
+
console.log(`
|
|
3080
|
+
${colors5.green}Has wallpapers${colors5.reset}`);
|
|
3081
|
+
}
|
|
3082
|
+
if (theme.hasPreview) {
|
|
3083
|
+
console.log(`${colors5.green}Has preview image${colors5.reset}`);
|
|
3084
|
+
}
|
|
3085
|
+
if (theme.isLightMode) {
|
|
3086
|
+
console.log(`${colors5.yellow}Light mode theme${colors5.reset}`);
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
async function runSetTheme(themeName) {
|
|
3090
|
+
return applyTheme(themeName);
|
|
3091
|
+
}
|
|
3092
|
+
async function main4() {
|
|
3093
|
+
const { positionals, values } = parseArgs4({
|
|
3094
|
+
args: process.argv.slice(2),
|
|
3095
|
+
options: {
|
|
3096
|
+
info: { type: "boolean", short: "i" }
|
|
3097
|
+
},
|
|
3098
|
+
allowPositionals: true
|
|
3099
|
+
});
|
|
3100
|
+
const [themeName] = positionals;
|
|
3101
|
+
if (!themeName) {
|
|
3102
|
+
const themes = await listThemes();
|
|
3103
|
+
if (themes.length === 0) {
|
|
3104
|
+
console.log(`${colors5.yellow}No themes available.${colors5.reset}`);
|
|
3105
|
+
console.log(`This system is compatible with omarchy themes.`);
|
|
3106
|
+
console.log(`
|
|
3107
|
+
Add themes to: ${colors5.cyan}~/.config/formalconf/themes/${colors5.reset}`);
|
|
3108
|
+
process.exit(0);
|
|
2520
3109
|
}
|
|
2521
|
-
|
|
2522
|
-
|
|
3110
|
+
console.log(`${colors5.cyan}Usage: formalconf theme <theme-name>${colors5.reset}`);
|
|
3111
|
+
console.log(` formalconf theme --info <theme-name>
|
|
3112
|
+
`);
|
|
3113
|
+
console.log("Available themes:");
|
|
3114
|
+
for (const theme of themes) {
|
|
3115
|
+
const extras = [];
|
|
3116
|
+
if (theme.hasBackgrounds)
|
|
3117
|
+
extras.push("wallpapers");
|
|
3118
|
+
if (theme.isLightMode)
|
|
3119
|
+
extras.push("light");
|
|
3120
|
+
const suffix = extras.length ? ` ${colors5.dim}(${extras.join(", ")})${colors5.reset}` : "";
|
|
3121
|
+
console.log(` ${colors5.blue}•${colors5.reset} ${theme.name}${suffix}`);
|
|
2523
3122
|
}
|
|
3123
|
+
process.exit(0);
|
|
3124
|
+
}
|
|
3125
|
+
if (values.info) {
|
|
3126
|
+
await showThemeInfo(themeName);
|
|
3127
|
+
} else {
|
|
3128
|
+
const result = await applyTheme(themeName);
|
|
3129
|
+
console.log(result.success ? `${colors5.green}${result.output}${colors5.reset}` : `${colors5.red}${result.output}${colors5.reset}`);
|
|
3130
|
+
}
|
|
3131
|
+
}
|
|
3132
|
+
var isMainModule4 = process.argv[1]?.includes("set-theme");
|
|
3133
|
+
if (isMainModule4) {
|
|
3134
|
+
main4().catch(console.error);
|
|
3135
|
+
}
|
|
3136
|
+
|
|
3137
|
+
// src/components/menus/ThemeMenu.tsx
|
|
3138
|
+
import { jsxDEV as jsxDEV18 } from "react/jsx-dev-runtime";
|
|
3139
|
+
function ThemeMenu({ onBack }) {
|
|
3140
|
+
const [themes, setThemes] = useState9([]);
|
|
3141
|
+
const [loading, setLoading] = useState9(true);
|
|
3142
|
+
const { state, output, success, isRunning, isResult, execute, reset } = useMenuAction();
|
|
3143
|
+
const grid = useThemeGrid({
|
|
3144
|
+
itemCount: themes.length,
|
|
3145
|
+
onSelect: (index) => applyTheme2(themes[index]),
|
|
3146
|
+
onBack,
|
|
3147
|
+
enabled: state === "menu" && !loading && themes.length > 0
|
|
2524
3148
|
});
|
|
2525
|
-
|
|
3149
|
+
useEffect5(() => {
|
|
2526
3150
|
async function loadThemes() {
|
|
2527
|
-
if (!
|
|
3151
|
+
if (!existsSync7(THEMES_DIR)) {
|
|
2528
3152
|
setThemes([]);
|
|
2529
3153
|
setLoading(false);
|
|
2530
3154
|
return;
|
|
@@ -2533,7 +3157,7 @@ function ThemeMenu({ onBack }) {
|
|
|
2533
3157
|
const loadedThemes = [];
|
|
2534
3158
|
for (const entry of entries) {
|
|
2535
3159
|
if (entry.isDirectory()) {
|
|
2536
|
-
const themePath =
|
|
3160
|
+
const themePath = join6(THEMES_DIR, entry.name);
|
|
2537
3161
|
const theme = await parseTheme(themePath, entry.name);
|
|
2538
3162
|
loadedThemes.push(theme);
|
|
2539
3163
|
}
|
|
@@ -2544,52 +3168,49 @@ function ThemeMenu({ onBack }) {
|
|
|
2544
3168
|
loadThemes();
|
|
2545
3169
|
}, []);
|
|
2546
3170
|
const applyTheme2 = async (theme) => {
|
|
2547
|
-
setState("running");
|
|
2548
3171
|
const themeName = theme.path.split("/").pop();
|
|
2549
|
-
|
|
2550
|
-
setOutput(result.output);
|
|
2551
|
-
setSuccess(result.success);
|
|
2552
|
-
setState("result");
|
|
3172
|
+
await execute(() => runSetTheme(themeName));
|
|
2553
3173
|
};
|
|
2554
|
-
|
|
2555
|
-
return
|
|
3174
|
+
const visibleThemes = useMemo4(() => {
|
|
3175
|
+
return themes.slice(grid.visibleStartIndex, grid.visibleEndIndex);
|
|
3176
|
+
}, [themes, grid.visibleStartIndex, grid.visibleEndIndex]);
|
|
3177
|
+
if (loading || isRunning) {
|
|
3178
|
+
return /* @__PURE__ */ jsxDEV18(LoadingPanel, {
|
|
2556
3179
|
title: "Select Theme",
|
|
2557
|
-
|
|
2558
|
-
label: loading ? "Loading themes..." : "Applying theme..."
|
|
2559
|
-
}, undefined, false, undefined, this)
|
|
3180
|
+
label: loading ? "Loading themes..." : "Applying theme..."
|
|
2560
3181
|
}, undefined, false, undefined, this);
|
|
2561
3182
|
}
|
|
2562
|
-
if (
|
|
2563
|
-
return /* @__PURE__ */
|
|
3183
|
+
if (isResult) {
|
|
3184
|
+
return /* @__PURE__ */ jsxDEV18(CommandOutput, {
|
|
2564
3185
|
title: "Select Theme",
|
|
2565
3186
|
output,
|
|
2566
3187
|
success,
|
|
2567
|
-
onDismiss:
|
|
3188
|
+
onDismiss: reset
|
|
2568
3189
|
}, undefined, false, undefined, this);
|
|
2569
3190
|
}
|
|
2570
3191
|
if (themes.length === 0) {
|
|
2571
|
-
return /* @__PURE__ */
|
|
3192
|
+
return /* @__PURE__ */ jsxDEV18(Panel, {
|
|
2572
3193
|
title: "Select Theme",
|
|
2573
3194
|
children: [
|
|
2574
|
-
/* @__PURE__ */
|
|
3195
|
+
/* @__PURE__ */ jsxDEV18(Box15, {
|
|
2575
3196
|
flexDirection: "column",
|
|
2576
3197
|
children: [
|
|
2577
|
-
/* @__PURE__ */
|
|
3198
|
+
/* @__PURE__ */ jsxDEV18(Text14, {
|
|
2578
3199
|
color: colors.warning,
|
|
2579
3200
|
children: "No themes available."
|
|
2580
3201
|
}, undefined, false, undefined, this),
|
|
2581
|
-
/* @__PURE__ */
|
|
3202
|
+
/* @__PURE__ */ jsxDEV18(Text14, {
|
|
2582
3203
|
children: "This system is compatible with omarchy themes."
|
|
2583
3204
|
}, undefined, false, undefined, this),
|
|
2584
|
-
/* @__PURE__ */
|
|
3205
|
+
/* @__PURE__ */ jsxDEV18(Text14, {
|
|
2585
3206
|
dimColor: true,
|
|
2586
3207
|
children: "Add themes to ~/.config/formalconf/themes/"
|
|
2587
3208
|
}, undefined, false, undefined, this)
|
|
2588
3209
|
]
|
|
2589
3210
|
}, undefined, true, undefined, this),
|
|
2590
|
-
/* @__PURE__ */
|
|
3211
|
+
/* @__PURE__ */ jsxDEV18(Box15, {
|
|
2591
3212
|
marginTop: 1,
|
|
2592
|
-
children: /* @__PURE__ */
|
|
3213
|
+
children: /* @__PURE__ */ jsxDEV18(VimSelect, {
|
|
2593
3214
|
options: [{ label: "Back", value: "back" }],
|
|
2594
3215
|
onChange: () => onBack()
|
|
2595
3216
|
}, undefined, false, undefined, this)
|
|
@@ -2597,44 +3218,43 @@ function ThemeMenu({ onBack }) {
|
|
|
2597
3218
|
]
|
|
2598
3219
|
}, undefined, true, undefined, this);
|
|
2599
3220
|
}
|
|
2600
|
-
|
|
2601
|
-
const showScrollDown = scrollOffset + visibleRows < totalRows;
|
|
2602
|
-
const gridHeight = visibleRows * CARD_HEIGHT;
|
|
2603
|
-
return /* @__PURE__ */ jsxDEV12(Panel, {
|
|
3221
|
+
return /* @__PURE__ */ jsxDEV18(Panel, {
|
|
2604
3222
|
title: "Select Theme",
|
|
2605
3223
|
children: [
|
|
2606
|
-
showScrollUp && /* @__PURE__ */
|
|
3224
|
+
grid.showScrollUp && /* @__PURE__ */ jsxDEV18(Text14, {
|
|
2607
3225
|
dimColor: true,
|
|
2608
3226
|
children: [
|
|
2609
|
-
"
|
|
2610
|
-
|
|
3227
|
+
" ",
|
|
3228
|
+
"↑ ",
|
|
3229
|
+
grid.scrollOffset,
|
|
2611
3230
|
" more row",
|
|
2612
|
-
scrollOffset > 1 ? "s" : ""
|
|
3231
|
+
grid.scrollOffset > 1 ? "s" : ""
|
|
2613
3232
|
]
|
|
2614
3233
|
}, undefined, true, undefined, this),
|
|
2615
|
-
/* @__PURE__ */
|
|
3234
|
+
/* @__PURE__ */ jsxDEV18(Box15, {
|
|
2616
3235
|
flexDirection: "row",
|
|
2617
3236
|
flexWrap: "wrap",
|
|
2618
|
-
height: gridHeight,
|
|
3237
|
+
height: grid.gridHeight,
|
|
2619
3238
|
overflow: "hidden",
|
|
2620
|
-
children: visibleThemes.map((theme, index) => /* @__PURE__ */
|
|
3239
|
+
children: visibleThemes.map((theme, index) => /* @__PURE__ */ jsxDEV18(ThemeCard, {
|
|
2621
3240
|
theme,
|
|
2622
|
-
isSelected: visibleStartIndex + index === selectedIndex,
|
|
2623
|
-
width: cardWidth
|
|
3241
|
+
isSelected: grid.visibleStartIndex + index === grid.selectedIndex,
|
|
3242
|
+
width: grid.cardWidth
|
|
2624
3243
|
}, theme.path, false, undefined, this))
|
|
2625
3244
|
}, undefined, false, undefined, this),
|
|
2626
|
-
showScrollDown && /* @__PURE__ */
|
|
3245
|
+
grid.showScrollDown && /* @__PURE__ */ jsxDEV18(Text14, {
|
|
2627
3246
|
dimColor: true,
|
|
2628
3247
|
children: [
|
|
2629
|
-
"
|
|
2630
|
-
|
|
3248
|
+
" ",
|
|
3249
|
+
"↓ ",
|
|
3250
|
+
grid.totalRows - grid.scrollOffset - grid.visibleRows,
|
|
2631
3251
|
" more row",
|
|
2632
|
-
totalRows - scrollOffset - visibleRows > 1 ? "s" : ""
|
|
3252
|
+
grid.totalRows - grid.scrollOffset - grid.visibleRows > 1 ? "s" : ""
|
|
2633
3253
|
]
|
|
2634
3254
|
}, undefined, true, undefined, this),
|
|
2635
|
-
/* @__PURE__ */
|
|
3255
|
+
/* @__PURE__ */ jsxDEV18(Box15, {
|
|
2636
3256
|
marginTop: 1,
|
|
2637
|
-
children: /* @__PURE__ */
|
|
3257
|
+
children: /* @__PURE__ */ jsxDEV18(Text14, {
|
|
2638
3258
|
dimColor: true,
|
|
2639
3259
|
children: "←→↑↓/hjkl navigate • Enter select • Esc back"
|
|
2640
3260
|
}, undefined, false, undefined, this)
|
|
@@ -2642,122 +3262,81 @@ function ThemeMenu({ onBack }) {
|
|
|
2642
3262
|
]
|
|
2643
3263
|
}, undefined, true, undefined, this);
|
|
2644
3264
|
}
|
|
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
|
-
}
|
|
3265
|
+
|
|
3266
|
+
// src/cli/formalconf.tsx
|
|
3267
|
+
import { jsxDEV as jsxDEV19 } from "react/jsx-dev-runtime";
|
|
3268
|
+
var BREADCRUMBS = {
|
|
3269
|
+
main: ["Main"],
|
|
3270
|
+
config: ["Main", "Config Manager"],
|
|
3271
|
+
packages: ["Main", "Package Sync"],
|
|
3272
|
+
themes: ["Main", "Themes"]
|
|
3273
|
+
};
|
|
2693
3274
|
function App() {
|
|
2694
|
-
const [appState, setAppState] =
|
|
2695
|
-
const [missingDeps, setMissingDeps] =
|
|
2696
|
-
const [screen, setScreen] =
|
|
2697
|
-
const { exit } =
|
|
2698
|
-
|
|
2699
|
-
if (input === "q")
|
|
3275
|
+
const [appState, setAppState] = useState10("loading");
|
|
3276
|
+
const [missingDeps, setMissingDeps] = useState10([]);
|
|
3277
|
+
const [screen, setScreen] = useState10("main");
|
|
3278
|
+
const { exit } = useApp2();
|
|
3279
|
+
useInput10((input) => {
|
|
3280
|
+
if (input === "q")
|
|
2700
3281
|
exit();
|
|
2701
|
-
}
|
|
2702
3282
|
});
|
|
2703
|
-
|
|
3283
|
+
useEffect6(() => {
|
|
2704
3284
|
async function init() {
|
|
2705
|
-
ensureConfigDir();
|
|
3285
|
+
await ensureConfigDir();
|
|
2706
3286
|
const result = await checkPrerequisites();
|
|
2707
3287
|
if (!result.ok) {
|
|
2708
3288
|
setMissingDeps(result.missing);
|
|
2709
3289
|
setAppState("error");
|
|
2710
|
-
|
|
2711
|
-
|
|
3290
|
+
return;
|
|
3291
|
+
}
|
|
3292
|
+
const firstRun = await isFirstRun();
|
|
3293
|
+
if (firstRun) {
|
|
3294
|
+
setAppState("onboarding");
|
|
3295
|
+
return;
|
|
2712
3296
|
}
|
|
3297
|
+
setAppState("ready");
|
|
2713
3298
|
}
|
|
2714
3299
|
init();
|
|
2715
3300
|
}, []);
|
|
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
3301
|
if (appState === "loading") {
|
|
2729
|
-
return /* @__PURE__ */
|
|
3302
|
+
return /* @__PURE__ */ jsxDEV19(Layout, {
|
|
2730
3303
|
breadcrumb: ["Loading"],
|
|
2731
|
-
children: /* @__PURE__ */
|
|
3304
|
+
children: /* @__PURE__ */ jsxDEV19(Panel, {
|
|
2732
3305
|
title: "FormalConf",
|
|
2733
|
-
children: /* @__PURE__ */
|
|
3306
|
+
children: /* @__PURE__ */ jsxDEV19(Spinner2, {
|
|
2734
3307
|
label: "Checking prerequisites..."
|
|
2735
3308
|
}, undefined, false, undefined, this)
|
|
2736
3309
|
}, undefined, false, undefined, this)
|
|
2737
3310
|
}, undefined, false, undefined, this);
|
|
2738
3311
|
}
|
|
2739
3312
|
if (appState === "error") {
|
|
2740
|
-
return /* @__PURE__ */
|
|
3313
|
+
return /* @__PURE__ */ jsxDEV19(PrerequisiteError, {
|
|
2741
3314
|
missing: missingDeps,
|
|
2742
3315
|
onExit: exit
|
|
2743
3316
|
}, undefined, false, undefined, this);
|
|
2744
3317
|
}
|
|
2745
|
-
|
|
2746
|
-
|
|
3318
|
+
if (appState === "onboarding") {
|
|
3319
|
+
return /* @__PURE__ */ jsxDEV19(Onboarding, {
|
|
3320
|
+
onComplete: () => setAppState("ready")
|
|
3321
|
+
}, undefined, false, undefined, this);
|
|
3322
|
+
}
|
|
3323
|
+
const goBack = () => setScreen("main");
|
|
3324
|
+
return /* @__PURE__ */ jsxDEV19(Layout, {
|
|
3325
|
+
breadcrumb: BREADCRUMBS[screen],
|
|
2747
3326
|
children: [
|
|
2748
|
-
screen === "main" && /* @__PURE__ */
|
|
3327
|
+
screen === "main" && /* @__PURE__ */ jsxDEV19(MainMenu, {
|
|
2749
3328
|
onSelect: setScreen
|
|
2750
3329
|
}, undefined, false, undefined, this),
|
|
2751
|
-
screen === "config" && /* @__PURE__ */
|
|
2752
|
-
onBack:
|
|
3330
|
+
screen === "config" && /* @__PURE__ */ jsxDEV19(ConfigMenu, {
|
|
3331
|
+
onBack: goBack
|
|
2753
3332
|
}, undefined, false, undefined, this),
|
|
2754
|
-
screen === "packages" && /* @__PURE__ */
|
|
2755
|
-
onBack:
|
|
3333
|
+
screen === "packages" && /* @__PURE__ */ jsxDEV19(PackageMenu, {
|
|
3334
|
+
onBack: goBack
|
|
2756
3335
|
}, undefined, false, undefined, this),
|
|
2757
|
-
screen === "themes" && /* @__PURE__ */
|
|
2758
|
-
onBack:
|
|
3336
|
+
screen === "themes" && /* @__PURE__ */ jsxDEV19(ThemeMenu, {
|
|
3337
|
+
onBack: goBack
|
|
2759
3338
|
}, undefined, false, undefined, this)
|
|
2760
3339
|
]
|
|
2761
3340
|
}, undefined, true, undefined, this);
|
|
2762
3341
|
}
|
|
2763
|
-
render(/* @__PURE__ */
|
|
3342
|
+
render(/* @__PURE__ */ jsxDEV19(App, {}, undefined, false, undefined, this));
|