Skip to content
Open
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
71 changes: 58 additions & 13 deletions app/services/[slug]/ExpertisePageClient.tsx

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion app/services/[slug]/ExpertisePageHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const heroCTAMap: Record<string, { text: string; href: string }> = {
"nextjs": { text: "Talk to a Next.js Engineer", href: "#book-call" },
"nodejs": { text: "Talk to a Node.js Engineer", href: "#book-call" },
"react": { text: "Talk to a React Engineer", href: "#book-call" },
"go": { text: "Talk to a Go Engineer", href: "#book-call" },
"python": { text: "Talk to a Python Engineer", href: "#book-call" },
"angular": { text: "Talk to an Angular Engineer", href: "#book-call" },
"flutter": { text: "Talk to a Flutter Engineer", href: "#book-call" },
Expand All @@ -19,7 +20,7 @@ const heroCTAMap: Record<string, { text: string; href: string }> = {

const noSecondaryCTASlugs = [
"ai-engineering", "ai-agents", "dotnet", "nextjs", "nodejs",
"react", "python", "angular", "flutter", "react-native",
"react", "go", "python", "angular", "flutter", "react-native",
"prometheus-monitoring", "istio-consulting", "thanos-long-term-storage",
];

Expand Down Expand Up @@ -90,6 +91,13 @@ const heroChildrenMap: Record<string, HeroChildrenConfig> = {
{ href: "#hire", text: "Need developers on your team?" },
],
},
"go": {
badges: ["Free architecture review", "30-minute call", "Talk to engineers, not sales"],
links: [
{ href: "#services", text: "Need a system built?" },
{ href: "#hire", text: "Need Go developers on your team?" },
],
},
"python": {
badges: ["Free architecture review", "30-minute call", "Talk to engineers, not sales"],
links: [
Expand Down
8 changes: 4 additions & 4 deletions app/services/[slug]/slug-sections/CustomStackTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ const dataMap: Record<string, StackData> = {
},
react: {
type: "three-column",
title: "Our",
highlight: "React",
afterHighlight: "Stack",
title: "React Technology",
highlight: "Stack",
afterHighlight: "We Use in Production",
subtitle:
"Every tool earns its place. Here\u2019s what we ship with and why.",
whyHeader: "Why",
Expand Down Expand Up @@ -196,7 +196,7 @@ const dataMap: Record<string, StackData> = {
},
],
bottomNote:
"We pick the tooling based on your project. A dashboard doesn\u2019t need Next.js and Vercel - React + Vite + CloudFront is faster to build and cheaper to run. A marketing site doesn\u2019t need Redux - server state with React Query is enough. The stack follows the problem.",
"Procedure picks the tooling based on your project. A dashboard doesn\u2019t need Next.js and Vercel - React + Vite + CloudFront is faster to build and cheaper to run. A marketing site doesn\u2019t need Redux - server state with React Query is enough. The stack follows the problem.",
},
python: {
type: "three-column",
Expand Down
5 changes: 3 additions & 2 deletions app/services/[slug]/slug-sections/FrameworkComparison.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ const comparisonDataMap: Record<string, ComparisonData> = {
],
bottomNote: (
<>
Many projects use both. A public marketing site on Next.js, an
authenticated dashboard on React + Vite, sharing the same component
Many projects use both. A public marketing site on{" "}
<a href="/technologies/nextjs/" className="text-accent hover:text-accent-light">Next.js</a>
, an authenticated dashboard on React + Vite, sharing the same component
library and design system. We architect for this pattern regularly.
</>
),
Expand Down
81 changes: 38 additions & 43 deletions app/services/[slug]/slug-sections/TechDecisionTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ const dataMap: Record<string, TechDecisionData> = {
},
react: {
sectionId: "decision",
title: "Is React Right for Your",
highlight: "Project?",
subtitle: "The most popular frontend library isn\u2019t always the right one.",
title: "When to Choose React for Your",
highlight: "Project",
subtitle: "React is the most widely adopted frontend library in professional software development, with the largest ecosystem of third-party packages, component libraries, and developer tooling of any frontend technology. But the most popular library isn\u2019t always the right one.",
cards: [
{
label: "Dynamic, interaction-heavy UIs (dashboards, editors, tools)",
Expand All @@ -89,46 +89,41 @@ const dataMap: Record<string, TechDecisionData> = {
},
],
bottomNote: (
<p className="text-sm text-text-muted max-w-3xl mx-auto leading-relaxed">
If SEO and page speed are your top priority,{" "}
<a
href="/technologies/nextjs/"
className="text-accent hover:text-accent-light"
>
Next.js
</a>{" "}
gives you server-side rendering, static generation, and edge functions
built on React. For structured enterprise apps with strict conventions,{" "}
<a
href="/technologies/angular/"
className="text-accent hover:text-accent-light"
>
Angular
</a>{" "}
provides routing, forms, and dependency injection out of the box. Need a
lightweight backend to pair with React?{" "}
<a
href="/technologies/nodejs/"
className="text-accent hover:text-accent-light"
>
Node.js
</a>{" "}
or{" "}
<a
href="/technologies/python/"
className="text-accent hover:text-accent-light"
>
Python
</a>{" "}
depending on your workload. Not sure? That&apos;s what our{" "}
<a
href="#book-call"
className="text-accent hover:text-accent-light"
>
architecture consultation
</a>{" "}
is for.
</p>
<div className="text-left max-w-3xl mx-auto">
<h3 className="text-lg font-semibold text-text-primary mb-4">
Choosing the Right Approach for Your Project
</h3>
<div className="space-y-3 text-sm text-text-muted leading-relaxed">
<p>
Some projects start as &ldquo;we need a React app&rdquo; but turn out to need something slightly different. Here&apos;s how we help teams land on the right approach:
</p>
<p>
If your project needs strong SEO and server-side rendering, we typically recommend{" "}
<a href="/technologies/nextjs/" className="text-accent hover:text-accent-light">Next.js</a>
{" "}- which is built on React, so your team still writes React components.
</p>
<p>
If you need a cross-platform mobile app alongside your web app,{" "}
<a href="/technologies/react-native/" className="text-accent hover:text-accent-light">React Native</a>
{" "}lets you share code across both.
</p>
<p>
If your enterprise already runs{" "}
<a href="/technologies/angular/" className="text-accent hover:text-accent-light">Angular</a>
{" "}and wants consistency across teams, extending that investment can make more sense than introducing a new framework.
</p>
<p>
Need a lightweight backend to pair with React?{" "}
<a href="/technologies/nodejs/" className="text-accent hover:text-accent-light">Node.js</a>
{" "}or{" "}
<a href="/technologies/python/" className="text-accent hover:text-accent-light">Python</a>
{" "}depending on your workload.
</p>
<p>
We&apos;ll always recommend what fits your situation. That&apos;s what the free architecture review is for.
</p>
</div>
</div>
),
},
python: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export default function DotnetModernizationPageClient() {

{/* Problem Signals Section */}
<ProblemSignals
title="Is Your Legacy .NET Holding You Back?"
title="Is Your Legacy .NET Framework Holding You Back?"
intro={problemIntro}
signals={problemSignals}
/>
Expand All @@ -192,7 +192,7 @@ export default function DotnetModernizationPageClient() {

{/* Approach / Process Timeline */}
<ProcessTimeline
title="Our .NET Modernization Approach"
title="How .NET Modernization Works at Procedure"
subtitle="A proven process that minimizes risk and maximizes velocity"
steps={approachSteps}
/>
Expand Down
12 changes: 6 additions & 6 deletions app/technologies/dotnet/modernization/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import type { Metadata } from "next";

export const metadata: Metadata = {
title:
".NET Modernization Services | Migrate .NET Framework to .NET 8 | Procedure",
".NET Modernization Services | Migrate .NET Framework to .NET 8/10 | Procedure.tech",
description:
"Migrate legacy .NET Framework applications to .NET 8 with zero downtime. Expert .NET modernization using Strangler Fig pattern. Free migration assessment included.",
"Migrate legacy .NET Framework applications to modern .NET with zero downtime. Expert .NET modernization using Strangler Fig pattern. Free migration assessment included.",
alternates: {
canonical: "/technologies/dotnet/modernization",
},
openGraph: {
title:
".NET Modernization Services | Migrate .NET Framework to .NET 8 | Procedure",
".NET Modernization Services | Migrate .NET Framework to .NET 8/10 | Procedure.tech",
description:
"Migrate legacy .NET Framework applications to .NET 8 with zero downtime. Expert .NET modernization using Strangler Fig pattern. Free migration assessment included.",
"Migrate legacy .NET Framework applications to modern .NET with zero downtime. Expert .NET modernization using Strangler Fig pattern. Free migration assessment included.",
type: "website",
url: "/technologies/dotnet/modernization",
images: [
Expand All @@ -27,9 +27,9 @@ export const metadata: Metadata = {
twitter: {
card: "summary_large_image",
title:
".NET Modernization Services | Migrate .NET Framework to .NET 8 | Procedure",
".NET Modernization Services | Migrate .NET Framework to .NET 8/10 | Procedure.tech",
description:
"Migrate legacy .NET Framework applications to .NET 8 with zero downtime. Expert .NET modernization using Strangler Fig pattern. Free migration assessment included.",
"Migrate legacy .NET Framework applications to modern .NET with zero downtime. Expert .NET modernization using Strangler Fig pattern. Free migration assessment included.",
images: [
{
url: "/assets/technologies/dotnet-migration.png",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
SkillsTable,
UseCaseStories,
EngagementModels,
ComparisonTable,
RelatedDotnetServices,
} from "@/components/technologies";
import {
Expand All @@ -29,6 +30,8 @@ import {
whyProcedure,
engagementModelsTitle,
engagementModels,
comparisonTitle,
comparisonRows,
faqs,
ctaData,
relatedServices,
Expand Down Expand Up @@ -219,6 +222,9 @@ export default function DotnetStaffAugPageClient() {
models={engagementModels}
/>

{/* Comparison Table */}
<ComparisonTable title={comparisonTitle} rows={comparisonRows} />

{/* CTA Section with Cal.com Embed */}
<section
id="book-call"
Expand Down
6 changes: 3 additions & 3 deletions app/technologies/dotnet/staff-augmentation/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import type { Metadata } from "next";

export const metadata: Metadata = {
title:
".NET Staff Augmentation | Hire Senior .NET Developers | Procedure",
".NET Staff Augmentation | Hire Senior .NET Developers | Procedure.tech",
description:
"Extend your team with senior .NET developers in 5 days. Pre-vetted ASP.NET Core, C#, and Azure experts who integrate with your workflows. No recruitment overhead.",
alternates: {
canonical: "/technologies/dotnet/staff-augmentation",
},
openGraph: {
title:
".NET Staff Augmentation | Hire Senior .NET Developers | Procedure",
".NET Staff Augmentation | Hire Senior .NET Developers | Procedure.tech",
description:
"Extend your team with senior .NET developers in 5 days. Pre-vetted ASP.NET Core, C#, and Azure experts who integrate with your workflows. No recruitment overhead.",
type: "website",
Expand All @@ -27,7 +27,7 @@ export const metadata: Metadata = {
twitter: {
card: "summary_large_image",
title:
".NET Staff Augmentation | Hire Senior .NET Developers | Procedure",
".NET Staff Augmentation | Hire Senior .NET Developers | Procedure.tech",
description:
"Extend your team with senior .NET developers in 5 days. Pre-vetted ASP.NET Core, C#, and Azure experts who integrate with your workflows. No recruitment overhead.",
images: [
Expand Down
36 changes: 36 additions & 0 deletions app/technologies/go/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { Metadata } from "next";

export const metadata: Metadata = {
title:
"Go Development Services | High-Performance APIs & Microservices",
description:
"Go development services for scalable APIs, microservices, and cloud-native backends. Senior Go engineers, free architecture review. Talk to engineers, not sales.",
alternates: {
canonical: "/technologies/go",
},
openGraph: {
title:
"Go Development Services | High-Performance APIs & Microservices",
description:
"Go development services for scalable APIs, microservices, and cloud-native backends. Senior Go engineers, free architecture review. Talk to engineers, not sales.",
type: "website",
url: "/technologies/go",
},
twitter: {
card: "summary_large_image",
title:
"Go Development Services | High-Performance APIs & Microservices",
description:
"Go development services for scalable APIs, microservices, and cloud-native backends. Senior Go engineers, free architecture review. Talk to engineers, not sales.",
site: "@procedurehq",
creator: "@procedurehq",
},
};

export default function GoLayout({
children,
}: {
children: React.ReactNode;
}) {
return <>{children}</>;
}
28 changes: 28 additions & 0 deletions app/technologies/go/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { notFound } from "next/navigation";
import {
getTechnologyForListing,
getRelatedExpertiseForListing,
} from "@/lib/content";
import ExpertisePageClient from "@/app/services/[slug]/ExpertisePageClient";
import { ExpertisePageHero } from "@/app/services/[slug]/ExpertisePageHero";

export default function GoPage() {
const technology = getTechnologyForListing("go");

if (!technology) {
notFound();
}

const relatedPages = getRelatedExpertiseForListing(
technology.relatedExpertise || [],
);

return (
<ExpertisePageClient
expertise={technology}
relatedPages={relatedPages}
basePath="/technologies"
heroSlot={<ExpertisePageHero expertise={technology} />}
/>
);
}
12 changes: 6 additions & 6 deletions app/technologies/react/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@ import type { Metadata } from "next";

export const metadata: Metadata = {
title:
"React Development Services | Web Apps, SPAs & UI Engineering",
"React Development Services | Web Apps, SPAs & Dashboard Development",
description:
"React development services for web applications, SPAs, dashboards, and component libraries. React 19, TypeScript, production-tested. Talk to engineers, not sales.",
"React development services for web apps, SPAs, and enterprise dashboards. React 19, TypeScript, free architecture review. Talk to engineers, not sales.",
alternates: {
canonical: "/technologies/react",
},
openGraph: {
title:
"React Development Services | Web Apps, SPAs & UI Engineering",
"React Development Services | Web Apps, SPAs & Dashboard Development",
description:
"React development services for web applications, SPAs, and dashboards. React 19, TypeScript, production-tested. Talk to engineers, not sales.",
"React development services for web apps, SPAs, and enterprise dashboards. React 19, TypeScript, free architecture review. Talk to engineers, not sales.",
type: "website",
url: "/technologies/react",
},
twitter: {
card: "summary_large_image",
title:
"React Development Services | Web Apps, SPAs & UI Engineering",
"React Development Services | Web Apps, SPAs & Dashboard Development",
description:
"React development services for web applications, SPAs, and dashboards. React 19, TypeScript, production-tested. Talk to engineers, not sales.",
"React development services for web apps, SPAs, and enterprise dashboards. React 19, TypeScript, free architecture review. Talk to engineers, not sales.",
site: "@procedurehq",
creator: "@procedurehq",
},
Expand Down
3 changes: 2 additions & 1 deletion components/expertise/CapabilitiesGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { m } from "framer-motion";
import { ReactNode } from "react";
import { cn } from "@/lib/utils";
import { renderLinkedText } from "@/lib/render-linked-text";

interface Capability {
icon: ReactNode;
Expand Down Expand Up @@ -92,7 +93,7 @@ export function CapabilitiesGrid({
{capability.title}
</h3>
<p className="text-text-secondary leading-relaxed">
{capability.description}
{renderLinkedText(capability.description)}
</p>
</m.div>
))}
Expand Down
3 changes: 2 additions & 1 deletion components/expertise/FAQSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { useState } from "react";
import { m, AnimatePresence } from "framer-motion";
import { cn } from "@/lib/utils";
import { renderLinkedText } from "@/lib/render-linked-text";

interface FAQ {
question: string;
Expand Down Expand Up @@ -99,7 +100,7 @@ export function FAQSection({
<div className="px-6 pb-5">
<div className="h-px bg-border mb-4" />
<p className="text-text-secondary leading-relaxed">
{faq.answer}
{renderLinkedText(faq.answer)}
</p>
</div>
</m.div>
Expand Down
Loading
Loading