Skip to content

Commit 59deb24

Browse files
committed
fix: added mobile sidebar menu
1 parent c2aeaf8 commit 59deb24

4 files changed

Lines changed: 169 additions & 105 deletions

File tree

package-lock.json

Lines changed: 9 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/Header.tsx

Lines changed: 114 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,124 @@
1-
2-
import { useLanguage } from "@/contexts/LanguageContext";
1+
import {useState} from "react";
2+
import {Link, useNavigate} from "react-router-dom";
3+
import {Home, Menu} from "lucide-react";
4+
import {useLanguage} from "@/contexts/LanguageContext";
5+
import {cn} from "@/lib/utils";
36
import LanguageToggle from "./LanguageToggle";
4-
import { ModeToggle } from "./ModeToggle";
5-
import { cn } from "@/lib/utils";
6-
import { Link } from "react-router-dom";
7-
import { Home } from "lucide-react";
7+
import {ModeToggle} from "./ModeToggle";
8+
import {Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger,} from "@/components/ui/sheet.tsx";
9+
import {Button} from "@/components/ui/button.tsx";
10+
11+
type MenuItem = {
12+
label: string;
13+
icon: React.ComponentType<{ className?: string }> | null;
14+
path: string;
15+
};
816

917
const Header = () => {
10-
const { t, isRTL } = useLanguage();
18+
const {t, isRTL} = useLanguage();
19+
const navigate = useNavigate();
20+
const [isMenuOpen, setMenuOpen] = useState(false);
1121

12-
return (
13-
<header className="sticky top-0 z-10 bg-background/80 backdrop-blur-sm shadow-sm py-4 dark:shadow-yaqiin-50/5">
14-
<div className="yaqiin-container flex items-center justify-between">
15-
<div
16-
className={`flex items-center gap-4 ${isRTL ? "ml-auto" : "mr-auto"}`}
17-
>
18-
<Link to="/">
19-
<img
20-
src="/logo.png"
21-
alt="Site logo"
22-
className="w-12 h-12 md:w-16 md:h-16"
23-
/>
22+
const menuItems: MenuItem[] = [
23+
{
24+
label: t("products"),
25+
icon: Home,
26+
path: "/",
27+
},
28+
{
29+
label: t("whyBoycott"),
30+
icon: null,
31+
path: "/why",
32+
},
33+
];
34+
35+
const renderMobileMenu = () => (
36+
<div className="md:hidden">
37+
<Sheet open={isMenuOpen} onOpenChange={setMenuOpen}>
38+
<SheetTrigger asChild>
39+
<Menu className="w-10 shadow-sm"/>
40+
</SheetTrigger>
41+
<SheetContent side={isRTL ? "right" : "left"} className="w-64">
42+
<SheetHeader>
43+
<SheetTitle className="text-lg font-bold">
44+
{t("menuTitle")}
45+
</SheetTitle>
46+
</SheetHeader>
47+
<SheetDescription className="flex flex-col gap-4 mt-4">
48+
{menuItems.map((item, index) => (
49+
<Button
50+
key={index}
51+
variant="ghost"
52+
className="w-full justify-center"
53+
onClick={() => {
54+
navigate(item.path);
55+
setMenuOpen(false);
56+
}}
57+
>
58+
{item.icon && <item.icon className="mr-2 h-4 w-4"/>}
59+
{item.label}
60+
</Button>
61+
))}
62+
<LanguageToggle/>
63+
</SheetDescription>
64+
</SheetContent>
65+
</Sheet>
66+
</div>
67+
);
68+
69+
const renderLogo = () => (
70+
<div className={cn("flex items-center gap-4", isRTL ? "ml-auto" : "mr-auto")}>
71+
<Link to="/">
72+
<img
73+
src="/logo.png"
74+
alt="Site logo"
75+
className="w-12 h-12 md:w-16 md:h-16"
76+
/>
77+
</Link>
78+
<div>
79+
<h1 className="text-xl md:text-2xl font-bold">
80+
{t("siteName")}
81+
</h1>
82+
<p className="text-sm md:text-base">
83+
{t("siteSlogan")}
84+
</p>
85+
</div>
86+
</div>
87+
);
88+
89+
const renderDesktopNav = () => (
90+
<div className="hidden md:block">
91+
<nav className="flex items-center gap-4 mx-4">
92+
{menuItems.map((menuItem, index) => (
93+
<Link
94+
key={index}
95+
to={menuItem.path}
96+
className="flex items-center gap-2 px-3 py-2 rounded-md transition-colors text-foreground/80 hover:text-yaqiin-500"
97+
>
98+
{menuItem.icon && <menuItem.icon size={18}/>}
99+
<span>{menuItem.label}</span>
24100
</Link>
25-
<div>
26-
<h1 className="text-xl md:text-2xl font-bold text-foreground">
27-
{t("siteName")}
28-
</h1>
29-
<p className="text-mosque-accent text-sm md:text-base">
30-
{t("siteSlogan")}
31-
</p>
32-
</div>
33-
</div>
101+
))}
102+
</nav>
103+
</div>
104+
);
34105

35-
<div className="flex items-center gap-2">
36-
<nav className="hidden md:flex items-center gap-4 mx-4">
37-
<Link
38-
to="/"
39-
className="flex items-center gap-2 px-3 py-2 rounded-md hover:bg-accent transition-colors text-foreground/80 hover:text-foreground"
40-
>
41-
<Home size={18} />
42-
<span>{t("products")}</span>
43-
</Link>
44-
<Link
45-
to="/why"
46-
className="px-3 py-2 rounded-md hover:bg-accent transition-colors text-foreground/80 hover:text-foreground"
47-
>
48-
{t("whyBoycott")}
49-
</Link>
50-
</nav>
51-
</div>
106+
const renderControls = () => (
107+
<div className={cn(isRTL ? "mr-auto" : "ml-auto", "flex items-center gap-2")}>
108+
<div className="hidden md:block">
109+
<LanguageToggle/>
110+
</div>
111+
<ModeToggle/>
112+
</div>
113+
);
52114

53-
<div
54-
className={cn(
55-
isRTL ? "mr-auto" : "ml-auto",
56-
"flex items-center gap-2"
57-
)}
58-
>
59-
<LanguageToggle />
60-
<ModeToggle />
61-
</div>
115+
return (
116+
<header className="sticky top-0 z-10 bg-background/80 backdrop-blur-sm shadow-sm py-4 dark:shadow-yaqiin-50/5">
117+
<div className="yaqiin-container flex items-center justify-between">
118+
{renderMobileMenu()}
119+
{renderLogo()}
120+
{renderDesktopNav()}
121+
{renderControls()}
62122
</div>
63123
</header>
64124
);

src/contexts/LanguageContext/languageConfig.ts

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
export interface LanguageConfig {
32
code: string;
43
name: string;
@@ -7,51 +6,23 @@ export interface LanguageConfig {
76
}
87

98
export const SUPPORTED_LANGUAGES: Record<string, LanguageConfig> = {
10-
ar: { code: 'ar', name: 'Arabic', nativeName: 'العربية', dir: 'rtl' },
11-
en: { code: 'en', name: 'English', nativeName: 'English', dir: 'ltr' },
12-
bn: { code: 'bn', name: 'Bengali', nativeName: 'বাংলা', dir: 'ltr' },
13-
es: { code: 'es', name: 'Spanish', nativeName: 'Español', dir: 'ltr' },
14-
fr: { code: 'fr', name: 'French', nativeName: 'Français', dir: 'ltr' },
15-
id: { code: 'id', name: 'Indonesian', nativeName: 'Bahasa Indonesia', dir: 'ltr' },
16-
tr: { code: 'tr', name: 'Turkish', nativeName: 'Türkçe', dir: 'ltr' },
17-
ur: { code: 'ur', name: 'Urdu', nativeName: 'اردو', dir: 'rtl' },
9+
ar: {code: 'ar', name: 'Arabic', nativeName: 'العربية', dir: 'rtl'},
10+
en: {code: 'en', name: 'English', nativeName: 'English', dir: 'ltr'},
11+
bn: {code: 'bn', name: 'Bengali', nativeName: 'বাংলা', dir: 'ltr'},
12+
es: {code: 'es', name: 'Spanish', nativeName: 'Español', dir: 'ltr'},
13+
fr: {code: 'fr', name: 'French', nativeName: 'Français', dir: 'ltr'},
14+
id: {code: 'id', name: 'Indonesian', nativeName: 'Bahasa Indonesia', dir: 'ltr'},
15+
tr: {code: 'tr', name: 'Turkish', nativeName: 'Türkçe', dir: 'ltr'},
16+
ur: {code: 'ur', name: 'Urdu', nativeName: 'اردو', dir: 'rtl'},
1817
};
1918

2019
export type Language = keyof typeof SUPPORTED_LANGUAGES;
2120

2221
export const translations = {
23-
bn: {
24-
'siteName': 'ইয়াকীন বয়কট',
25-
'siteSlogan': 'নৈতিক বয়কট, আমাদের ভাইদের সমর্থন',
26-
'toggleLanguage': 'বাংলা',
27-
'searchPlaceholder': 'একটি পণ্য খুঁজুন',
28-
'productName': 'পণ্যের নাম',
29-
'countryOfOrigin': 'উৎপত্তির দেশ',
30-
'alternatives': 'বিকল্পসমূহ',
31-
'noAlternatives': 'এখনো কোনো বিকল্প উপলব্ধ নেই',
32-
'loading': 'লোড হচ্ছে...',
33-
'error': 'ডেটা লোড করতে সমস্যা হয়েছে',
34-
'pageNotFound': 'উপস! পেজটি পাওয়া যায়নি',
35-
'backHome': 'হোমে ফিরুন',
36-
'introText': 'ইসরায়েলি এবং মার্কিন প্রযুক্তি পণ্যের নৈতিক বিকল্পগুলি আবিষ্কার করতে সাহায্য করার একটি প্ল্যাটফর্ম।',
37-
'copyright': 'ইয়াকীন বয়কট। সর্বস্বত্ব সংরক্ষিত।',
38-
'whyBoycott': 'কেন বয়কট?',
39-
'products': 'পণ্যসমূহ',
40-
'backToProducts': 'পণ্যসমূহে ফিরে যান',
41-
'whyBoycottSubtitle1': 'আমরা কেন বয়কট করি?',
42-
'whyBoycottParagraph1': 'বয়কট হল আমাদের ভোক্তা ক্ষমতা ব্যবহার করে অন্যায়কারী প্রতিষ্ঠানগুলিকে তাদের নীতি পরিবর্তন করতে বাধ্য করার একটি শক্তিশালী উপায়।',
43-
'whyBoycottSubtitle2': 'এর প্রভাব কী?',
44-
'whyBoycottParagraph2': 'সম্মিলিত ক্রেতাদের বয়কট সংস্থাগুলির আর্থিক স্বাস্থ্যকে প্রভাবিত করতে পারে এবং কোম্পানির আচরণে পরিবর্তন আনতে পারে।',
45-
'whyBoycottSubtitle3': 'কিভাবে বয়কট কাজ করে?',
46-
'whyBoycottParagraph3': 'আমরা কোম্পানিগুলির পণ্য ও পরিষেবা না কিনে এবং নৈতিক বিকল্পগুলিকে সমর্থন করে আমাদের অর্থনৈতিক ক্ষমতার কণ্ঠস্বর দেই।',
47-
'whyBoycottSubtitle4': 'কেন এই বয়কট?',
48-
'whyBoycottParagraph4': 'যারা অন্যায়, নিপীড়ন এবং মানবাধিকার লঙ্ঘনে সহায়তা করে তাদের থেকে অর্থনৈতিক সমর্থন ফিরিয়ে নেওয়া আমাদের নৈতিক দায়িত্ব।',
49-
'allCategories': 'সকল বিভাগ',
50-
'productsCount': 'পণ্য',
51-
},
5222
ar: {
5323
'siteName': 'يقين للمقاطعة',
5424
'siteSlogan': 'مقاطعة أخلاقية، نصرة لأخوتنا',
25+
'menuTitle': 'القائمة',
5526
'toggleLanguage': 'English',
5627
'searchPlaceholder': 'ابحث عن منتج',
5728
'productName': 'اسم المنتج',
@@ -78,9 +49,40 @@ export const translations = {
7849
'allCategories': 'جميع الفئات',
7950
'productsCount': 'منتج',
8051
},
52+
bn: {
53+
'siteName': 'ইয়াকীন বয়কট',
54+
'siteSlogan': 'নৈতিক বয়কট, আমাদের ভাইদের সমর্থন',
55+
'menuTitle': 'তালিকা',
56+
'toggleLanguage': 'বাংলা',
57+
'searchPlaceholder': 'একটি পণ্য খুঁজুন',
58+
'productName': 'পণ্যের নাম',
59+
'countryOfOrigin': 'উৎপত্তির দেশ',
60+
'alternatives': 'বিকল্পসমূহ',
61+
'noAlternatives': 'এখনো কোনো বিকল্প উপলব্ধ নেই',
62+
'loading': 'লোড হচ্ছে...',
63+
'error': 'ডেটা লোড করতে সমস্যা হয়েছে',
64+
'pageNotFound': 'উপস! পেজটি পাওয়া যায়নি',
65+
'backHome': 'হোমে ফিরুন',
66+
'introText': 'ইসরায়েলি এবং মার্কিন প্রযুক্তি পণ্যের নৈতিক বিকল্পগুলি আবিষ্কার করতে সাহায্য করার একটি প্ল্যাটফর্ম।',
67+
'copyright': 'ইয়াকীন বয়কট। সর্বস্বত্ব সংরক্ষিত।',
68+
'whyBoycott': 'কেন বয়কট?',
69+
'products': 'পণ্যসমূহ',
70+
'backToProducts': 'পণ্যসমূহে ফিরে যান',
71+
'whyBoycottSubtitle1': 'আমরা কেন বয়কট করি?',
72+
'whyBoycottParagraph1': 'বয়কট হল আমাদের ভোক্তা ক্ষমতা ব্যবহার করে অন্যায়কারী প্রতিষ্ঠানগুলিকে তাদের নীতি পরিবর্তন করতে বাধ্য করার একটি শক্তিশালী উপায়।',
73+
'whyBoycottSubtitle2': 'এর প্রভাব কী?',
74+
'whyBoycottParagraph2': 'সম্মিলিত ক্রেতাদের বয়কট সংস্থাগুলির আর্থিক স্বাস্থ্যকে প্রভাবিত করতে পারে এবং কোম্পানির আচরণে পরিবর্তন আনতে পারে।',
75+
'whyBoycottSubtitle3': 'কিভাবে বয়কট কাজ করে?',
76+
'whyBoycottParagraph3': 'আমরা কোম্পানিগুলির পণ্য ও পরিষেবা না কিনে এবং নৈতিক বিকল্পগুলিকে সমর্থন করে আমাদের অর্থনৈতিক ক্ষমতার কণ্ঠস্বর দেই।',
77+
'whyBoycottSubtitle4': 'কেন এই বয়কট?',
78+
'whyBoycottParagraph4': 'যারা অন্যায়, নিপীড়ন এবং মানবাধিকার লঙ্ঘনে সহায়তা করে তাদের থেকে অর্থনৈতিক সমর্থন ফিরিয়ে নেওয়া আমাদের নৈতিক দায়িত্ব।',
79+
'allCategories': 'সকল বিভাগ',
80+
'productsCount': 'পণ্য',
81+
},
8182
en: {
8283
'siteName': 'Yaqiin Boycott',
8384
'siteSlogan': 'Ethical Boycott, Supporting Our Brothers',
85+
'menuTitle': 'Menu',
8486
'toggleLanguage': 'العربية',
8587
'searchPlaceholder': 'Search for a product',
8688
'productName': 'Product Name',
@@ -110,6 +112,7 @@ export const translations = {
110112
es: {
111113
'siteName': 'Yaqiin Boicot',
112114
'siteSlogan': 'Boicot Ético, Apoyando a Nuestros Hermanos',
115+
'menuTitle': 'Menú',
113116
'toggleLanguage': 'Cambiar Idioma',
114117
'searchPlaceholder': 'Buscar un producto',
115118
'productName': 'Nombre del Producto',
@@ -139,6 +142,7 @@ export const translations = {
139142
fr: {
140143
'siteName': 'Yaqiin Boycott',
141144
'siteSlogan': 'Boycott Éthique, Soutenir Nos Frères',
145+
'menuTitle': 'Menu',
142146
'toggleLanguage': 'Changer de langue',
143147
'searchPlaceholder': 'Rechercher un produit',
144148
'productName': 'Nom du Produit',
@@ -168,6 +172,7 @@ export const translations = {
168172
id: {
169173
'siteName': 'Yaqiin Boikot',
170174
'siteSlogan': 'Boikot Etis, Mendukung Saudara-saudara Kita',
175+
'menuTitle': 'Menu',
171176
'toggleLanguage': 'Bahasa Indonesia',
172177
'searchPlaceholder': 'Cari produk',
173178
'productName': 'Nama Produk',
@@ -197,6 +202,7 @@ export const translations = {
197202
tr: {
198203
'siteName': 'Yaqiin Boykot',
199204
'siteSlogan': 'Etik Boykot, Kardeşlerimize Destek',
205+
'menuTitle': 'Menü',
200206
'toggleLanguage': 'Türkçe',
201207
'searchPlaceholder': 'Bir ürün ara',
202208
'productName': 'Ürün Adı',
@@ -226,6 +232,7 @@ export const translations = {
226232
ur: {
227233
'siteName': 'یقین بائیکاٹ',
228234
'siteSlogan': 'اخلاقی بائیکاٹ، ہمارے بھائیوں کی حمایت',
235+
'menuTitle': 'فہرست',
229236
'toggleLanguage': 'اردو',
230237
'searchPlaceholder': 'مصنوعات تلاش کریں',
231238
'productName': 'مصنوعات کا نام',

src/pages/Why.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const Why = () => {
3232
</Link>
3333

3434
<div className="max-w-3xl mx-auto">
35-
<h1 className="text-3xl font-bold mb-6 text-yaqiin-800 dark:text-yaqiin-500">
35+
<h1 className="text-3xl font-bold mb-6 text-yaqiin-800 dark:text-yaqiin-500 text-center">
3636
{t("whyBoycott")}
3737
</h1>
3838
<section className="prose p-6 dark:prose-invert prose-yaqiin">

0 commit comments

Comments
 (0)