├── src
├── vite-env.d.ts
├── main.tsx
├── utils.ts
├── App.css
├── hooks.ts
├── natives.ts
├── assets
│ └── react.svg
└── App.tsx
├── src-tauri
├── build.rs
├── icons
│ ├── 32x32.png
│ ├── 64x64.png
│ ├── icon.icns
│ ├── icon.ico
│ ├── icon.png
│ ├── 128x128.png
│ ├── 128x128@2x.png
│ ├── StoreLogo.png
│ ├── Square30x30Logo.png
│ ├── Square44x44Logo.png
│ ├── Square71x71Logo.png
│ ├── Square89x89Logo.png
│ ├── Square107x107Logo.png
│ ├── Square142x142Logo.png
│ ├── Square150x150Logo.png
│ ├── Square284x284Logo.png
│ └── Square310x310Logo.png
├── .gitignore
├── src
│ ├── main.rs
│ └── lib.rs
├── capabilities
│ └── default.json
├── tauri.conf.json
└── Cargo.toml
├── app-icon.png
├── screenshot.png
├── tsconfig.node.json
├── .gitignore
├── index.html
├── tsconfig.json
├── README.md
├── vite.config.ts
├── package.json
├── LICENSE
└── public
├── vite.svg
└── tauri.svg
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src-tauri/build.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | tauri_build::build()
3 | }
4 |
--------------------------------------------------------------------------------
/app-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/app-icon.png
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/screenshot.png
--------------------------------------------------------------------------------
/src-tauri/icons/32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/32x32.png
--------------------------------------------------------------------------------
/src-tauri/icons/64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/64x64.png
--------------------------------------------------------------------------------
/src-tauri/icons/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/icon.icns
--------------------------------------------------------------------------------
/src-tauri/icons/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/icon.ico
--------------------------------------------------------------------------------
/src-tauri/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/icon.png
--------------------------------------------------------------------------------
/src-tauri/icons/128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/128x128.png
--------------------------------------------------------------------------------
/src-tauri/icons/128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/128x128@2x.png
--------------------------------------------------------------------------------
/src-tauri/icons/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/StoreLogo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square30x30Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/Square30x30Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square44x44Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/Square44x44Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square71x71Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/Square71x71Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square89x89Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/Square89x89Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square107x107Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/Square107x107Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square142x142Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/Square142x142Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square150x150Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/Square150x150Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square284x284Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/Square284x284Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square310x310Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiql/get-unique-id-app/HEAD/src-tauri/icons/Square310x310Logo.png
--------------------------------------------------------------------------------
/src-tauri/.gitignore:
--------------------------------------------------------------------------------
1 | # Generated by Cargo
2 | # will have compiled files and executables
3 | /target/
4 |
5 | # Generated by Tauri
6 | # will have schema files for capabilities auto-completion
7 | /gen/schemas
8 |
--------------------------------------------------------------------------------
/src-tauri/src/main.rs:
--------------------------------------------------------------------------------
1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!!
2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
3 |
4 | fn main() {
5 | get_unique_id_app_lib::run()
6 | }
7 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App";
4 |
5 | ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
6 |
7 |
8 | ,
9 | );
10 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | export function sleep(millis: number) {
2 | return new Promise((resolve) => setTimeout(resolve, millis));
3 | }
4 |
5 | export function isDigit(char: string): boolean {
6 | return /^\d$/.test(char);
7 | }
8 |
9 | export function isLetter(char: string): boolean {
10 | return /^[A-Za-z]$/.test(char);
11 | }
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Get Unique ID
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 0;
3 | margin: 0;
4 | overflow: hidden;
5 |
6 | cursor: default;
7 | -webkit-user-select: none; /* Chrome, Safari, Opera */
8 | -moz-user-select: none; /* Firefox */
9 | -ms-user-select: none; /* Internet Explorer/Edge */
10 | user-select: none; /* Standard syntax */
11 | }
12 |
13 | :root {
14 | font-synthesis: none;
15 | text-rendering: optimizeLegibility;
16 | -webkit-font-smoothing: antialiased;
17 | -moz-osx-font-smoothing: grayscale;
18 | -webkit-text-size-adjust: 100%;
19 | }
20 |
--------------------------------------------------------------------------------
/src-tauri/capabilities/default.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../gen/schemas/desktop-schema.json",
3 | "identifier": "default",
4 | "description": "Capability for the main window",
5 | "windows": ["main"],
6 | "permissions": [
7 | "core:default",
8 | "opener:default",
9 | "core:window:allow-start-dragging",
10 | "core:window:allow-set-size",
11 | "core:window:allow-theme",
12 | "core:event:allow-listen",
13 | "clipboard-manager:default",
14 | "clipboard-manager:allow-write-text",
15 | "clipboard-manager:allow-read-text",
16 | "dialog:default"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "jsx": "react-jsx",
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "noFallthroughCasesInSwitch": true
22 | },
23 | "include": ["src"],
24 | "references": [{ "path": "./tsconfig.node.json" }]
25 | }
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Get Unique ID
4 |
5 | Generates unique IDs(UUID/CUID/ULID/NanoID/ObjectID/Snowflake, etc) for you to use in debugging, development, or anywhere else you may need a unique ID.
6 |
7 | 
8 |
9 | ## Supported ID Formats
10 | - UUID v1(Gregorian Time-based)
11 | - UUID v3(MD5 Name-based)
12 | - UUID v4(Random)
13 | - UUID v5(SHA-1 Name-based)
14 | - UUID v6(Reordered Gregorian Time-based)
15 | - UUID v7(Unix Time-based)
16 | - Short UUID
17 | - Nil UUID
18 | - Max UUID
19 | - ULID
20 | - UPID
21 | - CUID
22 | - CUID2
23 | - Nano ID
24 | - NUID
25 | - TSID
26 | - SCRU128
27 | - Snowflake
28 | - Sonyflake
29 | - Object ID
30 |
31 | ## License
32 |
33 | MIT
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import react from "@vitejs/plugin-react";
3 |
4 | // @ts-expect-error process is a nodejs global
5 | const host = process.env.TAURI_DEV_HOST;
6 |
7 | // https://vitejs.dev/config/
8 | export default defineConfig(async () => ({
9 | plugins: [react()],
10 |
11 | // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
12 | //
13 | // 1. prevent vite from obscuring rust errors
14 | clearScreen: false,
15 | // 2. tauri expects a fixed port, fail if that port is not available
16 | server: {
17 | port: 1420,
18 | strictPort: true,
19 | host: host || false,
20 | hmr: host
21 | ? {
22 | protocol: "ws",
23 | host,
24 | port: 1421,
25 | }
26 | : undefined,
27 | watch: {
28 | // 3. tell vite to ignore watching `src-tauri`
29 | ignored: ["**/src-tauri/**"],
30 | },
31 | },
32 | }));
33 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "get-unique-id-app",
3 | "private": true,
4 | "version": "0.1.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview",
10 | "tauri": "tauri"
11 | },
12 | "dependencies": {
13 | "@radix-ui/react-icons": "^1.3.2",
14 | "@radix-ui/themes": "^3.2.0",
15 | "@tauri-apps/api": "^2",
16 | "@tauri-apps/plugin-clipboard-manager": "^2",
17 | "@tauri-apps/plugin-dialog": "^2.2.0",
18 | "@tauri-apps/plugin-opener": "^2",
19 | "@tauri-apps/plugin-shell": "^2",
20 | "react": "^18.3.1",
21 | "react-dom": "^18.3.1",
22 | "react-intl": "^7.1.5",
23 | "use-resize-observer": "^9.1.0"
24 | },
25 | "devDependencies": {
26 | "@tauri-apps/cli": "^2",
27 | "@types/react": "^18.3.1",
28 | "@types/react-dom": "^18.3.1",
29 | "@vitejs/plugin-react": "^4.3.4",
30 | "typescript": "~5.6.2",
31 | "vite": "^6.0.3"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src-tauri/tauri.conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.tauri.app/config/2",
3 | "productName": "Get Unique ID",
4 | "version": "0.1.0",
5 | "identifier": "com.hiqlapps.get-unique-id-app",
6 | "build": {
7 | "beforeDevCommand": "npm run dev",
8 | "devUrl": "http://localhost:1420",
9 | "beforeBuildCommand": "npm run build",
10 | "frontendDist": "../dist"
11 | },
12 | "app": {
13 | "windows": [
14 | {
15 | "title": "Get Unique ID",
16 | "width": 680,
17 | "height": 400,
18 | "maximized": false,
19 | "resizable": false,
20 | "titleBarStyle": "Overlay"
21 | }
22 | ],
23 | "security": {
24 | "csp": null
25 | }
26 | },
27 | "bundle": {
28 | "active": true,
29 | "targets": "all",
30 | "icon": [
31 | "icons/32x32.png",
32 | "icons/128x128.png",
33 | "icons/128x128@2x.png",
34 | "icons/icon.icns",
35 | "icons/icon.ico"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 hiql
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/src-tauri/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "get-unique-id-app"
3 | version = "0.1.0"
4 | description = "Unique ID Generator"
5 | authors = ["hiql"]
6 | edition = "2021"
7 |
8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
9 |
10 | [lib]
11 | # The `_lib` suffix may seem redundant but it is necessary
12 | # to make the lib name unique and wouldn't conflict with the bin name.
13 | # This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
14 | name = "get_unique_id_app_lib"
15 | crate-type = ["staticlib", "cdylib", "rlib"]
16 |
17 | [build-dependencies]
18 | tauri-build = { version = "2", features = [] }
19 |
20 | [dependencies]
21 | tauri = { version = "2", features = [] }
22 | tauri-plugin-opener = "2"
23 | tauri-plugin-shell = "2"
24 | tauri-plugin-clipboard-manager = "2"
25 | tauri-plugin-dialog = "2"
26 | serde = { version = "1", features = ["derive"] }
27 | serde_json = "1"
28 | uuid = { version = "1.12.1", features = ["v1", "v3", "v4", "v5", "v6", "v7"] }
29 | short-uuid = "0.1.4"
30 | nanoid = "0.4.0"
31 | ulid = "1.1.4"
32 | cuid = "1.3.3"
33 | uguid = "2.2.0"
34 | nuid = "0.5.0"
35 | upid = "0.2.0"
36 | tsid = "0.3.1"
37 | scru128 = "3.1.0"
38 | sonyflake = "0.3.0"
39 | rs-snowflake = "0.6.0"
40 | bson = "2.13.0"
41 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/tauri.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/hooks.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 | import { UnlistenFn } from "@tauri-apps/api/event";
3 | import { getCurrentWindow } from "@tauri-apps/api/window";
4 | import { writeText } from "@tauri-apps/plugin-clipboard-manager";
5 |
6 | export const useTheme = () => {
7 | const [theme, setTheme] = useState<"light" | "dark" | "inherit">("inherit");
8 |
9 | useEffect(() => {
10 | let unlisten: UnlistenFn | undefined;
11 |
12 | (async () => {
13 | setTheme((await getCurrentWindow().theme()) || "inherit");
14 |
15 | unlisten = await getCurrentWindow().onThemeChanged(
16 | ({ payload: theme }) => {
17 | console.log(`theme changed to ${theme}`);
18 | setTheme(theme);
19 | },
20 | );
21 | })();
22 |
23 | return () => {
24 | if (unlisten != null) {
25 | unlisten();
26 | }
27 | };
28 | }, []);
29 |
30 | return theme;
31 | };
32 |
33 | export function useCopy() {
34 | const [isCopied, setIsCopied] = useState(false);
35 |
36 | const copyToClipboard = async (text: string) => {
37 | await writeText(text);
38 | setIsCopied(true);
39 | };
40 |
41 | const resetCopyStatus = () => {
42 | setIsCopied(false);
43 | };
44 |
45 | useEffect(() => {
46 | if (isCopied) {
47 | const timer = setTimeout(resetCopyStatus, 3000); // Reset copy status after 3 seconds
48 | return () => clearTimeout(timer);
49 | }
50 | }, [isCopied]);
51 |
52 | return { isCopied, copyToClipboard, resetCopyStatus };
53 | }
54 |
55 | export function useLocalStorage(key: string, initialValue: T) {
56 | // State to store our value
57 | // Pass initial state function to useState so logic is only executed once
58 | const [storedValue, setStoredValue] = useState(() => {
59 | try {
60 | // Get from local storage by key
61 | const item = window.localStorage.getItem(key);
62 | // Parse stored json or if none return initialValue
63 | return item ? JSON.parse(item) : initialValue;
64 | } catch (error) {
65 | // If error also return initialValue
66 | console.log(error);
67 | return initialValue;
68 | }
69 | });
70 | // Return a wrapped version of useState's setter function that ...
71 | // ... persists the new value to localStorage.
72 | const setValue = (value: T | ((val: T) => T)) => {
73 | try {
74 | // Allow value to be a function so we have same API as useState
75 | const valueToStore =
76 | value instanceof Function ? value(storedValue) : value;
77 | // Save state
78 | setStoredValue(valueToStore);
79 | // Save to local storage
80 | window.localStorage.setItem(key, JSON.stringify(valueToStore));
81 | } catch (error) {
82 | // A more advanced implementation would handle the error case
83 | console.log(error);
84 | }
85 | };
86 | return [storedValue, setValue] as const;
87 | }
88 |
--------------------------------------------------------------------------------
/src/natives.ts:
--------------------------------------------------------------------------------
1 | import { invoke } from "@tauri-apps/api/core";
2 |
3 | const saveToFile = async (
4 | content: string,
5 | fileName: string,
6 | ): Promise => {
7 | return await invoke("save_to_file", { content, fileName: fileName });
8 | };
9 |
10 | const generateUUIDV1 = async (n?: number): Promise => {
11 | return await invoke("gen_uuid_v1", { n: n || 1 });
12 | };
13 |
14 | const generateUUIDV3 = async (
15 | namespace: string,
16 | name: string,
17 | n?: number,
18 | ): Promise => {
19 | return await invoke("gen_uuid_v3", {
20 | namespace,
21 | name: name || "name",
22 | n: n || 1,
23 | });
24 | };
25 |
26 | const generateUUIDV4 = async (n?: number): Promise => {
27 | return await invoke("gen_uuid_v4", { n: n || 1 });
28 | };
29 |
30 | const generateUUIDV5 = async (
31 | namespace: string,
32 | name: string,
33 | n?: number,
34 | ): Promise => {
35 | return await invoke("gen_uuid_v5", {
36 | namespace,
37 | name: name || "name",
38 | n: n || 1,
39 | });
40 | };
41 |
42 | const generateUUIDV6 = async (n?: number): Promise => {
43 | return await invoke("gen_uuid_v6", { n: n || 1 });
44 | };
45 |
46 | const generateUUIDV7 = async (n?: number): Promise => {
47 | return await invoke("gen_uuid_v7", { n: n || 1 });
48 | };
49 |
50 | const generateShortUUID = async (n?: number): Promise => {
51 | return await invoke("gen_short_uuid", { n: n || 1 });
52 | };
53 |
54 | const generateNilUUID = async (n?: number): Promise => {
55 | return await invoke("gen_nil_uuid", { n: n || 1 });
56 | };
57 |
58 | const generateMaxUUID = async (n?: number): Promise => {
59 | return await invoke("gen_max_uuid", { n: n || 1 });
60 | };
61 |
62 | const generateNanoID = async (n?: number): Promise => {
63 | return await invoke("gen_nano_id", { n: n || 1 });
64 | };
65 |
66 | const generateULID = async (n?: number): Promise => {
67 | return await invoke("gen_ulid", { n: n || 1 });
68 | };
69 |
70 | const generateCUID = async (n?: number): Promise => {
71 | return await invoke("gen_cuid", { n: n || 1 });
72 | };
73 |
74 | const generateCUID2 = async (n?: number): Promise => {
75 | return await invoke("gen_cuid2", { n: n || 1 });
76 | };
77 |
78 | const generateSnowflake = async (n?: number): Promise => {
79 | return await invoke("gen_snowflake", { n: n || 1 });
80 | };
81 |
82 | const generateSonyflake = async (n?: number): Promise => {
83 | return await invoke("gen_sonyflake", { n: n || 1 });
84 | };
85 |
86 | const generateNUID = async (n?: number): Promise => {
87 | return await invoke("gen_nuid", { n: n || 1 });
88 | };
89 |
90 | const generateUPID = async (prefix: string, n?: number): Promise => {
91 | return await invoke("gen_upid", { prefix, n: n || 1 });
92 | };
93 |
94 | const generateTSID = async (n?: number): Promise => {
95 | return await invoke("gen_tsid", { n: n || 1 });
96 | };
97 |
98 | const generateObjectID = async (n?: number): Promise => {
99 | return await invoke("gen_object_id", { n: n || 1 });
100 | };
101 |
102 | const generateSCRU128 = async (n?: number): Promise => {
103 | return await invoke("gen_scru128", { n: n || 1 });
104 | };
105 |
106 | export default {
107 | saveToFile,
108 | generateUUIDV1,
109 | generateUUIDV3,
110 | generateUUIDV4,
111 | generateUUIDV5,
112 | generateUUIDV6,
113 | generateUUIDV7,
114 | generateShortUUID,
115 | generateNilUUID,
116 | generateMaxUUID,
117 | generateNanoID,
118 | generateULID,
119 | generateCUID,
120 | generateCUID2,
121 | generateNUID,
122 | generateUPID,
123 | generateTSID,
124 | generateSnowflake,
125 | generateSonyflake,
126 | generateObjectID,
127 | generateSCRU128,
128 | };
129 |
--------------------------------------------------------------------------------
/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src-tauri/src/lib.rs:
--------------------------------------------------------------------------------
1 | use std::fs;
2 |
3 | use nanoid::nanoid;
4 | use short_uuid::short;
5 | use snowflake::SnowflakeIdGenerator;
6 | use sonyflake::Sonyflake;
7 | use tauri::menu::{AboutMetadata, MenuBuilder, MenuItemBuilder, SubmenuBuilder};
8 | use tauri_plugin_dialog::DialogExt;
9 | use tauri_plugin_opener::OpenerExt;
10 | use uuid::Uuid;
11 |
12 | #[tauri::command]
13 | fn gen_uuid_v1(n: u32) -> Vec {
14 | let mut list = vec![];
15 | for _ in 0..n {
16 | let id = Uuid::now_v1(&[1, 2, 3, 4, 5, 6]).hyphenated().to_string();
17 | list.push(id);
18 | }
19 | list
20 | }
21 |
22 | #[tauri::command]
23 | fn gen_uuid_v3(namespace: &str, name: &str, n: u32) -> Vec {
24 | if name.is_empty() {
25 | return vec![];
26 | }
27 | let new_id = match Uuid::try_parse(namespace) {
28 | Ok(v) => Uuid::new_v3(&v, name.as_bytes()).hyphenated().to_string(),
29 | _ => "".to_string(),
30 | };
31 | let mut list = vec![];
32 | for _ in 0..n {
33 | let id = if new_id.is_empty() {
34 | let r = Uuid::new_v4();
35 | Uuid::new_v3(&r, name.as_bytes()).hyphenated().to_string()
36 | } else {
37 | new_id.clone()
38 | };
39 | list.push(id);
40 | }
41 | list
42 | }
43 |
44 | #[tauri::command]
45 | fn gen_uuid_v4(n: u32) -> Vec {
46 | let mut list = vec![];
47 | for _ in 0..n {
48 | let id = Uuid::new_v4().hyphenated().to_string();
49 | list.push(id);
50 | }
51 | list
52 | }
53 |
54 | #[tauri::command]
55 | fn gen_uuid_v5(namespace: &str, name: &str, n: u32) -> Vec {
56 | if name.is_empty() {
57 | return vec![];
58 | }
59 | let new_id = match Uuid::try_parse(namespace) {
60 | Ok(v) => Uuid::new_v5(&v, name.as_bytes()).hyphenated().to_string(),
61 | _ => "".to_string(),
62 | };
63 | let mut list = vec![];
64 | for _ in 0..n {
65 | let id = if new_id.is_empty() {
66 | let r = Uuid::new_v4();
67 | Uuid::new_v5(&r, name.as_bytes()).hyphenated().to_string()
68 | } else {
69 | new_id.clone()
70 | };
71 | list.push(id);
72 | }
73 | list
74 | }
75 |
76 | #[tauri::command]
77 | fn gen_uuid_v6(n: u32) -> Vec {
78 | let mut list = vec![];
79 | for _ in 0..n {
80 | let id = Uuid::now_v6(&[1, 2, 3, 4, 5, 6]).hyphenated().to_string();
81 | list.push(id);
82 | }
83 | list
84 | }
85 |
86 | #[tauri::command]
87 | fn gen_uuid_v7(n: u32) -> Vec {
88 | let mut list = vec![];
89 | for _ in 0..n {
90 | let id = Uuid::now_v7().hyphenated().to_string();
91 | list.push(id);
92 | }
93 | list
94 | }
95 |
96 | #[tauri::command]
97 | fn gen_short_uuid(n: u32) -> Vec {
98 | let mut list = vec![];
99 | for _ in 0..n {
100 | let shortened_uuid = short!();
101 | let id = shortened_uuid.to_string();
102 | list.push(id);
103 | }
104 | list
105 | }
106 |
107 | #[tauri::command]
108 | fn gen_nil_uuid(n: u32) -> Vec {
109 | let mut list = vec![];
110 | let id = "00000000-0000-0000-0000-000000000000".to_string();
111 | for _ in 0..n {
112 | list.push(id.clone());
113 | }
114 | list
115 | }
116 |
117 | #[tauri::command]
118 | fn gen_max_uuid(n: u32) -> Vec {
119 | let mut list = vec![];
120 | let id = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF".to_string();
121 | for _ in 0..n {
122 | list.push(id.clone());
123 | }
124 | list
125 | }
126 |
127 | #[tauri::command]
128 | fn gen_nano_id(n: u32) -> Vec {
129 | let mut list = vec![];
130 | for _ in 0..n {
131 | let id = nanoid!();
132 | list.push(id);
133 | }
134 | list
135 | }
136 |
137 | #[tauri::command]
138 | fn gen_ulid(n: u32) -> Vec {
139 | let mut list = vec![];
140 | let mut gen = ulid::Generator::new();
141 | for _ in 0..n {
142 | let id = gen.generate().unwrap();
143 | list.push(id.to_string());
144 | }
145 | list
146 | }
147 |
148 | #[tauri::command]
149 | fn gen_cuid(n: u32) -> Vec {
150 | let mut list = vec![];
151 | for _ in 0..n {
152 | let id = cuid::cuid1().unwrap();
153 | list.push(id);
154 | }
155 | list
156 | }
157 |
158 | #[tauri::command]
159 | fn gen_cuid2(n: u32) -> Vec {
160 | let mut list = vec![];
161 | for _ in 0..n {
162 | let id = cuid::cuid2();
163 | list.push(id);
164 | }
165 | list
166 | }
167 |
168 | #[tauri::command]
169 | fn gen_nuid(n: u32) -> Vec {
170 | let mut list = vec![];
171 | let mut gen = nuid::NUID::new();
172 | for _ in 0..n {
173 | let id = gen.next().to_string();
174 | list.push(id);
175 | }
176 | list
177 | }
178 |
179 | #[tauri::command]
180 | fn gen_snowflake(n: u32) -> Vec {
181 | let mut list = vec![];
182 | let mut g = SnowflakeIdGenerator::new(1, 1);
183 | for _ in 0..n {
184 | let id = g.generate().to_string();
185 | list.push(id);
186 | }
187 | list
188 | }
189 |
190 | #[tauri::command]
191 | fn gen_sonyflake(n: u32) -> Vec {
192 | let mut list = vec![];
193 | let gen = Sonyflake::new().unwrap();
194 | for _ in 0..n {
195 | let id = format!("{}", gen.next_id().unwrap());
196 | list.push(id);
197 | }
198 | list
199 | }
200 |
201 | #[tauri::command]
202 | fn gen_upid(prefix: &str, n: u32) -> Vec {
203 | let mut list = vec![];
204 | for _ in 0..n {
205 | let id = upid::Upid::new(prefix).to_string();
206 | list.push(id);
207 | }
208 | list
209 | }
210 |
211 | #[tauri::command]
212 | fn gen_tsid(n: u32) -> Vec {
213 | let mut list = vec![];
214 | for _ in 0..n {
215 | let id = tsid::create_tsid().to_string();
216 | list.push(id);
217 | }
218 | list
219 | }
220 |
221 | #[tauri::command]
222 | fn gen_object_id(n: u32) -> Vec {
223 | let mut list = vec![];
224 | for _ in 0..n {
225 | let id = bson::oid::ObjectId::new().to_string();
226 | list.push(id)
227 | }
228 | list
229 | }
230 |
231 | #[tauri::command]
232 | fn gen_scru128(n: u32) -> Vec {
233 | let mut list = vec![];
234 | for _ in 0..n {
235 | let id = scru128::new_string();
236 | list.push(id);
237 | }
238 | list
239 | }
240 |
241 | #[tauri::command]
242 | async fn save_to_file(app: tauri::AppHandle, content: &str, file_name: &str) -> Result<(), String> {
243 | let file_path = app
244 | .dialog()
245 | .file()
246 | .set_file_name(file_name)
247 | .blocking_save_file();
248 | if let Some(path) = file_path {
249 | match fs::write(path.to_string(), content) {
250 | Ok(_) => println!("File saved"),
251 | Err(e) => eprintln!("Failed to save file: {}", e),
252 | }
253 | }
254 | Ok(())
255 | }
256 |
257 | #[cfg_attr(mobile, tauri::mobile_entry_point)]
258 | pub fn run() {
259 | tauri::Builder::default()
260 | .setup(|app| {
261 | let github = MenuItemBuilder::new("Github").id("github").build(app)?;
262 | let rfc9562 = MenuItemBuilder::new("RFC 9562").id("rfc9562").build(app)?;
263 | let app_submenu = SubmenuBuilder::new(app, "App")
264 | .about(Some(AboutMetadata {
265 | ..Default::default()
266 | }))
267 | .separator()
268 | .item(&github)
269 | .item(&rfc9562)
270 | .separator()
271 | .services()
272 | .separator()
273 | .hide()
274 | .hide_others()
275 | .quit()
276 | .build()?;
277 | let menu = MenuBuilder::new(app).items(&[&app_submenu]).build()?;
278 | app.set_menu(menu)?;
279 | app.on_menu_event(move |app, event| {
280 | if event.id() == github.id() {
281 | app.opener()
282 | .open_url("https://github.com/hiql/get-unique-id-app", None::<&str>)
283 | .unwrap();
284 | } else if event.id() == rfc9562.id() {
285 | app.opener()
286 | .open_url("https://www.rfc-editor.org/rfc/rfc9562.html", None::<&str>)
287 | .unwrap();
288 | }
289 | });
290 | Ok(())
291 | })
292 | .plugin(tauri_plugin_clipboard_manager::init())
293 | .plugin(tauri_plugin_shell::init())
294 | .plugin(tauri_plugin_opener::init())
295 | .plugin(tauri_plugin_dialog::init())
296 | .invoke_handler(tauri::generate_handler![
297 | save_to_file,
298 | gen_uuid_v1,
299 | gen_uuid_v3,
300 | gen_uuid_v4,
301 | gen_uuid_v5,
302 | gen_uuid_v6,
303 | gen_uuid_v7,
304 | gen_short_uuid,
305 | gen_nil_uuid,
306 | gen_max_uuid,
307 | gen_ulid,
308 | gen_upid,
309 | gen_nano_id,
310 | gen_cuid,
311 | gen_cuid2,
312 | gen_nuid,
313 | gen_tsid,
314 | gen_snowflake,
315 | gen_sonyflake,
316 | gen_object_id,
317 | gen_scru128
318 | ])
319 | .run(tauri::generate_context!())
320 | .expect("error while running tauri application");
321 | }
322 |
323 | #[cfg(test)]
324 | mod test {
325 | use super::*;
326 |
327 | #[test]
328 | fn test_gen_nil_empty_uuid() {
329 | let expected = "00000000-0000-0000-0000-000000000000";
330 | let ids = gen_nil_uuid(5);
331 | println!("{:?}", ids);
332 | assert_eq!(5, ids.len());
333 | assert_eq!(expected, ids[0]);
334 | }
335 | }
336 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 | import {
3 | Text,
4 | Flex,
5 | Theme,
6 | Box,
7 | Select,
8 | Button,
9 | TextField,
10 | IconButton,
11 | DropdownMenu,
12 | Separator,
13 | Tooltip,
14 | Badge,
15 | Switch,
16 | RadioGroup,
17 | ScrollArea,
18 | } from "@radix-ui/themes";
19 | import { getCurrentWindow, LogicalSize } from "@tauri-apps/api/window";
20 | import useResizeObserver from "use-resize-observer";
21 | import { FormattedMessage, IntlProvider, useIntl } from "react-intl";
22 | import {
23 | CopyIcon,
24 | DownloadIcon,
25 | MinusIcon,
26 | PlusIcon,
27 | QuestionMarkCircledIcon,
28 | ShuffleIcon,
29 | UpdateIcon,
30 | } from "@radix-ui/react-icons";
31 | import "@radix-ui/themes/styles.css";
32 | import "./App.css";
33 | import { useCopy, useLocalStorage, useTheme } from "./hooks";
34 | import { isDigit, isLetter, sleep } from "./utils";
35 | import natives from "./natives";
36 |
37 | interface IDVersion {
38 | key: string;
39 | name: string;
40 | }
41 |
42 | interface PredefinedUUID {
43 | id: string;
44 | name: string;
45 | }
46 |
47 | const ID_VERSIONS: IDVersion[] = [
48 | { key: "uuidv1", name: "UUID v1(Gregorian Time-based)" },
49 | { key: "uuidv3", name: "UUID v3(MD5 Name-based)" },
50 | { key: "uuidv4", name: "UUID v4(Random)" },
51 | { key: "uuidv5", name: "UUID v5(SHA-1 Name-based)" },
52 | { key: "uuidv6", name: "UUID v6(Reordered Gregorian Time-based)" },
53 | { key: "uuidv7", name: "UUID v7(Unix Time-based)" },
54 | { key: "shortuuid", name: "Short UUID" },
55 | { key: "niluuid", name: "Nil UUID" },
56 | { key: "maxuuid", name: "Max UUID" },
57 | { key: "ulid", name: "ULID" },
58 | { key: "upid", name: "UPID" },
59 | { key: "cuid", name: "CUID" },
60 | { key: "cuid2", name: "CUID2" },
61 | { key: "nanoid", name: "Nano ID" },
62 | { key: "nuid", name: "NUID" },
63 | { key: "tsid", name: "TSID" },
64 | { key: "scru128", name: "SCRU128" },
65 | { key: "snowflake", name: "Snowflake" },
66 | { key: "sonyflake", name: "Sonyflake" },
67 | { key: "objectid", name: "Object ID" },
68 | ];
69 |
70 | const PREDEFINED_UUIDS: PredefinedUUID[] = [
71 | { id: "6ba7b810-9dad-11d1-80b4-00c04fd430c8", name: "DNS" },
72 | { id: "6ba7b811-9dad-11d1-80b4-00c04fd430c8", name: "URL" },
73 | { id: "6ba7b812-9dad-11d1-80b4-00c04fd430c8", name: "OID" },
74 | { id: "6ba7b814-9dad-11d1-80b4-00c04fd430c8", name: "X.500" },
75 | ];
76 |
77 | const MIN_BULK_QUANTITY = 1;
78 | const MAX_BULK_QUANTITY = 500;
79 | const DFT_BULK_QUANTITY = 10;
80 |
81 | const messagesInChinese = {
82 | uniqueIDVersion: "选择类型:",
83 | namespace: "命名空间:",
84 | namespacePlaceholder: "输入命名空间UUID值(默认随机)",
85 | namespaceTooltip:
86 | "命名空间必须是格式为00000000-0000-0000-0000-000000000000的有效UUID值。请选择一个预设的UUID值或自动填充随机UUID值。",
87 | name: "名称:",
88 | namePlaceholder: "输入名称(默认是‘name’)",
89 | nameTooltip:
90 | "必填项。名称可以是任意内容。相同命名空间和相同名称将始终生成相同的UUID值。",
91 | prefix: "前缀:",
92 | prefixPlaceholder: "输入前缀(4个字符长度,默认是'zzzz')",
93 | predefinedUUIDs: "预设UUID值",
94 | bulkGeneration: "批量生成",
95 | bulkQuantity: "批量生成数量({min}~{max}):",
96 | bulkOutput: "输出格式:",
97 | bulkOutputRaw: "原始",
98 | bulkOutputJson: "JSON",
99 | generatedResult: "生成结果:",
100 | regenerate: "重新生成",
101 | copyToClipboard: "拷贝至剪贴板",
102 | saveToFile: "保存至文件",
103 | copied: "已拷贝!",
104 | };
105 |
106 | function App({ changeLocale }: { changeLocale: (locale: string) => void }) {
107 | const [idVersion, setIDVersion] = useState("uuidv4");
108 | const [namespace, setNamespace] = useState("");
109 | const [name, setName] = useState("");
110 | const [namespaceType, setNamespaceType] = useState("");
111 | const [prefix, setPrefix] = useState("");
112 | const [isBulkMode, setIsBulkMode] = useState(false);
113 | const [bulkQuantity, setBulkQuantity] = useState(DFT_BULK_QUANTITY);
114 | const [bulkOutput, setBulkOutput] = useState("raw");
115 | const [isGenerating, setIsGenerating] = useState(false);
116 | const [result, setResult] = useState("");
117 | const [bulkResult, setBulkResult] = useState([]);
118 | const { isCopied, copyToClipboard } = useCopy();
119 | const { isCopied: isBulkCopied, copyToClipboard: copyBulkToClipboard } =
120 | useCopy();
121 | const intl = useIntl();
122 |
123 | async function generate(n: number) {
124 | let value: string[] = [];
125 | if (idVersion === "uuidv1") {
126 | value = await natives.generateUUIDV1(n);
127 | } else if (idVersion === "uuidv3") {
128 | value = await natives.generateUUIDV3(namespace, name, n);
129 | } else if (idVersion === "uuidv4") {
130 | value = await natives.generateUUIDV4(n);
131 | } else if (idVersion === "uuidv5") {
132 | value = await natives.generateUUIDV5(namespace, name, n);
133 | } else if (idVersion === "uuidv6") {
134 | value = await natives.generateUUIDV6(n);
135 | } else if (idVersion === "uuidv7") {
136 | value = await natives.generateUUIDV7(n);
137 | } else if (idVersion === "shortuuid") {
138 | value = await natives.generateShortUUID(n);
139 | } else if (idVersion === "niluuid") {
140 | value = await natives.generateNilUUID(n);
141 | } else if (idVersion === "maxuuid") {
142 | value = await natives.generateMaxUUID(n);
143 | } else if (idVersion === "ulid") {
144 | value = await natives.generateULID(n);
145 | } else if (idVersion === "nanoid") {
146 | value = await natives.generateNanoID(n);
147 | } else if (idVersion === "cuid") {
148 | value = await natives.generateCUID(n);
149 | } else if (idVersion === "cuid2") {
150 | value = await natives.generateCUID2(n);
151 | } else if (idVersion === "snowflake") {
152 | value = await natives.generateSnowflake(n);
153 | } else if (idVersion === "sonyflake") {
154 | value = await natives.generateSonyflake(n);
155 | } else if (idVersion === "nuid") {
156 | value = await natives.generateNUID(n);
157 | } else if (idVersion === "upid") {
158 | value = await natives.generateUPID(prefix || "zzzz", n);
159 | } else if (idVersion === "tsid") {
160 | value = await natives.generateTSID(n);
161 | } else if (idVersion === "objectid") {
162 | value = await natives.generateObjectID(n);
163 | } else if (idVersion === "scru128") {
164 | value = await natives.generateSCRU128(n);
165 | }
166 | return value;
167 | }
168 |
169 | async function generateOne() {
170 | setIsGenerating(true);
171 | const newID = (await generate(1))[0];
172 | setResult(newID);
173 | setIsGenerating(false);
174 | }
175 |
176 | async function generateBulk() {
177 | setIsGenerating(true);
178 | await sleep(100);
179 | const ids = await generate(bulkQuantity);
180 | setBulkResult(ids);
181 | setIsGenerating(false);
182 | }
183 |
184 | useEffect(() => {
185 | generateOne();
186 | setBulkResult([]);
187 | }, [idVersion, namespace, name, prefix]);
188 |
189 | async function setWindowHeight(height: number) {
190 | await getCurrentWindow().setSize(new LogicalSize(480, height));
191 | }
192 |
193 | const { ref: windowInnerBoxRef } = useResizeObserver({
194 | onResize: ({ height }) => {
195 | if (height) {
196 | setWindowHeight(height);
197 | }
198 | },
199 | });
200 |
201 | useEffect(() => {
202 | document.addEventListener(
203 | "contextmenu",
204 | (e) => {
205 | e.preventDefault();
206 | return false;
207 | },
208 | { capture: true }
209 | );
210 | }, []);
211 |
212 | return (
213 |
214 |
215 |
216 |
217 |
218 |
229 |
230 |
231 |
232 | changeLocale && changeLocale("en")}
234 | >
235 | English
236 |
237 | changeLocale && changeLocale("cn")}
239 | >
240 | 简体中文
241 |
242 |
243 |
244 |
245 |
246 |
247 |
251 |
252 | setIDVersion(value)}
255 | >
256 |
257 |
258 | {ID_VERSIONS.map((version) => (
259 |
260 | {version.name}
261 |
262 | ))}
263 |
264 |
265 | {idVersion === "uuidv3" || idVersion === "uuidv5" ? (
266 | <>
267 |
268 |
269 |
270 | {
278 | setNamespace(e.target.value);
279 | setNamespaceType("");
280 | }}
281 | >
282 |
283 | {namespaceType ? (
284 |
285 | {namespaceType}
286 |
287 | ) : null}
288 | {
292 | const id = (await natives.generateUUIDV4())[0];
293 | setNamespace(id);
294 | setNamespaceType("");
295 | }}
296 | >
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
312 |
313 | {PREDEFINED_UUIDS.map((uuid) => (
314 | {
317 | setNamespace(uuid.id);
318 | setNamespaceType(uuid.name);
319 | }}
320 | >
321 | {uuid.name}
322 |
323 | ))}
324 |
325 |
326 |
327 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 | setName(e.target.value)}
349 | >
350 |
351 |
358 |
359 |
360 |
361 |
362 | >
363 | ) : null}
364 | {idVersion === "upid" ? (
365 | <>
366 |
367 |
368 |
369 | setPrefix(e.target.value)}
379 | />
380 | >
381 | ) : null}
382 |
383 |
394 |
395 |
396 |
400 |
401 | setIsBulkMode(checked)}
405 | />
406 |
407 | {isBulkMode ? (
408 | <>
409 |
410 |
411 |
412 |
420 |
421 | {
426 | if (!e.target.value) {
427 | setBulkQuantity(MIN_BULK_QUANTITY);
428 | return;
429 | }
430 | const value = parseInt(e.target.value, 10);
431 | if (value <= MIN_BULK_QUANTITY) {
432 | setBulkQuantity(MIN_BULK_QUANTITY);
433 | } else if (value >= MAX_BULK_QUANTITY) {
434 | setBulkQuantity(MAX_BULK_QUANTITY);
435 | } else {
436 | setBulkQuantity(parseInt(e.target.value, 10));
437 | }
438 | }}
439 | >
440 |
441 | {
445 | if (bulkQuantity >= MAX_BULK_QUANTITY) {
446 | setBulkQuantity(MAX_BULK_QUANTITY);
447 | } else {
448 | setBulkQuantity(bulkQuantity + 1);
449 | }
450 | }}
451 | >
452 |
453 |
454 | {
458 | if (bulkQuantity <= MIN_BULK_QUANTITY) {
459 | setBulkQuantity(MIN_BULK_QUANTITY);
460 | } else {
461 | setBulkQuantity(bulkQuantity - 1);
462 | }
463 | }}
464 | >
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
476 |
477 | setBulkOutput(value)}
480 | radioGroup="bulkOutput"
481 | >
482 |
483 |
484 |
485 |
486 |
490 |
491 |
492 |
493 |
494 |
495 |
499 |
500 |
501 |
502 |
503 |
504 |
505 | >
506 | ) : null}
507 |
508 |
509 |
510 |
514 |
515 |
516 |
517 | {isBulkMode ? (
518 |
528 |
529 | {bulkOutput === "raw" ? (
530 | bulkResult.map((item, rownum) => (
531 |
532 |
544 | {rownum + 1}
545 |
546 | {item}
547 |
548 | ))
549 | ) : bulkOutput === "json" ? (
550 |
551 |
552 | {bulkResult.length > 0
553 | ? JSON.stringify(bulkResult, undefined, 2)
554 | : ""}
555 |
556 |
557 | ) : null}
558 |
559 |
560 | ) : (
561 |
570 |
576 | {[...result].map((char, i) =>
577 | char === " " ? (
578 |
579 | ) : (
580 |
592 | {char}
593 |
594 | )
595 | )}
596 |
597 |
598 | )}
599 |
606 |
619 |
653 | {isBulkMode ? (
654 |
690 | ) : null}
691 |
692 |
693 |
694 | );
695 | }
696 |
697 | function AppWithProvider() {
698 | const theme = useTheme();
699 | const [storedLocaleValue, setLocaleValue] = useLocalStorage("language", "en");
700 | return (
701 |
706 |
707 |
708 |
709 |
710 | );
711 | }
712 |
713 | export default AppWithProvider;
714 |
--------------------------------------------------------------------------------