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
13 changes: 10 additions & 3 deletions src/components/Header.astro
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
---
import LanguageSwitch from "./LanguageSwitch.astro";
import type { RouteKey, RouteParams } from "../i18n/routes";

const { lang } = Astro.props;
type Props = {
lang: "pl" | "en";
routeKey: RouteKey;
routeParams?: RouteParams;
};

const { lang, routeKey, routeParams } = Astro.props as Props;

const homeHref = lang === "pl" ? "/pl/" : "/en/";

Expand Down Expand Up @@ -94,7 +101,7 @@ const nav = lang === "pl"
{nav.map((i) => (
<a href={i.href}>{i.label}</a>
))}
<LanguageSwitch lang={lang} />
<LanguageSwitch lang={lang} routeKey={routeKey} routeParams={routeParams} />
</div>
</nav>

Expand All @@ -111,4 +118,4 @@ const nav = lang === "pl"
navLinks.dataset.open = nextState;
});
}
</script>
</script>
13 changes: 10 additions & 3 deletions src/components/LanguageSwitch.astro
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
---
const { lang } = Astro.props;
import { getRoutePaths } from "../i18n/routes";
import type { RouteKey, RouteParams } from "../i18n/routes";

type Props = {
lang: "pl" | "en";
routeKey: RouteKey;
routeParams?: RouteParams;
};

const { lang, routeKey, routeParams } = Astro.props as Props;
const isPL = lang === "pl";
const plHref = "/pl/";
const enHref = "/en/";
const { pl: plHref, en: enHref } = getRoutePaths(routeKey, routeParams);
---
<div class="lang" aria-label="Language switch">
<a href={plHref} aria-current={isPL ? "page" : undefined}>PL</a>
Expand Down
103 changes: 103 additions & 0 deletions src/i18n/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
export type RouteKey =
| "home"
| "services"
| "servicesDevelopment"
| "servicesDesign"
| "servicesInfrastructure"
| "servicesDeployment"
| "servicesPostLaunch"
| "contact"
| "caseStudies"
| "caseStudy"
| "howWeWork"
| "faq"
| "forFounders";

export type RouteParams = {
slug?: string;
};

type RouteBuilder = (params?: RouteParams) => string;

type RouteEntry = {
pl: string | RouteBuilder;
en: string | RouteBuilder;
};

const buildCaseStudyPath = (basePath: string): RouteBuilder => (params) => {
if (!params?.slug) {
throw new Error("Missing slug for case study route.");
}

return `${basePath}${params.slug}/`;
};

const routes: Record<RouteKey, RouteEntry> = {
home: {
pl: "/pl/",
en: "/en/",
},
services: {
pl: "/pl/oferta/",
en: "/en/services/",
},
servicesDevelopment: {
pl: "/pl/oferta/programowanie/",
en: "/en/services/development/",
},
servicesDesign: {
pl: "/pl/oferta/projektowanie/",
en: "/en/services/design/",
},
servicesInfrastructure: {
pl: "/pl/oferta/infrastruktura/",
en: "/en/services/infrastructure/",
},
servicesDeployment: {
pl: "/pl/oferta/wdrozenie/",
en: "/en/services/deployment/",
},
servicesPostLaunch: {
pl: "/pl/oferta/obsluga/",
en: "/en/services/post-launch/",
},
contact: {
pl: "/pl/kontakt/",
en: "/en/contact/",
},
caseStudies: {
pl: "/pl/case-studies/",
en: "/en/case-studies/",
},
caseStudy: {
pl: buildCaseStudyPath("/pl/case-studies/"),
en: buildCaseStudyPath("/en/case-studies/"),
},
howWeWork: {
pl: "/pl/how-we-work/",
en: "/en/how-we-work/",
},
faq: {
pl: "/pl/faq/",
en: "/en/faq/",
},
forFounders: {
pl: "/pl/for-founders/",
en: "/en/for-founders/",
},
};

const resolvePath = (value: string | RouteBuilder, params?: RouteParams): string =>
typeof value === "function" ? value(params) : value;

export const getRoutePaths = (
routeKey: RouteKey,
params?: RouteParams,
): { pl: string; en: string } => {
const entry = routes[routeKey];

return {
pl: resolvePath(entry.pl, params),
en: resolvePath(entry.en, params),
};
};
33 changes: 30 additions & 3 deletions src/layouts/BaseLayout.astro
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
---
const { title, description = "", lang = "en" } = Astro.props;

import "../styles/global.css";
import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro";
import ContactLauncher from "../components/ContactLauncher.astro";
import { getRoutePaths } from "../i18n/routes";
import type { RouteKey, RouteParams } from "../i18n/routes";

type Props = {
title?: string;
description?: string;
lang?: "pl" | "en";
routeKey?: RouteKey;
routeParams?: RouteParams;
};

const {
title,
description = "",
lang = "en",
routeKey,
routeParams,
} = Astro.props as Props;

const baseUrl = "https://rocketdeploy.dev";
const routePaths = routeKey ? getRoutePaths(routeKey, routeParams) : null;
const plUrl = routePaths ? new URL(routePaths.pl, baseUrl).toString() : null;
const enUrl = routePaths ? new URL(routePaths.en, baseUrl).toString() : null;
const canonicalUrl = routePaths ? (lang === "pl" ? plUrl : enUrl) : null;
---

<!doctype html>
Expand All @@ -19,12 +41,17 @@ import ContactLauncher from "../components/ContactLauncher.astro";
{description && <meta name="description" content={description} />}
{description && <meta property="og:description" content={description} />}
{description && <meta name="twitter:description" content={description} />}

{canonicalUrl && <link rel="canonical" href={canonicalUrl} />}
{plUrl && <link rel="alternate" hreflang="pl" href={plUrl} />}
{enUrl && <link rel="alternate" hreflang="en" href={enUrl} />}
{enUrl && <link rel="alternate" hreflang="x-default" href={enUrl} />}
</head>

<body>
<div class="header">
<div class="container">
<Header lang={lang} />
<Header lang={lang} routeKey={routeKey ?? "home"} routeParams={routeParams} />
</div>
</div>

Expand Down
20 changes: 18 additions & 2 deletions src/layouts/CaseStudyLayout.astro
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
---
import BaseLayout from "./BaseLayout.astro";
const { title, lang = "en", tags = [] } = Astro.props;
import type { RouteKey, RouteParams } from "../i18n/routes";

type Props = {
title: string;
lang?: "pl" | "en";
tags?: string[];
routeKey?: RouteKey;
routeParams?: RouteParams;
};

const {
title,
lang = "en",
tags = [],
routeKey,
routeParams,
} = Astro.props as Props;
---

<BaseLayout lang={lang} title={title}>
<BaseLayout lang={lang} title={title} routeKey={routeKey} routeParams={routeParams}>
<div style="max-width: 78ch;">
<div style="font-family: var(--mono); color: rgba(122,162,255,.85); font-size: 12px;">case study</div>
<h1 style="margin-top:10px;">{title}</h1>
Expand Down
3 changes: 2 additions & 1 deletion src/pages/en/case-studies.astro
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const entries = await getCollection("en-case-studies");

<BaseLayout
lang="en"
routeKey="caseStudies"
title="Case studies: delivered systems"
description="RocketDeploy case studies: how we design, build and deliver systems. Scope, architectural decisions and real production outcomes."
>
Expand All @@ -26,4 +27,4 @@ const entries = await getCollection("en-case-studies");
))}
</div>
</section>
</BaseLayout>
</BaseLayout>
7 changes: 6 additions & 1 deletion src/pages/en/case-studies/[slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ const { entry } = Astro.props;
const { Content } = await entry.render();
---

<BaseLayout lang="en" title={entry.data.title}>
<BaseLayout
lang="en"
routeKey="caseStudy"
routeParams={{ slug: entry.slug }}
title={entry.data.title}
>
<section class="section">
<a class="btn" href="/en/case-studies/">← Back to list</a>
</section>
Expand Down
3 changes: 2 additions & 1 deletion src/pages/en/contact.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import BaseLayout from "../../layouts/BaseLayout.astro";

<BaseLayout
lang="en"
routeKey="contact"
title="Contact — let’s talk about your system"
description="Contact RocketDeploy. Share what you want to build or improve — we’ll respond with a clear next step and a realistic path forward."
>
Expand Down Expand Up @@ -139,4 +140,4 @@ import BaseLayout from "../../layouts/BaseLayout.astro";
showTick();
};
</script>
</BaseLayout>
</BaseLayout>
4 changes: 2 additions & 2 deletions src/pages/en/faq/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import BaseLayout from "../../../layouts/BaseLayout.astro";
---

<BaseLayout lang="en" title="FAQ">
<BaseLayout lang="en" routeKey="faq" title="FAQ">
<section class="section">
<h1>FAQ</h1>

Expand Down Expand Up @@ -129,4 +129,4 @@ import BaseLayout from "../../../layouts/BaseLayout.astro";
</div>
</div>
</section>
</BaseLayout>
</BaseLayout>
3 changes: 2 additions & 1 deletion src/pages/en/for-founders.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import BaseLayout from "../../layouts/BaseLayout.astro";

<BaseLayout
lang="en"
routeKey="forFounders"
title="From idea to MVP and production"
description="We help founders go from idea to a working system. MVPs, prototypes and first deployments with clear trade-offs and a path to production."
>
Expand Down Expand Up @@ -125,4 +126,4 @@ import BaseLayout from "../../layouts/BaseLayout.astro";
</div>
</div>
</section>
</BaseLayout>
</BaseLayout>
3 changes: 2 additions & 1 deletion src/pages/en/how-we-work.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import BaseLayout from "../../layouts/BaseLayout.astro";

<BaseLayout
lang="en"
routeKey="howWeWork"
title="How we deliver production systems"
description="How we work at RocketDeploy: clear scope, predictable delivery and a production mindset from day one. Architecture, implementation and deployment."
>
Expand Down Expand Up @@ -97,4 +98,4 @@ import BaseLayout from "../../layouts/BaseLayout.astro";
</p>
</div>
</section>
</BaseLayout>
</BaseLayout>
3 changes: 2 additions & 1 deletion src/pages/en/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import HeroVisual from "../../components/HeroVisual.astro";

<BaseLayout
lang="en"
routeKey="home"
title="End-to-end systems — architecture & delivery"
description="We design and deliver production-ready software systems — from MVPs and prototypes to stable platforms. Microservices, APIs, event-driven architecture, Kubernetes, cloud and device integrations."
>
Expand Down Expand Up @@ -211,4 +212,4 @@ import HeroVisual from "../../components/HeroVisual.astro";
</div>
</div>
</section>
</BaseLayout>
</BaseLayout>
4 changes: 2 additions & 2 deletions src/pages/en/services/deployment/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import BaseLayout from "../../../../layouts/BaseLayout.astro";
---

<BaseLayout lang="en" title="Services – Deployment">
<BaseLayout lang="en" routeKey="servicesDeployment" title="Services – Deployment">
<section class="section">
<h1>Deployment</h1>

Expand Down Expand Up @@ -41,4 +41,4 @@ import BaseLayout from "../../../../layouts/BaseLayout.astro";
</ul>
</div>
</section>
</BaseLayout>
</BaseLayout>
4 changes: 2 additions & 2 deletions src/pages/en/services/design/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import BaseLayout from "../../../../layouts/BaseLayout.astro";
---

<BaseLayout lang="en" title="Services – Design">
<BaseLayout lang="en" routeKey="servicesDesign" title="Services – Design">
<section class="section">
<h1>Design</h1>

Expand Down Expand Up @@ -45,4 +45,4 @@ import BaseLayout from "../../../../layouts/BaseLayout.astro";
</ul>
</div>
</section>
</BaseLayout>
</BaseLayout>
4 changes: 2 additions & 2 deletions src/pages/en/services/development/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import BaseLayout from "../../../../layouts/BaseLayout.astro";
---

<BaseLayout lang="en" title="Services – Development">
<BaseLayout lang="en" routeKey="servicesDevelopment" title="Services – Development">
<section class="section">
<h1>Development</h1>

Expand Down Expand Up @@ -45,4 +45,4 @@ import BaseLayout from "../../../../layouts/BaseLayout.astro";
</ul>
</div>
</section>
</BaseLayout>
</BaseLayout>
Loading