Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions content/writing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Writing content

MDX posts will live here as the writing archive grows.

## Convention

1. Add a post entry in `src/data/writing.ts`
2. Create `content/writing/<slug>.mdx`
3. Wire an MDX loader / route under `src/app/writing/[slug]` when the first post ships

Keep essays decision-maker useful — product judgment, delivery, and shipping systems.
2 changes: 1 addition & 1 deletion src/app/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { AboutPage } from "@/features/about";
export const metadata: Metadata = createMetadata({
title: "About",
description:
"Product engineering partner for international founders — clarity, ownership, and production-ready delivery.",
"Kailash Gayari — Product Engineering Partner in Vapi, Gujarat. Nearly seven years shipping web, mobile, and IoT products for founders and teams.",
alternates: {
canonical: "/about",
},
Expand Down
17 changes: 17 additions & 0 deletions src/app/experience/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Metadata } from "next";

import { createMetadata } from "@/config/site";
import { ExperiencePage } from "@/features/experience";

export const metadata: Metadata = createMetadata({
title: "Experience",
description:
"Product engineering timeline — senior delivery across web, mobile, IoT, and founder-facing platforms since 2019.",
alternates: {
canonical: "/experience",
},
});

export default function Page() {
return <ExperiencePage />;
}
8 changes: 6 additions & 2 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import {
CapabilitiesSection,
ClientQuotesSection,
ExperiencePreviewSection,
HeroSection,
HomeCtaSection,
ProofMetricsSection,
ProcessSnapshotSection,
SelectedWorkSection,
ServicesPreviewSection,
TrustBarSection,
WhoIHelpSection,
} from "@/features/home";

export default function HomePage() {
return (
<>
<HeroSection />
<TrustBarSection />
<ProofMetricsSection />
<WhoIHelpSection />
<SelectedWorkSection />
<ExperiencePreviewSection />
<CapabilitiesSection />
<ClientQuotesSection />
<ServicesPreviewSection />
<ProcessSnapshotSection />
Expand Down
12 changes: 12 additions & 0 deletions src/app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,24 @@ export default function sitemap(): MetadataRoute.Sitemap {
changeFrequency: "monthly",
priority: 0.8,
},
{
url: `${baseUrl}/experience`,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 0.8,
},
{
url: `${baseUrl}/about`,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 0.7,
},
{
url: `${baseUrl}/writing`,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 0.5,
},
{
url: `${baseUrl}/contact`,
lastModified: new Date(),
Expand Down
17 changes: 17 additions & 0 deletions src/app/writing/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Metadata } from "next";

import { createMetadata } from "@/config/site";
import { WritingPage } from "@/features/writing";

export const metadata: Metadata = createMetadata({
title: "Writing",
description:
"Product engineering notes from Kailash — shipping software, delivery judgment, and building systems that last.",
alternates: {
canonical: "/writing",
},
});

export default function Page() {
return <WritingPage />;
}
4 changes: 4 additions & 0 deletions src/components/common/case-study-badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@ export function CaseStudyBadge({ study }: { study: CaseStudy }) {
return <Badge>Founder product</Badge>;
}

if (study.engagement === "employment") {
return <Badge>Product delivery</Badge>;
}

return <Badge>{study.category}</Badge>;
}
24 changes: 15 additions & 9 deletions src/components/common/section.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { forwardRef } from "react";

import { cn } from "@/lib/utils";
import { layout } from "@/constants";

Expand All @@ -7,16 +9,20 @@ type SectionProps = React.HTMLAttributes<HTMLElement> & {
muted?: boolean;
};

export function Section({
as: Component = "section",
bordered = false,
muted = false,
className,
children,
...props
}: SectionProps) {
export const Section = forwardRef<HTMLElement, SectionProps>(function Section(
{
as: Component = "section",
bordered = false,
muted = false,
className,
children,
...props
},
ref,
) {
return (
<Component
ref={ref as never}
className={cn(
layout.section.paddingY,
bordered && "border-y border-border",
Expand All @@ -28,4 +34,4 @@ export function Section({
{children}
</Component>
);
}
});
2 changes: 1 addition & 1 deletion src/components/layout/mobile-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function MobileNav() {
}, [open]);

return (
<div className="md:hidden">
<div className="lg:hidden">
<Button
variant="ghost"
size="icon"
Expand Down
36 changes: 25 additions & 11 deletions src/components/layout/site-footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,24 @@ export function SiteFooter() {
return (
<footer className="border-t border-border">
<div
className={`mx-auto flex flex-col gap-8 py-12 ${layout.container.default} ${layout.section.paddingX}`}
className={`mx-auto flex flex-col gap-10 py-14 ${layout.container.default} ${layout.section.paddingX}`}
>
<div className="flex flex-col gap-8 md:flex-row md:items-start md:justify-between">
<div className="grid gap-10 md:grid-cols-[1.2fr_1fr]">
<div>
<p className="text-sm font-medium">{siteConfig.fullName}</p>
<p className="text-muted-foreground mt-1 text-sm">
{siteConfig.title}
<p className="text-lg font-semibold tracking-tight">
{siteConfig.fullName}
</p>
<p className="text-muted-foreground mt-2 max-w-md text-sm leading-relaxed">
{siteConfig.title}. {siteConfig.tagline}
</p>
<p className="text-muted-foreground mt-3 text-sm">
{siteConfig.location}
</p>
{socialLinks.length > 0 && (
<div className="mt-4 flex items-center gap-3">
<div className="mt-5 flex items-center gap-3">
{socialLinks.map((link) => {
const Icon = socialIcons[link.label as keyof typeof socialIcons];
const Icon =
socialIcons[link.label as keyof typeof socialIcons];
return (
<a
key={link.href}
Expand All @@ -46,7 +52,7 @@ export function SiteFooter() {
</div>

<nav
className="flex flex-wrap gap-x-6 gap-y-2"
className="grid grid-cols-2 gap-x-6 gap-y-3 sm:justify-self-end"
aria-label="Footer"
>
{navigation.map((item) => (
Expand All @@ -61,9 +67,17 @@ export function SiteFooter() {
</nav>
</div>

<p className="text-muted-foreground text-sm">
© {year} {siteConfig.author.name}
</p>
<div className="flex flex-col gap-2 border-t border-border pt-6 sm:flex-row sm:items-center sm:justify-between">
<p className="text-muted-foreground text-sm">
© {year} {siteConfig.author.name}
</p>
<a
href={`mailto:${siteConfig.author.email}`}
className="text-muted-foreground hover:text-foreground text-sm transition-colors"
>
{siteConfig.author.email}
</a>
</div>
</div>
</footer>
);
Expand Down
4 changes: 2 additions & 2 deletions src/components/layout/site-header-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function DesktopNav() {
const pathname = usePathname();

return (
<nav className="hidden items-center gap-8 md:flex" aria-label="Main">
<nav className="hidden items-center gap-5 lg:flex xl:gap-7" aria-label="Main">
{navigation.map((item) => {
const isActive = pathname.startsWith(item.href);

Expand Down Expand Up @@ -40,7 +40,7 @@ export function HeaderActions() {
return (
<div className="flex items-center gap-1">
<ThemeToggle />
<Button asChild size="sm" className="hidden shrink-0 md:inline-flex">
<Button asChild size="sm" className="hidden shrink-0 lg:inline-flex">
<Link href={cta.href}>{cta.label}</Link>
</Button>
</div>
Expand Down
9 changes: 6 additions & 3 deletions src/components/layout/site-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ export function SiteHeader() {
return (
<header className="sticky top-0 z-50 border-b border-border/60 bg-background/80 backdrop-blur-md">
<div
className={`mx-auto flex h-16 items-center justify-between ${layout.container.default} ${layout.section.paddingX}`}
className={`mx-auto flex h-16 items-center justify-between gap-4 ${layout.container.default} ${layout.section.paddingX}`}
>
<Link href="/" className="text-sm font-semibold tracking-tight">
<Link
href="/"
className="shrink-0 text-sm font-semibold tracking-tight"
>
{siteConfig.name}
<span className="text-muted-foreground font-normal">
<span className="text-muted-foreground hidden font-normal lg:inline">
{" "}
— {siteConfig.title}
</span>
Expand Down
8 changes: 8 additions & 0 deletions src/config/site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ export const siteConfig = {
name: "Kailash",
fullName: "Kailash Gayari",
title: "Product Engineering Partner",
tagline: "Building production web, mobile & IoT products since 2019.",
description:
"I help founders and growing teams design, build, and ship production-ready web and mobile software — from architecture through deployment.",
url: process.env.NEXT_PUBLIC_SITE_URL ?? "https://kailash-dev.github.io",
ogImage: withBasePath("/opengraph-image"),
locale: "en_US",
location: "Vapi, Gujarat, India",
author: {
name: "Kailash Gayari",
email: "kailash514910@gmail.com",
Expand All @@ -22,6 +24,8 @@ export const siteConfig = {
github: "https://github.com/Kailash-dev",
},
calendlyUrl: process.env.NEXT_PUBLIC_CALENDLY_URL ?? "",
/** Set when a public resume PDF is available under /public */
resumeUrl: "",
keywords: [
"product engineering partner",
"software engineering consultant",
Expand All @@ -30,6 +34,7 @@ export const siteConfig = {
"SaaS MVP development",
"international software consultant",
"full stack product development",
"IoT product engineering",
],
trustSignals: [
{
Expand Down Expand Up @@ -63,6 +68,9 @@ export function createMetadata(overrides?: Partial<Metadata>): Metadata {
keywords: [...keywords],
authors: [{ name: author.name, url }],
creator: author.name,
alternates: {
canonical: url,
},
openGraph: {
type: "website",
locale: siteConfig.locale,
Expand Down
3 changes: 2 additions & 1 deletion src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
export const navigation = [
{ label: "Work", href: "/work" },
{ label: "Process", href: "/process" },
{ label: "Experience", href: "/experience" },
{ label: "Services", href: "/services" },
{ label: "About", href: "/about" },
{ label: "Writing", href: "/writing" },
{ label: "Contact", href: "/contact" },
] as const;

Expand Down
20 changes: 13 additions & 7 deletions src/data/about.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
export const aboutContent = {
headline: "Engineering partner for founders who need clarity and delivery",
headline: "Senior product engineer. Partner for founders who need ownership.",
intro:
"I help international founders and growing teams turn product ideas into production-ready software. My work spans architecture, full-stack development, and deployment — with a focus on outcomes, not output.",
"I'm Kailash Gayari — a Product Engineering Partner based in Vapi, Gujarat, with nearly seven years building production web, mobile, backend, and IoT systems. I help founders and growing teams take software from idea to production with clarity and accountability.",
story: [
"Over years of building products across web, mobile, and IoT, I've learned that the hardest part isn't writing code — it's making the right decisions under uncertainty.",
"I work with decision makers who need a senior partner they can trust: someone who takes ownership, communicates clearly, and ships software that holds up in production.",
"Whether you're launching an MVP, scaling a SaaS product, or need reliable execution on a complex feature — I bring structured delivery without the overhead of a large agency.",
"Since 2019 I've shipped entertainment devices, IoT dashboards, design tools, invoice platforms, community products, and founder-facing SaaS — always with the same standard: production software that decision makers can trust.",
"I work best when ownership is clear. Architecture, delivery, and deployment are not separate conversations — they're one engagement. That is how complex products stay coherent.",
"Whether you need an MVP, a technical partner on an existing product, or senior judgment on architecture — I bring structured delivery without agency overhead, and without treating your product like a ticket queue.",
],
availability: [
"Full-time product engineering roles",
"Freelance and contract engagements",
"Technical consulting",
"Startup CTO / founding engineer conversations",
],
workingStyle: [
{
Expand All @@ -31,12 +37,12 @@ export const aboutContent = {
],
capabilities: [
"Product architecture & technical strategy",
"Web applications (Next.js, React)",
"Web applications (React, Next.js, Angular)",
"Mobile applications (React Native)",
"API design & third-party integrations",
"Authentication, payments & billing flows",
"IoT dashboards & device-facing software",
"Cloud deployment (AWS, Docker, CI/CD)",
"Database design & data modeling",
"Technical advisory & code review",
],
} as const;
Loading
Loading