Skip to main content
The web application is the main public-facing website for SkyTeam ROBLOX, built with Next.js 15 and React 19.

Overview

The web app serves as the marketing and content hub for SkyTeam ROBLOX, featuring press releases, legal pages, and alliance information. Package: @skyteam/web
Location: apps/web
Port: 3000 (dev)

Technology Stack

  • Framework: Next.js 15.2.8 with App Router
  • UI: React 19, Tailwind CSS 4.0, Radix UI components
  • Content: Contentlayer for MDX-based press releases
  • Styling: Tailwind CSS with custom animations
  • Icons: Lucide React, Radix UI Icons

Project Structure

apps/web/
├── app/
│   ├── (marketing)/          # Marketing pages group
│   │   └── page.tsx          # Landing page
│   ├── press-releases/       # Press release pages
│   ├── privacy/              # Privacy policy
│   ├── terms/                # Terms of service
│   ├── layout.tsx            # Root layout
│   └── globals.css           # Global styles
├── components/
│   ├── site/                 # Site-specific components
│   │   ├── header.tsx
│   │   ├── footer.tsx
│   │   ├── post-card.tsx
│   │   └── ...
│   └── ui/                   # Reusable UI components
├── content/posts/            # MDX press releases
└── contentlayer.config.ts    # Content configuration

Key Features

Landing Page

The landing page (app/(marketing)/page.tsx:9) features:
  • Hero Banner: Fullscreen image banner with “CARING MORE ABOUT YOU” tagline
  • Call-to-Actions: Links to press releases and Discord server
  • Latest News: Displays 3 most recent published press releases
apps/web/app/(marketing)/page.tsx
export default function LandingPage() {
  const posts = (allPosts as any[])
    .filter((p: any) => p.published)
    .sort((a: any, b: any) => +new Date(b.date) - +new Date(a.date))
    .slice(0, 3);

  return (
    <div className="pb-16">
      {/* Fullscreen banner with bottom-left text */}
      <section className="relative h-[80svh] w-full -mt-[72px] pt-[72px]">
        <Image
          src="/images/LandingPage.png"
          alt="Caring more about you"
          fill
          priority
          className="object-cover"
        />
        <div className="absolute inset-0 bg-black/40" />
        <div className="absolute bottom-0 left-0 w-full">
          <div className="mx-auto max-w-6xl px-4 py-10">
            <div className="space-y-4 max-w-2xl">
              <h1 className="font-display text-4xl md:text-6xl font-extrabold tracking-tight">
                CARING MORE ABOUT YOU
              </h1>
              <p className="text-muted-foreground">
                SkyTeam ROBLOX is an alliance of exceptional virtual airlines
                looking to provide the best connected experience within our platform.
              </p>
            </div>
          </div>
        </div>
      </section>
      {/* Latest news section */}
    </div>
  );
}

Content Management

Press releases are managed using Contentlayer (contentlayer.config.ts:1):
apps/web/contentlayer.config.ts
export const Post = defineDocumentType(() => ({
  name: "Post",
  filePathPattern: `posts/**/*.mdx`,
  contentType: "mdx",
  fields: {
    title: { type: "string", required: true },
    description: { type: "string", required: true },
    date: { type: "date", required: true },
    published: { type: "boolean", required: true },
    tags: { type: "list", of: { type: "string" } },
    cover: { type: "string" },
    banner: { type: "string" },
    location: { type: "string" },
  },
  computedFields: {
    slug: {
      type: "string",
      resolve: (doc) => doc._raw.flattenedPath.replace(/^posts\//, ""),
    },
    url: {
      type: "string",
      resolve: (doc) =>
        `/press-releases/${doc._raw.flattenedPath.replace(/^posts\//, "")}`,
    },
  },
}));

Layout & Metadata

The root layout (app/layout.tsx:1) provides consistent structure:
apps/web/app/layout.tsx
export const metadata: Metadata = {
  title: "SkyTeam ROBLOX",
  description:
    "SkyTeam ROBLOX is an alliance of exceptional virtual airlines looking to provide the best connected experience within our platform.",
  icons: {
    icon: "/favicon.ico",
  },
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning className="dark overflow-x-hidden">
      <body className="min-h-dvh flex flex-col">
        <Header />
        <main className="flex-1 relative">{children}</main>
        <Footer />
      </body>
    </html>
  );
}

Component Library

The app uses a custom component library based on shadcn/ui:
  • Site Components: Header, Footer, Logo, PostCard, SocialLinks
  • UI Components: Button, Card, Badge, NavigationMenu, Breadcrumb
  • Styling: Class variance authority (CVA) for component variants

Development

Scripts

# Development server
pnpm dev

# Production build
pnpm build

# Start production server
pnpm start

# Lint code
pnpm lint

Dependencies

Key dependencies from package.json:11:
{
  "dependencies": {
    "@skyteam/database": "workspace:*",
    "@skyteam/ui": "workspace:*",
    "next": "15.2.8",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "next-contentlayer": "^0.3.4",
    "tailwindcss": "^4.0.9"
  }
}

SEO Features

  • Sitemap: Auto-generated at /sitemap.xml
  • RSS Feed: Available at /rss.xml
  • Metadata: Comprehensive OpenGraph and Twitter cards
  • Dark Mode: Default dark theme with proper color schemes

Workspace Integration

The web app integrates with:
  • @skyteam/database - Database queries and schema
  • @skyteam/ui - Shared UI components and utilities

Styling Approach

  • Utility-First: Tailwind CSS with custom configuration
  • Typography: Special Gothic Expanded One custom font
  • Dark Theme: Default dark mode optimized for aviation aesthetic
  • Animations: Custom animations via tailwindcss-animate and tw-animate-css
  • Responsive: Mobile-first responsive design

Build docs developers (and LLMs) love