feat: add Bates numbering tool with PDF processing capabilities

- Implemented bates-numbering-page.ts for handling Bates numbering logic.
- Created a new HTML page for Bates numbering functionality.
- Added style presets and file handling for multiple PDF uploads.
- Integrated user interface elements for file selection, style customization, and preview.
- Enhanced main.ts to support collapsible categories and compact mode for tool grid.
- Updated types for Bates numbering in bates-numbering-type.ts.
- Registered the new tool in tools.html and updated routing in vite.config.ts.
This commit is contained in:
alam00000
2026-02-21 14:05:38 +05:30
parent 7313fa08a8
commit 3cae20a10c
26 changed files with 1443 additions and 21 deletions

View File

@@ -255,19 +255,78 @@ const init = async () => {
if (dom.toolGrid) {
dom.toolGrid.textContent = '';
let collapsedCategories: string[] = [];
try {
const stored = localStorage.getItem('collapsedCategories');
if (stored) collapsedCategories = JSON.parse(stored);
} catch {
localStorage.removeItem('collapsedCategories');
}
function saveCollapsedCategories() {
localStorage.setItem(
'collapsedCategories',
JSON.stringify(collapsedCategories)
);
}
categories.forEach((category) => {
const categoryGroup = document.createElement('div');
categoryGroup.className = 'category-group col-span-full';
const title = document.createElement('h2');
title.className =
'text-xl font-bold text-indigo-400 mb-4 mt-8 first:mt-0 text-white';
const header = document.createElement('button');
header.className = 'category-header';
header.type = 'button';
const title = document.createElement('span');
const categoryKey = categoryTranslationKeys[category.name];
title.textContent = categoryKey ? t(categoryKey) : category.name;
const chevron = document.createElement('i');
chevron.setAttribute('data-lucide', 'chevron-down');
chevron.className =
'category-chevron w-5 h-5 text-gray-400 transition-transform duration-300';
header.append(title, chevron);
const toolsContainer = document.createElement('div');
toolsContainer.className =
'grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4 md:gap-6';
'category-tools grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4 md:gap-6';
const isCollapsed = collapsedCategories.includes(category.name);
if (isCollapsed) {
categoryGroup.classList.add('collapsed');
toolsContainer.style.maxHeight = '0px';
}
toolsContainer.addEventListener('transitionend', (e) => {
if ((e as TransitionEvent).propertyName !== 'max-height') return;
if (!categoryGroup.classList.contains('collapsed')) {
toolsContainer.style.maxHeight = 'none';
toolsContainer.style.overflow = 'visible';
}
});
header.addEventListener('click', () => {
const collapsed = categoryGroup.classList.toggle('collapsed');
if (collapsed) {
toolsContainer.style.maxHeight = toolsContainer.scrollHeight + 'px';
toolsContainer.style.overflow = 'hidden';
requestAnimationFrame(() => {
toolsContainer.style.maxHeight = '0px';
});
if (!collapsedCategories.includes(category.name)) {
collapsedCategories.push(category.name);
}
} else {
toolsContainer.style.overflow = 'hidden';
toolsContainer.style.maxHeight = toolsContainer.scrollHeight + 'px';
collapsedCategories = collapsedCategories.filter(
(n) => n !== category.name
);
}
saveCollapsedCategories();
});
category.tools.forEach((tool) => {
let toolCard: HTMLDivElement | HTMLAnchorElement;
@@ -312,8 +371,13 @@ const init = async () => {
toolsContainer.appendChild(toolCard);
});
categoryGroup.append(title, toolsContainer);
categoryGroup.append(header, toolsContainer);
dom.toolGrid.appendChild(categoryGroup);
if (!isCollapsed) {
toolsContainer.style.maxHeight = 'none';
toolsContainer.style.overflow = 'visible';
}
});
const searchBar = document.getElementById('search-bar');
@@ -547,6 +611,35 @@ const init = async () => {
});
}
const compactModeToggle = document.getElementById(
'compact-mode-toggle'
) as HTMLInputElement;
const savedCompactMode = localStorage.getItem('compactMode') === 'true';
if (compactModeToggle) {
compactModeToggle.checked = savedCompactMode;
}
applyCompactMode(savedCompactMode);
function applyCompactMode(enabled: boolean) {
if (dom.toolGrid) {
dom.toolGrid.classList.toggle('compact-mode', enabled);
dom.toolGrid
.querySelectorAll('.category-group:not(.collapsed) .category-tools')
.forEach((container) => {
(container as HTMLElement).style.maxHeight = 'none';
});
}
}
if (compactModeToggle) {
compactModeToggle.addEventListener('change', (e) => {
const enabled = (e.target as HTMLInputElement).checked;
localStorage.setItem('compactMode', enabled.toString());
applyCompactMode(enabled);
});
}
// Shortcuts UI Handlers
if (dom.openShortcutsBtn) {
dom.openShortcutsBtn.addEventListener('click', () => {