A responsive, single-page Arabic beverage and recipe browser built with React 19 and Framer Motion.
Overview • Key Features • Screenshots • Tech Stack • Architecture • Data Model • Navigation Flow • Routes • Project Structure • Installation & Setup • Available Scripts • Author & Contact
RKN AL TAHLIA (recipes-tk) is a client-side single-page application (SPA) designed for discovering, filtering, and preparing curated Arabic beverage recipes. The application delivers an Arabic-first, Right-to-Left (RTL) experience with dynamic theme switching (light/dark mode), real-time search, category filters, and deep-linkable recipe navigation.
Architecture Note:
All recipe and beverage data is bundled locally withinsrc/data.js. The repository operates entirely client-side without a backend server, database, external API integration, or authentication layer. User favorites are persisted locally via the browser'slocalStorageAPI.
- RTL-Native Interface: Tailored specifically for Arabic reading flow and typography.
- Theme Switching: Instant toggle between light and dark modes with persistent visual harmony.
- Micro-Interactions & Transitions: Fluid page transitions, card hover animations, and hero motion driven by Framer Motion.
- Accessibility & Motion Preferences: Target-card smooth scrolling automatically respects the user's
prefers-reduced-motionsettings. - Responsive Navigation: Sticky navigation bar, scroll progress indicator, custom loading screen, and mobile drawer menu.
- Real-Time Search: Search across all drinks and recipe titles instantly.
- Category Filtering: Filter items by Cold, Hot, and Sweet beverages.
- Dedicated Recipe Views: Detailed preparation cards listing ingredients, step-by-step instructions, preparation time, difficulty level, and beverage classification.
- Local Favorites: Save favorite beverages with instant synchronization to
localStorageunderfavorite-drink-ids.
- Bi-Directional Deep Linking: Seamless navigation between drink preview cards on the Home view and comprehensive Recipe cards on the Recipes view.
- Anchor Offset Scrolling: Automated scroll targeting that calculates sticky navbar offsets using native CSS
scroll-margin-top.
| Category | Technology | Purpose & Role |
|---|---|---|
| Frontend Framework | React 19 |
UI component composition, lifecycle management, and reactive hooks |
| Build & Tooling | Create React App (react-scripts) |
Development server bundling, optimization, and production build pipelines |
| Programming Language | JavaScript |
Application logic, routing rules, and local data models |
| Styling & Layout | CSS |
Theme variables, RTL layout rules, responsive breakpoints, and custom styles |
| Motion & Animation | Framer Motion |
View entry/exit transitions, hero element shifts, and loading states |
| Iconography | React Icons |
Vector icons for social and brand links |
| Testing | React Testing Library |
Unit and smoke testing (App.test.js) |
| Performance Metrics | Web Vitals |
Standardized web vitals reporting scaffold (reportWebVitals.js) |
| Package Management | npm |
Dependency management with locked resolution (package-lock.json) |
The application mounts via src/index.js in React.StrictMode. Top-level state and routing logic reside in src/App.js, which manages view rendering, query and hash parsing, filter application, and localStorage synchronization.
Routing is implemented natively with the browser History API and window.location, listening for popstate events without requiring external router dependencies like React Router.
flowchart TD
entry["src/index.js and React StrictMode"] --> app["src/App.js"]
data["src/data.js local recipes and drinks"] --> app
app -->|syncs favorite IDs| storage["localStorage favorite-drink-ids"]
app --> navbar["Navbar.js"]
app --> hero["HeroSection.js"]
app --> drinkGrid["DrinkCardGrid.js"]
app --> recipeGrid["RecipeCardGrid.js"]
app --> contact["Contact.js"]
app --> footer["Footer.js"]
app --> toast["Toast.js"]
All records are declared in src/data.js. The relationship between drinks and recipes relies on deterministic, stable identifiers rather than array indices:
classDiagram
class Recipe {
+String id
+String title
+String image
+String[] ingredients
+String[] method
+String description
+String type
+String preparationTime
+String difficulty
+String drinkId
}
class Drink {
+String id
+String recipeId
+String name
+String image
+String category
+String description
}
Recipe --> Drink : uses stable IDs
Drink --> Recipe : uses stable IDs
- Base Recipe Record: Defines
id,title,image,ingredients,preparationMethod,description,type,time,difficulty, anddrinkId. - Derived Drink Record: Extracted from the recipe dataset with matching
drinkId(drink-<recipe-id>),recipeId, display name, image, category, and summary description.
The application provides deterministic two-way navigation between the Home overview grid and the detailed Recipes collection:
flowchart LR
homeCard["Home drink card"] -->|"View Details"| recipeCard["Recipe card"]
recipeCard -->|"Back to Drink"| homeCard
- Target Identification: Navigation buttons emit the stable entity ID (
recipeIdordrinkId). - URL Update & View Render:
App.jsupdates browser history, switches the active view, and triggers a lightweight Framer Motion fade-and-shift transition. - Smooth Viewport Alignment: A
useEffecthook triggers native smooth scrolling (block: "start"), adjusting for sticky header height via CSSscroll-margin-top. - Cleanup & Accessibility: Timers for scheduled route scrolling are cleanly aborted if the route changes during execution, and animations are suppressed when reduced-motion preferences are detected.
The custom route parser in src/App.js evaluates pathnames, query parameters, and hashes:
| Route / URL Pattern | Active View | Target Element / Purpose |
|---|---|---|
/ |
Home |
Full home view: Hero, Drinks Grid, Statistics, Contact, and Footer |
/#home |
Home |
Scroll-positions the viewport at the Hero section |
/#drinks |
Home |
Scroll-positions the viewport at the Drinks collection section |
/#contact |
Home |
Scroll-positions the viewport at the Contact section |
/#drink-<drink-id> |
Home |
Scroll-targets the specific drink card with DOM ID drink-<drink-id> |
/?recipe=<recipe-id> |
Home |
Scroll-targets the drink card matching the specified recipe ID |
/drinks |
Home |
Direct pathname route targeting the Drinks collection |
/recipes |
Recipes |
Displays the complete recipe cards collection |
/recipes?recipe=<recipe-id> |
Recipes |
Targets and highlights the recipe card with DOM ID recipe-card-<recipe-id> |
/recipes/<recipe-id> |
Recipes |
Displays recipes view with the specified recipe card marked active |
/favorites |
Favorites |
Filtered view displaying user-saved favorite drink cards |
Note: If an unknown recipe or drink ID is supplied in the URL, the page renders gracefully without attempting an invalid scroll target.
| Component | File Path | Responsibilities |
|---|---|---|
Navbar |
src/components/Navbar.js |
Top-level branding, active section tracking, theme switcher, and mobile drawer toggle |
HeroSection |
src/components/HeroSection.js |
Visual hero banner, quick category filters (Cold / Hot / Sweet), and search input |
DrinkCardGrid |
src/components/DrinkCardGrid.js |
Grid of drink cards with favorite controls and links to detailed recipes |
RecipeCardGrid |
src/components/RecipeCardGrid.js |
Structured recipe cards detailing ingredients, preparation steps, metadata, and back-links |
Contact |
src/components/Contact.js |
External community and communication links (LinkedIn, Facebook, TikTok, WhatsApp) |
Footer |
src/components/Footer.js |
Project information, internal anchors, and direct email link |
Toast |
src/components/Toast.js |
Accessible alert status notification utilizing an aria-live region |
┌─────────────────────────────────────────────────────────────────────────┐
│ src/App.js (State) │
├───────────────────────────────────┬─────────────────────────────────────┤
│ In-Memory (Transient) │ Local Storage (Persistent) │
├───────────────────────────────────┼─────────────────────────────────────┤
│ • Theme mode (light / dark) │ • 'favorite-drink-ids' │
│ • Search query │ (Validated and normalized against │
│ • Active category filter │ available IDs in src/data.js) │
│ • Mobile menu toggle state │ │
│ • Active route & recipe ID │ │
│ • Loading indicator state │ │
└───────────────────────────────────┴─────────────────────────────────────┘
recipes-tk/
├── assets/
│ └── screenshots/
│ ├── drinks-grid.png
│ ├── hero-section.png
│ └── recipe-details.png
├── public/
│ ├── img/
│ ├── index.html
│ ├── manifest.json
│ ├── pr.jpg
│ └── robots.txt
├── src/
│ ├── components/
│ │ ├── Contact.js
│ │ ├── DrinkCardGrid.js
│ │ ├── Footer.js
│ │ ├── HeroSection.js
│ │ ├── Navbar.js
│ │ ├── RecipeCardGrid.js
│ │ └── Toast.js
│ ├── hooks/
│ │ └── useScrollProgress.js
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── data.js
│ ├── index.css
│ ├── index.js
│ ├── reportWebVitals.js
│ └── setupTests.js
├── package.json
├── package-lock.json
└── README.md
- Node.js and npm installed on your system.
- A modern web browser supported by Create React App's default browserslist.
git clone <repository-url>
cd recipes-tknpm installNote: The project runs entirely on client-side static data. No environment variables or
.envfiles are required.
npm startThe application will launch at http://localhost:3000. If port 3000 is occupied, Create React App will prompt to run on an alternate available port.
npm run buildCompiled, production-ready static assets will be output to the build/ directory.
| Script | Command | Purpose |
|---|---|---|
| Development | npm start |
Launches the Create React App development server with hot reloading |
| Build | npm run build |
Bundles and optimizes static production assets into build/ |
| Test | npm test |
Executes React Testing Library test suite (App.test.js) in interactive watch mode |
| Eject | npm run eject |
Ejects Create React App configuration and dependencies (Irreversible) |
The HTML document shell located in public/index.html includes:
- Language & Direction:
lang="ar"for Arabic layout context. - Title:
RKN AL TAHLIA - Description:
ركن التحلية - وصفات مشروبات عربية فاخرة بأسلوب غني وفاخر. - Theme Color:
#000000 - Branding Assets: Favicon and Apple Touch Icon linked to
public/pr.jpg. - Web App Manifest:
public/manifest.jsonreferencing default application metadata. - Robots Policy:
public/robots.txtpermitting standard web crawler access across all routes.
The application compiles into static files (HTML, CSS, JS, and media assets) inside build/.
Important Deployment Requirement:
Because the application relies on client-side History API routing for pathname routes (such as/recipesand/favorites), your static web server (e.g., Nginx, Apache, Netlify, Vercel, Firebase Hosting, GitHub Pages) must be configured to route all unknown path requests back topublic/index.html(SPA fallback).
| Issue | Potential Cause | Solution |
|---|---|---|
| Dependency installation fails | Node/npm version mismatch or corrupted node_modules | Ensure Node.js is up to date and run npm install using the committed package-lock.json. |
| Port 3000 is already in use | Another local process is binding to port 3000 | Accept the CLI prompt to bind to an alternate port, or terminate the process utilizing port 3000. |
| 404 Not Found on direct route visit | Server lacking SPA rewrite / fallback configuration | Configure your static web host to route all pathname requests (e.g., /recipes) to fallback to index.html. |
| Images failing to load | Missing or altered asset paths | Ensure the public/img/ directory remains intact with the original filenames, as images use root-relative paths. |
- ID Integrity: Always link drinks and recipes using stable string IDs (
drink-<recipe-id>) rather than mutable array indexes. - Routing Engine: Preserve the browser History API and
popstateevent listeners when modifying view navigation. - Linting: Code formatting follows Create React App's internal ESLint configuration.
- Version:
0.1.0(as declared inpackage.json). - License: No license file or project license declaration is currently included in the repository.
Eslam Adel
- Email: Eslam.Adel2596@gmail.com
- LinkedIn: linkedin.com/in/eslam-adel-jadalrab-808862361
- Facebook: facebook.com/eslam20057
- TikTok: @eslam.adel2596
- WhatsApp: +20 109 339 7961


