Merge remote-tracking branch 'origin' into navbar

This commit is contained in:
zahravaziri
2025-06-01 17:36:19 +03:30
14 changed files with 167 additions and 101 deletions
+2 -4
View File
@@ -1,7 +1,5 @@
import type { NextConfig } from "next";
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
/* config options here */
};
const nextConfig: NextConfig = {};
export default nextConfig;
+2 -14
View File
@@ -8,13 +8,9 @@
"name": "pasargad_bricks",
"version": "0.1.0",
"dependencies": {
"i18next": "^25.2.1",
"i18next-browser-languagedetector": "^8.1.0",
"i18next-http-backend": "^3.0.2",
"next": "15.3.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-i18next": "^15.5.2"
"react-dom": "^19.0.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
@@ -57,14 +53,6 @@
"node": ">=6.0.0"
}
},
"node_modules/@babel/runtime": {
"version": "7.27.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.4.tgz",
"integrity": "sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@emnapi/core": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz",
@@ -5762,7 +5750,7 @@
"version": "5.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"devOptional": true,
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
+1 -5
View File
@@ -9,13 +9,9 @@
"lint": "next lint"
},
"dependencies": {
"i18next": "^25.2.1",
"i18next-browser-languagedetector": "^8.1.0",
"i18next-http-backend": "^3.0.2",
"next": "15.3.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-i18next": "^15.5.2"
"react-dom": "^19.0.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
+1 -1
View File
@@ -10,7 +10,7 @@ export default async function Home() {
const data = await getData();
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24 text-gray-300">
<main className="flex min-h-screen flex-col items-center justify-between p-24 text-bg-primary">
ssss
</main>
);
+9 -9
View File
@@ -1,24 +1,24 @@
'use client'
import type { Metadata } from 'next';
import './globals.css';
import { I18nextProvider } from 'react-i18next';
import i18n from '../config/i18n';
import { cookies } from 'next/headers';
// export const metadata: Metadata = {
// title: 'Create Next App',
// description: 'Generated by create next app',
// };
export default function RootLayout({
export default async function RootLayout({
children,
}: {
}: Readonly<{
children: React.ReactNode;
}) {
}>) {
const cookieStore = await cookies();
const locale = cookieStore.get('lang')?.value || 'en';
return (
<html lang="en">
<I18nextProvider i18n={i18n}>
<body>{children}</body>
</I18nextProvider>
<html lang={locale} dir={locale === 'fa' ? 'rtl' : 'ltr'}>
<body>{children}</body>
</html>
);
}
+10 -3
View File
@@ -1,6 +1,8 @@
// ... existing imports ...
import Header from '@/components/layout/header';
import Navbar from '@/components/layout/navbar';
import ChangeLangButton from '@/components/layout/languageSwitcher';
import { changeLanguage, t } from '@/locales/translates';
async function getData() {
// Simulate a delay to show server-side data fetching
@@ -8,13 +10,18 @@ async function getData() {
return { message: 'This data was fetched on the server!' };
}
const change = () => {
changeLanguage('fa');
};
export default async function Home() {
const data = await getData();
return (
<main className="">
<main className="flex min-h-screen flex-col items-center justify-between p-24 text-gray-300">
<Header/>
{/* <Navbar/> */}
<span>{t('pages_home_title') as string}</span>
</main>
);
)
}
+3 -4
View File
@@ -1,13 +1,12 @@
import { useTranslation } from 'react-i18next';
const { t } = useTranslation('routes');
import { t, translates } from '@/locales/translates';
export default {
home: {
title: t('home'),
title: t('pages_home_title'),
route: () => '/',
},
about: {
title: t('about'),
title: t('pages_about_title'),
route: () => '/about',
},
};
@@ -0,0 +1,17 @@
'use client';
import { changeLanguage, TLocales } from '@/locales/translates';
import Button from '../Button';
export default function ChangeLangButton() {
const changeLang = (lang: TLocales) => {
changeLanguage(lang);
window.location.reload(); // Reload to get new SSR content
};
return (
<>
<Button onClick={() => changeLang('en')}>English</Button>
<Button onClick={() => changeLang('fa')}>فارسی</Button>
</>
);
}
+1
View File
@@ -1,3 +1,4 @@
'use client';
import React, { ButtonHTMLAttributes, ReactNode } from 'react';
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
-19
View File
@@ -1,19 +0,0 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-http-backend';
i18n
.use(Backend)
.use(initReactI18next)
.init({
fallbackLng: 'en',
debug: false,
interpolation: {
escapeValue: false,
},
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json',
}
});
export default i18n;
+10
View File
@@ -0,0 +1,10 @@
const en = {
pages_home_title: 'Home',
pages_home_description: 'Welcome to the home page',
pages_about_title: 'About Us',
pages_about_description: 'Learn more about us on this page',
pages_contact_title: 'Contact Us',
pages_contact_description: 'Get in touch with us through this page',
};
export default en;
+12
View File
@@ -0,0 +1,12 @@
import { Translates } from './translates';
const fa = {
pages_home_title: 'صفحه‌ی اصلی',
pages_home_description: 'Welcome to the home page',
pages_about_title: 'About Us',
pages_about_description: 'Learn more about us on this page',
pages_contact_title: 'Contact Us',
pages_contact_description: 'Get in touch with us through this page',
} as Translates;
export default fa;
+57
View File
@@ -0,0 +1,57 @@
import en from './en';
import fa from './fa';
// Universal getCookie function
export function getCookie(name: string): string | undefined {
if (typeof window !== 'undefined') {
// Client-side
const match = document.cookie.match(
new RegExp('(^| )' + name + '=([^;]+)'),
);
return match ? decodeURIComponent(match[2]) : undefined;
} else {
// Server-side (Next.js App Router)
try {
// Dynamically import to avoid errors in client bundle
const { cookies } = require('next/headers');
return cookies().get(name)?.value;
} catch {
return undefined;
}
}
}
// Universal setCookie function to change language
export function changeLanguage(lang: TLocales, days = 365) {
if (typeof window !== 'undefined') {
// Client-side
const expires = new Date(Date.now() + days * 864e5).toUTCString();
document.cookie = `lang=${encodeURIComponent(lang)}; expires=${expires}; path=/`;
} else {
// Server-side (Next.js App Router)
try {
const { cookies } = require('next/headers');
cookies().set('lang', lang, { path: '/', maxAge: days * 24 * 60 * 60 });
} catch {
// No-op on server if not available
}
}
}
export const locales = {
en: en as Translates,
fa,
} as Record<TLocales, Translates>;
export const translates = (key: keyof Translates): string | (() => string) => {
const lang = (getCookie('lang') || 'en') as TLocales;
return locales[lang][key] || locales.en[key] || key;
};
export const t = (key: keyof Translates) => translates(key);
export type TLocales = 'en' | 'fa';
export type Translates = {
[K in keyof typeof en]: string | (() => string);
};
+42 -42
View File
@@ -9,51 +9,51 @@ const config: Config = {
],
theme: {
// Move your custom colors directly here to override default Tailwind colors
extend: {
colors: {
// Custom colors
primary: {
light: '#6366F1',
DEFAULT: '#6366F1',
dark: '#FA003F',
colors: {
// Custom colors
primary: {
light: '#6366F1',
DEFAULT: '#6366F1',
dark: '#FA003F',
},
secondary: {
light: '#A78BFA',
DEFAULT: '#8B5CF6',
dark: '#7C3AED',
},
textColorLight: {
light: '#FFFFFF',
DEFAULT: '#FFFFFF',
dark: '#FA003F',
},
textColorGray: {
light: '#222222',
DEFAULT: '#222222',
dark: '#FA003F',
},
bgPrimary: {
light: '#FFFFFF',
DEFAULT: '#FFFFFF',
dark: '#FA003F',
},
gray: {
light: {
100: '#EBEBEB',
200: '#F5F5F5',
300: '#81848A',
400: '#777',
500: '#222',
},
secondary: {
light: '#A78BFA',
DEFAULT: '#8B5CF6',
dark: '#7C3AED',
},
textColorLight: {
light: '#FFFFFF',
DEFAULT: '#FFFFFF',
dark: '#FA003F',
},
textColorGray: {
light: '#222222',
DEFAULT: '#222222',
dark: '#FA003F',
},
bgPrimary: {
light: '#FFFFFF',
DEFAULT: '#FFFFFF',
dark: '#FA003F',
},
gray: {
light: {
100: '#EBEBEB',
200: '#F5F5F5',
300: '#81848A',
400: '#777',
500: '#222',
},
dark: {
100: '#EBEBEB',
200: '#F5F5F5',
300: '#81848A',
400: '#777',
500: '#222',
},
dark: {
100: '#EBEBEB',
200: '#F5F5F5',
300: '#81848A',
400: '#777',
500: '#222',
},
},
},
extend: {
backgroundImage: {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
'gradient-conic':