mirror of
https://github.com/ershisan99/DevToysWeb.git
synced 2026-01-07 20:52:07 +00:00
renewal
recreate project by using https://github.com/shadcn/next-template App: - support dark mode - add toggle theme button - add clear search button - add search button - add current page indicator - add tool group pages - add settings tool - add 1 tab format option to Json format tool - add paste button to some tools - add file button to some tools - add copy button to some tools - add clear button to some tools - change favicon - change search hit rate - change each page title - change icons from Material Icons to Lucide - change sidebar scroll area - change editor from Ace to Monaco - change parsable separators of number base converter - change default value of format option of number base converter - change default values of some tool forms - change some styles - remove disabled tools - remove real-time search - fix uri encoding tool Dev: - MUI + Emotion -> Radix UI + Tailwind CSS - Next.js 12 Pages -> Next.js 13 App Router - React 17 -> React 18 - many other packages upgraded - use useState instead of recoil - use Next.js typedRoutes instead of pathpida - clean npm scripts - format import statements by Prettier - no component separations between container and presenter - effective component memoizations - add vscode settings - many refactors
This commit is contained in:
11
app/generators/uuid/layout.tsx
Normal file
11
app/generators/uuid/layout.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Metadata } from "next";
|
||||
|
||||
import { toolGroups } from "@/config/tools";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: toolGroups.generators.tools.uuid.longTitle,
|
||||
};
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
171
app/generators/uuid/page.tsx
Normal file
171
app/generators/uuid/page.tsx
Normal file
@@ -0,0 +1,171 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { range } from "fp-ts/NonEmptyArray";
|
||||
import * as t from "io-ts";
|
||||
|
||||
import { toolGroups } from "@/config/tools";
|
||||
import { uuid } from "@/lib/uuid";
|
||||
import { useScrollFollow } from "@/hooks/useScrollFollow";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input, InputProps } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectProps,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { ClearButton } from "@/components/buttons/clear";
|
||||
import { CopyButton } from "@/components/buttons/copy";
|
||||
import { Configuration } from "@/components/configuration";
|
||||
import { Configurations } from "@/components/configurations";
|
||||
import { ControlMenu } from "@/components/control-menu";
|
||||
import { icons } from "@/components/icons";
|
||||
import { LabeledSwitch } from "@/components/labeled-switch";
|
||||
import { PageRootSection } from "@/components/page-root-section";
|
||||
import { PageSection } from "@/components/page-section";
|
||||
|
||||
const v1 = "1";
|
||||
const v4 = "4";
|
||||
|
||||
const uuidVersions = t.keyof({ [v1]: null, [v4]: null });
|
||||
type UuidVersion = t.TypeOf<typeof uuidVersions>;
|
||||
|
||||
export default function Page() {
|
||||
const [hyphens, setHyphens] = useState(true);
|
||||
const [uppercase, setUppercase] = useState(false);
|
||||
const [uuidVersion, setUuidVersion] = useState<UuidVersion>("4");
|
||||
const [generates, setGenerates] = useState(1);
|
||||
const [uuids, setUuids] = useState<string[]>([]);
|
||||
const ref = useScrollFollow<HTMLTextAreaElement>([uuids]);
|
||||
|
||||
const uuidsString = uuids.join("\n");
|
||||
|
||||
const clearUuids = useCallback(() => setUuids([]), []);
|
||||
|
||||
const onUuidVersionChange: SelectProps["onValueChange"] = value => {
|
||||
if (uuidVersions.is(value)) {
|
||||
setUuidVersion(value);
|
||||
}
|
||||
};
|
||||
|
||||
const onGeneratesChange: InputProps["onChange"] = ({ currentTarget: { value } }) => {
|
||||
const newGenerates = Number(value);
|
||||
|
||||
if (newGenerates >= 1 && newGenerates <= 1000) {
|
||||
setGenerates(newGenerates);
|
||||
}
|
||||
};
|
||||
|
||||
const onGenerateClick = () => {
|
||||
const newUuids = range(1, generates).map(_ => uuid(uuidVersion, hyphens, uppercase));
|
||||
setUuids([...uuids, ...newUuids]);
|
||||
};
|
||||
|
||||
const hyphensConfig = useMemo(
|
||||
() => (
|
||||
<Configuration
|
||||
icon={<icons.Minus size={24} />}
|
||||
title="Hyphens"
|
||||
control={
|
||||
<LabeledSwitch
|
||||
id="hyphens-switch"
|
||||
label={hyphens ? "On" : "Off"}
|
||||
checked={hyphens}
|
||||
onCheckedChange={setHyphens}
|
||||
aria-label="toggle whether to add hyphens"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
[hyphens]
|
||||
);
|
||||
|
||||
const uppercaseConfig = useMemo(
|
||||
() => (
|
||||
<Configuration
|
||||
icon={<icons.CaseSensitive size={24} />}
|
||||
title="Uppercase"
|
||||
control={
|
||||
<LabeledSwitch
|
||||
id="uppercase-switch"
|
||||
label={uppercase ? "On" : "Off"}
|
||||
checked={uppercase}
|
||||
onCheckedChange={setUppercase}
|
||||
aria-label="toggle whether to generate in uppercase"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
[uppercase]
|
||||
);
|
||||
|
||||
const uuidVersionConfig = useMemo(
|
||||
() => (
|
||||
<Configuration
|
||||
icon={<icons.Settings2 size={24} />}
|
||||
title="UUID version"
|
||||
description="Choose the version of UUID to generate"
|
||||
control={
|
||||
<Select value={uuidVersion} onValueChange={onUuidVersionChange}>
|
||||
<SelectTrigger
|
||||
className="w-28"
|
||||
aria-label="toggle open/close state of uuid version selection"
|
||||
>
|
||||
<SelectValue placeholder={uuidVersion} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value={v1}>1</SelectItem>
|
||||
<SelectItem value={v4}>4 (GUID)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
}
|
||||
/>
|
||||
),
|
||||
[uuidVersion]
|
||||
);
|
||||
|
||||
const generatesInput = useMemo(
|
||||
() => (
|
||||
<Input
|
||||
className="w-24 font-sans"
|
||||
type="number"
|
||||
value={generates}
|
||||
onChange={onGeneratesChange}
|
||||
/>
|
||||
),
|
||||
[generates]
|
||||
);
|
||||
|
||||
const uuidsCopyButton = useMemo(() => <CopyButton text={uuidsString} />, [uuidsString]);
|
||||
|
||||
const uuidsClearButton = useMemo(
|
||||
() => <ClearButton onClick={clearUuids} iconOnly aria-label="clear uuids" />,
|
||||
[clearUuids]
|
||||
);
|
||||
|
||||
const uuidsControl = <ControlMenu list={[uuidsCopyButton, uuidsClearButton]} />;
|
||||
|
||||
return (
|
||||
<PageRootSection title={toolGroups.generators.tools.uuid.longTitle}>
|
||||
<PageSection title="Configuration">
|
||||
<Configurations list={[hyphensConfig, uppercaseConfig, uuidVersionConfig]} />
|
||||
</PageSection>
|
||||
<PageSection className="mt-6" title="Generate">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="secondary" onClick={onGenerateClick}>
|
||||
Generate UUID(s)
|
||||
</Button>
|
||||
<span>×</span>
|
||||
{generatesInput}
|
||||
</div>
|
||||
</PageSection>
|
||||
<PageSection title="UUID(s)" control={uuidsControl}>
|
||||
<Textarea {...{ ref }} value={uuidsString} rows={10} readOnly />
|
||||
</PageSection>
|
||||
</PageRootSection>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user