unity-hub-cli 0.9.0 → 0.10.1
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 +439 -378
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -621,55 +621,136 @@ 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 as useStdout2 } 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 "~";
|
|
658
680
|
}
|
|
681
|
+
if (homePrefix && normalizedTarget.startsWith(homePrefix)) {
|
|
682
|
+
return `~/${normalizedTarget.slice(homePrefix.length)}`;
|
|
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, useStdout } 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
|
+
const { stdout } = useStdout();
|
|
714
|
+
const computedCenterWidth = typeof stdout?.columns === "number" ? Math.max(0, stdout.columns - 6) : void 0;
|
|
715
|
+
const centerWidth = typeof computedCenterWidth === "number" ? Math.max(0, computedCenterWidth - (isSelected ? 1 : 0)) : void 0;
|
|
716
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", children: [
|
|
717
|
+
/* @__PURE__ */ jsxs2(Box2, { width: 1, flexDirection: "column", alignItems: "center", marginLeft: 0, children: [
|
|
718
|
+
/* @__PURE__ */ jsx2(Text, { color: isSelected ? "green" : void 0, children: selectionBar }),
|
|
719
|
+
showBranch ? /* @__PURE__ */ jsx2(Text, { color: isSelected ? "green" : void 0, children: selectionBar }) : null,
|
|
720
|
+
showPath ? /* @__PURE__ */ jsx2(Text, { color: isSelected ? "green" : void 0, children: selectionBar }) : null
|
|
721
|
+
] }),
|
|
722
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginLeft: isSelected ? 2 : 1, width: centerWidth, children: [
|
|
723
|
+
/* @__PURE__ */ jsxs2(Text, { wrap: "truncate", children: [
|
|
724
|
+
/* @__PURE__ */ jsx2(Text, { color: projectColor, bold: true, children: projectName }),
|
|
725
|
+
/* @__PURE__ */ jsxs2(Text, { children: [
|
|
726
|
+
" ",
|
|
727
|
+
versionLabel
|
|
728
|
+
] }),
|
|
729
|
+
updatedText ? /* @__PURE__ */ jsx2(Text, { children: ` ${updatedText}` }) : null,
|
|
730
|
+
statusLabel && statusColor ? /* @__PURE__ */ jsx2(Text, { color: statusColor, children: ` ${statusLabel}` }) : null
|
|
731
|
+
] }),
|
|
732
|
+
showBranch ? /* @__PURE__ */ jsx2(Text, { color: "#e3839c", wrap: "truncate", children: branchLine }) : null,
|
|
733
|
+
showPath ? /* @__PURE__ */ jsx2(Text, { color: "#719bd8", wrap: "truncate", children: pathLine }) : null,
|
|
734
|
+
/* @__PURE__ */ jsx2(Text, { children: " " })
|
|
735
|
+
] }),
|
|
736
|
+
/* @__PURE__ */ jsxs2(Box2, { marginLeft: 1, width: 1, flexDirection: "column", alignItems: "center", children: [
|
|
737
|
+
/* @__PURE__ */ jsx2(Text, { children: scrollbar.title }),
|
|
738
|
+
showBranch ? /* @__PURE__ */ jsx2(Text, { children: scrollbar.branch }) : null,
|
|
739
|
+
showPath ? /* @__PURE__ */ jsx2(Text, { children: scrollbar.path }) : null,
|
|
740
|
+
/* @__PURE__ */ jsx2(Text, { children: scrollbar.spacer })
|
|
741
|
+
] })
|
|
742
|
+
] });
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
// src/presentation/components/ProjectList.tsx
|
|
746
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
747
|
+
var PROJECT_COLOR = "#abd8e7";
|
|
748
|
+
var LOCK_COLOR = "yellow";
|
|
749
|
+
var STATUS_LABELS = {
|
|
750
|
+
idle: "",
|
|
751
|
+
running: "[running]",
|
|
752
|
+
crashed: "[crash]"
|
|
753
|
+
};
|
|
673
754
|
var extractRootFolder = (repository) => {
|
|
674
755
|
if (!repository?.root) {
|
|
675
756
|
return void 0;
|
|
@@ -680,13 +761,13 @@ var extractRootFolder = (repository) => {
|
|
|
680
761
|
}
|
|
681
762
|
return segments[segments.length - 1];
|
|
682
763
|
};
|
|
683
|
-
var formatProjectName = (
|
|
764
|
+
var formatProjectName = (projectTitle, repository, useGitRootName) => {
|
|
684
765
|
if (!useGitRootName) {
|
|
685
|
-
return
|
|
766
|
+
return projectTitle;
|
|
686
767
|
}
|
|
687
768
|
const rootFolder = extractRootFolder(repository);
|
|
688
769
|
if (!rootFolder) {
|
|
689
|
-
return
|
|
770
|
+
return projectTitle;
|
|
690
771
|
}
|
|
691
772
|
return rootFolder;
|
|
692
773
|
};
|
|
@@ -750,76 +831,269 @@ var formatUpdatedText = (lastModified) => {
|
|
|
750
831
|
}
|
|
751
832
|
return `${UPDATED_LABEL} ${relativeTime}`;
|
|
752
833
|
};
|
|
753
|
-
var
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
834
|
+
var ProjectList = ({
|
|
835
|
+
visibleProjects,
|
|
836
|
+
startIndex,
|
|
837
|
+
selectedIndex,
|
|
838
|
+
linesPerProject,
|
|
839
|
+
showBranch,
|
|
840
|
+
showPath,
|
|
841
|
+
useGitRootName,
|
|
842
|
+
releasedProjects,
|
|
843
|
+
launchedProjects,
|
|
844
|
+
totalProjects
|
|
845
|
+
}) => {
|
|
846
|
+
const scrollbarChars = useMemo(() => {
|
|
847
|
+
const totalLines = totalProjects * linesPerProject;
|
|
848
|
+
const windowProjects = visibleProjects.length;
|
|
849
|
+
const visibleLines = windowProjects * linesPerProject;
|
|
850
|
+
if (totalLines === 0 || visibleLines === 0) {
|
|
851
|
+
return [];
|
|
852
|
+
}
|
|
853
|
+
if (totalLines <= visibleLines) {
|
|
854
|
+
return Array.from({ length: visibleLines }, () => "\u2588");
|
|
855
|
+
}
|
|
856
|
+
const trackLength = visibleLines;
|
|
857
|
+
const sliderSize = Math.max(1, Math.round(visibleLines / totalLines * trackLength));
|
|
858
|
+
const maxSliderStart = Math.max(0, trackLength - sliderSize);
|
|
859
|
+
const topLine = startIndex * linesPerProject;
|
|
860
|
+
const denominator = Math.max(1, totalLines - visibleLines);
|
|
861
|
+
const sliderStart = Math.min(
|
|
862
|
+
maxSliderStart,
|
|
863
|
+
Math.round(topLine / denominator * maxSliderStart)
|
|
864
|
+
);
|
|
865
|
+
return Array.from({ length: trackLength }, (_, position) => {
|
|
866
|
+
if (position >= sliderStart && position < sliderStart + sliderSize) {
|
|
867
|
+
return "\u2588";
|
|
868
|
+
}
|
|
869
|
+
return "|";
|
|
870
|
+
});
|
|
871
|
+
}, [linesPerProject, startIndex, totalProjects, visibleProjects.length]);
|
|
872
|
+
const rows = useMemo(() => {
|
|
873
|
+
return visibleProjects.map(({ project, repository, launchStatus }, offset) => {
|
|
874
|
+
const rowIndex = startIndex + offset;
|
|
875
|
+
const isSelected = rowIndex === selectedIndex;
|
|
876
|
+
const selectionBar = isSelected ? "\u2503" : " ";
|
|
877
|
+
const projectName = formatProjectName(project.title, repository, useGitRootName);
|
|
878
|
+
const versionLabel = `(${project.version.value})`;
|
|
879
|
+
const updatedText = formatUpdatedText(project.lastModified);
|
|
880
|
+
const pathLine = shortenHomePath(project.path);
|
|
881
|
+
const branchLine = formatBranch(repository?.branch);
|
|
882
|
+
const hasReleasedLock = releasedProjects.has(project.id);
|
|
883
|
+
const isLocallyLaunched = launchedProjects.has(project.id);
|
|
884
|
+
const displayStatus = (() => {
|
|
885
|
+
if (isLocallyLaunched) {
|
|
886
|
+
return "running";
|
|
887
|
+
}
|
|
888
|
+
if (hasReleasedLock) {
|
|
889
|
+
return "idle";
|
|
890
|
+
}
|
|
891
|
+
return launchStatus;
|
|
892
|
+
})();
|
|
893
|
+
const baseScrollbarIndex = offset * linesPerProject;
|
|
894
|
+
const titleScrollbar = scrollbarChars[baseScrollbarIndex] ?? " ";
|
|
895
|
+
const branchScrollbar = showBranch ? scrollbarChars[baseScrollbarIndex + 1] ?? " " : " ";
|
|
896
|
+
const pathScrollbar = showPath ? scrollbarChars[baseScrollbarIndex + 1 + (showBranch ? 1 : 0)] ?? " " : " ";
|
|
897
|
+
const spacerScrollbar = scrollbarChars[baseScrollbarIndex + linesPerProject - 1] ?? " ";
|
|
898
|
+
const statusLabel = STATUS_LABELS[displayStatus];
|
|
899
|
+
const statusColor = displayStatus === "running" ? LOCK_COLOR : displayStatus === "crashed" ? "red" : void 0;
|
|
900
|
+
return /* @__PURE__ */ jsx3(
|
|
901
|
+
ProjectRow,
|
|
902
|
+
{
|
|
903
|
+
isSelected,
|
|
904
|
+
selectionBar,
|
|
905
|
+
projectName,
|
|
906
|
+
projectColor: PROJECT_COLOR,
|
|
907
|
+
versionLabel,
|
|
908
|
+
updatedText,
|
|
909
|
+
statusLabel,
|
|
910
|
+
statusColor,
|
|
911
|
+
branchLine,
|
|
912
|
+
pathLine,
|
|
913
|
+
showBranch,
|
|
914
|
+
showPath,
|
|
915
|
+
scrollbar: {
|
|
916
|
+
title: titleScrollbar,
|
|
917
|
+
branch: branchScrollbar,
|
|
918
|
+
path: pathScrollbar,
|
|
919
|
+
spacer: spacerScrollbar
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
project.id
|
|
923
|
+
);
|
|
924
|
+
});
|
|
925
|
+
}, [
|
|
926
|
+
launchedProjects,
|
|
927
|
+
releasedProjects,
|
|
928
|
+
scrollbarChars,
|
|
929
|
+
selectedIndex,
|
|
930
|
+
showBranch,
|
|
931
|
+
showPath,
|
|
932
|
+
startIndex,
|
|
933
|
+
useGitRootName,
|
|
934
|
+
visibleProjects,
|
|
935
|
+
linesPerProject
|
|
936
|
+
]);
|
|
937
|
+
return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: rows.length === 0 ? null : rows });
|
|
765
938
|
};
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
939
|
+
|
|
940
|
+
// src/presentation/components/SortPanel.tsx
|
|
941
|
+
import { Box as Box4, Text as Text2 } from "ink";
|
|
942
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
943
|
+
var lineForPrimary = (primary) => {
|
|
944
|
+
return `Primary: ${primary === "updated" ? "Updated" : "Name (Git root)"}`;
|
|
945
|
+
};
|
|
946
|
+
var lineForDirection = (prefs) => {
|
|
947
|
+
if (prefs.primary === "updated") {
|
|
948
|
+
return `Direction: ${prefs.direction === "desc" ? "New to Old" : "Old to New"}`;
|
|
775
949
|
}
|
|
776
|
-
return
|
|
950
|
+
return `Direction: ${prefs.direction === "asc" ? "A to Z" : "Z to A"}`;
|
|
777
951
|
};
|
|
778
|
-
var
|
|
779
|
-
return `
|
|
952
|
+
var lineForFavorites = (favoritesFirst) => {
|
|
953
|
+
return `Favorites first: ${favoritesFirst ? "ON" : "OFF"}`;
|
|
780
954
|
};
|
|
781
|
-
var
|
|
782
|
-
const
|
|
783
|
-
|
|
955
|
+
var SortPanel = ({ sortPreferences, focusedIndex, width }) => {
|
|
956
|
+
const primaryLine = lineForPrimary(sortPreferences.primary);
|
|
957
|
+
const directionLine = lineForDirection(sortPreferences);
|
|
958
|
+
const favoritesLine = lineForFavorites(sortPreferences.favoritesFirst);
|
|
959
|
+
const Item = ({ label, selected }) => {
|
|
960
|
+
const prefix = selected ? "> " : " ";
|
|
961
|
+
return /* @__PURE__ */ jsxs3(Text2, { children: [
|
|
962
|
+
selected ? /* @__PURE__ */ jsx4(Text2, { color: "green", children: prefix }) : prefix,
|
|
963
|
+
label
|
|
964
|
+
] });
|
|
965
|
+
};
|
|
966
|
+
return /* @__PURE__ */ jsxs3(
|
|
967
|
+
Box4,
|
|
968
|
+
{
|
|
969
|
+
flexDirection: "column",
|
|
970
|
+
borderStyle: "round",
|
|
971
|
+
borderColor: "green",
|
|
972
|
+
paddingX: 1,
|
|
973
|
+
width,
|
|
974
|
+
children: [
|
|
975
|
+
/* @__PURE__ */ jsx4(Item, { label: primaryLine, selected: focusedIndex === 0 }),
|
|
976
|
+
/* @__PURE__ */ jsx4(Item, { label: directionLine, selected: focusedIndex === 1 }),
|
|
977
|
+
/* @__PURE__ */ jsx4(Item, { label: favoritesLine, selected: focusedIndex === 2 })
|
|
978
|
+
]
|
|
979
|
+
}
|
|
980
|
+
);
|
|
784
981
|
};
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
982
|
+
|
|
983
|
+
// src/presentation/hooks/useSortPreferences.ts
|
|
984
|
+
import { useEffect, useState } from "react";
|
|
985
|
+
|
|
986
|
+
// src/infrastructure/config.ts
|
|
987
|
+
import { mkdir, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
988
|
+
var defaultPreferences = {
|
|
989
|
+
favoritesFirst: true,
|
|
990
|
+
primary: "updated",
|
|
991
|
+
direction: "desc"
|
|
992
|
+
};
|
|
993
|
+
var getConfigDir = () => {
|
|
994
|
+
const home = process.env.HOME ?? "";
|
|
995
|
+
return `${home}/Library/Application Support/UnityHubCli`;
|
|
996
|
+
};
|
|
997
|
+
var getConfigPath = () => `${getConfigDir()}/config.json`;
|
|
998
|
+
var isValidPrimary = (value) => value === "updated" || value === "name";
|
|
999
|
+
var isValidDirection = (value) => value === "asc" || value === "desc";
|
|
1000
|
+
var sanitizePreferences = (input) => {
|
|
1001
|
+
if (!input || typeof input !== "object") {
|
|
1002
|
+
return defaultPreferences;
|
|
1003
|
+
}
|
|
1004
|
+
const record = input;
|
|
1005
|
+
const favoritesFirst = typeof record.favoritesFirst === "boolean" ? record.favoritesFirst : defaultPreferences.favoritesFirst;
|
|
1006
|
+
const primary = isValidPrimary(record.primary) ? record.primary : defaultPreferences.primary;
|
|
1007
|
+
const direction = isValidDirection(record.direction) ? record.direction : defaultPreferences.direction;
|
|
1008
|
+
return { favoritesFirst, primary, direction };
|
|
1009
|
+
};
|
|
1010
|
+
var readSortPreferences = async () => {
|
|
1011
|
+
try {
|
|
1012
|
+
const content = await readFile3(getConfigPath(), "utf8");
|
|
1013
|
+
const json = JSON.parse(content);
|
|
1014
|
+
return sanitizePreferences(json);
|
|
1015
|
+
} catch {
|
|
1016
|
+
return defaultPreferences;
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
var writeSortPreferences = async (prefs) => {
|
|
1020
|
+
try {
|
|
1021
|
+
await mkdir(getConfigDir(), { recursive: true });
|
|
1022
|
+
} catch {
|
|
797
1023
|
}
|
|
798
|
-
|
|
1024
|
+
const sanitized = sanitizePreferences(prefs);
|
|
1025
|
+
const json = JSON.stringify(sanitized, void 0, 2);
|
|
1026
|
+
await writeFile2(getConfigPath(), json, "utf8");
|
|
1027
|
+
};
|
|
1028
|
+
var getDefaultSortPreferences = () => defaultPreferences;
|
|
1029
|
+
|
|
1030
|
+
// src/presentation/hooks/useSortPreferences.ts
|
|
1031
|
+
var useSortPreferences = () => {
|
|
1032
|
+
const [sortPreferences, setSortPreferences] = useState(getDefaultSortPreferences());
|
|
1033
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
1034
|
+
useEffect(() => {
|
|
1035
|
+
void (async () => {
|
|
1036
|
+
try {
|
|
1037
|
+
const prefs = await readSortPreferences();
|
|
1038
|
+
setSortPreferences(prefs);
|
|
1039
|
+
} finally {
|
|
1040
|
+
setIsLoaded(true);
|
|
1041
|
+
}
|
|
1042
|
+
})();
|
|
1043
|
+
}, []);
|
|
1044
|
+
useEffect(() => {
|
|
1045
|
+
if (!isLoaded) {
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
void writeSortPreferences(sortPreferences);
|
|
1049
|
+
}, [isLoaded, sortPreferences]);
|
|
1050
|
+
return { sortPreferences, setSortPreferences, isLoaded };
|
|
799
1051
|
};
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
1052
|
+
|
|
1053
|
+
// src/presentation/hooks/useVisibleCount.ts
|
|
1054
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
1055
|
+
var useVisibleCount = (stdout, linesPerProject, panelVisible, panelHeight, minimumVisibleProjectCount2) => {
|
|
1056
|
+
const compute = () => {
|
|
1057
|
+
if (!stdout || typeof stdout.columns !== "number" || typeof stdout.rows !== "number") {
|
|
1058
|
+
return minimumVisibleProjectCount2;
|
|
1059
|
+
}
|
|
1060
|
+
const borderRows = 2;
|
|
1061
|
+
const hintRows = 1;
|
|
1062
|
+
const reservedRows = borderRows + hintRows + (panelVisible ? panelHeight : 0);
|
|
1063
|
+
const availableRows = Math.max(0, stdout.rows - reservedRows);
|
|
1064
|
+
const rowsPerProject = Math.max(linesPerProject, 1);
|
|
1065
|
+
const calculatedCount = Math.max(1, Math.floor(availableRows / rowsPerProject));
|
|
1066
|
+
return calculatedCount;
|
|
1067
|
+
};
|
|
1068
|
+
const [visibleCount, setVisibleCount] = useState2(compute);
|
|
1069
|
+
useEffect2(() => {
|
|
1070
|
+
const updateVisible = () => setVisibleCount(compute());
|
|
1071
|
+
updateVisible();
|
|
1072
|
+
stdout?.on("resize", updateVisible);
|
|
1073
|
+
return () => {
|
|
1074
|
+
stdout?.off("resize", updateVisible);
|
|
1075
|
+
};
|
|
1076
|
+
}, [stdout, linesPerProject, panelVisible, panelHeight]);
|
|
1077
|
+
return visibleCount;
|
|
805
1078
|
};
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
1079
|
+
|
|
1080
|
+
// src/presentation/App.tsx
|
|
1081
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1082
|
+
var extractRootFolder2 = (repository) => {
|
|
1083
|
+
if (!repository?.root) {
|
|
1084
|
+
return void 0;
|
|
810
1085
|
}
|
|
811
|
-
|
|
1086
|
+
const segments = repository.root.split("/").filter((segment) => segment.length > 0);
|
|
1087
|
+
if (segments.length === 0) {
|
|
1088
|
+
return void 0;
|
|
1089
|
+
}
|
|
1090
|
+
return segments[segments.length - 1];
|
|
812
1091
|
};
|
|
813
|
-
var
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
if (width + w > maxWidth) break;
|
|
819
|
-
result += ch;
|
|
820
|
-
width += w;
|
|
821
|
-
}
|
|
822
|
-
return result;
|
|
1092
|
+
var minimumVisibleProjectCount = 4;
|
|
1093
|
+
var defaultHintMessage = "Select: j/k \xB7 Open: o \xB7 Quit: q \xB7 Refresh: r \xB7 CopyPath: c \xB7 Sort: s \xB7 Close: ctrl + c";
|
|
1094
|
+
var getCopyTargetPath = (view) => {
|
|
1095
|
+
const root = view.repository?.root;
|
|
1096
|
+
return root && root.length > 0 ? root : view.project.path;
|
|
823
1097
|
};
|
|
824
1098
|
var App = ({
|
|
825
1099
|
projects,
|
|
@@ -831,31 +1105,24 @@ var App = ({
|
|
|
831
1105
|
showPath = true
|
|
832
1106
|
}) => {
|
|
833
1107
|
const { exit } = useApp();
|
|
834
|
-
const { stdout } =
|
|
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);
|
|
1108
|
+
const { stdout } = useStdout2();
|
|
1109
|
+
const [projectViews, setProjectViews] = useState3(projects);
|
|
1110
|
+
const [isSortMenuOpen, setIsSortMenuOpen] = useState3(false);
|
|
848
1111
|
const linesPerProject = (showBranch ? 1 : 0) + (showPath ? 1 : 0) + 2;
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
const
|
|
1112
|
+
const panelHeight = 6;
|
|
1113
|
+
const visibleCount = useVisibleCount(stdout, linesPerProject, isSortMenuOpen, panelHeight, minimumVisibleProjectCount);
|
|
1114
|
+
const [index, setIndex] = useState3(0);
|
|
1115
|
+
const [hint, setHint] = useState3(defaultHintMessage);
|
|
1116
|
+
const [windowStart, setWindowStart] = useState3(0);
|
|
1117
|
+
const [releasedProjects, setReleasedProjects] = useState3(/* @__PURE__ */ new Set());
|
|
1118
|
+
const [launchedProjects, setLaunchedProjects] = useState3(/* @__PURE__ */ new Set());
|
|
1119
|
+
const [isRefreshing, setIsRefreshing] = useState3(false);
|
|
1120
|
+
const [sortMenuIndex, setSortMenuIndex] = useState3(0);
|
|
1121
|
+
const { sortPreferences, setSortPreferences } = useSortPreferences();
|
|
1122
|
+
const sortedProjects = useMemo2(() => {
|
|
856
1123
|
const fallbackTime = 0;
|
|
857
1124
|
const getNameKey = (view) => {
|
|
858
|
-
const rootName =
|
|
1125
|
+
const rootName = extractRootFolder2(view.repository);
|
|
859
1126
|
const base = rootName || view.project.title;
|
|
860
1127
|
return base.toLocaleLowerCase();
|
|
861
1128
|
};
|
|
@@ -904,24 +1171,7 @@ var App = ({
|
|
|
904
1171
|
return tieBreaker(a).localeCompare(tieBreaker(b));
|
|
905
1172
|
});
|
|
906
1173
|
}, [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(() => {
|
|
1174
|
+
useEffect3(() => {
|
|
925
1175
|
const handleSigint = () => {
|
|
926
1176
|
exit();
|
|
927
1177
|
};
|
|
@@ -930,26 +1180,6 @@ var App = ({
|
|
|
930
1180
|
process.off("SIGINT", handleSigint);
|
|
931
1181
|
};
|
|
932
1182
|
}, [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
1183
|
const limit = Math.max(1, visibleCount);
|
|
954
1184
|
const move = useCallback(
|
|
955
1185
|
(delta) => {
|
|
@@ -994,7 +1224,7 @@ var App = ({
|
|
|
994
1224
|
},
|
|
995
1225
|
[index, limit, sortedProjects.length]
|
|
996
1226
|
);
|
|
997
|
-
|
|
1227
|
+
useEffect3(() => {
|
|
998
1228
|
setWindowStart((prevStart) => {
|
|
999
1229
|
if (sortedProjects.length <= limit) {
|
|
1000
1230
|
return prevStart === 0 ? prevStart : 0;
|
|
@@ -1137,7 +1367,7 @@ var App = ({
|
|
|
1137
1367
|
}, 3e3);
|
|
1138
1368
|
}
|
|
1139
1369
|
}, [index, onTerminate, sortedProjects]);
|
|
1140
|
-
|
|
1370
|
+
useEffect3(() => {
|
|
1141
1371
|
setProjectViews(projects);
|
|
1142
1372
|
setReleasedProjects(/* @__PURE__ */ new Set());
|
|
1143
1373
|
setLaunchedProjects(/* @__PURE__ */ new Set());
|
|
@@ -1198,10 +1428,7 @@ var App = ({
|
|
|
1198
1428
|
useInput((input, key) => {
|
|
1199
1429
|
if (isSortMenuOpen) {
|
|
1200
1430
|
if (key.escape || input === "\x1B") {
|
|
1201
|
-
clearOverlay();
|
|
1202
|
-
forceFullRepaint();
|
|
1203
1431
|
setIsSortMenuOpen(false);
|
|
1204
|
-
setRenderEpoch((prev) => prev + 1);
|
|
1205
1432
|
return;
|
|
1206
1433
|
}
|
|
1207
1434
|
if (input === "j") {
|
|
@@ -1262,7 +1489,7 @@ var App = ({
|
|
|
1262
1489
|
copyProjectPath();
|
|
1263
1490
|
}
|
|
1264
1491
|
});
|
|
1265
|
-
const { startIndex, visibleProjects } =
|
|
1492
|
+
const { startIndex, visibleProjects } = useMemo2(() => {
|
|
1266
1493
|
if (sortedProjects.length <= limit) {
|
|
1267
1494
|
return {
|
|
1268
1495
|
startIndex: 0,
|
|
@@ -1277,219 +1504,53 @@ var App = ({
|
|
|
1277
1504
|
visibleProjects: sortedProjects.slice(clampedStart, end)
|
|
1278
1505
|
};
|
|
1279
1506
|
}, [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";
|
|
1507
|
+
return /* @__PURE__ */ jsx5(
|
|
1508
|
+
LayoutManager,
|
|
1509
|
+
{
|
|
1510
|
+
layoutMode: getLayoutMode(),
|
|
1511
|
+
panelVisible: isSortMenuOpen,
|
|
1512
|
+
list: /* @__PURE__ */ jsx5(
|
|
1513
|
+
Box5,
|
|
1514
|
+
{
|
|
1515
|
+
flexDirection: "column",
|
|
1516
|
+
borderStyle: "round",
|
|
1517
|
+
borderColor: "green",
|
|
1518
|
+
width: typeof stdout?.columns === "number" ? stdout.columns : void 0,
|
|
1519
|
+
children: sortedProjects.length === 0 ? /* @__PURE__ */ jsx5(Text3, { children: "No Unity Hub projects were found." }) : /* @__PURE__ */ jsx5(
|
|
1520
|
+
ProjectList,
|
|
1521
|
+
{
|
|
1522
|
+
visibleProjects,
|
|
1523
|
+
startIndex,
|
|
1524
|
+
selectedIndex: index,
|
|
1525
|
+
linesPerProject,
|
|
1526
|
+
showBranch,
|
|
1527
|
+
showPath,
|
|
1528
|
+
useGitRootName,
|
|
1529
|
+
releasedProjects,
|
|
1530
|
+
launchedProjects,
|
|
1531
|
+
totalProjects: sortedProjects.length
|
|
1532
|
+
}
|
|
1533
|
+
)
|
|
1325
1534
|
}
|
|
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
|
-
}
|
|
1535
|
+
),
|
|
1536
|
+
panel: /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", width: typeof stdout?.columns === "number" ? stdout.columns : void 0, children: [
|
|
1537
|
+
/* @__PURE__ */ jsx5(Text3, { children: "Sort Settings" }),
|
|
1538
|
+
/* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(
|
|
1539
|
+
SortPanel,
|
|
1540
|
+
{
|
|
1541
|
+
sortPreferences,
|
|
1542
|
+
focusedIndex: sortMenuIndex,
|
|
1543
|
+
width: typeof stdout?.columns === "number" ? stdout.columns : void 0
|
|
1544
|
+
}
|
|
1545
|
+
) })
|
|
1546
|
+
] }),
|
|
1547
|
+
statusBar: isSortMenuOpen ? /* @__PURE__ */ jsx5(Text3, { wrap: "truncate", children: "Select: j/k, Toggle: Space, Back: Esc" }) : /* @__PURE__ */ jsx5(Text3, { wrap: "truncate", children: hint })
|
|
1482
1548
|
}
|
|
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);
|
|
1549
|
+
);
|
|
1489
1550
|
};
|
|
1490
1551
|
|
|
1491
1552
|
// src/index.tsx
|
|
1492
|
-
import { jsx as
|
|
1553
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1493
1554
|
var bootstrap = async () => {
|
|
1494
1555
|
const unityHubReader = new UnityHubProjectsReader();
|
|
1495
1556
|
const gitRepositoryInfoReader = new GitRepositoryInfoReader();
|
|
@@ -1525,7 +1586,7 @@ var bootstrap = async () => {
|
|
|
1525
1586
|
try {
|
|
1526
1587
|
const projects = await listProjectsUseCase.execute();
|
|
1527
1588
|
const { waitUntilExit } = render(
|
|
1528
|
-
/* @__PURE__ */
|
|
1589
|
+
/* @__PURE__ */ jsx6(
|
|
1529
1590
|
App,
|
|
1530
1591
|
{
|
|
1531
1592
|
projects,
|