Initial deploy
هذا الالتزام موجود في:
37
app/[lang]/page.tsx
Normal file
37
app/[lang]/page.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { Metadata } from "next";
|
||||
import { notFound } from "next/navigation";
|
||||
import { HomePage } from "@/components/home-page";
|
||||
import { getPortfolioContent, isLanguage, languages, type Language } from "@/data/portfolio";
|
||||
|
||||
export function generateStaticParams() {
|
||||
return languages.map((lang) => ({ lang }));
|
||||
}
|
||||
|
||||
export function generateMetadata({ params }: { params: { lang: string } }): Metadata {
|
||||
if (!isLanguage(params.lang)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const language = params.lang as Language;
|
||||
const t = getPortfolioContent(language);
|
||||
|
||||
return {
|
||||
title: t.meta.title,
|
||||
description: t.meta.description,
|
||||
alternates: {
|
||||
canonical: `/${language}`,
|
||||
languages: {
|
||||
en: "/en",
|
||||
ar: "/ar",
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function LocalizedHomePage({ params }: { params: { lang: string } }) {
|
||||
if (!isLanguage(params.lang)) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return <HomePage language={params.lang as Language} />;
|
||||
}
|
||||
37
app/[lang]/resume/page.tsx
Normal file
37
app/[lang]/resume/page.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { Metadata } from "next";
|
||||
import { notFound } from "next/navigation";
|
||||
import { ResumePageContent } from "@/components/resume-page-content";
|
||||
import { getPortfolioContent, isLanguage, languages, type Language } from "@/data/portfolio";
|
||||
|
||||
export function generateStaticParams() {
|
||||
return languages.map((lang) => ({ lang }));
|
||||
}
|
||||
|
||||
export function generateMetadata({ params }: { params: { lang: string } }): Metadata {
|
||||
if (!isLanguage(params.lang)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const language = params.lang as Language;
|
||||
const t = getPortfolioContent(language);
|
||||
|
||||
return {
|
||||
title: language === "ar" ? `السيرة الذاتية | ${t.meta.title}` : `Resume | ${t.meta.title}`,
|
||||
description: t.resume.description,
|
||||
alternates: {
|
||||
canonical: `/${language}/resume`,
|
||||
languages: {
|
||||
en: "/en/resume",
|
||||
ar: "/ar/resume",
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function LocalizedResumePage({ params }: { params: { lang: string } }) {
|
||||
if (!isLanguage(params.lang)) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return <ResumePageContent language={params.lang as Language} />;
|
||||
}
|
||||
ثنائية
app/apple-icon.png
Normal file
ثنائية
app/apple-icon.png
Normal file
ملف ثنائي غير معروض.
|
بعد العرض: | الارتفاع: | الحجم: 56 KiB |
4
app/globals.css
Normal file
4
app/globals.css
Normal file
@@ -0,0 +1,4 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
ثنائية
app/icon.png
Normal file
ثنائية
app/icon.png
Normal file
ملف ثنائي غير معروض.
|
بعد العرض: | الارتفاع: | الحجم: 56 KiB |
59
app/layout.tsx
Normal file
59
app/layout.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
import "./portfolio.css";
|
||||
|
||||
const themeInitScript = `
|
||||
(() => {
|
||||
try {
|
||||
const storageKey = "grace-portfolio-theme";
|
||||
const savedTheme = window.localStorage.getItem(storageKey);
|
||||
const theme = savedTheme === "dark" ? "dark" : "light";
|
||||
document.documentElement.dataset.theme = theme;
|
||||
document.documentElement.style.colorScheme = theme;
|
||||
} catch {
|
||||
document.documentElement.dataset.theme = "light";
|
||||
document.documentElement.style.colorScheme = "light";
|
||||
}
|
||||
})();
|
||||
`;
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Grace Butrus Salmoun | Architectural Engineer Specialized in Architectural Design",
|
||||
description:
|
||||
"A bilingual architecture portfolio for Grace Butrus Salmoun, an architectural engineer specialized in architectural design, working across urban rehabilitation, landscape, shop drawings, and visual presentation.",
|
||||
metadataBase: new URL("https://grace-salamoun-architect.vercel.app"),
|
||||
openGraph: {
|
||||
title: "Grace Butrus Salmoun | Architectural Engineer Specialized in Architectural Design",
|
||||
description:
|
||||
"Architectural design, urban rehabilitation, landscape, shop drawings, and visual presentation in English and Arabic.",
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "Grace Butrus Salmoun | Architectural Engineer Specialized in Architectural Design",
|
||||
description:
|
||||
"A bilingual architecture portfolio featuring selected works, technical documentation, and visual presentation.",
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html
|
||||
lang="en"
|
||||
dir="ltr"
|
||||
data-theme="light"
|
||||
className="scroll-smooth"
|
||||
style={{ colorScheme: "light" }}
|
||||
suppressHydrationWarning
|
||||
>
|
||||
<head>
|
||||
<script dangerouslySetInnerHTML={{ __html: themeInitScript }} />
|
||||
</head>
|
||||
<body className="bg-[var(--color-cream)] font-sans text-[var(--color-ink)] antialiased">{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
5
app/page.tsx
Normal file
5
app/page.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function RootPage() {
|
||||
redirect("/en");
|
||||
}
|
||||
778
app/portfolio.css
Normal file
778
app/portfolio.css
Normal file
@@ -0,0 +1,778 @@
|
||||
:root {
|
||||
--font-display: "Georgia", "Times New Roman", serif;
|
||||
--font-display-ar: "Segoe UI", "Tahoma", "Arial", sans-serif;
|
||||
--font-body: "Trebuchet MS", "Segoe UI", "Tahoma", sans-serif;
|
||||
--text-label: 17px;
|
||||
--text-button: 14px;
|
||||
--text-nav: 14px;
|
||||
--text-chip: 16px;
|
||||
--text-body: 18px;
|
||||
--text-body-editorial: 17px;
|
||||
--text-body-large: 18px;
|
||||
--text-contact-label: 15px;
|
||||
--text-contact-value: clamp(16px, 1.4vw, 18px);
|
||||
--text-contact-email: clamp(15px, 1.1vw, 15px);
|
||||
--text-section-kicker: 25px;
|
||||
--text-eyebrow: 20px;
|
||||
--text-brand: 30px;
|
||||
--text-footer-brand: 24px;
|
||||
--text-hero-title: clamp(15px, 5.4vw, 50px);
|
||||
--text-hero-title-latin: clamp(20px, 4.35vw, 52px);
|
||||
--text-page-title: clamp(36px, 4.8vw, 60px);
|
||||
--text-section-title: clamp(30px, 3vw, 36px);
|
||||
--text-card-title-small: clamp(24px, 2.4vw, 30px);
|
||||
--text-card-title: clamp(20px, 3vw, 36px);
|
||||
--text-project-title: clamp(36px, 4vw, 48px);
|
||||
--text-metric: clamp(48px, 5vw, 60px);
|
||||
--text-contact-title: clamp(36px, 5vw, 60px);
|
||||
--color-mauve-100: #d8f2ff;
|
||||
--color-mauve-300: #86d7ff;
|
||||
--color-mauve-500: #3eb8ff;
|
||||
--color-mauve-600: #1698ea;
|
||||
--color-mauve-700: #0a6eb8;
|
||||
--color-blue-400: #1689c8;
|
||||
--color-blue-500: #21a7e8;
|
||||
--color-blue-050: #dff6ff;
|
||||
--color-ink: #16222d;
|
||||
--color-muted: #657586;
|
||||
--color-white: #ffffff;
|
||||
--color-cream: #f6fbff;
|
||||
--color-deep: #eaf4fa;
|
||||
--color-panel: rgba(255, 255, 255, 0.84);
|
||||
--color-panel-strong: rgba(255, 255, 255, 0.96);
|
||||
--color-line: rgba(28, 126, 177, 0.18);
|
||||
--shadow-soft: 0 24px 70px rgba(25, 72, 105, 0.14);
|
||||
--shadow-card: 0 18px 48px rgba(25, 72, 105, 0.12);
|
||||
--html-background: linear-gradient(180deg, #ffffff 0%, #f6fbff 44%, #eaf4fa 100%);
|
||||
--body-background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(246, 251, 255, 0.96)),
|
||||
linear-gradient(90deg, rgba(33, 167, 232, 0.05) 1px, transparent 1px),
|
||||
linear-gradient(rgba(33, 167, 232, 0.05) 1px, transparent 1px);
|
||||
--section-shell-background: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(244, 250, 254, 0.92));
|
||||
--editorial-grid-background:
|
||||
linear-gradient(rgba(33, 167, 232, 0.08) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(33, 167, 232, 0.06) 1px, transparent 1px);
|
||||
--line-frame-color: rgba(28, 126, 177, 0.2);
|
||||
--soft-card-background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(241, 249, 253, 0.92));
|
||||
--gradient-card-border: rgba(28, 126, 177, 0.2);
|
||||
--gradient-card-background:
|
||||
linear-gradient(145deg, rgba(232, 247, 255, 0.98), rgba(255, 255, 255, 0.98) 48%, rgba(240, 249, 252, 0.96));
|
||||
--hero-background:
|
||||
linear-gradient(135deg, rgba(255, 255, 255, 0.98), rgba(232, 247, 255, 0.94) 46%, rgba(245, 251, 255, 0.98));
|
||||
--button-secondary-background: rgba(255, 255, 255, 0.92);
|
||||
--button-secondary-shadow: 0 10px 24px rgba(25, 72, 105, 0.08);
|
||||
--editorial-rule-background: linear-gradient(90deg, rgba(28, 126, 177, 0), rgba(28, 126, 177, 0.22), rgba(28, 126, 177, 0));
|
||||
--image-frame-background: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(238, 248, 253, 0.92));
|
||||
--header-background: rgba(255, 255, 255, 0.82);
|
||||
--header-border: rgba(28, 126, 177, 0.14);
|
||||
--logo-shell-background: #ffffff;
|
||||
--logo-shell-border: rgba(28, 126, 177, 0.18);
|
||||
--logo-shell-shadow: 0 10px 28px rgba(25, 72, 105, 0.12);
|
||||
--control-background: #ffffff;
|
||||
--control-border: rgba(28, 126, 177, 0.2);
|
||||
--control-border-hover: rgba(28, 126, 177, 0.36);
|
||||
--control-shadow: 0 8px 22px rgba(25, 72, 105, 0.08);
|
||||
--top-wash-background: linear-gradient(180deg, rgba(53, 182, 255, 0.12), transparent 64%);
|
||||
--surface-card-background: rgba(255, 255, 255, 0.88);
|
||||
--surface-card-alt-background: rgba(232, 247, 255, 0.86);
|
||||
--surface-card-strong-background: rgba(255, 255, 255, 0.9);
|
||||
--surface-card-shadow: 0 14px 36px rgba(25, 72, 105, 0.08);
|
||||
--project-card-background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(241, 249, 253, 0.94));
|
||||
--project-card-shadow: 0 24px 70px rgba(25, 72, 105, 0.12);
|
||||
--rule-color: rgba(28, 126, 177, 0.22);
|
||||
--meta-border-color: rgba(28, 126, 177, 0.14);
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
color-scheme: dark;
|
||||
--color-mauve-100: #d8f2ff;
|
||||
--color-mauve-300: #9fe1ff;
|
||||
--color-mauve-500: #63c8ff;
|
||||
--color-mauve-600: #35b6ff;
|
||||
--color-mauve-700: #86d7ff;
|
||||
--color-blue-400: #86d7ff;
|
||||
--color-blue-500: #35b6ff;
|
||||
--color-blue-050: #10283a;
|
||||
--color-ink: #f7fbff;
|
||||
--color-muted: #a8bac8;
|
||||
--color-cream: #06101a;
|
||||
--color-deep: #030b12;
|
||||
--color-panel: rgba(9, 24, 36, 0.84);
|
||||
--color-panel-strong: rgba(13, 34, 49, 0.94);
|
||||
--color-line: rgba(141, 220, 255, 0.16);
|
||||
--shadow-soft: 0 30px 90px rgba(0, 0, 0, 0.28);
|
||||
--shadow-card: 0 20px 54px rgba(0, 0, 0, 0.24);
|
||||
--html-background: linear-gradient(180deg, #030b12 0%, #06101a 46%, #0b1c2a 100%);
|
||||
--body-background:
|
||||
linear-gradient(180deg, rgba(3, 11, 18, 0.92), rgba(6, 16, 26, 0.96)),
|
||||
linear-gradient(90deg, rgba(141, 220, 255, 0.04) 1px, transparent 1px),
|
||||
linear-gradient(rgba(141, 220, 255, 0.04) 1px, transparent 1px);
|
||||
--section-shell-background: linear-gradient(180deg, rgba(8, 22, 33, 0.84), rgba(5, 14, 23, 0.96));
|
||||
--editorial-grid-background:
|
||||
linear-gradient(rgba(141, 220, 255, 0.08) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(141, 220, 255, 0.06) 1px, transparent 1px);
|
||||
--line-frame-color: rgba(141, 220, 255, 0.22);
|
||||
--soft-card-background: linear-gradient(180deg, rgba(10, 27, 40, 0.92), rgba(6, 18, 28, 0.94));
|
||||
--gradient-card-border: rgba(141, 220, 255, 0.16);
|
||||
--gradient-card-background:
|
||||
linear-gradient(145deg, rgba(14, 43, 61, 0.96), rgba(8, 22, 33, 0.98) 48%, rgba(5, 14, 23, 0.96));
|
||||
--hero-background:
|
||||
linear-gradient(135deg, rgba(13, 34, 49, 0.96), rgba(6, 18, 29, 0.94) 46%, rgba(3, 11, 18, 0.98));
|
||||
--button-secondary-background: rgba(8, 22, 33, 0.9);
|
||||
--button-secondary-shadow: 0 10px 24px rgba(0, 0, 0, 0.2);
|
||||
--editorial-rule-background: linear-gradient(90deg, rgba(141, 220, 255, 0), rgba(141, 220, 255, 0.22), rgba(141, 220, 255, 0));
|
||||
--image-frame-background: linear-gradient(180deg, rgba(10, 26, 38, 0.92), rgba(5, 14, 23, 0.96));
|
||||
--header-background: rgba(3, 11, 18, 0.72);
|
||||
--header-border: rgba(141, 220, 255, 0.08);
|
||||
--logo-shell-background: rgba(10, 26, 38, 0.92);
|
||||
--logo-shell-border: rgba(141, 220, 255, 0.14);
|
||||
--logo-shell-shadow: 0 14px 34px rgba(0, 0, 0, 0.3);
|
||||
--control-background: rgba(9, 24, 36, 0.84);
|
||||
--control-border: rgba(141, 220, 255, 0.18);
|
||||
--control-border-hover: rgba(141, 220, 255, 0.34);
|
||||
--control-shadow: 0 10px 24px rgba(0, 0, 0, 0.22);
|
||||
--top-wash-background: linear-gradient(180deg, rgba(53, 182, 255, 0.12), transparent 64%);
|
||||
--surface-card-background: rgba(8, 22, 33, 0.88);
|
||||
--surface-card-alt-background: rgba(12, 31, 45, 0.94);
|
||||
--surface-card-strong-background: rgba(10, 27, 40, 0.9);
|
||||
--surface-card-shadow: 0 14px 36px rgba(0, 0, 0, 0.2);
|
||||
--project-card-background: linear-gradient(180deg, rgba(9, 24, 36, 0.9), rgba(6, 16, 26, 0.96));
|
||||
--project-card-shadow: 0 30px 90px rgba(0, 0, 0, 0.3);
|
||||
--rule-color: rgba(141, 220, 255, 0.18);
|
||||
--meta-border-color: rgba(141, 220, 255, 0.12);
|
||||
}
|
||||
|
||||
* {
|
||||
@apply border-transparent;
|
||||
}
|
||||
|
||||
html {
|
||||
background: var(--html-background);
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
font-family: var(--font-body), sans-serif;
|
||||
font-size: var(--text-body);
|
||||
color: var(--color-ink);
|
||||
background: var(--body-background);
|
||||
background-size: auto, 96px 96px, 96px 96px;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: var(--font-display), serif;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
[dir="rtl"] h1,
|
||||
[dir="rtl"] h2,
|
||||
[dir="rtl"] h3,
|
||||
[dir="rtl"] h4,
|
||||
[dir="rtl"] h5,
|
||||
[dir="rtl"] h6,
|
||||
[dir="rtl"] .display-face {
|
||||
font-family: var(--font-display-ar);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[dir="rtl"] {
|
||||
font-family: var(--font-display-ar);
|
||||
}
|
||||
|
||||
p {
|
||||
@apply leading-7;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply transition-colors duration-200;
|
||||
}
|
||||
|
||||
.type-label {
|
||||
font-size: var(--text-label);
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.type-label-wide {
|
||||
font-size: var(--text-label);
|
||||
line-height: 1.35;
|
||||
letter-spacing: 0.22em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.type-button {
|
||||
font-size: var(--text-button);
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.type-nav {
|
||||
font-size: var(--text-nav);
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.type-chip {
|
||||
font-size: var(--text-chip);
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.type-body {
|
||||
font-size: var(--text-body);
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.type-body-editorial {
|
||||
font-size: var(--text-body-editorial);
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.type-body-responsive {
|
||||
font-size: var(--text-body);
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.type-brand {
|
||||
font-size: var(--text-brand);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.type-footer-brand {
|
||||
font-size: var(--text-footer-brand);
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.type-hero-title {
|
||||
font-size: var(--text-hero-title);
|
||||
line-height: 1.08;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.type-hero-title-latin {
|
||||
font-size: var(--text-hero-title-latin);
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.type-page-title {
|
||||
font-size: var(--text-page-title);
|
||||
line-height: 1.08;
|
||||
}
|
||||
|
||||
.type-section-title {
|
||||
font-size: var(--text-section-title);
|
||||
line-height: 1.16;
|
||||
}
|
||||
|
||||
.type-card-title-small {
|
||||
font-size: var(--text-card-title-small);
|
||||
line-height: 1.16;
|
||||
}
|
||||
|
||||
.type-card-title {
|
||||
font-size: var(--text-card-title-small);
|
||||
line-height: 1.16;
|
||||
}
|
||||
|
||||
.type-project-title {
|
||||
font-size: var(--text-project-title);
|
||||
line-height: 1.08;
|
||||
}
|
||||
|
||||
.type-metric {
|
||||
font-size: var(--text-metric);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.type-body-responsive {
|
||||
font-size: var(--text-body-large);
|
||||
}
|
||||
}
|
||||
|
||||
.site-container {
|
||||
@apply mx-auto w-full max-w-[1440px] px-6 md:px-8 lg:px-12;
|
||||
}
|
||||
|
||||
.section-shell {
|
||||
@apply relative overflow-hidden rounded-[34px] border backdrop-blur-xl;
|
||||
border-color: var(--color-line);
|
||||
background: var(--section-shell-background);
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
.section-padding {
|
||||
@apply px-6 py-16 md:px-10 md:py-20 lg:px-16;
|
||||
}
|
||||
|
||||
.section-kicker {
|
||||
@apply font-semibold uppercase tracking-[0.22em] text-[var(--color-mauve-700)];
|
||||
font-size: var(--text-section-kicker);
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.editorial-grid {
|
||||
background-image: var(--editorial-grid-background);
|
||||
background-position: center;
|
||||
background-size: 140px 140px;
|
||||
}
|
||||
|
||||
.line-frame::before,
|
||||
.line-frame::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
border-color: var(--line-frame-color);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.line-frame::before {
|
||||
inset: 18px auto auto 18px;
|
||||
height: 84px;
|
||||
width: 84px;
|
||||
border-left-width: 1px;
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
.line-frame::after {
|
||||
inset: auto 18px 18px auto;
|
||||
height: 84px;
|
||||
width: 84px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.soft-card {
|
||||
@apply rounded-[28px] border p-6 backdrop-blur-xl transition-transform duration-300 hover:-translate-y-1;
|
||||
border-color: var(--color-line);
|
||||
background: var(--soft-card-background);
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
|
||||
.gradient-card {
|
||||
@apply rounded-[28px] border p-6;
|
||||
border-color: var(--gradient-card-border);
|
||||
background: var(--gradient-card-background);
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
|
||||
.hero-glow {
|
||||
background: var(--hero-background);
|
||||
}
|
||||
|
||||
.button-primary {
|
||||
@apply inline-flex items-center justify-center rounded-full border px-6 py-3 font-semibold transition-all duration-200 hover:-translate-y-0.5;
|
||||
font-size: var(--text-button);
|
||||
line-height: 1.25;
|
||||
border-color: rgba(22, 137, 200, 0.32);
|
||||
background: linear-gradient(135deg, #1698ea, #35b6ff);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 12px 30px rgba(33, 167, 232, 0.22);
|
||||
}
|
||||
|
||||
.button-secondary {
|
||||
@apply inline-flex items-center justify-center rounded-full border px-6 py-3 font-semibold text-[var(--color-ink)] transition-all duration-200 hover:-translate-y-0.5;
|
||||
font-size: var(--text-button);
|
||||
line-height: 1.25;
|
||||
border-color: var(--color-line);
|
||||
background: var(--button-secondary-background);
|
||||
box-shadow: var(--button-secondary-shadow);
|
||||
}
|
||||
|
||||
.display-face {
|
||||
font-family: var(--font-display), serif;
|
||||
}
|
||||
|
||||
.editorial-rule {
|
||||
@apply h-px w-full;
|
||||
background: var(--editorial-rule-background);
|
||||
}
|
||||
|
||||
.image-frame {
|
||||
@apply relative overflow-hidden rounded-[32px] border p-3;
|
||||
border-color: var(--color-line);
|
||||
background: var(--image-frame-background);
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
.eyebrow-note {
|
||||
@apply uppercase tracking-[0.22em] text-[var(--color-muted)];
|
||||
font-size: var(--text-eyebrow);
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.navbar-shell {
|
||||
border-color: var(--header-border);
|
||||
background: var(--header-background);
|
||||
}
|
||||
|
||||
.logo-shell {
|
||||
border-color: var(--logo-shell-border);
|
||||
background: var(--logo-shell-background);
|
||||
box-shadow: var(--logo-shell-shadow);
|
||||
}
|
||||
|
||||
.control-pill {
|
||||
@apply inline-flex h-10 items-center justify-center rounded-full border px-4 font-semibold text-[var(--color-ink)] transition-transform duration-200 hover:-translate-y-0.5 hover:text-[var(--color-blue-400)];
|
||||
font-size: var(--text-button);
|
||||
line-height: 1.25;
|
||||
border-color: var(--control-border);
|
||||
background: var(--control-background);
|
||||
box-shadow: var(--control-shadow);
|
||||
}
|
||||
|
||||
.control-pill:hover {
|
||||
border-color: var(--control-border-hover);
|
||||
}
|
||||
|
||||
.nav-link-pill {
|
||||
@apply inline-flex h-10 items-center justify-center rounded-full border px-4 font-semibold text-[var(--color-ink)] transition-transform duration-200 hover:-translate-y-0.5 hover:text-[var(--color-blue-400)];
|
||||
font-size: var(--text-nav);
|
||||
line-height: 1.25;
|
||||
border-color: var(--control-border);
|
||||
background: var(--control-background);
|
||||
box-shadow: var(--control-shadow);
|
||||
}
|
||||
|
||||
.nav-link-pill:hover {
|
||||
border-color: var(--control-border-hover);
|
||||
}
|
||||
|
||||
.nav-link-pill[data-active="true"] {
|
||||
border-color: rgba(33, 167, 232, 0.5);
|
||||
background: linear-gradient(135deg, rgba(33, 167, 232, 0.16), var(--control-background));
|
||||
color: var(--color-blue-400);
|
||||
}
|
||||
|
||||
.nav-scroll {
|
||||
@apply -mx-1 max-w-full overflow-x-auto px-1 pb-1;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.nav-scroll::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-list {
|
||||
@apply flex w-max items-center gap-2 font-medium text-[var(--color-muted)] md:w-full md:flex-wrap;
|
||||
font-size: var(--text-nav);
|
||||
}
|
||||
|
||||
.mobile-menu-panel {
|
||||
@apply absolute inset-x-0 top-full z-50 mt-3 rounded-[24px] border p-3 backdrop-blur-xl md:hidden;
|
||||
border-color: var(--control-border);
|
||||
background: var(--header-background);
|
||||
box-shadow: var(--shadow-card);
|
||||
max-height: calc(100vh - 5.5rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mobile-menu-list {
|
||||
@apply grid gap-2;
|
||||
}
|
||||
|
||||
.mobile-menu-link {
|
||||
@apply flex min-h-[48px] items-center rounded-[18px] border px-4 py-3 font-semibold text-[var(--color-ink)] transition-all duration-200 hover:-translate-y-0.5 hover:text-[var(--color-blue-400)];
|
||||
border-color: var(--control-border);
|
||||
background: var(--control-background);
|
||||
box-shadow: var(--control-shadow);
|
||||
}
|
||||
|
||||
.mobile-menu-link:hover {
|
||||
border-color: var(--control-border-hover);
|
||||
}
|
||||
|
||||
.theme-toggle {
|
||||
@apply inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-full border text-[var(--color-ink)] transition-transform duration-200 hover:-translate-y-0.5 hover:text-[var(--color-blue-400)];
|
||||
border-color: var(--control-border);
|
||||
background: var(--control-background);
|
||||
box-shadow: var(--control-shadow);
|
||||
}
|
||||
|
||||
.theme-toggle:hover {
|
||||
border-color: var(--control-border-hover);
|
||||
}
|
||||
|
||||
.theme-toggle svg {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.theme-toggle .sun-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .theme-toggle .moon-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .theme-toggle .sun-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.top-wash {
|
||||
background: var(--top-wash-background);
|
||||
}
|
||||
|
||||
.project-card-shell {
|
||||
border-color: var(--color-line);
|
||||
background: var(--project-card-background);
|
||||
box-shadow: var(--project-card-shadow);
|
||||
}
|
||||
|
||||
.project-rule-line {
|
||||
background: var(--rule-color);
|
||||
}
|
||||
|
||||
.project-meta-list {
|
||||
border-color: var(--meta-border-color);
|
||||
}
|
||||
|
||||
.surface-chip {
|
||||
@apply rounded-full border;
|
||||
border-color: var(--color-line);
|
||||
background: var(--surface-card-background);
|
||||
}
|
||||
|
||||
.surface-chip-alt {
|
||||
@apply rounded-full border;
|
||||
border-color: var(--color-line);
|
||||
background: var(--surface-card-alt-background);
|
||||
}
|
||||
|
||||
.surface-card {
|
||||
@apply border;
|
||||
border-color: var(--meta-border-color);
|
||||
background: var(--surface-card-background);
|
||||
box-shadow: var(--surface-card-shadow);
|
||||
}
|
||||
|
||||
.surface-card-alt {
|
||||
@apply border;
|
||||
border-color: var(--meta-border-color);
|
||||
background: var(--surface-card-alt-background);
|
||||
box-shadow: var(--surface-card-shadow);
|
||||
}
|
||||
|
||||
.surface-card-strong {
|
||||
@apply border;
|
||||
border-color: var(--color-line);
|
||||
background: var(--surface-card-strong-background);
|
||||
box-shadow: var(--surface-card-shadow);
|
||||
}
|
||||
|
||||
.notice-card {
|
||||
@apply rounded-[22px] border px-5 py-4 text-[var(--color-muted)];
|
||||
font-size: var(--text-chip);
|
||||
line-height: 1.55;
|
||||
border-color: var(--color-line);
|
||||
background: var(--control-background);
|
||||
box-shadow: var(--control-shadow);
|
||||
}
|
||||
|
||||
.resume-timeline-card {
|
||||
@apply rounded-[24px] border p-6;
|
||||
border-color: var(--meta-border-color);
|
||||
background: var(--project-card-background);
|
||||
box-shadow: var(--surface-card-shadow);
|
||||
}
|
||||
|
||||
.contact-card {
|
||||
@apply min-h-[140px] rounded-[26px] border px-6 py-5 transition-transform duration-300 hover:-translate-y-1;
|
||||
border-color: var(--color-line);
|
||||
background: var(--surface-card-strong-background);
|
||||
box-shadow: var(--surface-card-shadow);
|
||||
}
|
||||
|
||||
.contact-card:hover {
|
||||
border-color: var(--control-border-hover);
|
||||
}
|
||||
|
||||
.contact-label {
|
||||
font-size: var(--text-contact-label);
|
||||
line-height: 1.35;
|
||||
letter-spacing: 0.22em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.contact-value {
|
||||
font-size: var(--text-contact-value);
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.contact-value-ltr {
|
||||
direction: ltr;
|
||||
unicode-bidi: isolate;
|
||||
text-align: center;
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-feature-settings: "tnum" 1, "lnum" 1;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.contact-value-email {
|
||||
font-size: var(--text-contact-email);
|
||||
line-height: 1.45;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.data-ltr {
|
||||
direction: ltr;
|
||||
unicode-bidi: isolate;
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-feature-settings: "tnum" 1, "lnum" 1;
|
||||
}
|
||||
|
||||
.contact-copy {
|
||||
@apply self-start pt-1;
|
||||
}
|
||||
|
||||
.contact-title {
|
||||
@apply mt-5 max-w-4xl whitespace-pre-line text-[var(--color-ink)];
|
||||
font-size: var(--text-contact-title);
|
||||
line-height: 1.14;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
.contact-description {
|
||||
@apply mt-6 max-w-2xl text-[var(--color-muted)];
|
||||
font-size: var(--text-body);
|
||||
line-height: 1.75;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.contact-description {
|
||||
font-size: var(--text-body-large);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.site-container {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.section-shell {
|
||||
border-radius: 28px;
|
||||
}
|
||||
|
||||
.section-padding {
|
||||
padding: 1.25rem 1rem 1.5rem;
|
||||
}
|
||||
|
||||
.section-kicker {
|
||||
font-size: clamp(18px, 4.8vw, 22px);
|
||||
letter-spacing: 0.18em;
|
||||
}
|
||||
|
||||
.eyebrow-note,
|
||||
.type-label-wide {
|
||||
font-size: 15px;
|
||||
letter-spacing: 0.14em;
|
||||
}
|
||||
|
||||
.navbar-shell .type-brand {
|
||||
font-size: clamp(24px, 8vw, 30px);
|
||||
}
|
||||
|
||||
.navbar-shell .type-label {
|
||||
display: block;
|
||||
max-width: 17rem;
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
.type-page-title {
|
||||
font-size: clamp(28px, 9vw, 42px);
|
||||
}
|
||||
|
||||
.type-section-title {
|
||||
font-size: clamp(24px, 7vw, 32px);
|
||||
}
|
||||
|
||||
.type-project-title {
|
||||
font-size: clamp(28px, 9vw, 38px);
|
||||
}
|
||||
|
||||
.type-card-title,
|
||||
.type-card-title-small {
|
||||
font-size: clamp(20px, 6.8vw, 28px);
|
||||
}
|
||||
|
||||
.contact-title {
|
||||
font-size: clamp(28px, 10vw, 42px);
|
||||
}
|
||||
|
||||
.contact-card {
|
||||
min-height: 126px;
|
||||
padding: 1.25rem 1rem;
|
||||
}
|
||||
|
||||
.line-frame::before,
|
||||
.line-frame::after {
|
||||
height: 56px;
|
||||
width: 56px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.type-hero-title {
|
||||
font-size: clamp(30px, 11.5vw, 40px);
|
||||
line-height: 1.02;
|
||||
}
|
||||
|
||||
.type-hero-title-latin {
|
||||
font-size: clamp(28px, 10vw, 36px);
|
||||
line-height: 1.04;
|
||||
}
|
||||
|
||||
.type-project-title {
|
||||
font-size: clamp(24px, 9vw, 32px);
|
||||
}
|
||||
|
||||
.contact-title {
|
||||
font-size: clamp(26px, 9.5vw, 36px);
|
||||
}
|
||||
|
||||
.hero-action-group {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.hero-action-group > * {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 390px) {
|
||||
.site-container {
|
||||
padding-left: 0.875rem;
|
||||
padding-right: 0.875rem;
|
||||
}
|
||||
|
||||
.section-padding {
|
||||
padding: 1rem 0.875rem 1.25rem;
|
||||
}
|
||||
|
||||
.navbar-shell .type-brand {
|
||||
font-size: clamp(20px, 7.2vw, 26px);
|
||||
}
|
||||
|
||||
.contact-card {
|
||||
padding: 1rem 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
.type-hero-title {
|
||||
font-size: clamp(26px, 10.5vw, 34px);
|
||||
}
|
||||
|
||||
.type-section-title {
|
||||
font-size: clamp(22px, 8.3vw, 28px);
|
||||
}
|
||||
|
||||
.type-chip {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
5
app/resume/page.tsx
Normal file
5
app/resume/page.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function RootResumePage() {
|
||||
redirect("/en/resume");
|
||||
}
|
||||
11
app/robots.ts
Normal file
11
app/robots.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
export default function robots(): MetadataRoute.Robots {
|
||||
return {
|
||||
rules: {
|
||||
userAgent: "*",
|
||||
allow: "/",
|
||||
},
|
||||
sitemap: "https://grace-salamoun-architect.vercel.app/sitemap.xml",
|
||||
};
|
||||
}
|
||||
33
app/sitemap.ts
Normal file
33
app/sitemap.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
export default function sitemap(): MetadataRoute.Sitemap {
|
||||
const baseUrl = "https://grace-salamoun-architect.vercel.app";
|
||||
const lastModified = new Date("2026-04-18T00:00:00.000Z");
|
||||
|
||||
return [
|
||||
{
|
||||
url: `${baseUrl}/en`,
|
||||
lastModified,
|
||||
changeFrequency: "monthly",
|
||||
priority: 1,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/ar`,
|
||||
lastModified,
|
||||
changeFrequency: "monthly",
|
||||
priority: 1,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/en/resume`,
|
||||
lastModified,
|
||||
changeFrequency: "monthly",
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/ar/resume`,
|
||||
lastModified,
|
||||
changeFrequency: "monthly",
|
||||
priority: 0.8,
|
||||
},
|
||||
];
|
||||
}
|
||||
المرجع في مشكلة جديدة
حظر مستخدم