unity-hub-cli 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +435 -377
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -621,55 +621,133 @@ var UnityTempDirectoryCleaner = class {
|
|
|
621
621
|
|
|
622
622
|
// src/presentation/App.tsx
|
|
623
623
|
import clipboard from "clipboardy";
|
|
624
|
-
import { Box, Text, useApp, useInput, useStdout } from "ink";
|
|
625
|
-
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
624
|
+
import { Box as Box5, Text as Text3, useApp, useInput, useStdout } from "ink";
|
|
625
|
+
import { useCallback, useEffect as useEffect3, useMemo as useMemo2, useState as useState3 } from "react";
|
|
626
626
|
|
|
627
|
-
// src/
|
|
628
|
-
import {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
const home = process.env.HOME ?? "";
|
|
636
|
-
return `${home}/Library/Application Support/UnityHubCli`;
|
|
627
|
+
// src/presentation/components/LayoutManager.tsx
|
|
628
|
+
import { Box } from "ink";
|
|
629
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
630
|
+
var getLayoutMode = () => {
|
|
631
|
+
const value = process.env.UNITYHUBCLI_LAYOUT;
|
|
632
|
+
if (value === "right") return "rightPanel";
|
|
633
|
+
if (value === "screen") return "screenSwitch";
|
|
634
|
+
return "screenSwitch";
|
|
637
635
|
};
|
|
638
|
-
var
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
636
|
+
var LayoutManager = ({
|
|
637
|
+
layoutMode,
|
|
638
|
+
panelVisible,
|
|
639
|
+
list,
|
|
640
|
+
panel,
|
|
641
|
+
statusBar
|
|
642
|
+
}) => {
|
|
643
|
+
if (layoutMode === "rightPanel") {
|
|
644
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
645
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
646
|
+
/* @__PURE__ */ jsx(Box, { flexGrow: 1, children: list }),
|
|
647
|
+
panelVisible ? /* @__PURE__ */ jsx(Box, { marginLeft: 1, children: panel }) : null
|
|
648
|
+
] }),
|
|
649
|
+
/* @__PURE__ */ jsx(Box, { children: statusBar })
|
|
650
|
+
] });
|
|
644
651
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
652
|
+
if (layoutMode === "screenSwitch") {
|
|
653
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
654
|
+
/* @__PURE__ */ jsx(Box, { children: panelVisible ? panel : list }),
|
|
655
|
+
/* @__PURE__ */ jsx(Box, { children: statusBar })
|
|
656
|
+
] });
|
|
657
|
+
}
|
|
658
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
659
|
+
/* @__PURE__ */ jsx(Box, { children: list }),
|
|
660
|
+
panelVisible ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: panel }) : null,
|
|
661
|
+
/* @__PURE__ */ jsx(Box, { children: statusBar })
|
|
662
|
+
] });
|
|
650
663
|
};
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
664
|
+
|
|
665
|
+
// src/presentation/components/ProjectList.tsx
|
|
666
|
+
import { Box as Box3 } from "ink";
|
|
667
|
+
import { useMemo } from "react";
|
|
668
|
+
|
|
669
|
+
// src/presentation/utils/path.ts
|
|
670
|
+
var homeDirectory = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
671
|
+
var normalizedHomeDirectory = homeDirectory.replace(/\\/g, "/");
|
|
672
|
+
var homePrefix = normalizedHomeDirectory ? `${normalizedHomeDirectory}/` : "";
|
|
673
|
+
var shortenHomePath = (targetPath) => {
|
|
674
|
+
if (!normalizedHomeDirectory) {
|
|
675
|
+
return targetPath;
|
|
676
|
+
}
|
|
677
|
+
const normalizedTarget = targetPath.replace(/\\/g, "/");
|
|
678
|
+
if (normalizedTarget === normalizedHomeDirectory) {
|
|
679
|
+
return "~";
|
|
680
|
+
}
|
|
681
|
+
if (homePrefix && normalizedTarget.startsWith(homePrefix)) {
|
|
682
|
+
return `~/${normalizedTarget.slice(homePrefix.length)}`;
|
|
658
683
|
}
|
|
684
|
+
return targetPath;
|
|
659
685
|
};
|
|
660
|
-
var
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
686
|
+
var buildCdCommand = (targetPath) => {
|
|
687
|
+
if (process.platform === "win32") {
|
|
688
|
+
const escapedForWindows = targetPath.replace(/"/g, '""');
|
|
689
|
+
return `cd "${escapedForWindows}"`;
|
|
664
690
|
}
|
|
665
|
-
const
|
|
666
|
-
|
|
667
|
-
await writeFile2(getConfigPath(), json, "utf8");
|
|
691
|
+
const escapedForPosix = targetPath.replace(/'/g, "'\\''");
|
|
692
|
+
return `cd '${escapedForPosix}'`;
|
|
668
693
|
};
|
|
669
|
-
var getDefaultSortPreferences = () => defaultPreferences;
|
|
670
694
|
|
|
671
|
-
// src/presentation/
|
|
672
|
-
import {
|
|
695
|
+
// src/presentation/components/ProjectRow.tsx
|
|
696
|
+
import { Box as Box2, Text } from "ink";
|
|
697
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
698
|
+
var ProjectRow = ({
|
|
699
|
+
isSelected,
|
|
700
|
+
selectionBar,
|
|
701
|
+
projectName,
|
|
702
|
+
projectColor,
|
|
703
|
+
versionLabel,
|
|
704
|
+
updatedText,
|
|
705
|
+
statusLabel,
|
|
706
|
+
statusColor,
|
|
707
|
+
branchLine,
|
|
708
|
+
pathLine,
|
|
709
|
+
showBranch,
|
|
710
|
+
showPath,
|
|
711
|
+
scrollbar
|
|
712
|
+
}) => {
|
|
713
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", children: [
|
|
714
|
+
/* @__PURE__ */ jsxs2(Box2, { width: 1, flexDirection: "column", alignItems: "center", marginLeft: isSelected ? 1 : 0, children: [
|
|
715
|
+
/* @__PURE__ */ jsx2(Text, { color: isSelected ? "green" : void 0, children: selectionBar }),
|
|
716
|
+
showBranch ? /* @__PURE__ */ jsx2(Text, { color: isSelected ? "green" : void 0, children: selectionBar }) : null,
|
|
717
|
+
showPath ? /* @__PURE__ */ jsx2(Text, { color: isSelected ? "green" : void 0, children: selectionBar }) : null
|
|
718
|
+
] }),
|
|
719
|
+
/* @__PURE__ */ jsxs2(Box2, { flexGrow: 1, flexDirection: "column", marginLeft: isSelected ? 2 : 1, children: [
|
|
720
|
+
/* @__PURE__ */ jsxs2(Text, { wrap: "truncate", children: [
|
|
721
|
+
/* @__PURE__ */ jsx2(Text, { color: projectColor, bold: true, children: projectName }),
|
|
722
|
+
/* @__PURE__ */ jsxs2(Text, { children: [
|
|
723
|
+
" ",
|
|
724
|
+
versionLabel
|
|
725
|
+
] }),
|
|
726
|
+
updatedText ? /* @__PURE__ */ jsx2(Text, { children: ` ${updatedText}` }) : null,
|
|
727
|
+
statusLabel && statusColor ? /* @__PURE__ */ jsx2(Text, { color: statusColor, children: ` ${statusLabel}` }) : null
|
|
728
|
+
] }),
|
|
729
|
+
showBranch ? /* @__PURE__ */ jsx2(Text, { color: "#e3839c", wrap: "truncate", children: branchLine }) : null,
|
|
730
|
+
showPath ? /* @__PURE__ */ jsx2(Text, { color: "#719bd8", wrap: "truncate", children: pathLine }) : null,
|
|
731
|
+
/* @__PURE__ */ jsx2(Text, { children: " " })
|
|
732
|
+
] }),
|
|
733
|
+
/* @__PURE__ */ jsxs2(Box2, { marginLeft: 1, width: 1, flexDirection: "column", alignItems: "center", children: [
|
|
734
|
+
/* @__PURE__ */ jsx2(Text, { children: scrollbar.title }),
|
|
735
|
+
showBranch ? /* @__PURE__ */ jsx2(Text, { children: scrollbar.branch }) : null,
|
|
736
|
+
showPath ? /* @__PURE__ */ jsx2(Text, { children: scrollbar.path }) : null,
|
|
737
|
+
/* @__PURE__ */ jsx2(Text, { children: scrollbar.spacer })
|
|
738
|
+
] })
|
|
739
|
+
] });
|
|
740
|
+
};
|
|
741
|
+
|
|
742
|
+
// src/presentation/components/ProjectList.tsx
|
|
743
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
744
|
+
var PROJECT_COLOR = "#abd8e7";
|
|
745
|
+
var LOCK_COLOR = "yellow";
|
|
746
|
+
var STATUS_LABELS = {
|
|
747
|
+
idle: "",
|
|
748
|
+
running: "[running]",
|
|
749
|
+
crashed: "[crash]"
|
|
750
|
+
};
|
|
673
751
|
var extractRootFolder = (repository) => {
|
|
674
752
|
if (!repository?.root) {
|
|
675
753
|
return void 0;
|
|
@@ -680,13 +758,13 @@ var extractRootFolder = (repository) => {
|
|
|
680
758
|
}
|
|
681
759
|
return segments[segments.length - 1];
|
|
682
760
|
};
|
|
683
|
-
var formatProjectName = (
|
|
761
|
+
var formatProjectName = (projectTitle, repository, useGitRootName) => {
|
|
684
762
|
if (!useGitRootName) {
|
|
685
|
-
return
|
|
763
|
+
return projectTitle;
|
|
686
764
|
}
|
|
687
765
|
const rootFolder = extractRootFolder(repository);
|
|
688
766
|
if (!rootFolder) {
|
|
689
|
-
return
|
|
767
|
+
return projectTitle;
|
|
690
768
|
}
|
|
691
769
|
return rootFolder;
|
|
692
770
|
};
|
|
@@ -750,76 +828,269 @@ var formatUpdatedText = (lastModified) => {
|
|
|
750
828
|
}
|
|
751
829
|
return `${UPDATED_LABEL} ${relativeTime}`;
|
|
752
830
|
};
|
|
753
|
-
var
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
831
|
+
var ProjectList = ({
|
|
832
|
+
visibleProjects,
|
|
833
|
+
startIndex,
|
|
834
|
+
selectedIndex,
|
|
835
|
+
linesPerProject,
|
|
836
|
+
showBranch,
|
|
837
|
+
showPath,
|
|
838
|
+
useGitRootName,
|
|
839
|
+
releasedProjects,
|
|
840
|
+
launchedProjects,
|
|
841
|
+
totalProjects
|
|
842
|
+
}) => {
|
|
843
|
+
const scrollbarChars = useMemo(() => {
|
|
844
|
+
const totalLines = totalProjects * linesPerProject;
|
|
845
|
+
const windowProjects = visibleProjects.length;
|
|
846
|
+
const visibleLines = windowProjects * linesPerProject;
|
|
847
|
+
if (totalLines === 0 || visibleLines === 0) {
|
|
848
|
+
return [];
|
|
849
|
+
}
|
|
850
|
+
if (totalLines <= visibleLines) {
|
|
851
|
+
return Array.from({ length: visibleLines }, () => "\u2588");
|
|
852
|
+
}
|
|
853
|
+
const trackLength = visibleLines;
|
|
854
|
+
const sliderSize = Math.max(1, Math.round(visibleLines / totalLines * trackLength));
|
|
855
|
+
const maxSliderStart = Math.max(0, trackLength - sliderSize);
|
|
856
|
+
const topLine = startIndex * linesPerProject;
|
|
857
|
+
const denominator = Math.max(1, totalLines - visibleLines);
|
|
858
|
+
const sliderStart = Math.min(
|
|
859
|
+
maxSliderStart,
|
|
860
|
+
Math.round(topLine / denominator * maxSliderStart)
|
|
861
|
+
);
|
|
862
|
+
return Array.from({ length: trackLength }, (_, position) => {
|
|
863
|
+
if (position >= sliderStart && position < sliderStart + sliderSize) {
|
|
864
|
+
return "\u2588";
|
|
865
|
+
}
|
|
866
|
+
return "|";
|
|
867
|
+
});
|
|
868
|
+
}, [linesPerProject, startIndex, totalProjects, visibleProjects.length]);
|
|
869
|
+
const rows = useMemo(() => {
|
|
870
|
+
return visibleProjects.map(({ project, repository, launchStatus }, offset) => {
|
|
871
|
+
const rowIndex = startIndex + offset;
|
|
872
|
+
const isSelected = rowIndex === selectedIndex;
|
|
873
|
+
const selectionBar = isSelected ? "\u2503" : " ";
|
|
874
|
+
const projectName = formatProjectName(project.title, repository, useGitRootName);
|
|
875
|
+
const versionLabel = `(${project.version.value})`;
|
|
876
|
+
const updatedText = formatUpdatedText(project.lastModified);
|
|
877
|
+
const pathLine = shortenHomePath(project.path);
|
|
878
|
+
const branchLine = formatBranch(repository?.branch);
|
|
879
|
+
const hasReleasedLock = releasedProjects.has(project.id);
|
|
880
|
+
const isLocallyLaunched = launchedProjects.has(project.id);
|
|
881
|
+
const displayStatus = (() => {
|
|
882
|
+
if (isLocallyLaunched) {
|
|
883
|
+
return "running";
|
|
884
|
+
}
|
|
885
|
+
if (hasReleasedLock) {
|
|
886
|
+
return "idle";
|
|
887
|
+
}
|
|
888
|
+
return launchStatus;
|
|
889
|
+
})();
|
|
890
|
+
const baseScrollbarIndex = offset * linesPerProject;
|
|
891
|
+
const titleScrollbar = scrollbarChars[baseScrollbarIndex] ?? " ";
|
|
892
|
+
const branchScrollbar = showBranch ? scrollbarChars[baseScrollbarIndex + 1] ?? " " : " ";
|
|
893
|
+
const pathScrollbar = showPath ? scrollbarChars[baseScrollbarIndex + 1 + (showBranch ? 1 : 0)] ?? " " : " ";
|
|
894
|
+
const spacerScrollbar = scrollbarChars[baseScrollbarIndex + linesPerProject - 1] ?? " ";
|
|
895
|
+
const statusLabel = STATUS_LABELS[displayStatus];
|
|
896
|
+
const statusColor = displayStatus === "running" ? LOCK_COLOR : displayStatus === "crashed" ? "red" : void 0;
|
|
897
|
+
return /* @__PURE__ */ jsx3(
|
|
898
|
+
ProjectRow,
|
|
899
|
+
{
|
|
900
|
+
isSelected,
|
|
901
|
+
selectionBar,
|
|
902
|
+
projectName,
|
|
903
|
+
projectColor: PROJECT_COLOR,
|
|
904
|
+
versionLabel,
|
|
905
|
+
updatedText,
|
|
906
|
+
statusLabel,
|
|
907
|
+
statusColor,
|
|
908
|
+
branchLine,
|
|
909
|
+
pathLine,
|
|
910
|
+
showBranch,
|
|
911
|
+
showPath,
|
|
912
|
+
scrollbar: {
|
|
913
|
+
title: titleScrollbar,
|
|
914
|
+
branch: branchScrollbar,
|
|
915
|
+
path: pathScrollbar,
|
|
916
|
+
spacer: spacerScrollbar
|
|
917
|
+
}
|
|
918
|
+
},
|
|
919
|
+
project.id
|
|
920
|
+
);
|
|
921
|
+
});
|
|
922
|
+
}, [
|
|
923
|
+
launchedProjects,
|
|
924
|
+
releasedProjects,
|
|
925
|
+
scrollbarChars,
|
|
926
|
+
selectedIndex,
|
|
927
|
+
showBranch,
|
|
928
|
+
showPath,
|
|
929
|
+
startIndex,
|
|
930
|
+
useGitRootName,
|
|
931
|
+
visibleProjects,
|
|
932
|
+
linesPerProject
|
|
933
|
+
]);
|
|
934
|
+
return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: rows.length === 0 ? null : rows });
|
|
765
935
|
};
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
936
|
+
|
|
937
|
+
// src/presentation/components/SortPanel.tsx
|
|
938
|
+
import { Box as Box4, Text as Text2 } from "ink";
|
|
939
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
940
|
+
var lineForPrimary = (primary) => {
|
|
941
|
+
return `Primary: ${primary === "updated" ? "Updated" : "Name (Git root)"}`;
|
|
942
|
+
};
|
|
943
|
+
var lineForDirection = (prefs) => {
|
|
944
|
+
if (prefs.primary === "updated") {
|
|
945
|
+
return `Direction: ${prefs.direction === "desc" ? "New to Old" : "Old to New"}`;
|
|
775
946
|
}
|
|
776
|
-
return
|
|
947
|
+
return `Direction: ${prefs.direction === "asc" ? "A to Z" : "Z to A"}`;
|
|
777
948
|
};
|
|
778
|
-
var
|
|
779
|
-
return `
|
|
949
|
+
var lineForFavorites = (favoritesFirst) => {
|
|
950
|
+
return `Favorites first: ${favoritesFirst ? "ON" : "OFF"}`;
|
|
780
951
|
};
|
|
781
|
-
var
|
|
782
|
-
const
|
|
783
|
-
|
|
952
|
+
var SortPanel = ({ sortPreferences, focusedIndex, width }) => {
|
|
953
|
+
const primaryLine = lineForPrimary(sortPreferences.primary);
|
|
954
|
+
const directionLine = lineForDirection(sortPreferences);
|
|
955
|
+
const favoritesLine = lineForFavorites(sortPreferences.favoritesFirst);
|
|
956
|
+
const Item = ({ label, selected }) => {
|
|
957
|
+
const prefix = selected ? "> " : " ";
|
|
958
|
+
return /* @__PURE__ */ jsxs3(Text2, { children: [
|
|
959
|
+
selected ? /* @__PURE__ */ jsx4(Text2, { color: "green", children: prefix }) : prefix,
|
|
960
|
+
label
|
|
961
|
+
] });
|
|
962
|
+
};
|
|
963
|
+
return /* @__PURE__ */ jsxs3(
|
|
964
|
+
Box4,
|
|
965
|
+
{
|
|
966
|
+
flexDirection: "column",
|
|
967
|
+
borderStyle: "round",
|
|
968
|
+
borderColor: "green",
|
|
969
|
+
paddingX: 1,
|
|
970
|
+
width,
|
|
971
|
+
children: [
|
|
972
|
+
/* @__PURE__ */ jsx4(Item, { label: primaryLine, selected: focusedIndex === 0 }),
|
|
973
|
+
/* @__PURE__ */ jsx4(Item, { label: directionLine, selected: focusedIndex === 1 }),
|
|
974
|
+
/* @__PURE__ */ jsx4(Item, { label: favoritesLine, selected: focusedIndex === 2 })
|
|
975
|
+
]
|
|
976
|
+
}
|
|
977
|
+
);
|
|
784
978
|
};
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
979
|
+
|
|
980
|
+
// src/presentation/hooks/useSortPreferences.ts
|
|
981
|
+
import { useEffect, useState } from "react";
|
|
982
|
+
|
|
983
|
+
// src/infrastructure/config.ts
|
|
984
|
+
import { mkdir, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
985
|
+
var defaultPreferences = {
|
|
986
|
+
favoritesFirst: true,
|
|
987
|
+
primary: "updated",
|
|
988
|
+
direction: "desc"
|
|
989
|
+
};
|
|
990
|
+
var getConfigDir = () => {
|
|
991
|
+
const home = process.env.HOME ?? "";
|
|
992
|
+
return `${home}/Library/Application Support/UnityHubCli`;
|
|
993
|
+
};
|
|
994
|
+
var getConfigPath = () => `${getConfigDir()}/config.json`;
|
|
995
|
+
var isValidPrimary = (value) => value === "updated" || value === "name";
|
|
996
|
+
var isValidDirection = (value) => value === "asc" || value === "desc";
|
|
997
|
+
var sanitizePreferences = (input) => {
|
|
998
|
+
if (!input || typeof input !== "object") {
|
|
999
|
+
return defaultPreferences;
|
|
1000
|
+
}
|
|
1001
|
+
const record = input;
|
|
1002
|
+
const favoritesFirst = typeof record.favoritesFirst === "boolean" ? record.favoritesFirst : defaultPreferences.favoritesFirst;
|
|
1003
|
+
const primary = isValidPrimary(record.primary) ? record.primary : defaultPreferences.primary;
|
|
1004
|
+
const direction = isValidDirection(record.direction) ? record.direction : defaultPreferences.direction;
|
|
1005
|
+
return { favoritesFirst, primary, direction };
|
|
1006
|
+
};
|
|
1007
|
+
var readSortPreferences = async () => {
|
|
1008
|
+
try {
|
|
1009
|
+
const content = await readFile3(getConfigPath(), "utf8");
|
|
1010
|
+
const json = JSON.parse(content);
|
|
1011
|
+
return sanitizePreferences(json);
|
|
1012
|
+
} catch {
|
|
1013
|
+
return defaultPreferences;
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
var writeSortPreferences = async (prefs) => {
|
|
1017
|
+
try {
|
|
1018
|
+
await mkdir(getConfigDir(), { recursive: true });
|
|
1019
|
+
} catch {
|
|
797
1020
|
}
|
|
798
|
-
|
|
1021
|
+
const sanitized = sanitizePreferences(prefs);
|
|
1022
|
+
const json = JSON.stringify(sanitized, void 0, 2);
|
|
1023
|
+
await writeFile2(getConfigPath(), json, "utf8");
|
|
1024
|
+
};
|
|
1025
|
+
var getDefaultSortPreferences = () => defaultPreferences;
|
|
1026
|
+
|
|
1027
|
+
// src/presentation/hooks/useSortPreferences.ts
|
|
1028
|
+
var useSortPreferences = () => {
|
|
1029
|
+
const [sortPreferences, setSortPreferences] = useState(getDefaultSortPreferences());
|
|
1030
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
1031
|
+
useEffect(() => {
|
|
1032
|
+
void (async () => {
|
|
1033
|
+
try {
|
|
1034
|
+
const prefs = await readSortPreferences();
|
|
1035
|
+
setSortPreferences(prefs);
|
|
1036
|
+
} finally {
|
|
1037
|
+
setIsLoaded(true);
|
|
1038
|
+
}
|
|
1039
|
+
})();
|
|
1040
|
+
}, []);
|
|
1041
|
+
useEffect(() => {
|
|
1042
|
+
if (!isLoaded) {
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
void writeSortPreferences(sortPreferences);
|
|
1046
|
+
}, [isLoaded, sortPreferences]);
|
|
1047
|
+
return { sortPreferences, setSortPreferences, isLoaded };
|
|
799
1048
|
};
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
1049
|
+
|
|
1050
|
+
// src/presentation/hooks/useVisibleCount.ts
|
|
1051
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
1052
|
+
var useVisibleCount = (stdout, linesPerProject, panelVisible, panelHeight, minimumVisibleProjectCount2) => {
|
|
1053
|
+
const compute = () => {
|
|
1054
|
+
if (!stdout || typeof stdout.columns !== "number" || typeof stdout.rows !== "number") {
|
|
1055
|
+
return minimumVisibleProjectCount2;
|
|
1056
|
+
}
|
|
1057
|
+
const borderRows = 2;
|
|
1058
|
+
const hintRows = 1;
|
|
1059
|
+
const reservedRows = borderRows + hintRows + (panelVisible ? panelHeight : 0);
|
|
1060
|
+
const availableRows = Math.max(0, stdout.rows - reservedRows);
|
|
1061
|
+
const rowsPerProject = Math.max(linesPerProject, 1);
|
|
1062
|
+
const calculatedCount = Math.max(1, Math.floor(availableRows / rowsPerProject));
|
|
1063
|
+
return calculatedCount;
|
|
1064
|
+
};
|
|
1065
|
+
const [visibleCount, setVisibleCount] = useState2(compute);
|
|
1066
|
+
useEffect2(() => {
|
|
1067
|
+
const updateVisible = () => setVisibleCount(compute());
|
|
1068
|
+
updateVisible();
|
|
1069
|
+
stdout?.on("resize", updateVisible);
|
|
1070
|
+
return () => {
|
|
1071
|
+
stdout?.off("resize", updateVisible);
|
|
1072
|
+
};
|
|
1073
|
+
}, [stdout, linesPerProject, panelVisible, panelHeight]);
|
|
1074
|
+
return visibleCount;
|
|
805
1075
|
};
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
1076
|
+
|
|
1077
|
+
// src/presentation/App.tsx
|
|
1078
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1079
|
+
var extractRootFolder2 = (repository) => {
|
|
1080
|
+
if (!repository?.root) {
|
|
1081
|
+
return void 0;
|
|
810
1082
|
}
|
|
811
|
-
|
|
1083
|
+
const segments = repository.root.split("/").filter((segment) => segment.length > 0);
|
|
1084
|
+
if (segments.length === 0) {
|
|
1085
|
+
return void 0;
|
|
1086
|
+
}
|
|
1087
|
+
return segments[segments.length - 1];
|
|
812
1088
|
};
|
|
813
|
-
var
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
if (width + w > maxWidth) break;
|
|
819
|
-
result += ch;
|
|
820
|
-
width += w;
|
|
821
|
-
}
|
|
822
|
-
return result;
|
|
1089
|
+
var minimumVisibleProjectCount = 4;
|
|
1090
|
+
var defaultHintMessage = "Select: j/k \xB7 Open: o \xB7 Quit: q \xB7 Refresh: r \xB7 CopyPath: c \xB7 Sort: s \xB7 Close: ctrl + c";
|
|
1091
|
+
var getCopyTargetPath = (view) => {
|
|
1092
|
+
const root = view.repository?.root;
|
|
1093
|
+
return root && root.length > 0 ? root : view.project.path;
|
|
823
1094
|
};
|
|
824
1095
|
var App = ({
|
|
825
1096
|
projects,
|
|
@@ -832,30 +1103,23 @@ var App = ({
|
|
|
832
1103
|
}) => {
|
|
833
1104
|
const { exit } = useApp();
|
|
834
1105
|
const { stdout } = useStdout();
|
|
835
|
-
const [projectViews, setProjectViews] =
|
|
836
|
-
const [
|
|
837
|
-
const [index, setIndex] = useState(0);
|
|
838
|
-
const [hint, setHint] = useState(defaultHintMessage);
|
|
839
|
-
const [windowStart, setWindowStart] = useState(0);
|
|
840
|
-
const [releasedProjects, setReleasedProjects] = useState(/* @__PURE__ */ new Set());
|
|
841
|
-
const [launchedProjects, setLaunchedProjects] = useState(/* @__PURE__ */ new Set());
|
|
842
|
-
const [isRefreshing, setIsRefreshing] = useState(false);
|
|
843
|
-
const [isSortMenuOpen, setIsSortMenuOpen] = useState(false);
|
|
844
|
-
const [sortMenuIndex, setSortMenuIndex] = useState(0);
|
|
845
|
-
const [sortPreferences, setSortPreferences] = useState(getDefaultSortPreferences());
|
|
846
|
-
const [isSortPreferencesLoaded, setIsSortPreferencesLoaded] = useState(false);
|
|
847
|
-
const [renderEpoch, setRenderEpoch] = useState(0);
|
|
1106
|
+
const [projectViews, setProjectViews] = useState3(projects);
|
|
1107
|
+
const [isSortMenuOpen, setIsSortMenuOpen] = useState3(false);
|
|
848
1108
|
const linesPerProject = (showBranch ? 1 : 0) + (showPath ? 1 : 0) + 2;
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
const
|
|
1109
|
+
const panelHeight = 6;
|
|
1110
|
+
const visibleCount = useVisibleCount(stdout, linesPerProject, isSortMenuOpen, panelHeight, minimumVisibleProjectCount);
|
|
1111
|
+
const [index, setIndex] = useState3(0);
|
|
1112
|
+
const [hint, setHint] = useState3(defaultHintMessage);
|
|
1113
|
+
const [windowStart, setWindowStart] = useState3(0);
|
|
1114
|
+
const [releasedProjects, setReleasedProjects] = useState3(/* @__PURE__ */ new Set());
|
|
1115
|
+
const [launchedProjects, setLaunchedProjects] = useState3(/* @__PURE__ */ new Set());
|
|
1116
|
+
const [isRefreshing, setIsRefreshing] = useState3(false);
|
|
1117
|
+
const [sortMenuIndex, setSortMenuIndex] = useState3(0);
|
|
1118
|
+
const { sortPreferences, setSortPreferences } = useSortPreferences();
|
|
1119
|
+
const sortedProjects = useMemo2(() => {
|
|
856
1120
|
const fallbackTime = 0;
|
|
857
1121
|
const getNameKey = (view) => {
|
|
858
|
-
const rootName =
|
|
1122
|
+
const rootName = extractRootFolder2(view.repository);
|
|
859
1123
|
const base = rootName || view.project.title;
|
|
860
1124
|
return base.toLocaleLowerCase();
|
|
861
1125
|
};
|
|
@@ -904,24 +1168,7 @@ var App = ({
|
|
|
904
1168
|
return tieBreaker(a).localeCompare(tieBreaker(b));
|
|
905
1169
|
});
|
|
906
1170
|
}, [projectViews, sortPreferences]);
|
|
907
|
-
|
|
908
|
-
void (async () => {
|
|
909
|
-
try {
|
|
910
|
-
const prefs = await readSortPreferences();
|
|
911
|
-
setSortPreferences(prefs);
|
|
912
|
-
} catch {
|
|
913
|
-
} finally {
|
|
914
|
-
setIsSortPreferencesLoaded(true);
|
|
915
|
-
}
|
|
916
|
-
})();
|
|
917
|
-
}, []);
|
|
918
|
-
useEffect(() => {
|
|
919
|
-
if (!isSortPreferencesLoaded) {
|
|
920
|
-
return;
|
|
921
|
-
}
|
|
922
|
-
void writeSortPreferences(sortPreferences);
|
|
923
|
-
}, [sortPreferences, isSortPreferencesLoaded]);
|
|
924
|
-
useEffect(() => {
|
|
1171
|
+
useEffect3(() => {
|
|
925
1172
|
const handleSigint = () => {
|
|
926
1173
|
exit();
|
|
927
1174
|
};
|
|
@@ -930,26 +1177,6 @@ var App = ({
|
|
|
930
1177
|
process.off("SIGINT", handleSigint);
|
|
931
1178
|
};
|
|
932
1179
|
}, [exit]);
|
|
933
|
-
useEffect(() => {
|
|
934
|
-
const updateVisibleCount = () => {
|
|
935
|
-
if (!stdout || typeof stdout.columns !== "number" || typeof stdout.rows !== "number") {
|
|
936
|
-
setVisibleCount(minimumVisibleProjectCount);
|
|
937
|
-
return;
|
|
938
|
-
}
|
|
939
|
-
const borderRows = 2;
|
|
940
|
-
const hintRows = 1;
|
|
941
|
-
const reservedRows = borderRows + hintRows;
|
|
942
|
-
const availableRows = Math.max(0, stdout.rows - reservedRows);
|
|
943
|
-
const rowsPerProject = Math.max(linesPerProject, 1);
|
|
944
|
-
const calculatedCount = Math.max(1, Math.floor(availableRows / rowsPerProject));
|
|
945
|
-
setVisibleCount(calculatedCount);
|
|
946
|
-
};
|
|
947
|
-
updateVisibleCount();
|
|
948
|
-
stdout?.on("resize", updateVisibleCount);
|
|
949
|
-
return () => {
|
|
950
|
-
stdout?.off("resize", updateVisibleCount);
|
|
951
|
-
};
|
|
952
|
-
}, [linesPerProject, stdout]);
|
|
953
1180
|
const limit = Math.max(1, visibleCount);
|
|
954
1181
|
const move = useCallback(
|
|
955
1182
|
(delta) => {
|
|
@@ -994,7 +1221,7 @@ var App = ({
|
|
|
994
1221
|
},
|
|
995
1222
|
[index, limit, sortedProjects.length]
|
|
996
1223
|
);
|
|
997
|
-
|
|
1224
|
+
useEffect3(() => {
|
|
998
1225
|
setWindowStart((prevStart) => {
|
|
999
1226
|
if (sortedProjects.length <= limit) {
|
|
1000
1227
|
return prevStart === 0 ? prevStart : 0;
|
|
@@ -1137,7 +1364,7 @@ var App = ({
|
|
|
1137
1364
|
}, 3e3);
|
|
1138
1365
|
}
|
|
1139
1366
|
}, [index, onTerminate, sortedProjects]);
|
|
1140
|
-
|
|
1367
|
+
useEffect3(() => {
|
|
1141
1368
|
setProjectViews(projects);
|
|
1142
1369
|
setReleasedProjects(/* @__PURE__ */ new Set());
|
|
1143
1370
|
setLaunchedProjects(/* @__PURE__ */ new Set());
|
|
@@ -1198,10 +1425,7 @@ var App = ({
|
|
|
1198
1425
|
useInput((input, key) => {
|
|
1199
1426
|
if (isSortMenuOpen) {
|
|
1200
1427
|
if (key.escape || input === "\x1B") {
|
|
1201
|
-
clearOverlay();
|
|
1202
|
-
forceFullRepaint();
|
|
1203
1428
|
setIsSortMenuOpen(false);
|
|
1204
|
-
setRenderEpoch((prev) => prev + 1);
|
|
1205
1429
|
return;
|
|
1206
1430
|
}
|
|
1207
1431
|
if (input === "j") {
|
|
@@ -1262,7 +1486,7 @@ var App = ({
|
|
|
1262
1486
|
copyProjectPath();
|
|
1263
1487
|
}
|
|
1264
1488
|
});
|
|
1265
|
-
const { startIndex, visibleProjects } =
|
|
1489
|
+
const { startIndex, visibleProjects } = useMemo2(() => {
|
|
1266
1490
|
if (sortedProjects.length <= limit) {
|
|
1267
1491
|
return {
|
|
1268
1492
|
startIndex: 0,
|
|
@@ -1277,219 +1501,53 @@ var App = ({
|
|
|
1277
1501
|
visibleProjects: sortedProjects.slice(clampedStart, end)
|
|
1278
1502
|
};
|
|
1279
1503
|
}, [limit, sortedProjects, windowStart]);
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
const rows = useMemo(() => {
|
|
1308
|
-
return visibleProjects.map(({ project, repository, launchStatus }, offset) => {
|
|
1309
|
-
const rowIndex = startIndex + offset;
|
|
1310
|
-
const isSelected = rowIndex === index;
|
|
1311
|
-
const selectionBar = isSelected ? "\u2503" : " ";
|
|
1312
|
-
const projectName = formatProjectName(project, repository, useGitRootName);
|
|
1313
|
-
const versionLabel = `(${project.version.value})`;
|
|
1314
|
-
const updatedText = formatUpdatedText(project.lastModified);
|
|
1315
|
-
const pathLine = shortenHomePath(project.path);
|
|
1316
|
-
const branchLine = formatBranch(repository?.branch);
|
|
1317
|
-
const hasReleasedLock = releasedProjects.has(project.id);
|
|
1318
|
-
const isLocallyLaunched = launchedProjects.has(project.id);
|
|
1319
|
-
const displayStatus = (() => {
|
|
1320
|
-
if (isLocallyLaunched) {
|
|
1321
|
-
return "running";
|
|
1322
|
-
}
|
|
1323
|
-
if (hasReleasedLock) {
|
|
1324
|
-
return "idle";
|
|
1504
|
+
return /* @__PURE__ */ jsx5(
|
|
1505
|
+
LayoutManager,
|
|
1506
|
+
{
|
|
1507
|
+
layoutMode: getLayoutMode(),
|
|
1508
|
+
panelVisible: isSortMenuOpen,
|
|
1509
|
+
list: /* @__PURE__ */ jsx5(
|
|
1510
|
+
Box5,
|
|
1511
|
+
{
|
|
1512
|
+
flexDirection: "column",
|
|
1513
|
+
borderStyle: "round",
|
|
1514
|
+
borderColor: "green",
|
|
1515
|
+
width: typeof stdout?.columns === "number" ? stdout.columns : void 0,
|
|
1516
|
+
children: sortedProjects.length === 0 ? /* @__PURE__ */ jsx5(Text3, { children: "No Unity Hub projects were found." }) : /* @__PURE__ */ jsx5(
|
|
1517
|
+
ProjectList,
|
|
1518
|
+
{
|
|
1519
|
+
visibleProjects,
|
|
1520
|
+
startIndex,
|
|
1521
|
+
selectedIndex: index,
|
|
1522
|
+
linesPerProject,
|
|
1523
|
+
showBranch,
|
|
1524
|
+
showPath,
|
|
1525
|
+
useGitRootName,
|
|
1526
|
+
releasedProjects,
|
|
1527
|
+
launchedProjects,
|
|
1528
|
+
totalProjects: sortedProjects.length
|
|
1529
|
+
}
|
|
1530
|
+
)
|
|
1325
1531
|
}
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
showPath ? /* @__PURE__ */ jsx(Text, { color: isSelected ? "green" : void 0, children: selectionBar }) : null
|
|
1340
|
-
] }),
|
|
1341
|
-
/* @__PURE__ */ jsxs(Box, { flexGrow: 1, flexDirection: "column", marginLeft: isSelected ? 2 : 1, children: [
|
|
1342
|
-
/* @__PURE__ */ jsxs(Text, { wrap: "truncate", children: [
|
|
1343
|
-
/* @__PURE__ */ jsx(Text, { color: PROJECT_COLOR, bold: true, children: projectName }),
|
|
1344
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
1345
|
-
" ",
|
|
1346
|
-
versionLabel
|
|
1347
|
-
] }),
|
|
1348
|
-
updatedText ? /* @__PURE__ */ jsx(Text, { children: ` ${updatedText}` }) : null,
|
|
1349
|
-
statusLabel && statusColor ? /* @__PURE__ */ jsx(Text, { color: statusColor, children: ` ${statusLabel}` }) : null
|
|
1350
|
-
] }),
|
|
1351
|
-
showBranch ? /* @__PURE__ */ jsx(Text, { color: BRANCH_COLOR, wrap: "truncate", children: branchLine }) : null,
|
|
1352
|
-
showPath ? /* @__PURE__ */ jsx(Text, { color: PATH_COLOR, wrap: "truncate", children: pathLine }) : null,
|
|
1353
|
-
/* @__PURE__ */ jsx(Text, { children: " " })
|
|
1354
|
-
] }),
|
|
1355
|
-
/* @__PURE__ */ jsxs(Box, { marginLeft: 1, width: 1, flexDirection: "column", alignItems: "center", children: [
|
|
1356
|
-
/* @__PURE__ */ jsx(Text, { children: titleScrollbar }),
|
|
1357
|
-
showBranch ? /* @__PURE__ */ jsx(Text, { children: branchScrollbar }) : null,
|
|
1358
|
-
showPath ? /* @__PURE__ */ jsx(Text, { children: pathScrollbar }) : null,
|
|
1359
|
-
/* @__PURE__ */ jsx(Text, { children: spacerScrollbar })
|
|
1360
|
-
] })
|
|
1361
|
-
] }, project.id);
|
|
1362
|
-
});
|
|
1363
|
-
}, [
|
|
1364
|
-
index,
|
|
1365
|
-
launchedProjects,
|
|
1366
|
-
releasedProjects,
|
|
1367
|
-
scrollbarChars,
|
|
1368
|
-
showBranch,
|
|
1369
|
-
showPath,
|
|
1370
|
-
startIndex,
|
|
1371
|
-
useGitRootName,
|
|
1372
|
-
visibleProjects
|
|
1373
|
-
]);
|
|
1374
|
-
useEffect(() => {
|
|
1375
|
-
if (!isSortMenuOpen || !stdout) {
|
|
1376
|
-
return;
|
|
1377
|
-
}
|
|
1378
|
-
const columns = typeof stdout.columns === "number" ? stdout.columns : 80;
|
|
1379
|
-
const contentRows = rows.length === 0 ? 1 : visibleProjects.length * linesPerProject;
|
|
1380
|
-
const contentWidth = Math.max(10, columns - 2);
|
|
1381
|
-
const modalInnerWidth = Math.min(60, Math.max(28, contentWidth - 6));
|
|
1382
|
-
const modalWidth = Math.min(contentWidth, modalInnerWidth);
|
|
1383
|
-
const leftPadding = Math.max(0, Math.floor((contentWidth - modalWidth) / 2));
|
|
1384
|
-
const title = "Sort Menu (Select: j/k, Toggle: Space, Close: Esc)";
|
|
1385
|
-
const linePrimary = `Primary: ${sortPreferences.primary === "updated" ? "Updated" : "Name (Git root)"}`;
|
|
1386
|
-
const lineDirection = `Direction: ${sortPreferences.primary === "updated" ? sortPreferences.direction === "desc" ? "New to Old" : "Old to New" : sortPreferences.direction === "asc" ? "A to Z" : "Z to A"}`;
|
|
1387
|
-
const lineFav = `Favorites first: ${sortPreferences.favoritesFirst ? "ON" : "OFF"}`;
|
|
1388
|
-
const innerWidth = modalWidth - 2;
|
|
1389
|
-
const BORDER_ON = "\x1B[32m";
|
|
1390
|
-
const BORDER_OFF = "\x1B[39m";
|
|
1391
|
-
const fixedPrefixWidth = 2;
|
|
1392
|
-
const buildContentLine = (label, selected) => {
|
|
1393
|
-
const arrow = selected ? "> " : " ";
|
|
1394
|
-
const maxLabelWidth = Math.max(0, innerWidth - fixedPrefixWidth);
|
|
1395
|
-
const rawLabel = label;
|
|
1396
|
-
const limitedLabel = stringWidth(rawLabel) > maxLabelWidth ? `${truncateToWidth(rawLabel, Math.max(0, maxLabelWidth - 3))}...` : rawLabel;
|
|
1397
|
-
const visibleBase = `${arrow}${limitedLabel}`;
|
|
1398
|
-
const colored = selected ? `\x1B[32m${visibleBase}\x1B[39m` : visibleBase;
|
|
1399
|
-
const pad = Math.max(0, innerWidth - stringWidth(visibleBase));
|
|
1400
|
-
return `${BORDER_ON}\u2502${BORDER_OFF}${colored}${" ".repeat(pad)}${BORDER_ON}\u2502${BORDER_OFF}`;
|
|
1401
|
-
};
|
|
1402
|
-
const contentLines = [
|
|
1403
|
-
(() => {
|
|
1404
|
-
const prefix = " ";
|
|
1405
|
-
const maxTitleWidth = Math.max(0, innerWidth - fixedPrefixWidth);
|
|
1406
|
-
const visibleTitle = stringWidth(title) > maxTitleWidth ? `${truncateToWidth(title, Math.max(0, maxTitleWidth - 3))}...` : title;
|
|
1407
|
-
const content = `${prefix}${visibleTitle}`;
|
|
1408
|
-
const pad = Math.max(0, innerWidth - stringWidth(content));
|
|
1409
|
-
return `${BORDER_ON}\u2502${BORDER_OFF}${content}${" ".repeat(pad)}${BORDER_ON}\u2502${BORDER_OFF}`;
|
|
1410
|
-
})(),
|
|
1411
|
-
`${BORDER_ON}\u2502${BORDER_OFF}${" ".repeat(innerWidth)}${BORDER_ON}\u2502${BORDER_OFF}`,
|
|
1412
|
-
buildContentLine(linePrimary, sortMenuIndex === 0),
|
|
1413
|
-
buildContentLine(lineDirection, sortMenuIndex === 1),
|
|
1414
|
-
buildContentLine(lineFav, sortMenuIndex === 2)
|
|
1415
|
-
];
|
|
1416
|
-
const topBorder = `${BORDER_ON}\u250C${"\u2500".repeat(modalWidth - 2)}\u2510${BORDER_OFF}`;
|
|
1417
|
-
const bottomBorder = `${BORDER_ON}\u2514${"\u2500".repeat(modalWidth - 2)}\u2518${BORDER_OFF}`;
|
|
1418
|
-
const overlayLines = [topBorder, ...contentLines, bottomBorder];
|
|
1419
|
-
const overlayHeight = overlayLines.length;
|
|
1420
|
-
const overlayTopWithinContent = Math.max(0, Math.floor((contentRows - overlayHeight) / 2));
|
|
1421
|
-
const overlayTopRelativeToComponent = 1 + overlayTopWithinContent;
|
|
1422
|
-
const bottomIndex = contentRows + 2;
|
|
1423
|
-
const moveUp = Math.max(0, bottomIndex - overlayTopRelativeToComponent);
|
|
1424
|
-
const moveRight = 1 + leftPadding;
|
|
1425
|
-
stdout.write("\x1B7");
|
|
1426
|
-
if (moveUp > 0) {
|
|
1427
|
-
stdout.write(`\x1B[${moveUp}A`);
|
|
1428
|
-
}
|
|
1429
|
-
stdout.write("\r");
|
|
1430
|
-
for (let i = 0; i < overlayLines.length; i++) {
|
|
1431
|
-
stdout.write("\r");
|
|
1432
|
-
if (moveRight > 0) {
|
|
1433
|
-
stdout.write(`\x1B[${moveRight}C`);
|
|
1434
|
-
}
|
|
1435
|
-
stdout.write(" ".repeat(Math.max(0, modalWidth)));
|
|
1436
|
-
stdout.write(`\x1B[${Math.max(0, modalWidth)}D`);
|
|
1437
|
-
stdout.write(overlayLines[i]);
|
|
1438
|
-
if (i < overlayLines.length - 1) {
|
|
1439
|
-
stdout.write("\r\n");
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
stdout.write("\x1B8");
|
|
1443
|
-
}, [
|
|
1444
|
-
isSortMenuOpen,
|
|
1445
|
-
linesPerProject,
|
|
1446
|
-
rows,
|
|
1447
|
-
sortPreferences,
|
|
1448
|
-
sortMenuIndex,
|
|
1449
|
-
stdout,
|
|
1450
|
-
visibleProjects.length
|
|
1451
|
-
]);
|
|
1452
|
-
const clearOverlay = useCallback(() => {
|
|
1453
|
-
if (!stdout) {
|
|
1454
|
-
return;
|
|
1455
|
-
}
|
|
1456
|
-
const columns = typeof stdout.columns === "number" ? stdout.columns : 80;
|
|
1457
|
-
const contentRows = rows.length === 0 ? 1 : visibleProjects.length * linesPerProject;
|
|
1458
|
-
const contentWidth = Math.max(10, columns - 2);
|
|
1459
|
-
const modalInnerWidth = Math.min(60, Math.max(28, contentWidth - 6));
|
|
1460
|
-
const modalWidth = Math.min(contentWidth, modalInnerWidth);
|
|
1461
|
-
const leftPadding = Math.max(0, Math.floor((contentWidth - modalWidth) / 2));
|
|
1462
|
-
const overlayHeight = 6;
|
|
1463
|
-
const overlayTopWithinContent = Math.max(0, Math.floor((contentRows - overlayHeight) / 2));
|
|
1464
|
-
const overlayTopRelativeToComponent = 1 + overlayTopWithinContent;
|
|
1465
|
-
const bottomIndex = contentRows + 2;
|
|
1466
|
-
const moveUp = Math.max(0, bottomIndex - overlayTopRelativeToComponent);
|
|
1467
|
-
const moveRight = 1 + leftPadding;
|
|
1468
|
-
stdout.write("\x1B7");
|
|
1469
|
-
if (moveUp > 0) {
|
|
1470
|
-
stdout.write(`\x1B[${moveUp}A`);
|
|
1471
|
-
}
|
|
1472
|
-
stdout.write("\r");
|
|
1473
|
-
for (let i = 0; i < overlayHeight; i++) {
|
|
1474
|
-
stdout.write("\r");
|
|
1475
|
-
if (moveRight > 0) {
|
|
1476
|
-
stdout.write(`\x1B[${moveRight}C`);
|
|
1477
|
-
}
|
|
1478
|
-
stdout.write(" ".repeat(Math.max(0, modalWidth)));
|
|
1479
|
-
if (i < overlayHeight - 1) {
|
|
1480
|
-
stdout.write("\r\n");
|
|
1481
|
-
}
|
|
1532
|
+
),
|
|
1533
|
+
panel: /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", width: typeof stdout?.columns === "number" ? stdout.columns : void 0, children: [
|
|
1534
|
+
/* @__PURE__ */ jsx5(Text3, { children: "Sort Settings" }),
|
|
1535
|
+
/* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(
|
|
1536
|
+
SortPanel,
|
|
1537
|
+
{
|
|
1538
|
+
sortPreferences,
|
|
1539
|
+
focusedIndex: sortMenuIndex,
|
|
1540
|
+
width: typeof stdout?.columns === "number" ? stdout.columns : void 0
|
|
1541
|
+
}
|
|
1542
|
+
) })
|
|
1543
|
+
] }),
|
|
1544
|
+
statusBar: isSortMenuOpen ? /* @__PURE__ */ jsx5(Text3, { wrap: "truncate", children: "Select: j/k, Toggle: Space, Back: Esc" }) : /* @__PURE__ */ jsx5(Text3, { wrap: "truncate", children: hint })
|
|
1482
1545
|
}
|
|
1483
|
-
|
|
1484
|
-
}, [linesPerProject, rows.length, visibleProjects.length, stdout]);
|
|
1485
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1486
|
-
/* @__PURE__ */ jsx(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", children: rows.length === 0 ? /* @__PURE__ */ jsx(Text, { children: "No Unity Hub projects were found." }) : rows }),
|
|
1487
|
-
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { wrap: "truncate", children: hint }) })
|
|
1488
|
-
] }, renderEpoch);
|
|
1546
|
+
);
|
|
1489
1547
|
};
|
|
1490
1548
|
|
|
1491
1549
|
// src/index.tsx
|
|
1492
|
-
import { jsx as
|
|
1550
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1493
1551
|
var bootstrap = async () => {
|
|
1494
1552
|
const unityHubReader = new UnityHubProjectsReader();
|
|
1495
1553
|
const gitRepositoryInfoReader = new GitRepositoryInfoReader();
|
|
@@ -1525,7 +1583,7 @@ var bootstrap = async () => {
|
|
|
1525
1583
|
try {
|
|
1526
1584
|
const projects = await listProjectsUseCase.execute();
|
|
1527
1585
|
const { waitUntilExit } = render(
|
|
1528
|
-
/* @__PURE__ */
|
|
1586
|
+
/* @__PURE__ */ jsx6(
|
|
1529
1587
|
App,
|
|
1530
1588
|
{
|
|
1531
1589
|
projects,
|