Files
ArchiTools/docs/guides/HTML-TOOL-INTEGRATION.md
Marius Tarau 4c46e8bcdd Initial commit: ArchiTools modular dashboard platform
Complete Next.js 16 application with 13 fully implemented modules:
Email Signature, Word XML Generator, Registratura, Dashboard,
Tag Manager, IT Inventory, Address Book, Password Vault,
Mini Utilities, Prompt Generator, Digital Signatures,
Word Templates, and AI Chat.

Includes core platform systems (module registry, feature flags,
storage abstraction, i18n, theming, auth stub, tagging),
16 technical documentation files, Docker deployment config,
and legacy HTML tool reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 12:50:25 +02:00

621 lines
23 KiB
Markdown

# HTML Tool Integration Guide
How to migrate existing standalone HTML tools into React modules within the ArchiTools dashboard.
---
## Overview
ArchiTools currently has four standalone HTML files that implement useful internal tools:
| File | Purpose |
|---|---|
| `emailsignature/emailsignature-config.html` | Email signature configurator with live preview, color pickers, layout sliders, HTML export |
| `wordXMLgenerator/word-xml-generator-basic.html` | Simple Word XML Custom Part generator |
| `wordXMLgenerator/word-xml-generator-medium.html` | Extended version with Short/Upper/Lower/Initials/First field variants |
| `wordXMLgenerator/word-xml-generator-advanced.html` | Full version with categories, localStorage, simple/advanced mode, POT/CUT metrics, ZIP export |
### Why Integrate
Standalone HTML files work, but they cannot:
- Share a consistent UI theme (dark/light toggle, company branding).
- Use shared storage abstraction (configurations saved in one tool are invisible to another).
- Participate in feature flags or access control.
- Link to related data (e.g., an XML template referencing a project tag).
- Provide a unified navigation experience.
- Be tested with standard tooling (Jest, Playwright).
Integration brings these tools into the dashboard shell with shared infrastructure while preserving all existing functionality.
---
## Migration Strategy
Migration happens in three phases. Each phase produces a working state -- there is no "big bang" cutover.
### Phase 1: Embed (Temporary Bridge)
Wrap the existing HTML file in an `<iframe>` inside a dashboard page. This gives immediate navigation integration with zero rewrite.
```tsx
// src/modules/email-signature/pages/email-signature-page.tsx (Phase 1 only)
export function EmailSignaturePage() {
return (
<div className="h-[calc(100vh-3.5rem)]">
<iframe
src="/legacy/emailsignature-config.html"
className="w-full h-full border-0"
title="Email Signature Configurator"
/>
</div>
);
}
```
**When to use Phase 1:**
- When a tool needs to appear in the sidebar immediately but rewrite resources are not available.
- As a fallback during Phase 2 development (iframe stays live while React version is being built).
**Limitations:**
- No theme synchronization (iframe has its own styles).
- No shared state between iframe and parent.
- No storage abstraction.
- Content Security Policy may block certain CDN scripts.
**Phase 1 is not recommended as a long-term solution.** Move to Phase 2 as soon as practical.
### Phase 2: Extract
Pull JavaScript logic out of the HTML files into typed TypeScript hooks and utility functions. Build a React UI that replaces the HTML structure.
This is where the bulk of the work happens. The goal is functional parity with the original tool, running inside the React component tree with proper state management.
Detailed extraction plans for each tool are in the sections below.
### Phase 3: Normalize
With React UI in place, integrate with platform-level features:
- **Storage abstraction**: Save/load configurations through the shared storage layer instead of raw `localStorage`.
- **Theming**: All colors respond to dark/light toggle and company accent.
- **Tagging**: Link generated artifacts to project tags from the tag manager.
- **Feature flags**: Gate experimental features behind flags.
- **Company context**: Tool behavior adapts to the selected company (logo, colors, address, namespace).
- **Cross-module linking**: An XML template can reference a project; a signature config can link to a company profile.
---
## Email Signature Generator -- Migration Plan
### Current State Analysis
The existing `emailsignature-config.html` contains:
1. **Data inputs**: prefix, name, title, phone (4 text fields).
2. **Color picker system**: 7 color targets (prefix, name, title, address, phone, website, motto) with 4 swatch options each (Beletage brand palette).
3. **Layout sliders**: 8 range inputs controlling pixel-level spacing (green line width, section spacing, logo spacing, title spacing, gutter alignment, icon-text spacing, icon vertical position, motto spacing).
4. **Options**: 3 checkboxes (reply variant, super-reply variant, SVG images).
5. **Signature HTML template builder**: `generateSignatureHTML(data)` function producing a table-based email signature.
6. **Phone formatter**: Converts `07xxxxxxxx` to `+40 xxx xxx xxx` format.
7. **Live preview**: Real-time DOM update on any input change.
8. **Export**: Downloads the signature HTML as a file.
9. **Zoom toggle**: 100%/200% preview scaling.
10. **Collapsible sections**: Manual accordion implementation.
Everything is Beletage-specific: logo URL, address, website, motto, brand colors.
### Extraction Plan
#### Hook: `useSignatureBuilder`
Encapsulates the signature generation logic.
```
Source: generateSignatureHTML() function (lines 280-361)
Target: src/modules/email-signature/hooks/use-signature-builder.ts
Responsibilities:
- Accept SignatureConfig object (all field values, colors, spacing, variant flags)
- Return generated HTML string
- Return structured SignatureData for preview rendering
- Pure computation, no side effects
Interface:
Input: SignatureConfig (typed object with all config fields)
Output: { html: string; previewData: SignatureData }
```
#### Hook: `useSignatureExport`
Handles file download and clipboard copy.
```
Source: export button click handler (lines 441-450)
Target: src/modules/email-signature/hooks/use-signature-export.ts
Responsibilities:
- Generate Blob from HTML string
- Trigger file download with appropriate filename
- Copy HTML to clipboard
- Filename includes company name and date
Interface:
Input: { html: string; companySlug: string }
Output: { downloadHtml: () => void; copyToClipboard: () => Promise<void> }
```
#### Utility: `formatPhoneNumber`
```
Source: phone formatting logic in updatePreview() (lines 365-372)
Target: src/shared/utils/format-phone.ts
Responsibilities:
- Accept raw phone string
- Detect Romanian mobile format (07xxxxxxxx)
- Return { display: string; tel: string } with formatted display and tel: link
This is a shared utility, not signature-specific.
```
#### React UI Replacements
| Original | React Replacement |
|---|---|
| Text inputs with `document.getElementById` | Controlled `<Input>` components with React state |
| Color swatch grid with DOM event delegation | `<ColorPicker>` component with `useState` |
| Range inputs with manual value display | `<Slider>` (shadcn/ui) with value label |
| Collapsible sections | `<Collapsible>` (shadcn/ui) |
| Checkboxes | `<Switch>` or `<Checkbox>` (shadcn/ui) |
| Live preview via `innerHTML` | React component rendering signature structure |
| `alert()`/`confirm()` | `<AlertDialog>` (shadcn/ui) |
| File download via DOM | `useSignatureExport` hook |
#### Generalization: Multi-Company Support
The current tool is hardcoded for Beletage. The React version must support all three companies.
```ts
// src/config/companies.ts
export interface CompanyProfile {
id: string;
name: string;
slug: string;
accent: string; // hex color
logo: {
png: string;
svg: string;
};
address: {
street: string;
city: string;
county: string;
postalCode: string;
country: string;
mapsUrl: string;
};
website: string;
motto: string;
brandColors: Record<string, string>; // named palette
signatureIcons: {
greySlash: { png: string; svg: string };
greenSlash: { png: string; svg: string };
};
}
```
The company selector in the header drives `CompanyProfile` into context. The signature builder reads from this context to populate logo, address, website, motto, and available colors.
#### New: Storage Integration
Save and load signature configurations via the storage abstraction:
```ts
// Signature configs are stored as:
{
id: string;
companyId: string;
name: string; // e.g., "Marius TARAU - Beletage"
config: SignatureConfig; // all field values
createdAt: string;
updatedAt: string;
}
```
Users can save multiple configs (one per person/company combo), load previous configs, and delete old ones.
### File Structure
```
src/modules/email-signature/
pages/
email-signature-page.tsx -- Main page component
components/
signature-form.tsx -- Config form (inputs, colors, sliders)
signature-preview.tsx -- Live preview panel
signature-color-picker.tsx -- Color swatch selector
saved-configs-list.tsx -- List of saved configurations
hooks/
use-signature-builder.ts -- HTML generation logic
use-signature-export.ts -- Download/copy logic
use-signature-config.ts -- State management for all config fields
types.ts -- SignatureConfig, SignatureData interfaces
```
---
## Word XML Generators -- Migration Plan (Consolidate 3 into 1)
### Current State Analysis
Three separate HTML files with increasing complexity:
**Basic** (`word-xml-generator-basic.html`):
- Namespace URI, root element name, field list (textarea).
- Generates XML with one element per field.
- Generates XPath list.
- Copy to clipboard, download XML, demo fill.
- Field name sanitization (spaces to underscores, invalid chars removed, dedup).
**Medium** (`word-xml-generator-medium.html`):
- Same as basic, but generates 6 variants per field: base, Short, Upper, Lower, Initials, First.
- `initials()` helper function.
**Advanced** (`word-xml-generator-advanced.html`):
- Category-based organization (Beneficiar, Proiect, Suprafete, Meta) with default presets.
- Per-category namespace (base namespace + `/CategoryName`).
- Per-category root element (`CategoryNameData`).
- Simple/Advanced mode toggle (advanced adds the 6 variants).
- POT/CUT metric computation for "Suprafete" category.
- localStorage persistence for category data.
- Category management (add, delete, reset to preset, clear).
- Single-category XML download.
- ZIP export of all categories via JSZip.
- Pill-based category selector UI.
### Consolidation Strategy
The three tools become a single React module with a complexity toggle:
| Mode | Equivalent to | Behavior |
|---|---|---|
| **Simplu** | basic | One element per field, no variants |
| **Avansat** | advanced | Categories, variants, POT/CUT, ZIP |
The medium version is subsumed by the advanced mode -- it was an intermediate step, not a distinct use case.
### Extraction Plan
#### Hook: `useXmlGenerator`
Core XML generation logic.
```
Source: generateXML() from basic, generateCategory() from advanced
Target: src/modules/xml-generator/hooks/use-xml-generator.ts
Responsibilities:
- Accept field list, namespace, root element name, mode (simple/advanced)
- Generate XML string for a Custom XML Part
- Generate XPath listing
- Handle variant generation (Short, Upper, Lower, Initials, First)
- Handle metric fields (POT/CUT) when category is surface-related
Interface:
Input: XmlGeneratorInput { fields: string[]; namespace: string; rootElement: string; mode: 'simple' | 'advanced'; computeMetrics: boolean; categoryName?: string }
Output: XmlGeneratorResult { xml: string; xpaths: string; fieldCount: number }
```
#### Hook: `useCategoryManager`
Category CRUD and persistence.
```
Source: initCategories(), switchCategory(), addCategoryPrompt(), etc. from advanced
Target: src/modules/xml-generator/hooks/use-category-manager.ts
Responsibilities:
- Manage list of categories with their field text
- Track active category
- Provide CRUD operations (add, delete, rename, reset to preset, clear)
- Persist to storage abstraction (not raw localStorage)
- Load default presets on first use
Interface:
Input: StorageAdapter
Output: { categories: Category[]; activeCategory: string; addCategory, deleteCategory, ... }
```
#### Pure Function: `sanitizeXmlName`
```
Source: sanitizeName() / sanitizeXmlName() (present in all three files)
Target: src/modules/xml-generator/utils/sanitize-xml-name.ts
Responsibilities:
- Trim whitespace
- Replace spaces with underscores
- Remove invalid XML name characters
- Ensure name starts with letter or underscore
- Return null for empty input
Easily unit-tested in isolation.
```
#### Pure Function: `generateFieldVariants`
```
Source: variant generation logic in medium and advanced
Target: src/modules/xml-generator/utils/generate-field-variants.ts
Responsibilities:
- Given a base field name, return array of variant names
- Variants: base, baseShort, baseUpper, baseLower, baseInitials, baseFirst
- Deduplication against a provided Set of used names
```
#### Pure Function: `generateXpaths`
```
Source: XPath string building in all three files
Target: src/modules/xml-generator/utils/generate-xpaths.ts
Responsibilities:
- Given root element and field list (with variants), produce formatted XPath listing
- Include namespace and root info in header
```
#### Service: `zipExportService`
```
Source: downloadZipAll() from advanced
Target: src/modules/xml-generator/services/zip-export-service.ts
Responsibilities:
- Accept map of { filename: xmlContent }
- Use JSZip to create archive
- Return Blob for download
Dependency: jszip (npm package, replaces CDN script tag)
```
### React UI Replacements
| Original | React Replacement |
|---|---|
| Textarea for field list | Controlled `<Textarea>` with React state |
| Pill-based category selector | `<Tabs>` (shadcn/ui) or custom pill component |
| Simple/Advanced pill toggle | `<Tabs>` with two items |
| `prompt()` for new category name | `<Dialog>` with `<Input>` |
| `confirm()` for deletion | `<AlertDialog>` |
| `alert()` for validation | Toast notification (shadcn/ui `sonner`) |
| `<pre>` for XML output | `<pre>` with syntax highlighting (optional) + copy button |
| Direct `localStorage` | Storage abstraction via hook |
| JSZip CDN | `jszip` npm package |
### New Features in React Version
1. **Template presets per company**: Each company can have its own default categories and fields. Driven by company context.
2. **Save/load configurations**: Named configurations stored via storage abstraction. Users can maintain multiple XML schemas.
3. **Project tag linking**: When generating XML for a specific project, link the configuration to a project tag from the tag manager.
4. **Copy individual XPaths**: Click-to-copy on each XPath line, not just the whole block.
### File Structure
```
src/modules/xml-generator/
pages/
xml-generator-page.tsx -- Main page component
components/
xml-generator-form.tsx -- Namespace, root, mode controls
category-manager.tsx -- Category tabs/pills + CRUD
field-editor.tsx -- Textarea for field list
xml-preview.tsx -- XML output with copy/download
xpath-preview.tsx -- XPath output with copy
saved-configs-list.tsx -- Saved configuration browser
hooks/
use-xml-generator.ts -- XML generation logic
use-category-manager.ts -- Category state management
use-xml-export.ts -- Download/ZIP export
services/
zip-export-service.ts -- JSZip wrapper
utils/
sanitize-xml-name.ts -- Field name sanitization
generate-field-variants.ts -- Variant name generation
generate-xpaths.ts -- XPath string builder
data/
default-presets.ts -- Default category presets
types.ts -- Category, XmlGeneratorInput, etc.
```
---
## General Extraction Patterns
### DOM Manipulation to React State
| HTML/JS Pattern | React Equivalent |
|---|---|
| `document.getElementById('x').value` | `const [x, setX] = useState('')` + controlled input |
| `element.innerHTML = html` | JSX return with variables |
| `element.textContent = text` | `{text}` in JSX |
| `element.classList.toggle('active')` | Conditional className: `cn('pill', isActive && 'active')` |
| `element.style.backgroundColor = color` | `style={{ backgroundColor: color }}` or Tailwind class |
| `element.addEventListener('input', handler)` | `onChange={handler}` on element |
| `document.createElement('div')` | JSX element or `.map()` rendering |
| `parent.appendChild(child)` | Render in JSX, controlled by state array |
| `element.disabled = true` | `disabled={condition}` prop |
### Refs
Use `useRef` only when React state is insufficient:
- Measuring DOM element dimensions.
- Integrating with third-party DOM libraries.
- Storing mutable values that should not trigger re-render.
Do not use `useRef` as a replacement for `document.getElementById`. That pattern belongs in controlled component state.
### Storage
| HTML Pattern | React Equivalent |
|---|---|
| `localStorage.getItem('key')` | `storageAdapter.get<T>('key')` |
| `localStorage.setItem('key', JSON.stringify(data))` | `storageAdapter.set('key', data)` |
| `JSON.parse(localStorage.getItem('key'))` | `storageAdapter.get<T>('key')` (typed, handles parse errors) |
The storage abstraction (`src/core/storage/`) wraps localStorage with:
- Typed get/set.
- JSON serialization.
- Error handling (quota exceeded, parse failures).
- Key namespacing by module.
- Future: swap backend to IndexedDB or API without changing module code.
### Styling
| HTML Pattern | React Equivalent |
|---|---|
| Inline `style="color: #22B5AB"` | `className="text-teal-500"` or CSS variable |
| Tailwind CDN classes | Same Tailwind classes (compiled at build time, not CDN) |
| Raw CSS in `<style>` block | Tailwind utilities in JSX, or `globals.css` for truly global styles |
| CSS custom properties | Keep if needed for dynamic values (e.g., accent color) |
| `linear-gradient(135deg, #38bdf8, #6366f1)` | Tailwind `bg-gradient-to-br from-sky-400 to-indigo-500` or define in theme |
### Dependencies
| HTML Pattern | React Equivalent |
|---|---|
| `<script src="https://cdn.tailwindcss.com">` | Tailwind installed via npm, configured in `tailwind.config.ts` |
| `<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/...">` | `npm install jszip` + `import JSZip from 'jszip'` |
| Google Fonts CDN link | `next/font/google` in layout |
### Dialogs
| HTML Pattern | React Equivalent |
|---|---|
| `alert('Message')` | `toast('Message')` via sonner, or `<AlertDialog>` for important messages |
| `confirm('Are you sure?')` | `<AlertDialog>` with confirm/cancel buttons |
| `prompt('Enter name:')` | `<Dialog>` with `<Input>` and submit button |
---
## File Placement Conventions
```
src/
modules/
email-signature/ -- Email signature module
pages/ -- Route-level page components
components/ -- Module-specific UI components
hooks/ -- Module-specific hooks
services/ -- Module-specific services (e.g., zip export)
utils/ -- Module-specific pure functions
data/ -- Static data, presets, defaults
types.ts -- Module type definitions
xml-generator/ -- XML generator module (consolidated)
(same structure)
shared/
components/
ui/ -- shadcn/ui components
utils/ -- Cross-module utilities (formatPhoneNumber, etc.)
hooks/ -- Cross-module hooks
core/
storage/ -- Storage abstraction
i18n/
labels.ts -- All UI text
theme/ -- Theme configuration
config/
companies.ts -- Company profiles
modules.ts -- Module registry (drives sidebar)
```
Module code never imports from another module directly. Shared functionality lives in `src/shared/` or `src/core/`.
---
## Testing Migrated Logic
### Unit Tests
All extracted pure functions and hooks must have unit tests.
**Pure functions** (sanitize, format, generate): straightforward input/output tests.
```ts
// src/modules/xml-generator/utils/__tests__/sanitize-xml-name.test.ts
import { sanitizeXmlName } from '../sanitize-xml-name';
describe('sanitizeXmlName', () => {
it('replaces spaces with underscores', () => {
expect(sanitizeXmlName('Nume Client')).toBe('Nume_Client');
});
it('removes invalid XML characters', () => {
expect(sanitizeXmlName('Preț/m²')).toBe('Prem');
});
it('prepends underscore if starts with digit', () => {
expect(sanitizeXmlName('123Field')).toBe('_123Field');
});
it('returns null for empty input', () => {
expect(sanitizeXmlName('')).toBeNull();
expect(sanitizeXmlName(' ')).toBeNull();
});
});
```
**Hooks**: test with `@testing-library/react-hooks` or `renderHook` from `@testing-library/react`.
```ts
import { renderHook, act } from '@testing-library/react';
import { useCategoryManager } from '../use-category-manager';
describe('useCategoryManager', () => {
it('initializes with default presets', () => {
const { result } = renderHook(() => useCategoryManager(mockStorage));
expect(result.current.categories).toHaveLength(4);
expect(result.current.activeCategory).toBe('Beneficiar');
});
});
```
### Integration Tests
Test full page rendering with mocked storage. Verify that:
- Form inputs update preview in real time.
- Export produces valid HTML/XML.
- Save/load round-trips correctly.
### Regression Testing
Before removing Phase 1 iframe, verify the React version produces identical output to the original HTML tool for a set of reference inputs. Store reference outputs as test fixtures.
For the email signature generator, compare generated HTML string character-by-character for known input configurations.
---
## Legacy Tool Preservation
Original HTML files are kept in the repository under their current paths for reference:
```
emailsignature/emailsignature-config.html
wordXMLgenerator/word-xml-generator-basic.html
wordXMLgenerator/word-xml-generator-medium.html
wordXMLgenerator/word-xml-generator-advanced.html
```
These files are not served by the Next.js application in production. They remain in the repository as:
- Reference implementation for migration accuracy.
- Fallback if a React module has a blocking bug.
- Historical documentation of original tool behavior.
Once Phase 3 is complete and the React versions are stable, legacy files can be moved to a `legacy/` directory or archived in a separate branch. Do not delete them until the React versions have been in production use for at least one release cycle.