diff --git a/admin-compliance/app/sdk/company-profile/_components/PresetSelector.tsx b/admin-compliance/app/sdk/company-profile/_components/PresetSelector.tsx new file mode 100644 index 0000000..6efe28f --- /dev/null +++ b/admin-compliance/app/sdk/company-profile/_components/PresetSelector.tsx @@ -0,0 +1,49 @@ +'use client' + +import { COMPANY_PROFILE_PRESETS, type CompanyProfilePreset } from '@/lib/sdk/company-profile-presets' + +interface PresetSelectorProps { + onSelect: (preset: CompanyProfilePreset) => void + onSkip: () => void +} + +export function PresetSelector({ onSelect, onSkip }: PresetSelectorProps) { + return ( +
+
+

Welcher Unternehmenstyp passt zu Ihnen?

+

+ Waehlen Sie eine Vorlage fuer Ihre Branche — alle Felder werden vorbefuellt + und Sie koennen anschliessend anpassen. +

+
+ +
+ {COMPANY_PROFILE_PRESETS.map((preset) => ( + + ))} +
+ +
+ +
+
+ ) +} diff --git a/admin-compliance/app/sdk/document-generator/_components/GeneratorPreviewTab.tsx b/admin-compliance/app/sdk/document-generator/_components/GeneratorPreviewTab.tsx index 4c3b260..cee658c 100644 --- a/admin-compliance/app/sdk/document-generator/_components/GeneratorPreviewTab.tsx +++ b/admin-compliance/app/sdk/document-generator/_components/GeneratorPreviewTab.tsx @@ -1,5 +1,6 @@ 'use client' +import { useState } from 'react' import { LegalTemplateResult } from '@/lib/sdk/types' import { RuleEngineResult } from '../ruleEngine' @@ -12,6 +13,72 @@ interface GeneratorPreviewTabProps { onExportMarkdown: () => void } +// ============================================================================ +// Lightweight Markdown → HTML (no dependency needed) +// ============================================================================ + +function markdownToHtml(md: string): string { + let html = md + // Escape HTML entities first + .replace(/&/g, '&') + .replace(//g, '>') + + // Headings + html = html.replace(/^#### (.+)$/gm, '

$1

') + html = html.replace(/^### (.+)$/gm, '

$1

') + html = html.replace(/^## (.+)$/gm, '

$1

') + html = html.replace(/^# (.+)$/gm, '

$1

') + + // Horizontal rules + html = html.replace(/^---$/gm, '
') + + // Bold + Italic + html = html.replace(/\*\*\*(.+?)\*\*\*/g, '$1') + html = html.replace(/\*\*(.+?)\*\*/g, '$1') + html = html.replace(/\*(.+?)\*/g, '$1') + + // Links + html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1') + + // Tables (simple) + html = html.replace(/^\|(.+)\|$/gm, (match) => { + const cells = match.split('|').filter(c => c.trim()) + const isHeader = cells.every(c => /^[\s-:]+$/.test(c)) + if (isHeader) return '' + const tag = 'td' + return '' + cells.map(c => `<${tag}>${c.trim()}`).join('') + '' + }) + + // Wrap consecutive table rows + html = html.replace(/((?:.*<\/tr>\n?\n?)?(?:.*<\/tr>\n?)+)/g, (block) => { + const rows = block.split('\n').filter(r => r.startsWith('')) + if (rows.length === 0) return block + const headerRow = rows[0].replace(//g, '').replace(/<\/td>/g, '') + const bodyRows = rows.slice(1).join('\n') + return `${headerRow}${bodyRows}
` + }) + + // Remove separator comments + html = html.replace(/\n?/g, '') + + // Unordered lists + html = html.replace(/^- (.+)$/gm, '
  • $1
  • ') + html = html.replace(/((?:
  • .*<\/li>\n?)+)/g, '') + + // Paragraphs (lines that aren't already HTML) + html = html.replace(/^(?!<[a-z/]|$)(.+)$/gm, '

    $1

    ') + + // Clean up empty paragraphs + html = html.replace(/

    \s*<\/p>/g, '') + + return html +} + +// ============================================================================ +// Component +// ============================================================================ + export default function GeneratorPreviewTab({ template, ruleResult, @@ -20,12 +87,17 @@ export default function GeneratorPreviewTab({ onCopy, onExportMarkdown, }: GeneratorPreviewTabProps) { + const [viewMode, setViewMode] = useState<'preview' | 'markdown'>('preview') + + const htmlContent = markdownToHtml(renderedContent) + return (

    + {/* Violations */} {ruleResult && ruleResult.violations.length > 0 && (

    - 🔴 {ruleResult.violations.length} Fehler + {ruleResult.violations.length} Fehler

      {ruleResult.violations.map((v) => ( @@ -36,6 +108,8 @@ export default function GeneratorPreviewTab({
    )} + + {/* Warnings */} {ruleResult && ruleResult.warnings.filter((w) => w.id !== 'WARN_LEGAL_REVIEW').length > 0 && (
      @@ -43,69 +117,133 @@ export default function GeneratorPreviewTab({ .filter((w) => w.id !== 'WARN_LEGAL_REVIEW') .map((w) => (
    • - 🟡 [{w.id}] {w.message} + [{w.id}] {w.message}
    • ))}
    )} + + {/* Legal notice */} {ruleResult && (

    - ℹ️ Rechtlicher Hinweis: Diese Vorlage ist MIT-lizenziert. Vor Produktionseinsatz - wird eine rechtliche Überprüfung dringend empfohlen. + Rechtlicher Hinweis: Diese Vorlage ist MIT-lizenziert. Vor Produktionseinsatz + wird eine rechtliche Ueberpruefung dringend empfohlen.

    )} - {ruleResult && ruleResult.appliedDefaults.length > 0 && ( -

    - Defaults angewendet: {ruleResult.appliedDefaults.join(', ')} -

    - )} + {/* Toolbar */}
    - - {missing.length > 0 && ( - - ⚠ {missing.length} Platzhalter noch nicht ausgefüllt - - )} - -
    +
    +
    + +
    + {missing.length > 0 && ( + + {missing.length} Platzhalter offen + + )} + +
    -
    -
    -          {renderedContent}
    -        
    -
    + + {/* Content */} + {viewMode === 'markdown' ? ( +
    +
    +            {renderedContent}
    +          
    +
    + ) : ( +
    + {/* A4 Page */} +
    + +
    +
    +
    + )} + + {/* Attribution */} {template.attributionRequired && template.attributionText && (
    Attribution erforderlich: {template.attributionText} diff --git a/admin-compliance/app/sdk/document-generator/_components/GeneratorSection.tsx b/admin-compliance/app/sdk/document-generator/_components/GeneratorSection.tsx index 01a722c..ea313e6 100644 --- a/admin-compliance/app/sdk/document-generator/_components/GeneratorSection.tsx +++ b/admin-compliance/app/sdk/document-generator/_components/GeneratorSection.tsx @@ -160,6 +160,33 @@ export default function GeneratorSection({
    )}
    +
    + +