From 436bbf532c485e9b02e6deb0094706d786ad73c3 Mon Sep 17 00:00:00 2001 From: Your Name <119736744+aborayan2022@users.noreply.github.com> Date: Sun, 22 Mar 2026 20:20:15 +0200 Subject: [PATCH] seo(frontend): strengthen indexing and internal linking --- frontend/public/sitemap.xml | 916 +++++++++--------- frontend/scripts/generate-seo-assets.mjs | 67 +- frontend/src/components/seo/BreadcrumbNav.tsx | 47 + frontend/src/components/seo/RelatedTools.tsx | 11 +- frontend/src/components/seo/SEOHead.tsx | 1 + .../src/components/seo/SuggestedTools.tsx | 4 +- .../src/components/seo/ToolLandingPage.tsx | 12 + frontend/src/components/tools/ImageToSvg.tsx | 167 ++++ frontend/src/config/routes.ts | 1 + frontend/src/config/seo-tools.json | 2 +- frontend/src/config/seoData.ts | 73 ++ frontend/src/i18n/ar.json | 20 + frontend/src/i18n/en.json | 20 + frontend/src/i18n/fr.json | 20 + frontend/src/pages/SeoCollectionPage.tsx | 9 + frontend/src/pages/SeoPage.tsx | 9 + frontend/src/utils/fileRouting.ts | 1 + nginx/nginx.prod.conf | 1 - 18 files changed, 894 insertions(+), 487 deletions(-) create mode 100644 frontend/src/components/seo/BreadcrumbNav.tsx create mode 100644 frontend/src/components/tools/ImageToSvg.tsx diff --git a/frontend/public/sitemap.xml b/frontend/public/sitemap.xml index 2ec118a..87504f0 100644 --- a/frontend/public/sitemap.xml +++ b/frontend/public/sitemap.xml @@ -2,937 +2,943 @@ https://dociva.io/ - 2026-03-21 + 2026-03-22 daily 1.0 https://dociva.io/about - 2026-03-21 + 2026-03-22 monthly 0.4 https://dociva.io/contact - 2026-03-21 + 2026-03-22 monthly 0.4 https://dociva.io/privacy - 2026-03-21 + 2026-03-22 yearly 0.3 https://dociva.io/terms - 2026-03-21 + 2026-03-22 yearly 0.3 https://dociva.io/pricing - 2026-03-21 + 2026-03-22 monthly 0.7 https://dociva.io/blog - 2026-03-21 + 2026-03-22 weekly 0.6 https://dociva.io/developers - 2026-03-21 + 2026-03-22 monthly 0.5 https://dociva.io/blog/how-to-compress-pdf-online - 2026-03-21 + 2026-03-22 monthly 0.6 https://dociva.io/blog/convert-images-without-losing-quality - 2026-03-21 + 2026-03-22 monthly 0.6 https://dociva.io/blog/ocr-extract-text-from-images - 2026-03-21 + 2026-03-22 monthly 0.6 https://dociva.io/blog/merge-split-pdf-files - 2026-03-21 + 2026-03-22 monthly 0.6 https://dociva.io/blog/ai-chat-with-pdf-documents - 2026-03-21 + 2026-03-22 monthly 0.6 https://dociva.io/tools/pdf-to-word - 2026-03-21 + 2026-03-22 weekly 0.9 https://dociva.io/tools/word-to-pdf - 2026-03-21 + 2026-03-22 weekly 0.9 https://dociva.io/tools/compress-pdf - 2026-03-21 + 2026-03-22 weekly 0.9 https://dociva.io/tools/merge-pdf - 2026-03-21 + 2026-03-22 weekly 0.9 https://dociva.io/tools/split-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 https://dociva.io/tools/rotate-pdf - 2026-03-21 + 2026-03-22 weekly 0.7 https://dociva.io/tools/pdf-to-images - 2026-03-21 + 2026-03-22 weekly 0.8 https://dociva.io/tools/images-to-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 https://dociva.io/tools/watermark-pdf - 2026-03-21 - weekly - 0.7 - - - https://dociva.io/tools/remove-watermark-pdf - 2026-03-21 + 2026-03-22 weekly 0.7 https://dociva.io/tools/protect-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 https://dociva.io/tools/unlock-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 https://dociva.io/tools/page-numbers - 2026-03-21 - weekly - 0.7 - - - https://dociva.io/tools/reorder-pdf - 2026-03-21 - weekly - 0.7 - - - https://dociva.io/tools/extract-pages - 2026-03-21 + 2026-03-22 weekly 0.7 https://dociva.io/tools/pdf-editor - 2026-03-21 + 2026-03-22 weekly 0.8 https://dociva.io/tools/pdf-flowchart - 2026-03-21 + 2026-03-22 weekly 0.7 https://dociva.io/tools/pdf-to-excel - 2026-03-21 + 2026-03-22 weekly 0.8 - https://dociva.io/tools/sign-pdf - 2026-03-21 - weekly - 0.8 - - - https://dociva.io/tools/crop-pdf - 2026-03-21 + https://dociva.io/tools/remove-watermark-pdf + 2026-03-22 weekly 0.7 - https://dociva.io/tools/flatten-pdf - 2026-03-21 + https://dociva.io/tools/reorder-pdf + 2026-03-22 weekly 0.7 - https://dociva.io/tools/repair-pdf - 2026-03-21 + https://dociva.io/tools/extract-pages + 2026-03-22 weekly 0.7 - - https://dociva.io/tools/pdf-metadata - 2026-03-21 - weekly - 0.6 - https://dociva.io/tools/image-converter - 2026-03-21 + 2026-03-22 weekly 0.8 https://dociva.io/tools/image-resize - 2026-03-21 + 2026-03-22 weekly 0.8 https://dociva.io/tools/compress-image - 2026-03-21 + 2026-03-22 + weekly + 0.8 + + + https://dociva.io/tools/ocr + 2026-03-22 weekly 0.8 https://dociva.io/tools/remove-background - 2026-03-21 + 2026-03-22 weekly 0.8 - https://dociva.io/tools/image-crop - 2026-03-21 - weekly - 0.7 - - - https://dociva.io/tools/image-rotate-flip - 2026-03-21 - weekly - 0.7 - - - https://dociva.io/tools/ocr - 2026-03-21 - weekly - 0.8 - - - https://dociva.io/tools/chat-pdf - 2026-03-21 - weekly - 0.8 - - - https://dociva.io/tools/summarize-pdf - 2026-03-21 - weekly - 0.8 - - - https://dociva.io/tools/translate-pdf - 2026-03-21 - weekly - 0.8 - - - https://dociva.io/tools/extract-tables - 2026-03-21 + https://dociva.io/tools/image-to-svg + 2026-03-22 weekly 0.8 https://dociva.io/tools/html-to-pdf - 2026-03-21 + 2026-03-22 weekly 0.7 + + https://dociva.io/tools/chat-pdf + 2026-03-22 + weekly + 0.8 + + + https://dociva.io/tools/summarize-pdf + 2026-03-22 + weekly + 0.8 + + + https://dociva.io/tools/translate-pdf + 2026-03-22 + weekly + 0.8 + + + https://dociva.io/tools/extract-tables + 2026-03-22 + weekly + 0.8 + https://dociva.io/tools/qr-code - 2026-03-21 + 2026-03-22 weekly 0.7 https://dociva.io/tools/video-to-gif - 2026-03-21 + 2026-03-22 weekly 0.7 https://dociva.io/tools/word-counter - 2026-03-21 + 2026-03-22 weekly 0.6 https://dociva.io/tools/text-cleaner - 2026-03-21 + 2026-03-22 weekly 0.6 https://dociva.io/tools/pdf-to-pptx - 2026-03-21 + 2026-03-22 weekly 0.8 https://dociva.io/tools/excel-to-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 https://dociva.io/tools/pptx-to-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/tools/sign-pdf + 2026-03-22 + weekly + 0.8 + + + https://dociva.io/tools/crop-pdf + 2026-03-22 + weekly + 0.7 + + + https://dociva.io/tools/flatten-pdf + 2026-03-22 + weekly + 0.7 + + + https://dociva.io/tools/repair-pdf + 2026-03-22 + weekly + 0.7 + + + https://dociva.io/tools/pdf-metadata + 2026-03-22 + weekly + 0.6 + + + https://dociva.io/tools/image-crop + 2026-03-22 + weekly + 0.7 + + + https://dociva.io/tools/image-rotate-flip + 2026-03-22 + weekly + 0.7 + https://dociva.io/tools/barcode-generator - 2026-03-21 + 2026-03-22 weekly 0.7 https://dociva.io/pdf-to-word - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/word-to-pdf - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/compress-pdf-online - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/convert-jpg-to-pdf - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/merge-pdf-files - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/remove-pdf-password - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/pdf-to-word-editable - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/convert-pdf-to-text - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/split-pdf-online - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/jpg-to-pdf - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/png-to-pdf - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/images-to-pdf-online - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/pdf-to-jpg - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/pdf-to-png - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/compress-pdf-for-email - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/compress-scanned-pdf - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/merge-pdf-online-free - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/combine-pdf-files - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/extract-pages-from-pdf - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/reorder-pdf-pages - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/rotate-pdf-pages - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/add-page-numbers-to-pdf - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/protect-pdf-with-password - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/unlock-pdf-online - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/watermark-pdf-online - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/remove-watermark-from-pdf - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/edit-pdf-online-free - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/pdf-to-excel-online - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/extract-tables-from-pdf - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/html-to-pdf-online - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/scan-pdf-to-text - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/chat-with-pdf - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/summarize-pdf-online - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/translate-pdf-online - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/convert-image-to-pdf - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/convert-webp-to-jpg - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/resize-image-online - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/compress-image-online - 2026-03-21 - weekly - 0.88 - - - https://dociva.io/remove-image-background - 2026-03-21 + 2026-03-22 weekly 0.88 https://dociva.io/ar/pdf-to-word - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/word-to-pdf + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/word-to-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/compress-pdf-online + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/compress-pdf-online - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/convert-jpg-to-pdf + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/convert-jpg-to-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/merge-pdf-files + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/merge-pdf-files - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/remove-pdf-password + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/remove-pdf-password - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/pdf-to-word-editable + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/pdf-to-word-editable - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/convert-pdf-to-text + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/convert-pdf-to-text - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/split-pdf-online + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/split-pdf-online - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/jpg-to-pdf + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/jpg-to-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/png-to-pdf + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/png-to-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/images-to-pdf-online + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/images-to-pdf-online - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/pdf-to-jpg + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/pdf-to-jpg - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/pdf-to-png + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/pdf-to-png - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/compress-pdf-for-email + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/compress-pdf-for-email - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/compress-scanned-pdf + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/compress-scanned-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/merge-pdf-online-free + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/merge-pdf-online-free - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/combine-pdf-files + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/combine-pdf-files - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/extract-pages-from-pdf + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/extract-pages-from-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/reorder-pdf-pages + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/reorder-pdf-pages - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/rotate-pdf-pages + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/rotate-pdf-pages - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/add-page-numbers-to-pdf + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/add-page-numbers-to-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/protect-pdf-with-password + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/protect-pdf-with-password - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/unlock-pdf-online + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/unlock-pdf-online - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/watermark-pdf-online + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/watermark-pdf-online - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/remove-watermark-from-pdf + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/remove-watermark-from-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/edit-pdf-online-free + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/edit-pdf-online-free - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/pdf-to-excel-online + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/pdf-to-excel-online - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/extract-tables-from-pdf + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/extract-tables-from-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/html-to-pdf-online + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/html-to-pdf-online - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/scan-pdf-to-text + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/scan-pdf-to-text - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/chat-with-pdf + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/chat-with-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/summarize-pdf-online + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/summarize-pdf-online - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/translate-pdf-online + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/translate-pdf-online - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/convert-image-to-pdf + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/convert-image-to-pdf - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/convert-webp-to-jpg + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/convert-webp-to-jpg - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/resize-image-online + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/resize-image-online - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/compress-image-online + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/compress-image-online - 2026-03-21 + 2026-03-22 weekly 0.8 + + https://dociva.io/remove-image-background + 2026-03-22 + weekly + 0.88 + https://dociva.io/ar/remove-image-background - 2026-03-21 + 2026-03-22 weekly 0.8 https://dociva.io/best-pdf-tools - 2026-03-21 - weekly - 0.82 - - - https://dociva.io/free-pdf-tools-online - 2026-03-21 - weekly - 0.82 - - - https://dociva.io/convert-files-online - 2026-03-21 - weekly - 0.82 - - - https://dociva.io/pdf-converter-tools - 2026-03-21 - weekly - 0.82 - - - https://dociva.io/secure-pdf-tools - 2026-03-21 - weekly - 0.82 - - - https://dociva.io/ai-document-tools - 2026-03-21 - weekly - 0.82 - - - https://dociva.io/image-to-pdf-tools - 2026-03-21 - weekly - 0.82 - - - https://dociva.io/online-image-tools - 2026-03-21 - weekly - 0.82 - - - https://dociva.io/office-to-pdf-tools - 2026-03-21 - weekly - 0.82 - - - https://dociva.io/scanned-document-tools - 2026-03-21 - weekly - 0.82 - - - https://dociva.io/arabic-pdf-tools - 2026-03-21 + 2026-03-22 weekly 0.82 https://dociva.io/ar/best-pdf-tools - 2026-03-21 + 2026-03-22 weekly 0.74 + + https://dociva.io/free-pdf-tools-online + 2026-03-22 + weekly + 0.82 + https://dociva.io/ar/free-pdf-tools-online - 2026-03-21 + 2026-03-22 weekly 0.74 + + https://dociva.io/convert-files-online + 2026-03-22 + weekly + 0.82 + https://dociva.io/ar/convert-files-online - 2026-03-21 + 2026-03-22 weekly 0.74 + + https://dociva.io/pdf-converter-tools + 2026-03-22 + weekly + 0.82 + https://dociva.io/ar/pdf-converter-tools - 2026-03-21 + 2026-03-22 weekly 0.74 + + https://dociva.io/secure-pdf-tools + 2026-03-22 + weekly + 0.82 + https://dociva.io/ar/secure-pdf-tools - 2026-03-21 + 2026-03-22 weekly 0.74 + + https://dociva.io/ai-document-tools + 2026-03-22 + weekly + 0.82 + https://dociva.io/ar/ai-document-tools - 2026-03-21 + 2026-03-22 weekly 0.74 + + https://dociva.io/image-to-pdf-tools + 2026-03-22 + weekly + 0.82 + https://dociva.io/ar/image-to-pdf-tools - 2026-03-21 + 2026-03-22 weekly 0.74 + + https://dociva.io/online-image-tools + 2026-03-22 + weekly + 0.82 + https://dociva.io/ar/online-image-tools - 2026-03-21 + 2026-03-22 weekly 0.74 + + https://dociva.io/office-to-pdf-tools + 2026-03-22 + weekly + 0.82 + https://dociva.io/ar/office-to-pdf-tools - 2026-03-21 + 2026-03-22 weekly 0.74 + + https://dociva.io/scanned-document-tools + 2026-03-22 + weekly + 0.82 + https://dociva.io/ar/scanned-document-tools - 2026-03-21 + 2026-03-22 weekly 0.74 + + https://dociva.io/arabic-pdf-tools + 2026-03-22 + weekly + 0.82 + https://dociva.io/ar/arabic-pdf-tools - 2026-03-21 + 2026-03-22 weekly 0.74 diff --git a/frontend/scripts/generate-seo-assets.mjs b/frontend/scripts/generate-seo-assets.mjs index 57ff8ea..ea55563 100644 --- a/frontend/scripts/generate-seo-assets.mjs +++ b/frontend/scripts/generate-seo-assets.mjs @@ -12,6 +12,7 @@ const today = new Date().toISOString().slice(0, 10); const seoConfig = JSON.parse( await readFile(path.join(frontendRoot, 'src', 'seo', 'seoData.json'), 'utf8') ); +const routeRegistrySource = await readFile(path.join(frontendRoot, 'src', 'config', 'routes.ts'), 'utf8'); const staticPages = [ { path: '/', changefreq: 'daily', priority: '1.0' }, @@ -52,6 +53,7 @@ const toolRoutePriorities = new Map([ ['image-resize', '0.8'], ['compress-image', '0.8'], ['remove-background', '0.8'], + ['image-to-svg', '0.8'], ['image-crop', '0.7'], ['image-rotate-flip', '0.7'], ['ocr', '0.8'], @@ -70,6 +72,10 @@ const toolRoutePriorities = new Map([ ['barcode-generator', '0.7'], ]); +function extractToolSlugs(source) { + return [...source.matchAll(/'\/tools\/([^']+)'/g)].map((match) => match[1]); +} + function extractBlogSlugs(source) { return [...source.matchAll(/slug:\s*'([^']+)'/g)].map((match) => match[1]); } @@ -78,32 +84,47 @@ function makeUrlTag({ loc, changefreq, priority }) { return ` \n ${loc}\n ${today}\n ${changefreq}\n ${priority}\n `; } +function dedupeEntries(entries) { + const seen = new Set(); + return entries.filter((entry) => { + if (seen.has(entry.loc)) { + return false; + } + + seen.add(entry.loc); + return true; + }); +} + const blogSource = await readFile(path.join(frontendRoot, 'src', 'content', 'blogArticles.ts'), 'utf8'); const blogSlugs = extractBlogSlugs(blogSource); +const toolSlugs = extractToolSlugs(routeRegistrySource); -const sitemapEntries = [ - ...staticPages.map((page) => - makeUrlTag({ loc: `${siteOrigin}${page.path}`, changefreq: page.changefreq, priority: page.priority }) - ), - ...blogSlugs.map((slug) => - makeUrlTag({ loc: `${siteOrigin}/blog/${slug}`, changefreq: 'monthly', priority: '0.6' }) - ), - ...[...toolRoutePriorities.entries()].map(([slug, priority]) => - makeUrlTag({ loc: `${siteOrigin}/tools/${slug}`, changefreq: 'weekly', priority }) - ), - ...seoConfig.toolPageSeeds.map((page) => - makeUrlTag({ loc: `${siteOrigin}/${page.slug}`, changefreq: 'weekly', priority: '0.88' }) - ), - ...seoConfig.toolPageSeeds.map((page) => - makeUrlTag({ loc: `${siteOrigin}/ar/${page.slug}`, changefreq: 'weekly', priority: '0.8' }) - ), - ...seoConfig.collectionPageSeeds.map((page) => - makeUrlTag({ loc: `${siteOrigin}/${page.slug}`, changefreq: 'weekly', priority: '0.82' }) - ), - ...seoConfig.collectionPageSeeds.map((page) => - makeUrlTag({ loc: `${siteOrigin}/ar/${page.slug}`, changefreq: 'weekly', priority: '0.74' }) - ), -]; +const sitemapEntries = dedupeEntries([ + ...staticPages.map((page) => ({ + loc: `${siteOrigin}${page.path}`, + changefreq: page.changefreq, + priority: page.priority, + })), + ...blogSlugs.map((slug) => ({ + loc: `${siteOrigin}/blog/${slug}`, + changefreq: 'monthly', + priority: '0.6', + })), + ...toolSlugs.map((slug) => ({ + loc: `${siteOrigin}/tools/${slug}`, + changefreq: 'weekly', + priority: toolRoutePriorities.get(slug) || '0.6', + })), + ...seoConfig.toolPageSeeds.flatMap((page) => ([ + { loc: `${siteOrigin}/${page.slug}`, changefreq: 'weekly', priority: '0.88' }, + { loc: `${siteOrigin}/ar/${page.slug}`, changefreq: 'weekly', priority: '0.8' }, + ])), + ...seoConfig.collectionPageSeeds.flatMap((page) => ([ + { loc: `${siteOrigin}/${page.slug}`, changefreq: 'weekly', priority: '0.82' }, + { loc: `${siteOrigin}/ar/${page.slug}`, changefreq: 'weekly', priority: '0.74' }, + ])), +]).map((entry) => makeUrlTag(entry)); const sitemap = `\n\n${sitemapEntries.join('\n')}\n\n`; diff --git a/frontend/src/components/seo/BreadcrumbNav.tsx b/frontend/src/components/seo/BreadcrumbNav.tsx new file mode 100644 index 0000000..3170a82 --- /dev/null +++ b/frontend/src/components/seo/BreadcrumbNav.tsx @@ -0,0 +1,47 @@ +import { ChevronRight } from 'lucide-react'; +import { Link } from 'react-router-dom'; + +interface BreadcrumbItem { + label: string; + to?: string; +} + +interface BreadcrumbNavProps { + items: BreadcrumbItem[]; + className?: string; +} + +export default function BreadcrumbNav({ items, className = '' }: BreadcrumbNavProps) { + if (items.length === 0) { + return null; + } + + return ( + + ); +} \ No newline at end of file diff --git a/frontend/src/components/seo/RelatedTools.tsx b/frontend/src/components/seo/RelatedTools.tsx index 5e0e7bc..67db82d 100644 --- a/frontend/src/components/seo/RelatedTools.tsx +++ b/frontend/src/components/seo/RelatedTools.tsx @@ -1,9 +1,10 @@ import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { getToolSEO } from '@/config/seoData'; +import { getInternalLinkToolSlugs, getToolSEO } from '@/config/seoData'; interface RelatedToolsProps { currentSlug: string; + limit?: number; } const CATEGORY_COLORS: Record = { @@ -14,12 +15,12 @@ const CATEGORY_COLORS: Record = { Utility: 'bg-amber-50 text-amber-700 dark:bg-amber-900/20 dark:text-amber-400', }; -export default function RelatedTools({ currentSlug }: RelatedToolsProps) { +export default function RelatedTools({ currentSlug, limit = 8 }: RelatedToolsProps) { const { t } = useTranslation(); const currentTool = getToolSEO(currentSlug); if (!currentTool) return null; - const relatedTools = currentTool.relatedSlugs + const relatedTools = getInternalLinkToolSlugs(currentSlug, limit) .map((slug) => getToolSEO(slug)) .filter(Boolean); @@ -39,7 +40,7 @@ export default function RelatedTools({ currentSlug }: RelatedToolsProps) { >

- {tool!.titleSuffix.replace(/^Free Online\s*/, '').replace(/\s*—.*$/, '')} + {t(`tools.${tool!.i18nKey}.title`)}

- {tool!.metaDescription} + {t(`tools.${tool!.i18nKey}.shortDesc`)}

))} diff --git a/frontend/src/components/seo/SEOHead.tsx b/frontend/src/components/seo/SEOHead.tsx index 4c59d04..0d1ea85 100644 --- a/frontend/src/components/seo/SEOHead.tsx +++ b/frontend/src/components/seo/SEOHead.tsx @@ -44,6 +44,7 @@ export default function SEOHead({ title, description, keywords, path, type = 'we {fullTitle} + {keywords ? : null} {languageAlternates.map((alternate) => ( diff --git a/frontend/src/components/seo/SuggestedTools.tsx b/frontend/src/components/seo/SuggestedTools.tsx index 0aa5ec2..8f98a02 100644 --- a/frontend/src/components/seo/SuggestedTools.tsx +++ b/frontend/src/components/seo/SuggestedTools.tsx @@ -1,7 +1,7 @@ import { ArrowRight } from 'lucide-react'; import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { getToolSEO } from '@/config/seoData'; +import { getPopularToolSlugs, getToolSEO } from '@/config/seoData'; interface SuggestedToolsProps { currentSlug: string; @@ -24,7 +24,7 @@ export default function SuggestedTools({ currentSlug, limit = 3 }: SuggestedTool return null; } - const relatedTools = currentTool.relatedSlugs + const relatedTools = getPopularToolSlugs(limit, [currentSlug, ...currentTool.relatedSlugs]) .map((slug) => getToolSEO(slug)) .filter(Boolean) .slice(0, limit); diff --git a/frontend/src/components/seo/ToolLandingPage.tsx b/frontend/src/components/seo/ToolLandingPage.tsx index 7f5468f..ecae8c6 100644 --- a/frontend/src/components/seo/ToolLandingPage.tsx +++ b/frontend/src/components/seo/ToolLandingPage.tsx @@ -3,8 +3,10 @@ import { useTranslation } from 'react-i18next'; import { CheckCircle } from 'lucide-react'; import { getToolSEO } from '@/config/seoData'; import { buildLanguageAlternates, buildSocialImageUrl, generateToolSchema, generateBreadcrumbs, generateFAQ, generateHowTo, getOgLocale, getSiteOrigin } from '@/utils/seo'; +import BreadcrumbNav from './BreadcrumbNav'; import FAQSection from './FAQSection'; import RelatedTools from './RelatedTools'; +import SuggestedTools from './SuggestedTools'; import ToolRating from '@/components/shared/ToolRating'; import SharePanel from '@/components/shared/SharePanel'; import ToolWorkflowPanel from '@/components/shared/ToolWorkflowPanel'; @@ -76,6 +78,7 @@ export default function ToolLandingPage({ slug, children }: ToolLandingPageProps {toolTitle} — {seo.titleSuffix} | {t('common.appName')} + {languageAlternates.map((alternate) => ( {/* Tool Interface */} +
+ +
{children}
@@ -222,6 +233,7 @@ export default function ToolLandingPage({ slug, children }: ToolLandingPageProps {/* Related Tools */} + {/* User Rating */} diff --git a/frontend/src/components/tools/ImageToSvg.tsx b/frontend/src/components/tools/ImageToSvg.tsx new file mode 100644 index 0000000..72bd474 --- /dev/null +++ b/frontend/src/components/tools/ImageToSvg.tsx @@ -0,0 +1,167 @@ +import { useState, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Helmet } from 'react-helmet-async'; +import { ImageIcon } from 'lucide-react'; +import FileUploader from '@/components/shared/FileUploader'; +import ProgressBar from '@/components/shared/ProgressBar'; +import DownloadButton from '@/components/shared/DownloadButton'; +import AdSlot from '@/components/layout/AdSlot'; +import { useFileUpload } from '@/hooks/useFileUpload'; +import { useTaskPolling } from '@/hooks/useTaskPolling'; +import { generateToolSchema } from '@/utils/seo'; +import { useFileStore } from '@/stores/fileStore'; + +type ColorMode = 'color' | 'binary'; + +export default function ImageToSvg() { + const { t } = useTranslation(); + const [phase, setPhase] = useState<'upload' | 'processing' | 'done'>('upload'); + const [colorMode, setColorMode] = useState('color'); + + const { + file, + uploadProgress, + isUploading, + taskId, + error: uploadError, + selectFile, + startUpload, + reset, + } = useFileUpload({ + endpoint: '/image/to-svg', + maxSizeMB: 10, + acceptedTypes: ['png', 'jpg', 'jpeg', 'webp'], + extraData: { color_mode: colorMode }, + }); + + const { status, result, error: taskError } = useTaskPolling({ + taskId, + onComplete: () => setPhase('done'), + onError: () => setPhase('done'), + }); + + // Accept file from homepage smart upload + const storeFile = useFileStore((s) => s.file); + const clearStoreFile = useFileStore((s) => s.clearFile); + useEffect(() => { + if (storeFile) { + selectFile(storeFile); + clearStoreFile(); + } + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + const handleUpload = async () => { + const id = await startUpload(); + if (id) setPhase('processing'); + }; + + const handleReset = () => { + reset(); + setPhase('upload'); + }; + + const modes: { value: ColorMode; label: string }[] = [ + { value: 'color', label: t('tools.imageToSvg.colorMode') }, + { value: 'binary', label: t('tools.imageToSvg.binaryMode') }, + ]; + + const schema = generateToolSchema({ + name: t('tools.imageToSvg.title'), + description: t('tools.imageToSvg.description'), + url: `${window.location.origin}/tools/image-to-svg`, + }); + + return ( + <> + + {t('tools.imageToSvg.title')} — {t('common.appName')} + + + + + +
+
+
+ +
+

{t('tools.imageToSvg.title')}

+

{t('tools.imageToSvg.description')}

+
+ + + + {phase === 'upload' && ( +
+ + + {file && !isUploading && ( + <> + {/* Color Mode Selector */} +
+ +
+ {modes.map((m) => ( + + ))} +
+
+ + + + )} +
+ )} + + {phase === 'processing' && !result && ( + + )} + + {phase === 'done' && result && result.status === 'completed' && ( + + )} + + {phase === 'done' && taskError && ( +
+
+

{taskError}

+
+ +
+ )} + + +
+ + ); +} diff --git a/frontend/src/config/routes.ts b/frontend/src/config/routes.ts index 2dcb34e..c35fad9 100644 --- a/frontend/src/config/routes.ts +++ b/frontend/src/config/routes.ts @@ -62,6 +62,7 @@ export const TOOL_ROUTES = [ '/tools/compress-image', '/tools/ocr', '/tools/remove-background', + '/tools/image-to-svg', // Convert Tools '/tools/html-to-pdf', diff --git a/frontend/src/config/seo-tools.json b/frontend/src/config/seo-tools.json index ebf4ebf..1a00701 100644 --- a/frontend/src/config/seo-tools.json +++ b/frontend/src/config/seo-tools.json @@ -382,7 +382,7 @@ "en": "Conversion traffic is broad, so this page groups the workflows people use most when they need one format changed into another quickly from the browser.", "ar": "ترافيك التحويل واسع، لذلك تجمع هذه الصفحة المسارات الأكثر استخداماً عندما يحتاج المستخدم إلى تغيير صيغة ملف إلى أخرى بسرعة من المتصفح." }, - "targetToolSlugs": ["pdf-to-word", "word-to-pdf", "images-to-pdf", "image-converter", "html-to-pdf", "video-to-gif"], + "targetToolSlugs": ["pdf-to-word", "word-to-pdf", "images-to-pdf", "image-converter", "image-to-svg", "html-to-pdf", "video-to-gif"], "faqTemplates": [ { "question": { diff --git a/frontend/src/config/seoData.ts b/frontend/src/config/seoData.ts index d8e04ab..1a0c415 100644 --- a/frontend/src/config/seoData.ts +++ b/frontend/src/config/seoData.ts @@ -448,6 +448,27 @@ export const TOOLS_SEO: ToolSEO[] = [ { question: 'What format is the output?', answer: 'The output is always a PNG file with a transparent background.' }, ], }, + { + i18nKey: 'imageToSvg', + slug: 'image-to-svg', + titleSuffix: 'Free Online Image to SVG Converter', + metaDescription: 'Convert PNG, JPG, and WebP images to scalable SVG vector format online for free. Perfect for logos, icons, and graphics that need to scale without quality loss.', + category: 'Image', + relatedSlugs: ['image-converter', 'compress-image', 'image-resize', 'remove-background'], + keywords: 'image to svg, png to svg, jpg to svg, raster to vector, convert image to svg, vectorize image, image vectorizer', + features: [ + 'Convert raster images (PNG, JPG, WebP) to SVG', + 'Color or black-and-white tracing modes', + 'Scalable vector output — no pixelation', + 'Perfect for logos, icons, and illustrations', + ], + faqs: [ + { question: 'What image formats can I convert to SVG?', answer: 'You can convert PNG, JPG, JPEG, and WebP images to SVG vector format.' }, + { question: 'What is the difference between color and binary mode?', answer: 'Color mode preserves the full color palette. Binary mode converts the image to black and white first, producing cleaner vector paths — ideal for logos and line art.' }, + { question: 'Will the SVG be editable?', answer: 'Yes, the output SVG contains vector paths that can be edited in any vector editor such as Adobe Illustrator, Inkscape, or Figma.' }, + { question: 'Is there a file size limit?', answer: 'Images up to 10 MB are supported. For best results, use images under 4000×4000 pixels.' }, + ], + }, { i18nKey: 'ocr', slug: 'ocr', @@ -881,6 +902,36 @@ export const TOOLS_SEO: ToolSEO[] = [ }, ]; +const POPULAR_TOOL_SLUGS = [ + 'pdf-to-word', + 'word-to-pdf', + 'compress-pdf', + 'merge-pdf', + 'image-converter', + 'image-resize', + 'compress-image', + 'ocr', + 'html-to-pdf', + 'pdf-to-excel', + 'qr-code', + 'video-to-gif', +] as const; + +function dedupeExistingToolSlugs(slugs: string[], excludeSlugs: string[] = []): string[] { + const excluded = new Set(excludeSlugs); + const seen = new Set(); + const validSlugs = new Set(TOOLS_SEO.map((tool) => tool.slug)); + + return slugs.filter((slug) => { + if (excluded.has(slug) || seen.has(slug) || !validSlugs.has(slug)) { + return false; + } + + seen.add(slug); + return true; + }); +} + /** Look up a tool's SEO data by slug */ export function getToolSEO(slug: string): ToolSEO | undefined { return TOOLS_SEO.find((t) => t.slug === slug); @@ -890,3 +941,25 @@ export function getToolSEO(slug: string): ToolSEO | undefined { export function getAllToolSlugs(): string[] { return TOOLS_SEO.map((t) => t.slug); } + +export function getPopularToolSlugs(limit = 4, excludeSlugs: string[] = []): string[] { + return dedupeExistingToolSlugs([...POPULAR_TOOL_SLUGS], excludeSlugs).slice(0, limit); +} + +export function getInternalLinkToolSlugs(currentSlug: string, limit = 8): string[] { + const currentTool = getToolSEO(currentSlug); + if (!currentTool) { + return []; + } + + const sameCategorySlugs = TOOLS_SEO + .filter((tool) => tool.category === currentTool.category && tool.slug !== currentSlug) + .map((tool) => tool.slug); + + const internalLinks = dedupeExistingToolSlugs( + [...currentTool.relatedSlugs, ...sameCategorySlugs, ...POPULAR_TOOL_SLUGS], + [currentSlug] + ); + + return internalLinks.slice(0, limit); +} diff --git a/frontend/src/i18n/ar.json b/frontend/src/i18n/ar.json index ac6d3cc..4f00bdc 100644 --- a/frontend/src/i18n/ar.json +++ b/frontend/src/i18n/ar.json @@ -443,6 +443,14 @@ "lockAspect": "قفل نسبة العرض للارتفاع", "aspectHint": "أدخل بُعداً واحداً — سيتم حساب الآخر تلقائياً للحفاظ على نسبة العرض للارتفاع." }, + "imageToSvg": { + "title": "تحويل الصورة إلى SVG", + "description": "حوّل الصور النقطية (PNG, JPG, WebP) إلى صيغة SVG المتجهية القابلة للتحجيم. مثالية للشعارات والأيقونات والرسوم التوضيحية.", + "shortDesc": "تحويل إلى SVG", + "modeLabel": "وضع التتبع", + "colorMode": "ألوان كاملة", + "binaryMode": "أبيض وأسود" + }, "ocr": { "title": "OCR — التعرف على النصوص", "description": "استخرج النصوص من الصور ومستندات PDF الممسوحة ضوئياً باستخدام التعرف الضوئي على الحروف.", @@ -1234,6 +1242,18 @@ {"q": "ما صيغة المخرجات؟", "a": "المخرجات دائماً ملف PNG بخلفية شفافة."} ] }, + "imageToSvg": { + "whatItDoes": "حوّل الصور النقطية (PNG, JPG, WebP) إلى صيغة SVG المتجهية القابلة للتحجيم. سواء كنت تحتاج شعارات أو أيقونات أو رسوم توضيحية متجهية، تتتبع هذه الأداة مسارات الصورة وتنتج ملف SVG نظيف يتوسع لأي حجم دون تشويش.", + "howToUse": ["ارفع ملف الصورة (PNG أو JPG أو WebP).", "اختر وضع التتبع: ألوان كاملة أو أبيض وأسود.", "انقر تحويل إلى SVG لبدء المعالجة.", "حمّل ملف SVG المتجهي القابل للتحجيم."], + "benefits": ["تحويل PNG و JPG و WebP إلى SVG", "وضع ألوان كاملة أو أبيض وأسود", "مخرجات متجهية قابلة للتحجيم — بدون تشويش", "قابل للتعديل في محررات الرسوم المتجهية (Illustrator, Figma, Inkscape)", "مجاني بدون تسجيل"], + "useCases": ["تحويل الشعارات إلى صيغة متجهية قابلة للتحجيم", "إنشاء أيقونات SVG للمواقع والتطبيقات", "تحويل الرسوم التوضيحية للمواد المطبوعة", "تحضير الرسومات للتصميم المتجاوب للويب", "تحويل الرسوم الخطية أو المخططات إلى مسارات قابلة للتعديل"], + "faq": [ + {"q": "ما صيغ الصور التي يمكنني تحويلها إلى SVG؟", "a": "يمكنك تحويل صور PNG و JPG و JPEG و WebP إلى صيغة SVG المتجهية."}, + {"q": "ما الفرق بين وضع الألوان ووضع الأبيض والأسود؟", "a": "وضع الألوان يحافظ على لوحة الألوان الكاملة لصورتك. وضع الأبيض والأسود يحوّل إلى أحادي اللون أولاً، منتجاً مسارات متجهية أنظف وأبسط — مثالي للشعارات والرسوم الخطية."}, + {"q": "هل يمكنني تعديل ملف SVG الناتج؟", "a": "نعم، يحتوي ملف SVG الناتج على مسارات متجهية يمكن تعديلها في أي محرر رسومات متجهية."}, + {"q": "هل يوجد حد لحجم الملف؟", "a": "يدعم صور حتى 10 ميجابايت. للحصول على أفضل النتائج، استخدم صور واضحة أقل من 4000×4000 بكسل."} + ] + }, "ocr": { "whatItDoes": "استخرج النص من الصور ومستندات PDF الممسوحة ضوئياً باستخدام التعرف البصري على الحروف (OCR). يدعم محركنا المبني على Tesseract اللغات العربية والإنجليزية والفرنسية بدقة عالية.", "howToUse": ["اختر نوع المصدر: صورة أو PDF.", "ارفع ملفك.", "اختر لغة OCR (الإنجليزية أو العربية أو الفرنسية).", "انقر استخراج النص وانسخ النتيجة."], diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 18b7e03..3440a4e 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -443,6 +443,14 @@ "lockAspect": "Lock aspect ratio", "aspectHint": "Enter one dimension — the other will auto-calculate to preserve aspect ratio." }, + "imageToSvg": { + "title": "Image to SVG", + "description": "Convert raster images (PNG, JPG, WebP) to scalable SVG vector format. Perfect for logos, icons, and illustrations.", + "shortDesc": "Convert to SVG", + "modeLabel": "Tracing Mode", + "colorMode": "Full Color", + "binaryMode": "Black & White" + }, "ocr": { "title": "OCR — Text Recognition", "description": "Extract text from images and scanned PDF documents using optical character recognition.", @@ -1234,6 +1242,18 @@ {"q": "What format is the output?", "a": "The output is always a PNG file with a transparent background."} ] }, + "imageToSvg": { + "whatItDoes": "Convert raster images (PNG, JPG, WebP) to scalable SVG vector format. Whether you need vector logos, icons, or illustrations, this tool traces the image paths and produces a clean SVG that scales to any size without pixelation.", + "howToUse": ["Upload your image file (PNG, JPG, or WebP).", "Choose the tracing mode: Full Color or Black & White.", "Click Convert to SVG to start processing.", "Download your scalable SVG vector file."], + "benefits": ["Convert PNG, JPG, and WebP to SVG", "Color or black-and-white tracing modes", "Scalable vector output — no pixelation", "Editable in vector editors (Illustrator, Figma, Inkscape)", "Free with no registration"], + "useCases": ["Converting logos to scalable vector format", "Creating SVG icons for websites and apps", "Vectorizing illustrations for print materials", "Preparing graphics for responsive web design", "Converting line art or diagrams to editable paths"], + "faq": [ + {"q": "What image formats can I convert to SVG?", "a": "You can convert PNG, JPG, JPEG, and WebP images to SVG vector format."}, + {"q": "What is the difference between Color and Black & White mode?", "a": "Color mode preserves the full color palette of your image. Black & White mode converts to monochrome first, producing cleaner and simpler vector paths — ideal for logos and line art."}, + {"q": "Can I edit the resulting SVG?", "a": "Yes, the output SVG contains vector paths that can be edited in any vector graphics editor."}, + {"q": "Is there a file size limit?", "a": "Images up to 10 MB are supported. For best results, use clear images under 4000×4000 pixels."} + ] + }, "ocr": { "whatItDoes": "Extract text from images and scanned PDF documents using Optical Character Recognition (OCR). Our Tesseract-powered engine supports English, Arabic, and French text recognition with high accuracy.", "howToUse": ["Choose the source type: Image or PDF.", "Upload your file.", "Select the OCR language (English, Arabic, or French).", "Click Extract Text and copy the result."], diff --git a/frontend/src/i18n/fr.json b/frontend/src/i18n/fr.json index a7b9894..81e155a 100644 --- a/frontend/src/i18n/fr.json +++ b/frontend/src/i18n/fr.json @@ -443,6 +443,14 @@ "lockAspect": "Verrouiller le rapport d'aspect", "aspectHint": "Entrez une dimension — l'autre sera calculée automatiquement pour préserver le rapport d'aspect." }, + "imageToSvg": { + "title": "Image vers SVG", + "description": "Convertissez des images raster (PNG, JPG, WebP) en format vectoriel SVG évolutif. Idéal pour les logos, icônes et illustrations.", + "shortDesc": "Convertir en SVG", + "modeLabel": "Mode de tracé", + "colorMode": "Couleurs complètes", + "binaryMode": "Noir et blanc" + }, "ocr": { "title": "OCR — Reconnaissance de texte", "description": "Extrayez le texte des images et des documents PDF numérisés grâce à la reconnaissance optique de caractères.", @@ -1234,6 +1242,18 @@ {"q": "Quel est le format de sortie ?", "a": "La sortie est toujours un fichier PNG avec un arrière-plan transparent."} ] }, + "imageToSvg": { + "whatItDoes": "Convertissez des images raster (PNG, JPG, WebP) en format vectoriel SVG évolutif. Que vous ayez besoin de logos, d'icônes ou d'illustrations vectoriels, cet outil trace les chemins de l'image et produit un SVG propre qui s'adapte à toute taille sans pixelisation.", + "howToUse": ["Téléchargez votre fichier image (PNG, JPG ou WebP).", "Choisissez le mode de traçage : Couleurs complètes ou Noir et blanc.", "Cliquez sur Convertir en SVG pour démarrer le traitement.", "Téléchargez votre fichier vectoriel SVG évolutif."], + "benefits": ["Conversion de PNG, JPG et WebP en SVG", "Modes de traçage couleur ou noir et blanc", "Sortie vectorielle évolutive — sans pixelisation", "Modifiable dans les éditeurs vectoriels (Illustrator, Figma, Inkscape)", "Gratuit sans inscription"], + "useCases": ["Convertir des logos en format vectoriel évolutif", "Créer des icônes SVG pour les sites web et les applications", "Vectoriser des illustrations pour les supports imprimés", "Préparer des graphiques pour le design web responsive", "Convertir des dessins au trait ou des diagrammes en chemins modifiables"], + "faq": [ + {"q": "Quels formats d'image puis-je convertir en SVG ?", "a": "Vous pouvez convertir des images PNG, JPG, JPEG et WebP en format vectoriel SVG."}, + {"q": "Quelle est la différence entre le mode Couleur et Noir et blanc ?", "a": "Le mode couleur préserve la palette complète de votre image. Le mode noir et blanc convertit d'abord en monochrome, produisant des chemins vectoriels plus propres et plus simples — idéal pour les logos et les dessins au trait."}, + {"q": "Puis-je modifier le SVG résultant ?", "a": "Oui, le SVG de sortie contient des chemins vectoriels modifiables dans n'importe quel éditeur graphique vectoriel."}, + {"q": "Y a-t-il une limite de taille de fichier ?", "a": "Les images jusqu'à 10 Mo sont prises en charge. Pour de meilleurs résultats, utilisez des images claires de moins de 4000×4000 pixels."} + ] + }, "ocr": { "whatItDoes": "Extrayez du texte à partir d'images et de documents PDF numérisés grâce à la reconnaissance optique de caractères (OCR). Notre moteur basé sur Tesseract prend en charge l'arabe, l'anglais et le français avec une haute précision.", "howToUse": ["Sélectionnez le type de source : image ou PDF.", "Téléchargez votre fichier.", "Choisissez la langue OCR (anglais, arabe ou français).", "Cliquez sur Extraire le texte et copiez le résultat."], diff --git a/frontend/src/pages/SeoCollectionPage.tsx b/frontend/src/pages/SeoCollectionPage.tsx index 3d183b5..b4073d4 100644 --- a/frontend/src/pages/SeoCollectionPage.tsx +++ b/frontend/src/pages/SeoCollectionPage.tsx @@ -1,6 +1,7 @@ import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { ArrowRight, FolderKanban, Link2 } from 'lucide-react'; +import BreadcrumbNav from '@/components/seo/BreadcrumbNav'; import SEOHead from '@/components/seo/SEOHead'; import FAQSection from '@/components/seo/FAQSection'; import { @@ -100,6 +101,14 @@ export default function SeoCollectionPage({ slug }: SeoCollectionPageProps) {
+
diff --git a/frontend/src/pages/SeoPage.tsx b/frontend/src/pages/SeoPage.tsx index c175d76..1411125 100644 --- a/frontend/src/pages/SeoPage.tsx +++ b/frontend/src/pages/SeoPage.tsx @@ -1,6 +1,7 @@ import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { ArrowRight, CheckCircle, FileText, Link2 } from 'lucide-react'; +import BreadcrumbNav from '@/components/seo/BreadcrumbNav'; import SEOHead from '@/components/seo/SEOHead'; import FAQSection from '@/components/seo/FAQSection'; import RelatedTools from '@/components/seo/RelatedTools'; @@ -146,6 +147,14 @@ export default function SeoPage({ slug }: SeoPageProps) {
+

diff --git a/frontend/src/utils/fileRouting.ts b/frontend/src/utils/fileRouting.ts index c050b62..e8b3478 100644 --- a/frontend/src/utils/fileRouting.ts +++ b/frontend/src/utils/fileRouting.ts @@ -71,6 +71,7 @@ const imageTools: ToolOption[] = [ { key: 'removeBg', path: '/tools/remove-background', icon: ImageIcon, bgColor: 'bg-fuchsia-100 dark:bg-fuchsia-900/30', iconColor: 'text-fuchsia-600 dark:text-fuchsia-400' }, { key: 'imagesToPdf', path: '/tools/images-to-pdf', icon: FileImage, bgColor: 'bg-lime-100 dark:bg-lime-900/30', iconColor: 'text-lime-600 dark:text-lime-400' }, { key: 'compressImage', path: '/tools/compress-image', icon: Minimize2, bgColor: 'bg-orange-100 dark:bg-orange-900/30', iconColor: 'text-orange-600 dark:text-orange-400' }, + { key: 'imageToSvg', path: '/tools/image-to-svg', icon: ImageIcon, bgColor: 'bg-indigo-100 dark:bg-indigo-900/30', iconColor: 'text-indigo-600 dark:text-indigo-400' }, ]; /** Video tools available when a video is uploaded */ diff --git a/nginx/nginx.prod.conf b/nginx/nginx.prod.conf index ea4dc17..8c8cbac 100644 --- a/nginx/nginx.prod.conf +++ b/nginx/nginx.prod.conf @@ -95,7 +95,6 @@ server { # Frontend static files location / { root /usr/share/nginx/html; - add_header Link "; rel=canonical" always; try_files $uri $uri/ /index.html; # Cache static assets