mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-20 06:29:32 +02:00
feat: password generator to test translation
This commit is contained in:
143
.idea/workspace.xml
generated
143
.idea/workspace.xml
generated
@@ -4,119 +4,12 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="chore: saveMissing">
|
||||
<change afterPath="$PROJECT_DIR$/.env.example" afterDir="false" />
|
||||
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="fix: translation related behaviors">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/package-lock.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/components/Hero.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/Hero.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/components/ToolLayout.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolLayout.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/i18n/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/i18n/index.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools-by-category/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools-by-category/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/audio/change-speed/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/audio/change-speed/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/audio/extract-audio/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/audio/extract-audio/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/audio/merge-audio/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/audio/merge-audio/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/audio/trim/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/audio/trim/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/csv/change-csv-separator/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/csv/change-csv-separator/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/csv/csv-rows-to-columns/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/csv/csv-rows-to-columns/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/csv/csv-to-json/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/csv/csv-to-json/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/csv/csv-to-tsv/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/csv/csv-to-tsv/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/csv/csv-to-xml/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/csv/csv-to-xml/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/csv/csv-to-yaml/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/csv/csv-to-yaml/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/csv/find-incomplete-csv-records/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/csv/find-incomplete-csv-records/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/csv/insert-csv-columns/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/csv/insert-csv-columns/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/csv/swap-csv-columns/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/csv/swap-csv-columns/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/csv/transpose-csv/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/csv/transpose-csv/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/change-colors/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/change-colors/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/change-opacity/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/change-opacity/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/compress/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/compress/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/convert-to-jpg/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/convert-to-jpg/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/create-transparent/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/create-transparent/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/crop/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/crop/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/editor/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/editor/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/image-to-text/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/image-to-text/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/qr-code/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/qr-code/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/remove-background/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/remove-background/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/resize/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/resize/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/rotate/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/rotate/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/png/compress-png/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/png/compress-png/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/png/convert-jgp-to-png/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/png/convert-jgp-to-png/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/json/escape-json/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/json/escape-json/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/json/json-to-xml/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/json/json-to-xml/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/json/minify/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/json/minify/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/json/prettify/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/json/prettify/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/json/stringify/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/json/stringify/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/json/tsv-to-json/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/json/tsv-to-json/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/json/validateJson/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/json/validateJson/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/duplicate/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/duplicate/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/find-most-popular/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/find-most-popular/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/find-unique/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/find-unique/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/group/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/group/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/reverse/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/reverse/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/rotate/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/rotate/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/shuffle/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/shuffle/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/sort/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/sort/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/truncate/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/truncate/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/unwrap/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/unwrap/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/wrap/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/wrap/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/arithmetic-sequence/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/arithmetic-sequence/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generate/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generate/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/ohmsLaw.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/ohmsLaw.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/slackline.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/slackline.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/sphereArea.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/sphereArea.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/sphereVolume.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/sphereVolume.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/voltageDropInWire.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/voltageDropInWire.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/sum/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/sum/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/pdf/compress-pdf/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/pdf/compress-pdf/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/pdf/editor/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/pdf/editor/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/pdf/merge-pdf/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/pdf/merge-pdf/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/pdf/pdf-to-epub/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/pdf/pdf-to-epub/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/pdf/pdf-to-png/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/pdf/pdf-to-png/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/pdf/protect-pdf/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/pdf/protect-pdf/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/pdf/rotate-pdf/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/pdf/rotate-pdf/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/pdf/split-pdf/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/pdf/split-pdf/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/base64/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/base64/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/censor/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/censor/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/create-palindrome/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/create-palindrome/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/extract-substring/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/extract-substring/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/join/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/join/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/palindrome/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/palindrome/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/quote/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/quote/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/randomize-case/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/randomize-case/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/remove-duplicate-lines/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/remove-duplicate-lines/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/repeat/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/repeat/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/reverse/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/reverse/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/rot13/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/rot13/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/rotate/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/rotate/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/split/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/split/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/statistic/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/statistic/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/text-replacer/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/text-replacer/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/to-morse/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/to-morse/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/truncate/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/truncate/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/uppercase/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/uppercase/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/time/check-leap-years/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/time/check-leap-years/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/time/convert-days-to-hours/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/time/convert-days-to-hours/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/time/convert-hours-to-days/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/time/convert-hours-to-days/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/time/convert-seconds-to-time/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/time/convert-seconds-to-time/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/time/convert-time-to-seconds/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/time/convert-time-to-seconds/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/time/crontab-guru/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/time/crontab-guru/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/time/time-between-dates/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/time/time-between-dates/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/time/truncate-clock-time/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/time/truncate-clock-time/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/video/change-speed/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/video/change-speed/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/video/compress/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/video/compress/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/video/crop-video/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/video/crop-video/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/video/flip/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/video/flip/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/video/gif/change-speed/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/video/gif/change-speed/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/video/loop/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/video/loop/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/video/rotate/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/video/rotate/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/video/trim/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/video/trim/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/video/video-to-gif/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/video/video-to-gif/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/xml/xml-beautifier/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/xml/xml-beautifier/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/xml/xml-validator/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/xml/xml-validator/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/i18n/en.json" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/i18n/en.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/i18n/hi.json" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/i18n/hi.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/index.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/tools/defineTool.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/tools/defineTool.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/tools/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/tools/index.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/utils/string.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/string.ts" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -487,7 +380,7 @@
|
||||
</scripts>
|
||||
<node-interpreter value="project" />
|
||||
<envs>
|
||||
<env name="LOCIZE_API_KEY" value="a2ac4dc2-d10le-4d35-bcf7-92db87381711" />
|
||||
<env name="LOCIZE_API_KEY" value="a2ac4dc2-d10e-4d35-bcf7-92db87381711" />
|
||||
</envs>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
@@ -617,15 +510,7 @@
|
||||
<workItem from="1752157409587" duration="2415000" />
|
||||
<workItem from="1752403829295" duration="13253000" />
|
||||
<workItem from="1752493585622" duration="11629000" />
|
||||
<workItem from="1752507105323" duration="4936000" />
|
||||
</task>
|
||||
<task id="LOCAL-00181" summary="fix: stars button width for 1k+ 😊">
|
||||
<option name="closed" value="true" />
|
||||
<created>1743470832619</created>
|
||||
<option name="number" value="00181" />
|
||||
<option name="presentableId" value="LOCAL-00181" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1743470832619</updated>
|
||||
<workItem from="1752507105323" duration="6496000" />
|
||||
</task>
|
||||
<task id="LOCAL-00182" summary="feat: compress pdf">
|
||||
<option name="closed" value="true" />
|
||||
@@ -1011,7 +896,15 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1752505593881</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="230" />
|
||||
<task id="LOCAL-00230" summary="fix: translation related behaviors">
|
||||
<option name="closed" value="true" />
|
||||
<created>1752512678963</created>
|
||||
<option name="number" value="00230" />
|
||||
<option name="presentableId" value="LOCAL-00230" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1752512678963</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="231" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
@@ -1058,8 +951,6 @@
|
||||
<option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="false" />
|
||||
<option name="CHECK_NEW_TODO" value="false" />
|
||||
<option name="ADD_EXTERNAL_FILES_SILENTLY" value="true" />
|
||||
<MESSAGE value="chore: rename from Omni Tools to OmniTools" />
|
||||
<MESSAGE value="fix: tools by category page title" />
|
||||
<MESSAGE value="chore: use scrollY" />
|
||||
<MESSAGE value="chore: remove flip x and y" />
|
||||
<MESSAGE value="chore: new logo and font" />
|
||||
@@ -1083,7 +974,9 @@
|
||||
<MESSAGE value="fix: tsc" />
|
||||
<MESSAGE value="chore: remove unnecessary" />
|
||||
<MESSAGE value="chore: saveMissing" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="chore: saveMissing" />
|
||||
<MESSAGE value="fix: translations" />
|
||||
<MESSAGE value="fix: translation related behaviors" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="fix: translation related behaviors" />
|
||||
</component>
|
||||
<component name="VgoProject">
|
||||
<integration-enabled>false</integration-enabled>
|
||||
|
@@ -17,6 +17,7 @@ import { tool as stringTruncate } from './truncate/meta';
|
||||
import { tool as stringBase64 } from './base64/meta';
|
||||
import { tool as stringStatistic } from './statistic/meta';
|
||||
import { tool as stringCensor } from './censor/meta';
|
||||
import { tool as stringPasswordGenerator } from './password-generator/meta';
|
||||
|
||||
export const stringTools = [
|
||||
stringSplit,
|
||||
@@ -37,5 +38,6 @@ export const stringTools = [
|
||||
stringRot13,
|
||||
stringBase64,
|
||||
stringStatistic,
|
||||
stringCensor
|
||||
stringCensor,
|
||||
stringPasswordGenerator
|
||||
];
|
||||
|
165
src/pages/tools/string/password-generator/index.tsx
Normal file
165
src/pages/tools/string/password-generator/index.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Box, Checkbox, FormControlLabel, FormGroup } from '@mui/material';
|
||||
import { generatePassword } from './service';
|
||||
import { initialValues, InitialValuesType } from './initialValues';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { GetGroupsType } from '@components/options/ToolOptions';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
title: 'Strong Password (12 characters)',
|
||||
description:
|
||||
'Generate a secure password with all character types including symbols.',
|
||||
sampleText: '',
|
||||
sampleResult: 'A7#mK9$pL2@x',
|
||||
sampleOptions: {
|
||||
length: '12',
|
||||
includeLowercase: true,
|
||||
includeUppercase: true,
|
||||
includeNumbers: true,
|
||||
includeSymbols: true,
|
||||
avoidAmbiguous: false
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Simple Password (8 characters)',
|
||||
description: 'Generate a basic password with letters and numbers only.',
|
||||
sampleText: '',
|
||||
sampleResult: 'Ab3mK9pL',
|
||||
sampleOptions: {
|
||||
length: '8',
|
||||
includeLowercase: true,
|
||||
includeUppercase: true,
|
||||
includeNumbers: true,
|
||||
includeSymbols: false,
|
||||
avoidAmbiguous: false
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Clear Password (No ambiguous)',
|
||||
description:
|
||||
'Generate a password without ambiguous characters (i, I, l, 0, O).',
|
||||
sampleText: '',
|
||||
sampleResult: 'A7#mK9$pL2@x',
|
||||
sampleOptions: {
|
||||
length: '12',
|
||||
includeLowercase: true,
|
||||
includeUppercase: true,
|
||||
includeNumbers: true,
|
||||
includeSymbols: true,
|
||||
avoidAmbiguous: true
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export default function PasswordGenerator({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
function compute(values: InitialValuesType) {
|
||||
setResult(generatePassword(values));
|
||||
}
|
||||
|
||||
const getGroups: GetGroupsType<InitialValuesType> = ({
|
||||
values,
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: t('passwordGenerator.optionsTitle'),
|
||||
component: (
|
||||
<Box sx={{ display: 'flex', gap: 2, flexDirection: 'column' }}>
|
||||
<TextFieldWithDesc
|
||||
description={t('passwordGenerator.lengthDesc')}
|
||||
placeholder={t('passwordGenerator.lengthPlaceholder')}
|
||||
value={values.length}
|
||||
onOwnChange={(val) => updateField('length', val)}
|
||||
type="number"
|
||||
/>
|
||||
|
||||
<FormGroup>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.includeLowercase}
|
||||
onChange={(e) =>
|
||||
updateField('includeLowercase', e.target.checked)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label={t('passwordGenerator.includeLowercase')}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.includeUppercase}
|
||||
onChange={(e) =>
|
||||
updateField('includeUppercase', e.target.checked)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label={t('passwordGenerator.includeUppercase')}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.includeNumbers}
|
||||
onChange={(e) =>
|
||||
updateField('includeNumbers', e.target.checked)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label={t('passwordGenerator.includeNumbers')}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.includeSymbols}
|
||||
onChange={(e) =>
|
||||
updateField('includeSymbols', e.target.checked)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label={t('passwordGenerator.includeSymbols')}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.avoidAmbiguous}
|
||||
onChange={(e) =>
|
||||
updateField('avoidAmbiguous', e.target.checked)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label={t('passwordGenerator.avoidAmbiguous')}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
title={title}
|
||||
initialValues={initialValues}
|
||||
getGroups={getGroups}
|
||||
compute={compute}
|
||||
resultComponent={
|
||||
<ToolTextResult
|
||||
title={t('passwordGenerator.resultTitle')}
|
||||
value={result}
|
||||
/>
|
||||
}
|
||||
toolInfo={{
|
||||
title: t('passwordGenerator.toolInfo.title'),
|
||||
description: t('passwordGenerator.toolInfo.description')
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
/>
|
||||
);
|
||||
}
|
17
src/pages/tools/string/password-generator/initialValues.ts
Normal file
17
src/pages/tools/string/password-generator/initialValues.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export type InitialValuesType = {
|
||||
length: string; // user enters a number here
|
||||
includeLowercase: boolean;
|
||||
includeUppercase: boolean;
|
||||
includeNumbers: boolean;
|
||||
includeSymbols: boolean;
|
||||
avoidAmbiguous: boolean;
|
||||
};
|
||||
|
||||
export const initialValues: InitialValuesType = {
|
||||
length: '12',
|
||||
includeLowercase: true,
|
||||
includeUppercase: true,
|
||||
includeNumbers: true,
|
||||
includeSymbols: true,
|
||||
avoidAmbiguous: false
|
||||
};
|
14
src/pages/tools/string/password-generator/meta.ts
Normal file
14
src/pages/tools/string/password-generator/meta.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
path: 'password-generator',
|
||||
icon: 'material-symbols:key',
|
||||
keywords: ['password', 'generator', 'random', 'secure'],
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:passwordGenerator.title',
|
||||
description: 'string:passwordGenerator.description',
|
||||
shortDescription: 'string:passwordGenerator.shortDescription'
|
||||
}
|
||||
});
|
@@ -0,0 +1,143 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { generatePassword } from './service';
|
||||
import { initialValues } from './initialValues';
|
||||
|
||||
describe('generatePassword', () => {
|
||||
it('should generate a password with the specified length', () => {
|
||||
const options = { ...initialValues, length: '10' };
|
||||
const result = generatePassword(options);
|
||||
expect(result).toHaveLength(10);
|
||||
});
|
||||
|
||||
it('should return empty string for invalid length', () => {
|
||||
const options = { ...initialValues, length: '0' };
|
||||
const result = generatePassword(options);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should return empty string for non-numeric length', () => {
|
||||
const options = { ...initialValues, length: 'abc' };
|
||||
const result = generatePassword(options);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should return empty string when no character types are selected', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
includeLowercase: false,
|
||||
includeUppercase: false,
|
||||
includeNumbers: false,
|
||||
includeSymbols: false
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should only include lowercase letters when only lowercase is selected', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '20',
|
||||
includeLowercase: true,
|
||||
includeUppercase: false,
|
||||
includeNumbers: false,
|
||||
includeSymbols: false
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).toMatch(/^[a-z]+$/);
|
||||
expect(result).toHaveLength(20);
|
||||
});
|
||||
|
||||
it('should only include uppercase letters when only uppercase is selected', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '15',
|
||||
includeLowercase: false,
|
||||
includeUppercase: true,
|
||||
includeNumbers: false,
|
||||
includeSymbols: false
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).toMatch(/^[A-Z]+$/);
|
||||
expect(result).toHaveLength(15);
|
||||
});
|
||||
|
||||
it('should only include numbers when only numbers is selected', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '8',
|
||||
includeLowercase: false,
|
||||
includeUppercase: false,
|
||||
includeNumbers: true,
|
||||
includeSymbols: false
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).toMatch(/^[0-9]+$/);
|
||||
expect(result).toHaveLength(8);
|
||||
});
|
||||
|
||||
it('should include mixed character types when multiple are selected', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '100', // larger sample for better testing
|
||||
includeLowercase: true,
|
||||
includeUppercase: true,
|
||||
includeNumbers: true,
|
||||
includeSymbols: false
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).toMatch(/^[a-zA-Z0-9]+$/);
|
||||
expect(result).toHaveLength(100);
|
||||
});
|
||||
|
||||
it('should exclude ambiguous characters when avoidAmbiguous is true', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '50',
|
||||
avoidAmbiguous: true
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).not.toMatch(/[iIl0O]/);
|
||||
expect(result).toHaveLength(50);
|
||||
});
|
||||
|
||||
it('should include symbols when includeSymbols is true', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '30',
|
||||
includeLowercase: false,
|
||||
includeUppercase: false,
|
||||
includeNumbers: false,
|
||||
includeSymbols: true
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).toMatch(/^[!@#$%^&*()_+~`|}{[\]:;?><,./-=]+$/);
|
||||
expect(result).toHaveLength(30);
|
||||
});
|
||||
|
||||
it('should exclude ambiguous characters from symbols too', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '50',
|
||||
includeLowercase: false,
|
||||
includeUppercase: false,
|
||||
includeNumbers: true,
|
||||
includeSymbols: true,
|
||||
avoidAmbiguous: true
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).not.toMatch(/[iIl0O]/);
|
||||
expect(result).toHaveLength(50);
|
||||
});
|
||||
|
||||
it('should handle edge case with very short length', () => {
|
||||
const options = { ...initialValues, length: '1' };
|
||||
const result = generatePassword(options);
|
||||
expect(result).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should handle negative length', () => {
|
||||
const options = { ...initialValues, length: '-5' };
|
||||
const result = generatePassword(options);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
});
|
38
src/pages/tools/string/password-generator/service.ts
Normal file
38
src/pages/tools/string/password-generator/service.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import type { InitialValuesType } from './initialValues';
|
||||
|
||||
export function generatePassword(options: InitialValuesType): string {
|
||||
const length = parseInt(options.length || '', 10);
|
||||
if (isNaN(length) || length <= 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let charset = '';
|
||||
const lower = 'abcdefghijklmnopqrstuvwxyz';
|
||||
const upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
const numbers = '0123456789';
|
||||
const symbols = '!@#$%^&*()_+~`|}{[]:;?><,./-=';
|
||||
|
||||
if (options.includeLowercase) charset += lower;
|
||||
if (options.includeUppercase) charset += upper;
|
||||
if (options.includeNumbers) charset += numbers;
|
||||
if (options.includeSymbols) charset += symbols;
|
||||
|
||||
if (options.avoidAmbiguous) {
|
||||
// ambiguous set = i, I, l, 0, O
|
||||
const ambig = new Set(['i', 'I', 'l', '0', 'O']);
|
||||
charset = Array.from(charset)
|
||||
.filter((c) => !ambig.has(c))
|
||||
.join('');
|
||||
}
|
||||
|
||||
if (!charset) {
|
||||
return ''; // nothing to pick from
|
||||
}
|
||||
|
||||
let pwd = '';
|
||||
for (let i = 0; i < length; i++) {
|
||||
const idx = Math.floor(Math.random() * charset.length);
|
||||
pwd += charset[idx];
|
||||
}
|
||||
return pwd;
|
||||
}
|
@@ -2,7 +2,7 @@ import ToolLayout from '../components/ToolLayout';
|
||||
import React, { JSXElementConstructor, LazyExoticComponent } from 'react';
|
||||
import { IconifyIcon } from '@iconify/react';
|
||||
import { FullI18nKey } from '../i18n';
|
||||
import { ParseKeys } from 'i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export interface ToolMeta {
|
||||
path: string;
|
||||
@@ -62,10 +62,16 @@ export const defineTool = (
|
||||
description: i18n.description,
|
||||
shortDescription: i18n.shortDescription,
|
||||
keywords,
|
||||
component: () => {
|
||||
component: function ToolComponent() {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<ToolLayout icon={icon} type={basePath} i18n={i18n}>
|
||||
<Component title={i18n.name} longDescription={i18n.longDescription} />
|
||||
<Component
|
||||
title={t(i18n.name)}
|
||||
longDescription={
|
||||
i18n.longDescription ? t(i18n.longDescription) : undefined
|
||||
}
|
||||
/>
|
||||
</ToolLayout>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user