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
58 changes: 58 additions & 0 deletions apps/marketing-app/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,64 @@ import type { NextConfig } from "next";
const nextConfig: NextConfig = {
reactStrictMode: true,
transpilePackages: ["@asyncstatus/ui"],

// Performance optimizations
compress: true,
poweredByHeader: false,

// Image optimization
images: {
formats: ["image/avif", "image/webp"],
minimumCacheTTL: 31536000, // 1 year
dangerouslyAllowSVG: true,
Comment on lines +14 to +16
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete

contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
},

// Headers for SEO and security
async headers() {
return [
{
source: "/(.*)",
headers: [
{
key: "X-Content-Type-Options",
value: "nosniff",
},
{
key: "X-Frame-Options",
value: "DENY",
},
{
key: "X-XSS-Protection",
value: "1; mode=block",
},
{
key: "Referrer-Policy",
value: "strict-origin-when-cross-origin",
},
],
},
// Cache static assets
{
source: "/favicon.ico",
headers: [
{
key: "Cache-Control",
value: "public, max-age=31536000, immutable",
},
],
},
{
source: "/(.*\\.(?:ico|png|jpg|jpeg|gif|svg|webp|avif))",
headers: [
{
key: "Cache-Control",
value: "public, max-age=31536000, immutable",
},
],
},
];
},
};

export default nextConfig;
Expand Down
60 changes: 47 additions & 13 deletions apps/marketing-app/src/app/(app)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
import { AsyncStatusLogo } from "@asyncstatus/ui/components/async-status-logo";
import { Button } from "@asyncstatus/ui/components/button";
import Link from "next/link";
import type { Metadata } from "next";

export const metadata: Metadata = {
title: "Home",
description: "Replace daily standup meetings with automated status updates. AsyncStatus saves your team 2-3 hours per week by generating updates from Git, Jira, and Slack activity automatically.",
openGraph: {
title: "AsyncStatus - Automated Status Updates for Remote Teams",
description: "Replace daily standup meetings with automated status updates. Save 2-3 hours per developer per week.",
url: "https://asyncstatus.com",
images: [
{
url: "/opengraph-image.jpg",
width: 1200,
height: 630,
alt: "AsyncStatus - No more daily standups, just automated status updates",
},
],
},
twitter: {
card: "summary_large_image",
title: "AsyncStatus - Automated Status Updates for Remote Teams",
description: "Replace daily standup meetings with automated status updates. Save 2-3 hours per developer per week.",
},
alternates: {
canonical: "https://asyncstatus.com",
},
};
import { BetaMessage } from "../components/beta-message";
import { ConnectCard } from "../components/connect-card";
import { CtaSection } from "../components/cta-section";
Expand All @@ -16,6 +43,7 @@ import { TrackCard } from "../components/track-card";
import { UseItYourWay } from "../components/use-it-your-way";
import { peopleSummary } from "./people-summary";
import { PersonSelect } from "./person-select";
import { StructuredData, organizationSchema, productSchema, websiteSchema, faqSchema } from "../structured-data";

export default async function Page(props: {
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
Expand Down Expand Up @@ -48,7 +76,7 @@ export default async function Page(props: {
<div className="flex flex-col">
<Link href="/" className="flex items-center gap-2">
<AsyncStatusLogo className="h-3.5 w-auto" />
<h1 className="text-lg font-medium max-sm:text-base">AsyncStatus</h1>
<span className="text-lg font-medium max-sm:text-base">AsyncStatus</span>
</Link>
</div>

Expand Down Expand Up @@ -137,21 +165,21 @@ export default async function Page(props: {
</a>
</div>

<h2 className="text-fit mr-[2.5vw] text-center font-bold max-sm:hidden">
<h1 className="text-fit mr-[2.5vw] text-center font-bold max-sm:hidden">
<span>
<span>Standup meetings suck</span>
</span>
<span aria-hidden="true">Standup meetings suck</span>
</h2>
<h2 className="hidden text-center text-5xl font-bold max-sm:block">
</h1>
<h1 className="hidden text-center text-5xl font-bold max-sm:block">
Standup meetings suck
</h2>
</h1>

<h3 className="text-muted-foreground mt-6 text-center text-2xl leading-normal text-balance max-md:text-lg max-sm:text-base">
<p className="text-muted-foreground mt-6 text-center text-2xl leading-normal text-balance max-md:text-lg max-sm:text-base">
Your team already pushed code, closed tickets, replied in threads, fixed small things no
one asked them to. We turn it into an update. Or you can write it yourself. Either way, no
one has to talk about it at 9:30 a.m.
</h3>
</p>

<div className="mt-14 flex flex-col items-center justify-center max-sm:mt-6">
<Button size="lg" asChild>
Expand Down Expand Up @@ -265,9 +293,9 @@ export default async function Page(props: {
</div>
</div>

<h3 className="mt-36 text-center text-6xl font-bold max-sm:text-5xl" id="how-it-works">
<h2 className="mt-36 text-center text-6xl font-bold max-sm:text-5xl" id="how-it-works">
How it works
</h3>
</h2>
<div className="mt-24 grid grid-cols-1 gap-8 max-sm:gap-12 sm:grid-cols-2 md:gap-12">
<ConnectCard />
<TrackCard />
Expand Down Expand Up @@ -301,13 +329,13 @@ export default async function Page(props: {

<section id="calculator" className="mt-36">
<div className="mb-12 text-center">
<h3 className="text-center text-6xl font-bold max-sm:text-5xl">
<h2 className="text-center text-6xl font-bold max-sm:text-5xl">
Calculate your savings
</h3>
<h3 className="text-muted-foreground mt-6 text-xl text-pretty">
</h2>
<p className="text-muted-foreground mt-6 text-xl text-pretty">
See how much time and money your team can save by replacing synchronous standups with
AsyncStatus.
</h3>
</p>
</div>
<SavingsCalculator />

Expand Down Expand Up @@ -345,6 +373,12 @@ export default async function Page(props: {
</main>

<Footer />

{/* Structured Data */}
<StructuredData data={organizationSchema} />
<StructuredData data={productSchema} />
<StructuredData data={websiteSchema} />
<StructuredData data={faqSchema} />
</>
);
}
77 changes: 75 additions & 2 deletions apps/marketing-app/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,72 @@ const noto = Noto_Sans({
});

export const metadata: Metadata = {
title: "Async status updates for remote startups",
description: "Made for high-agency teams that value their time.",
title: {
default: "AsyncStatus - Replace Daily Standups with Automated Status Updates",
template: "%s | AsyncStatus"
},
description: "Stop wasting time in daily standups. AsyncStatus automatically generates status updates from your Git commits, Jira tickets, and Slack activity. Save 2-3 hours per developer per week.",
keywords: [
"async status updates",
"remote team management",
"standup replacement",
"team productivity",
"remote work tools",
"automated status reports",
"software development tools",
"team communication",
"agile without meetings",
"distributed teams"
],
authors: [{ name: "AsyncStatus Team" }],
creator: "AsyncStatus",
publisher: "AsyncStatus",
formatDetection: {
email: false,
address: false,
telephone: false,
},
metadataBase: new URL("https://asyncstatus.com"),
alternates: {
canonical: "https://asyncstatus.com",
},
openGraph: {
type: "website",
locale: "en_US",
url: "https://asyncstatus.com",
title: "AsyncStatus - Replace Daily Standups with Automated Status Updates",
description: "Stop wasting time in daily standups. AsyncStatus automatically generates status updates from your Git commits, Jira tickets, and Slack activity. Save 2-3 hours per developer per week.",
siteName: "AsyncStatus",
images: [
{
url: "/opengraph-image.jpg",
width: 1200,
height: 630,
alt: "AsyncStatus - Automated status updates for remote teams",
},
],
},
twitter: {
card: "summary_large_image",
title: "AsyncStatus - Replace Daily Standups with Automated Status Updates",
description: "Stop wasting time in daily standups. AsyncStatus automatically generates status updates from your Git commits, Jira tickets, and Slack activity.",
images: ["/opengraph-image.jpg"],
creator: "@asyncstatus",
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
"max-video-preview": -1,
"max-image-preview": "large",
"max-snippet": -1,
},
},
verification: {
google: "your-google-verification-code", // Replace with actual verification code
},
icons: [
{
url: "/favicon.ico",
Expand All @@ -47,6 +110,16 @@ export const metadata: Metadata = {
href: "/apple-touch-icon-dark.png",
media: "(prefers-color-scheme: dark)",
},
{
url: "/icon-192.png",
sizes: "192x192",
type: "image/png",
},
{
url: "/icon-512.png",
sizes: "512x512",
type: "image/png",
},
],
};

Expand Down
27 changes: 27 additions & 0 deletions apps/marketing-app/src/app/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
User-agent: *
Allow: /

# Disallow sensitive areas
Disallow: /admin/
Disallow: /api/
Disallow: /_next/
Disallow: /private/

# Allow specific bots
User-agent: Googlebot
Allow: /

User-agent: Bingbot
Allow: /

User-agent: facebookexternalhit
Allow: /

User-agent: Twitterbot
Allow: /
Comment on lines +1 to +21
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allow everything


# Sitemap
Sitemap: https://asyncstatus.com/sitemap.xml

# Crawl delay (optional - helps prevent overwhelming server)
Crawl-delay: 1
Comment on lines +26 to +27
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

Loading