-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathVersion.tsx
More file actions
127 lines (118 loc) · 4.96 KB
/
Version.tsx
File metadata and controls
127 lines (118 loc) · 4.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { Button } from "@fluffylabs/shared-ui";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
} from "@fluffylabs/shared-ui";
import { ChevronDown } from "lucide-react";
import { useCallback, useContext, useRef } from "react";
import { Tooltip } from "react-tooltip";
import { CodeSyncContext, type ICodeSyncContext } from "../CodeSyncProvider/CodeSyncProvider";
import { type ILocationContext, LocationContext } from "../LocationProvider/LocationProvider";
import { type IMetadataContext, type IVersionInfo, MetadataContext } from "../MetadataProvider/MetadataProvider";
export function Version() {
const { metadata } = useContext(MetadataContext) as IMetadataContext;
const { locationParams, setLocationParams } = useContext(LocationContext) as ILocationContext;
const { migrateSelection } = useContext(CodeSyncContext) as ICodeSyncContext;
const versions = [...Object.values(metadata.versions).filter(({ legacy }) => !legacy), metadata.nightly];
const isNightly = locationParams.version === metadata.nightly.hash;
const currentVersion = isNightly ? metadata.nightly : metadata.versions[locationParams.version];
const currentVersionHash = currentVersion.hash;
const dropdownContentRef = useRef<HTMLDivElement>(null);
const currentItemRef = useRef<HTMLDivElement>(null);
const handleVersionSelect = useCallback(
(newVersion: string) => {
const { selectionStart, selectionEnd, version } = locationParams;
if (!selectionStart || !selectionEnd) {
setLocationParams({ version: newVersion });
} else {
migrateSelection({ selectionStart, selectionEnd }, version, newVersion).then((newSelection) => {
setLocationParams({
...locationParams,
selectionStart: newSelection?.selectionStart ?? selectionStart,
selectionEnd: newSelection?.selectionEnd ?? selectionEnd,
version: newVersion,
});
});
}
},
[setLocationParams, locationParams, migrateSelection],
);
const getCurrentVersionLabel = () => {
const date = new Date(currentVersion.date);
const isLatest = currentVersion.hash === metadata.latest;
let label = isNightly ? "Nightly" : isLatest ? "Latest" : "v";
if (currentVersion.name && !isNightly) {
label += `: ${currentVersion.name}`;
}
return `${label} ${shortHash(currentVersion.hash)} (${date.toLocaleDateString()})`;
};
const handleOpenChange = (open: boolean) => {
if (open) {
requestAnimationFrame(() => {
if (currentItemRef.current && dropdownContentRef.current) {
currentItemRef.current.scrollIntoView({ block: "center", behavior: "auto" });
}
});
}
};
return (
<div className="flex items-center justify-end gap-2 mx-4">
{currentVersionHash !== metadata.latest && (
<span
data-tooltip-id="version"
data-tooltip-content="The current version is not the latest"
data-tooltip-place="top"
className="text-amber-500 text-2xl mt-[-2px]"
>
⚠
</span>
)}
<DropdownMenu onOpenChange={handleOpenChange}>
<DropdownMenuTrigger asChild>
<Button variant="tertiary" forcedColorScheme="dark" className="flex-1 justify-between h-[32px]">
<span className="px-2">{getCurrentVersionLabel()}</span>
<ChevronDown className="ml-2 h-5 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent ref={dropdownContentRef} className="max-h-[60vh] overflow-y-auto" forcedColorScheme="dark">
<DropdownMenuRadioGroup value={currentVersionHash} onValueChange={handleVersionSelect}>
{versions.map((version) => (
<DropdownMenuRadioItem
value={version.hash}
key={version.hash}
ref={version.hash === currentVersionHash ? currentItemRef : null}
>
<VersionOption version={version} latest={metadata.latest} nightly={metadata.nightly.hash} />
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
<Tooltip
id="version"
style={{ backgroundColor: "oklch(76.9% 0.188 70.08)", zIndex: 1, color: "black", fontSize: "10px" }}
/>
</div>
);
}
type VersionOptionProps = { version: IVersionInfo; latest: string; nightly: string };
function VersionOption({ version, latest, nightly }: VersionOptionProps) {
const date = new Date(version.date);
const isNightly = version.hash === nightly;
const isLatest = version.hash === latest;
let label = isNightly ? "Nightly" : isLatest ? "Latest" : "v";
if (version.name && !isNightly) {
label += `: ${version.name}`;
}
return (
<span className="w-full">
{label} {shortHash(version.hash)} ({date.toLocaleDateString()})
</span>
);
}
function shortHash(h: string) {
return `${h.substring(0, 3)}...${h.substring(h.length - 3)}`;
}