mirror of
https://github.com/trafficlunar/blockmatic.git
synced 2026-06-28 06:34:13 +00:00
feat: set version dialog
This commit is contained in:
parent
cf83d2fc7c
commit
a7e5dfd3d6
10 changed files with 908 additions and 27 deletions
80
src/components/VersionCombobox.tsx
Normal file
80
src/components/VersionCombobox.tsx
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { numberToVersion, versionToNumber } from "@/utils/version";
|
||||
|
||||
const versions = [
|
||||
"1.21.4",
|
||||
"1.21",
|
||||
"1.20",
|
||||
"1.18",
|
||||
"1.19",
|
||||
"1.17",
|
||||
"1.16",
|
||||
"1.15",
|
||||
"1.14",
|
||||
"1.13",
|
||||
"1.12",
|
||||
"1.11",
|
||||
"1.10",
|
||||
"1.9",
|
||||
"1.8",
|
||||
"1.7.2",
|
||||
"1.6.1",
|
||||
];
|
||||
|
||||
interface Props {
|
||||
version: number;
|
||||
setVersion: React.Dispatch<React.SetStateAction<number>>;
|
||||
}
|
||||
|
||||
function VersionCombobox({ version, setVersion }: Props) {
|
||||
const [comboboxOpen, setComboboxOpen] = useState(false);
|
||||
const [comboboxValue, setComboboxValue] = useState(numberToVersion(version));
|
||||
|
||||
useEffect(() => {
|
||||
setVersion(versionToNumber(comboboxValue));
|
||||
}, [comboboxValue]);
|
||||
|
||||
return (
|
||||
<Popover open={comboboxOpen} onOpenChange={setComboboxOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline" role="combobox" aria-expanded={comboboxOpen} className="w-[200px] justify-between">
|
||||
{comboboxValue ? versions.find((version) => version === comboboxValue) : "Select version..."}
|
||||
|
||||
<ChevronsUpDownIcon className="opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[200px] p-0 pointer-events-auto">
|
||||
<Command>
|
||||
<CommandInput placeholder="Search version..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No version found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{versions.map((version) => (
|
||||
<CommandItem
|
||||
key={version}
|
||||
value={version}
|
||||
onSelect={(currentValue) => {
|
||||
setComboboxValue(currentValue === comboboxValue ? versions[0] : currentValue);
|
||||
setComboboxOpen(false);
|
||||
}}
|
||||
>
|
||||
{version}
|
||||
<CheckIcon className={cn("ml-auto", comboboxValue === version ? "opacity-100" : "opacity-0")} />
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
export default VersionCombobox;
|
||||
40
src/components/dialogs/SetVersion.tsx
Normal file
40
src/components/dialogs/SetVersion.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { useContext, useState } from "react";
|
||||
|
||||
import { CanvasContext } from "@/context/Canvas";
|
||||
|
||||
import { DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import VersionCombobox from "../VersionCombobox";
|
||||
|
||||
function SetVersion({ close }: DialogProps) {
|
||||
const { version: contextVersion, setVersion: setContextVersion } = useContext(CanvasContext);
|
||||
|
||||
const [version, setVersion] = useState(contextVersion);
|
||||
|
||||
const onSubmit = () => {
|
||||
setContextVersion(version);
|
||||
close();
|
||||
};
|
||||
|
||||
return (
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Set Version</DialogTitle>
|
||||
<DialogDescription>Updates your block palette to the specified Minecraft version</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<VersionCombobox version={version} setVersion={setVersion} />
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={close}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" onClick={onSubmit}>
|
||||
Set
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default SetVersion;
|
||||
|
|
@ -34,6 +34,7 @@ function FileMenu() {
|
|||
</MenubarSub>
|
||||
<MenubarSeparator />
|
||||
|
||||
<MenubarItem onClick={() => openDialog("SetVersion")}>Set Version</MenubarItem>
|
||||
<MenubarItem onClick={() => openDialog("ClearBlocks")}>Clear All Blocks</MenubarItem>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
|
|
|
|||
151
src/components/ui/command.tsx
Normal file
151
src/components/ui/command.tsx
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
import * as React from "react"
|
||||
import { type DialogProps } from "@radix-ui/react-dialog"
|
||||
import { Command as CommandPrimitive } from "cmdk"
|
||||
import { Search } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col overflow-hidden rounded-md bg-white text-zinc-950 dark:bg-zinc-950 dark:text-zinc-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Command.displayName = CommandPrimitive.displayName
|
||||
|
||||
const CommandDialog = ({ children, ...props }: DialogProps) => {
|
||||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogContent className="overflow-hidden p-0 shadow-lg">
|
||||
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-zinc-500 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5 dark:[&_[cmdk-group-heading]]:text-zinc-400">
|
||||
{children}
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
const CommandInput = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-zinc-500 disabled:cursor-not-allowed disabled:opacity-50 dark:placeholder:text-zinc-400",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
|
||||
CommandInput.displayName = CommandPrimitive.Input.displayName
|
||||
|
||||
const CommandList = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.List
|
||||
ref={ref}
|
||||
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandList.displayName = CommandPrimitive.List.displayName
|
||||
|
||||
const CommandEmpty = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
||||
>((props, ref) => (
|
||||
<CommandPrimitive.Empty
|
||||
ref={ref}
|
||||
className="py-6 text-center text-sm"
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||
|
||||
const CommandGroup = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Group
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"overflow-hidden p-1 text-zinc-950 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-zinc-500 dark:text-zinc-50 dark:[&_[cmdk-group-heading]]:text-zinc-400",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
||||
|
||||
const CommandSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 h-px bg-zinc-200 dark:bg-zinc-800", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||
|
||||
const CommandItem = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-zinc-100 data-[selected=true]:text-zinc-900 data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:data-[selected='true']:bg-zinc-800 dark:data-[selected=true]:text-zinc-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||
|
||||
const CommandShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-zinc-500 dark:text-zinc-400",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
CommandShortcut.displayName = "CommandShortcut"
|
||||
|
||||
export {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandInput,
|
||||
CommandList,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandSeparator,
|
||||
}
|
||||
29
src/components/ui/popover.tsx
Normal file
29
src/components/ui/popover.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import * as React from "react"
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Popover = PopoverPrimitive.Root
|
||||
|
||||
const PopoverTrigger = PopoverPrimitive.Trigger
|
||||
|
||||
const PopoverContent = React.forwardRef<
|
||||
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-72 rounded-md border border-zinc-200 bg-white p-4 text-zinc-950 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
))
|
||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent }
|
||||
|
|
@ -25,7 +25,7 @@ export const CanvasProvider = ({ children }: Props) => {
|
|||
const [blocks, setBlocks] = useState<Block[]>([]);
|
||||
const [coords, setCoords] = useState<Position>({ x: 0, y: 0 });
|
||||
const [scale, setScale] = useState(1);
|
||||
const [version, setVersion] = useState(1200);
|
||||
const [version, setVersion] = useState(1214);
|
||||
|
||||
const canvasSize = useMemo(() => {
|
||||
let minX = Infinity,
|
||||
|
|
|
|||
|
|
@ -503,13 +503,13 @@
|
|||
},
|
||||
"chiseled_nether_bricks": {
|
||||
"name": "Chiseled Nether Bricks",
|
||||
"version": 1000,
|
||||
"version": 1160,
|
||||
"id": ["chiseled_nether_bricks", 887],
|
||||
"color": [48, 24, 29, 255]
|
||||
},
|
||||
"chiseled_polished_blackstone": {
|
||||
"name": "Chiseled Polished Blackstone",
|
||||
"version": 1000,
|
||||
"version": 1160,
|
||||
"id": ["chiseled_polished_blackstone", 877],
|
||||
"color": [57, 53, 61, 255]
|
||||
},
|
||||
|
|
@ -539,7 +539,7 @@
|
|||
},
|
||||
"chiseled_stone_bricks": {
|
||||
"name": "Chiseled Stone Bricks",
|
||||
"version": 1000,
|
||||
"version": 1020,
|
||||
"id": ["chiseled_stone_bricks", 310],
|
||||
"color": [122, 121, 122, 255]
|
||||
},
|
||||
|
|
@ -1505,7 +1505,7 @@
|
|||
},
|
||||
"lodestone_side": {
|
||||
"name": "Lodestone",
|
||||
"version": 1000,
|
||||
"version": 1160,
|
||||
"id": ["lodestone", 869],
|
||||
"color": [124, 125, 128, 255]
|
||||
},
|
||||
|
|
@ -1669,7 +1669,7 @@
|
|||
},
|
||||
"nether_gold_ore": {
|
||||
"name": "Nether Gold Ore",
|
||||
"version": 1000,
|
||||
"version": 1160,
|
||||
"id": ["nether_gold_ore", 48],
|
||||
"color": [124, 74, 47, 255]
|
||||
},
|
||||
|
|
@ -1857,7 +1857,7 @@
|
|||
},
|
||||
"packed_ice": {
|
||||
"name": "Packed Ice",
|
||||
"version": 1000,
|
||||
"version": 1072,
|
||||
"id": ["packed_ice", 513],
|
||||
"color": [142, 180, 251, 255]
|
||||
},
|
||||
|
|
@ -2177,7 +2177,7 @@
|
|||
},
|
||||
"red_nether_bricks": {
|
||||
"name": "Red Nether Bricks",
|
||||
"version": 1000,
|
||||
"version": 1100,
|
||||
"id": ["red_nether_bricks", 630],
|
||||
"color": [73, 10, 12, 255]
|
||||
},
|
||||
|
|
@ -2259,7 +2259,7 @@
|
|||
},
|
||||
"resin_bricks": {
|
||||
"name": "Resin Bricks",
|
||||
"version": 1000,
|
||||
"version": 1214,
|
||||
"id": ["resin_bricks", -1],
|
||||
"color": [207, 94, 29, 255]
|
||||
},
|
||||
|
|
@ -2271,7 +2271,7 @@
|
|||
},
|
||||
"rooted_dirt": {
|
||||
"name": "Rooted Dirt",
|
||||
"version": 1000,
|
||||
"version": 1170,
|
||||
"id": ["rooted_dirt", 1042],
|
||||
"color": [147, 107, 81, 255]
|
||||
},
|
||||
|
|
@ -2357,7 +2357,7 @@
|
|||
},
|
||||
"smooth_stone_slab_side": {
|
||||
"name": "Smooth Stone Slab",
|
||||
"version": 1000,
|
||||
"version": 1140,
|
||||
"id": ["smooth_stone_slab", 568],
|
||||
"color": [169, 169, 169, 255],
|
||||
"properties": {
|
||||
|
|
@ -2453,13 +2453,13 @@
|
|||
},
|
||||
"stripped_bamboo_block": {
|
||||
"name": "Block of Stripped Bamboo",
|
||||
"version": 1130,
|
||||
"version": 1200,
|
||||
"id": ["stripped_bamboo_block", 70],
|
||||
"color": [195, 175, 82, 255]
|
||||
},
|
||||
"stripped_bamboo_block_top": {
|
||||
"name": "Block of Stripped Bamboo (Top)",
|
||||
"version": 1130,
|
||||
"version": 1200,
|
||||
"id": ["stripped_bamboo_block", 70],
|
||||
"color": [183, 163, 77, 255],
|
||||
"properties": {
|
||||
|
|
@ -2483,13 +2483,13 @@
|
|||
},
|
||||
"stripped_cherry_log": {
|
||||
"name": "Stripped Cherry Log",
|
||||
"version": 1130,
|
||||
"version": 1200,
|
||||
"id": ["stripped_cherry_log", 65],
|
||||
"color": [215, 145, 149, 255]
|
||||
},
|
||||
"stripped_cherry_log_top": {
|
||||
"name": "Stripped Cherry Log (Top)",
|
||||
"version": 1130,
|
||||
"version": 1200,
|
||||
"id": ["stripped_cherry_log", 65],
|
||||
"color": [221, 166, 159, 255],
|
||||
"properties": {
|
||||
|
|
@ -2498,13 +2498,13 @@
|
|||
},
|
||||
"stripped_crimson_stem": {
|
||||
"name": "Stripped Crimson Stem",
|
||||
"version": 1130,
|
||||
"version": 1160,
|
||||
"id": ["stripped_crimson_stem", 820],
|
||||
"color": [138, 58, 90, 255]
|
||||
},
|
||||
"stripped_crimson_stem_top": {
|
||||
"name": "Stripped Crimson Stem (Top)",
|
||||
"version": 1130,
|
||||
"version": 1160,
|
||||
"id": ["stripped_crimson_stem", 820],
|
||||
"color": [123, 57, 83, 255],
|
||||
"properties": {
|
||||
|
|
@ -2543,13 +2543,13 @@
|
|||
},
|
||||
"stripped_mangrove_log": {
|
||||
"name": "Stripped Mangrove Log",
|
||||
"version": 1130,
|
||||
"version": 1190,
|
||||
"id": ["stripped_mangrove_log", 69],
|
||||
"color": [120, 55, 48, 255]
|
||||
},
|
||||
"stripped_mangrove_log_top": {
|
||||
"name": "Stripped Mangrove Log (Top)",
|
||||
"version": 1130,
|
||||
"version": 1190,
|
||||
"id": ["stripped_mangrove_log", 69],
|
||||
"color": [109, 45, 44, 255],
|
||||
"properties": {
|
||||
|
|
@ -2573,13 +2573,13 @@
|
|||
},
|
||||
"stripped_pale_oak_log": {
|
||||
"name": "Stripped Pale Oak Log",
|
||||
"version": 1130,
|
||||
"version": 1214,
|
||||
"id": ["stripped_pale_oak_log", 67],
|
||||
"color": [246, 238, 237, 255]
|
||||
},
|
||||
"stripped_pale_oak_log_top": {
|
||||
"name": "Stripped Pale Oak Log (Top)",
|
||||
"version": 1130,
|
||||
"version": 1214,
|
||||
"id": ["stripped_pale_oak_log", 67],
|
||||
"color": [236, 228, 226, 255],
|
||||
"properties": {
|
||||
|
|
@ -2603,13 +2603,13 @@
|
|||
},
|
||||
"stripped_warped_stem": {
|
||||
"name": "Stripped Warped Stem",
|
||||
"version": 1130,
|
||||
"version": 1160,
|
||||
"id": ["stripped_warped_stem", 811],
|
||||
"color": [58, 151, 148, 255]
|
||||
},
|
||||
"stripped_warped_stem_top": {
|
||||
"name": "Stripped Warped Stem (Top)",
|
||||
"version": 1130,
|
||||
"version": 1160,
|
||||
"id": ["stripped_warped_stem", 811],
|
||||
"color": [53, 130, 126, 255],
|
||||
"properties": {
|
||||
|
|
@ -2632,7 +2632,7 @@
|
|||
},
|
||||
"suspicious_sand_0": {
|
||||
"name": "Suspicious Sand",
|
||||
"version": 1000,
|
||||
"version": 1200,
|
||||
"id": ["suspicious_sand", -1],
|
||||
"color": [218, 205, 160, 255],
|
||||
"fallable": true
|
||||
|
|
@ -2651,7 +2651,7 @@
|
|||
},
|
||||
"tinted_glass": {
|
||||
"name": "Tinted Glass",
|
||||
"version": 1000,
|
||||
"version": 1170,
|
||||
"id": ["tinted_glass", 945],
|
||||
"color": [45, 39, 48, 131]
|
||||
},
|
||||
|
|
@ -2663,7 +2663,7 @@
|
|||
},
|
||||
"trial_spawner_side_inactive": {
|
||||
"name": "Trial Spawner",
|
||||
"version": 1000,
|
||||
"version": 1210,
|
||||
"id": ["trial_spawner", -1],
|
||||
"color": [56, 76, 90, 193],
|
||||
"creative": true
|
||||
|
|
@ -2683,7 +2683,7 @@
|
|||
},
|
||||
"tuff_bricks": {
|
||||
"name": "Tuff Bricks",
|
||||
"version": 1000,
|
||||
"version": 1210,
|
||||
"id": ["tuff_bricks", 939],
|
||||
"color": [101, 105, 98, 255]
|
||||
},
|
||||
|
|
|
|||
18
src/utils/version.ts
Normal file
18
src/utils/version.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
export function versionToNumber(version: string) {
|
||||
const parts = version.split(".").map(Number);
|
||||
return parts[0] * 1000 + (parts[1] || 0) * 10 + (parts[2] || 0);
|
||||
}
|
||||
|
||||
export function numberToVersion(version: number) {
|
||||
const major = Math.floor(version / 1000);
|
||||
const minor = version % 1000; // Remainder becomes the minor and patch version
|
||||
|
||||
// If minor is a multiple of 10, it's just minor with no patch
|
||||
if (minor % 10 === 0) {
|
||||
return `${major}.${Math.floor(minor / 10)}`;
|
||||
}
|
||||
|
||||
// Otherwise, split into minor and patch
|
||||
const patch = minor % 10;
|
||||
return `${major}.${Math.floor(minor / 10)}.${patch}`;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue