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

23 KiB

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.

// 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.

// 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:

// 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.

// 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.

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.