feat: add uuid generator

This commit is contained in:
rusconn
2022-04-02 19:02:41 +09:00
parent 8e79da00f3
commit d410830b7e
10 changed files with 248 additions and 3 deletions

View File

@@ -10,7 +10,7 @@ A web clone of [DevToys](https://github.com/veler/DevToys)
- [x] Converters
- [x] Encoders / Decoders
- [x] Formatters
- [ ] Generators
- [x] Generators
- [ ] Text
- [ ] Graphic
- [ ] Support dark mode

View File

@@ -36,6 +36,7 @@
"react-ace": "^9.5.0",
"react-dom": "17.0.2",
"recoil": "^0.6.1",
"uuid": "^8.3.2",
"yaml": "^1.10.2"
},
"devDependencies": {
@@ -43,6 +44,7 @@
"@types/create-hash": "^1.2.2",
"@types/node": "^16.11.45",
"@types/react": "17.0.41",
"@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "^5.15.0",
"@typescript-eslint/parser": "^5.15.0",
"babel-plugin-import": "^1.13.3",

View File

@@ -0,0 +1,87 @@
import { FontDownload, HorizontalRule, Tune } from "@mui/icons-material";
import { FormControl, FormControlLabel, MenuItem, Select, Switch } from "@mui/material";
import { SwitchBaseProps } from "@mui/material/internal/SwitchBase";
import { SelectInputProps } from "@mui/material/Select/SelectInput";
import { css } from "@mui/material/styles";
import { memo } from "react";
import { Configurations } from "@/components/common";
const uuidVersions = [1, 4] as const;
export type UuidVersion = typeof uuidVersions[number];
export const isUuidVersion = (x: number): x is UuidVersion =>
uuidVersions.includes(x as UuidVersion);
type SwitchChecked = NonNullable<SwitchBaseProps["checked"]>;
type OnSwitchChange = NonNullable<SwitchBaseProps["onChange"]>;
type OnSelectChange<T> = NonNullable<SelectInputProps<T>["onChange"]>;
type Props = {
hyphens: SwitchChecked;
uppercase: SwitchChecked;
uuidVersion: UuidVersion;
onHyphensChange: OnSwitchChange;
onCaseChange: OnSwitchChange;
onUuidVersionChange: OnSelectChange<UuidVersion>;
};
const select = css`
& .MuiSelect-select:focus {
background-color: transparent;
}
`;
const StyledComponent = ({
hyphens,
uppercase,
uuidVersion,
onHyphensChange,
onCaseChange,
onUuidVersionChange,
}: Props) => (
<Configurations
configurations={[
{
icon: <HorizontalRule />,
title: "Hyphens",
input: (
<FormControlLabel
labelPlacement="start"
label={hyphens ? "On" : "Off"}
control={<Switch checked={hyphens} onChange={onHyphensChange} />}
/>
),
},
{
icon: <FontDownload />,
title: "Uppercase",
input: (
<FormControlLabel
labelPlacement="start"
label={uppercase ? "On" : "Off"}
control={<Switch checked={uppercase} onChange={onCaseChange} />}
/>
),
},
{
icon: <Tune />,
title: "UUID version",
input: (
<FormControl variant="standard">
<Select value={uuidVersion} onChange={onUuidVersionChange} css={select}>
{uuidVersions.map(value => (
<MenuItem key={value} {...{ value }}>
{value === 1 ? "1" : "4 (GUID)"}
</MenuItem>
))}
</Select>
</FormControl>
),
},
]}
/>
);
export const Component = memo(StyledComponent);
export default Component;

View File

@@ -0,0 +1,115 @@
import { Button, Stack, Typography } from "@mui/material";
import { range } from "fp-ts/NonEmptyArray";
import { ComponentPropsWithoutRef, memo, useCallback, useState } from "react";
import { Main, MainItem, TextField } from "@/components/common";
import { uuid } from "@/libs/uuid";
import Configuration, { isUuidVersion, UuidVersion } from "./Configuration";
type TextFieldValue = ComponentPropsWithoutRef<typeof TextField>["value"];
type OnTextFieldChange = NonNullable<ComponentPropsWithoutRef<typeof TextField>["onChange"]>;
type OnButtonClick = NonNullable<ComponentPropsWithoutRef<typeof Button>["onChange"]>;
type Props = {
generates: TextFieldValue;
uuids: TextFieldValue;
onGeneratesChange: OnTextFieldChange;
onGenerateClick: OnButtonClick;
} & ComponentPropsWithoutRef<typeof Configuration>;
const StyledComponent = ({
hyphens,
uppercase,
uuidVersion,
generates,
uuids,
onHyphensChange,
onCaseChange,
onUuidVersionChange,
onGeneratesChange,
onGenerateClick,
}: Props) => (
<Main title="UUID Generator">
<MainItem title="Configuration">
<Configuration
{...{ hyphens, uppercase, uuidVersion, onHyphensChange, onCaseChange, onUuidVersionChange }}
/>
</MainItem>
<MainItem title="Generate">
<Stack direction="row" spacing={1} alignItems="center">
<Button variant="contained" onClick={onGenerateClick}>
Generate UUID(s)
</Button>
<Typography fontSize={theme => theme.typography.fontSize * 2.2}>×</Typography>
<TextField type="number" fullWidth={false} value={generates} onChange={onGeneratesChange} />
</Stack>
</MainItem>
<MainItem title="UUID(s)">
<TextField multiline rows={10} value={uuids} InputProps={{ readOnly: true }} />
</MainItem>
</Main>
);
export const Component = memo(StyledComponent);
const Container = () => {
const [hyphens, setHyphens] = useState(true);
const [uppercase, setUppercase] = useState(false);
const [uuidVersion, setUuidVersion] = useState<UuidVersion>(4);
const [generates, setGenerates] = useState(1);
const [uuidArray, setUuidArray] = useState<string[]>([]);
const onHyphensChange: Props["onHyphensChange"] = useCallback((_e, checked) => {
setHyphens(checked);
}, []);
const onCaseChange: Props["onCaseChange"] = useCallback((_e, checked) => {
setUppercase(checked);
}, []);
const onUuidVersionChange: Props["onUuidVersionChange"] = useCallback(({ target: { value } }) => {
const newUuidVersion = Number(value);
if (isUuidVersion(newUuidVersion)) {
setUuidVersion(newUuidVersion);
}
}, []);
const onGeneratesChange: Props["onGeneratesChange"] = useCallback(
({ currentTarget: { value } }) => {
const newGenerates = Number(value);
if (newGenerates >= 1 && newGenerates <= 1000) {
setGenerates(newGenerates);
}
},
[]
);
const onGenerateClick: Props["onGenerateClick"] = useCallback(() => {
const newUuids = range(1, generates).map(_ => uuid(uuidVersion, hyphens, uppercase));
setUuidArray([...uuidArray, ...newUuids]);
}, [hyphens, uppercase, uuidVersion, generates, uuidArray]);
const uuids = uuidArray.join("\n");
return (
<Component
{...{
hyphens,
uppercase,
uuidVersion,
generates,
uuids,
onHyphensChange,
onCaseChange,
onUuidVersionChange,
onGeneratesChange,
onGenerateClick,
}}
/>
);
};
export default Container;

View File

@@ -0,0 +1,3 @@
import Content from "./Content";
export { Content };

View File

@@ -121,8 +121,8 @@ const toolGroups = [
longTitle: "UUID Generator",
description: "Generate UUIDs version 1 and 4",
keywords: "guid uuid1 uuid4 generator",
href: pagesPath.$url(),
disabled: true,
href: pagesPath.generators.uuid.$url(),
disabled: false,
},
],
},

View File

@@ -54,6 +54,12 @@ export const pagesPath = {
hash: url?.hash,
}),
},
uuid: {
$url: (url?: { hash?: string }) => ({
pathname: "/generators/uuid" as const,
hash: url?.hash,
}),
},
},
search: {
$url: (url?: { hash?: string }) => ({ pathname: "/search" as const, hash: url?.hash }),

15
src/libs/uuid.ts Normal file
View File

@@ -0,0 +1,15 @@
import { v1 as uuidv1, v4 as uuidv4 } from "uuid";
export const uuid = (version: 1 | 4, hyphens: boolean, uppercase: boolean) => {
let generated = version === 1 ? uuidv1() : uuidv4();
if (!hyphens) {
generated = generated.replaceAll("-", "");
}
if (uppercase) {
generated = generated.toUpperCase();
}
return generated;
};

View File

@@ -0,0 +1,7 @@
import type { NextPage } from "next";
import { Content } from "@/components/pages/generators/uuid";
const Page: NextPage = Content;
export default Page;

View File

@@ -459,6 +459,11 @@
resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz"
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
"@types/uuid@^8.3.4":
version "8.3.4"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc"
integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==
"@typescript-eslint/eslint-plugin@^5.15.0":
version "5.15.0"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.15.0.tgz"
@@ -2655,6 +2660,11 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1:
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
v8-compile-cache@^2.0.3:
version "2.3.0"
resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz"