Redesign homepage as an Apple-style bento grid
deploy / deploy (push) Successful in 24s

Replace the flat minimal sections with a bento layout (ui-ux-pro-max "Bento
Box Grid" style) while keeping the light theme and single blue accent.

- Bento grid system in CSS: 4-col -> 2-col -> 1-col, varied spans (span-2,
  row-2), 22px tiles, hover lift, dark/accent/tint tile variants
- Hero is now a bento: dark name/anchor tile + value-prop tile + accent
  availability tile + social tile
- Services: bento tiles with a tinted featured tile and a dark AI tile
- Stack: four category tiles (AI/ML tinted)
- Portfolio: featured 2x2 tile + colored covers per project
- Pipeline / expertise / blog / contact kept as different layouts for rhythm

Verified: 4-col desktop, clean 1-col mobile with no horizontal overflow,
no console errors. Tailwind bundle rebuilt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-26 15:52:59 +03:30
parent 7a7542d77b
commit 4c759851ce
3 changed files with 107 additions and 44 deletions
+73 -43
View File
@@ -5,35 +5,48 @@
var locale = Model.Locale;
}
<!-- ─── HERO (editorial, centered) ───────────────────────────────────── -->
<section id="top" class="px-5 pt-28 pb-24 sm:px-8 sm:pt-32">
<div class="mx-auto max-w-3xl text-center">
<div class="reveal mb-7 flex justify-center">
<span class="status"><span class="dot"></span>@(fa ? "پذیرای پروژه‌های جدید" : "Available for new projects")</span>
</div>
<!-- ─── HERO (bento) ─────────────────────────────────────────────────── -->
<section id="top" class="px-5 pt-24 pb-12 sm:px-8 sm:pt-28">
<div class="mx-auto max-w-6xl">
<div class="bento">
<h1 class="reveal @(fa ? "font-fa" : "")" style="font-size:clamp(2.6rem,7vw,4.75rem);transition-delay:.05s">
@(fa ? "سروش اسعدی" : "Soroush Asadi")
</h1>
<!-- Name / anchor tile -->
<div class="tile tile-dark span-2 row-2 reveal">
<span class="kicker @(fa ? "font-fa" : "")" style="color:#a1a1aa">@(fa ? "مهندس نرم‌افزار و هوش مصنوعی" : "Software & AI Engineer")</span>
<h1 class="mt-3 @(fa ? "font-fa" : "")" style="font-size:clamp(2.4rem,5.5vw,4rem)">@(fa ? "سروش اسعدی" : "Soroush Asadi")</h1>
<p class="t-sub mt-3 text-[1rem] @(fa ? "font-fa" : "")">@(fa ? "معمار سیستم. از ایده تا اجرا." : "Solution architect. From idea to production.")</p>
<div class="mt-auto flex flex-wrap gap-3 pt-8">
<a href="#contact" class="btn">
@(fa ? "رزرو جلسه" : "Book a call")
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" class="@(fa ? "rotate-180" : "")" aria-hidden="true"><path d="M5 12h14"/><path d="m13 6 6 6-6 6"/></svg>
</a>
<a href="#portfolio" class="btn-ghost btn-on-dark">@(fa ? "نمونه‌کارها" : "View work")</a>
</div>
</div>
<p class="reveal mx-auto mt-6 max-w-2xl text-balance leading-snug text-zinc-800" style="font-size:clamp(1.2rem,2.4vw,1.6rem);transition-delay:.1s">
@(fa ? "نرم‌افزار، اپلیکیشن‌های سازمانی و " : "I build software, enterprise apps, and ")<span class="accent-text font-semibold">@(fa ? "راهکارهای هوش مصنوعی" : "AI solutions")</span>@(fa ? " می‌سازم که در عمل و در مقیاس واقعی کار می‌کنند." : " that hold up in production, at real scale.")
</p>
<!-- Value-prop tile -->
<div class="tile span-2 reveal" style="transition-delay:.06s">
<p class="mt-auto text-balance leading-snug text-zinc-800 @(fa ? "font-fa" : "")" style="font-size:clamp(1.15rem,2vw,1.5rem)">
@(fa ? "نرم‌افزار، اپلیکیشن‌های سازمانی و " : "I build software, enterprise apps, and ")<span class="accent-text font-semibold">@(fa ? "راهکارهای هوش مصنوعی" : "AI solutions")</span>@(fa ? " می‌سازم که در عمل و در مقیاس واقعی کار می‌کنند." : " that hold up in production, at real scale.")
</p>
</div>
<p class="lede reveal mx-auto mt-4 text-[.98rem]" style="transition-delay:.15s">@(fa ? "مهندس نرم‌افزار و هوش مصنوعی، معمار سیستم." : "Software and AI Engineer, Solution Architect.")</p>
<!-- Availability tile -->
<div class="tile tile-accent reveal" style="transition-delay:.12s">
<span class="inline-flex items-center gap-2 text-[.82rem]" style="color:rgba(255,255,255,.9)"><span style="width:7px;height:7px;border-radius:99px;background:#fff;display:inline-block"></span>@(fa ? "وضعیت" : "Status")</span>
<p class="mt-auto pt-6 text-[1.05rem] font-semibold @(fa ? "font-fa" : "")" style="color:#fff">@(fa ? "پذیرای پروژه‌های جدید" : "Open for new projects")</p>
</div>
<div class="reveal mt-9 flex flex-wrap items-center justify-center gap-3" style="transition-delay:.2s">
<a href="#contact" class="btn">
@(fa ? "رزرو جلسه" : "Book a call")
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" class="@(fa ? "rotate-180" : "")" aria-hidden="true"><path d="M5 12h14"/><path d="m13 6 6 6-6 6"/></svg>
</a>
<a href="#portfolio" class="btn-ghost">@(fa ? "نمونه‌کارها" : "View work")</a>
</div>
<!-- Social tile -->
<div class="tile reveal" style="transition-delay:.18s">
<span class="kicker @(fa ? "font-fa" : "")">@(fa ? "ارتباط" : "Connect")</span>
<div class="mt-auto flex items-center gap-2.5 pt-6">
<a class="social" href="https://www.linkedin.com/in/soroushdes/" target="_blank" rel="noopener" aria-label="LinkedIn"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5ZM3 9h4v12H3V9Zm6 0h3.8v1.64h.05c.53-1 1.83-2.06 3.76-2.06 4.02 0 4.76 2.65 4.76 6.1V21h-4v-5.4c0-1.29-.02-2.95-1.8-2.95-1.8 0-2.07 1.4-2.07 2.85V21H9V9Z"/></svg></a>
<a class="social" href="https://www.instagram.com/soroushasadicom/" target="_blank" rel="noopener" aria-label="Instagram"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.2" cy="6.8" r="1.1" fill="currentColor" stroke="none"/></svg></a>
<a class="social" href="mailto:code.soroush@gmail.com" aria-label="Email"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/></svg></a>
</div>
</div>
<div class="reveal mt-8 flex items-center justify-center gap-2.5" style="transition-delay:.25s">
<a class="social" href="https://www.linkedin.com/in/soroushdes/" target="_blank" rel="noopener" aria-label="LinkedIn"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5ZM3 9h4v12H3V9Zm6 0h3.8v1.64h.05c.53-1 1.83-2.06 3.76-2.06 4.02 0 4.76 2.65 4.76 6.1V21h-4v-5.4c0-1.29-.02-2.95-1.8-2.95-1.8 0-2.07 1.4-2.07 2.85V21H9V9Z"/></svg></a>
<a class="social" href="https://www.instagram.com/soroushasadicom/" target="_blank" rel="noopener" aria-label="Instagram"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.2" cy="6.8" r="1.1" fill="currentColor" stroke="none"/></svg></a>
<a class="social" href="mailto:code.soroush@gmail.com" aria-label="Email"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/></svg></a>
</div>
</div>
</section>
@@ -46,7 +59,7 @@
<p class="lede">@(fa ? "از همان جلسه‌ی اول تا وقتی محصول روی پای خودش می‌ایستد، کنارتان هستم؛ در تمام مسیر مهندسی و محصول." : "From the first idea to production rollout, one engineering partner across the whole product.")</p>
</div>
<div class="grid grid-cols-1 gap-x-10 gap-y-10 sm:grid-cols-2 lg:grid-cols-3">
<div class="bento">
@{
var services = fa ? new[]{
("apps","اپلیکیشن‌های وب و سازمانی","پلتفرم‌های وب و SaaS از صفر تا صد: داشبورد، چندمستاجری، صورت‌حساب و پنل مدیریت، ساخته‌شده برای رشد.",new[]{"Web","SaaS","Dashboards"}),
@@ -67,11 +80,17 @@
@{ int si = 0; }
@foreach (var (id, title, desc, tags) in services)
{
<article class="svc reveal border-t border-zinc-200 pt-6" style="transition-delay:@(si * 60)ms">
<span class="svc-icon text-zinc-500" aria-hidden="true">@Html.Raw(ServiceIcon(id))</span>
<h3 class="mt-5 text-lg font-semibold @(fa ? "font-fa" : "")">@title</h3>
<p class="mt-2.5 text-[.95rem] leading-relaxed text-zinc-600">@desc</p>
<div class="mt-4 flex flex-wrap gap-1.5">
var (spanCls, variant) = id switch {
"apps" => ("span-2", "tile-tint"),
"llm-rag" => ("span-2", "tile-dark"),
_ => ("", ""),
};
var descCls = variant == "tile-dark" ? "t-sub" : "text-zinc-600";
<article class="tile reveal @spanCls @variant" style="transition-delay:@(si * 60)ms">
<span class="tile-icon" aria-hidden="true">@Html.Raw(ServiceIcon(id))</span>
<h3 class="mt-4 text-lg font-semibold @(fa ? "font-fa" : "")">@title</h3>
<p class="mt-2.5 text-[.93rem] leading-relaxed @descCls">@desc</p>
<div class="mt-auto flex flex-wrap gap-1.5 pt-5">
@foreach (var tag in tags) { <span class="chip">@tag</span> }
</div>
</article>
@@ -128,7 +147,7 @@
<p class="lede">@(fa ? "هر چیزی که می‌سازم روی این‌ها بنا می‌شود؛ انتخاب‌شان کرده‌ام چون می‌مانند، نه چون مد روزند." : "Everything I ship sits on this foundation, chosen for longevity, not hype cycles.")</p>
</div>
<div class="grid grid-cols-1 gap-x-8 gap-y-9 sm:grid-cols-2 lg:grid-cols-4">
<div class="bento">
@{
var cats = fa ? new[]{
("زبان‌ها", new[]{"Python","TypeScript","Go","Rust","SQL"}),
@@ -142,14 +161,16 @@
("AI / ML", new[]{"Vertex AI","Gemini","OpenAI","Anthropic","LangGraph","Pinecone","pgvector"}),
};
}
@{ int ci = 0; }
@foreach (var (catLabel, items) in cats)
{
<div class="reveal border-t border-zinc-200 pt-5">
<h3 class="mb-4 text-sm font-semibold @(fa ? "font-fa" : "")">@catLabel</h3>
<div class="flex flex-wrap gap-1.5">
<div class="tile reveal @(ci == 3 ? "tile-tint" : "")" style="transition-delay:@(ci * 60)ms">
<h3 class="text-sm font-semibold @(fa ? "font-fa" : "")">@catLabel</h3>
<div class="mt-4 flex flex-wrap gap-1.5">
@foreach (var item in items) { <span class="chip">@item</span> }
</div>
</div>
ci++;
}
</div>
</div>
@@ -198,7 +219,7 @@
<p class="lede">@(fa ? "محصولاتی که خودم طراحی و ساخته‌ام. روی هر کارت بزنید تا خودِ سایت را ببینید." : "Products I have designed and built. Tap any card to open the live site.")</p>
</div>
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
<div class="bento">
@{
var projects = fa ? new[]{
("hamkadr","همکادر","hamkadr.ir","بازاری که کادر درمان را برای شیفت و استخدام به بیمارستان‌ها و کلینیک‌ها وصل می‌کند؛ با پروفایل، فیلتر، تقویم هفتگی و اپ موبایل.",new[]{"Marketplace","Healthcare","Mobile"}),
@@ -212,26 +233,35 @@
("flatrender","Flatrender","flatrender.ir","An AI studio that turns 1,200+ templates into platform-ready videos and images in minutes, billed by render-seconds. In beta.",new[]{"AI","Video","SaaS"}),
};
}
@{ int pi = 0; }
@foreach (var (pid, pname, pdomain, pdesc, ptags) in projects)
{
var initial = char.ToUpperInvariant(pid[0]);
<a href="https://@pdomain" target="_blank" rel="noopener" class="group card card-link reveal block overflow-hidden">
<div class="cover flex aspect-[16/9] items-center justify-center bg-zinc-100" aria-hidden="true">
<span class="font-display text-6xl font-bold text-zinc-300">@initial</span>
var (spanCls, coverBg, coverFg) = pi switch {
0 => ("span-2 row-2", "#18181b", "#fafafa"),
1 => ("span-2", "#2563eb", "#ffffff"),
2 => ("", "#eff4ff", "#2563eb"),
_ => ("", "#f4f4f5", "#a1a1aa"),
};
<a href="https://@pdomain" target="_blank" rel="noopener" aria-label="@pname"
class="group tile tile-link reveal @spanCls" style="padding:0;transition-delay:@(pi * 60)ms">
<div class="pcover" style="background:@coverBg;@(pi == 0 ? "min-height:210px" : "min-height:104px")">
<span class="font-display font-bold" style="font-size:@(pi == 0 ? "5rem" : "2.6rem");color:@coverFg">@initial</span>
</div>
<div class="p-6">
<div class="flex flex-1 flex-col p-5">
<div class="mb-3 flex flex-wrap gap-1.5">
@foreach (var tag in ptags) { <span class="chip">@tag</span> }
</div>
<h3 class="text-[1.15rem] font-semibold @(fa ? "font-fa" : "")">@pname</h3>
<p class="mt-1 text-[.8rem] text-zinc-500" dir="ltr">@pdomain</p>
<p class="mt-3 text-[.9rem] leading-relaxed text-zinc-600">@pdesc</p>
<span class="arrow-link mt-4">
<h3 class="text-[1.1rem] font-semibold @(fa ? "font-fa" : "")">@pname</h3>
<p class="mt-1 text-[.78rem] text-zinc-500" dir="ltr">@pdomain</p>
<p class="mt-2.5 text-[.88rem] leading-relaxed text-zinc-600 @(pi == 0 ? "" : "line-clamp-3")">@pdesc</p>
<span class="arrow-link mt-auto pt-4">
@(fa ? "مشاهده‌ی سایت" : "Visit site")
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 17 17 7"/><path d="M8 7h9v9"/></svg>
</span>
</div>
</a>
pi++;
}
</div>
</div>
+33
View File
@@ -172,6 +172,39 @@ body.site {
.cover > * { transition: transform .45s cubic-bezier(.22,1,.36,1); }
.card-link:hover .cover > * { transform: scale(1.04); }
/* ─── Bento grid (Apple-style tiles, varied spans) ───────────────────── */
.bento { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); grid-auto-rows: minmax(158px, auto); gap: 14px; }
.tile {
position: relative; display: flex; flex-direction: column;
background: var(--surface); border: 1px solid var(--line); border-radius: 22px;
padding: 1.5rem; overflow: hidden;
transition: transform .22s cubic-bezier(.22,1,.36,1), box-shadow .22s ease, border-color .22s ease;
}
.tile-link { cursor: pointer; }
.tile-link:hover { transform: translateY(-4px); box-shadow: 0 22px 48px -26px rgba(24,24,27,.4); border-color: var(--line-strong); }
.span-2 { grid-column: span 2; } .span-3 { grid-column: span 3; } .span-4 { grid-column: span 4; }
.row-2 { grid-row: span 2; }
.tile-dark { background: #18181b; border-color: #18181b; }
.tile-accent { background: var(--accent); border-color: var(--accent); }
.tile-tint { background: var(--accent-weak); border-color: #dbe3ff; }
.tile-icon { color: var(--accent); }
.tile-dark .tile-icon, .tile-accent .tile-icon { color: #fff; }
.tile-dark h1, .tile-dark h2, .tile-dark h3, .tile-accent h1, .tile-accent h2, .tile-accent h3 { color: #fafafa; }
.t-sub { color: #d4d4d8; }
.tile-accent .t-sub { color: rgba(255,255,255,.85); }
.btn-on-dark { color: #fafafa; background: transparent; border-color: rgba(255,255,255,.28); }
.btn-on-dark:hover { color: #fafafa; background: rgba(255,255,255,.08); border-color: #fafafa; }
.pcover { display: flex; align-items: center; justify-content: center; }
@media (max-width: 1023px) {
.bento { grid-template-columns: repeat(2, minmax(0,1fr)); }
.span-3, .span-4 { grid-column: span 2; }
}
@media (max-width: 639px) {
.bento { grid-template-columns: 1fr; grid-auto-rows: auto; }
.span-2, .span-3, .span-4 { grid-column: span 1; }
.row-2 { grid-row: span 1; }
}
/* ─── Form fields ────────────────────────────────────────────────────── */
.flabel { display: block; font-size: .85rem; font-weight: 500; color: var(--text-2); margin-bottom: .4rem; }
.field {
File diff suppressed because one or more lines are too long