diff --git a/.github/workflows/gitmotion-docker-image.yml b/.github/workflows/gitmotion-docker-image.yml new file mode 100644 index 0000000000..473a7274b8 --- /dev/null +++ b/.github/workflows/gitmotion-docker-image.yml @@ -0,0 +1,67 @@ +name: Build and Push Docker Image + +on: + push: + branches: + - gitmotion/main # You can also specify the branch where you want the action to trigger, like `develop`, or your custom branch. + +jobs: + ci: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - run: corepack enable + - uses: actions/setup-node@v3 + with: + node-version: 20 + cache: 'pnpm' + + - name: Install dependencies + run: pnpm i + + - name: Run linters + run: pnpm lint + + - name: Run unit tests + run: pnpm test + + - name: Build the app + run: pnpm build + + build: + runs-on: ubuntu-latest + needs: + - ci + steps: + # Checkout the repository + - name: Checkout repository + uses: actions/checkout@v3 + + # Set up Docker Buildx (to support multi-platform builds) + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + # Log in to GitHub Container Registry (GHCR) + - name: Log in to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ secrets.GHCR_USERNAME }} + password: ${{ secrets.GHCR_TOKEN }} + + # Build and push the Docker image + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ghcr.io/${{ secrets.GHCR_USERNAME }}/it-tools:latest + # Optionally add version tags or specific branch tags like: + # tags: | + # ghcr.io/${{ secrets.GHCR_USERNAME }}/your-repo-name:latest + # ghcr.io/${{ secrets.GHCR_USERNAME }}/your-repo-name:${{ github.sha }} + + # Optionally log out + - name: Log out from GitHub Container Registry + run: docker logout ghcr.io diff --git a/README.md b/README.md index 8bf7616bb3..372ba102be 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,40 @@ +### Check out these change here: + +You can use my image in your docker-compose file if you want this functionality along with my other additions until the main branch has been updated. + +- github action triggers on every push to this branch - [view package here](https://github.com/gitmotion/it-tools/pkgs/container/it-tools) + +## Added features + +
+ Pull requests added + +| Feature | PR Links | +|---------------------------------|--------------------------------------------------------------------------------------------------------------------| +| [Reorder favorites with drag and drop](https://gitmotion-it-tools-beta.vercel.app/) | [#1360](https://github.com/CorentinTh/it-tools/pull/1360), [#1375](https://github.com/CorentinTh/it-tools/pull/1375) | +| [AI prompt splitter](https://gitmotion-it-tools-beta.vercel.app/ai-prompt-splitter) | [#1357](https://github.com/CorentinTh/it-tools/pull/1357) | +| [Multi-link downloader](https://gitmotion-it-tools-beta.vercel.app/multi-link-downloader) | [#1354](https://github.com/CorentinTh/it-tools/pull/1354) | +| [Image resizer](https://gitmotion-it-tools-beta.vercel.app/image-resizer) | [#1361](https://github.com/CorentinTh/it-tools/pull/1361) | +| [JSON String converter](https://gitmotion-it-tools-beta.vercel.app/json-string-converter) | [#1351](https://github.com/CorentinTh/it-tools/pull/1351) | +| [Emoji picker performance updates](https://gitmotion-it-tools-beta.vercel.app/emoji-picker) | [#1374](https://github.com/CorentinTh/it-tools/pull/1374) | +| Updates/Bug fixes | [#1355](https://github.com/CorentinTh/it-tools/pull/1355), [#1342](https://github.com/CorentinTh/it-tools/issues/1342) | + +
+ +## Installation methods + +| Docker Image | Local Installation | +|-----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------| +| `ghcr.io/gitmotion/it-tools:latest` | `git clone -b gitmotion/main https://github.com/gitmotion/it-tools.git && cd it-tools/ && pnpm i && pnpm dev` | +| replace your current image with this image | copy & paste oneliner (from github repo) | +| You may need to clear cache and hard reload to get new features loading | Installing packages for the first time may take some time; please wait until it finishes | + +## + +![Alt](https://repobeats.axiom.co/api/embed/c5fb872b58d75b099aff112d9c4c7fc1eabf8a9b.svg "Repobeats analytics image") + +## + @@ -6,6 +43,8 @@ Useful tools for developer and people working in IT. [Have a look !](https://it-tools.tech). +
+ ## Sponsors [![Fern banner](./.github/fern-banner.svg)](https://bit.ly/3zBl7DG) @@ -133,3 +172,4 @@ Contributor graph is generated using [contrib.rocks](https://contrib.rocks/previ ## License This project is under the [GNU GPLv3](LICENSE). +
diff --git a/components.d.ts b/components.d.ts index 3e65c3cc52..4509b58d60 100644 --- a/components.d.ts +++ b/components.d.ts @@ -11,6 +11,7 @@ declare module '@vue/runtime-core' { export interface GlobalComponents { '404.page': typeof import('./src/pages/404.page.vue')['default'] About: typeof import('./src/pages/About.vue')['default'] + AiPromptSplitter: typeof import('./src/tools/ai-prompt-splitter/ai-prompt-splitter.vue')['default'] App: typeof import('./src/App.vue')['default'] AsciiTextDrawer: typeof import('./src/tools/ascii-text-drawer/ascii-text-drawer.vue')['default'] 'Base.layout': typeof import('./src/layouts/base.layout.vue')['default'] @@ -101,6 +102,7 @@ declare module '@vue/runtime-core' { IconMdiSearch: typeof import('~icons/mdi/search')['default'] IconMdiTranslate: typeof import('~icons/mdi/translate')['default'] IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default'] + ImageResizer: typeof import('./src/tools/image-resizer/image-resizer.vue')['default'] InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] @@ -109,6 +111,7 @@ declare module '@vue/runtime-core' { Ipv6UlaGenerator: typeof import('./src/tools/ipv6-ula-generator/ipv6-ula-generator.vue')['default'] JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default'] JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default'] + JsonStringConverter: typeof import('./src/tools/json-string-converter/json-string-converter.vue')['default'] JsonToCsv: typeof import('./src/tools/json-to-csv/json-to-csv.vue')['default'] JsonToToml: typeof import('./src/tools/json-to-toml/json-to-toml.vue')['default'] JsonToXml: typeof import('./src/tools/json-to-xml/json-to-xml.vue')['default'] @@ -129,6 +132,7 @@ declare module '@vue/runtime-core' { MenuLayout: typeof import('./src/components/MenuLayout.vue')['default'] MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] + MultiLinkDownloader: typeof import('./src/tools/multi-link-downloader/multi-link-downloader.vue')['default'] NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] NCheckbox: typeof import('naive-ui')['NCheckbox'] NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] diff --git a/locales/en.yml b/locales/en.yml index b195dbd85d..7f48c391e3 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -333,6 +333,10 @@ tools: title: JSON minify description: Minify and compress your JSON by removing unnecessary whitespace. + json-string-converter: + title: JSON string converter + description: Convert your plain text or JavaScript objects into JSON string format and vice versa. + ulid-generator: title: ULID generator description: Generate random Universally Unique Lexicographically Sortable Identifier (ULID). @@ -392,3 +396,15 @@ tools: text-to-binary: title: Text to ASCII binary description: Convert text to its ASCII binary representation and vice-versa. + + ai-prompt-splitter: + title: AI prompt splitter + description: Split up large prompts into smaller, manageable segments based on a set character limit for AI chat prompts. + + image-resizer: + title: Image resizer + description: Convert the width and height of an image file, preview, and download it in a desired format (.jpg, .jpeg, .png, .bmp, .ico, .svg) + + multi-link-downloader: + title: Multi link downloader + description: Asynchronously downloads from multiple links into a zip file while a single link downloads directly. (Requires an internet connection) \ No newline at end of file diff --git a/package.json b/package.json index 5c991cff64..5c2d2e5d1e 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "ibantools": "^4.3.3", "js-base64": "^3.7.6", "json5": "^2.2.3", + "jszip": "^3.10.1", "jwt-decode": "^3.1.2", "libphonenumber-js": "^1.10.28", "lodash": "^4.17.21", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3798ae1716..ab1a598c19 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -110,6 +110,9 @@ dependencies: json5: specifier: ^2.2.3 version: 2.2.3 + jszip: + specifier: ^3.10.1 + version: 3.10.1 jwt-decode: specifier: ^3.1.2 version: 3.1.2 @@ -4674,6 +4677,9 @@ packages: browserslist: 4.22.1 dev: true + /core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + /country-code-lookup@0.1.0: resolution: {integrity: sha512-IOI66HEG+8bXfWPy+sTzuN7161vmDZOHg1wgIPFf3WfD73FeLajnn6C+fnxOIa9RL1WRBDMXQQWW/FOaOYaQ3w==} dev: false @@ -6195,6 +6201,9 @@ packages: dev: true optional: true + /immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + /import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -6501,6 +6510,9 @@ packages: is-docker: 2.2.1 dev: true + /isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + /isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} dev: true @@ -6695,6 +6707,14 @@ packages: engines: {node: '>=0.10.0'} dev: true + /jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + /kolorist@1.8.0: resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} dev: true @@ -6735,6 +6755,11 @@ packages: resolution: {integrity: sha512-1eAgjLrZA0+2Wgw4hs+4Q/kEBycxQo8ZLYnmOvZ3AlM8ImAVAJgDPlZtISLEzD1vunc2q8s2Pn7XwB7I8U3Kzw==} dev: false + /lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + dependencies: + immediate: 3.0.6 + /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true @@ -7341,6 +7366,9 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + /pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + /param-case@2.1.1: resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==} dependencies: @@ -7580,6 +7608,7 @@ packages: engines: {node: ^14.13.1 || >=16.0.0} dev: true + /pretty-format@29.6.2: resolution: {integrity: sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7589,6 +7618,9 @@ packages: react-is: 18.2.0 dev: true + /process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + /prosemirror-changeset@2.2.1: resolution: {integrity: sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==} dependencies: @@ -7841,6 +7873,17 @@ packages: type-fest: 0.6.0 dev: true + /readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + /readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -8047,6 +8090,9 @@ packages: isarray: 2.0.5 dev: true + /safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: true @@ -8170,6 +8216,9 @@ packages: is-primitive: 3.0.1 dev: false + /setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -8376,6 +8425,11 @@ packages: es-abstract: 1.22.3 dev: true + /string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + /string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: diff --git a/src/pages/Home.page.vue b/src/pages/Home.page.vue index fdbccf7e21..1b8c568973 100644 --- a/src/pages/Home.page.vue +++ b/src/pages/Home.page.vue @@ -76,7 +76,7 @@ function onUpdateFavoriteTools() {

{{ $t('home.categories.favoriteTools') }} - +

diff --git a/src/tools/ai-prompt-splitter/ai-prompt-splitter.vue b/src/tools/ai-prompt-splitter/ai-prompt-splitter.vue new file mode 100644 index 0000000000..445a01a540 --- /dev/null +++ b/src/tools/ai-prompt-splitter/ai-prompt-splitter.vue @@ -0,0 +1,282 @@ + + + + + diff --git a/src/tools/ai-prompt-splitter/index.ts b/src/tools/ai-prompt-splitter/index.ts new file mode 100644 index 0000000000..8b9d6d2884 --- /dev/null +++ b/src/tools/ai-prompt-splitter/index.ts @@ -0,0 +1,12 @@ +import { IconMessages } from '@tabler/icons-vue'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Ai prompt splitter', + path: '/ai-prompt-splitter', + description: '', + keywords: ['ai', 'prompt', 'splitter'], + component: () => import('./ai-prompt-splitter.vue'), + icon: IconMessages, + createdAt: new Date(), +}); diff --git a/src/tools/emoji-picker/emoji-picker.vue b/src/tools/emoji-picker/emoji-picker.vue index a12b10c2f7..2110579ab7 100644 --- a/src/tools/emoji-picker/emoji-picker.vue +++ b/src/tools/emoji-picker/emoji-picker.vue @@ -2,6 +2,7 @@ import emojiUnicodeData from 'unicode-emoji-json'; import emojiKeywords from 'emojilib'; import _ from 'lodash'; +import { IconChevronRight, IconSearch } from '@tabler/icons-vue'; import type { EmojiInfo } from './emoji.types'; import { useFuzzySearch } from '@/composable/fuzzySearch'; import useDebouncedRef from '@/composable/debouncedref'; @@ -36,10 +37,36 @@ const { searchResult } = useFuzzySearch({ isCaseSensitive: false, }, }); + +const emojisPerPage = 30; // Number of emojis to load per group initially + +// Tracks how many emojis are shown per group and the collapsed state of each group +const groupLoadLimits = ref( + emojisGroups.reduce((acc, group) => { + acc[group.group] = { limit: emojisPerPage, collapsed: false }; + return acc; + }, {} as Record), +); + +// Toggles the visibility of the emoji group +function toggleGroup(group: string) { + groupLoadLimits.value[group].collapsed = !groupLoadLimits.value[group].collapsed; +}; + +// Loads more emojis incrementally +function loadMoreEmojis(group: string) { + groupLoadLimits.value[group].limit += emojisPerPage; +}; + +// Loads all emojis in the group at once +function loadAllEmojis(group: string) { + groupLoadLimits.value[group].limit = emojisGroups.find(g => g.group === group)?.emojiInfos.length || 0; +}; diff --git a/src/tools/emoji-picker/index.ts b/src/tools/emoji-picker/index.ts index 3a28cf0f19..a82123da2b 100644 --- a/src/tools/emoji-picker/index.ts +++ b/src/tools/emoji-picker/index.ts @@ -9,5 +9,5 @@ export const tool = defineTool({ keywords: ['emoji', 'picker', 'unicode', 'copy', 'paste'], component: () => import('./emoji-picker.vue'), icon: MoodSmile, - createdAt: new Date('2023-08-07'), + createdAt: new Date(), }); diff --git a/src/tools/image-resizer/image-resizer.vue b/src/tools/image-resizer/image-resizer.vue new file mode 100644 index 0000000000..3c88ff1be2 --- /dev/null +++ b/src/tools/image-resizer/image-resizer.vue @@ -0,0 +1,197 @@ + + + + + diff --git a/src/tools/image-resizer/index.ts b/src/tools/image-resizer/index.ts new file mode 100644 index 0000000000..6a3e754a75 --- /dev/null +++ b/src/tools/image-resizer/index.ts @@ -0,0 +1,12 @@ +import { Resize } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Image resizer', + path: '/image-resizer', + description: '', + keywords: ['image', 'resizer', 'favicon', 'jpg', 'jpeg', 'png', 'bmp', 'ico', 'svg'], + component: () => import('./image-resizer.vue'), + icon: Resize, + createdAt: new Date(), +}); diff --git a/src/tools/index.ts b/src/tools/index.ts index 388cfaf494..6ed6c4d28b 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -1,6 +1,10 @@ import { tool as base64FileConverter } from './base64-file-converter'; import { tool as base64StringConverter } from './base64-string-converter'; import { tool as basicAuthGenerator } from './basic-auth-generator'; +import { tool as jsonStringConverter } from './json-string-converter'; +import { tool as aiPromptSplitter } from './ai-prompt-splitter'; +import { tool as imageResizer } from './image-resizer'; +import { tool as multiLinkDownloader } from './multi-link-downloader'; import { tool as emailNormalizer } from './email-normalizer'; import { tool as asciiTextDrawer } from './ascii-text-drawer'; @@ -106,6 +110,7 @@ export const toolsByCategory: ToolCategory[] = [ textToNatoAlphabet, textToBinary, textToUnicode, + jsonStringConverter, yamlToJson, yamlToToml, jsonToYaml, @@ -141,7 +146,13 @@ export const toolsByCategory: ToolCategory[] = [ }, { name: 'Images and videos', - components: [qrCodeGenerator, wifiQrCodeGenerator, svgPlaceholderGenerator, cameraRecorder], + components: [ + qrCodeGenerator, + wifiQrCodeGenerator, + svgPlaceholderGenerator, + cameraRecorder, + imageResizer, + ], }, { name: 'Development', @@ -184,11 +195,16 @@ export const toolsByCategory: ToolCategory[] = [ textDiff, numeronymGenerator, asciiTextDrawer, + aiPromptSplitter, ], }, { name: 'Data', - components: [phoneParserAndFormatter, ibanValidatorAndParser], + components: [ + phoneParserAndFormatter, + ibanValidatorAndParser, + multiLinkDownloader, + ], }, ]; diff --git a/src/tools/json-string-converter/index.ts b/src/tools/json-string-converter/index.ts new file mode 100644 index 0000000000..ea95a88ee5 --- /dev/null +++ b/src/tools/json-string-converter/index.ts @@ -0,0 +1,12 @@ +import { Braces } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Json string converter', + path: '/json-string-converter', + description: '', + keywords: ['json', 'string', 'converter'], + component: () => import('./json-string-converter.vue'), + icon: Braces, + createdAt: new Date(), +}); diff --git a/src/tools/json-string-converter/json-string-converter.vue b/src/tools/json-string-converter/json-string-converter.vue new file mode 100644 index 0000000000..71da26038a --- /dev/null +++ b/src/tools/json-string-converter/json-string-converter.vue @@ -0,0 +1,56 @@ + + + diff --git a/src/tools/json-to-csv/json-to-csv.vue b/src/tools/json-to-csv/json-to-csv.vue index e2f5ddb67f..0f02bce9cd 100644 --- a/src/tools/json-to-csv/json-to-csv.vue +++ b/src/tools/json-to-csv/json-to-csv.vue @@ -4,6 +4,8 @@ import { convertArrayToCsv } from './json-to-csv.service'; import type { UseValidationRule } from '@/composable/validation'; import { withDefaultOnError } from '@/utils/defaults'; +const defaultValue = '[\n {\n "Age": 18,\n "Country": "Germany",\n "Gender": "Male",\n "Purchased": "N",\n "Salary": 20000\n },\n {\n "Age": 19,\n "Country": "France",\n "Gender": "Female",\n "Purchased": "N",\n "Salary": 22000\n },\n {\n "Age": 20,\n "Country": "England",\n "Gender": "Female",\n "Purchased": "N",\n "Salary": 24000\n }\n]'; + function transformer(value: string) { return withDefaultOnError(() => { if (value === '') { @@ -24,6 +26,7 @@ const rules: UseValidationRule[] = [