mirror of
https://github.com/ershisan99/DevToysWeb.git
synced 2025-12-16 20:49:23 +00:00
feat: add uuid generator
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
87
src/components/pages/generators/uuid/Configuration.tsx
Normal file
87
src/components/pages/generators/uuid/Configuration.tsx
Normal 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;
|
||||
115
src/components/pages/generators/uuid/Content.tsx
Normal file
115
src/components/pages/generators/uuid/Content.tsx
Normal 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;
|
||||
3
src/components/pages/generators/uuid/index.ts
Normal file
3
src/components/pages/generators/uuid/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import Content from "./Content";
|
||||
|
||||
export { Content };
|
||||
@@ -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,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -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
15
src/libs/uuid.ts
Normal 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;
|
||||
};
|
||||
7
src/pages/generators/uuid.tsx
Normal file
7
src/pages/generators/uuid.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { NextPage } from "next";
|
||||
|
||||
import { Content } from "@/components/pages/generators/uuid";
|
||||
|
||||
const Page: NextPage = Content;
|
||||
|
||||
export default Page;
|
||||
10
yarn.lock
10
yarn.lock
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user