diff --git a/Dockerfile b/Dockerfile
index f42cda5..106eb15 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -59,6 +59,9 @@ ENV VITE_BRAND_NAME=$VITE_BRAND_NAME
ENV VITE_BRAND_LOGO=$VITE_BRAND_LOGO
ENV VITE_FOOTER_TEXT=$VITE_FOOTER_TEXT
+ARG DISABLE_TOOLS
+ENV DISABLE_TOOLS=$DISABLE_TOOLS
+
ENV NODE_OPTIONS="--max-old-space-size=3072"
RUN --mount=type=secret,id=VITE_CORS_PROXY_URL \
diff --git a/docs/self-hosting/docker.md b/docs/self-hosting/docker.md
index 2e3d2f4..e062a07 100644
--- a/docs/self-hosting/docker.md
+++ b/docs/self-hosting/docker.md
@@ -106,6 +106,7 @@ docker run -d -p 3000:8080 bentopdf:custom
| `VITE_BRAND_NAME` | Custom brand name | `BentoPDF` |
| `VITE_BRAND_LOGO` | Logo path relative to `public/` | `images/favicon-no-bg.svg` |
| `VITE_FOOTER_TEXT` | Custom footer/copyright text | `© 2026 BentoPDF. All rights reserved.` |
+| `DISABLE_TOOLS` | Comma-separated tool IDs to hide | _(empty; all tools enabled)_ |
WASM module URLs are pre-configured with CDN defaults — all advanced features work out of the box. Override these for air-gapped or self-hosted deployments.
@@ -135,6 +136,74 @@ docker build \
Branding works in both full mode and Simple Mode, and can be combined with all other build-time options.
+### Disabling Specific Tools
+
+Hide tools from the UI for compliance or security requirements. Disabled tools are removed from the homepage, search results, keyboard shortcuts, and the workflow builder. Direct URL access shows a "tool unavailable" page.
+
+Tool IDs are the page URL without `.html`. For example, if the tool lives at `bentopdf.com/edit-pdf.html`, the ID is `edit-pdf`.
+
+#### Finding Tool IDs
+
+The easiest way: open any tool in BentoPDF and look at the URL. The last part of the path (without `.html`) is the tool ID.
+
+
+Full list of tool IDs
+
+**Edit & Annotate:** `edit-pdf`, `bookmark`, `table-of-contents`, `page-numbers`, `add-page-labels`, `bates-numbering`, `add-watermark`, `header-footer`, `invert-colors`, `scanner-effect`, `adjust-colors`, `background-color`, `text-color`, `sign-pdf`, `add-stamps`, `remove-annotations`, `crop-pdf`, `form-filler`, `form-creator`, `remove-blank-pages`
+
+**Convert to PDF:** `image-to-pdf`, `jpg-to-pdf`, `png-to-pdf`, `webp-to-pdf`, `svg-to-pdf`, `bmp-to-pdf`, `heic-to-pdf`, `tiff-to-pdf`, `txt-to-pdf`, `markdown-to-pdf`, `json-to-pdf`, `csv-to-pdf`, `rtf-to-pdf`, `odt-to-pdf`, `word-to-pdf`, `excel-to-pdf`, `powerpoint-to-pdf`, `xps-to-pdf`, `mobi-to-pdf`, `epub-to-pdf`, `fb2-to-pdf`, `cbz-to-pdf`, `wpd-to-pdf`, `wps-to-pdf`, `xml-to-pdf`, `pages-to-pdf`, `odg-to-pdf`, `ods-to-pdf`, `odp-to-pdf`, `pub-to-pdf`, `vsd-to-pdf`, `psd-to-pdf`, `email-to-pdf`
+
+**Convert from PDF:** `pdf-to-jpg`, `pdf-to-png`, `pdf-to-webp`, `pdf-to-bmp`, `pdf-to-tiff`, `pdf-to-cbz`, `pdf-to-svg`, `pdf-to-csv`, `pdf-to-excel`, `pdf-to-greyscale`, `pdf-to-json`, `pdf-to-docx`, `extract-images`, `pdf-to-markdown`, `prepare-pdf-for-ai`, `pdf-to-text`
+
+**Organize & Manage:** `ocr-pdf`, `merge-pdf`, `alternate-merge`, `organize-pdf`, `add-attachments`, `extract-attachments`, `edit-attachments`, `pdf-multi-tool`, `pdf-layers`, `extract-tables`, `split-pdf`, `divide-pages`, `extract-pages`, `delete-pages`, `add-blank-page`, `reverse-pages`, `rotate-pdf`, `rotate-custom`, `n-up-pdf`, `pdf-booklet`, `combine-single-page`, `view-metadata`, `edit-metadata`, `pdf-to-zip`, `compare-pdfs`, `posterize-pdf`, `page-dimensions`
+
+**Optimize & Repair:** `compress-pdf`, `pdf-to-pdfa`, `fix-page-size`, `linearize-pdf`, `remove-restrictions`, `repair-pdf`, `rasterize-pdf`, `deskew-pdf`, `font-to-outline`
+
+**Security:** `encrypt-pdf`, `sanitize-pdf`, `decrypt-pdf`, `flatten-pdf`, `remove-metadata`, `change-permissions`, `digital-sign-pdf`, `validate-signature-pdf`, `timestamp-pdf`
+
+
+
+#### Option 1: Build-time (Docker build arg)
+
+```bash
+docker build \
+ --build-arg DISABLE_TOOLS="edit-pdf,sign-pdf,encrypt-pdf" \
+ -t bentopdf .
+```
+
+This bakes the disabled list into the JavaScript bundle. Requires a rebuild to change.
+
+#### Option 2: Runtime (config.json)
+
+Mount a `config.json` file into the served directory — no rebuild needed:
+
+```json
+{
+ "disabledTools": ["edit-pdf", "sign-pdf", "encrypt-pdf"]
+}
+```
+
+```bash
+docker run -d \
+ -p 3000:8080 \
+ -v ./config.json:/usr/share/nginx/html/config.json:ro \
+ ghcr.io/alam00000/bentopdf:latest
+```
+
+Or with Docker Compose:
+
+```yaml
+services:
+ bentopdf:
+ image: ghcr.io/alam00000/bentopdf:latest
+ ports:
+ - '3000:8080'
+ volumes:
+ - ./config.json:/usr/share/nginx/html/config.json:ro
+```
+
+Both methods can be combined — the lists are merged. If a tool appears in either, it is disabled.
+
### Custom WASM URLs (Air-Gapped / Self-Hosted)
> [!IMPORTANT]
diff --git a/docs/self-hosting/index.md b/docs/self-hosting/index.md
index 3a79e1f..d1d1f79 100644
--- a/docs/self-hosting/index.md
+++ b/docs/self-hosting/index.md
@@ -138,6 +138,34 @@ docker build \
Branding works in both full mode and Simple Mode, and can be combined with all other build-time options (`BASE_URL`, `SIMPLE_MODE`, `VITE_DEFAULT_LANGUAGE`).
+### Disabling Specific Tools
+
+Hide individual tools for compliance or security. Disabled tools are removed from the homepage, search, shortcuts, workflow builder, and direct URL access.
+
+Tool IDs are the page URL without `.html` — open any tool and look at the URL (e.g., `edit-pdf`, `sign-pdf`, `encrypt-pdf`).
+
+**Build-time** (baked into the bundle):
+
+```bash
+DISABLE_TOOLS="edit-pdf,sign-pdf" npm run build
+```
+
+**Runtime** (no rebuild needed — mount a `config.json`):
+
+```json
+{
+ "disabledTools": ["edit-pdf", "sign-pdf"]
+}
+```
+
+```bash
+docker run -d -p 3000:8080 \
+ -v ./config.json:/usr/share/nginx/html/config.json:ro \
+ ghcr.io/alam00000/bentopdf:latest
+```
+
+Both methods can be combined — the lists are merged. See the [Docker guide](/self-hosting/docker#disabling-specific-tools) for full details.
+
## Deployment Guides
Choose your platform:
diff --git a/docs/self-hosting/kubernetes.md b/docs/self-hosting/kubernetes.md
index 183ad9e..354010b 100644
--- a/docs/self-hosting/kubernetes.md
+++ b/docs/self-hosting/kubernetes.md
@@ -4,11 +4,12 @@ Kubernetes may be overkill for a static site, but it can be a great fit if you a
> [!IMPORTANT]
> **Required Headers for Office File Conversion**
->
+>
> LibreOffice-based tools (Word, Excel, PowerPoint conversion) require these HTTP headers for `SharedArrayBuffer` support:
+>
> - `Cross-Origin-Opener-Policy: same-origin`
> - `Cross-Origin-Embedder-Policy: require-corp`
->
+>
> The official BentoPDF nginx images include these headers. In Kubernetes, **Ingress/Gateway controllers are also reverse proxies**, so ensure these headers are preserved (or add them at the edge).
## Prereqs
@@ -155,3 +156,39 @@ httpRoute:
```
Support for specific filters depends on your Gateway controller; if a filter is ignored, add headers at the edge/controller layer instead.
+
+## Disabling Specific Tools
+
+Use a ConfigMap to disable tools at runtime without rebuilding the image:
+
+```yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: bentopdf-config
+ namespace: bentopdf
+data:
+ config.json: |
+ {
+ "disabledTools": ["edit-pdf", "sign-pdf", "encrypt-pdf"]
+ }
+```
+
+Mount it into the served directory:
+
+```yaml
+spec:
+ containers:
+ - name: bentopdf
+ volumeMounts:
+ - name: config
+ mountPath: /usr/share/nginx/html/config.json
+ subPath: config.json
+ readOnly: true
+ volumes:
+ - name: config
+ configMap:
+ name: bentopdf-config
+```
+
+Tool IDs are the page URL without `.html` — open any tool and look at the URL (e.g., `edit-pdf`, `merge-pdf`, `compress-pdf`). Disabled tools are hidden from the homepage, search, shortcuts, workflow builder, and direct URL access. See the [Docker guide](/self-hosting/docker#disabling-specific-tools) for the full list of options.
diff --git a/public/locales/ar/common.json b/public/locales/ar/common.json
index 133e022..693b1a7 100644
--- a/public/locales/ar/common.json
+++ b/public/locales/ar/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "أدوات PDF",
"subtitle": "اختر أداة للبدء"
+ },
+ "disabledTool": {
+ "title": "الأداة غير متاحة",
+ "heading": "هذه الأداة معطّلة",
+ "message": "هذه الأداة غير متوفرة في بيئة النشر الخاصة بك. تواصل مع المسؤول للحصول على مزيد من المعلومات.",
+ "backHome": "العودة إلى الرئيسية"
}
}
diff --git a/public/locales/be/common.json b/public/locales/be/common.json
index 3161429..67c94ee 100644
--- a/public/locales/be/common.json
+++ b/public/locales/be/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "Інструменты PDF",
"subtitle": "Выберыце інструмент, каб пачаць"
+ },
+ "disabledTool": {
+ "title": "Інструмент недаступны",
+ "heading": "Гэты інструмент адключаны",
+ "message": "Гэты інструмент недаступны ў вашым разгортванні. Звяжыцеся з адміністратарам для атрымання дадатковай інфармацыі.",
+ "backHome": "Вярнуцца на галоўную"
}
}
diff --git a/public/locales/da/common.json b/public/locales/da/common.json
index 6710815..68836e3 100644
--- a/public/locales/da/common.json
+++ b/public/locales/da/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "PDF-værktøjer",
"subtitle": "Vælg et værktøj for at komme i gang"
+ },
+ "disabledTool": {
+ "title": "Værktøj utilgængeligt",
+ "heading": "Dette værktøj er deaktiveret",
+ "message": "Dette værktøj er ikke tilgængeligt i din installation. Kontakt din administrator for yderligere oplysninger.",
+ "backHome": "Tilbage til forsiden"
}
}
diff --git a/public/locales/de/common.json b/public/locales/de/common.json
index 3c342e8..b24e2da 100644
--- a/public/locales/de/common.json
+++ b/public/locales/de/common.json
@@ -362,5 +362,11 @@
"simpleMode": {
"title": "PDF-Werkzeuge",
"subtitle": "Wählen Sie ein Werkzeug aus, um zu beginnen"
+ },
+ "disabledTool": {
+ "title": "Werkzeug nicht verfügbar",
+ "heading": "Dieses Werkzeug wurde deaktiviert",
+ "message": "Dieses Werkzeug ist in Ihrer Installation nicht verfügbar. Wenden Sie sich an Ihren Administrator, um weitere Informationen zu erhalten.",
+ "backHome": "Zurück zur Startseite"
}
}
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index c66aebd..0d9b28f 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -363,5 +363,11 @@
"simpleMode": {
"title": "PDF Tools",
"subtitle": "Select a tool to get started"
+ },
+ "disabledTool": {
+ "title": "Tool Unavailable",
+ "heading": "This tool has been disabled",
+ "message": "This tool is not available in your deployment. Contact your administrator for more information.",
+ "backHome": "Back to Home"
}
}
diff --git a/public/locales/es/common.json b/public/locales/es/common.json
index 690ba7b..039d1ae 100644
--- a/public/locales/es/common.json
+++ b/public/locales/es/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "Herramientas PDF",
"subtitle": "Selecciona una herramienta para comenzar"
+ },
+ "disabledTool": {
+ "title": "Herramienta no disponible",
+ "heading": "Esta herramienta ha sido desactivada",
+ "message": "Esta herramienta no está disponible en tu instalación. Contacta con tu administrador para obtener más información.",
+ "backHome": "Volver al inicio"
}
}
diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json
index cbd7211..16aa178 100644
--- a/public/locales/fr/common.json
+++ b/public/locales/fr/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "Outils PDF",
"subtitle": "Sélectionnez un outil pour commencer"
+ },
+ "disabledTool": {
+ "title": "Outil indisponible",
+ "heading": "Cet outil a été désactivé",
+ "message": "Cet outil n'est pas disponible dans votre déploiement. Contactez votre administrateur pour plus d'informations.",
+ "backHome": "Retour à l'accueil"
}
}
diff --git a/public/locales/id/common.json b/public/locales/id/common.json
index f178594..1956687 100644
--- a/public/locales/id/common.json
+++ b/public/locales/id/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "Alat PDF",
"subtitle": "Pilih alat untuk memulai"
+ },
+ "disabledTool": {
+ "title": "Alat Tidak Tersedia",
+ "heading": "Alat ini telah dinonaktifkan",
+ "message": "Alat ini tidak tersedia dalam penerapan Anda. Hubungi administrator Anda untuk informasi lebih lanjut.",
+ "backHome": "Kembali ke Beranda"
}
}
diff --git a/public/locales/it/common.json b/public/locales/it/common.json
index e938a8a..c72f4d8 100644
--- a/public/locales/it/common.json
+++ b/public/locales/it/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "Strumenti PDF",
"subtitle": "Seleziona uno strumento per iniziare"
+ },
+ "disabledTool": {
+ "title": "Strumento Non Disponibile",
+ "heading": "Questo strumento è stato disabilitato",
+ "message": "Questo strumento non è disponibile nella tua distribuzione. Contatta il tuo amministratore per ulteriori informazioni.",
+ "backHome": "Torna alla Home"
}
}
diff --git a/public/locales/ko/common.json b/public/locales/ko/common.json
index bbe93bd..6beed76 100644
--- a/public/locales/ko/common.json
+++ b/public/locales/ko/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "PDF 도구",
"subtitle": "사용할 도구를 선택하세요"
+ },
+ "disabledTool": {
+ "title": "도구를 사용할 수 없음",
+ "heading": "이 도구는 비활성화되었습니다",
+ "message": "이 도구는 현재 배포 환경에서 사용할 수 없습니다. 자세한 내용은 관리자에게 문의하세요.",
+ "backHome": "홈으로 돌아가기"
}
}
diff --git a/public/locales/nl/common.json b/public/locales/nl/common.json
index ba30d98..2dc6027 100644
--- a/public/locales/nl/common.json
+++ b/public/locales/nl/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "PDF-tools",
"subtitle": "Selecteer een tool om te beginnen"
+ },
+ "disabledTool": {
+ "title": "Tool Niet Beschikbaar",
+ "heading": "Deze tool is uitgeschakeld",
+ "message": "Deze tool is niet beschikbaar in uw implementatie. Neem contact op met uw beheerder voor meer informatie.",
+ "backHome": "Terug naar Home"
}
}
diff --git a/public/locales/pt/common.json b/public/locales/pt/common.json
index 632ebb9..0f4ac7d 100644
--- a/public/locales/pt/common.json
+++ b/public/locales/pt/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "Ferramentas PDF",
"subtitle": "Selecione uma ferramenta para começar"
+ },
+ "disabledTool": {
+ "title": "Ferramenta Indisponível",
+ "heading": "Esta ferramenta foi desativada",
+ "message": "Esta ferramenta não está disponível na sua implantação. Entre em contato com o seu administrador para mais informações.",
+ "backHome": "Voltar para o Início"
}
}
diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json
index 54e05f5..ef82a2b 100644
--- a/public/locales/ru/common.json
+++ b/public/locales/ru/common.json
@@ -357,5 +357,11 @@
"errorRendering": "Не удалось отрисовать миниатюры страниц",
"error": "Ошибка",
"failedToLoad": "Не удалось загрузить"
+ },
+ "disabledTool": {
+ "title": "Инструмент недоступен",
+ "heading": "Этот инструмент отключён",
+ "message": "Этот инструмент недоступен в вашей конфигурации. Обратитесь к администратору для получения дополнительной информации.",
+ "backHome": "На главную"
}
}
diff --git a/public/locales/sv/common.json b/public/locales/sv/common.json
index a63647d..a602899 100644
--- a/public/locales/sv/common.json
+++ b/public/locales/sv/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "PDF-verktyg",
"subtitle": "Välj ett verktyg för att komma igång"
+ },
+ "disabledTool": {
+ "title": "Verktyget är inte tillgängligt",
+ "heading": "Det här verktyget har inaktiverats",
+ "message": "Det här verktyget är inte tillgängligt i din installation. Kontakta din administratör för mer information.",
+ "backHome": "Tillbaka till startsidan"
}
}
diff --git a/public/locales/tr/common.json b/public/locales/tr/common.json
index ca6fceb..3d32b95 100644
--- a/public/locales/tr/common.json
+++ b/public/locales/tr/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "PDF Araçları",
"subtitle": "Başlamak için bir araç seçin"
+ },
+ "disabledTool": {
+ "title": "Araç Kullanılamıyor",
+ "heading": "Bu araç devre dışı bırakıldı",
+ "message": "Bu araç, dağıtımınızda mevcut değil. Daha fazla bilgi için yöneticinizle iletişime geçin.",
+ "backHome": "Ana Sayfaya Dön"
}
}
diff --git a/public/locales/vi/common.json b/public/locales/vi/common.json
index 0a57f66..3ee1a28 100644
--- a/public/locales/vi/common.json
+++ b/public/locales/vi/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "Công cụ PDF",
"subtitle": "Chọn một công cụ để bắt đầu"
+ },
+ "disabledTool": {
+ "title": "Công cụ không khả dụng",
+ "heading": "Công cụ này đã bị vô hiệu hóa",
+ "message": "Công cụ này không có sẵn trong môi trường triển khai của bạn. Vui lòng liên hệ quản trị viên để biết thêm thông tin.",
+ "backHome": "Quay về trang chủ"
}
}
diff --git a/public/locales/zh-TW/common.json b/public/locales/zh-TW/common.json
index 7b10dc4..6d372a8 100644
--- a/public/locales/zh-TW/common.json
+++ b/public/locales/zh-TW/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "PDF 工具",
"subtitle": "選擇一個工具開始使用"
+ },
+ "disabledTool": {
+ "title": "工具無法使用",
+ "heading": "此工具已被停用",
+ "message": "此工具在您的部署環境中無法使用。請聯絡管理員以取得更多資訊。",
+ "backHome": "返回首頁"
}
}
diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json
index a3b76bd..8aa2583 100644
--- a/public/locales/zh/common.json
+++ b/public/locales/zh/common.json
@@ -361,5 +361,11 @@
"simpleMode": {
"title": "PDF 工具",
"subtitle": "选择一个工具开始使用"
+ },
+ "disabledTool": {
+ "title": "工具不可用",
+ "heading": "此工具已被禁用",
+ "message": "此工具在您的部署环境中不可用。请联系管理员以获取更多信息。",
+ "backHome": "返回首页"
}
}
diff --git a/src/js/logic/pdf-workflow-page.ts b/src/js/logic/pdf-workflow-page.ts
index 7bac637..1a6e59c 100644
--- a/src/js/logic/pdf-workflow-page.ts
+++ b/src/js/logic/pdf-workflow-page.ts
@@ -7,6 +7,7 @@ import {
getNodesByCategory,
createNodeByType,
} from '../workflow/nodes/registry';
+import { isToolDisabled } from '../utils/disabled-tools.js';
import type { BaseWorkflowNode } from '../workflow/nodes/base-node';
import type { WorkflowEditor } from '../workflow/editor';
import {
@@ -447,7 +448,9 @@ function buildToolbox() {
];
for (const cat of categoryOrder) {
- const entries = categorized[cat.key as keyof typeof categorized] ?? [];
+ const entries = (
+ categorized[cat.key as keyof typeof categorized] ?? []
+ ).filter((entry) => !entry.toolPageId || !isToolDisabled(entry.toolPageId));
if (entries.length === 0) continue;
const section = document.createElement('div');
diff --git a/src/js/main.ts b/src/js/main.ts
index a20e7de..50458f2 100644
--- a/src/js/main.ts
+++ b/src/js/main.ts
@@ -15,13 +15,38 @@ import {
createLanguageSwitcher,
t,
} from './i18n/index.js';
+import {
+ loadRuntimeConfig,
+ isToolDisabled,
+ isCurrentPageDisabled,
+} from './utils/disabled-tools.js';
declare const __BRAND_NAME__: string;
const init = async () => {
await initI18n();
+ await loadRuntimeConfig();
injectLanguageSwitcher();
applyTranslations();
+ if (isCurrentPageDisabled()) {
+ document.title = t('disabledTool.title') || 'Tool Unavailable';
+ const main = document.querySelector('main') || document.body;
+ const heading = t('disabledTool.heading') || 'This tool has been disabled';
+ const message =
+ t('disabledTool.message') ||
+ 'This tool is not available in your deployment. Contact your administrator for more information.';
+ const backHome = t('disabledTool.backHome') || 'Back to Home';
+ main.innerHTML = `
+
+
+
${heading}
+
${message}
+
${backHome}
+
+ `;
+ return;
+ }
+
pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url
@@ -275,7 +300,14 @@ const init = async () => {
);
}
- categories.forEach((category) => {
+ const filteredCategories = categories
+ .map((category) => ({
+ ...category,
+ tools: category.tools.filter((tool) => !isToolDisabled(tool.id)),
+ }))
+ .filter((category) => category.tools.length > 0);
+
+ filteredCategories.forEach((category) => {
const categoryGroup = document.createElement('div');
categoryGroup.className = 'category-group col-span-full';
@@ -872,16 +904,21 @@ const init = async () => {
const allShortcuts = ShortcutsManager.getAllShortcuts();
const isMac = navigator.userAgent.toUpperCase().includes('MAC');
- const allTools = categories.flatMap((c) => c.tools);
+ const shortcutCategories = categories
+ .map((category) => ({
+ ...category,
+ tools: category.tools.filter((tool) => !isToolDisabled(tool.id)),
+ }))
+ .filter((category) => category.tools.length > 0);
+ const allTools = shortcutCategories.flatMap((c) => c.tools);
- categories.forEach((category) => {
+ shortcutCategories.forEach((category) => {
const section = document.createElement('div');
section.className = 'category-section mb-6 last:mb-0';
const header = document.createElement('h3');
header.className =
'text-gray-400 text-xs font-bold uppercase tracking-wider mb-3 pl-1';
- // Translate category name
const categoryKey = categoryTranslationKeys[category.name];
header.textContent = categoryKey ? t(categoryKey) : category.name;
section.appendChild(header);
diff --git a/src/js/types/config-types.ts b/src/js/types/config-types.ts
new file mode 100644
index 0000000..40c29c5
--- /dev/null
+++ b/src/js/types/config-types.ts
@@ -0,0 +1,3 @@
+export interface AppConfig {
+ disabledTools?: string[];
+}
diff --git a/src/js/types/index.ts b/src/js/types/index.ts
index b859335..acd03cd 100644
--- a/src/js/types/index.ts
+++ b/src/js/types/index.ts
@@ -55,3 +55,4 @@ export * from './add-page-labels-type.ts';
export * from './pdf-to-tiff-type.ts';
export * from './pdf-to-cbz-type.ts';
export * from './password-prompt-type.ts';
+export * from './config-types.ts';
diff --git a/src/js/utils/disabled-tools.ts b/src/js/utils/disabled-tools.ts
new file mode 100644
index 0000000..a70491d
--- /dev/null
+++ b/src/js/utils/disabled-tools.ts
@@ -0,0 +1,43 @@
+import type { AppConfig } from '@/types';
+
+const disabledToolsSet = new Set(__DISABLED_TOOLS__);
+let runtimeConfigLoaded = false;
+
+export async function loadRuntimeConfig(): Promise {
+ if (runtimeConfigLoaded) return;
+ runtimeConfigLoaded = true;
+
+ try {
+ const response = await fetch(`${import.meta.env.BASE_URL}config.json`, {
+ cache: 'no-cache',
+ });
+ if (!response.ok) return;
+
+ const config: AppConfig = await response.json();
+ if (Array.isArray(config.disabledTools)) {
+ for (const toolId of config.disabledTools) {
+ if (typeof toolId === 'string') {
+ disabledToolsSet.add(toolId);
+ }
+ }
+ }
+ } catch {}
+}
+
+export function isToolDisabled(toolId: string): boolean {
+ return disabledToolsSet.has(toolId);
+}
+
+export function getToolIdFromPath(): string | null {
+ const path = window.location.pathname;
+ const withExt = path.match(/\/([^/]+)\.html$/);
+ if (withExt) return withExt[1];
+ const withoutExt = path.match(/\/([^/]+)\/?$/);
+ return withoutExt?.[1] ?? null;
+}
+
+export function isCurrentPageDisabled(): boolean {
+ const toolId = getToolIdFromPath();
+ if (!toolId) return false;
+ return isToolDisabled(toolId);
+}
diff --git a/src/js/workflow/nodes/registry.ts b/src/js/workflow/nodes/registry.ts
index 2fdfa67..10dd6a6 100644
--- a/src/js/workflow/nodes/registry.ts
+++ b/src/js/workflow/nodes/registry.ts
@@ -80,6 +80,7 @@ export interface NodeRegistryEntry {
description: string;
factory: () => BaseWorkflowNode;
hidden?: boolean;
+ toolPageId?: string;
}
export const nodeRegistry: Record = {
@@ -96,6 +97,7 @@ export const nodeRegistry: Record = {
icon: 'ph-image',
description: 'Upload images and convert to PDF',
factory: () => new ImageInputNode(),
+ toolPageId: 'image-to-pdf',
},
WordToPdfNode: {
label: 'Word to PDF',
@@ -103,6 +105,7 @@ export const nodeRegistry: Record = {
icon: 'ph-microsoft-word-logo',
description: 'Convert Word documents to PDF',
factory: () => new WordToPdfNode(),
+ toolPageId: 'word-to-pdf',
},
ExcelToPdfNode: {
label: 'Excel to PDF',
@@ -110,6 +113,7 @@ export const nodeRegistry: Record = {
icon: 'ph-microsoft-excel-logo',
description: 'Convert Excel spreadsheets to PDF',
factory: () => new ExcelToPdfNode(),
+ toolPageId: 'excel-to-pdf',
},
PowerPointToPdfNode: {
label: 'PowerPoint to PDF',
@@ -117,6 +121,7 @@ export const nodeRegistry: Record = {
icon: 'ph-microsoft-powerpoint-logo',
description: 'Convert PowerPoint presentations to PDF',
factory: () => new PowerPointToPdfNode(),
+ toolPageId: 'powerpoint-to-pdf',
},
TextToPdfNode: {
label: 'Text to PDF',
@@ -124,6 +129,7 @@ export const nodeRegistry: Record = {
icon: 'ph-text-t',
description: 'Convert plain text to PDF',
factory: () => new TextToPdfNode(),
+ toolPageId: 'txt-to-pdf',
},
SvgToPdfNode: {
label: 'SVG to PDF',
@@ -131,6 +137,7 @@ export const nodeRegistry: Record = {
icon: 'ph-file-svg',
description: 'Convert SVG files to PDF',
factory: () => new SvgToPdfNode(),
+ toolPageId: 'svg-to-pdf',
},
EpubToPdfNode: {
label: 'EPUB to PDF',
@@ -138,6 +145,7 @@ export const nodeRegistry: Record = {
icon: 'ph-book-open-text',
description: 'Convert EPUB ebooks to PDF',
factory: () => new EpubToPdfNode(),
+ toolPageId: 'epub-to-pdf',
},
EmailToPdfNode: {
label: 'Email to PDF',
@@ -145,6 +153,7 @@ export const nodeRegistry: Record = {
icon: 'ph-envelope',
description: 'Convert email files (.eml, .msg) to PDF',
factory: () => new EmailToPdfNode(),
+ toolPageId: 'email-to-pdf',
},
XpsToPdfNode: {
label: 'XPS to PDF',
@@ -152,6 +161,7 @@ export const nodeRegistry: Record = {
icon: 'ph-scan',
description: 'Convert XPS/OXPS documents to PDF',
factory: () => new XpsToPdfNode(),
+ toolPageId: 'xps-to-pdf',
},
MobiToPdfNode: {
label: 'MOBI to PDF',
@@ -159,6 +169,7 @@ export const nodeRegistry: Record = {
icon: 'ph-book-open-text',
description: 'Convert MOBI e-books to PDF',
factory: () => new MobiToPdfNode(),
+ toolPageId: 'mobi-to-pdf',
},
Fb2ToPdfNode: {
label: 'FB2 to PDF',
@@ -166,6 +177,7 @@ export const nodeRegistry: Record = {
icon: 'ph-book-bookmark',
description: 'Convert FB2 e-books to PDF',
factory: () => new Fb2ToPdfNode(),
+ toolPageId: 'fb2-to-pdf',
},
CbzToPdfNode: {
label: 'CBZ to PDF',
@@ -173,6 +185,7 @@ export const nodeRegistry: Record = {
icon: 'ph-book-open',
description: 'Convert comic book archives (CBZ/CBR) to PDF',
factory: () => new CbzToPdfNode(),
+ toolPageId: 'cbz-to-pdf',
},
MarkdownToPdfNode: {
label: 'Markdown to PDF',
@@ -180,6 +193,7 @@ export const nodeRegistry: Record = {
icon: 'ph-markdown-logo',
description: 'Convert Markdown files to PDF',
factory: () => new MarkdownToPdfNode(),
+ toolPageId: 'markdown-to-pdf',
},
JsonToPdfNode: {
label: 'JSON to PDF',
@@ -187,6 +201,7 @@ export const nodeRegistry: Record = {
icon: 'ph-file-code',
description: 'Convert JSON files to PDF',
factory: () => new JsonToPdfNode(),
+ toolPageId: 'json-to-pdf',
},
XmlToPdfNode: {
label: 'XML to PDF',
@@ -194,6 +209,7 @@ export const nodeRegistry: Record = {
icon: 'ph-file-code',
description: 'Convert XML documents to PDF',
factory: () => new XmlToPdfNode(),
+ toolPageId: 'xml-to-pdf',
},
WpdToPdfNode: {
label: 'WPD to PDF',
@@ -201,6 +217,7 @@ export const nodeRegistry: Record = {
icon: 'ph-file-text',
description: 'Convert WordPerfect documents to PDF',
factory: () => new WpdToPdfNode(),
+ toolPageId: 'wpd-to-pdf',
},
WpsToPdfNode: {
label: 'WPS to PDF',
@@ -208,6 +225,7 @@ export const nodeRegistry: Record = {
icon: 'ph-file-text',
description: 'Convert WPS Office documents to PDF',
factory: () => new WpsToPdfNode(),
+ toolPageId: 'wps-to-pdf',
},
PagesToPdfNode: {
label: 'Pages to PDF',
@@ -215,6 +233,7 @@ export const nodeRegistry: Record = {
icon: 'ph-file-text',
description: 'Convert Apple Pages documents to PDF',
factory: () => new PagesToPdfNode(),
+ toolPageId: 'pages-to-pdf',
},
OdgToPdfNode: {
label: 'ODG to PDF',
@@ -222,6 +241,7 @@ export const nodeRegistry: Record = {
icon: 'ph-image',
description: 'Convert OpenDocument Graphics to PDF',
factory: () => new OdgToPdfNode(),
+ toolPageId: 'odg-to-pdf',
},
PubToPdfNode: {
label: 'PUB to PDF',
@@ -229,6 +249,7 @@ export const nodeRegistry: Record = {
icon: 'ph-book-open',
description: 'Convert Microsoft Publisher to PDF',
factory: () => new PubToPdfNode(),
+ toolPageId: 'pub-to-pdf',
},
VsdToPdfNode: {
label: 'VSD to PDF',
@@ -236,6 +257,7 @@ export const nodeRegistry: Record = {
icon: 'ph-git-branch',
description: 'Convert Visio diagrams (VSD/VSDX) to PDF',
factory: () => new VsdToPdfNode(),
+ toolPageId: 'vsd-to-pdf',
},
MergeNode: {
label: 'Merge PDFs',
@@ -243,6 +265,7 @@ export const nodeRegistry: Record = {
icon: 'ph-browsers',
description: 'Combine multiple PDFs into one',
factory: () => new MergeNode(),
+ toolPageId: 'merge-pdf',
},
SplitNode: {
label: 'Split PDF',
@@ -250,6 +273,7 @@ export const nodeRegistry: Record = {
icon: 'ph-scissors',
description: 'Extract a range of pages',
factory: () => new SplitNode(),
+ toolPageId: 'split-pdf',
},
ExtractPagesNode: {
label: 'Extract Pages',
@@ -257,6 +281,7 @@ export const nodeRegistry: Record = {
icon: 'ph-squares-four',
description: 'Extract pages as separate PDFs',
factory: () => new ExtractPagesNode(),
+ toolPageId: 'extract-pages',
},
RotateNode: {
label: 'Rotate',
@@ -264,6 +289,7 @@ export const nodeRegistry: Record = {
icon: 'ph-arrow-clockwise',
description: 'Rotate all pages',
factory: () => new RotateNode(),
+ toolPageId: 'rotate-pdf',
},
DeletePagesNode: {
label: 'Delete Pages',
@@ -271,6 +297,7 @@ export const nodeRegistry: Record = {
icon: 'ph-trash',
description: 'Remove specific pages',
factory: () => new DeletePagesNode(),
+ toolPageId: 'delete-pages',
},
ReversePagesNode: {
label: 'Reverse Pages',
@@ -278,6 +305,7 @@ export const nodeRegistry: Record = {
icon: 'ph-sort-descending',
description: 'Reverse page order',
factory: () => new ReversePagesNode(),
+ toolPageId: 'reverse-pages',
},
AddBlankPageNode: {
label: 'Add Blank Page',
@@ -285,6 +313,7 @@ export const nodeRegistry: Record = {
icon: 'ph-file-plus',
description: 'Insert blank pages',
factory: () => new AddBlankPageNode(),
+ toolPageId: 'add-blank-page',
},
DividePagesNode: {
label: 'Divide Pages',
@@ -292,6 +321,7 @@ export const nodeRegistry: Record = {
icon: 'ph-columns',
description: 'Split pages vertically or horizontally',
factory: () => new DividePagesNode(),
+ toolPageId: 'divide-pages',
},
NUpNode: {
label: 'N-Up',
@@ -299,6 +329,7 @@ export const nodeRegistry: Record = {
icon: 'ph-squares-four',
description: 'Arrange multiple pages per sheet',
factory: () => new NUpNode(),
+ toolPageId: 'n-up-pdf',
},
FixPageSizeNode: {
label: 'Fix Page Size',
@@ -306,6 +337,7 @@ export const nodeRegistry: Record = {
icon: 'ph-frame-corners',
description: 'Standardize all pages to a target size',
factory: () => new FixPageSizeNode(),
+ toolPageId: 'fix-page-size',
},
CombineSinglePageNode: {
label: 'Combine to Single Page',
@@ -313,6 +345,7 @@ export const nodeRegistry: Record = {
icon: 'ph-arrows-out-line-vertical',
description: 'Stitch all pages into one continuous page',
factory: () => new CombineSinglePageNode(),
+ toolPageId: 'combine-single-page',
},
BookletNode: {
label: 'Booklet',
@@ -320,6 +353,7 @@ export const nodeRegistry: Record = {
icon: 'ph-book-open',
description: 'Arrange pages for booklet printing',
factory: () => new BookletNode(),
+ toolPageId: 'pdf-booklet',
},
PosterizeNode: {
label: 'Posterize',
@@ -327,6 +361,7 @@ export const nodeRegistry: Record = {
icon: 'ph-notepad',
description: 'Split pages into tile grid for poster printing',
factory: () => new PosterizeNode(),
+ toolPageId: 'posterize-pdf',
},
EditMetadataNode: {
label: 'Edit Metadata',
@@ -334,6 +369,7 @@ export const nodeRegistry: Record = {
icon: 'ph-file-code',
description: 'Edit PDF metadata',
factory: () => new EditMetadataNode(),
+ toolPageId: 'edit-metadata',
},
TableOfContentsNode: {
label: 'Table of Contents',
@@ -341,6 +377,7 @@ export const nodeRegistry: Record = {
icon: 'ph-list',
description: 'Generate table of contents from bookmarks',
factory: () => new TableOfContentsNode(),
+ toolPageId: 'table-of-contents',
},
OCRNode: {
label: 'OCR',
@@ -348,6 +385,7 @@ export const nodeRegistry: Record = {
icon: 'ph-barcode',
description: 'Add searchable text layer via OCR',
factory: () => new OCRNode(),
+ toolPageId: 'ocr-pdf',
},
CropNode: {
label: 'Crop',
@@ -355,6 +393,7 @@ export const nodeRegistry: Record = {
icon: 'ph-crop',
description: 'Trim margins from all pages',
factory: () => new CropNode(),
+ toolPageId: 'crop-pdf',
},
GreyscaleNode: {
label: 'Greyscale',
@@ -362,6 +401,7 @@ export const nodeRegistry: Record = {
icon: 'ph-palette',
description: 'Convert to greyscale',
factory: () => new GreyscaleNode(),
+ toolPageId: 'pdf-to-greyscale',
},
InvertColorsNode: {
label: 'Invert Colors',
@@ -369,6 +409,7 @@ export const nodeRegistry: Record = {
icon: 'ph-circle-half',
description: 'Invert all colors',
factory: () => new InvertColorsNode(),
+ toolPageId: 'invert-colors',
},
ScannerEffectNode: {
label: 'Scanner Effect',
@@ -376,6 +417,7 @@ export const nodeRegistry: Record = {
icon: 'ph-scan',
description: 'Apply scanner simulation effect',
factory: () => new ScannerEffectNode(),
+ toolPageId: 'scanner-effect',
},
AdjustColorsNode: {
label: 'Adjust Colors',
@@ -383,6 +425,7 @@ export const nodeRegistry: Record = {
icon: 'ph-sliders-horizontal',
description: 'Adjust brightness, contrast, and colors',
factory: () => new AdjustColorsNode(),
+ toolPageId: 'adjust-colors',
},
BackgroundColorNode: {
label: 'Background Color',
@@ -390,6 +433,7 @@ export const nodeRegistry: Record = {
icon: 'ph-palette',
description: 'Change background color',
factory: () => new BackgroundColorNode(),
+ toolPageId: 'background-color',
},
WatermarkNode: {
label: 'Watermark',
@@ -397,6 +441,7 @@ export const nodeRegistry: Record = {
icon: 'ph-drop',
description: 'Add text watermark',
factory: () => new WatermarkNode(),
+ toolPageId: 'add-watermark',
},
PageNumbersNode: {
label: 'Page Numbers',
@@ -404,6 +449,7 @@ export const nodeRegistry: Record = {
icon: 'ph-list-numbers',
description: 'Add page numbers',
factory: () => new PageNumbersNode(),
+ toolPageId: 'page-numbers',
},
HeaderFooterNode: {
label: 'Header & Footer',
@@ -411,6 +457,7 @@ export const nodeRegistry: Record = {
icon: 'ph-paragraph',
description: 'Add header and footer text',
factory: () => new HeaderFooterNode(),
+ toolPageId: 'header-footer',
},
RemoveBlankPagesNode: {
label: 'Remove Blank Pages',
@@ -418,6 +465,7 @@ export const nodeRegistry: Record = {
icon: 'ph-file-minus',
description: 'Remove blank pages automatically',
factory: () => new RemoveBlankPagesNode(),
+ toolPageId: 'remove-blank-pages',
},
RemoveAnnotationsNode: {
label: 'Remove Annotations',
@@ -425,6 +473,7 @@ export const nodeRegistry: Record = {
icon: 'ph-eraser',
description: 'Strip all annotations',
factory: () => new RemoveAnnotationsNode(),
+ toolPageId: 'remove-annotations',
},
CompressNode: {
label: 'Compress',
@@ -432,6 +481,7 @@ export const nodeRegistry: Record = {
icon: 'ph-lightning',
description: 'Reduce PDF file size',
factory: () => new CompressNode(),
+ toolPageId: 'compress-pdf',
},
RasterizeNode: {
label: 'Rasterize',
@@ -439,6 +489,7 @@ export const nodeRegistry: Record = {
icon: 'ph-image',
description: 'Convert to image-based PDF',
factory: () => new RasterizeNode(),
+ toolPageId: 'rasterize-pdf',
},
LinearizeNode: {
label: 'Linearize',
@@ -446,6 +497,7 @@ export const nodeRegistry: Record = {
icon: 'ph-gauge',
description: 'Optimize PDF for fast web viewing',
factory: () => new LinearizeNode(),
+ toolPageId: 'linearize-pdf',
},
DeskewNode: {
label: 'Deskew',
@@ -453,6 +505,7 @@ export const nodeRegistry: Record = {
icon: 'ph-perspective',
description: 'Straighten skewed PDF pages',
factory: () => new DeskewNode(),
+ toolPageId: 'deskew-pdf',
},
PdfToPdfANode: {
label: 'PDF to PDF/A',
@@ -460,6 +513,7 @@ export const nodeRegistry: Record = {
icon: 'ph-archive',
description: 'Convert PDF to PDF/A for archiving',
factory: () => new PdfToPdfANode(),
+ toolPageId: 'pdf-to-pdfa',
},
FontToOutlineNode: {
label: 'Font to Outline',
@@ -467,6 +521,7 @@ export const nodeRegistry: Record = {
icon: 'ph-text-outdent',
description: 'Convert fonts to vector outlines',
factory: () => new FontToOutlineNode(),
+ toolPageId: 'font-to-outline',
},
RepairNode: {
label: 'Repair',
@@ -474,6 +529,7 @@ export const nodeRegistry: Record = {
icon: 'ph-wrench',
description: 'Repair corrupted PDF',
factory: () => new RepairNode(),
+ toolPageId: 'repair-pdf',
},
EncryptNode: {
label: 'Encrypt',
@@ -481,6 +537,7 @@ export const nodeRegistry: Record = {
icon: 'ph-lock',
description: 'Encrypt PDF with password',
factory: () => new EncryptNode(),
+ toolPageId: 'encrypt-pdf',
},
DecryptNode: {
label: 'Decrypt',
@@ -488,6 +545,7 @@ export const nodeRegistry: Record = {
icon: 'ph-lock-open',
description: 'Remove PDF password protection',
factory: () => new DecryptNode(),
+ toolPageId: 'decrypt-pdf',
},
SanitizeNode: {
label: 'Sanitize',
@@ -495,6 +553,7 @@ export const nodeRegistry: Record = {
icon: 'ph-broom',
description: 'Remove metadata, scripts, and hidden data',
factory: () => new SanitizeNode(),
+ toolPageId: 'sanitize-pdf',
},
FlattenNode: {
label: 'Flatten',
@@ -502,6 +561,7 @@ export const nodeRegistry: Record = {
icon: 'ph-stack',
description: 'Flatten forms and annotations',
factory: () => new FlattenNode(),
+ toolPageId: 'flatten-pdf',
},
DigitalSignNode: {
label: 'Digital Sign',
@@ -509,6 +569,7 @@ export const nodeRegistry: Record = {
icon: 'ph-certificate',
description: 'Apply a digital signature to PDF',
factory: () => new DigitalSignNode(),
+ toolPageId: 'digital-sign-pdf',
},
TimestampNode: {
label: 'Timestamp',
@@ -516,6 +577,7 @@ export const nodeRegistry: Record = {
icon: 'ph-clock',
description: 'Add an RFC 3161 document timestamp',
factory: () => new TimestampNode(),
+ toolPageId: 'timestamp-pdf',
},
RedactNode: {
label: 'Redact',
@@ -523,6 +585,7 @@ export const nodeRegistry: Record = {
icon: 'ph-eye-slash',
description: 'Redact text from PDF',
factory: () => new RedactNode(),
+ toolPageId: 'edit-pdf',
},
DownloadNode: {
label: 'Download',
@@ -554,6 +617,7 @@ export const nodeRegistry: Record = {
icon: 'ph-file-image',
description: 'Convert PDF pages to images (ZIP)',
factory: () => new PdfToImagesNode(),
+ toolPageId: 'pdf-to-jpg',
},
PdfToTextNode: {
label: 'PDF to Text',
@@ -561,6 +625,7 @@ export const nodeRegistry: Record = {
icon: 'ph-text-aa',
description: 'Extract text from PDF',
factory: () => new PdfToTextNode(),
+ toolPageId: 'pdf-to-text',
},
PdfToDocxNode: {
label: 'PDF to DOCX',
@@ -568,6 +633,7 @@ export const nodeRegistry: Record = {
icon: 'ph-microsoft-word-logo',
description: 'Convert PDF to Word document',
factory: () => new PdfToDocxNode(),
+ toolPageId: 'pdf-to-docx',
},
PdfToXlsxNode: {
label: 'PDF to XLSX',
@@ -575,6 +641,7 @@ export const nodeRegistry: Record = {
icon: 'ph-microsoft-excel-logo',
description: 'Convert PDF tables to Excel',
factory: () => new PdfToXlsxNode(),
+ toolPageId: 'pdf-to-excel',
},
PdfToCsvNode: {
label: 'PDF to CSV',
@@ -582,6 +649,7 @@ export const nodeRegistry: Record = {
icon: 'ph-file-csv',
description: 'Convert PDF tables to CSV',
factory: () => new PdfToCsvNode(),
+ toolPageId: 'pdf-to-csv',
},
PdfToSvgNode: {
label: 'PDF to SVG',
@@ -589,6 +657,7 @@ export const nodeRegistry: Record = {
icon: 'ph-file-code',
description: 'Convert PDF pages to SVG',
factory: () => new PdfToSvgNode(),
+ toolPageId: 'pdf-to-svg',
},
PdfToMarkdownNode: {
label: 'PDF to Markdown',
@@ -596,6 +665,7 @@ export const nodeRegistry: Record = {
icon: 'ph-markdown-logo',
description: 'Convert PDF to Markdown text',
factory: () => new PdfToMarkdownNode(),
+ toolPageId: 'pdf-to-markdown',
},
ExtractImagesNode: {
label: 'Extract Images',
@@ -603,6 +673,7 @@ export const nodeRegistry: Record = {
icon: 'ph-download-simple',
description: 'Extract all images from PDF',
factory: () => new ExtractImagesNode(),
+ toolPageId: 'extract-images',
},
};
diff --git a/src/types/globals.d.ts b/src/types/globals.d.ts
index aee6f2f..e2b983e 100644
--- a/src/types/globals.d.ts
+++ b/src/types/globals.d.ts
@@ -13,3 +13,4 @@ interface ImportMeta {
}
declare const __SIMPLE_MODE__: boolean;
+declare const __DISABLED_TOOLS__: string[];
diff --git a/vite.config.ts b/vite.config.ts
index f193aa7..1f8e3af 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -420,6 +420,12 @@ export default defineConfig(() => {
define: {
__SIMPLE_MODE__: JSON.stringify(process.env.SIMPLE_MODE === 'true'),
__BRAND_NAME__: JSON.stringify(process.env.VITE_BRAND_NAME || ''),
+ __DISABLED_TOOLS__: JSON.stringify(
+ (process.env.DISABLE_TOOLS || '')
+ .split(',')
+ .map((s) => s.trim())
+ .filter(Boolean)
+ ),
},
resolve: {
alias: {