Abdoul-AI commited on
Commit
7af1d37
·
verified ·
1 Parent(s): 1af0faa

# Vis En France — Frontend Technical & Functional Specification

Browse files

**Version**: 2.0
**Framework**: Next.js 15 (App Router)
**Last Updated**: December 2024

---

## Table of Contents

1. [Project Overview](#1-project-overview)
2. [Tech Stack & Dependencies](#2-tech-stack--dependencies)
3. [Environment Configuration](#3-environment-configuration)
4. [Project Structure](#4-project-structure)
5. [Routing & Pages](#5-routing--pages)
6. [Layout System](#6-layout-system)
7. [Navigation Architecture](#7-navigation-architecture)
8. [Component Specifications](#8-component-specifications)
9. [Advertising System](#9-advertising-system)
10. [Content Architecture](#10-content-architecture)
11. [Feature Flags System](#11-feature-flags-system)
12. [Internationalization (i18n)](#12-internationalization-i18n)
13. [State Management](#13-state-management)
14. [Custom Hooks](#14-custom-hooks)
15. [Authentication System](#15-authentication-system)
16. [Data Layer & Mock Patterns](#16-data-layer--mock-patterns)
17. [Type Definitions](#17-type-definitions)
18. [Styling Guidelines](#18-styling-guidelines)
19. [Accessibility Requirements](#19-accessibility-requirements)
20. [Performance Guidelines](#20-performance-guidelines)
21. [SEO & Meta](#21-seo--meta)
22. [Error Handling](#22-error-handling)
23. [Testing Strategy](#23-testing-strategy)
24. [Development Workflow](#24-development-workflow)
25. [Build Order & Milestones](#25-build-order--milestones)

---

## 1. Project Overview

### Purpose

**Vis En France** is a multilingual web platform providing comprehensive guidance for three distinct audiences navigating French administrative processes:

| Audience | French Slug | English Label | Description |
|----------|-------------|---------------|-------------|
| Students | `etudiants` | Students | Student visa procedures, scholarships, VLS-TS |
| Employees | `salarie` | Employees | Work permits, Passeport Talent, employment contracts |
| Naturalization | `naturalisations` | Naturalization | Citizenship process, eligibility, interviews |

### Core User Flows

1. **Audience Selection** → User selects their situation via top tabs
2. **Section Navigation** → User browses sub-categories via pill navigation
3. **Content Consumption** → User reads articles and guides
4. **Question Submission** → User asks questions via modal form
5. **Ad Interaction** → User views and clicks sponsor advertisements

### Key Features

- Tab-based audience switching with sub-category filtering
- Static guides (Overview, Steps, Documents) per audience
- Dynamic article/update feeds
- Rotating advertisement sidebars (desktop) and banners (mobile)
- Multilingual support (French/English)
- Mock visitor counter for MVP
- Feature flag controlled functionality
- User authentication with role-based access

---

## 2. Tech Stack & Dependencies

### Core Framework

| Package | Version | Purpose |
|---------|---------|---------|
| Next.js | 15.x | React framework with App Router |
| React | 18.3.x | UI library |
| TypeScript | 5.4.x | Type safety |

### Styling

| Package | Version | Purpose |
|---------|---------|---------|
| Tailwind CSS | 3.4.x | Utility-first CSS |
| tailwind-merge | 2.x | Class name conflict resolution |
| clsx | 2.x | Conditional class names |

### State & Data

| Package | Version | Purpose |
|---------|---------|---------|
| Zustand | 4.5.x | Global state management |
| next-intl | 3.20.x | Internationalization |

### UI Components

| Package | Version | Purpose |
|---------|---------|---------|
| Lucide React | 0.400.x | Icon library |
| date-fns | 3.6.x | Date formatting |
| react-google-recaptcha | 3.x | Form protection |

### Development

| Package | Version | Purpose |
|---------|---------|---------|
| ESLint | 8.x | Code linting |
| Prettier | 3.x | Code formatting |
| Playwright | 1.x | E2E testing |
| React Testing Library | 14.x | Component testing |

---

## 3. Environment Configuration

### Environment Variables

Create `.env.local` with the following variables:

```env
# API Configuration
NEXT_PUBLIC_API_BASE=/api
NEXT_PUBLIC_SITE_URL=http://localhost:3000

# Internationalization
NEXT_PUBLIC_DEFAULT_LOCALE=fr
NEXT_PUBLIC_SUPPORTED_LOCALES=fr,en

# Advertising
NEXT_PUBLIC_AD_ROTATION_MS=15000
NEXT_PUBLIC_AD_SLOTS_PER_SIDE=6

# Authentication
NEXT_PUBLIC_JWT_EXPIRY_DAYS=7

# reCAPTCHA
NEXT_PUBLIC_RECAPTCHA_SITE_KEY=your_site_key_here
RECAPTCHA_SECRET_KEY=your_secret_key_here

# Feature Defaults (overridden by API)
NEXT_PUBLIC_ADS_ENABLED=true
NEXT_PUBLIC_FAQ_ENABLED=true
```

### Variable Naming Convention

- `NEXT_PUBLIC_*` — Exposed to browser, use for client-side configuration
- No prefix — Server-only, use for secrets and API keys

---

## 4. Project Structure

```
frontend/
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── layout.tsx # Root layout (html, body, providers)
│ │ ├── page.tsx # Home page (/)
│ │ ├── [locale]/ # Locale-wrapped routes
│ │ │ ├── layout.tsx # Locale provider wrapper
│ │ │ └── page.tsx # Localized home
│ │ ├── articles/
│ │ │ └── [slug]/
│ │ │ └── page.tsx # Article detail
│ │ ├── guides/
│ │ │ └── [audience]/
│ │ │ ├── page.tsx # Guide overview
│ │ │ ├── steps/page.tsx # Step-by-step timeline
│ │ │ └── documents/page.tsx# Document checklist
│ │ ├── faq/
│ │ │ └── page.tsx # Global FAQ
│ │ ├── (admin)/
│ │ │ └── dashboard/
│ │ │ ├── layout.tsx # Admin layout
│ │ │ ├── page.tsx # Dashboard overview
│ │ │ ├── settings/page.tsx # Site settings
│ │ │ ├── articles/page.tsx # Article management
│ │ │ ├── ads/page.tsx # Ad management
│ │ │ └── users/page.tsx # User management
│ │ └── (auth)/
│ │ ├── login/page.tsx # Login page
│ │ └── register/page.tsx # Registration page
│ │
│ ├── components/
│ │ ├── ui/ # Base UI primitives
│ │ │ ├── Button.tsx
│ │ │ ├── Input.tsx
│ │ │ ├── Textarea.tsx
│ │ │ ├── Modal.tsx
│ │ │ ├── Card.tsx
│ │ │ ├── Badge.tsx
│ │ │ ├── Skeleton.tsx
│ │ │ ├── Toast.tsx
│ │ │ └── index.ts
│ │ ├── layout/ # Layout components
│ │ │ ├── Header.tsx
│ │ │ ├── MainLayout.tsx
│ │ │ ├── AdminLayout.tsx
│ │ │ ├── Footer.tsx
│ │ │ └── index.ts
│ │ ├── navigation/ # Navigation components
│ │ │ ├── TabNavigation.tsx
│ │ │ ├── SubNavigation.tsx
│ │ │ ├── LanguageSwitcher.tsx
│ │ │ ├── VisitorCounter.tsx
│ │ │ ├── Breadcrumbs.tsx
│ │ │ └── index.ts
│ │ ├── ads/ # Advertising components
│ │ │ ├── AdCard.tsx
│ │ │ ├── AdRail.tsx
│ │ │ ├── AdMobileBar.tsx
│ │ │ └── index.ts
│ │ ├── content/ # Content display components
│ │ │ ├── ArticleCard.tsx
│ │ │ ├── ArticleList.tsx
│ │ │ ├── ArticleContent.tsx
│ │ │ ├── GuideOverview.tsx
│ │ │ ├── StepTimeline.tsx
│ │ │ ├── DocumentChecklist.tsx
│ │ │ ├── UpdateCard.tsx
│ │ │ ├── UpdateFeed.tsx
│ │ │ ├── FAQList.tsx
│ │ │ ├── FAQItem.tsx
│ │ │ └── index.ts
│ │ ├── forms/ # Form components
│ │ │ ├── QuestionForm.tsx
│ │ │ ├── LoginForm.tsx
│ │ │ ├── RegisterForm.tsx
│ │ │ ├── FilterBar.tsx
│ │ │ ├── SearchInput.tsx
│ │ │ └── index.ts
│ │ ├── modals/ # Modal dialogs
│ │ │ ├── QuestionModal.tsx
│ │ │ ├── AdvertiseModal.tsx
│ │ │ ├── AdBookingModal.tsx
│ │ │ ├── LoginModal.tsx
│ │ │ ├── RegisterModal.tsx
│ │ │ ├── ConfirmModal.tsx
│ │ │ └── index.ts
│ │ ├── admin/ # Admin-specific components
│ │ │ ├── Sidebar.tsx
│ │ │ ├── StatsCard.tsx
│ │ │ ├── DataTable.tsx
│ │ │ ├── FeatureToggle.tsx
│ │ │ └── index.ts
│ │ └── common/ # Shared utilities
│ │ ├── EmptyState.tsx
│ │ ├── ErrorBoundary.tsx
│ │ ├── LoadingSpinner.tsx
│ │ ├── ProtectedRoute.tsx
│ │ └── index.ts
│ │
│ ├── stores/ # Zustand state stores
│ │ ├── navigation-store.ts
│ │ ├── auth-store.ts
│ │ ├── config-store.ts
│ │ ├── ads-store.ts
│ │ ├── modal-store.ts
│ │ ├── locale-store.ts
│ │ └── index.ts
│ │
│ ├── hooks/ # Custom React hooks
│ │ ├── useAuth.ts
│ │ ├── useFeatureFlag.ts
│ │ ├── useAdRotation.ts
│ │ ├── useIntersectionImpression.ts
│ │ ├── useMockVisitors.ts
│ │ ├── useLocale.ts
│ │ ├── useMediaQuery.ts
│ │ └── index.ts
│ │
│ ├── lib/ # Utili

Files changed (4) hide show
  1. README.md +8 -5
  2. index.html +253 -19
  3. script.js +91 -0
  4. style.css +46 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Administrative Aide Visualizer
3
- emoji: 👀
4
- colorFrom: green
5
- colorTo: purple
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: Administrative Aide Visualizer 🏛️
3
+ colorFrom: yellow
4
+ colorTo: red
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://huggingface.co/deepsite).
index.html CHANGED
@@ -1,19 +1,253 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Administrative Aide Visualizer</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://unpkg.com/feather-icons"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
10
+ <link rel="stylesheet" href="style.css">
11
+ <script>
12
+ tailwind.config = {
13
+ theme: {
14
+ extend: {
15
+ colors: {
16
+ primary: {
17
+ 50: '#f0f9ff',
18
+ 100: '#e0f2fe',
19
+ 200: '#bae6fd',
20
+ 300: '#7dd3fc',
21
+ 400: '#38bdf8',
22
+ 500: '#0ea5e9',
23
+ 600: '#0284c7',
24
+ 700: '#0369a1',
25
+ 800: '#075985',
26
+ 900: '#0c4a6e',
27
+ },
28
+ secondary: {
29
+ 50: '#f5f3ff',
30
+ 100: '#ede9fe',
31
+ 200: '#ddd6fe',
32
+ 300: '#c4b5fd',
33
+ 400: '#a78bfa',
34
+ 500: '#8b5cf6',
35
+ 600: '#7c3aed',
36
+ 700: '#6d28d9',
37
+ 800: '#5b21b6',
38
+ 900: '#4c1d95',
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ </script>
45
+ </head>
46
+ <body class="bg-gray-50">
47
+ <!-- Navigation -->
48
+ <nav class="bg-white shadow-sm">
49
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
50
+ <div class="flex justify-between h-16">
51
+ <div class="flex items-center">
52
+ <i data-feather="book" class="text-primary-600 mr-2"></i>
53
+ <span class="text-xl font-bold text-gray-800">AdminAide</span>
54
+ </div>
55
+ <div class="flex items-center space-x-4">
56
+ <a href="#" class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-primary-600">Home</a>
57
+ <a href="#" class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-primary-600">Guides</a>
58
+ <a href="#" class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-primary-600">FAQ</a>
59
+ <button class="bg-primary-500 text-white px-4 py-2 rounded-md text-sm font-medium hover:bg-primary-600">
60
+ Ask Question
61
+ </button>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ </nav>
66
+
67
+ <!-- Hero Section -->
68
+ <div class="bg-gradient-to-r from-primary-500 to-secondary-500">
69
+ <div class="max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:px-8 lg:py-24">
70
+ <div class="text-center">
71
+ <h1 class="text-4xl font-extrabold tracking-tight text-white sm:text-5xl lg:text-6xl">
72
+ Navigate French Administration
73
+ </h1>
74
+ <p class="mt-6 max-w-3xl mx-auto text-xl text-primary-100">
75
+ Comprehensive guides for students, employees, and citizenship applicants
76
+ </p>
77
+ <div class="mt-10 flex justify-center space-x-4">
78
+ <a href="#" class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md shadow-sm text-primary-700 bg-white hover:bg-gray-50">
79
+ Get Started
80
+ </a>
81
+ <a href="#" class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-primary-700 bg-opacity-60 hover:bg-opacity-70">
82
+ Watch Video
83
+ </a>
84
+ </div>
85
+ </div>
86
+ </div>
87
+ </div>
88
+
89
+ <!-- Main Content -->
90
+ <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
91
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
92
+ <!-- Student Card -->
93
+ <div class="bg-white rounded-lg shadow-md overflow-hidden transition-transform hover:scale-105">
94
+ <div class="bg-primary-100 p-6">
95
+ <div class="flex items-center">
96
+ <i data-feather="book-open" class="text-primary-600 mr-3"></i>
97
+ <h2 class="text-xl font-bold text-gray-800">Students</h2>
98
+ </div>
99
+ </div>
100
+ <div class="p-6">
101
+ <p class="text-gray-600 mb-4">Everything about student visas, university registration, and scholarship applications.</p>
102
+ <a href="#" class="inline-flex items-center text-primary-600 hover:text-primary-800">
103
+ Student guide
104
+ <i data-feather="arrow-right" class="ml-1 w-4 h-4"></i>
105
+ </a>
106
+ </div>
107
+ </div>
108
+
109
+ <!-- Employee Card -->
110
+ <div class="bg-white rounded-lg shadow-md overflow-hidden transition-transform hover:scale-105">
111
+ <div class="bg-secondary-100 p-6">
112
+ <div class="flex items-center">
113
+ <i data-feather="briefcase" class="text-secondary-600 mr-3"></i>
114
+ <h2 class="text-xl font-bold text-gray-800">Employees</h2>
115
+ </div>
116
+ </div>
117
+ <div class="p-6">
118
+ <p class="text-gray-600 mb-4">Work permits, employment contracts, and professional visa requirements.</p>
119
+ <a href="#" class="inline-flex items-center text-secondary-600 hover:text-secondary-800">
120
+ Employee guide
121
+ <i data-feather="arrow-right" class="ml-1 w-4 h-4"></i>
122
+ </a>
123
+ </div>
124
+ </div>
125
+
126
+ <!-- Naturalization Card -->
127
+ <div class="bg-white rounded-lg shadow-md overflow-hidden transition-transform hover:scale-105">
128
+ <div class="bg-gray-100 p-6">
129
+ <div class="flex items-center">
130
+ <i data-feather="flag" class="text-gray-600 mr-3"></i>
131
+ <h2 class="text-xl font-bold text-gray-800">Naturalization</h2>
132
+ </div>
133
+ </div>
134
+ <div class="p-6">
135
+ <p class="text-gray-600 mb-4">Citizenship application process, eligibility criteria, and interview preparation.</p>
136
+ <a href="#" class="inline-flex items-center text-gray-600 hover:text-gray-800">
137
+ Citizenship guide
138
+ <i data-feather="arrow-right" class="ml-1 w-4 h-4"></i>
139
+ </a>
140
+ </div>
141
+ </div>
142
+ </div>
143
+
144
+ <!-- Updates Section -->
145
+ <div class="mt-16">
146
+ <h2 class="text-2xl font-bold text-gray-800 mb-6">Latest Updates</h2>
147
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
148
+ <!-- Update 1 -->
149
+ <div class="bg-white rounded-lg shadow-md overflow-hidden">
150
+ <div class="p-6">
151
+ <div class="flex items-center mb-3">
152
+ <span class="bg-primary-100 text-primary-800 text-xs font-semibold px-2.5 py-0.5 rounded">New</span>
153
+ <span class="text-gray-500 text-sm ml-2">May 15, 2023</span>
154
+ </div>
155
+ <h3 class="text-lg font-semibold text-gray-800 mb-2">Student Visa Fee Changes</h3>
156
+ <p class="text-gray-600 mb-4">The French government has announced updated fees for student visa applications effective June 1st.</p>
157
+ <a href="#" class="text-primary-600 hover:text-primary-800 text-sm font-medium">Read more →</a>
158
+ </div>
159
+ </div>
160
+
161
+ <!-- Update 2 -->
162
+ <div class="bg-white rounded-lg shadow-md overflow-hidden">
163
+ <div class="p-6">
164
+ <div class="flex items-center mb-3">
165
+ <span class="bg-secondary-100 text-secondary-800 text-xs font-semibold px-2.5 py-0.5 rounded">Update</span>
166
+ <span class="text-gray-500 text-sm ml-2">May 10, 2023</span>
167
+ </div>
168
+ <h3 class="text-lg font-semibold text-gray-800 mb-2">Work Permit Processing Times</h3>
169
+ <p class="text-gray-600 mb-4">Current processing times for employee work permits have been reduced by 15% in most regions.</p>
170
+ <a href="#" class="text-primary-600 hover:text-primary-800 text-sm font-medium">Read more →</a>
171
+ </div>
172
+ </div>
173
+
174
+ <!-- Update 3 -->
175
+ <div class="bg-white rounded-lg shadow-md overflow-hidden">
176
+ <div class="p-6">
177
+ <div class="flex items-center mb-3">
178
+ <span class="bg-gray-100 text-gray-800 text-xs font-semibold px-2.5 py-0.5 rounded">Notice</span>
179
+ <span class="text-gray-500 text-sm ml-2">May 5, 2023</span>
180
+ </div>
181
+ <h3 class="text-lg font-semibold text-gray-800 mb-2">Citizenship Test Updates</h3>
182
+ <p class="text-gray-600 mb-4">The Ministry has published new study materials for the French language and civics tests.</p>
183
+ <a href="#" class="text-primary-600 hover:text-primary-800 text-sm font-medium">Read more →</a>
184
+ </div>
185
+ </div>
186
+ </div>
187
+ </div>
188
+ </main>
189
+
190
+ <!-- Footer -->
191
+ <footer class="bg-gray-800 text-white py-12">
192
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
193
+ <div class="grid grid-cols-1 md:grid-cols-4 gap-8">
194
+ <div>
195
+ <h3 class="text-lg font-semibold mb-4">Administrative Aide</h3>
196
+ <p class="text-gray-400">Simplifying French administrative processes for international visitors and residents.</p>
197
+ </div>
198
+ <div>
199
+ <h4 class="text-sm font-semibold uppercase tracking-wider mb-4">Guides</h4>
200
+ <ul class="space-y-2">
201
+ <li><a href="#" class="text-gray-400 hover:text-white">Student Visa</a></li>
202
+ <li><a href="#" class="text-gray-400 hover:text-white">Work Permits</a></li>
203
+ <li><a href="#" class="text-gray-400 hover:text-white">Citizenship</a></li>
204
+ <li><a href="#" class="text-gray-400 hover:text-white">Residency</a></li>
205
+ </ul>
206
+ </div>
207
+ <div>
208
+ <h4 class="text-sm font-semibold uppercase tracking-wider mb-4">Resources</h4>
209
+ <ul class="space-y-2">
210
+ <li><a href="#" class="text-gray-400 hover:text-white">Forms & Documents</a></li>
211
+ <li><a href="#" class="text-gray-400 hover:text-white">FAQ</a></li>
212
+ <li><a href="#" class="text-gray-400 hover:text-white">Glossary</a></li>
213
+ <li><a href="#" class="text-gray-400 hover:text-white">Contact Prefectures</a></li>
214
+ </ul>
215
+ </div>
216
+ <div>
217
+ <h4 class="text-sm font-semibold uppercase tracking-wider mb-4">Connect</h4>
218
+ <div class="flex space-x-4">
219
+ <a href="#" class="text-gray-400 hover:text-white">
220
+ <i data-feather="facebook"></i>
221
+ </a>
222
+ <a href="#" class="text-gray-400 hover:text-white">
223
+ <i data-feather="twitter"></i>
224
+ </a>
225
+ <a href="#" class="text-gray-400 hover:text-white">
226
+ <i data-feather="linkedin"></i>
227
+ </a>
228
+ <a href="#" class="text-gray-400 hover:text-white">
229
+ <i data-feather="mail"></i>
230
+ </a>
231
+ </div>
232
+ <div class="mt-6">
233
+ <button class="flex items-center text-gray-400 hover:text-white text-sm">
234
+ <i data-feather="globe" class="mr-2"></i>
235
+ English
236
+ <i data-feather="chevron-down" class="ml-1"></i>
237
+ </button>
238
+ </div>
239
+ </div>
240
+ </div>
241
+ <div class="mt-12 pt-8 border-t border-gray-700">
242
+ <p class="text-gray-400 text-sm text-center">© 2023 Administrative Aide Visualizer. All rights reserved.</p>
243
+ </div>
244
+ </div>
245
+ </footer>
246
+
247
+ <script src="script.js"></script>
248
+ <script>
249
+ feather.replace();
250
+ </script>
251
+ <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
252
+ </body>
253
+ </html>
script.js ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener('DOMContentLoaded', function() {
2
+ // Initialize tooltips
3
+ const tooltipTriggers = document.querySelectorAll('[data-tooltip]');
4
+ tooltipTriggers.forEach(trigger => {
5
+ const tooltip = document.createElement('div');
6
+ tooltip.className = 'hidden bg-gray-800 text-white text-xs rounded py-1 px-2 absolute z-50';
7
+ tooltip.textContent = trigger.getAttribute('data-tooltip');
8
+ document.body.appendChild(tooltip);
9
+
10
+ trigger.addEventListener('mouseenter', () => {
11
+ const rect = trigger.getBoundingClientRect();
12
+ tooltip.style.top = `${rect.top - 30}px`;
13
+ tooltip.style.left = `${rect.left + rect.width / 2}px`;
14
+ tooltip.style.transform = 'translateX(-50%)';
15
+ tooltip.classList.remove('hidden');
16
+ });
17
+
18
+ trigger.addEventListener('mouseleave', () => {
19
+ tooltip.classList.add('hidden');
20
+ });
21
+ });
22
+
23
+ // Mock visitor counter animation
24
+ const visitorCounter = document.getElementById('visitor-counter');
25
+ if (visitorCounter) {
26
+ let count = Math.floor(Math.random() * 100) + 50;
27
+ setInterval(() => {
28
+ count += Math.floor(Math.random() * 3) - 1;
29
+ visitorCounter.textContent = count.toLocaleString() + ' Active Visitors';
30
+ }, 5000);
31
+ }
32
+
33
+ // Form submission handling
34
+ const forms = document.querySelectorAll('form');
35
+ forms.forEach(form => {
36
+ form.addEventListener('submit', function(e) {
37
+ e.preventDefault();
38
+ const submitButton = form.querySelector('button[type="submit"]');
39
+ if (submitButton) {
40
+ const originalText = submitButton.textContent;
41
+ submitButton.innerHTML = '<i data-feather="loader" class="animate-spin mr-2 w-4 h-4"></i> Processing...';
42
+ feather.replace();
43
+
44
+ // Simulate API call
45
+ setTimeout(() => {
46
+ submitButton.textContent = originalText;
47
+ // Show success message
48
+ alert('Form submitted successfully!');
49
+ }, 1500);
50
+ }
51
+ });
52
+ });
53
+
54
+ // Mobile menu toggle (if exists)
55
+ const mobileMenuButton = document.getElementById('mobile-menu-button');
56
+ const mobileMenu = document.getElementById('mobile-menu');
57
+ if (mobileMenuButton && mobileMenu) {
58
+ mobileMenuButton.addEventListener('click', () => {
59
+ mobileMenu.classList.toggle('hidden');
60
+ });
61
+ }
62
+
63
+ // Smooth scrolling for anchor links
64
+ document.querySelectorAll('a[href^="#"]').forEach(anchor => {
65
+ anchor.addEventListener('click', function(e) {
66
+ e.preventDefault();
67
+ document.querySelector(this.getAttribute('href')).scrollIntoView({
68
+ behavior: 'smooth'
69
+ });
70
+ });
71
+ });
72
+
73
+ // Initialize all feather icons
74
+ feather.replace();
75
+ });
76
+
77
+ // Debounce function for resize/scroll events
78
+ function debounce(func, wait = 20, immediate = true) {
79
+ let timeout;
80
+ return function() {
81
+ const context = this, args = arguments;
82
+ const later = function() {
83
+ timeout = null;
84
+ if (!immediate) func.apply(context, args);
85
+ };
86
+ const callNow = immediate && !timeout;
87
+ clearTimeout(timeout);
88
+ timeout = setTimeout(later, wait);
89
+ if (callNow) func.apply(context, args);
90
+ };
91
+ }
style.css CHANGED
@@ -1,28 +1,56 @@
 
 
1
  body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
 
 
 
 
 
 
 
 
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
 
 
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
 
28
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
2
+
3
  body {
4
+ font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
5
+ -webkit-font-smoothing: antialiased;
6
+ line-height: 1.6;
7
+ }
8
+
9
+ /* Custom animations */
10
+ @keyframes fadeIn {
11
+ from { opacity: 0; transform: translateY(10px); }
12
+ to { opacity: 1; transform: translateY(0); }
13
+ }
14
+
15
+ .animate-fade-in {
16
+ animation: fadeIn 0.5s ease-out forwards;
17
  }
18
 
19
+ /* Custom card hover effect */
20
+ .card-hover:hover {
21
+ box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
22
+ transform: translateY(-2px);
23
+ transition: all 0.3s ease;
24
  }
25
 
26
+ /* Custom button focus state */
27
+ .button-focus:focus {
28
+ outline: none;
29
+ box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.5);
 
30
  }
31
 
32
+ /* Responsive typography */
33
+ @media (min-width: 1024px) {
34
+ .text-responsive {
35
+ font-size: 1.125rem;
36
+ }
 
37
  }
38
 
39
+ /* Custom scrollbar */
40
+ ::-webkit-scrollbar {
41
+ width: 8px;
42
+ height: 8px;
43
  }
44
+
45
+ ::-webkit-scrollbar-track {
46
+ background: #f1f1f1;
47
+ }
48
+
49
+ ::-webkit-scrollbar-thumb {
50
+ background: #888;
51
+ border-radius: 4px;
52
+ }
53
+
54
+ ::-webkit-scrollbar-thumb:hover {
55
+ background: #555;
56
+ }