formalconf 2.0.2 → 2.0.4
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 +900 -156
- package/package.json +1 -1
package/dist/formalconf.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// src/cli/formalconf.tsx
|
|
3
|
-
import { useState as
|
|
4
|
-
import { render, useApp as useApp2, useInput as
|
|
3
|
+
import { useState as useState11, useEffect as useEffect6 } from "react";
|
|
4
|
+
import { render, useApp as useApp2, useInput as useInput11 } from "ink";
|
|
5
5
|
import { Spinner as Spinner2 } from "@inkjs/ui";
|
|
6
6
|
|
|
7
7
|
// src/components/layout/Layout.tsx
|
|
@@ -41,6 +41,7 @@ import { existsSync, readlinkSync, readdirSync, lstatSync } from "fs";
|
|
|
41
41
|
// src/lib/paths.ts
|
|
42
42
|
import { homedir } from "os";
|
|
43
43
|
import { join } from "path";
|
|
44
|
+
import { readdir } from "fs/promises";
|
|
44
45
|
|
|
45
46
|
// src/lib/runtime.ts
|
|
46
47
|
import { spawn as nodeSpawn } from "child_process";
|
|
@@ -294,6 +295,19 @@ async function ensureConfigDir() {
|
|
|
294
295
|
await ensureDir2(THEME_TARGET_DIR);
|
|
295
296
|
await ensureDir2(BACKGROUNDS_TARGET_DIR);
|
|
296
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
|
+
}
|
|
297
311
|
|
|
298
312
|
// src/hooks/useSystemStatus.ts
|
|
299
313
|
import { basename, dirname as dirname2, join as join2 } from "path";
|
|
@@ -400,7 +414,7 @@ function StatusIndicator({
|
|
|
400
414
|
// package.json
|
|
401
415
|
var package_default = {
|
|
402
416
|
name: "formalconf",
|
|
403
|
-
version: "2.0.
|
|
417
|
+
version: "2.0.4",
|
|
404
418
|
description: "Dotfiles management TUI for macOS - config management, package sync, and theme switching",
|
|
405
419
|
type: "module",
|
|
406
420
|
main: "./dist/formalconf.js",
|
|
@@ -684,8 +698,9 @@ function PrerequisiteError({ missing, onExit }) {
|
|
|
684
698
|
}, undefined, false, undefined, this);
|
|
685
699
|
}
|
|
686
700
|
|
|
687
|
-
// src/components/
|
|
688
|
-
import {
|
|
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";
|
|
689
704
|
|
|
690
705
|
// src/components/ui/VimSelect.tsx
|
|
691
706
|
import { useState as useState3 } from "react";
|
|
@@ -721,13 +736,502 @@ function VimSelect({ options, onChange, isDisabled = false }) {
|
|
|
721
736
|
}, undefined, false, undefined, this);
|
|
722
737
|
}
|
|
723
738
|
|
|
724
|
-
// src/
|
|
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
|
|
725
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,
|
|
982
|
+
children: [
|
|
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)
|
|
997
|
+
]
|
|
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,
|
|
1022
|
+
children: [
|
|
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)
|
|
1060
|
+
]
|
|
1061
|
+
}, undefined, true, undefined, this)
|
|
1062
|
+
}, undefined, false, undefined, this)
|
|
1063
|
+
}, undefined, false, undefined, this);
|
|
1064
|
+
}
|
|
1065
|
+
function ThemesStep({
|
|
1066
|
+
onNext,
|
|
1067
|
+
onCreate
|
|
1068
|
+
}) {
|
|
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();
|
|
1137
|
+
}
|
|
1138
|
+
});
|
|
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)
|
|
1224
|
+
}, undefined, false, undefined, this);
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
// src/components/menus/MainMenu.tsx
|
|
1228
|
+
import { useApp } from "ink";
|
|
1229
|
+
import { jsxDEV as jsxDEV10 } from "react/jsx-dev-runtime";
|
|
726
1230
|
function MainMenu({ onSelect }) {
|
|
727
1231
|
const { exit } = useApp();
|
|
728
|
-
return /* @__PURE__ */
|
|
1232
|
+
return /* @__PURE__ */ jsxDEV10(Panel, {
|
|
729
1233
|
title: "Main Menu",
|
|
730
|
-
children: /* @__PURE__ */
|
|
1234
|
+
children: /* @__PURE__ */ jsxDEV10(VimSelect, {
|
|
731
1235
|
options: [
|
|
732
1236
|
{ label: "Config Manager", value: "config" },
|
|
733
1237
|
{ label: "Package Sync", value: "packages" },
|
|
@@ -746,33 +1250,33 @@ function MainMenu({ onSelect }) {
|
|
|
746
1250
|
}
|
|
747
1251
|
|
|
748
1252
|
// src/components/CommandOutput.tsx
|
|
749
|
-
import { Box as
|
|
750
|
-
import { jsxDEV as
|
|
1253
|
+
import { Box as Box10, Text as Text9, useInput as useInput4 } from "ink";
|
|
1254
|
+
import { jsxDEV as jsxDEV11 } from "react/jsx-dev-runtime";
|
|
751
1255
|
function CommandOutput({
|
|
752
1256
|
title,
|
|
753
1257
|
output,
|
|
754
1258
|
success = true,
|
|
755
1259
|
onDismiss
|
|
756
1260
|
}) {
|
|
757
|
-
|
|
1261
|
+
useInput4(() => {
|
|
758
1262
|
onDismiss();
|
|
759
1263
|
});
|
|
760
|
-
return /* @__PURE__ */
|
|
1264
|
+
return /* @__PURE__ */ jsxDEV11(Panel, {
|
|
761
1265
|
title,
|
|
762
1266
|
borderColor: success ? colors.success : colors.error,
|
|
763
1267
|
children: [
|
|
764
|
-
output && /* @__PURE__ */
|
|
1268
|
+
output && /* @__PURE__ */ jsxDEV11(Box10, {
|
|
765
1269
|
flexDirection: "column",
|
|
766
1270
|
marginBottom: 1,
|
|
767
|
-
children: /* @__PURE__ */
|
|
1271
|
+
children: /* @__PURE__ */ jsxDEV11(Text9, {
|
|
768
1272
|
children: output
|
|
769
1273
|
}, undefined, false, undefined, this)
|
|
770
1274
|
}, undefined, false, undefined, this),
|
|
771
|
-
/* @__PURE__ */
|
|
1275
|
+
/* @__PURE__ */ jsxDEV11(Text9, {
|
|
772
1276
|
color: success ? colors.success : colors.error,
|
|
773
1277
|
children: success ? "Done" : "Failed"
|
|
774
1278
|
}, undefined, false, undefined, this),
|
|
775
|
-
/* @__PURE__ */
|
|
1279
|
+
/* @__PURE__ */ jsxDEV11(Text9, {
|
|
776
1280
|
dimColor: true,
|
|
777
1281
|
children: "Press any key to continue..."
|
|
778
1282
|
}, undefined, false, undefined, this)
|
|
@@ -782,22 +1286,22 @@ function CommandOutput({
|
|
|
782
1286
|
|
|
783
1287
|
// src/components/LoadingPanel.tsx
|
|
784
1288
|
import { Spinner } from "@inkjs/ui";
|
|
785
|
-
import { jsxDEV as
|
|
1289
|
+
import { jsxDEV as jsxDEV12 } from "react/jsx-dev-runtime";
|
|
786
1290
|
function LoadingPanel({ title, label = "Processing..." }) {
|
|
787
|
-
return /* @__PURE__ */
|
|
1291
|
+
return /* @__PURE__ */ jsxDEV12(Panel, {
|
|
788
1292
|
title,
|
|
789
|
-
children: /* @__PURE__ */
|
|
1293
|
+
children: /* @__PURE__ */ jsxDEV12(Spinner, {
|
|
790
1294
|
label
|
|
791
1295
|
}, undefined, false, undefined, this)
|
|
792
1296
|
}, undefined, false, undefined, this);
|
|
793
1297
|
}
|
|
794
1298
|
|
|
795
1299
|
// src/hooks/useMenuAction.ts
|
|
796
|
-
import { useState as
|
|
1300
|
+
import { useState as useState5, useCallback } from "react";
|
|
797
1301
|
function useMenuAction() {
|
|
798
|
-
const [state, setState] =
|
|
799
|
-
const [output, setOutput] =
|
|
800
|
-
const [success, setSuccess] =
|
|
1302
|
+
const [state, setState] = useState5("menu");
|
|
1303
|
+
const [output, setOutput] = useState5("");
|
|
1304
|
+
const [success, setSuccess] = useState5(true);
|
|
801
1305
|
const execute = useCallback(async (action) => {
|
|
802
1306
|
setState("running");
|
|
803
1307
|
const result = await action();
|
|
@@ -820,12 +1324,12 @@ function useMenuAction() {
|
|
|
820
1324
|
}
|
|
821
1325
|
|
|
822
1326
|
// src/hooks/useBackNavigation.ts
|
|
823
|
-
import { useInput as
|
|
1327
|
+
import { useInput as useInput5 } from "ink";
|
|
824
1328
|
function useBackNavigation({
|
|
825
1329
|
enabled = true,
|
|
826
1330
|
onBack
|
|
827
1331
|
}) {
|
|
828
|
-
|
|
1332
|
+
useInput5((input, key) => {
|
|
829
1333
|
if (enabled && (key.escape || key.leftArrow || input === "h")) {
|
|
830
1334
|
onBack();
|
|
831
1335
|
}
|
|
@@ -834,7 +1338,7 @@ function useBackNavigation({
|
|
|
834
1338
|
|
|
835
1339
|
// src/cli/config-manager.ts
|
|
836
1340
|
import { parseArgs } from "util";
|
|
837
|
-
import { readdirSync as readdirSync2, existsSync as
|
|
1341
|
+
import { readdirSync as readdirSync2, existsSync as existsSync3, lstatSync as lstatSync2, readlinkSync as readlinkSync2 } from "fs";
|
|
838
1342
|
var colors2 = {
|
|
839
1343
|
red: "\x1B[0;31m",
|
|
840
1344
|
green: "\x1B[0;32m",
|
|
@@ -859,12 +1363,12 @@ function listPackages() {
|
|
|
859
1363
|
}
|
|
860
1364
|
function checkPackageStowed(packageName) {
|
|
861
1365
|
const packageDir = `${CONFIGS_DIR}/${packageName}`;
|
|
862
|
-
if (!
|
|
1366
|
+
if (!existsSync3(packageDir))
|
|
863
1367
|
return false;
|
|
864
1368
|
const entries = readdirSync2(packageDir, { withFileTypes: true });
|
|
865
1369
|
for (const entry of entries) {
|
|
866
1370
|
const targetPath = `${HOME_DIR}/${entry.name}`;
|
|
867
|
-
if (!
|
|
1371
|
+
if (!existsSync3(targetPath))
|
|
868
1372
|
return false;
|
|
869
1373
|
try {
|
|
870
1374
|
const stat = lstatSync2(targetPath);
|
|
@@ -1130,7 +1634,7 @@ if (isMainModule) {
|
|
|
1130
1634
|
}
|
|
1131
1635
|
|
|
1132
1636
|
// src/components/menus/ConfigMenu.tsx
|
|
1133
|
-
import { jsxDEV as
|
|
1637
|
+
import { jsxDEV as jsxDEV13 } from "react/jsx-dev-runtime";
|
|
1134
1638
|
function ConfigMenu({ onBack }) {
|
|
1135
1639
|
const { state, output, success, isRunning, isResult, execute, reset } = useMenuAction();
|
|
1136
1640
|
useBackNavigation({ enabled: state === "menu", onBack });
|
|
@@ -1142,21 +1646,21 @@ function ConfigMenu({ onBack }) {
|
|
|
1142
1646
|
await execute(() => runConfigManager([action]));
|
|
1143
1647
|
};
|
|
1144
1648
|
if (isRunning) {
|
|
1145
|
-
return /* @__PURE__ */
|
|
1649
|
+
return /* @__PURE__ */ jsxDEV13(LoadingPanel, {
|
|
1146
1650
|
title: "Config Manager"
|
|
1147
1651
|
}, undefined, false, undefined, this);
|
|
1148
1652
|
}
|
|
1149
1653
|
if (isResult) {
|
|
1150
|
-
return /* @__PURE__ */
|
|
1654
|
+
return /* @__PURE__ */ jsxDEV13(CommandOutput, {
|
|
1151
1655
|
title: "Config Manager",
|
|
1152
1656
|
output,
|
|
1153
1657
|
success,
|
|
1154
1658
|
onDismiss: reset
|
|
1155
1659
|
}, undefined, false, undefined, this);
|
|
1156
1660
|
}
|
|
1157
|
-
return /* @__PURE__ */
|
|
1661
|
+
return /* @__PURE__ */ jsxDEV13(Panel, {
|
|
1158
1662
|
title: "Config Manager",
|
|
1159
|
-
children: /* @__PURE__ */
|
|
1663
|
+
children: /* @__PURE__ */ jsxDEV13(VimSelect, {
|
|
1160
1664
|
options: [
|
|
1161
1665
|
{ label: "Stow all packages", value: "stow-all" },
|
|
1162
1666
|
{ label: "Unstow all packages", value: "unstow-all" },
|
|
@@ -1170,13 +1674,13 @@ function ConfigMenu({ onBack }) {
|
|
|
1170
1674
|
}
|
|
1171
1675
|
|
|
1172
1676
|
// src/components/menus/PackageMenu.tsx
|
|
1173
|
-
import { useState as
|
|
1174
|
-
import { Box as
|
|
1677
|
+
import { useState as useState8, useCallback as useCallback2, useMemo as useMemo2, useRef } from "react";
|
|
1678
|
+
import { Box as Box14, Text as Text13, useInput as useInput9 } from "ink";
|
|
1175
1679
|
|
|
1176
1680
|
// src/components/ScrollableLog.tsx
|
|
1177
|
-
import { useState as
|
|
1178
|
-
import { Box as
|
|
1179
|
-
import { jsxDEV as
|
|
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";
|
|
1180
1684
|
function ScrollableLog({
|
|
1181
1685
|
lines,
|
|
1182
1686
|
maxHeight,
|
|
@@ -1185,8 +1689,8 @@ function ScrollableLog({
|
|
|
1185
1689
|
}) {
|
|
1186
1690
|
const { rows } = useTerminalSize();
|
|
1187
1691
|
const visibleLines = maxHeight || Math.max(5, rows - 12);
|
|
1188
|
-
const [scrollOffset, setScrollOffset] =
|
|
1189
|
-
const [isAutoScrolling, setIsAutoScrolling] =
|
|
1692
|
+
const [scrollOffset, setScrollOffset] = useState6(0);
|
|
1693
|
+
const [isAutoScrolling, setIsAutoScrolling] = useState6(autoScroll);
|
|
1190
1694
|
const totalLines = lines.length;
|
|
1191
1695
|
const maxOffset = Math.max(0, totalLines - visibleLines);
|
|
1192
1696
|
useEffect3(() => {
|
|
@@ -1194,7 +1698,7 @@ function ScrollableLog({
|
|
|
1194
1698
|
setScrollOffset(maxOffset);
|
|
1195
1699
|
}
|
|
1196
1700
|
}, [totalLines, maxOffset, isAutoScrolling]);
|
|
1197
|
-
|
|
1701
|
+
useInput6((input, key) => {
|
|
1198
1702
|
if (key.downArrow || input === "j") {
|
|
1199
1703
|
setIsAutoScrolling(false);
|
|
1200
1704
|
setScrollOffset((prev) => Math.min(prev + 1, maxOffset));
|
|
@@ -1217,10 +1721,10 @@ function ScrollableLog({
|
|
|
1217
1721
|
}, [lines, scrollOffset, visibleLines]);
|
|
1218
1722
|
const showScrollUp = scrollOffset > 0;
|
|
1219
1723
|
const showScrollDown = scrollOffset < maxOffset;
|
|
1220
|
-
return /* @__PURE__ */
|
|
1724
|
+
return /* @__PURE__ */ jsxDEV14(Box11, {
|
|
1221
1725
|
flexDirection: "column",
|
|
1222
1726
|
children: [
|
|
1223
|
-
showScrollHint && showScrollUp && /* @__PURE__ */
|
|
1727
|
+
showScrollHint && showScrollUp && /* @__PURE__ */ jsxDEV14(Text10, {
|
|
1224
1728
|
dimColor: true,
|
|
1225
1729
|
children: [
|
|
1226
1730
|
" ↑ ",
|
|
@@ -1229,15 +1733,15 @@ function ScrollableLog({
|
|
|
1229
1733
|
scrollOffset !== 1 ? "s" : ""
|
|
1230
1734
|
]
|
|
1231
1735
|
}, undefined, true, undefined, this),
|
|
1232
|
-
/* @__PURE__ */
|
|
1736
|
+
/* @__PURE__ */ jsxDEV14(Box11, {
|
|
1233
1737
|
flexDirection: "column",
|
|
1234
1738
|
height: visibleLines,
|
|
1235
1739
|
overflow: "hidden",
|
|
1236
|
-
children: visibleContent.map((line, i) => /* @__PURE__ */
|
|
1740
|
+
children: visibleContent.map((line, i) => /* @__PURE__ */ jsxDEV14(Text10, {
|
|
1237
1741
|
children: line
|
|
1238
1742
|
}, scrollOffset + i, false, undefined, this))
|
|
1239
1743
|
}, undefined, false, undefined, this),
|
|
1240
|
-
showScrollHint && showScrollDown && /* @__PURE__ */
|
|
1744
|
+
showScrollHint && showScrollDown && /* @__PURE__ */ jsxDEV14(Text10, {
|
|
1241
1745
|
dimColor: true,
|
|
1242
1746
|
children: [
|
|
1243
1747
|
" ↓ ",
|
|
@@ -1246,7 +1750,7 @@ function ScrollableLog({
|
|
|
1246
1750
|
maxOffset - scrollOffset !== 1 ? "s" : ""
|
|
1247
1751
|
]
|
|
1248
1752
|
}, undefined, true, undefined, this),
|
|
1249
|
-
showScrollHint && totalLines > visibleLines && /* @__PURE__ */
|
|
1753
|
+
showScrollHint && totalLines > visibleLines && /* @__PURE__ */ jsxDEV14(Text10, {
|
|
1250
1754
|
dimColor: true,
|
|
1251
1755
|
children: [
|
|
1252
1756
|
"j/k scroll • g top • G bottom ",
|
|
@@ -1258,29 +1762,29 @@ function ScrollableLog({
|
|
|
1258
1762
|
}
|
|
1259
1763
|
|
|
1260
1764
|
// src/components/PromptInput.tsx
|
|
1261
|
-
import { Box as
|
|
1262
|
-
import { jsxDEV as
|
|
1765
|
+
import { Box as Box12, Text as Text11, useInput as useInput7 } from "ink";
|
|
1766
|
+
import { jsxDEV as jsxDEV15 } from "react/jsx-dev-runtime";
|
|
1263
1767
|
function PromptInput({
|
|
1264
1768
|
question,
|
|
1265
1769
|
options = ["y", "n"],
|
|
1266
1770
|
onAnswer
|
|
1267
1771
|
}) {
|
|
1268
|
-
|
|
1772
|
+
useInput7((input) => {
|
|
1269
1773
|
const lower = input.toLowerCase();
|
|
1270
1774
|
if (options.includes(lower)) {
|
|
1271
1775
|
onAnswer(lower);
|
|
1272
1776
|
}
|
|
1273
1777
|
});
|
|
1274
|
-
return /* @__PURE__ */
|
|
1778
|
+
return /* @__PURE__ */ jsxDEV15(Box12, {
|
|
1275
1779
|
marginTop: 1,
|
|
1276
1780
|
borderStyle: "single",
|
|
1277
1781
|
borderColor: colors.accent,
|
|
1278
1782
|
paddingX: 1,
|
|
1279
|
-
children: /* @__PURE__ */
|
|
1783
|
+
children: /* @__PURE__ */ jsxDEV15(Text11, {
|
|
1280
1784
|
children: [
|
|
1281
1785
|
question,
|
|
1282
1786
|
" ",
|
|
1283
|
-
/* @__PURE__ */
|
|
1787
|
+
/* @__PURE__ */ jsxDEV15(Text11, {
|
|
1284
1788
|
color: colors.accent,
|
|
1285
1789
|
children: [
|
|
1286
1790
|
"[",
|
|
@@ -1288,7 +1792,7 @@ function PromptInput({
|
|
|
1288
1792
|
"]"
|
|
1289
1793
|
]
|
|
1290
1794
|
}, undefined, true, undefined, this),
|
|
1291
|
-
/* @__PURE__ */
|
|
1795
|
+
/* @__PURE__ */ jsxDEV15(Text11, {
|
|
1292
1796
|
dimColor: true,
|
|
1293
1797
|
children: ": "
|
|
1294
1798
|
}, undefined, false, undefined, this)
|
|
@@ -1297,11 +1801,147 @@ function PromptInput({
|
|
|
1297
1801
|
}, undefined, false, undefined, this);
|
|
1298
1802
|
}
|
|
1299
1803
|
|
|
1804
|
+
// src/components/OrphanTable.tsx
|
|
1805
|
+
import { useState as useState7 } from "react";
|
|
1806
|
+
import { Box as Box13, Text as Text12, useInput as useInput8 } from "ink";
|
|
1807
|
+
import { jsxDEV as jsxDEV16 } from "react/jsx-dev-runtime";
|
|
1808
|
+
function OrphanTable({ result, onAction, onDismiss }) {
|
|
1809
|
+
const [selectedIndex, setSelectedIndex] = useState7(0);
|
|
1810
|
+
const { orphans } = result;
|
|
1811
|
+
useInput8((input, key) => {
|
|
1812
|
+
if (orphans.length > 0) {
|
|
1813
|
+
if (input === "j" || key.downArrow) {
|
|
1814
|
+
setSelectedIndex((i) => Math.min(i + 1, orphans.length - 1));
|
|
1815
|
+
}
|
|
1816
|
+
if (input === "k" || key.upArrow) {
|
|
1817
|
+
setSelectedIndex((i) => Math.max(i - 1, 0));
|
|
1818
|
+
}
|
|
1819
|
+
if (input === "a") {
|
|
1820
|
+
onAction("add", orphans[selectedIndex]);
|
|
1821
|
+
}
|
|
1822
|
+
if (input === "x") {
|
|
1823
|
+
onAction("uninstall", orphans[selectedIndex]);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
if (key.escape || input === "h" || key.leftArrow) {
|
|
1827
|
+
onDismiss();
|
|
1828
|
+
}
|
|
1829
|
+
});
|
|
1830
|
+
const borderColor = orphans.length > 0 ? colors.warning : colors.success;
|
|
1831
|
+
return /* @__PURE__ */ jsxDEV16(Panel, {
|
|
1832
|
+
title: "Orphaned Packages",
|
|
1833
|
+
borderColor,
|
|
1834
|
+
children: [
|
|
1835
|
+
/* @__PURE__ */ jsxDEV16(Box13, {
|
|
1836
|
+
marginBottom: 1,
|
|
1837
|
+
children: /* @__PURE__ */ jsxDEV16(Text12, {
|
|
1838
|
+
dimColor: true,
|
|
1839
|
+
children: [
|
|
1840
|
+
"Config: ",
|
|
1841
|
+
result.configFormulas,
|
|
1842
|
+
" formulas, ",
|
|
1843
|
+
result.configCasks,
|
|
1844
|
+
" casks | Installed: ",
|
|
1845
|
+
result.installedLeaves,
|
|
1846
|
+
" leaves, ",
|
|
1847
|
+
result.installedCasks,
|
|
1848
|
+
" ",
|
|
1849
|
+
"casks"
|
|
1850
|
+
]
|
|
1851
|
+
}, undefined, true, undefined, this)
|
|
1852
|
+
}, undefined, false, undefined, this),
|
|
1853
|
+
orphans.length === 0 ? /* @__PURE__ */ jsxDEV16(Box13, {
|
|
1854
|
+
flexDirection: "column",
|
|
1855
|
+
children: [
|
|
1856
|
+
/* @__PURE__ */ jsxDEV16(Text12, {
|
|
1857
|
+
color: colors.success,
|
|
1858
|
+
children: "No orphaned packages found!"
|
|
1859
|
+
}, undefined, false, undefined, this),
|
|
1860
|
+
/* @__PURE__ */ jsxDEV16(Text12, {
|
|
1861
|
+
dimColor: true,
|
|
1862
|
+
children: "All installed packages are in your config."
|
|
1863
|
+
}, undefined, false, undefined, this)
|
|
1864
|
+
]
|
|
1865
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV16(Box13, {
|
|
1866
|
+
flexDirection: "column",
|
|
1867
|
+
children: [
|
|
1868
|
+
/* @__PURE__ */ jsxDEV16(Text12, {
|
|
1869
|
+
color: colors.warning,
|
|
1870
|
+
children: [
|
|
1871
|
+
"Found ",
|
|
1872
|
+
orphans.length,
|
|
1873
|
+
" orphaned package",
|
|
1874
|
+
orphans.length !== 1 ? "s" : "",
|
|
1875
|
+
":"
|
|
1876
|
+
]
|
|
1877
|
+
}, undefined, true, undefined, this),
|
|
1878
|
+
/* @__PURE__ */ jsxDEV16(Box13, {
|
|
1879
|
+
marginTop: 1,
|
|
1880
|
+
flexDirection: "column",
|
|
1881
|
+
children: [
|
|
1882
|
+
/* @__PURE__ */ jsxDEV16(Box13, {
|
|
1883
|
+
children: [
|
|
1884
|
+
/* @__PURE__ */ jsxDEV16(Text12, {
|
|
1885
|
+
bold: true,
|
|
1886
|
+
children: [
|
|
1887
|
+
" ",
|
|
1888
|
+
"Name"
|
|
1889
|
+
]
|
|
1890
|
+
}, undefined, true, undefined, this),
|
|
1891
|
+
/* @__PURE__ */ jsxDEV16(Text12, {
|
|
1892
|
+
bold: true,
|
|
1893
|
+
children: [
|
|
1894
|
+
" ".repeat(28),
|
|
1895
|
+
"Type"
|
|
1896
|
+
]
|
|
1897
|
+
}, undefined, true, undefined, this)
|
|
1898
|
+
]
|
|
1899
|
+
}, undefined, true, undefined, this),
|
|
1900
|
+
/* @__PURE__ */ jsxDEV16(Text12, {
|
|
1901
|
+
color: colors.border,
|
|
1902
|
+
children: "─".repeat(50)
|
|
1903
|
+
}, undefined, false, undefined, this),
|
|
1904
|
+
orphans.map((pkg, i) => {
|
|
1905
|
+
const isSelected = i === selectedIndex;
|
|
1906
|
+
return /* @__PURE__ */ jsxDEV16(Box13, {
|
|
1907
|
+
children: [
|
|
1908
|
+
/* @__PURE__ */ jsxDEV16(Text12, {
|
|
1909
|
+
color: isSelected ? colors.primary : undefined,
|
|
1910
|
+
children: [
|
|
1911
|
+
isSelected ? "❯ " : " ",
|
|
1912
|
+
pkg.name.padEnd(30)
|
|
1913
|
+
]
|
|
1914
|
+
}, undefined, true, undefined, this),
|
|
1915
|
+
/* @__PURE__ */ jsxDEV16(Text12, {
|
|
1916
|
+
color: pkg.type === "formula" ? colors.info : colors.accent,
|
|
1917
|
+
children: pkg.type
|
|
1918
|
+
}, undefined, false, undefined, this)
|
|
1919
|
+
]
|
|
1920
|
+
}, `${pkg.type}-${pkg.name}`, true, undefined, this);
|
|
1921
|
+
})
|
|
1922
|
+
]
|
|
1923
|
+
}, undefined, true, undefined, this)
|
|
1924
|
+
]
|
|
1925
|
+
}, undefined, true, undefined, this),
|
|
1926
|
+
/* @__PURE__ */ jsxDEV16(Box13, {
|
|
1927
|
+
marginTop: 1,
|
|
1928
|
+
children: orphans.length > 0 ? /* @__PURE__ */ jsxDEV16(Text12, {
|
|
1929
|
+
dimColor: true,
|
|
1930
|
+
children: "j/k navigate | a add to config | x uninstall | esc/h back | q quit"
|
|
1931
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV16(Text12, {
|
|
1932
|
+
dimColor: true,
|
|
1933
|
+
children: "esc/h back | q quit"
|
|
1934
|
+
}, undefined, false, undefined, this)
|
|
1935
|
+
}, undefined, false, undefined, this)
|
|
1936
|
+
]
|
|
1937
|
+
}, undefined, true, undefined, this);
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1300
1940
|
// src/cli/pkg-sync.ts
|
|
1301
1941
|
import { parseArgs as parseArgs2 } from "util";
|
|
1302
1942
|
|
|
1303
1943
|
// src/lib/config.ts
|
|
1304
|
-
import { existsSync as
|
|
1944
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1305
1945
|
var DEFAULT_CONFIG = {
|
|
1306
1946
|
config: {
|
|
1307
1947
|
purge: false,
|
|
@@ -1316,7 +1956,7 @@ var DEFAULT_CONFIG = {
|
|
|
1316
1956
|
async function loadPkgConfig(path) {
|
|
1317
1957
|
await ensureConfigDir();
|
|
1318
1958
|
const configPath = path || PKG_CONFIG_PATH;
|
|
1319
|
-
if (!
|
|
1959
|
+
if (!existsSync4(configPath)) {
|
|
1320
1960
|
await savePkgConfig(DEFAULT_CONFIG, configPath);
|
|
1321
1961
|
return DEFAULT_CONFIG;
|
|
1322
1962
|
}
|
|
@@ -1328,7 +1968,7 @@ async function savePkgConfig(config, path) {
|
|
|
1328
1968
|
await writeFile(configPath, JSON.stringify(config, null, 2));
|
|
1329
1969
|
}
|
|
1330
1970
|
async function loadPkgLock() {
|
|
1331
|
-
if (!
|
|
1971
|
+
if (!existsSync4(PKG_LOCK_PATH)) {
|
|
1332
1972
|
return null;
|
|
1333
1973
|
}
|
|
1334
1974
|
return readJson(PKG_LOCK_PATH);
|
|
@@ -2109,21 +2749,88 @@ if (isMainModule3) {
|
|
|
2109
2749
|
main3().catch(console.error);
|
|
2110
2750
|
}
|
|
2111
2751
|
|
|
2752
|
+
// src/lib/orphan-detector.ts
|
|
2753
|
+
function getPackageName(fullName) {
|
|
2754
|
+
const parts = fullName.split("/");
|
|
2755
|
+
return parts[parts.length - 1];
|
|
2756
|
+
}
|
|
2757
|
+
async function detectOrphanedPackages() {
|
|
2758
|
+
const config = await loadPkgConfig();
|
|
2759
|
+
const leavesResult = await exec(["brew", "leaves"]);
|
|
2760
|
+
const installedLeaves = leavesResult.success ? leavesResult.stdout.split(`
|
|
2761
|
+
`).filter(Boolean) : [];
|
|
2762
|
+
const casksResult = await exec(["brew", "list", "--cask"]);
|
|
2763
|
+
const installedCasks = casksResult.success ? casksResult.stdout.split(`
|
|
2764
|
+
`).filter(Boolean) : [];
|
|
2765
|
+
const orphans = [];
|
|
2766
|
+
const configPackages = config.packages.map((pkg) => ({
|
|
2767
|
+
full: pkg,
|
|
2768
|
+
short: getPackageName(pkg)
|
|
2769
|
+
}));
|
|
2770
|
+
for (const installed of installedLeaves) {
|
|
2771
|
+
const installedShort = getPackageName(installed);
|
|
2772
|
+
const isInConfig = configPackages.some((cfg) => installed === cfg.full || installed === cfg.short || installedShort === cfg.full || installedShort === cfg.short || installed.endsWith(`/${cfg.short}`));
|
|
2773
|
+
if (!isInConfig) {
|
|
2774
|
+
orphans.push({ name: installed, type: "formula" });
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
const configCasksSet = new Set(config.casks);
|
|
2778
|
+
for (const cask of installedCasks) {
|
|
2779
|
+
if (!configCasksSet.has(cask)) {
|
|
2780
|
+
orphans.push({ name: cask, type: "cask" });
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
orphans.sort((a, b) => {
|
|
2784
|
+
if (a.type !== b.type)
|
|
2785
|
+
return a.type === "formula" ? -1 : 1;
|
|
2786
|
+
return a.name.localeCompare(b.name);
|
|
2787
|
+
});
|
|
2788
|
+
return {
|
|
2789
|
+
orphans,
|
|
2790
|
+
configFormulas: config.packages.length,
|
|
2791
|
+
configCasks: config.casks.length,
|
|
2792
|
+
installedLeaves: installedLeaves.length,
|
|
2793
|
+
installedCasks: installedCasks.length
|
|
2794
|
+
};
|
|
2795
|
+
}
|
|
2796
|
+
async function addToConfig(pkg) {
|
|
2797
|
+
const config = await loadPkgConfig();
|
|
2798
|
+
if (pkg.type === "formula") {
|
|
2799
|
+
if (!config.packages.includes(pkg.name)) {
|
|
2800
|
+
config.packages.push(pkg.name);
|
|
2801
|
+
config.packages.sort();
|
|
2802
|
+
}
|
|
2803
|
+
} else {
|
|
2804
|
+
if (!config.casks.includes(pkg.name)) {
|
|
2805
|
+
config.casks.push(pkg.name);
|
|
2806
|
+
config.casks.sort();
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
await savePkgConfig(config);
|
|
2810
|
+
}
|
|
2811
|
+
async function uninstallPackage(pkg) {
|
|
2812
|
+
const cmd = pkg.type === "cask" ? ["brew", "uninstall", "--cask", pkg.name] : ["brew", "uninstall", pkg.name];
|
|
2813
|
+
const result = await exec(cmd);
|
|
2814
|
+
return result.success;
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2112
2817
|
// src/components/menus/PackageMenu.tsx
|
|
2113
|
-
import { jsxDEV as
|
|
2818
|
+
import { jsxDEV as jsxDEV17 } from "react/jsx-dev-runtime";
|
|
2114
2819
|
function PackageMenu({ onBack }) {
|
|
2115
|
-
const [state, setState] =
|
|
2116
|
-
const [lines, setLines] =
|
|
2117
|
-
const [output, setOutput] =
|
|
2118
|
-
const [isStreamingOp, setIsStreamingOp] =
|
|
2119
|
-
const [pendingPrompt, setPendingPrompt] =
|
|
2120
|
-
const [success, setSuccess] =
|
|
2820
|
+
const [state, setState] = useState8("menu");
|
|
2821
|
+
const [lines, setLines] = useState8([]);
|
|
2822
|
+
const [output, setOutput] = useState8("");
|
|
2823
|
+
const [isStreamingOp, setIsStreamingOp] = useState8(true);
|
|
2824
|
+
const [pendingPrompt, setPendingPrompt] = useState8(null);
|
|
2825
|
+
const [success, setSuccess] = useState8(true);
|
|
2826
|
+
const [orphanResult, setOrphanResult] = useState8(null);
|
|
2827
|
+
const [isOrphanView, setIsOrphanView] = useState8(false);
|
|
2121
2828
|
const isRunningRef = useRef(false);
|
|
2122
|
-
|
|
2829
|
+
useInput9((input, key) => {
|
|
2123
2830
|
if (state === "menu" && (key.escape || key.leftArrow || input === "h")) {
|
|
2124
2831
|
onBack();
|
|
2125
2832
|
}
|
|
2126
|
-
if (state === "result") {
|
|
2833
|
+
if (state === "result" && !isOrphanView) {
|
|
2127
2834
|
setState("menu");
|
|
2128
2835
|
setLines([]);
|
|
2129
2836
|
}
|
|
@@ -2185,6 +2892,13 @@ function PackageMenu({ onBack }) {
|
|
|
2185
2892
|
result = await runPkgLock(["status"]);
|
|
2186
2893
|
setOutput(result.output);
|
|
2187
2894
|
break;
|
|
2895
|
+
case "orphans":
|
|
2896
|
+
setIsStreamingOp(false);
|
|
2897
|
+
setIsOrphanView(true);
|
|
2898
|
+
const orphanData = await detectOrphanedPackages();
|
|
2899
|
+
setOrphanResult(orphanData);
|
|
2900
|
+
result = { output: "", success: true };
|
|
2901
|
+
break;
|
|
2188
2902
|
default:
|
|
2189
2903
|
setIsStreamingOp(false);
|
|
2190
2904
|
result = { output: "Unknown action", success: false };
|
|
@@ -2196,17 +2910,17 @@ function PackageMenu({ onBack }) {
|
|
|
2196
2910
|
};
|
|
2197
2911
|
if (state === "running") {
|
|
2198
2912
|
if (!isStreamingOp) {
|
|
2199
|
-
return /* @__PURE__ */
|
|
2913
|
+
return /* @__PURE__ */ jsxDEV17(LoadingPanel, {
|
|
2200
2914
|
title: "Package Sync"
|
|
2201
2915
|
}, undefined, false, undefined, this);
|
|
2202
2916
|
}
|
|
2203
|
-
return /* @__PURE__ */
|
|
2917
|
+
return /* @__PURE__ */ jsxDEV17(Panel, {
|
|
2204
2918
|
title: "Package Sync",
|
|
2205
2919
|
children: [
|
|
2206
|
-
/* @__PURE__ */
|
|
2920
|
+
/* @__PURE__ */ jsxDEV17(ScrollableLog, {
|
|
2207
2921
|
lines
|
|
2208
2922
|
}, undefined, false, undefined, this),
|
|
2209
|
-
pendingPrompt && /* @__PURE__ */
|
|
2923
|
+
pendingPrompt && /* @__PURE__ */ jsxDEV17(PromptInput, {
|
|
2210
2924
|
question: pendingPrompt.question,
|
|
2211
2925
|
options: pendingPrompt.options,
|
|
2212
2926
|
onAnswer: handlePromptAnswer
|
|
@@ -2215,39 +2929,58 @@ function PackageMenu({ onBack }) {
|
|
|
2215
2929
|
}, undefined, true, undefined, this);
|
|
2216
2930
|
}
|
|
2217
2931
|
if (state === "result") {
|
|
2932
|
+
if (isOrphanView && orphanResult) {
|
|
2933
|
+
const handleOrphanAction = async (action, pkg) => {
|
|
2934
|
+
if (action === "add") {
|
|
2935
|
+
await addToConfig(pkg);
|
|
2936
|
+
} else {
|
|
2937
|
+
await uninstallPackage(pkg);
|
|
2938
|
+
}
|
|
2939
|
+
const updated = await detectOrphanedPackages();
|
|
2940
|
+
setOrphanResult(updated);
|
|
2941
|
+
};
|
|
2942
|
+
return /* @__PURE__ */ jsxDEV17(OrphanTable, {
|
|
2943
|
+
result: orphanResult,
|
|
2944
|
+
onAction: handleOrphanAction,
|
|
2945
|
+
onDismiss: () => {
|
|
2946
|
+
setIsOrphanView(false);
|
|
2947
|
+
setState("menu");
|
|
2948
|
+
}
|
|
2949
|
+
}, undefined, false, undefined, this);
|
|
2950
|
+
}
|
|
2218
2951
|
if (!isStreamingOp) {
|
|
2219
|
-
return /* @__PURE__ */
|
|
2952
|
+
return /* @__PURE__ */ jsxDEV17(CommandOutput, {
|
|
2220
2953
|
title: "Package Sync",
|
|
2221
2954
|
output,
|
|
2222
2955
|
success,
|
|
2223
2956
|
onDismiss: () => setState("menu")
|
|
2224
2957
|
}, undefined, false, undefined, this);
|
|
2225
2958
|
}
|
|
2226
|
-
return /* @__PURE__ */
|
|
2959
|
+
return /* @__PURE__ */ jsxDEV17(Panel, {
|
|
2227
2960
|
title: "Package Sync",
|
|
2228
2961
|
borderColor: success ? colors.success : colors.error,
|
|
2229
2962
|
children: [
|
|
2230
|
-
/* @__PURE__ */
|
|
2963
|
+
/* @__PURE__ */ jsxDEV17(ScrollableLog, {
|
|
2231
2964
|
lines,
|
|
2232
2965
|
autoScroll: false
|
|
2233
2966
|
}, undefined, false, undefined, this),
|
|
2234
|
-
/* @__PURE__ */
|
|
2967
|
+
/* @__PURE__ */ jsxDEV17(Box14, {
|
|
2235
2968
|
marginTop: 1,
|
|
2236
|
-
children: /* @__PURE__ */
|
|
2969
|
+
children: /* @__PURE__ */ jsxDEV17(Text13, {
|
|
2237
2970
|
color: success ? colors.success : colors.error,
|
|
2238
2971
|
children: success ? "Done" : "Failed"
|
|
2239
2972
|
}, undefined, false, undefined, this)
|
|
2240
2973
|
}, undefined, false, undefined, this),
|
|
2241
|
-
/* @__PURE__ */
|
|
2974
|
+
/* @__PURE__ */ jsxDEV17(Text13, {
|
|
2242
2975
|
dimColor: true,
|
|
2243
2976
|
children: "Press any key to continue..."
|
|
2244
2977
|
}, undefined, false, undefined, this)
|
|
2245
2978
|
]
|
|
2246
2979
|
}, undefined, true, undefined, this);
|
|
2247
2980
|
}
|
|
2248
|
-
return /* @__PURE__ */
|
|
2981
|
+
return /* @__PURE__ */ jsxDEV17(Panel, {
|
|
2249
2982
|
title: "Package Sync",
|
|
2250
|
-
children: /* @__PURE__ */
|
|
2983
|
+
children: /* @__PURE__ */ jsxDEV17(VimSelect, {
|
|
2251
2984
|
options: [
|
|
2252
2985
|
{ label: "Sync packages", value: "sync" },
|
|
2253
2986
|
{ label: "Sync with purge", value: "sync-purge" },
|
|
@@ -2255,6 +2988,7 @@ function PackageMenu({ onBack }) {
|
|
|
2255
2988
|
{ label: "Upgrade interactive", value: "upgrade-interactive" },
|
|
2256
2989
|
{ label: "Update lockfile", value: "lock-update" },
|
|
2257
2990
|
{ label: "Lockfile status", value: "lock-status" },
|
|
2991
|
+
{ label: "Find orphaned packages", value: "orphans" },
|
|
2258
2992
|
{ label: "Back", value: "back" }
|
|
2259
2993
|
],
|
|
2260
2994
|
onChange: handleAction
|
|
@@ -2263,14 +2997,14 @@ function PackageMenu({ onBack }) {
|
|
|
2263
2997
|
}
|
|
2264
2998
|
|
|
2265
2999
|
// src/components/menus/ThemeMenu.tsx
|
|
2266
|
-
import { useState as
|
|
2267
|
-
import { Box as
|
|
2268
|
-
import { existsSync as
|
|
2269
|
-
import { join as
|
|
3000
|
+
import { useState as useState10, useEffect as useEffect5, useMemo as useMemo4 } from "react";
|
|
3001
|
+
import { Box as Box16, Text as Text15 } from "ink";
|
|
3002
|
+
import { existsSync as existsSync7, readdirSync as readdirSync5 } from "fs";
|
|
3003
|
+
import { join as join6 } from "path";
|
|
2270
3004
|
|
|
2271
3005
|
// src/components/ThemeCard.tsx
|
|
2272
|
-
import { Box as
|
|
2273
|
-
import { jsxDEV as
|
|
3006
|
+
import { Box as Box15, Text as Text14 } from "ink";
|
|
3007
|
+
import { jsxDEV as jsxDEV18 } from "react/jsx-dev-runtime";
|
|
2274
3008
|
function ThemeCard({ theme, isSelected, width }) {
|
|
2275
3009
|
const borderColor = isSelected ? colors.accent : colors.border;
|
|
2276
3010
|
const nameColor = isSelected ? colors.primary : colors.text;
|
|
@@ -2280,25 +3014,25 @@ function ThemeCard({ theme, isSelected, width }) {
|
|
|
2280
3014
|
if (theme.isLightMode)
|
|
2281
3015
|
indicators.push("light");
|
|
2282
3016
|
const indicatorText = indicators.length > 0 ? ` [${indicators.join(" ")}]` : "";
|
|
2283
|
-
return /* @__PURE__ */
|
|
3017
|
+
return /* @__PURE__ */ jsxDEV18(Box15, {
|
|
2284
3018
|
flexDirection: "column",
|
|
2285
3019
|
width,
|
|
2286
3020
|
borderStyle: borderStyles.panel,
|
|
2287
3021
|
borderColor,
|
|
2288
3022
|
paddingX: 1,
|
|
2289
|
-
children: /* @__PURE__ */
|
|
3023
|
+
children: /* @__PURE__ */ jsxDEV18(Box15, {
|
|
2290
3024
|
children: [
|
|
2291
|
-
/* @__PURE__ */
|
|
3025
|
+
/* @__PURE__ */ jsxDEV18(Text14, {
|
|
2292
3026
|
color: isSelected ? colors.accent : colors.primaryDim,
|
|
2293
3027
|
children: isSelected ? "● " : " "
|
|
2294
3028
|
}, undefined, false, undefined, this),
|
|
2295
|
-
/* @__PURE__ */
|
|
3029
|
+
/* @__PURE__ */ jsxDEV18(Text14, {
|
|
2296
3030
|
color: nameColor,
|
|
2297
3031
|
bold: true,
|
|
2298
3032
|
wrap: "truncate",
|
|
2299
3033
|
children: theme.name
|
|
2300
3034
|
}, undefined, false, undefined, this),
|
|
2301
|
-
/* @__PURE__ */
|
|
3035
|
+
/* @__PURE__ */ jsxDEV18(Text14, {
|
|
2302
3036
|
color: colors.primaryDim,
|
|
2303
3037
|
children: indicatorText
|
|
2304
3038
|
}, undefined, false, undefined, this)
|
|
@@ -2308,8 +3042,8 @@ function ThemeCard({ theme, isSelected, width }) {
|
|
|
2308
3042
|
}
|
|
2309
3043
|
|
|
2310
3044
|
// src/hooks/useThemeGrid.ts
|
|
2311
|
-
import { useState as
|
|
2312
|
-
import { useInput as
|
|
3045
|
+
import { useState as useState9, useEffect as useEffect4 } from "react";
|
|
3046
|
+
import { useInput as useInput10 } from "ink";
|
|
2313
3047
|
function useThemeGrid({
|
|
2314
3048
|
itemCount,
|
|
2315
3049
|
cardHeight = 3,
|
|
@@ -2320,8 +3054,8 @@ function useThemeGrid({
|
|
|
2320
3054
|
enabled = true
|
|
2321
3055
|
}) {
|
|
2322
3056
|
const { columns, rows } = useTerminalSize();
|
|
2323
|
-
const [selectedIndex, setSelectedIndex] =
|
|
2324
|
-
const [scrollOffset, setScrollOffset] =
|
|
3057
|
+
const [selectedIndex, setSelectedIndex] = useState9(0);
|
|
3058
|
+
const [scrollOffset, setScrollOffset] = useState9(0);
|
|
2325
3059
|
const availableWidth = columns - 6;
|
|
2326
3060
|
const cardsPerRow = Math.max(1, Math.floor(availableWidth / minCardWidth));
|
|
2327
3061
|
const cardWidth = Math.floor(availableWidth / cardsPerRow);
|
|
@@ -2336,7 +3070,7 @@ function useThemeGrid({
|
|
|
2336
3070
|
setScrollOffset(selectedRow - visibleRows + 1);
|
|
2337
3071
|
}
|
|
2338
3072
|
}, [selectedRow, scrollOffset, visibleRows]);
|
|
2339
|
-
|
|
3073
|
+
useInput10((input, key) => {
|
|
2340
3074
|
if (!enabled)
|
|
2341
3075
|
return;
|
|
2342
3076
|
if (key.escape && onBack) {
|
|
@@ -2387,8 +3121,8 @@ function useThemeGrid({
|
|
|
2387
3121
|
}
|
|
2388
3122
|
|
|
2389
3123
|
// src/lib/theme-parser.ts
|
|
2390
|
-
import { existsSync as
|
|
2391
|
-
import { join as
|
|
3124
|
+
import { existsSync as existsSync5, readdirSync as readdirSync3 } from "fs";
|
|
3125
|
+
import { join as join4 } from "path";
|
|
2392
3126
|
function parseYaml(content) {
|
|
2393
3127
|
const result = {};
|
|
2394
3128
|
const lines = content.split(`
|
|
@@ -2419,8 +3153,8 @@ function parseYaml(content) {
|
|
|
2419
3153
|
return result;
|
|
2420
3154
|
}
|
|
2421
3155
|
async function parseThemeMetadata(themePath) {
|
|
2422
|
-
const yamlPath =
|
|
2423
|
-
if (!
|
|
3156
|
+
const yamlPath = join4(themePath, "theme.yaml");
|
|
3157
|
+
if (!existsSync5(yamlPath)) {
|
|
2424
3158
|
return;
|
|
2425
3159
|
}
|
|
2426
3160
|
try {
|
|
@@ -2442,7 +3176,7 @@ function parseThemeFiles(themePath) {
|
|
|
2442
3176
|
const entries = readdirSync3(themePath, { withFileTypes: true });
|
|
2443
3177
|
return entries.filter((e) => e.isFile() && !e.name.startsWith(".") && e.name !== "theme.yaml" && e.name !== "light.mode").map((e) => ({
|
|
2444
3178
|
name: e.name,
|
|
2445
|
-
path:
|
|
3179
|
+
path: join4(themePath, e.name),
|
|
2446
3180
|
application: e.name.replace(/\.(conf|theme|lua|toml|css|json|ini)$/, "")
|
|
2447
3181
|
}));
|
|
2448
3182
|
}
|
|
@@ -2454,16 +3188,16 @@ async function parseTheme(themePath, themeName) {
|
|
|
2454
3188
|
path: themePath,
|
|
2455
3189
|
files,
|
|
2456
3190
|
metadata,
|
|
2457
|
-
hasBackgrounds:
|
|
2458
|
-
hasPreview:
|
|
2459
|
-
isLightMode:
|
|
3191
|
+
hasBackgrounds: existsSync5(join4(themePath, "backgrounds")),
|
|
3192
|
+
hasPreview: existsSync5(join4(themePath, "preview.png")),
|
|
3193
|
+
isLightMode: existsSync5(join4(themePath, "light.mode"))
|
|
2460
3194
|
};
|
|
2461
3195
|
}
|
|
2462
3196
|
|
|
2463
3197
|
// src/cli/set-theme.ts
|
|
2464
3198
|
import { parseArgs as parseArgs4 } from "util";
|
|
2465
|
-
import { readdirSync as readdirSync4, existsSync as
|
|
2466
|
-
import { join as
|
|
3199
|
+
import { readdirSync as readdirSync4, existsSync as existsSync6, rmSync, symlinkSync, unlinkSync } from "fs";
|
|
3200
|
+
import { join as join5 } from "path";
|
|
2467
3201
|
var colors5 = {
|
|
2468
3202
|
red: "\x1B[0;31m",
|
|
2469
3203
|
green: "\x1B[0;32m",
|
|
@@ -2475,14 +3209,14 @@ var colors5 = {
|
|
|
2475
3209
|
};
|
|
2476
3210
|
async function listThemes() {
|
|
2477
3211
|
await ensureConfigDir();
|
|
2478
|
-
if (!
|
|
3212
|
+
if (!existsSync6(THEMES_DIR)) {
|
|
2479
3213
|
return [];
|
|
2480
3214
|
}
|
|
2481
3215
|
const entries = readdirSync4(THEMES_DIR, { withFileTypes: true });
|
|
2482
3216
|
const themes = [];
|
|
2483
3217
|
for (const entry of entries) {
|
|
2484
3218
|
if (entry.isDirectory()) {
|
|
2485
|
-
const themePath =
|
|
3219
|
+
const themePath = join5(THEMES_DIR, entry.name);
|
|
2486
3220
|
const theme = await parseTheme(themePath, entry.name);
|
|
2487
3221
|
themes.push(theme);
|
|
2488
3222
|
}
|
|
@@ -2490,10 +3224,10 @@ async function listThemes() {
|
|
|
2490
3224
|
return themes;
|
|
2491
3225
|
}
|
|
2492
3226
|
function clearDirectory(dir) {
|
|
2493
|
-
if (
|
|
3227
|
+
if (existsSync6(dir)) {
|
|
2494
3228
|
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
2495
3229
|
for (const entry of entries) {
|
|
2496
|
-
const fullPath =
|
|
3230
|
+
const fullPath = join5(dir, entry.name);
|
|
2497
3231
|
if (entry.isSymbolicLink() || entry.isFile()) {
|
|
2498
3232
|
unlinkSync(fullPath);
|
|
2499
3233
|
} else if (entry.isDirectory()) {
|
|
@@ -2503,33 +3237,33 @@ function clearDirectory(dir) {
|
|
|
2503
3237
|
}
|
|
2504
3238
|
}
|
|
2505
3239
|
function createSymlink(source, target) {
|
|
2506
|
-
if (
|
|
3240
|
+
if (existsSync6(target)) {
|
|
2507
3241
|
unlinkSync(target);
|
|
2508
3242
|
}
|
|
2509
3243
|
symlinkSync(source, target);
|
|
2510
3244
|
}
|
|
2511
3245
|
async function applyTheme(themeName) {
|
|
2512
|
-
const themeDir =
|
|
2513
|
-
if (!
|
|
3246
|
+
const themeDir = join5(THEMES_DIR, themeName);
|
|
3247
|
+
if (!existsSync6(themeDir)) {
|
|
2514
3248
|
return { output: `Theme '${themeName}' not found`, success: false };
|
|
2515
3249
|
}
|
|
2516
3250
|
await ensureConfigDir();
|
|
2517
3251
|
await ensureDir2(THEME_TARGET_DIR);
|
|
2518
3252
|
const theme = await parseTheme(themeDir, themeName);
|
|
2519
3253
|
clearDirectory(THEME_TARGET_DIR);
|
|
2520
|
-
if (
|
|
3254
|
+
if (existsSync6(BACKGROUNDS_TARGET_DIR)) {
|
|
2521
3255
|
rmSync(BACKGROUNDS_TARGET_DIR, { recursive: true, force: true });
|
|
2522
3256
|
}
|
|
2523
3257
|
const entries = readdirSync4(themeDir, { withFileTypes: true });
|
|
2524
3258
|
for (const entry of entries) {
|
|
2525
|
-
const source =
|
|
3259
|
+
const source = join5(themeDir, entry.name);
|
|
2526
3260
|
if (entry.isFile() && entry.name !== "theme.yaml" && entry.name !== "light.mode") {
|
|
2527
|
-
const target =
|
|
3261
|
+
const target = join5(THEME_TARGET_DIR, entry.name);
|
|
2528
3262
|
createSymlink(source, target);
|
|
2529
3263
|
}
|
|
2530
3264
|
}
|
|
2531
3265
|
if (theme.hasBackgrounds) {
|
|
2532
|
-
const backgroundsSource =
|
|
3266
|
+
const backgroundsSource = join5(themeDir, "backgrounds");
|
|
2533
3267
|
createSymlink(backgroundsSource, BACKGROUNDS_TARGET_DIR);
|
|
2534
3268
|
}
|
|
2535
3269
|
let output = `Theme '${theme.name}' applied successfully`;
|
|
@@ -2548,8 +3282,8 @@ Note: This is a light mode theme`;
|
|
|
2548
3282
|
return { output, success: true };
|
|
2549
3283
|
}
|
|
2550
3284
|
async function showThemeInfo(themeName) {
|
|
2551
|
-
const themeDir =
|
|
2552
|
-
if (!
|
|
3285
|
+
const themeDir = join5(THEMES_DIR, themeName);
|
|
3286
|
+
if (!existsSync6(themeDir)) {
|
|
2553
3287
|
console.error(`${colors5.red}Error: Theme '${themeName}' not found${colors5.reset}`);
|
|
2554
3288
|
process.exit(1);
|
|
2555
3289
|
}
|
|
@@ -2631,10 +3365,10 @@ if (isMainModule4) {
|
|
|
2631
3365
|
}
|
|
2632
3366
|
|
|
2633
3367
|
// src/components/menus/ThemeMenu.tsx
|
|
2634
|
-
import { jsxDEV as
|
|
3368
|
+
import { jsxDEV as jsxDEV19 } from "react/jsx-dev-runtime";
|
|
2635
3369
|
function ThemeMenu({ onBack }) {
|
|
2636
|
-
const [themes, setThemes] =
|
|
2637
|
-
const [loading, setLoading] =
|
|
3370
|
+
const [themes, setThemes] = useState10([]);
|
|
3371
|
+
const [loading, setLoading] = useState10(true);
|
|
2638
3372
|
const { state, output, success, isRunning, isResult, execute, reset } = useMenuAction();
|
|
2639
3373
|
const grid = useThemeGrid({
|
|
2640
3374
|
itemCount: themes.length,
|
|
@@ -2644,7 +3378,7 @@ function ThemeMenu({ onBack }) {
|
|
|
2644
3378
|
});
|
|
2645
3379
|
useEffect5(() => {
|
|
2646
3380
|
async function loadThemes() {
|
|
2647
|
-
if (!
|
|
3381
|
+
if (!existsSync7(THEMES_DIR)) {
|
|
2648
3382
|
setThemes([]);
|
|
2649
3383
|
setLoading(false);
|
|
2650
3384
|
return;
|
|
@@ -2653,7 +3387,7 @@ function ThemeMenu({ onBack }) {
|
|
|
2653
3387
|
const loadedThemes = [];
|
|
2654
3388
|
for (const entry of entries) {
|
|
2655
3389
|
if (entry.isDirectory()) {
|
|
2656
|
-
const themePath =
|
|
3390
|
+
const themePath = join6(THEMES_DIR, entry.name);
|
|
2657
3391
|
const theme = await parseTheme(themePath, entry.name);
|
|
2658
3392
|
loadedThemes.push(theme);
|
|
2659
3393
|
}
|
|
@@ -2671,13 +3405,13 @@ function ThemeMenu({ onBack }) {
|
|
|
2671
3405
|
return themes.slice(grid.visibleStartIndex, grid.visibleEndIndex);
|
|
2672
3406
|
}, [themes, grid.visibleStartIndex, grid.visibleEndIndex]);
|
|
2673
3407
|
if (loading || isRunning) {
|
|
2674
|
-
return /* @__PURE__ */
|
|
3408
|
+
return /* @__PURE__ */ jsxDEV19(LoadingPanel, {
|
|
2675
3409
|
title: "Select Theme",
|
|
2676
3410
|
label: loading ? "Loading themes..." : "Applying theme..."
|
|
2677
3411
|
}, undefined, false, undefined, this);
|
|
2678
3412
|
}
|
|
2679
3413
|
if (isResult) {
|
|
2680
|
-
return /* @__PURE__ */
|
|
3414
|
+
return /* @__PURE__ */ jsxDEV19(CommandOutput, {
|
|
2681
3415
|
title: "Select Theme",
|
|
2682
3416
|
output,
|
|
2683
3417
|
success,
|
|
@@ -2685,28 +3419,28 @@ function ThemeMenu({ onBack }) {
|
|
|
2685
3419
|
}, undefined, false, undefined, this);
|
|
2686
3420
|
}
|
|
2687
3421
|
if (themes.length === 0) {
|
|
2688
|
-
return /* @__PURE__ */
|
|
3422
|
+
return /* @__PURE__ */ jsxDEV19(Panel, {
|
|
2689
3423
|
title: "Select Theme",
|
|
2690
3424
|
children: [
|
|
2691
|
-
/* @__PURE__ */
|
|
3425
|
+
/* @__PURE__ */ jsxDEV19(Box16, {
|
|
2692
3426
|
flexDirection: "column",
|
|
2693
3427
|
children: [
|
|
2694
|
-
/* @__PURE__ */
|
|
3428
|
+
/* @__PURE__ */ jsxDEV19(Text15, {
|
|
2695
3429
|
color: colors.warning,
|
|
2696
3430
|
children: "No themes available."
|
|
2697
3431
|
}, undefined, false, undefined, this),
|
|
2698
|
-
/* @__PURE__ */
|
|
3432
|
+
/* @__PURE__ */ jsxDEV19(Text15, {
|
|
2699
3433
|
children: "This system is compatible with omarchy themes."
|
|
2700
3434
|
}, undefined, false, undefined, this),
|
|
2701
|
-
/* @__PURE__ */
|
|
3435
|
+
/* @__PURE__ */ jsxDEV19(Text15, {
|
|
2702
3436
|
dimColor: true,
|
|
2703
3437
|
children: "Add themes to ~/.config/formalconf/themes/"
|
|
2704
3438
|
}, undefined, false, undefined, this)
|
|
2705
3439
|
]
|
|
2706
3440
|
}, undefined, true, undefined, this),
|
|
2707
|
-
/* @__PURE__ */
|
|
3441
|
+
/* @__PURE__ */ jsxDEV19(Box16, {
|
|
2708
3442
|
marginTop: 1,
|
|
2709
|
-
children: /* @__PURE__ */
|
|
3443
|
+
children: /* @__PURE__ */ jsxDEV19(VimSelect, {
|
|
2710
3444
|
options: [{ label: "Back", value: "back" }],
|
|
2711
3445
|
onChange: () => onBack()
|
|
2712
3446
|
}, undefined, false, undefined, this)
|
|
@@ -2714,10 +3448,10 @@ function ThemeMenu({ onBack }) {
|
|
|
2714
3448
|
]
|
|
2715
3449
|
}, undefined, true, undefined, this);
|
|
2716
3450
|
}
|
|
2717
|
-
return /* @__PURE__ */
|
|
3451
|
+
return /* @__PURE__ */ jsxDEV19(Panel, {
|
|
2718
3452
|
title: "Select Theme",
|
|
2719
3453
|
children: [
|
|
2720
|
-
grid.showScrollUp && /* @__PURE__ */
|
|
3454
|
+
grid.showScrollUp && /* @__PURE__ */ jsxDEV19(Text15, {
|
|
2721
3455
|
dimColor: true,
|
|
2722
3456
|
children: [
|
|
2723
3457
|
" ",
|
|
@@ -2727,18 +3461,18 @@ function ThemeMenu({ onBack }) {
|
|
|
2727
3461
|
grid.scrollOffset > 1 ? "s" : ""
|
|
2728
3462
|
]
|
|
2729
3463
|
}, undefined, true, undefined, this),
|
|
2730
|
-
/* @__PURE__ */
|
|
3464
|
+
/* @__PURE__ */ jsxDEV19(Box16, {
|
|
2731
3465
|
flexDirection: "row",
|
|
2732
3466
|
flexWrap: "wrap",
|
|
2733
3467
|
height: grid.gridHeight,
|
|
2734
3468
|
overflow: "hidden",
|
|
2735
|
-
children: visibleThemes.map((theme, index) => /* @__PURE__ */
|
|
3469
|
+
children: visibleThemes.map((theme, index) => /* @__PURE__ */ jsxDEV19(ThemeCard, {
|
|
2736
3470
|
theme,
|
|
2737
3471
|
isSelected: grid.visibleStartIndex + index === grid.selectedIndex,
|
|
2738
3472
|
width: grid.cardWidth
|
|
2739
3473
|
}, theme.path, false, undefined, this))
|
|
2740
3474
|
}, undefined, false, undefined, this),
|
|
2741
|
-
grid.showScrollDown && /* @__PURE__ */
|
|
3475
|
+
grid.showScrollDown && /* @__PURE__ */ jsxDEV19(Text15, {
|
|
2742
3476
|
dimColor: true,
|
|
2743
3477
|
children: [
|
|
2744
3478
|
" ",
|
|
@@ -2748,9 +3482,9 @@ function ThemeMenu({ onBack }) {
|
|
|
2748
3482
|
grid.totalRows - grid.scrollOffset - grid.visibleRows > 1 ? "s" : ""
|
|
2749
3483
|
]
|
|
2750
3484
|
}, undefined, true, undefined, this),
|
|
2751
|
-
/* @__PURE__ */
|
|
3485
|
+
/* @__PURE__ */ jsxDEV19(Box16, {
|
|
2752
3486
|
marginTop: 1,
|
|
2753
|
-
children: /* @__PURE__ */
|
|
3487
|
+
children: /* @__PURE__ */ jsxDEV19(Text15, {
|
|
2754
3488
|
dimColor: true,
|
|
2755
3489
|
children: "←→↑↓/hjkl navigate • Enter select • Esc back"
|
|
2756
3490
|
}, undefined, false, undefined, this)
|
|
@@ -2760,7 +3494,7 @@ function ThemeMenu({ onBack }) {
|
|
|
2760
3494
|
}
|
|
2761
3495
|
|
|
2762
3496
|
// src/cli/formalconf.tsx
|
|
2763
|
-
import { jsxDEV as
|
|
3497
|
+
import { jsxDEV as jsxDEV20 } from "react/jsx-dev-runtime";
|
|
2764
3498
|
var BREADCRUMBS = {
|
|
2765
3499
|
main: ["Main"],
|
|
2766
3500
|
config: ["Main", "Config Manager"],
|
|
@@ -2768,61 +3502,71 @@ var BREADCRUMBS = {
|
|
|
2768
3502
|
themes: ["Main", "Themes"]
|
|
2769
3503
|
};
|
|
2770
3504
|
function App() {
|
|
2771
|
-
const [appState, setAppState] =
|
|
2772
|
-
const [missingDeps, setMissingDeps] =
|
|
2773
|
-
const [screen, setScreen] =
|
|
3505
|
+
const [appState, setAppState] = useState11("loading");
|
|
3506
|
+
const [missingDeps, setMissingDeps] = useState11([]);
|
|
3507
|
+
const [screen, setScreen] = useState11("main");
|
|
2774
3508
|
const { exit } = useApp2();
|
|
2775
|
-
|
|
3509
|
+
useInput11((input) => {
|
|
2776
3510
|
if (input === "q")
|
|
2777
3511
|
exit();
|
|
2778
3512
|
});
|
|
2779
3513
|
useEffect6(() => {
|
|
2780
3514
|
async function init() {
|
|
2781
|
-
ensureConfigDir();
|
|
3515
|
+
await ensureConfigDir();
|
|
2782
3516
|
const result = await checkPrerequisites();
|
|
2783
3517
|
if (!result.ok) {
|
|
2784
3518
|
setMissingDeps(result.missing);
|
|
2785
3519
|
setAppState("error");
|
|
2786
|
-
|
|
2787
|
-
setAppState("ready");
|
|
3520
|
+
return;
|
|
2788
3521
|
}
|
|
3522
|
+
const firstRun = await isFirstRun();
|
|
3523
|
+
if (firstRun) {
|
|
3524
|
+
setAppState("onboarding");
|
|
3525
|
+
return;
|
|
3526
|
+
}
|
|
3527
|
+
setAppState("ready");
|
|
2789
3528
|
}
|
|
2790
3529
|
init();
|
|
2791
3530
|
}, []);
|
|
2792
3531
|
if (appState === "loading") {
|
|
2793
|
-
return /* @__PURE__ */
|
|
3532
|
+
return /* @__PURE__ */ jsxDEV20(Layout, {
|
|
2794
3533
|
breadcrumb: ["Loading"],
|
|
2795
|
-
children: /* @__PURE__ */
|
|
3534
|
+
children: /* @__PURE__ */ jsxDEV20(Panel, {
|
|
2796
3535
|
title: "FormalConf",
|
|
2797
|
-
children: /* @__PURE__ */
|
|
3536
|
+
children: /* @__PURE__ */ jsxDEV20(Spinner2, {
|
|
2798
3537
|
label: "Checking prerequisites..."
|
|
2799
3538
|
}, undefined, false, undefined, this)
|
|
2800
3539
|
}, undefined, false, undefined, this)
|
|
2801
3540
|
}, undefined, false, undefined, this);
|
|
2802
3541
|
}
|
|
2803
3542
|
if (appState === "error") {
|
|
2804
|
-
return /* @__PURE__ */
|
|
3543
|
+
return /* @__PURE__ */ jsxDEV20(PrerequisiteError, {
|
|
2805
3544
|
missing: missingDeps,
|
|
2806
3545
|
onExit: exit
|
|
2807
3546
|
}, undefined, false, undefined, this);
|
|
2808
3547
|
}
|
|
3548
|
+
if (appState === "onboarding") {
|
|
3549
|
+
return /* @__PURE__ */ jsxDEV20(Onboarding, {
|
|
3550
|
+
onComplete: () => setAppState("ready")
|
|
3551
|
+
}, undefined, false, undefined, this);
|
|
3552
|
+
}
|
|
2809
3553
|
const goBack = () => setScreen("main");
|
|
2810
|
-
return /* @__PURE__ */
|
|
3554
|
+
return /* @__PURE__ */ jsxDEV20(Layout, {
|
|
2811
3555
|
breadcrumb: BREADCRUMBS[screen],
|
|
2812
3556
|
children: [
|
|
2813
|
-
screen === "main" && /* @__PURE__ */
|
|
3557
|
+
screen === "main" && /* @__PURE__ */ jsxDEV20(MainMenu, {
|
|
2814
3558
|
onSelect: setScreen
|
|
2815
3559
|
}, undefined, false, undefined, this),
|
|
2816
|
-
screen === "config" && /* @__PURE__ */
|
|
3560
|
+
screen === "config" && /* @__PURE__ */ jsxDEV20(ConfigMenu, {
|
|
2817
3561
|
onBack: goBack
|
|
2818
3562
|
}, undefined, false, undefined, this),
|
|
2819
|
-
screen === "packages" && /* @__PURE__ */
|
|
3563
|
+
screen === "packages" && /* @__PURE__ */ jsxDEV20(PackageMenu, {
|
|
2820
3564
|
onBack: goBack
|
|
2821
3565
|
}, undefined, false, undefined, this),
|
|
2822
|
-
screen === "themes" && /* @__PURE__ */
|
|
3566
|
+
screen === "themes" && /* @__PURE__ */ jsxDEV20(ThemeMenu, {
|
|
2823
3567
|
onBack: goBack
|
|
2824
3568
|
}, undefined, false, undefined, this)
|
|
2825
3569
|
]
|
|
2826
3570
|
}, undefined, true, undefined, this);
|
|
2827
3571
|
}
|
|
2828
|
-
render(/* @__PURE__ */
|
|
3572
|
+
render(/* @__PURE__ */ jsxDEV20(App, {}, undefined, false, undefined, this));
|