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
73 changes: 73 additions & 0 deletions apps/web/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ import {
CheckCircle2,
Search,
Cloud,
Users,
Building2,
Check,
} from "lucide-react";
import { sidebarData } from "@/components/sidebar/data/sidebar-data";
import { homepageFaqItems } from "@/lib/seo/structured-data";
Expand Down Expand Up @@ -701,6 +704,76 @@ export default function Page() {
</div>
</Link>
</motion.div>

{/* T4 — Teams & Workspaces (full-width, NEW) */}
<motion.div
variants={fadeUp}
transition={{ duration: 0.55, delay: 0.25 }}
className="md:col-span-3"
>
<Link
href="/login"
className="group relative flex flex-col gap-6 overflow-hidden rounded-2xl glass-overlay p-6 transition-all duration-300 hover:scale-[1.01] hover:shadow-2xl dark:hover:shadow-black/40 md:flex-row md:items-center md:p-8"
>
<div className="absolute inset-0 opacity-0 group-hover:opacity-[0.06] transition-opacity duration-500 bg-gradient-to-br from-sky-500 to-indigo-400" />

<div className="relative z-10 flex-1">
<div className="mb-4 flex items-center gap-2">
<div className="w-9 h-9 rounded-lg bg-gradient-to-br from-sky-500 to-indigo-400 p-px shadow-md">
<div className="flex h-full w-full items-center justify-center rounded-[7px] bg-card dark:bg-[hsl(var(--surface-2))]">
<Users className="h-4 w-4 text-foreground" />
</div>
</div>
<span className="text-[11px] font-mono uppercase tracking-wider text-muted-foreground">
Built for Teams
</span>
<span className="mdt-pill text-[10px]">NEW</span>
</div>
<h3 className="relative z-10 mb-3 text-2xl font-semibold">
One platform. Your whole team.
</h3>
<p className="max-w-lg text-sm leading-relaxed text-muted-foreground md:text-base">
Create organizations and shared workspaces, invite teammates, and control
exactly who can use what — owners, admins, developers, and viewers each get
the right level of access. Switch between personal and team context in one
click; every tool follows.
</p>
<div className="mt-4 inline-flex items-center gap-1.5 text-sm font-medium text-foreground/80 transition-colors group-hover:text-foreground">
<span>Set up your team workspace</span>
<ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-0.5" />
</div>
</div>

{/* Workspace + roles preview */}
<div className="relative z-10 w-full shrink-0 md:w-[340px]">
<div className="overflow-hidden rounded-xl border border-border/40 bg-background font-mono text-xs dark:border-white/5">
<div className="flex items-center gap-2 border-b border-border/40 bg-muted/40 px-3 py-2">
<Building2 className="h-3.5 w-3.5 text-muted-foreground" />
<span className="font-semibold">Acme Engineering</span>
<span className="ml-auto rounded bg-sky-500/15 px-1.5 py-0.5 text-[10px] font-semibold text-sky-600 dark:text-sky-400">
Team workspace
</span>
</div>
<div className="divide-y divide-border/30 dark:divide-white/5">
{[
{ name: "ada@acme.dev", role: "Owner" },
{ name: "grace@acme.dev", role: "Admin" },
{ name: "linus@acme.dev", role: "Developer" },
{ name: "margaret@acme.dev", role: "Viewer" },
].map((m) => (
<div key={m.name} className="flex items-center gap-2 px-3 py-2">
<Check className="h-3 w-3 shrink-0 text-emerald-500" />
<span className="truncate text-muted-foreground">{m.name}</span>
<span className="ml-auto rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium text-foreground/70">
{m.role}
</span>
</div>
))}
</div>
</div>
</div>
</Link>
</motion.div>
</div>
</Section>
</div>
Expand Down
63 changes: 63 additions & 0 deletions apps/web/src/components/announcement-banner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"use client";

import { useEffect, useState } from "react";
import Link from "next/link";
import { ArrowRight, X } from "lucide-react";

const DISMISS_KEY = "mdt-launch-offer-dismissed";

/**
* Slim launch-offer strip above the marketing header. Dismissible per browser
* (localStorage). Rendered on marketing pages only via <Header/>.
*/
export function AnnouncementBanner() {
// Start hidden to avoid a flash for users who already dismissed it.
const [visible, setVisible] = useState(false);

useEffect(() => {
try {
if (!localStorage.getItem(DISMISS_KEY)) setVisible(true);
} catch {
setVisible(true);
}
}, []);

const dismiss = () => {
setVisible(false);
try {
localStorage.setItem(DISMISS_KEY, "1");
} catch {
/* ignore */
}
};

if (!visible) return null;

return (
<div className="relative z-[60] bg-[linear-gradient(100deg,#5b63f0,#9a5cf2_52%,#4fd0e6)] text-white">
<div className="container mx-auto flex items-center justify-center gap-2 px-10 py-2 text-center text-[13px] font-medium sm:gap-3">
<span className="hidden rounded-full bg-white/15 px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wider ring-1 ring-inset ring-white/25 sm:inline-flex">
Launch offer
</span>
<p className="truncate">
First <span className="font-bold">250 accounts</span> get every Pro &amp; Team feature,
free. No card needed.
</p>
<Link
href="/login"
className="hidden shrink-0 items-center gap-1 font-semibold underline decoration-white/50 underline-offset-2 transition-opacity hover:opacity-90 sm:inline-flex"
>
Claim yours <ArrowRight className="h-3.5 w-3.5" />
</Link>
<button
type="button"
onClick={dismiss}
aria-label="Dismiss announcement"
className="absolute right-3 top-1/2 -translate-y-1/2 rounded-md p-1 text-white/80 transition-colors hover:bg-white/15 hover:text-white"
>
<X className="h-4 w-4" />
</button>
</div>
</div>
);
}
2 changes: 2 additions & 0 deletions apps/web/src/components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Github, Menu, X, ArrowRight } from "lucide-react";
import { Button } from "@/components/ui/button";
import { ModeToggle } from "./modeToggle";
import { Logo } from "./logo";
import { AnnouncementBanner } from "./announcement-banner";
import { Magnetic } from "@/components/mdt-magnetic";
import { motion, AnimatePresence } from "framer-motion";
import { cn } from "@/lib/utils";
Expand Down Expand Up @@ -77,6 +78,7 @@ export function Header({ showThemeToggle = true }: HeaderProps) {
: "border-b border-transparent bg-transparent"
)}
>
<AnnouncementBanner />
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl">
<div className="flex h-16 items-center justify-between">
{/* Logo */}
Expand Down
25 changes: 23 additions & 2 deletions apps/web/src/components/pricing-tiers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ export function PricingTiers() {
<p className="max-w-2xl text-muted-foreground">
Self-host for free, forever. Upgrade to cloud when you want the convenience.
</p>
<p className="mdt-pill inline-flex items-center gap-1.5 text-sm">
<span aria-hidden>🎉</span> Launch offer — every plan is free for a limited time
</p>

<div
role="radiogroup"
Expand Down Expand Up @@ -161,8 +164,26 @@ export function PricingTiers() {
</p>

<div className="mt-5 mb-6">
<div className="text-4xl font-bold tracking-tight">{big}</div>
<div className="mt-1 text-xs text-muted-foreground">{sub}</div>
{tier.monthly !== null && tier.monthly > 0 ? (
// Launch offer: paid tiers are free for a limited time — show
// the real price struck through so the value reads instantly.
<>
<div className="flex items-baseline gap-2.5">
<span className="text-2xl font-semibold text-muted-foreground/70 line-through decoration-[1.5px]">
{big}
</span>
<span className="mdt-grad-text text-4xl font-bold tracking-tight">Free</span>
</div>
<div className="mt-1 text-xs text-muted-foreground">
for a limited time · normally {sub}
</div>
</>
) : (
<>
<div className="text-4xl font-bold tracking-tight">{big}</div>
<div className="mt-1 text-xs text-muted-foreground">{sub}</div>
</>
)}
</div>

<Link
Expand Down
14 changes: 13 additions & 1 deletion apps/web/src/lib/seo/platform-pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,14 @@ export const platformSeoPages: PlatformSeoPage[] = [
slug: 'features',
title: 'Developer Toolkit Features',
description:
'Explore MyDevTools features: unified dashboard, command palette, favorites, browser-based tools, secure sync, self-hosting, and managed cloud hosting.',
'Explore MyDevTools features: unified dashboard, command palette, team workspaces with role-based access, browser-based tools, secure sync, self-hosting, and managed cloud hosting.',
keywords: [
'developer toolkit features',
'browser developer tools features',
'online developer dashboard',
'developer tools command palette',
'team workspaces developer tools',
'role based access developer tools',
],
eyebrow: 'Features',
heading: 'Features built for fast, private developer workflows',
Expand All @@ -95,6 +97,16 @@ export const platformSeoPages: PlatformSeoPage[] = [
'Use public tool pages for discovery, then open the full app when ready.',
],
},
{
title: 'Team workspaces with roles',
body:
'Create organizations and shared workspaces, invite teammates, and give each person the right level of access — no more pasting secrets over chat.',
bullets: [
'Organizations group your workspaces; switch between personal and team context in one click.',
'Four roles — owner, admin, developer, viewer — control who can manage members and which tools each role can use.',
'Bookmarks, notes, snippets, and connections are scoped per workspace, so team data stays with the team.',
],
},
{
title: 'Browser-based utilities',
body:
Expand Down