Components & Flows¶
Documentation of the key UI components, page architecture, animation system, and the bilingual internationalization system. For project setup and configuration, see the Setup page. For API communication details, see the API Integration page.
Layout Architecture¶
The application uses two distinct layout patterns depending on whether the user is viewing public marketing pages or authenticated dashboard pages.
flowchart TD
subgraph Public["Public Layout"]
N[Navbar] --> P[Page Content]
P --> F[Footer]
end
subgraph Dashboard["Dashboard Layout"]
S[Sidebar Nav] --> D[Header Bar]
D --> C[Page Content]
end
R{Route Type} -->|Public| Public
R -->|Protected| Dashboard
Public Layout¶
Public pages (/, /about, /pricing, /contact) compose a shared visual structure:
| Component | File | Description |
|---|---|---|
Navbar |
src/components/Navbar.tsx |
Sticky nav with scroll-aware background transition, desktop links + mobile hamburger menu with AnimatePresence |
Footer |
src/components/Footer.tsx |
4-column footer (Product, Company, Resources, Legal) with social links |
The landing page (Index.tsx) additionally includes these section components:
| Component | File | Description |
|---|---|---|
Hero |
src/components/Hero.tsx |
Hero section with gradient blobs, dashboard preview image, CTA buttons |
Features |
src/components/Features.tsx |
6-card feature grid (AI, Speed, Security, Analytics, Team, Global) |
HowItWorks |
src/components/HowItWorks.tsx |
4-step process (Connect, Process, Insights, Action) with connector lines |
CTA |
src/components/CTA.tsx |
Call-to-action section with animated gradient background |
Dashboard Layout¶
All authenticated pages are wrapped in DashboardLayout (src/components/DashboardLayout.tsx), which provides:
- Fixed sidebar (hidden on mobile, slide-in overlay on toggle)
- Sticky header with page title, subtitle, theme/language toggles, and user avatar
- User initials display — fetches current user profile on mount via
getCurrentUser()
Sidebar Navigation Items:
| Icon | Label Key | Route |
|---|---|---|
| LayoutDashboard | dashboard.layout.nav.dashboard |
/dashboard |
| Sparkles | dashboard.layout.nav.studio |
/studio |
| History | dashboard.layout.nav.history |
/history |
| Users | dashboard.layout.nav.users |
/users |
| User | dashboard.layout.nav.profile |
/profile |
| Settings | dashboard.layout.nav.settings |
/settings |
| CreditCard | dashboard.layout.nav.billing |
/billing |
| HelpCircle | dashboard.layout.nav.help |
/support |
Active route highlighting uses location.pathname comparison with primary-colored backgrounds.
Route Protection¶
The ProtectedRoute component (src/components/ProtectedRoute.tsx) wraps all dashboard routes:
const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
const { isAuthenticated } = useAuth();
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return <>{children}</>;
};
When isAuthenticated is false (no access token in memory), the user is redirected to /login. The replace prop prevents the protected route from appearing in browser history.
Page Components¶
Pages with Real API Integration¶
These pages connect to the backend server via the service layer. For the full list of backend endpoints, see the API Reference. For details on the server-side authentication flow, see the Security & Auth page.
| Page | File | API Calls |
|---|---|---|
| Login | src/pages/Login.tsx |
useAuth().login() → POST /api/v1/auth/login |
| Register | src/pages/Register.tsx |
registerRequest() → POST /api/v1/auth/register |
| Profile | src/pages/Profile.tsx |
getCurrentUser() → GET /api/v1/users/me; updateCurrentUser() → PATCH /api/v1/users/me |
The DashboardLayout also calls getCurrentUser() on mount to display the user's initials in the sidebar avatar.
Pages with Mock/Hardcoded Data¶
These pages have full UI implementations but use hardcoded data — backend integration is not yet implemented:
| Page | File | Mock Data |
|---|---|---|
| Dashboard | src/pages/Dashboard.tsx |
Stats cards (documents processed, storage used, etc.), quick actions, recent activity list |
| Studio | src/pages/Studio.tsx |
AI content generation interface with mode selector (Document/Chat/Image/Code), template picker, input/output panels |
| History | src/pages/History.tsx |
Document list with search, filter pills (All/Completed/Processing/Failed), table + mobile card views |
| Users | src/pages/Users.tsx |
Full user management: search, role filter, status tabs, paginated table with bulk select/delete, side sheet for editing |
| Settings | src/pages/Settings.tsx |
Notification toggles, appearance (dark mode, reduce motion), language, security sections, danger zone |
| Billing | src/pages/Billing.tsx |
Current plan display, usage progress bars, plan comparison grid (Starter/Professional/Enterprise), invoice history |
Static Content Pages¶
| Page | File | Description |
|---|---|---|
| About | src/pages/About.tsx |
Team member photos (9 members), company values, story sections |
| Pricing | src/pages/Pricing.tsx |
Public pricing with monthly/annual toggle, 3-tier comparison |
| Contact | src/pages/Contact.tsx |
Contact form with Zod validation, contact info cards, office hours |
| Support | src/pages/Support.tsx |
Searchable FAQ accordion with AnimatePresence, resource cards |
| NotFound | src/pages/NotFound.tsx |
Simple 404 page |
Theme System¶
ThemeContext¶
The theme system (src/context/ThemeContext.tsx) implements a light/dark toggle using the class strategy:
flowchart LR
A["ThemeContext"] -->|adds/removes| B[".dark class on html"]
B --> C["CSS Variables in index.css"]
C --> D["Tailwind resolves hsl(var(--*))"]
| Feature | Implementation |
|---|---|
| Storage | localStorage (key: theme preference) |
| Mechanism | Adds/removes dark class on document.documentElement |
| Default | Light mode |
| Hook | useTheme() → { theme, toggleTheme } |
ThemeToggle¶
The ThemeToggle component (src/components/ThemeToggle.tsx) renders an animated button that rotates between Sun and Moon icons using Framer Motion.
CSS Design System¶
All theme colors are defined as HSL CSS custom properties in src/index.css:
:root {
--primary: 237 92% 62%; /* Blue */
--accent: 262 83% 58%; /* Purple */
--background: 0 0% 100%; /* White */
--foreground: 222 47% 11%; /* Dark navy */
/* ... 12 more tokens */
}
.dark {
--background: 222 47% 11%; /* Dark navy */
--foreground: 210 40% 98%; /* Off-white */
/* ... overrides for all tokens */
}
Tailwind resolves these via the config: primary: "hsl(var(--primary))", ensuring all components automatically adapt to the active theme.
Internationalization (i18n)¶
NassaQ implements a custom i18n system supporting English (EN) and Arabic (AR) with full RTL support.
Architecture¶
flowchart TD
A["LanguageContext.tsx<br/><i>~150 component-level keys per language</i>"] --> C
B["LanguageContextPages.tsx<br/><i>~620 page-level keys per language</i>"] --> C
C["Merged translations<br/><i>~770 total keys per language</i>"]
C --> D["t('key') function"]
D --> E["UI Components"]
The translation system is split across two files:
| File | Scope | Key Count (per language) |
|---|---|---|
LanguageContext.tsx |
Shared components (Navbar, Hero, Footer, DashboardLayout, toggles) | ~150 |
LanguageContextPages.tsx |
Page-specific content (all 15 pages) | ~620 |
Total: approximately 1,540 translation entries (770 keys x 2 languages).
How It Works¶
- Language stored in
localStorage— persists across sessions - RTL handling — when Arabic is selected, sets
document.documentElement.dir = "rtl" - Translation function —
t(key)performs dot-notation lookup on the merged translations object - Namespace convention — keys are organized by component/page:
brand.name → "NassaQ"
nav.home → "Home" / "الرئيسية"
pages.login.title → "Welcome Back" / "مرحبًا بعودتك"
pages.dashboard.stats.documents → "Total Documents" / "إجمالي المستندات"
dashboard.layout.nav.studio → "AI Studio" / "استوديو الذكاء"
Usage in Components¶
Every visible string in the application uses the t() function:
const { t } = useLanguage();
return (
<h1>{t("pages.login.title")}</h1>
<p>{t("pages.login.subtitle")}</p>
<Button>{t("pages.login.form.submit")}</Button>
);
LanguageToggle¶
The LanguageToggle component (src/components/LanguageToggle.tsx) renders a Globe icon button that toggles between en and ar. The toggle label displays "EN" or "AR" next to the icon.
RTL Support¶
When Arabic is selected:
document.documentElement.diris set to"rtl"- The browser's native RTL rendering handles text alignment, flex direction, and margin/padding mirroring
- Tailwind's RTL utilities are available for cases needing explicit override
Animation System¶
Framer Motion is used extensively throughout the application. Every page and most components include entry animations.
Common Patterns¶
Page entry animation (used on every page):
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
>
{/* Page content */}
</motion.div>
Staggered children (used in feature grids, card lists):
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay: index * 0.1 }}
>
AnimatePresence (used for conditional rendering with exit animations):
<AnimatePresence>
{isOpen && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: "auto", opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
>
{/* Expandable content */}
</motion.div>
)}
</AnimatePresence>
Components Using Framer Motion¶
| Component | Animation Type |
|---|---|
| All 15 pages | Entry fade-in + slide-up |
Navbar |
Mobile menu AnimatePresence, active link layoutId animation |
Hero |
Animated gradient blobs, scroll indicator |
Features |
Staggered card entry, hover scale |
HowItWorks |
Sequential step reveal |
CTA |
Animated gradient background blobs |
ThemeToggle |
Rotating icon transition |
DashboardLayout |
Sidebar slide-in on mobile |
Support (FAQ) |
AnimatePresence accordion expand/collapse |
Profile |
Card entry animations, edit mode transitions |
shadcn/ui Components¶
The project includes 50 shadcn/ui components in src/components/ui/ — check that directory for the full list. They are standard, unmodified shadcn/ui components built on Radix UI primitives (accordion, dialog, dropdown-menu, select, tabs, toast, etc.) plus several non-Radix ones (calendar via react-day-picker, carousel via embla-carousel-react, chart via recharts, command via cmdk, drawer via vaul, form via react-hook-form, and more). See Setup → shadcn/ui for the components.json configuration.
Utility Functions¶
cn() — Class Name Utility¶
Located at src/lib/utils.ts:
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Combines clsx (conditional classes) with tailwind-merge (intelligent deduplication of Tailwind classes). Used throughout all components for dynamic className composition.
useIsMobile() — Mobile Detection¶
Located at src/hooks/use-mobile.tsx:
Uses window.matchMedia to reactively detect mobile viewports. Returns boolean.