mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 05:10:16 +03:00
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f63354e4e | ||
|
|
c6762532e5 | ||
|
|
f44346a569 | ||
|
|
596d92b29d | ||
|
|
7cec27175a | ||
|
|
3136aefbf1 | ||
|
|
f8456e4279 | ||
|
|
7344b3a1a7 | ||
|
|
40b49cc96e | ||
|
|
9baad91fad | ||
|
|
5cb2c5ee24 | ||
|
|
58a2a1b09b | ||
|
|
12b843ac33 | ||
|
|
d2d70fe793 | ||
|
|
31a653be32 |
Generated
+128
-41
@@ -102,6 +102,7 @@
|
||||
"postcss-preset-mantine": "^1.18.0",
|
||||
"postcss-simple-vars": "^7.0.1",
|
||||
"puppeteer": "^24.25.0",
|
||||
"rollup-plugin-visualizer": "^6.0.5",
|
||||
"typescript": "^5.9.2",
|
||||
"typescript-eslint": "^8.44.1",
|
||||
"vite": "^7.1.7",
|
||||
@@ -457,7 +458,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
@@ -501,7 +501,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -582,7 +581,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/core/-/core-1.5.0.tgz",
|
||||
"integrity": "sha512-Yrh9XoVaT8cUgzgqpJ7hx5wg6BqQrCFirqqlSwVb+Ly9oNn4fZbR9GycIWmzJOU5XBnaOJjXfQSaDyoNP0woNA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@embedpdf/engines": "1.5.0",
|
||||
"@embedpdf/models": "1.5.0"
|
||||
@@ -682,7 +680,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-history/-/plugin-history-1.5.0.tgz",
|
||||
"integrity": "sha512-p7PTNNaIr4gH3jLwX+eLJe1DeUXgi21kVGN6SRx/pocH8esg4jqoOeD/YiRRZoZnPOiy0jBXVhkPkwSmY7a2hQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.5.0"
|
||||
},
|
||||
@@ -699,7 +696,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-interaction-manager/-/plugin-interaction-manager-1.5.0.tgz",
|
||||
"integrity": "sha512-ckHgTfvkW6c5Ta7Mc+Dl9C2foVnvEpqEJ84wyBnqrU0OWbe/jsiPhyKBVeartMGqNI/kVfaQTXupyrKhekAVmg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.5.0"
|
||||
},
|
||||
@@ -717,7 +713,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-loader/-/plugin-loader-1.5.0.tgz",
|
||||
"integrity": "sha512-P4YpIZfaW69etYIjphyaL4cGl2pB14h3OdTE0tRQ2pZYZHFLTvlt4q9B3PVSdhlSrHK5nob7jfLGon2U7xCslg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.5.0"
|
||||
},
|
||||
@@ -771,7 +766,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-render/-/plugin-render-1.5.0.tgz",
|
||||
"integrity": "sha512-ywwSj0ByrlkvrJIHKRzqxARkOZriki8VJUC+T4MV8fGyF4CzvCRJyKlPktahFz+VxhoodqTh7lBCib68dH+GvA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.5.0"
|
||||
},
|
||||
@@ -806,7 +800,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-scroll/-/plugin-scroll-1.5.0.tgz",
|
||||
"integrity": "sha512-RNmTZCZ8X1mA8cw9M7TMDuhO9GtkOalGha2bBL3En3D1IlDRS7PzNNMSMV7eqT7OQICSTltlpJ8p8Qi5esvL/Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.5.0"
|
||||
},
|
||||
@@ -843,7 +836,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-selection/-/plugin-selection-1.5.0.tgz",
|
||||
"integrity": "sha512-zrxLBAZQoPswDuf9q9DrYaQc6B0Ysc2U1hueTjNH/4+ydfl0BFXZkKR63C2e3YmWtXvKjkoIj0GyPzsiBORLUw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.5.0"
|
||||
},
|
||||
@@ -919,7 +911,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-viewport/-/plugin-viewport-1.5.0.tgz",
|
||||
"integrity": "sha512-G8GDyYRhfehw72+r4qKkydnA5+AU8qH67g01Y12b0DzI0VIzymh/05Z4dK8DsY3jyWPXJfw2hlg5+KDHaMBHgQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.5.0"
|
||||
},
|
||||
@@ -1075,7 +1066,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
|
||||
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.13.5",
|
||||
@@ -1119,7 +1109,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz",
|
||||
"integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.13.5",
|
||||
@@ -2150,7 +2139,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@mantine/core/-/core-8.3.6.tgz",
|
||||
"integrity": "sha512-paTl+0x+O/QtgMtqVJaG8maD8sfiOdgPmLOyG485FmeGZ1L3KMdEkhxZtmdGlDFsLXhmMGQ57ducT90bvhXX5A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/react": "^0.27.16",
|
||||
"clsx": "^2.1.1",
|
||||
@@ -2201,7 +2189,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-8.3.6.tgz",
|
||||
"integrity": "sha512-liHfaWXHAkLjJy+Bkr29UsCwAoDQ/a64WrM67lksx8F0qqyjR5RQH8zVlhuOjdpQnwtlUkE/YiTvbJiPcoI0bw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"react": "^18.x || ^19.x"
|
||||
}
|
||||
@@ -2269,7 +2256,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.5.tgz",
|
||||
"integrity": "sha512-8VVxFmp1GIm9PpmnQoCoYo0UWHoOrdA57tDL62vkpzEgvb/d71Wsbv4FRg7r1Gyx7PuSo0tflH34cdl/NvfHNQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@mui/core-downloads-tracker": "^7.3.5",
|
||||
@@ -3202,7 +3188,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-7.9.0.tgz",
|
||||
"integrity": "sha512-ggs5k+/0FUJcIgNY08aZTqpBTtbExkJMYMLSMwyucrhtWexVOEY1KJmhBsxf+E/Q15f5rbwBpj+t0t2AW2oCsQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12.16"
|
||||
}
|
||||
@@ -3321,6 +3306,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.6.tgz",
|
||||
"integrity": "sha512-4awhxtMh4cx9blePWl10HRHj8Iivtqj+2QdDCSMDzxG+XKa9+VCNupQuCuvzEhYPzZSrX+0gC+0lHA/0fFKKQQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"acorn": "^8.9.0"
|
||||
}
|
||||
@@ -4097,7 +4083,6 @@
|
||||
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.10.4",
|
||||
"@babel/runtime": "^7.12.5",
|
||||
@@ -4426,7 +4411,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
|
||||
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
@@ -4437,7 +4421,6 @@
|
||||
"integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.2.0"
|
||||
}
|
||||
@@ -4507,7 +4490,6 @@
|
||||
"integrity": "sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.46.3",
|
||||
"@typescript-eslint/types": "8.46.3",
|
||||
@@ -5221,6 +5203,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.24.tgz",
|
||||
"integrity": "sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.5.24"
|
||||
}
|
||||
@@ -5230,6 +5213,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.24.tgz",
|
||||
"integrity": "sha512-RYP/byyKDgNIqfX/gNb2PB55dJmM97jc9wyF3jK7QUInYKypK2exmZMNwnjueWwGceEkP6NChd3D2ZVEp9undQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.24",
|
||||
"@vue/shared": "3.5.24"
|
||||
@@ -5240,6 +5224,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.24.tgz",
|
||||
"integrity": "sha512-Z8ANhr/i0XIluonHVjbUkjvn+CyrxbXRIxR7wn7+X7xlcb7dJsfITZbkVOeJZdP8VZwfrWRsWdShH6pngMxRjw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.24",
|
||||
"@vue/runtime-core": "3.5.24",
|
||||
@@ -5252,6 +5237,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.24.tgz",
|
||||
"integrity": "sha512-Yh2j2Y4G/0/4z/xJ1Bad4mxaAk++C2v4kaa8oSYTMJBJ00/ndPuxCnWeot0/7/qafQFLh5pr6xeV6SdMcE/G1w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.5.24",
|
||||
"@vue/shared": "3.5.24"
|
||||
@@ -5278,7 +5264,6 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -5686,6 +5671,7 @@
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
||||
"integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
@@ -5962,7 +5948,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.19",
|
||||
"caniuse-lite": "^1.0.30001751",
|
||||
@@ -6758,6 +6743,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/define-lazy-prop": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
||||
"integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/define-properties": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||
@@ -7010,8 +7005,7 @@
|
||||
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1521046.tgz",
|
||||
"integrity": "sha512-vhE6eymDQSKWUXwwA37NtTTVEzjtGVfDr3pRbsWEQ5onH/Snp2c+2xZHWJJawG/0hCCJLRGt4xVtEVUVILol4w==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"peer": true
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/dezalgo": {
|
||||
"version": "1.0.4",
|
||||
@@ -7406,7 +7400,6 @@
|
||||
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -7577,7 +7570,6 @@
|
||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.9",
|
||||
@@ -7744,7 +7736,8 @@
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
|
||||
"integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/espree": {
|
||||
"version": "10.4.0",
|
||||
@@ -7809,6 +7802,7 @@
|
||||
"resolved": "https://registry.npmjs.org/esrap/-/esrap-2.1.2.tgz",
|
||||
"integrity": "sha512-DgvlIQeowRNyvLPWW4PT7Gu13WznY288Du086E751mwwbsgr29ytBiYeLzAGIo0qk3Ujob0SDk8TiSaM5WQzNg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||
}
|
||||
@@ -8899,7 +8893,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.27.6"
|
||||
},
|
||||
@@ -9222,6 +9215,22 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-docker": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
|
||||
"integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"is-docker": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
@@ -9376,6 +9385,7 @@
|
||||
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
|
||||
"integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.6"
|
||||
}
|
||||
@@ -9580,6 +9590,19 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-wsl": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
|
||||
"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-docker": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
@@ -9696,7 +9719,6 @@
|
||||
"integrity": "sha512-Pcfm3eZ+eO4JdZCXthW9tCDT3nF4K+9dmeZ+5X39n+Kqz0DDIABRP5CAEOHRFZk8RGuC2efksTJxrjp8EXCunQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@acemir/cssom": "^0.9.19",
|
||||
"@asamuzakjp/dom-selector": "^6.7.3",
|
||||
@@ -10283,7 +10305,8 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
|
||||
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
@@ -10961,6 +10984,24 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/open": {
|
||||
"version": "8.4.2",
|
||||
"resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
|
||||
"integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"define-lazy-prop": "^2.0.0",
|
||||
"is-docker": "^2.1.1",
|
||||
"is-wsl": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||
@@ -11442,7 +11483,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
@@ -11722,7 +11762,6 @@
|
||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.27.2.tgz",
|
||||
"integrity": "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/preact"
|
||||
@@ -12105,7 +12144,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
||||
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -12115,7 +12153,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
||||
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
@@ -12728,6 +12765,60 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup-plugin-visualizer": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-6.0.5.tgz",
|
||||
"integrity": "sha512-9+HlNgKCVbJDs8tVtjQ43US12eqaiHyyiLMdBwQ7vSZPiHMysGNo2E88TAp1si5wx8NAoYriI2A5kuKfIakmJg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"open": "^8.0.0",
|
||||
"picomatch": "^4.0.2",
|
||||
"source-map": "^0.7.4",
|
||||
"yargs": "^17.5.1"
|
||||
},
|
||||
"bin": {
|
||||
"rollup-plugin-visualizer": "dist/bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rolldown": "1.x || ^1.0.0-beta",
|
||||
"rollup": "2.x || 3.x || 4.x"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"rolldown": {
|
||||
"optional": true
|
||||
},
|
||||
"rollup": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/rollup-plugin-visualizer/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup-plugin-visualizer/node_modules/source-map": {
|
||||
"version": "0.7.6",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
|
||||
"integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
@@ -13627,6 +13718,7 @@
|
||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
|
||||
"integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
@@ -13835,7 +13927,6 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -14137,7 +14228,6 @@
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -14219,7 +14309,6 @@
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"napi-postinstall": "^0.3.0"
|
||||
},
|
||||
@@ -14424,7 +14513,6 @@
|
||||
"integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -14595,7 +14683,6 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -14609,7 +14696,6 @@
|
||||
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/expect": "3.2.4",
|
||||
@@ -15221,7 +15307,8 @@
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
|
||||
"integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.25.76",
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
"scripts": {
|
||||
"predev": "npm run generate-icons",
|
||||
"dev": "vite",
|
||||
"clean": "rm -rf dist",
|
||||
"prebuild": "npm run generate-icons",
|
||||
"lint": "eslint --max-warnings=0",
|
||||
"build": "vite build",
|
||||
@@ -149,6 +150,7 @@
|
||||
"postcss-preset-mantine": "^1.18.0",
|
||||
"postcss-simple-vars": "^7.0.1",
|
||||
"puppeteer": "^24.25.0",
|
||||
"rollup-plugin-visualizer": "^6.0.5",
|
||||
"typescript": "^5.9.2",
|
||||
"typescript-eslint": "^8.44.1",
|
||||
"vite": "^7.1.7",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { FileId } from '@app/types/file';
|
||||
import { PDFDocument, PDFPage, PageBreakSettings } from '@app/types/pageEditor';
|
||||
import { pdfWorkerManager } from '@app/services/pdfWorkerManager';
|
||||
import { thumbnailGenerationService } from '@app/services/thumbnailGenerationService';
|
||||
|
||||
// V1-style DOM-first command system (replaces the old React state commands)
|
||||
export abstract class DOMCommand {
|
||||
@@ -727,8 +729,6 @@ export class InsertFilesCommand extends DOMCommand {
|
||||
|
||||
private async generateThumbnailsForInsertedPages(updatedDocument: PDFDocument): Promise<void> {
|
||||
try {
|
||||
const { thumbnailGenerationService } = await import('@app/services/thumbnailGenerationService');
|
||||
|
||||
// Group pages by file ID to generate thumbnails efficiently
|
||||
const pagesByFileId = new Map<FileId, PDFPage[]>();
|
||||
|
||||
@@ -809,7 +809,6 @@ export class InsertFilesCommand extends DOMCommand {
|
||||
const clonedArrayBuffer = arrayBuffer.slice(0);
|
||||
|
||||
// Use PDF.js via the worker manager to extract pages
|
||||
const { pdfWorkerManager } = await import('@app/services/pdfWorkerManager');
|
||||
const pdf = await pdfWorkerManager.createDocument(clonedArrayBuffer);
|
||||
|
||||
const pageCount = pdf.numPages;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Dispatch, SetStateAction, useCallback } from "react";
|
||||
import JSZip from "jszip";
|
||||
|
||||
import type {
|
||||
useFileActions,
|
||||
@@ -194,8 +195,7 @@ export const usePageEditorExport = ({
|
||||
);
|
||||
|
||||
if (files.length > 1) {
|
||||
const JSZip = await import("jszip");
|
||||
const zip = new JSZip.default();
|
||||
const zip = new JSZip();
|
||||
|
||||
files.forEach((file) => {
|
||||
zip.file(file.name, file);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useMemo, useState, useEffect, useCallback } from 'react';
|
||||
import React, { useMemo, useState, useEffect, useCallback, Suspense } from 'react';
|
||||
import { Modal, Text, ActionIcon, Tooltip, Group } from '@mantine/core';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import LocalIcon from '@app/components/shared/LocalIcon';
|
||||
@@ -223,7 +223,9 @@ const AppConfigModalInner: React.FC<AppConfigModalProps> = ({ opened, onClose })
|
||||
</ActionIcon>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
{activeComponent}
|
||||
<Suspense fallback={<div style={{ padding: '2rem', textAlign: 'center' }}>Loading...</div>}>
|
||||
{activeComponent}
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useRef, forwardRef, useEffect } from "react";
|
||||
import React, { useState, useRef, forwardRef, useEffect, lazy, Suspense } from "react";
|
||||
import { Stack, Divider, Menu, Indicator } from "@mantine/core";
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
@@ -14,8 +14,10 @@ import '@app/components/shared/quickAccessBar/QuickAccessBar.css';
|
||||
import { Tooltip } from '@app/components/shared/Tooltip';
|
||||
import AllToolsNavButton from '@app/components/shared/AllToolsNavButton';
|
||||
import ActiveToolButton from "@app/components/shared/quickAccessBar/ActiveToolButton";
|
||||
import AppConfigModal from '@app/components/shared/AppConfigModal';
|
||||
import { useAppConfig } from '@app/contexts/AppConfigContext';
|
||||
|
||||
// Lazy-load AppConfigModal
|
||||
const AppConfigModal = lazy(() => import('@app/components/shared/AppConfigModal'));
|
||||
import { useLicenseAlert } from "@app/hooks/useLicenseAlert";
|
||||
import { requestStartTour } from '@app/constants/events';
|
||||
import QuickAccessButton from '@app/components/shared/quickAccessBar/QuickAccessButton';
|
||||
@@ -365,10 +367,12 @@ const QuickAccessBar = forwardRef<HTMLDivElement>((_, ref) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AppConfigModal
|
||||
opened={configModalOpen}
|
||||
onClose={() => setConfigModalOpen(false)}
|
||||
/>
|
||||
<Suspense fallback={null}>
|
||||
<AppConfigModal
|
||||
opened={configModalOpen}
|
||||
onClose={() => setConfigModalOpen(false)}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@ export default function LoginRequiredBanner({ show }: LoginRequiredBannerProps)
|
||||
|
||||
return (
|
||||
<Alert
|
||||
icon={<LocalIcon icon="lock-rounded" width={20} height={20} />}
|
||||
icon={<LocalIcon icon="lock" width={20} height={20} />}
|
||||
title={t('admin.settings.loginDisabled.title', 'Login Mode Required')}
|
||||
color="blue"
|
||||
variant="light"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import React from 'react';
|
||||
import React, { lazy } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { NavKey } from '@app/components/shared/config/types';
|
||||
import HotkeysSection from '@app/components/shared/config/configSections/HotkeysSection';
|
||||
import GeneralSection from '@app/components/shared/config/configSections/GeneralSection';
|
||||
|
||||
// Lazy load config sections
|
||||
const HotkeysSection = lazy(() => import('@app/components/shared/config/configSections/HotkeysSection'));
|
||||
const GeneralSection = lazy(() => import('@app/components/shared/config/configSections/GeneralSection'));
|
||||
|
||||
export interface ConfigNavItem {
|
||||
key: NavKey;
|
||||
|
||||
@@ -193,7 +193,7 @@ const GeneralSection: React.FC<GeneralSectionProps> = ({ hideTitle = false }) =>
|
||||
size="sm"
|
||||
color={updateSummary.max_priority === 'urgent' ? 'red' : 'blue'}
|
||||
onClick={() => setUpdateModalOpened(true)}
|
||||
leftSection={<LocalIcon icon="system-update-rounded" width="1rem" height="1rem" />}
|
||||
leftSection={<LocalIcon icon="system-update-alt-rounded" width="1rem" height="1rem" />}
|
||||
>
|
||||
{t('settings.general.updates.viewDetails', 'View Details')}
|
||||
</Button>
|
||||
|
||||
@@ -63,7 +63,7 @@ export default function ToastRenderer() {
|
||||
{/* Icon */}
|
||||
<div className="toast-icon">
|
||||
{t.icon ?? (
|
||||
<LocalIcon icon={`material-symbols:${getDefaultIconName(t)}`} width={20} height={20} />
|
||||
<LocalIcon icon={getDefaultIconName(t)} width={20} height={20} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -86,7 +86,7 @@ export default function ToastRenderer() {
|
||||
}}
|
||||
className={`toast-button toast-expand-button ${t.isExpanded ? 'toast-expand-button--expanded' : ''}`}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:expand-more-rounded" />
|
||||
<LocalIcon icon="expand-more-rounded" />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
@@ -94,7 +94,7 @@ export default function ToastRenderer() {
|
||||
onClick={() => dismiss(t.id)}
|
||||
className="toast-button"
|
||||
>
|
||||
<LocalIcon icon="material-symbols:close-rounded" width={20} height={20} />
|
||||
<LocalIcon icon="close-rounded" width={20} height={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -42,7 +42,7 @@ const AddAttachmentsSettings = ({ parameters, onParameterChange, disabled = fals
|
||||
component="label"
|
||||
htmlFor="attachments-input"
|
||||
disabled={disabled}
|
||||
leftSection={<LocalIcon icon="plus" width="14" height="14" />}
|
||||
leftSection={<LocalIcon icon="add-rounded" width="14" height="14" />}
|
||||
>
|
||||
{parameters.attachments?.length > 0
|
||||
? t("AddAttachmentsRequest.addMoreFiles", "Add more files...")
|
||||
|
||||
@@ -234,7 +234,7 @@ export const SavedSignaturesSection = ({
|
||||
{groupedSignatures.personal.length > 0 && activePersonalSignature && (
|
||||
<Stack gap="xs">
|
||||
<Group gap="xs">
|
||||
<LocalIcon icon="material-symbols:person-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="person-rounded" width={18} height={18} />
|
||||
<Text fw={600} size="sm">
|
||||
{translate('saved.personalHeading', 'Personal Signatures')}
|
||||
</Text>
|
||||
@@ -257,7 +257,7 @@ export const SavedSignaturesSection = ({
|
||||
onClick={() => setActivePersonalIndex(prev => Math.max(0, prev - 1))}
|
||||
disabled={disabled || activePersonalIndex === 0}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:chevron-left-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="chevron-left-rounded" width={18} height={18} />
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
variant="light"
|
||||
@@ -265,7 +265,7 @@ export const SavedSignaturesSection = ({
|
||||
onClick={() => setActivePersonalIndex(prev => Math.min(groupedSignatures.personal.length - 1, prev + 1))}
|
||||
disabled={disabled || activePersonalIndex >= groupedSignatures.personal.length - 1}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:chevron-right-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="chevron-right-rounded" width={18} height={18} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</Group>
|
||||
@@ -284,7 +284,7 @@ export const SavedSignaturesSection = ({
|
||||
onClick={() => onUseSignature(activePersonalSignature)}
|
||||
disabled={disabled}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:check-circle-outline-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="check-circle-outline-rounded" width={18} height={18} />
|
||||
</ActionIcon>
|
||||
<Tooltip label={translate('saved.delete', 'Remove')}>
|
||||
<ActionIcon
|
||||
@@ -294,7 +294,7 @@ export const SavedSignaturesSection = ({
|
||||
onClick={() => onDeleteSignature(activePersonalSignature)}
|
||||
disabled={disabled}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:delete-outline-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="delete-outline-rounded" width={18} height={18} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Group>
|
||||
@@ -317,7 +317,7 @@ export const SavedSignaturesSection = ({
|
||||
{groupedSignatures.shared.length > 0 && activeSharedSignature && (
|
||||
<Stack gap="xs">
|
||||
<Group gap="xs">
|
||||
<LocalIcon icon="material-symbols:groups-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="groups-rounded" width={18} height={18} />
|
||||
<Text fw={600} size="sm">
|
||||
{translate('saved.sharedHeading', 'Shared Signatures')}
|
||||
</Text>
|
||||
@@ -340,7 +340,7 @@ export const SavedSignaturesSection = ({
|
||||
onClick={() => setActiveSharedIndex(prev => Math.max(0, prev - 1))}
|
||||
disabled={disabled || activeSharedIndex === 0}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:chevron-left-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="chevron-left-rounded" width={18} height={18} />
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
variant="light"
|
||||
@@ -348,7 +348,7 @@ export const SavedSignaturesSection = ({
|
||||
onClick={() => setActiveSharedIndex(prev => Math.min(groupedSignatures.shared.length - 1, prev + 1))}
|
||||
disabled={disabled || activeSharedIndex >= groupedSignatures.shared.length - 1}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:chevron-right-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="chevron-right-rounded" width={18} height={18} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</Group>
|
||||
@@ -367,7 +367,7 @@ export const SavedSignaturesSection = ({
|
||||
onClick={() => onUseSignature(activeSharedSignature)}
|
||||
disabled={disabled}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:check-circle-outline-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="check-circle-outline-rounded" width={18} height={18} />
|
||||
</ActionIcon>
|
||||
{isAdmin && (
|
||||
<Tooltip label={translate('saved.delete', 'Remove')}>
|
||||
@@ -378,7 +378,7 @@ export const SavedSignaturesSection = ({
|
||||
onClick={() => onDeleteSignature(activeSharedSignature)}
|
||||
disabled={disabled}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:delete-outline-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="delete-outline-rounded" width={18} height={18} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
)}
|
||||
@@ -424,7 +424,7 @@ export const SavedSignaturesSection = ({
|
||||
onClick={() => setActiveLocalStorageIndex(prev => Math.max(0, prev - 1))}
|
||||
disabled={disabled || activeLocalStorageIndex === 0}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:chevron-left-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="chevron-left-rounded" width={18} height={18} />
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
variant="light"
|
||||
@@ -432,7 +432,7 @@ export const SavedSignaturesSection = ({
|
||||
onClick={() => setActiveLocalStorageIndex(prev => Math.min(groupedSignatures.localStorage.length - 1, prev + 1))}
|
||||
disabled={disabled || activeLocalStorageIndex >= groupedSignatures.localStorage.length - 1}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:chevron-right-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="chevron-right-rounded" width={18} height={18} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</Group>
|
||||
@@ -451,7 +451,7 @@ export const SavedSignaturesSection = ({
|
||||
onClick={() => onUseSignature(activeLocalStorageSignature)}
|
||||
disabled={disabled}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:check-circle-outline-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="check-circle-outline-rounded" width={18} height={18} />
|
||||
</ActionIcon>
|
||||
<Tooltip label={translate('saved.delete', 'Remove')}>
|
||||
<ActionIcon
|
||||
@@ -461,7 +461,7 @@ export const SavedSignaturesSection = ({
|
||||
onClick={() => onDeleteSignature(activeLocalStorageSignature)}
|
||||
disabled={disabled}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:delete-outline-rounded" width={18} height={18} />
|
||||
<LocalIcon icon="delete-outline-rounded" width={18} height={18} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Group>
|
||||
|
||||
@@ -370,7 +370,7 @@ const SignSettings = ({
|
||||
isReady,
|
||||
onClick,
|
||||
'personal',
|
||||
'material-symbols:person-rounded',
|
||||
'person-rounded',
|
||||
translate('saved.savePersonal', 'Save Personal')
|
||||
);
|
||||
|
||||
@@ -379,7 +379,7 @@ const SignSettings = ({
|
||||
isReady,
|
||||
onClick,
|
||||
'shared',
|
||||
'material-symbols:groups-rounded',
|
||||
'groups-rounded',
|
||||
translate('saved.saveShared', 'Save Shared')
|
||||
);
|
||||
|
||||
@@ -964,7 +964,7 @@ const SignSettings = ({
|
||||
gap: '0.4rem',
|
||||
}}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:pause-rounded" width={20} height={20} />
|
||||
<LocalIcon icon="pause-rounded" width={20} height={20} />
|
||||
<Text component="span" size="sm" fw={500}>
|
||||
{translate('mode.pause', 'Pause placement')}
|
||||
</Text>
|
||||
@@ -987,7 +987,7 @@ const SignSettings = ({
|
||||
gap: '0.4rem',
|
||||
}}
|
||||
>
|
||||
<LocalIcon icon="material-symbols:play-arrow-rounded" width={20} height={20} />
|
||||
<LocalIcon icon="play-arrow-rounded" width={20} height={20} />
|
||||
<Text component="span" size="sm" fw={500}>
|
||||
{translate('mode.resume', 'Resume placement')}
|
||||
</Text>
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
ProcessedFileMetadata,
|
||||
} from '@app/types/fileContext';
|
||||
import { FileId, ToolOperation } from '@app/types/file';
|
||||
import { generateThumbnailWithMetadata } from '@app/utils/thumbnailUtils';
|
||||
import { generateThumbnailWithMetadata, generateThumbnailForFile } from '@app/utils/thumbnailUtils';
|
||||
import { FileLifecycleManager } from '@app/contexts/file/lifecycle';
|
||||
import { buildQuickKeySet } from '@app/contexts/file/fileSelectors';
|
||||
import { StirlingFile } from '@app/types/fileContext';
|
||||
@@ -296,7 +296,6 @@ export async function addFiles(
|
||||
// Non-PDF files: simple thumbnail generation, no processedFile metadata
|
||||
try {
|
||||
if (DEBUG) console.log(`📄 Generating simple thumbnail for non-PDF file ${file.name}`);
|
||||
const { generateThumbnailForFile } = await import('@app/utils/thumbnailUtils');
|
||||
thumbnail = await generateThumbnailForFile(file);
|
||||
if (DEBUG) console.log(`📄 Generated simple thumbnail for ${file.name}: no page count, thumbnail: SUCCESS`);
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,19 +1,8 @@
|
||||
import { useMemo } from "react";
|
||||
import { useMemo, lazy } from "react";
|
||||
import LocalIcon from "@app/components/shared/LocalIcon";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { devApiLink } from "@app/constants/links";
|
||||
import SplitPdfPanel from "@app/tools/Split";
|
||||
import CompressPdfPanel from "@app/tools/Compress";
|
||||
import OCRPanel from "@app/tools/OCR";
|
||||
import ConvertPanel from "@app/tools/Convert";
|
||||
import Sanitize from "@app/tools/Sanitize";
|
||||
import AddPassword from "@app/tools/AddPassword";
|
||||
import ChangePermissions from "@app/tools/ChangePermissions";
|
||||
import RemoveBlanks from "@app/tools/RemoveBlanks";
|
||||
import RemovePages from "@app/tools/RemovePages";
|
||||
import ReorganizePages from "@app/tools/ReorganizePages";
|
||||
import { reorganizePagesOperationConfig } from "@app/hooks/tools/reorganizePages/useReorganizePagesOperation";
|
||||
import RemovePassword from "@app/tools/RemovePassword";
|
||||
import {
|
||||
SubcategoryId,
|
||||
ToolCategoryId,
|
||||
@@ -23,34 +12,9 @@ import {
|
||||
LinkToolRegistry,
|
||||
} from "@app/data/toolsTaxonomy";
|
||||
import { isSuperToolId, isLinkToolId } from '@app/types/toolId';
|
||||
import AdjustContrast from "@app/tools/AdjustContrast";
|
||||
import AdjustContrastSingleStepSettings from "@app/components/tools/adjustContrast/AdjustContrastSingleStepSettings";
|
||||
import { adjustContrastOperationConfig } from "@app/hooks/tools/adjustContrast/useAdjustContrastOperation";
|
||||
import { getSynonyms } from "@app/utils/toolSynonyms";
|
||||
import { useProprietaryToolRegistry } from "@app/data/useProprietaryToolRegistry";
|
||||
import GetPdfInfo from "@app/tools/GetPdfInfo";
|
||||
import AddWatermark from "@app/tools/AddWatermark";
|
||||
import AddStamp from "@app/tools/AddStamp";
|
||||
import AddAttachments from "@app/tools/AddAttachments";
|
||||
import Merge from '@app/tools/Merge';
|
||||
import EditTableOfContents from '@app/tools/EditTableOfContents';
|
||||
import Repair from "@app/tools/Repair";
|
||||
import AutoRename from "@app/tools/AutoRename";
|
||||
import SingleLargePage from "@app/tools/SingleLargePage";
|
||||
import PageLayout from "@app/tools/PageLayout";
|
||||
import UnlockPdfForms from "@app/tools/UnlockPdfForms";
|
||||
import RemoveCertificateSign from "@app/tools/RemoveCertificateSign";
|
||||
import RemoveImage from "@app/tools/RemoveImage";
|
||||
import CertSign from "@app/tools/CertSign";
|
||||
import BookletImposition from "@app/tools/BookletImposition";
|
||||
import Flatten from "@app/tools/Flatten";
|
||||
import Rotate from "@app/tools/Rotate";
|
||||
import PdfTextEditor from "@app/tools/pdfTextEditor/PdfTextEditor";
|
||||
import ChangeMetadata from "@app/tools/ChangeMetadata";
|
||||
import Crop from "@app/tools/Crop";
|
||||
import Sign from "@app/tools/Sign";
|
||||
import AddText from "@app/tools/AddText";
|
||||
import AddImage from "@app/tools/AddImage";
|
||||
import { compressOperationConfig } from "@app/hooks/tools/compress/useCompressOperation";
|
||||
import { splitOperationConfig } from "@app/hooks/tools/split/useSplitOperation";
|
||||
import { addPasswordOperationConfig } from "@app/hooks/tools/addPassword/useAddPasswordOperation";
|
||||
@@ -88,50 +52,7 @@ import { scannerImageSplitOperationConfig } from "@app/hooks/tools/scannerImageS
|
||||
import { addPageNumbersOperationConfig } from "@app/components/tools/addPageNumbers/useAddPageNumbersOperation";
|
||||
import { extractPagesOperationConfig } from "@app/hooks/tools/extractPages/useExtractPagesOperation";
|
||||
import { ENDPOINTS as SPLIT_ENDPOINT_NAMES } from '@app/constants/splitConstants';
|
||||
import CompressSettings from "@app/components/tools/compress/CompressSettings";
|
||||
import AddPasswordSettings from "@app/components/tools/addPassword/AddPasswordSettings";
|
||||
import RemovePasswordSettings from "@app/components/tools/removePassword/RemovePasswordSettings";
|
||||
import SanitizeSettings from "@app/components/tools/sanitize/SanitizeSettings";
|
||||
import AddWatermarkSingleStepSettings from "@app/components/tools/addWatermark/AddWatermarkSingleStepSettings";
|
||||
import OCRSettings from "@app/components/tools/ocr/OCRSettings";
|
||||
import ConvertSettings from "@app/components/tools/convert/ConvertSettings";
|
||||
import ChangePermissionsSettings from "@app/components/tools/changePermissions/ChangePermissionsSettings";
|
||||
import BookletImpositionSettings from "@app/components/tools/bookletImposition/BookletImpositionSettings";
|
||||
import FlattenSettings from "@app/components/tools/flatten/FlattenSettings";
|
||||
import RedactSingleStepSettings from "@app/components/tools/redact/RedactSingleStepSettings";
|
||||
import Redact from "@app/tools/Redact";
|
||||
import AdjustPageScale from "@app/tools/AdjustPageScale";
|
||||
import ReplaceColor from "@app/tools/ReplaceColor";
|
||||
import ScannerImageSplit from "@app/tools/ScannerImageSplit";
|
||||
import OverlayPdfs from "@app/tools/OverlayPdfs";
|
||||
import { ToolId } from "@app/types/toolId";
|
||||
import MergeSettings from '@app/components/tools/merge/MergeSettings';
|
||||
import AdjustPageScaleSettings from "@app/components/tools/adjustPageScale/AdjustPageScaleSettings";
|
||||
import ScannerImageSplitSettings from "@app/components/tools/scannerImageSplit/ScannerImageSplitSettings";
|
||||
import ChangeMetadataSingleStep from "@app/components/tools/changeMetadata/ChangeMetadataSingleStep";
|
||||
import SignSettings from "@app/components/tools/sign/SignSettings";
|
||||
import AddPageNumbers from "@app/tools/AddPageNumbers";
|
||||
import RemoveAnnotations from "@app/tools/RemoveAnnotations";
|
||||
import PageLayoutSettings from "@app/components/tools/pageLayout/PageLayoutSettings";
|
||||
import ExtractImages from "@app/tools/ExtractImages";
|
||||
import ExtractPages from "@app/tools/ExtractPages";
|
||||
import ExtractImagesSettings from "@app/components/tools/extractImages/ExtractImagesSettings";
|
||||
import ExtractPagesSettings from "@app/components/tools/extractPages/ExtractPagesSettings";
|
||||
import ReplaceColorSettings from "@app/components/tools/replaceColor/ReplaceColorSettings";
|
||||
import AddStampAutomationSettings from "@app/components/tools/addStamp/AddStampAutomationSettings";
|
||||
import CertSignAutomationSettings from "@app/components/tools/certSign/CertSignAutomationSettings";
|
||||
import CropAutomationSettings from "@app/components/tools/crop/CropAutomationSettings";
|
||||
import RotateAutomationSettings from "@app/components/tools/rotate/RotateAutomationSettings";
|
||||
import SplitAutomationSettings from "@app/components/tools/split/SplitAutomationSettings";
|
||||
import AddAttachmentsSettings from "@app/components/tools/addAttachments/AddAttachmentsSettings";
|
||||
import RemovePagesSettings from "@app/components/tools/removePages/RemovePagesSettings";
|
||||
import RemoveBlanksSettings from "@app/components/tools/removeBlanks/RemoveBlanksSettings";
|
||||
import AddPageNumbersAutomationSettings from "@app/components/tools/addPageNumbers/AddPageNumbersAutomationSettings";
|
||||
import OverlayPdfsSettings from "@app/components/tools/overlayPdfs/OverlayPdfsSettings";
|
||||
import ValidateSignature from "@app/tools/ValidateSignature";
|
||||
import ShowJS from "@app/tools/ShowJS";
|
||||
import Automate from "@app/tools/Automate";
|
||||
import Compare from "@app/tools/Compare";
|
||||
import { CONVERT_SUPPORTED_FORMATS } from "@app/constants/convertSupportedFornats";
|
||||
|
||||
|
||||
@@ -156,7 +77,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
pdfTextEditor: {
|
||||
icon: <LocalIcon icon="edit-square-outline-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.pdfTextEditor.title", "PDF Text Editor"),
|
||||
component: PdfTextEditor,
|
||||
component: lazy(() => import("@app/tools/pdfTextEditor/PdfTextEditor")),
|
||||
description: t(
|
||||
"home.pdfTextEditor.desc",
|
||||
"Review and edit text and images in PDFs with grouped text editing and PDF regeneration"
|
||||
@@ -186,21 +107,21 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
merge: {
|
||||
icon: <LocalIcon icon="library-add-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.merge.title", "Merge"),
|
||||
component: Merge,
|
||||
component: lazy(() => import("@app/tools/Merge")),
|
||||
description: t("home.merge.desc", "Merge multiple PDFs into a single document"),
|
||||
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||
subcategoryId: SubcategoryId.GENERAL,
|
||||
maxFiles: -1,
|
||||
endpoints: ["merge-pdfs"],
|
||||
operationConfig: mergeOperationConfig,
|
||||
automationSettings: MergeSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/merge/MergeSettings")),
|
||||
synonyms: getSynonyms(t, "merge")
|
||||
},
|
||||
// Signing
|
||||
certSign: {
|
||||
icon: <LocalIcon icon="workspace-premium-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.certSign.title", "Certificate Sign"),
|
||||
component: CertSign,
|
||||
component: lazy(() => import("@app/tools/CertSign")),
|
||||
description: t("home.certSign.desc", "Sign PDF documents using digital certificates"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.SIGNING,
|
||||
@@ -208,24 +129,24 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
maxFiles: -1,
|
||||
endpoints: ["cert-sign"],
|
||||
operationConfig: certSignOperationConfig,
|
||||
automationSettings: CertSignAutomationSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/certSign/CertSignAutomationSettings")),
|
||||
},
|
||||
sign: {
|
||||
icon: <LocalIcon icon="signature-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.sign.title", "Sign"),
|
||||
component: Sign,
|
||||
component: lazy(() => import("@app/tools/Sign")),
|
||||
description: t("home.sign.desc", "Adds signature to PDF by drawing, text or image"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.SIGNING,
|
||||
operationConfig: signOperationConfig,
|
||||
automationSettings: SignSettings, // TODO:: not all settings shown, suggested next tools shown
|
||||
automationSettings: lazy(() => import("@app/components/tools/sign/SignSettings")), // TODO:: not all settings shown, suggested next tools shown
|
||||
synonyms: getSynonyms(t, "sign"),
|
||||
supportsAutomate: false, //TODO make support Sign
|
||||
},
|
||||
addText: {
|
||||
icon: <LocalIcon icon="material-symbols:text-fields-rounded" width="1.5rem" height="1.5rem" />,
|
||||
icon: <LocalIcon icon="text-fields-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t('home.addText.title', 'Add Text'),
|
||||
component: AddText,
|
||||
component: lazy(() => import("@app/tools/AddText")),
|
||||
description: t('home.addText.desc', 'Add custom text anywhere in your PDF'),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.GENERAL,
|
||||
@@ -237,7 +158,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
addImage: {
|
||||
icon: <LocalIcon icon="image-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t('home.addImage.title', 'Add Image'),
|
||||
component: AddImage,
|
||||
component: lazy(() => import("@app/tools/AddImage")),
|
||||
description: t('home.addImage.desc', 'Add images anywhere in your PDF'),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.GENERAL,
|
||||
@@ -252,33 +173,33 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
addPassword: {
|
||||
icon: <LocalIcon icon="password-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.addPassword.title", "Add Password"),
|
||||
component: AddPassword,
|
||||
component: lazy(() => import("@app/tools/AddPassword")),
|
||||
description: t("home.addPassword.desc", "Add password protection and restrictions to PDF files"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||
maxFiles: -1,
|
||||
endpoints: ["add-password"],
|
||||
operationConfig: addPasswordOperationConfig,
|
||||
automationSettings: AddPasswordSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/addPassword/AddPasswordSettings")),
|
||||
synonyms: getSynonyms(t, "addPassword")
|
||||
},
|
||||
watermark: {
|
||||
icon: <LocalIcon icon="branding-watermark-outline-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.watermark.title", "Add Watermark"),
|
||||
component: AddWatermark,
|
||||
component: lazy(() => import("@app/tools/AddWatermark")),
|
||||
maxFiles: -1,
|
||||
description: t("home.watermark.desc", "Add a custom watermark to your PDF document."),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||
endpoints: ["add-watermark"],
|
||||
operationConfig: addWatermarkOperationConfig,
|
||||
automationSettings: AddWatermarkSingleStepSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/addWatermark/AddWatermarkSingleStepSettings")),
|
||||
synonyms: getSynonyms(t, "watermark")
|
||||
},
|
||||
addStamp: {
|
||||
icon: <LocalIcon icon="approval-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.addStamp.title", "Add Stamp to PDF"),
|
||||
component: AddStamp,
|
||||
component: lazy(() => import("@app/tools/AddStamp")),
|
||||
description: t("home.addStamp.desc", "Add text or add image stamps at set locations"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||
@@ -286,38 +207,38 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
maxFiles: -1,
|
||||
endpoints: ["add-stamp"],
|
||||
operationConfig: addStampOperationConfig,
|
||||
automationSettings: AddStampAutomationSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/addStamp/AddStampAutomationSettings")),
|
||||
},
|
||||
sanitize: {
|
||||
icon: <LocalIcon icon="cleaning-services-outline-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.sanitize.title", "Sanitize"),
|
||||
component: Sanitize,
|
||||
component: lazy(() => import("@app/tools/Sanitize")),
|
||||
maxFiles: -1,
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||
description: t("home.sanitize.desc", "Remove potentially harmful elements from PDF files"),
|
||||
endpoints: ["sanitize-pdf"],
|
||||
operationConfig: sanitizeOperationConfig,
|
||||
automationSettings: SanitizeSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/sanitize/SanitizeSettings")),
|
||||
synonyms: getSynonyms(t, "sanitize")
|
||||
},
|
||||
flatten: {
|
||||
icon: <LocalIcon icon="layers-clear-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.flatten.title", "Flatten"),
|
||||
component: Flatten,
|
||||
component: lazy(() => import("@app/tools/Flatten")),
|
||||
description: t("home.flatten.desc", "Remove all interactive elements and forms from a PDF"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||
maxFiles: -1,
|
||||
endpoints: ["flatten"],
|
||||
operationConfig: flattenOperationConfig,
|
||||
automationSettings: FlattenSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/flatten/FlattenSettings")),
|
||||
synonyms: getSynonyms(t, "flatten")
|
||||
},
|
||||
unlockPDFForms: {
|
||||
icon: <LocalIcon icon="preview-off-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.unlockPDFForms.title", "Unlock PDF Forms"),
|
||||
component: UnlockPdfForms,
|
||||
component: lazy(() => import("@app/tools/UnlockPdfForms")),
|
||||
description: t("home.unlockPDFForms.desc", "Remove read-only property of form fields in a PDF document."),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||
@@ -330,20 +251,20 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
changePermissions: {
|
||||
icon: <LocalIcon icon="lock-outline" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.changePermissions.title", "Change Permissions"),
|
||||
component: ChangePermissions,
|
||||
component: lazy(() => import("@app/tools/ChangePermissions")),
|
||||
description: t("home.changePermissions.desc", "Change document restrictions and permissions"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||
maxFiles: -1,
|
||||
endpoints: ["add-password"],
|
||||
operationConfig: changePermissionsOperationConfig,
|
||||
automationSettings: ChangePermissionsSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/changePermissions/ChangePermissionsSettings")),
|
||||
synonyms: getSynonyms(t, "changePermissions"),
|
||||
},
|
||||
getPdfInfo: {
|
||||
icon: <LocalIcon icon="fact-check-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.getPdfInfo.title", "Get ALL Info on PDF"),
|
||||
component: GetPdfInfo,
|
||||
component: lazy(() => import("@app/tools/GetPdfInfo")),
|
||||
description: t("home.getPdfInfo.desc", "Grabs any and all information possible on PDFs"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.VERIFICATION,
|
||||
@@ -356,7 +277,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
validateSignature: {
|
||||
icon: <LocalIcon icon="verified-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.validateSignature.title", "Validate PDF Signature"),
|
||||
component: ValidateSignature,
|
||||
component: lazy(() => import("@app/tools/ValidateSignature")),
|
||||
description: t("home.validateSignature.desc", "Verify digital signatures and certificates in PDF documents"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.VERIFICATION,
|
||||
@@ -386,20 +307,20 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
changeMetadata: {
|
||||
icon: <LocalIcon icon="assignment-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.changeMetadata.title", "Change Metadata"),
|
||||
component: ChangeMetadata,
|
||||
component: lazy(() => import("@app/tools/ChangeMetadata")),
|
||||
description: t("home.changeMetadata.desc", "Change/Remove/Add metadata from a PDF document"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.DOCUMENT_REVIEW,
|
||||
maxFiles: -1,
|
||||
endpoints: ["update-metadata"],
|
||||
operationConfig: changeMetadataOperationConfig,
|
||||
automationSettings: ChangeMetadataSingleStep,
|
||||
automationSettings: lazy(() => import("@app/components/tools/changeMetadata/ChangeMetadataSingleStep")),
|
||||
synonyms: getSynonyms(t, "changeMetadata")
|
||||
},
|
||||
editTableOfContents: {
|
||||
icon: <LocalIcon icon="toc-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.editTableOfContents.title", "Edit Table of Contents"),
|
||||
component: EditTableOfContents,
|
||||
component: lazy(() => import("@app/tools/EditTableOfContents")),
|
||||
description: t(
|
||||
"home.editTableOfContents.desc",
|
||||
"Add or edit bookmarks and table of contents in PDF documents"
|
||||
@@ -418,44 +339,44 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
crop: {
|
||||
icon: <LocalIcon icon="crop-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.crop.title", "Crop PDF"),
|
||||
component: Crop,
|
||||
component: lazy(() => import("@app/tools/Crop")),
|
||||
description: t("home.crop.desc", "Crop a PDF to reduce its size (maintains text!)"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.PAGE_FORMATTING,
|
||||
maxFiles: -1,
|
||||
endpoints: ["crop"],
|
||||
operationConfig: cropOperationConfig,
|
||||
automationSettings: CropAutomationSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/crop/CropAutomationSettings")),
|
||||
},
|
||||
rotate: {
|
||||
icon: <LocalIcon icon="rotate-right-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.rotate.title", "Rotate"),
|
||||
component: Rotate,
|
||||
component: lazy(() => import("@app/tools/Rotate")),
|
||||
description: t("home.rotate.desc", "Easily rotate your PDFs."),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.PAGE_FORMATTING,
|
||||
maxFiles: -1,
|
||||
endpoints: ["rotate-pdf"],
|
||||
operationConfig: rotateOperationConfig,
|
||||
automationSettings: RotateAutomationSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/rotate/RotateAutomationSettings")),
|
||||
synonyms: getSynonyms(t, "rotate")
|
||||
},
|
||||
split: {
|
||||
icon: <LocalIcon icon="content-cut-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.split.title", "Split"),
|
||||
component: SplitPdfPanel,
|
||||
component: lazy(() => import("@app/tools/Split")),
|
||||
description: t("home.split.desc", "Split PDFs into multiple documents"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.PAGE_FORMATTING,
|
||||
endpoints: Array.from(new Set(Object.values(SPLIT_ENDPOINT_NAMES))),
|
||||
operationConfig: splitOperationConfig,
|
||||
automationSettings: SplitAutomationSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/split/SplitAutomationSettings")),
|
||||
synonyms: getSynonyms(t, "split")
|
||||
},
|
||||
reorganizePages: {
|
||||
icon: <LocalIcon icon="move-down-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.reorganizePages.title", "Reorganize Pages"),
|
||||
component: ReorganizePages,
|
||||
component: lazy(() => import("@app/tools/ReorganizePages")),
|
||||
description: t(
|
||||
"home.reorganizePages.desc",
|
||||
"Rearrange, duplicate, or delete PDF pages with visual drag-and-drop control."
|
||||
@@ -471,24 +392,24 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
scalePages: {
|
||||
icon: <LocalIcon icon="crop-free-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.scalePages.title", "Adjust page size/scale"),
|
||||
component: AdjustPageScale,
|
||||
component: lazy(() => import("@app/tools/AdjustPageScale")),
|
||||
description: t("home.scalePages.desc", "Change the size/scale of a page and/or its contents."),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.PAGE_FORMATTING,
|
||||
maxFiles: -1,
|
||||
endpoints: ["scale-pages"],
|
||||
operationConfig: adjustPageScaleOperationConfig,
|
||||
automationSettings: AdjustPageScaleSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/adjustPageScale/AdjustPageScaleSettings")),
|
||||
synonyms: getSynonyms(t, "scalePages")
|
||||
},
|
||||
addPageNumbers: {
|
||||
icon: <LocalIcon icon="123-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.addPageNumbers.title", "Add Page Numbers"),
|
||||
component: AddPageNumbers,
|
||||
component: lazy(() => import("@app/tools/AddPageNumbers")),
|
||||
description: t("home.addPageNumbers.desc", "Add Page numbers throughout a document in a set location"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.PAGE_FORMATTING,
|
||||
automationSettings: AddPageNumbersAutomationSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/addPageNumbers/AddPageNumbersAutomationSettings")),
|
||||
maxFiles: -1,
|
||||
endpoints: ["add-page-numbers"],
|
||||
operationConfig: addPageNumbersOperationConfig,
|
||||
@@ -497,21 +418,21 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
pageLayout: {
|
||||
icon: <LocalIcon icon="dashboard-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.pageLayout.title", "Multi-Page Layout"),
|
||||
component: PageLayout,
|
||||
component: lazy(() => import("@app/tools/PageLayout")),
|
||||
description: t("home.pageLayout.desc", "Merge multiple pages of a PDF document into a single page"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.PAGE_FORMATTING,
|
||||
maxFiles: -1,
|
||||
endpoints: ["multi-page-layout"],
|
||||
automationSettings: PageLayoutSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/pageLayout/PageLayoutSettings")),
|
||||
synonyms: getSynonyms(t, "pageLayout")
|
||||
},
|
||||
bookletImposition: {
|
||||
icon: <LocalIcon icon="menu-book-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.bookletImposition.title", "Booklet Imposition"),
|
||||
component: BookletImposition,
|
||||
component: lazy(() => import("@app/tools/BookletImposition")),
|
||||
operationConfig: bookletImpositionOperationConfig,
|
||||
automationSettings: BookletImpositionSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/bookletImposition/BookletImpositionSettings")),
|
||||
description: t("home.bookletImposition.desc", "Create booklets with proper page ordering and multi-page layout for printing and binding"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.PAGE_FORMATTING,
|
||||
@@ -521,7 +442,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
|
||||
icon: <LocalIcon icon="looks-one-outline-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.pdfToSinglePage.title", "PDF to Single Large Page"),
|
||||
component: SingleLargePage,
|
||||
component: lazy(() => import("@app/tools/SingleLargePage")),
|
||||
|
||||
description: t("home.pdfToSinglePage.desc", "Merges all PDF pages into one large single page"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
@@ -535,7 +456,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
addAttachments: {
|
||||
icon: <LocalIcon icon="attachment-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.addAttachments.title", "Add Attachments"),
|
||||
component: AddAttachments,
|
||||
component: lazy(() => import("@app/tools/AddAttachments")),
|
||||
description: t("home.addAttachments.desc", "Add or remove embedded files (attachments) to/from a PDF"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.PAGE_FORMATTING,
|
||||
@@ -543,7 +464,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
maxFiles: 1,
|
||||
endpoints: ["add-attachments"],
|
||||
operationConfig: addAttachmentsOperationConfig,
|
||||
automationSettings: AddAttachmentsSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/addAttachments/AddAttachmentsSettings")),
|
||||
},
|
||||
|
||||
// Extraction
|
||||
@@ -551,26 +472,26 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
extractPages: {
|
||||
icon: <LocalIcon icon="upload-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.extractPages.title", "Extract Pages"),
|
||||
component: ExtractPages,
|
||||
component: lazy(() => import("@app/tools/ExtractPages")),
|
||||
description: t("home.extractPages.desc", "Extract specific pages from a PDF document"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.EXTRACTION,
|
||||
synonyms: getSynonyms(t, "extractPages"),
|
||||
automationSettings: ExtractPagesSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/extractPages/ExtractPagesSettings")),
|
||||
operationConfig: extractPagesOperationConfig,
|
||||
endpoints: ["rearrange-pages"],
|
||||
},
|
||||
extractImages: {
|
||||
icon: <LocalIcon icon="photo-library-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.extractImages.title", "Extract Images"),
|
||||
component: ExtractImages,
|
||||
component: lazy(() => import("@app/tools/ExtractImages")),
|
||||
description: t("home.extractImages.desc", "Extract images from PDF documents"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.EXTRACTION,
|
||||
maxFiles: -1,
|
||||
endpoints: ["extract-images"],
|
||||
operationConfig: extractImagesOperationConfig,
|
||||
automationSettings: ExtractImagesSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/extractImages/ExtractImagesSettings")),
|
||||
synonyms: getSynonyms(t, "extractImages")
|
||||
},
|
||||
|
||||
@@ -579,7 +500,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
removePages: {
|
||||
icon: <LocalIcon icon="delete-outline-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.removePages.title", "Remove Pages"),
|
||||
component: RemovePages,
|
||||
component: lazy(() => import("@app/tools/RemovePages")),
|
||||
description: t("home.removePages.desc", "Remove specific pages from a PDF document"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.REMOVAL,
|
||||
@@ -587,12 +508,12 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
endpoints: ["remove-pages"],
|
||||
synonyms: getSynonyms(t, "removePages"),
|
||||
operationConfig: removePagesOperationConfig,
|
||||
automationSettings: RemovePagesSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/removePages/RemovePagesSettings")),
|
||||
},
|
||||
removeBlanks: {
|
||||
icon: <LocalIcon icon="scan-delete-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.removeBlanks.title", "Remove Blank Pages"),
|
||||
component: RemoveBlanks,
|
||||
component: lazy(() => import("@app/tools/RemoveBlanks")),
|
||||
description: t("home.removeBlanks.desc", "Remove blank pages from PDF documents"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.REMOVAL,
|
||||
@@ -600,12 +521,12 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
endpoints: ["remove-blanks"],
|
||||
synonyms: getSynonyms(t, "removeBlanks"),
|
||||
operationConfig: removeBlanksOperationConfig,
|
||||
automationSettings: RemoveBlanksSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/removeBlanks/RemoveBlanksSettings")),
|
||||
},
|
||||
removeAnnotations: {
|
||||
icon: <LocalIcon icon="thread-unread-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.removeAnnotations.title", "Remove Annotations"),
|
||||
component: RemoveAnnotations,
|
||||
component: lazy(() => import("@app/tools/RemoveAnnotations")),
|
||||
description: t("home.removeAnnotations.desc", "Remove annotations and comments from PDF documents"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.REMOVAL,
|
||||
@@ -618,7 +539,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
removeImage: {
|
||||
icon: <LocalIcon icon="remove-selection-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.removeImage.title", "Remove Images"),
|
||||
component: RemoveImage,
|
||||
component: lazy(() => import("@app/tools/RemoveImage")),
|
||||
description: t("home.removeImage.desc", "Remove all images from a PDF document"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.REMOVAL,
|
||||
@@ -631,20 +552,20 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
removePassword: {
|
||||
icon: <LocalIcon icon="lock-open-right-outline-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.removePassword.title", "Remove Password"),
|
||||
component: RemovePassword,
|
||||
component: lazy(() => import("@app/tools/RemovePassword")),
|
||||
description: t("home.removePassword.desc", "Remove password protection from PDF documents"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.REMOVAL,
|
||||
endpoints: ["remove-password"],
|
||||
maxFiles: -1,
|
||||
operationConfig: removePasswordOperationConfig,
|
||||
automationSettings: RemovePasswordSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/removePassword/RemovePasswordSettings")),
|
||||
synonyms: getSynonyms(t, "removePassword")
|
||||
},
|
||||
removeCertSign: {
|
||||
icon: <LocalIcon icon="remove-moderator-outline-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.removeCertSign.title", "Remove Certificate Sign"),
|
||||
component: RemoveCertificateSign,
|
||||
component: lazy(() => import("@app/tools/RemoveCertificateSign")),
|
||||
description: t("home.removeCertSign.desc", "Remove digital signature from PDF documents"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.REMOVAL,
|
||||
@@ -660,7 +581,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
automate: {
|
||||
icon: <LocalIcon icon="automation-outline" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.automate.title", "Automate"),
|
||||
component: Automate,
|
||||
component: lazy(() => import("@app/tools/Automate")),
|
||||
description: t(
|
||||
"home.automate.desc",
|
||||
"Build multi-step workflows by chaining together PDF actions. Ideal for recurring tasks."
|
||||
@@ -676,7 +597,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
autoRename: {
|
||||
icon: <LocalIcon icon="match-word-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.autoRename.title", "Auto Rename PDF File"),
|
||||
component: AutoRename,
|
||||
component: lazy(() => import("@app/tools/AutoRename")),
|
||||
maxFiles: -1,
|
||||
endpoints: ["auto-rename"],
|
||||
operationConfig: autoRenameOperationConfig,
|
||||
@@ -692,18 +613,18 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
adjustContrast: {
|
||||
icon: <LocalIcon icon="palette" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.adjustContrast.title", "Adjust Colors/Contrast"),
|
||||
component: AdjustContrast,
|
||||
component: lazy(() => import("@app/tools/AdjustContrast")),
|
||||
description: t("home.adjustContrast.desc", "Adjust colors and contrast of PDF documents"),
|
||||
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||
subcategoryId: SubcategoryId.ADVANCED_FORMATTING,
|
||||
operationConfig: adjustContrastOperationConfig,
|
||||
automationSettings: AdjustContrastSingleStepSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/adjustContrast/AdjustContrastSingleStepSettings")),
|
||||
synonyms: getSynonyms(t, "adjustContrast"),
|
||||
},
|
||||
repair: {
|
||||
icon: <LocalIcon icon="build-outline-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.repair.title", "Repair"),
|
||||
component: Repair,
|
||||
component: lazy(() => import("@app/tools/Repair")),
|
||||
description: t("home.repair.desc", "Repair corrupted or damaged PDF files"),
|
||||
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||
subcategoryId: SubcategoryId.ADVANCED_FORMATTING,
|
||||
@@ -716,39 +637,39 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
scannerImageSplit: {
|
||||
icon: <LocalIcon icon="scanner-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.scannerImageSplit.title", "Detect & Split Scanned Photos"),
|
||||
component: ScannerImageSplit,
|
||||
component: lazy(() => import("@app/tools/ScannerImageSplit")),
|
||||
description: t("home.scannerImageSplit.desc", "Detect and split scanned photos into separate pages"),
|
||||
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||
subcategoryId: SubcategoryId.ADVANCED_FORMATTING,
|
||||
maxFiles: -1,
|
||||
endpoints: ["extract-image-scans"],
|
||||
operationConfig: scannerImageSplitOperationConfig,
|
||||
automationSettings: ScannerImageSplitSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/scannerImageSplit/ScannerImageSplitSettings")),
|
||||
synonyms: getSynonyms(t, "ScannerImageSplit"),
|
||||
},
|
||||
overlayPdfs: {
|
||||
icon: <LocalIcon icon="layers-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.overlay-pdfs.title", "Overlay PDFs"),
|
||||
component: OverlayPdfs,
|
||||
component: lazy(() => import("@app/tools/OverlayPdfs")),
|
||||
description: t("home.overlay-pdfs.desc", "Overlay one PDF on top of another"),
|
||||
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||
subcategoryId: SubcategoryId.ADVANCED_FORMATTING,
|
||||
endpoints: ["overlay-pdf"],
|
||||
operationConfig: overlayPdfsOperationConfig,
|
||||
synonyms: getSynonyms(t, "overlay-pdfs"),
|
||||
automationSettings: OverlayPdfsSettings
|
||||
automationSettings: lazy(() => import("@app/components/tools/overlayPdfs/OverlayPdfsSettings"))
|
||||
},
|
||||
replaceColor: {
|
||||
icon: <LocalIcon icon="format-color-fill-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.replaceColor.title", "Replace & Invert Color"),
|
||||
component: ReplaceColor,
|
||||
component: lazy(() => import("@app/tools/ReplaceColor")),
|
||||
description: t("home.replaceColor.desc", "Replace or invert colors in PDF documents"),
|
||||
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||
subcategoryId: SubcategoryId.ADVANCED_FORMATTING,
|
||||
maxFiles: -1,
|
||||
endpoints: ["replace-invert-pdf"],
|
||||
operationConfig: replaceColorOperationConfig,
|
||||
automationSettings: ReplaceColorSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/replaceColor/ReplaceColorSettings")),
|
||||
synonyms: getSynonyms(t, "replaceColor"),
|
||||
},
|
||||
scannerEffect: {
|
||||
@@ -768,7 +689,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
showJS: {
|
||||
icon: <LocalIcon icon="javascript-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.showJS.title", "Show JavaScript"),
|
||||
component: ShowJS,
|
||||
component: lazy(() => import("@app/tools/ShowJS")),
|
||||
description: t("home.showJS.desc", "Extract and display JavaScript code from PDF documents"),
|
||||
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||
subcategoryId: SubcategoryId.DEVELOPER_TOOLS,
|
||||
@@ -831,7 +752,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
compare: {
|
||||
icon: <LocalIcon icon="compare-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.compare.title", "Compare"),
|
||||
component: Compare,
|
||||
component: lazy(() => import("@app/tools/Compare")),
|
||||
description: t("home.compare.desc", "Compare two PDF documents and highlight differences"),
|
||||
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||
subcategoryId: SubcategoryId.GENERAL,
|
||||
@@ -844,20 +765,20 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
compress: {
|
||||
icon: <LocalIcon icon="zoom-in-map-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.compress.title", "Compress"),
|
||||
component: CompressPdfPanel,
|
||||
component: lazy(() => import("@app/tools/Compress")),
|
||||
description: t("home.compress.desc", "Compress PDFs to reduce their file size."),
|
||||
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||
subcategoryId: SubcategoryId.GENERAL,
|
||||
maxFiles: -1,
|
||||
endpoints: ["compress-pdf"],
|
||||
operationConfig: compressOperationConfig,
|
||||
automationSettings: CompressSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/compress/CompressSettings")),
|
||||
synonyms: getSynonyms(t, "compress")
|
||||
},
|
||||
convert: {
|
||||
icon: <LocalIcon icon="sync-alt-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.convert.title", "Convert"),
|
||||
component: ConvertPanel,
|
||||
component: lazy(() => import("@app/tools/Convert")),
|
||||
description: t("home.convert.desc", "Convert files to and from PDF format"),
|
||||
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||
subcategoryId: SubcategoryId.GENERAL,
|
||||
@@ -881,34 +802,34 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog {
|
||||
],
|
||||
|
||||
operationConfig: convertOperationConfig,
|
||||
automationSettings: ConvertSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/convert/ConvertSettings")),
|
||||
synonyms: getSynonyms(t, "convert")
|
||||
},
|
||||
|
||||
ocr: {
|
||||
icon: <LocalIcon icon="quick-reference-all-outline-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.ocr.title", "OCR"),
|
||||
component: OCRPanel,
|
||||
component: lazy(() => import("@app/tools/OCR")),
|
||||
description: t("home.ocr.desc", "Extract text from scanned PDFs using Optical Character Recognition"),
|
||||
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||
subcategoryId: SubcategoryId.GENERAL,
|
||||
maxFiles: -1,
|
||||
endpoints: ["ocr-pdf"],
|
||||
operationConfig: ocrOperationConfig,
|
||||
automationSettings: OCRSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/ocr/OCRSettings")),
|
||||
synonyms: getSynonyms(t, "ocr")
|
||||
},
|
||||
redact: {
|
||||
icon: <LocalIcon icon="visibility-off-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.redact.title", "Redact"),
|
||||
component: Redact,
|
||||
component: lazy(() => import("@app/tools/Redact")),
|
||||
description: t("home.redact.desc", "Permanently remove sensitive information from PDF documents"),
|
||||
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||
subcategoryId: SubcategoryId.GENERAL,
|
||||
maxFiles: -1,
|
||||
endpoints: ["auto-redact"],
|
||||
operationConfig: redactOperationConfig,
|
||||
automationSettings: RedactSingleStepSettings,
|
||||
automationSettings: lazy(() => import("@app/components/tools/redact/RedactSingleStepSettings")),
|
||||
synonyms: getSynonyms(t, "redact")
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import JSZip from 'jszip';
|
||||
import { OCRParameters, defaultParameters } from '@app/hooks/tools/ocr/useOCRParameters';
|
||||
import { useToolOperation, ToolOperationConfig, ToolType } from '@app/hooks/tools/shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '@app/utils/toolErrorHandler';
|
||||
@@ -18,8 +19,7 @@ function getMimeType(filename: string): string {
|
||||
|
||||
// Lightweight ZIP extractor (keep or replace with a shared util if you have one)
|
||||
async function extractZipFile(zipBlob: Blob): Promise<File[]> {
|
||||
const JSZip = await import('jszip');
|
||||
const zip = new JSZip.default();
|
||||
const zip = new JSZip();
|
||||
const zipContent = await zip.loadAsync(await zipBlob.arrayBuffer());
|
||||
const out: File[] = [];
|
||||
for (const [filename, file] of Object.entries(zipContent.files)) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useRef, useState, lazy, Suspense } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useToolWorkflow } from "@app/contexts/ToolWorkflowContext";
|
||||
import { Group, useMantineColorScheme } from "@mantine/core";
|
||||
@@ -15,13 +15,16 @@ import { useViewer } from "@app/contexts/ViewerContext";
|
||||
import AppsIcon from '@mui/icons-material/AppsRounded';
|
||||
|
||||
import ToolPanel from "@app/components/tools/ToolPanel";
|
||||
import Workbench from "@app/components/layout/Workbench";
|
||||
import QuickAccessBar from "@app/components/shared/QuickAccessBar";
|
||||
import RightRail from "@app/components/shared/RightRail";
|
||||
import FileManager from "@app/components/FileManager";
|
||||
import LocalIcon from "@app/components/shared/LocalIcon";
|
||||
|
||||
// Lazy-load heavy components that aren't needed on initial render
|
||||
const Workbench = lazy(() => import("@app/components/layout/Workbench"));
|
||||
const FileManager = lazy(() => import("@app/components/FileManager"));
|
||||
const AppConfigModal = lazy(() => import("@app/components/shared/AppConfigModal"));
|
||||
|
||||
import { useFilesModalContext } from "@app/contexts/FilesModalContext";
|
||||
import AppConfigModal from "@app/components/shared/AppConfigModal";
|
||||
|
||||
import "@app/pages/HomePage.css";
|
||||
|
||||
@@ -218,7 +221,9 @@ export default function HomePage() {
|
||||
<div className="mobile-slide" aria-label={t('home.mobile.workbenchSlide', 'Workspace panel')}>
|
||||
<div className="mobile-slide-content">
|
||||
<div className="flex-1 min-h-0 flex">
|
||||
<Workbench />
|
||||
<Suspense fallback={<div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>Loading...</div>}>
|
||||
<Workbench />
|
||||
</Suspense>
|
||||
<RightRail />
|
||||
</div>
|
||||
</div>
|
||||
@@ -268,11 +273,15 @@ export default function HomePage() {
|
||||
<span className="mobile-bottom-button-label">{t('quickAccess.config', 'Config')}</span>
|
||||
</button>
|
||||
</div>
|
||||
<FileManager selectedTool={selectedTool as any /* FIX ME */} />
|
||||
<AppConfigModal
|
||||
opened={configModalOpen}
|
||||
onClose={() => setConfigModalOpen(false)}
|
||||
/>
|
||||
<Suspense fallback={null}>
|
||||
<FileManager selectedTool={selectedTool as any /* FIX ME */} />
|
||||
</Suspense>
|
||||
<Suspense fallback={null}>
|
||||
<AppConfigModal
|
||||
opened={configModalOpen}
|
||||
onClose={() => setConfigModalOpen(false)}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
) : (
|
||||
<Group
|
||||
@@ -283,9 +292,13 @@ export default function HomePage() {
|
||||
>
|
||||
<QuickAccessBar ref={quickAccessRef} />
|
||||
<ToolPanel />
|
||||
<Workbench />
|
||||
<Suspense fallback={<div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>Loading...</div>}>
|
||||
<Workbench />
|
||||
</Suspense>
|
||||
<RightRail />
|
||||
<FileManager selectedTool={selectedTool as any /* FIX ME */} />
|
||||
<Suspense fallback={null}>
|
||||
<FileManager selectedTool={selectedTool as any /* FIX ME */} />
|
||||
</Suspense>
|
||||
</Group>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -3,9 +3,14 @@
|
||||
*
|
||||
* Prevents infinite worker creation by managing PDF.js workers globally
|
||||
* and ensuring proper cleanup when operations complete.
|
||||
*
|
||||
* Uses dynamic imports to avoid bundling PDF.js in main bundle.
|
||||
*/
|
||||
|
||||
import { GlobalWorkerOptions, getDocument, PDFDocumentProxy } from 'pdfjs-dist/legacy/build/pdf.mjs';
|
||||
// Dynamic import types for TypeScript
|
||||
type PDFDocumentProxy = import('pdfjs-dist').PDFDocumentProxy;
|
||||
type GlobalWorkerOptions = typeof import('pdfjs-dist').GlobalWorkerOptions;
|
||||
type GetDocumentFn = typeof import('pdfjs-dist').getDocument;
|
||||
|
||||
class PDFWorkerManager {
|
||||
private static instance: PDFWorkerManager;
|
||||
@@ -13,9 +18,10 @@ class PDFWorkerManager {
|
||||
private workerCount = 0;
|
||||
private maxWorkers = 10; // Limit concurrent workers
|
||||
private isInitialized = false;
|
||||
private pdfjsLib: { GlobalWorkerOptions: GlobalWorkerOptions; getDocument: GetDocumentFn } | null = null;
|
||||
|
||||
private constructor() {
|
||||
this.initializeWorker();
|
||||
// Don't initialize worker in constructor - defer until first use
|
||||
}
|
||||
|
||||
static getInstance(): PDFWorkerManager {
|
||||
@@ -26,11 +32,14 @@ class PDFWorkerManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize PDF.js worker once globally
|
||||
* Lazy-load PDF.js library and initialize worker once globally
|
||||
*/
|
||||
private initializeWorker(): void {
|
||||
private async initializeWorker(): Promise<void> {
|
||||
if (!this.isInitialized) {
|
||||
GlobalWorkerOptions.workerSrc = new URL(
|
||||
// Dynamic import - only loads when first PDF operation is needed
|
||||
this.pdfjsLib = await import('pdfjs-dist/legacy/build/pdf.mjs');
|
||||
|
||||
this.pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
|
||||
'pdfjs-dist/legacy/build/pdf.worker.min.mjs',
|
||||
import.meta.url
|
||||
).toString();
|
||||
@@ -51,6 +60,13 @@ class PDFWorkerManager {
|
||||
verbosity?: number;
|
||||
} = {}
|
||||
): Promise<PDFDocumentProxy> {
|
||||
// Lazy-load PDF.js on first use
|
||||
await this.initializeWorker();
|
||||
|
||||
if (!this.pdfjsLib) {
|
||||
throw new Error('Failed to load PDF.js library');
|
||||
}
|
||||
|
||||
// Wait if we've hit the worker limit
|
||||
if (this.activeDocuments.size >= this.maxWorkers) {
|
||||
await this.waitForAvailableWorker();
|
||||
@@ -68,7 +84,7 @@ class PDFWorkerManager {
|
||||
pdfData = data; // Pass through as-is
|
||||
}
|
||||
|
||||
const loadingTask = getDocument(
|
||||
const loadingTask = this.pdfjsLib.getDocument(
|
||||
typeof pdfData === 'string' ? {
|
||||
url: pdfData,
|
||||
disableAutoFetch: options.disableAutoFetch ?? true,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { invoke, isTauri } from '@tauri-apps/api/core';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
|
||||
export interface FileOpenService {
|
||||
getOpenedFiles(): Promise<string[]>;
|
||||
@@ -60,8 +61,6 @@ class TauriFileOpenService implements FileOpenService {
|
||||
|
||||
// Only import if in Tauri environment
|
||||
if (isTauri()) {
|
||||
const { listen } = await import('@tauri-apps/api/event');
|
||||
|
||||
// Check again after async import
|
||||
if (isCleanedUp) {
|
||||
return;
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { Suspense } from "react";
|
||||
import { Suspense, lazy } from "react";
|
||||
import { Routes, Route } from "react-router-dom";
|
||||
import { AppProviders } from "@app/components/AppProviders";
|
||||
import { AppLayout } from "@app/components/AppLayout";
|
||||
import { LoadingFallback } from "@app/components/shared/LoadingFallback";
|
||||
import Landing from "@app/routes/Landing";
|
||||
import Login from "@app/routes/Login";
|
||||
import Signup from "@app/routes/Signup";
|
||||
import AuthCallback from "@app/routes/AuthCallback";
|
||||
import InviteAccept from "@app/routes/InviteAccept";
|
||||
import Onboarding from "@app/components/onboarding/Onboarding";
|
||||
|
||||
// Lazy-load auth routes - only loaded when user navigates to them
|
||||
const Landing = lazy(() => import("@app/routes/Landing"));
|
||||
const Login = lazy(() => import("@app/routes/Login"));
|
||||
const Signup = lazy(() => import("@app/routes/Signup"));
|
||||
const AuthCallback = lazy(() => import("@app/routes/AuthCallback"));
|
||||
const InviteAccept = lazy(() => import("@app/routes/InviteAccept"));
|
||||
|
||||
// Lazy-load Onboarding - only shown once for first-time users
|
||||
const Onboarding = lazy(() => import("@app/components/onboarding/Onboarding"));
|
||||
|
||||
// Import global styles
|
||||
import "@app/styles/tailwind.css";
|
||||
@@ -34,7 +38,9 @@ export default function App() {
|
||||
{/* Main app routes - Landing handles auth logic */}
|
||||
<Route path="/*" element={<Landing />} />
|
||||
</Routes>
|
||||
<Onboarding />
|
||||
<Suspense fallback={null}>
|
||||
<Onboarding />
|
||||
</Suspense>
|
||||
</AppLayout>
|
||||
</AppProviders>
|
||||
</Suspense>
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
import React from 'react';
|
||||
import React, { lazy } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useConfigNavSections as useCoreConfigNavSections, createConfigNavSections as createCoreConfigNavSections, ConfigNavSection } from '@core/components/shared/config/configNavSections';
|
||||
import PeopleSection from '@app/components/shared/config/configSections/PeopleSection';
|
||||
import TeamsSection from '@app/components/shared/config/configSections/TeamsSection';
|
||||
import AdminGeneralSection from '@app/components/shared/config/configSections/AdminGeneralSection';
|
||||
import AdminSecuritySection from '@app/components/shared/config/configSections/AdminSecuritySection';
|
||||
import AdminConnectionsSection from '@app/components/shared/config/configSections/AdminConnectionsSection';
|
||||
import AdminPrivacySection from '@app/components/shared/config/configSections/AdminPrivacySection';
|
||||
import AdminDatabaseSection from '@app/components/shared/config/configSections/AdminDatabaseSection';
|
||||
import AdminAdvancedSection from '@app/components/shared/config/configSections/AdminAdvancedSection';
|
||||
import AdminLegalSection from '@app/components/shared/config/configSections/AdminLegalSection';
|
||||
import AdminPlanSection from '@app/components/shared/config/configSections/AdminPlanSection';
|
||||
import AdminFeaturesSection from '@app/components/shared/config/configSections/AdminFeaturesSection';
|
||||
import AdminEndpointsSection from '@app/components/shared/config/configSections/AdminEndpointsSection';
|
||||
import AdminAuditSection from '@app/components/shared/config/configSections/AdminAuditSection';
|
||||
import AdminUsageSection from '@app/components/shared/config/configSections/AdminUsageSection';
|
||||
import ApiKeys from '@app/components/shared/config/configSections/ApiKeys';
|
||||
import AccountSection from '@app/components/shared/config/configSections/AccountSection';
|
||||
import GeneralSection from '@app/components/shared/config/configSections/GeneralSection';
|
||||
|
||||
// Lazy load all config sections
|
||||
const PeopleSection = lazy(() => import('@app/components/shared/config/configSections/PeopleSection'));
|
||||
const TeamsSection = lazy(() => import('@app/components/shared/config/configSections/TeamsSection'));
|
||||
const AdminGeneralSection = lazy(() => import('@app/components/shared/config/configSections/AdminGeneralSection'));
|
||||
const AdminSecuritySection = lazy(() => import('@app/components/shared/config/configSections/AdminSecuritySection'));
|
||||
const AdminConnectionsSection = lazy(() => import('@app/components/shared/config/configSections/AdminConnectionsSection'));
|
||||
const AdminPrivacySection = lazy(() => import('@app/components/shared/config/configSections/AdminPrivacySection'));
|
||||
const AdminDatabaseSection = lazy(() => import('@app/components/shared/config/configSections/AdminDatabaseSection'));
|
||||
const AdminAdvancedSection = lazy(() => import('@app/components/shared/config/configSections/AdminAdvancedSection'));
|
||||
const AdminLegalSection = lazy(() => import('@app/components/shared/config/configSections/AdminLegalSection'));
|
||||
const AdminPlanSection = lazy(() => import('@app/components/shared/config/configSections/AdminPlanSection'));
|
||||
const AdminFeaturesSection = lazy(() => import('@app/components/shared/config/configSections/AdminFeaturesSection'));
|
||||
const AdminEndpointsSection = lazy(() => import('@app/components/shared/config/configSections/AdminEndpointsSection'));
|
||||
const AdminAuditSection = lazy(() => import('@app/components/shared/config/configSections/AdminAuditSection'));
|
||||
const AdminUsageSection = lazy(() => import('@app/components/shared/config/configSections/AdminUsageSection'));
|
||||
const ApiKeys = lazy(() => import('@app/components/shared/config/configSections/ApiKeys'));
|
||||
const AccountSection = lazy(() => import('@app/components/shared/config/configSections/AccountSection'));
|
||||
const GeneralSection = lazy(() => import('@app/components/shared/config/configSections/GeneralSection'));
|
||||
|
||||
/**
|
||||
* Hook version of proprietary config nav sections with proper i18n support
|
||||
|
||||
+45
-1
@@ -2,6 +2,29 @@ import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react-swc';
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
||||
import { visualizer } from "rollup-plugin-visualizer";
|
||||
import type { OutputBundle } from "rollup";
|
||||
|
||||
const maxChunkSize = 500;
|
||||
|
||||
function failOnLargeChunks(limitKb: number) {
|
||||
return {
|
||||
name: "fail-on-large-chunks",
|
||||
generateBundle(_: unknown, bundle: OutputBundle) {
|
||||
for (const [fileName, chunk] of Object.entries(bundle)) {
|
||||
if (chunk.type === "chunk") {
|
||||
const sizeKb = Buffer.byteLength(chunk.code) / 1024;
|
||||
|
||||
if (sizeKb > limitKb) {
|
||||
throw new Error(
|
||||
`❌ Chunk "${fileName}" is ${sizeKb.toFixed(1)} KB (limit: ${limitKb} KB)`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
// When DISABLE_ADDITIONAL_FEATURES is false (or unset), enable proprietary features
|
||||
@@ -17,6 +40,10 @@ export default defineConfig(({ mode }) => {
|
||||
|
||||
return {
|
||||
plugins: [
|
||||
visualizer({
|
||||
open: true,
|
||||
filename: "stats.html"
|
||||
}),
|
||||
react(),
|
||||
tsconfigPaths({
|
||||
projects: [tsconfigProject],
|
||||
@@ -29,8 +56,25 @@ export default defineConfig(({ mode }) => {
|
||||
dest: 'pdfium'
|
||||
}
|
||||
]
|
||||
})
|
||||
}),
|
||||
failOnLargeChunks(maxChunkSize),
|
||||
],
|
||||
build: {
|
||||
chunkSizeWarningLimit: maxChunkSize,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
// Manual chunks for better code splitting
|
||||
manualChunks: {
|
||||
// Large UI libraries
|
||||
'vendor-ui': ['@mantine/core', '@mantine/hooks', '@mantine/dates', '@mantine/dropzone'],
|
||||
// React and related
|
||||
'vendor-react': ['react', 'react-dom', 'react-router-dom'],
|
||||
// Other large dependencies
|
||||
'vendor-utils': ['jszip'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
server: {
|
||||
host: true,
|
||||
// make sure this port matches the devUrl port in tauri.conf.json file
|
||||
|
||||
Reference in New Issue
Block a user