Component Architecture
Atomix QRGen uses a hybrid architecture combining Astro components (.astro) for static content and Preact components (.tsx) for interactive features.Component Hierarchy
Astro Components
Astro components render server-side at build time and produce static HTML.RootLayout.astro
Location:src/layouts/RootLayout.astro
Purpose: Provides the global HTML structure for all pages.
Features:
- HTML head with SEO metadata
- Favicon configuration (16x16, 32x32, 64x64, 120x120)
- Viewport configuration for responsive design
- Global CSS import
- Body styling (Rubik font, slate-900 background)
qr-code-generator.astro
Location:src/components/pages/qr-code-generator.astro
Purpose: Page wrapper component that bridges Astro and Preact.
Responsibility: Wraps the Preact QrGenApp component with client:load directive for hydration.
Preact Components
Preact components provide client-side interactivity.QrGenApp (Root Component)
Location:src/components/qr-code-app/app/qr-gen-app.tsx
Purpose: Main application logic and state management.
State:
- Manages selected QR type
- Manages form data for current QR type
- Coordinates data flow between child components
CardQrType
Location:src/components/qr-code-app/cards/qr-types/card-qr-type.tsx
Purpose: QR type selector displaying all available QR formats.
Props:
- Displays 6 QR type options with icons
- Visual feedback for selected type
- Disabled state for upcoming features (Payment, Event)
- Responsive hover states
- Icon filtering based on selection state
- Plain Text (PT) - Simple text content
- URL (UL) - Website links
- WiFi (WF) - Network credentials
- vCard (VC) - Contact information
- Payment (PB) - Payment requests (Coming soon)
- Event (EV) - Calendar events (Coming soon)
- Unselected (no selection): Gray with blue hover
- Selected: Blue background with white text
- Unselected (has selection): Faded gray with light hover
- Disabled: Light gray with “Soon” badge
CardContentInput
Location:src/components/qr-code-app/cards/content-input-card/card-content-input.tsx
Purpose: Dynamic form container that renders the appropriate form based on selected QR type.
Props:
- Uses form registry for dynamic component selection
- Resets form when QR type changes (via key prop)
- Displays placeholder text when no type is selected
- Propagates form data changes to parent
CardQrPreview
Location:src/components/qr-code-app/cards/qr-preview/card-qr-preview.tsx
Purpose: Displays generated QR code and provides download functionality.
Props:
- Real-time QR code generation using
qr-code-styling - Validates data before generating QR code
- Download QR code as PNG image
- Toast notifications for success/error states
- Responsive QR code sizing
- Encodes data using appropriate encoder
- Validates encoded data
- Generates QR code with styling options
- Handles download with dynamic filename
Form Components
Each form component follows a consistent pattern using theuseFormData hook.
Common Form Pattern
UrlForm
Location:src/components/forms/url/url-form.tsx
Fields:
- URL (required)
- Required field check
- Valid URL format
- Automatic protocol addition (https://)
TextForm
Location:src/components/forms/text/text-form.tsx
Fields:
- Text content (required, textarea)
- Minimum 1 character
- Maximum 2953 characters (QR code limit)
WifiForm
Location:src/components/forms/wifi/wifi-form.tsx
Fields:
- SSID (required)
- Password (conditional)
- Security type (WPA, WEP, or No password)
- SSID required, max 32 characters
- Password required for WPA/WEP
- WEP: minimum 5 characters
- WPA: minimum 8 characters
- Max 63 characters for passwords
VCardForm
Location:src/components/forms/v-card-form/v-card-form.tsx
Fields:
- First Name (required)
- Last Name (required)
- Phone (optional)
- Mobile (optional)
- Email (optional)
- Organization (optional)
- Title (optional)
- Website (optional)
- Address (optional)
- Note (optional)
- First and last name required
- Phone and mobile validated with regex
- Email format validation
- Website URL validation
EventForm
Location:src/components/forms/event-form/event-form.tsx
Fields:
- Title (required)
- Description (optional)
- Location (required)
- Start date/time (required)
- End date/time (required)
- All required fields present
- Valid datetime formats
- End time after start time
PaymentForm
Location:src/components/forms/payment-form/payment-form.tsx
Fields:
- Payment method (required)
- Recipient name (required)
- Account/Address (required)
- Bank/Platform (required)
- Amount (required)
- Reference (optional)
- All required fields present
- Amount greater than 0
- Account format based on payment method
- Crypto address validation (min 26 characters)
FormInput (Shared Component)
Location:src/components/forms/shared/form-input.tsx
Purpose: Reusable input component with consistent styling and error display.
Props:
- Supports both input and textarea
- Required field indicator (red asterisk)
- Error message display
- Consistent focus and hover states
- Tailwind-based styling with blue accent color
Component Communication
Props Down, Events Up Pattern
Components follow React/Preact best practices:Form Registry Pattern
Dynamic component selection using object mapping:- Eliminates large switch/if-else statements
- Makes adding new QR types straightforward
- Provides type safety with TypeScript
- Enables code splitting per form component
Styling Approach
All components use Tailwind CSS utility classes: Card Pattern:- Primary:
#0352D1(Blue) - Background: Slate-900
- Cards: White with gray borders
- Text: Gray-900 (dark) / White (on dark backgrounds)
- Error: Red-500
Component Best Practices
- Single Responsibility: Each component has one clear purpose
- Type Safety: All components use TypeScript interfaces
- Controlled Components: Forms use controlled inputs via
useFormData - Validation Separation: Validation logic in domain layer, not components
- Reusability: Shared components (
FormInput) reduce duplication - Prop Drilling Alternative: Form registry pattern instead of passing many components as props
- Key-based Reset: Use key prop to force component re-mount when needed