fix config

This commit is contained in:
dimitar 2025-03-27 11:34:43 +01:00
parent 269789e5ed
commit 71a12f8c0e
15 changed files with 1495 additions and 624 deletions

36
globals.css Normal file
View File

@ -0,0 +1,36 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--background: 255 255 255;
--foreground: 23 23 23;
--card: 255 255 255;
--card-foreground: 23 23 23;
--primary: 59 130 246;
--primary-foreground: 255 255 255;
--muted: 245 245 245;
--muted-foreground: 115 115 115;
--accent: 245 245 245;
--accent-foreground: 23 23 23;
--border: 229 229 229;
}
.dark {
--background: 10 10 10;
--foreground: 237 237 237;
--card: 23 23 23;
--card-foreground: 237 237 237;
--primary: 59 130 246;
--primary-foreground: 255 255 255;
--muted: 38 38 38;
--muted-foreground: 163 163 163;
--accent: 38 38 38;
--accent-foreground: 237 237 237;
--border: 38 38 38;
}
body {
background-color: rgb(var(--background));
color: rgb(var(--foreground));
font-family: var(--font-sans), system-ui, sans-serif;
}

1608
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -20,13 +20,14 @@
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"autoprefixer": "^10.4.21",
"eslint": "^9",
"eslint-config-next": "15.2.4",
"tailwindcss": "^4",
"postcss": "^8.5.3",
"tailwindcss": "^3.4.17",
"typescript": "^5"
}
}

4
postcss.config.js Normal file
View File

@ -0,0 +1,4 @@
export const plugins = {
tailwindcss: {},
autoprefixer: {},
};

View File

@ -1,5 +0,0 @@
const config = {
plugins: ["@tailwindcss/postcss"],
};
export default config;

View File

@ -0,0 +1,106 @@
// ngc/src/app/[locale]/about/page.tsx
import { unstable_setRequestLocale } from "next-intl/server";
import { getTranslations } from "next-intl/server";
import Image from "next/image";
type Props = {
params: { locale: string };
};
export default async function AboutPage({ params: { locale } }: Props) {
unstable_setRequestLocale(locale);
const t = await getTranslations("about");
return (
<div className="py-12">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="lg:text-center">
<h2 className="text-base text-blue-600 font-semibold tracking-wide uppercase">
{t("subtitle")}
</h2>
<p className="mt-2 text-3xl leading-8 font-extrabold tracking-tight text-gray-900 dark:text-white sm:text-4xl">
{t("title")}
</p>
<p className="mt-4 max-w-2xl text-xl text-gray-500 dark:text-gray-300 lg:mx-auto">
{t("description")}
</p>
</div>
<div className="mt-16">
<div className="grid grid-cols-1 gap-12 lg:grid-cols-3">
{[1, 2, 3].map((index) => (
<div key={index} className="pt-6">
<div className="flow-root bg-gray-50 dark:bg-gray-800 rounded-lg px-6 pb-8">
<div className="-mt-6">
<div>
<span className="inline-flex items-center justify-center p-3 bg-blue-500 rounded-md shadow-lg">
<svg
className="h-6 w-6 text-white"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M5 13l4 4L19 7"
/>
</svg>
</span>
</div>
<h3 className="mt-8 text-lg font-medium text-gray-900 dark:text-white tracking-tight">
{t(`values.${index}.title`)}
</h3>
<p className="mt-5 text-base text-gray-500 dark:text-gray-300">
{t(`values.${index}.description`)}
</p>
</div>
</div>
</div>
))}
</div>
</div>
<div className="mt-20">
<h3 className="text-2xl font-bold text-gray-900 dark:text-white mb-8 lg:text-center">
{t("teamTitle")}
</h3>
<div className="grid grid-cols-1 gap-12 sm:grid-cols-2 lg:grid-cols-4">
{[1, 2, 3, 4].map((index) => (
<div key={index} className="text-center">
<div className="relative mx-auto h-40 w-40 overflow-hidden rounded-full">
<Image
className="h-full w-full object-cover"
src={`/team-member-${index}.jpg`}
alt={t(`team.${index}.name`)}
width={160}
height={160}
/>
</div>
<div className="mt-4">
<h4 className="text-lg font-semibold">
{t(`team.${index}.name`)}
</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
{t(`team.${index}.role`)}
</p>
</div>
</div>
))}
</div>
</div>
</div>
</div>
);
}
export function generateMetadata({ params: { locale } }: Props) {
unstable_setRequestLocale(locale);
return {
title: "About Us",
description: "Learn more about our company, team and values",
};
}

View File

@ -0,0 +1,8 @@
function ContactPage() {
return (
<div>
<h1 className="bg-yellow-400">Contact Page</h1>
</div>
);
}
export default ContactPage;

View File

@ -1,24 +1,36 @@
@import "tailwindcss";
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--background: #ffffff;
--foreground: #171717;
--background: 255 255 255;
--foreground: 23 23 23;
--card: 255 255 255;
--card-foreground: 23 23 23;
--primary: 59 130 246;
--primary-foreground: 255 255 255;
--muted: 245 245 245;
--muted-foreground: 115 115 115;
--accent: 245 245 245;
--accent-foreground: 23 23 23;
--border: 229 229 229;
}
.dark {
--background: #0a0a0a;
--foreground: #ededed;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-inter);
--font-mono: var(--font-roboto-mono);
--background: 10 10 10;
--foreground: 237 237 237;
--card: 23 23 23;
--card-foreground: 237 237 237;
--primary: 59 130 246;
--primary-foreground: 255 255 255;
--muted: 38 38 38;
--muted-foreground: 163 163 163;
--accent: 38 38 38;
--accent-foreground: 237 237 237;
--border: 38 38 38;
}
body {
background: var(--background);
color: var(--foreground);
background-color: rgb(var(--background));
color: rgb(var(--foreground));
font-family: var(--font-sans), system-ui, sans-serif;
}

View File

@ -1,90 +1,3 @@
// // ngc/src/components/navbar.tsx
// "use client";
// import { useTheme } from "./theme-provider";
// import Link from "next/link";
// import { usePathname } from "next/navigation";
// import { Sun, Moon, Globe } from "lucide-react";
// import { useState } from "react";
// const languages = [
// { code: "en", name: "English", flag: "🇬🇧" },
// { code: "mk", name: "Македонски", flag: "🇲🇰" },
// { code: "sr", name: "Српски", flag: "🇷🇸" },
// ];
// export function Navbar() {
// const { theme, toggleTheme } = useTheme();
// const pathname = usePathname();
// const [showLanguages, setShowLanguages] = useState(false);
// const currentLang = pathname.split("/")[1];
// const currentPath = pathname.split("/").slice(2).join("/");
// return (
// <nav className="border-b dark:border-gray-700">
// <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
// <div className="flex justify-between h-16 items-center">
// <div className="flex items-center">
// <Link
// href={`/${currentLang}`}
// className="text-lg font-semibold hover:text-gray-600 dark:hover:text-gray-300"
// >
// Logo
// </Link>
// </div>
// <div className="flex items-center gap-4">
// <div className="relative">
// <button
// onClick={() => setShowLanguages(!showLanguages)}
// className="p-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800"
// aria-label="Language selector"
// >
// <Globe className="h-5 w-5" />
// </button>
// {showLanguages && (
// <div className="absolute right-0 mt-2 w-48 rounded-md shadow-lg bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5">
// <div className="py-1">
// {languages.map((lang) => (
// <Link
// key={lang.code}
// href={`/${lang.code}/${currentPath}`}
// className={`block px-4 py-2 text-sm ${
// currentLang === lang.code
// ? "bg-gray-100 dark:bg-gray-700"
// : "hover:bg-gray-100 dark:hover:bg-gray-700"
// } flex items-center gap-2`}
// onClick={() => setShowLanguages(false)}
// >
// <span className="text-base">{lang.flag}</span>
// {/* <span>{lang.name}</span> */}
// </Link>
// ))}
// </div>
// </div>
// )}
// </div>
// <button
// onClick={toggleTheme}
// className="p-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800"
// aria-label="Toggle theme"
// >
// {theme === "light" ? (
// <Moon className="h-5 w-5" />
// ) : (
// <Sun className="h-5 w-5" />
// )}
// </button>
// </div>
// </div>
// </div>
// </nav>
// );
// }
// ngc/src/components/navbar.tsx
"use client";
import { useTheme } from "./theme-provider";
@ -99,23 +12,36 @@ const languages = [
{ code: "sr", name: "Српски", flag: "🇷🇸" },
];
const navLinks = [
{ name: "Home", path: "" },
{ name: "About", path: "about" },
{ name: "Contact", path: "contact" },
];
export function Navbar() {
const { theme, toggleTheme } = useTheme();
const pathname = usePathname();
const [showLanguages, setShowLanguages] = useState(false);
// Extract language code and current path
const currentLang = pathname.split("/")[1];
const currentPath = pathname.split("/").slice(2).join("/");
// Find the current language object
const currentLanguage =
languages.find((lang) => lang.code === currentLang) || languages[0];
const isActive = (path: string) => {
if (path === "" && currentPath === "") return true;
if (path !== "" && currentPath.startsWith(path)) return true;
return false;
};
return (
<nav className="border-b dark:border-gray-700">
<nav className="border-b border-gray-200 dark:border-gray-800">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16 items-center">
<div className="flex items-center">
<div className="flex items-center justify-between h-16">
{/* Left: Logo */}
<div className="flex-shrink-0">
<Link
href={`/${currentLang}`}
className="text-lg font-semibold hover:text-gray-600 dark:hover:text-gray-300"
@ -124,12 +50,31 @@ export function Navbar() {
</Link>
</div>
{/* Center: Nav links (hidden on small screens, visible on md+) */}
<div className="hidden md:flex space-x-8">
{navLinks.map((link) => (
<Link
key={link.name}
href={`/${currentLang}/${link.path}`}
className={`text-base font-medium transition-colors ${
isActive(link.path)
? "text-blue-500 dark:text-blue-400"
: "hover:text-gray-600 dark:hover:text-gray-300"
}`}
>
{link.name}
</Link>
))}
</div>
{/* Right: Language Selector & Theme Toggler */}
<div className="flex items-center gap-4">
{/* Language Selector */}
<div className="relative">
<button
onClick={() => setShowLanguages(!showLanguages)}
className="p-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 flex items-center gap-2"
aria-label="Language selector"
aria-label="Language Selector"
>
<span
className="text-xl"
@ -140,8 +85,9 @@ export function Navbar() {
</span>
</button>
{/* Dropdown for selecting languages */}
{showLanguages && (
<div className="absolute right-0 mt-2 w-48 rounded-md shadow-lg bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5">
<div className="absolute right-0 mt-2 w-48 rounded-md shadow-lg bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5 z-10">
<div className="py-1">
{languages.map((lang) => (
<Link
@ -155,7 +101,7 @@ export function Navbar() {
onClick={() => setShowLanguages(false)}
>
<span className="text-base">{lang.flag}</span>
{/* <span>{lang.name}</span> */}
<span>{lang.name}</span>
</Link>
))}
</div>
@ -163,10 +109,11 @@ export function Navbar() {
)}
</div>
{/* Theme Toggler */}
<button
onClick={toggleTheme}
className="p-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800"
aria-label="Toggle theme"
aria-label="Toggle Theme"
>
{theme === "light" ? (
<Moon className="h-5 w-5" />

View File

@ -18,8 +18,10 @@ const ThemeContext = createContext<{
export function ThemeProvider({ children }: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>("light");
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
const savedTheme = localStorage.getItem("theme") as Theme;
if (savedTheme) {
setTheme(savedTheme);
@ -34,9 +36,14 @@ export function ThemeProvider({ children }: ThemeProviderProps) {
const newTheme = theme === "light" ? "dark" : "light";
setTheme(newTheme);
localStorage.setItem("theme", newTheme);
document.documentElement.classList.toggle("dark");
document.documentElement.classList.toggle("dark", newTheme === "dark");
};
// Avoid hydration mismatch by not rendering until mounted
if (!mounted) {
return <>{children}</>;
}
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}

View File

@ -11,11 +11,11 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
return (
<button
className={cn(
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none",
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none",
{
"bg-primary text-primary-foreground hover:bg-primary/90 h-10 py-2 px-4":
"bg-blue-500 text-white hover:bg-blue-600 h-10 py-2 px-4":
variant === "primary",
"border border-input hover:bg-accent hover:text-accent-foreground h-10 py-2 px-4":
"border border-gray-300 dark:border-gray-700 hover:bg-gray-100 dark:hover:bg-gray-800 h-10 py-2 px-4":
variant === "secondary",
},
className,

View File

@ -9,5 +9,43 @@
"description": "We help ambitious businesses like yours generate more profits by building awareness, driving web traffic, connecting with customers, and growing overall sales.",
"primaryButton": "Get Started",
"secondaryButton": "Learn More"
},
"about": {
"subtitle": "Our Philosophy",
"title": "A better way to build digital experiences",
"description": "We're a team of passionate designers, developers, and strategists who are dedicated to creating exceptional digital experiences.",
"values": {
"1": {
"title": "Customer-Centric Approach",
"description": "We put our clients first and work closely with them to understand their unique challenges and goals."
},
"2": {
"title": "Quality & Excellence",
"description": "We're committed to delivering high-quality solutions that exceed expectations and stand the test of time."
},
"3": {
"title": "Innovation & Creativity",
"description": "We constantly explore new technologies and approaches to solve complex problems in creative ways."
}
},
"teamTitle": "Meet Our Team",
"team": {
"1": {
"name": "John Smith",
"role": "CEO & Founder"
},
"2": {
"name": "Sarah Johnson",
"role": "Lead Designer"
},
"3": {
"name": "Michael Chen",
"role": "Senior Developer"
},
"4": {
"name": "Emily Wilson",
"role": "Project Manager"
}
}
}
}

View File

@ -9,5 +9,43 @@
"description": "Им помагаме на амбициозните бизниси како вашиот да генерираат повеќе профит преку градење свест, зголемување на веб сообраќај, поврзување со клиенти и целокупен раст на продажбата.",
"primaryButton": "Започнете",
"secondaryButton": "Дознајте Повеќе"
},
"about": {
"subtitle": "Нашата Филозофија",
"title": "Подобар начин за градење дигитални искуства",
"description": "Ние сме тим од страствени дизајнери, програмери и стратези кои се посветени на создавање исклучителни дигитални искуства.",
"values": {
"1": {
"title": "Пристап фокусиран на клиентот",
"description": "Нашите клиенти ни се на прво место и работиме со нив за да ги разбереме нивните уникатни предизвици и цели."
},
"2": {
"title": "Квалитет и Извонредност",
"description": "Посветени сме на испорака на високо-квалитетни решенија кои ги надминуваат очекувањата и издржуваат проба на времето."
},
"3": {
"title": "Иновација и Креативност",
"description": "Постојано истражуваме нови технологии и пристапи за решавање на комплексни проблеми на креативен начин."
}
},
"teamTitle": "Запознајте го нашиот тим",
"team": {
"1": {
"name": "Јован Смитовски",
"role": "Извршен директор и основач"
},
"2": {
"name": "Сара Јовановска",
"role": "Главен дизајнер"
},
"3": {
"name": "Михаил Ченовски",
"role": "Сениор програмер"
},
"4": {
"name": "Емилија Вилсон",
"role": "Проект менаџер"
}
}
}
}

View File

@ -9,5 +9,43 @@
"description": "Помажемо амбициозним предузећима попут вашег да генеришу већи профит кроз изградњу свести, повећање веб саобраћаја, повезивање са клијентима и укупан раст продаје.",
"primaryButton": "Започните",
"secondaryButton": "Сазнајте Више"
},
"about": {
"subtitle": "Наша Филозофија",
"title": "Бољи начин за изградњу дигиталних искустава",
"description": "Ми смо тим страствених дизајнера, програмера и стратега који су посвећени стварању изванредних дигиталних искустава.",
"values": {
"1": {
"title": "Приступ фокусиран на клијента",
"description": "Наши клијенти су нам на првом месту и радимо с њима да бисмо разумели њихове јединствене изазове и циљеве."
},
"2": {
"title": "Квалитет и Изврсност",
"description": "Посвећени смо испоруци висококвалитетних решења која премашују очекивања и издржавају тест времена."
},
"3": {
"title": "Иновација и Креативност",
"description": "Стално истражујемо нове технологије и приступе за решавање сложених проблема на креативан начин."
}
},
"teamTitle": "Упознајте наш тим",
"team": {
"1": {
"name": "Јован Смитовић",
"role": "Извршни директор и оснивач"
},
"2": {
"name": "Сара Јовановић",
"role": "Главни дизајнер"
},
"3": {
"name": "Михаило Ченовић",
"role": "Сениор програмер"
},
"4": {
"name": "Емилија Вилсон",
"role": "Пројектни менаџер"
}
}
}
}

39
tailwind.config.js Normal file
View File

@ -0,0 +1,39 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: "class",
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
fontFamily: {
sans: ["var(--font-inter)"],
mono: ["var(--font-roboto-mono)"],
},
colors: {
border: "rgb(var(--border) / <alpha-value>)",
background: "rgb(var(--background) / <alpha-value>)",
foreground: "rgb(var(--foreground) / <alpha-value>)",
primary: {
DEFAULT: "rgb(var(--primary) / <alpha-value>)",
foreground: "rgb(var(--primary-foreground) / <alpha-value>)",
},
muted: {
DEFAULT: "rgb(var(--muted) / <alpha-value>)",
foreground: "rgb(var(--muted-foreground) / <alpha-value>)",
},
accent: {
DEFAULT: "rgb(var(--accent) / <alpha-value>)",
foreground: "rgb(var(--accent-foreground) / <alpha-value>)",
},
card: {
DEFAULT: "rgb(var(--card) / <alpha-value>)",
foreground: "rgb(var(--card-foreground) / <alpha-value>)",
},
},
},
},
plugins: [],
};