diff --git a/.gitignore b/.gitignore deleted file mode 100644 index dd3ad3f..0000000 --- a/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? - -_TRASH/ diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index a60549c..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,163 +0,0 @@ -# TypoGenie - AI Coding Agent Guide - -## Project Overview - -TypoGenie is a web application that transforms Markdown content into professionally formatted Microsoft Word documents. Users upload `.md` or `.txt` files, select from 40+ typography styles across multiple categories (Minimalist, Corporate, Editorial, Tech, Creative, etc.), and download a formatted `.docx` file. - -The application uses a local Markdown parser (marked) rather than AI for document conversion, though it was originally designed with AI integration in mind. - -## Technology Stack - -- **Framework**: React 19.2.4 with TypeScript 5.8.2 -- **Build Tool**: Vite 6.2.0 -- **Styling**: Tailwind CSS (loaded via CDN in `index.html`) -- **Icons**: Lucide React -- **Document Generation**: docx library (client-side DOCX creation) -- **Markdown Parsing**: marked library (local conversion, no API calls) -- **Fonts**: Google Fonts loaded dynamically - -## Project Structure - -``` -├── App.tsx # Main application component with state machine -├── index.tsx # React root mount -├── index.html # HTML entry, Tailwind CDN, import maps -├── types.ts # TypeScript interfaces (StyleOption, DocxStyleConfig, etc.) -├── constants.ts # System prompts and style exports -├── components/ -│ ├── FileUpload.tsx # Drag-and-drop file upload (.md, .txt) -│ ├── StyleSelector.tsx # Style grid with preview iframe -│ ├── Preview.tsx # Final preview and DOCX export -│ └── StylePreviewModal.tsx # (Unused) Modal style preview component - -├── styles/ # Typography style definitions -│ ├── index.ts # Aggregates all style categories -│ ├── minimalist.ts # 11 minimalist styles -│ ├── corporate.ts # 13 corporate/professional styles -│ ├── editorial.ts # Editorial/magazine styles -│ ├── tech.ts # Tech/startup styles -│ ├── creative.ts # Creative/artistic styles -│ ├── vintage.ts # Retro/vintage styles -│ ├── lifestyle.ts # Lifestyle/blog styles -│ ├── academic.ts # Academic/research styles -│ └── industrial.ts # Industrial/technical styles -``` - -## Application State Flow - -The app uses a 4-state machine defined in `types.ts`: - -1. **UPLOAD** - Initial screen with file upload dropzone -2. **CONFIG** - Style selection interface with live preview -3. **GENERATING** - Processing animation (800ms artificial delay for UX) -4. **PREVIEW** - Final preview with DOCX download option - -State transitions: -- UPLOAD → CONFIG: After file loaded successfully -- CONFIG → GENERATING: When user clicks "Apply Style & Convert" -- GENERATING → PREVIEW: After HTML generation completes -- PREVIEW → CONFIG: Via "Back to Editor" button -- Any → UPLOAD: Via header logo click (reset) - -## Style System Architecture - -Each style is a `StyleOption` object containing: - -```typescript -{ - id: string, // Unique identifier - name: string, // Display name - category: string, // For filtering (Minimalist, Corporate, etc.) - description: string, // Short description - vibe: string, // Mood/aesthetic descriptor - googleFontsImport: string, // Google Fonts URL - wordConfig: { - heading1: DocxStyleConfig, // H1 formatting for Word - heading2: DocxStyleConfig, // H2 formatting for Word - body: DocxStyleConfig, // Body text formatting for Word - accentColor: string // Brand accent color - }, - previewCss: string // CSS string for web preview (must manually match wordConfig) -} -``` - -**Important**: `wordConfig` and `previewCss` must be kept in sync manually for visual fidelity between preview and exported document. - -## Build Commands - -```bash -# Install dependencies -npm install - -# Development server (runs on port 3000) -npm run dev - -# Production build (outputs to dist/) -npm run build - -# Preview production build -npm run preview -``` - -## Environment Configuration - -No environment variables required. The app uses local Markdown parsing only. - -## Key Implementation Details - -### DOCX Generation (components/Preview.tsx) - -The DOCX export uses the `docx` library to create Word-compatible documents: - -- Converts HTML to docx Paragraph elements -- Supports headings (h1-h6), paragraphs, blockquotes, lists -- Applies style-specific fonts, colors, spacing, borders, and shading -- Paper sizes: A4 (210mm × 297mm) and Letter (8.5in × 11in) -- Margins: 1in top/bottom, 1.2in left/right - -### Preview System - -Previews render in an iframe with dynamically injected: -- Google Fonts link from style config -- Style-specific CSS from `previewCss` -- Sample content for style selection view -- Actual converted content for final preview - -### File Upload - -Accepts: `.md`, `.txt`, `.markdown` -Uses FileReader API for client-side text extraction -Validates file extension before processing - -## Code Style Guidelines - -- **TypeScript**: Strict mode enabled; all components typed with React.FC -- **Imports**: Use `@/` path alias for project root imports -- **Styling**: Tailwind utility classes; custom CSS only in `previewCss` fields -- **Naming**: PascalCase for components, camelCase for functions/variables -- **Comments**: Explain business logic and non-obvious decisions - -## Adding New Typography Styles - -1. Choose appropriate category file in `/styles/` (or create new category) -2. Add StyleOption object to the array with: - - Unique `id` - - Google Fonts URL - - Complete `wordConfig` for DOCX export - - Matching `previewCss` for web preview -3. Export from `/styles/index.ts` if new category -4. Test both preview and DOCX export - -## Security Considerations - -- No server-side processing; all conversion happens client-side -- No API keys required; all processing is done locally -- File upload limited to text files by extension check -- iframe sandboxing for style previews (same-origin content only) - -## Known Limitations - -- `wordConfig` and `previewCss` require manual synchronization -- DOCX export has limited table support -- Complex Markdown (nested lists, code blocks) may not format perfectly -- Style categories are loosely organized and may overlap diff --git a/TypoGenie-v1.0.0-Windows-Portable.zip b/TypoGenie-v1.0.0-Windows-Portable.zip deleted file mode 100644 index f064a66..0000000 Binary files a/TypoGenie-v1.0.0-Windows-Portable.zip and /dev/null differ diff --git a/docs/plans/2026-02-18-wcag-aaa-accessibility-design.md b/docs/plans/2026-02-18-wcag-aaa-accessibility-design.md new file mode 100644 index 0000000..a17c9ac --- /dev/null +++ b/docs/plans/2026-02-18-wcag-aaa-accessibility-design.md @@ -0,0 +1,212 @@ +# WCAG 2.2 AAA Accessibility Remediation Design + +**Date:** 2026-02-18 +**Status:** Approved +**Scope:** 147 accessibility issues across 17 existing files, 3 new files + +## Decisions + +| Decision | Choice | +|----------|--------| +| Visual approach | Balance accessibility with dark aesthetic | +| Modals | Native `` element | +| Style cards | Listbox pattern with existing `useFocusableList` hook | +| Template colors | Runtime contrast validation only, no JSON template edits | +| Justified text | Override to `left` at render time | +| Contrast enforcement | Auto-correct via `ensureContrast()` utility at render time | + +## Section 1: CSS Foundation (~25 issues) + +### Root font size +Change `:root { font-size: 16px }` to `font-size: 100%` in `index.css` so user browser preferences are respected. + +### Overflow +Remove `overflow: hidden` from `body` and `#root`. Replace with `overflow-x: hidden` to prevent horizontal scroll but allow vertical content access when zoomed to 200%. + +### Focus indicators +Replace `rgba(99, 102, 241, 0.3)` focus ring with `rgba(99, 102, 241, 0.8)` at 2px. Meets 3:1 contrast on dark backgrounds while fitting indigo theme. + +### Reduced motion +Add global CSS rule: +```css +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} +``` + +### Forced colors +Add `@media (forced-colors: active)` rules for Windows High Contrast Mode compatibility. + +### Color replacements +Across all components: `text-zinc-600` -> `text-zinc-400`, `text-zinc-500` -> `text-zinc-400`. All text hits 7:1+ contrast on zinc-950. Keeps dark aesthetic. + +## Section 2: Modal System (~20 issues) + +### New `src/hooks/useDialog.ts` +Reusable hook wrapping native ``: +- Manages `dialogRef`, `showModal()`/`close()` +- Restores focus to trigger element on close +- Wires `aria-labelledby` +- Framer Motion animations on inner content div + +### KeyboardShortcutsHelp (App.tsx) +Convert from `motion.div` overlay to ``. Add `aria-labelledby` to heading. Close button gets `aria-label="Close shortcuts"`. Escape/focus trap handled natively. + +### ExportOptionsModal +Same `` conversion. Radio buttons wrapped in `
`. Close button labeled. + +### StylePreviewModal +Same `` conversion. Close button labeled. Iframe HTML gets `lang="en"`. + +### Animation approach +`dialog[open]` CSS selector for entrance. `::backdrop` gets fade-in. Framer Motion on inner content for exit. + +## Section 3: Keyboard Access & Interactive Elements (~20 issues) + +### Logo button +Replace `` with ``. + +### Single-character shortcut +Scope `?`/`/` listener to only fire when `document.activeElement` is body or non-input element. Prevents intercepting typing in search. + +### Style cards as listbox +Container: `role="listbox"` + `aria-label="Typography styles"`. Each card: `role="option"` + `tabIndex` + `aria-selected` + `onKeyDown`. Wire `useFocusableList` for arrow keys. Add `:focus-visible` indigo ring. + +### Favorite button +Add `aria-label` (dynamic: "Add to favorites"/"Remove from favorites") + `aria-pressed`. + +### Category filters +Wrap in `
`. Active button: `aria-pressed="true"`. + +### Paper size buttons +Wrap in `
`. Active button: `aria-pressed="true"`. + +### Search input +Add `aria-label="Search templates"` + `aria-describedby` pointing to live result count region. + +### Icon-only buttons +Add `aria-label` to all: zoom buttons, external link (Preview), close buttons. Decorative icons next to text: `aria-hidden="true"`. + +### Target sizes +Increase padding on small buttons to hit 44x44px minimum. Use `min-w-[44px] min-h-[44px]` with centered content where inline growth not possible. + +## Section 4: ARIA Live Regions & Status Announcements (~15 issues) + +### Root status region +Persistent `
` in App.tsx root. Updated on `appState` changes. + +### Generating state +Add `aria-busy="true"` + `role="status"` to container. + +### Preview loading +Wrap "Loading..." in `role="status"`. + +### Success message +`aria-live="polite"` on button text area for "Saved!" announcement. + +### Search results +Visually-hidden `role="status"` announcing "{N} templates found". Debounced 300ms. + +### Error fixes +- Remove `aria-live="polite"` where `role="alert"` already set (implies assertive) +- Remove 5-second auto-dismiss from FileUpload error +- Add `aria-describedby` linking FileUpload error to dropzone +- Template loading: `role="status"`. Template error: `role="alert"` + +### Loading state +Replace `return null` with minimal `
Loading TypoGenie
`. + +## Section 5: Semantic Structure & Landmarks (~15 issues) + +### Skip navigation +`Skip to main content` in index.html. + +### Page title +`TypoGenie - Markdown to Word Converter` + +### Noscript +`` + +### Landmarks +- `id="main-content"` on `
` in both app states +- `