Axe landing, fix dashboard routes

This commit is contained in:
cte 2025-05-15 14:51:33 -07:00
parent 3b0eb65457
commit 7268e657c6
24 changed files with 41 additions and 239 deletions

View file

Before

Width:  |  Height:  |  Size: 226 KiB

After

Width:  |  Height:  |  Size: 226 KiB

View file

Before

Width:  |  Height:  |  Size: 226 KiB

After

Width:  |  Height:  |  Size: 226 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

View file

@ -3,7 +3,7 @@
import { useTranslations } from 'next-intl';
import { TitleBar } from '@/components/dashboard/TitleBar';
import { AnalyticsPage } from '@/features/analytics/AnalyticsPage';
import { AnalyticsPage } from '@/components/analytics/AnalyticsPage';
const AnalyticsPageContainer = () => {
const t = useTranslations('Analytics');

View file

@ -5,10 +5,10 @@ import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Drawer } from '@/components/ui/drawer';
import { TitleBar } from '@/components/dashboard/TitleBar';
import { AuditLogDetails } from '@/features/dashboard/AuditLogDetails';
import { AuditLogEntry } from '@/features/dashboard/AuditLogEntry';
import type { AuditLog } from '@/features/dashboard/mockAuditLogs';
import { getFilteredLogs } from '@/features/dashboard/mockAuditLogs';
import { AuditLogDetails } from '@/components/dashboard/AuditLogDetails';
import { AuditLogEntry } from '@/components/dashboard/AuditLogEntry';
import type { AuditLog } from '@/components/dashboard/mockAuditLogs';
import { getFilteredLogs } from '@/components/dashboard/mockAuditLogs';
type TimePeriod = '7' | '30' | '90';

View file

@ -5,8 +5,8 @@ import { useTheme } from 'next-themes';
import { dark } from '@clerk/themes';
import { OrganizationProfile } from '@clerk/nextjs';
import DefaultParametersPage from '@/features/dashboard/DefaultParametersPage';
import ProviderWhitelistPage from '@/features/dashboard/ProviderWhitelistPage';
import DefaultParametersPage from '@/components/dashboard/DefaultParametersPage';
import ProviderWhitelistPage from '@/components/dashboard/ProviderWhitelistPage';
export const OrgProfile = () => {
const t = useTranslations('OrganizationProfile');

View file

@ -1,8 +1,8 @@
import { useTranslations } from 'next-intl';
import { TitleBar } from '@/components/dashboard/TitleBar';
import { AuditLogCard } from '@/features/dashboard/AuditLogCard';
import { UsageAnalyticsCard } from '@/features/dashboard/UsageAnalyticsCard';
import { AuditLogCard } from '@/components/dashboard/AuditLogCard';
import { UsageAnalyticsCard } from '@/components/dashboard/UsageAnalyticsCard';
export default function Page() {
const t = useTranslations('DashboardIndex');

View file

@ -2,7 +2,7 @@ import '@/styles/globals.css';
import type { Metadata } from 'next';
import { NextIntlClientProvider } from 'next-intl';
import { getLocale } from 'next-intl/server';
import { getLocale, getTranslations, setRequestLocale } from 'next-intl/server';
import { ClerkProvider } from '@clerk/nextjs';
import { getClerkLocale } from '@/lib/locale';
@ -11,24 +11,31 @@ import { ToastProvider, ToastViewport } from '@/components/ui/toast';
import { ToastProvider as ToastContextProvider } from '@/components/ui/toast-context';
import { Toaster } from '@/components/ui/toaster';
export const metadata: Metadata = {
icons: [
{ rel: 'apple-touch-icon', url: '/apple-touch-icon.png' },
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
url: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
url: '/favicon-16x16.png',
},
{ rel: 'icon', url: '/favicon.ico' },
],
};
export async function generateMetadata(): Promise<Metadata> {
const locale = await getLocale();
const t = await getTranslations({ locale, namespace: 'Index' });
return {
title: t('meta_title'),
description: t('meta_description'),
icons: [
{ rel: 'apple-touch-icon', url: '/apple-touch-icon.png' },
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
url: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
url: '/favicon-16x16.png',
},
{ rel: 'icon', url: '/favicon.ico' },
],
};
}
export default async function RootLayout({
children,
@ -36,6 +43,7 @@ export default async function RootLayout({
children: React.ReactNode;
}) {
const locale = await getLocale();
setRequestLocale(locale);
return (
<html lang={locale} suppressHydrationWarning>

View file

@ -1,31 +1,7 @@
import { redirect } from 'next/navigation';
import { auth as clerkAuth } from '@clerk/nextjs/server';
import { getLocale, getTranslations, setRequestLocale } from 'next-intl/server';
import { Navbar, Footer } from '@/components/layout';
import { Hero, Features } from '@/components/landing';
export async function generateMetadata() {
const locale = await getLocale();
const t = await getTranslations({ locale, namespace: 'Index' });
return { title: t('meta_title'), description: t('meta_description') };
}
export default async function Page() {
const { userId } = await clerkAuth();
if (userId) {
redirect('/dashboard');
}
setRequestLocale(await getLocale());
return (
<>
<Navbar />
<Hero />
<Features />
<Footer />
</>
);
redirect(userId ? '/dashboard' : '/sign-in');
}

View file

@ -1,148 +0,0 @@
import { useTranslations } from 'next-intl';
import { Section } from '@/components/layout';
export const Features = () => {
const t = useTranslations('Features');
return (
<Section className="bg-secondary">
<div className="mx-auto mb-12 max-w-screen-md text-center">
<div className="bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 bg-clip-text text-sm font-bold text-transparent">
{t('section_subtitle')}
</div>
<div className="mt-1 text-3xl font-bold">{t('section_title')}</div>
<div className="mt-2 text-lg text-muted-foreground">
{t('section_description')}
</div>
</div>
<div className="grid grid-cols-1 gap-x-3 gap-y-8 md:grid-cols-3">
<FeatureCard
icon={
<svg
className="stroke-primary-foreground stroke-2"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M0 0h24v24H0z" stroke="none" />
<path d="M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3M12 12l8-4.5M12 12v9M12 12L4 7.5" />
</svg>
}
title={t('feature1_title')}
>
{t('feature_description')}
</FeatureCard>
<FeatureCard
icon={
<svg
className="stroke-primary-foreground stroke-2"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M0 0h24v24H0z" stroke="none" />
<path d="M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3M12 12l8-4.5M12 12v9M12 12L4 7.5" />
</svg>
}
title={t('feature2_title')}
>
{t('feature_description')}
</FeatureCard>
<FeatureCard
icon={
<svg
className="stroke-primary-foreground stroke-2"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M0 0h24v24H0z" stroke="none" />
<path d="M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3M12 12l8-4.5M12 12v9M12 12L4 7.5" />
</svg>
}
title={t('feature3_title')}
>
{t('feature_description')}
</FeatureCard>
<FeatureCard
icon={
<svg
className="stroke-primary-foreground stroke-2"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M0 0h24v24H0z" stroke="none" />
<path d="M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3M12 12l8-4.5M12 12v9M12 12L4 7.5" />
</svg>
}
title={t('feature4_title')}
>
{t('feature_description')}
</FeatureCard>
<FeatureCard
icon={
<svg
className="stroke-primary-foreground stroke-2"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M0 0h24v24H0z" stroke="none" />
<path d="M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3M12 12l8-4.5M12 12v9M12 12L4 7.5" />
</svg>
}
title={t('feature5_title')}
>
{t('feature_description')}
</FeatureCard>
<FeatureCard
icon={
<svg
className="stroke-primary-foreground stroke-2"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M0 0h24v24H0z" stroke="none" />
<path d="M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3M12 12l8-4.5M12 12v9M12 12L4 7.5" />
</svg>
}
title={t('feature6_title')}
>
{t('feature_description')}
</FeatureCard>
</div>
</Section>
);
};
type FeatureCardProps = {
icon: React.ReactNode;
title: string;
children: React.ReactNode;
};
const FeatureCard = ({ icon, title, children }: FeatureCardProps) => (
<div className="rounded-xl border border-border bg-card p-5">
<div className="size-12 rounded-lg bg-gradient-to-br from-indigo-400 via-purple-400 to-pink-400 p-2 [&_svg]:stroke-white [&_svg]:stroke-2">
{icon}
</div>
<div className="mt-2 text-lg font-bold">{title}</div>
<div className="my-3 w-8 border-t border-purple-400" />
<div className="mt-2 text-muted-foreground">{children}</div>
</div>
);

View file

@ -1,24 +0,0 @@
import { useTranslations } from 'next-intl';
import { Section } from '@/components/layout/Section';
export const Hero = () => {
const t = useTranslations('Hero');
return (
<Section className="py-36">
<div className="mt-3 text-center text-5xl font-bold tracking-tight">
{t.rich('title', {
important: (chunks) => (
<span className="bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 bg-clip-text text-transparent">
{chunks}
</span>
),
})}
</div>
<div className="mx-auto mt-5 max-w-screen-md text-center text-xl text-muted-foreground">
{t('description')}
</div>
</Section>
);
};

View file

@ -1,2 +0,0 @@
export { Hero } from './Hero';
export { Features } from './Features';

View file

@ -2,7 +2,6 @@ import Link from 'next/link';
import { useTranslations } from 'next-intl';
import { Section } from '@/components/layout';
import { APP_NAME } from '@/lib/constants';
export const Footer = () => {
const t = useTranslations('Footer');
@ -34,9 +33,7 @@ export const Footer = () => {
</li>
</ul>
<div className="mt-6 flex w-full items-center justify-between gap-y-2 border-t pt-3 text-sm text-muted-foreground max-md:flex-col">
<div>
© Copyright {new Date().getFullYear()} {APP_NAME}.
</div>
<div>© Copyright {new Date().getFullYear()} Roo Code.</div>
<ul className="flex gap-x-4 font-medium [&_a:hover]:opacity-100 [&_a]:opacity-60">
<li>
<Link href="/sign-up">{t('terms_of_service')}</Link>

View file

@ -1,11 +1,9 @@
import { APP_NAME } from '@/lib/constants';
import Image from 'next/image';
export const Logo = (props: { isTextHidden?: boolean }) => (
export const Logo = () => (
<div className="flex items-center text-xl font-semibold">
<Image
src="/Roo-Code-Logo-Horiz-blk.svg"
src="/logo.svg"
alt="Roo Code Logo"
width={120}
height={26}
@ -13,13 +11,12 @@ export const Logo = (props: { isTextHidden?: boolean }) => (
style={{ height: 'auto' }}
/>
<Image
src="/Roo-Code-Logo-Horiz-white.svg"
src="/logo-dark.svg"
alt="Roo Code Logo"
width={120}
height={26}
className="mr-2 hidden dark:block"
style={{ height: 'auto' }}
/>
{!props.isTextHidden && APP_NAME}
</div>
);

View file

@ -1 +0,0 @@
export const APP_NAME = 'Roo Code Cloud';