Update admin and marketing layouts, add new admin components

Refined both admin and marketing layouts for a clearer design. Newly added components for the admin page include admin-account-page, admin-members-table and admin-memberships-table. Also included in this update are route renaming, minor text edits and corrections in the code.
This commit is contained in:
giancarlo
2024-04-08 20:00:52 +08:00
parent 767e2f21b5
commit 13308194ec
18 changed files with 426 additions and 103 deletions

View File

@@ -46,7 +46,9 @@ export function SiteNavigation() {
<div className={'hidden items-center lg:flex'}>
<NavigationMenu>
<NavigationMenuList
className={'space-x-1.5 rounded-full border px-1 py-2'}
className={
'space-x-1.5 rounded-full px-1 py-2 shadow-sm dark:shadow-primary/20'
}
>
{NavItems}
</NavigationMenuList>

View File

@@ -1,4 +1,3 @@
import { Heading } from '@kit/ui/heading';
import { cn } from '@kit/ui/utils';
export function SitePageHeader(props: {
@@ -8,9 +7,11 @@ export function SitePageHeader(props: {
}) {
return (
<div
className={cn('flex flex-col items-center space-y-2.5', props.className)}
className={cn('flex flex-col items-center space-y-4', props.className)}
>
<Heading level={1}>{props.title}</Heading>
<h1 className={'text-center text-3xl font-semibold xl:text-4xl'}>
{props.title}
</h1>
<h2 className={'text-center text-xl text-muted-foreground xl:text-2xl'}>
<span className={'font-normal'}>{props.subtitle}</span>

View File

@@ -25,7 +25,7 @@ async function BlogPage() {
return (
<div className={'container mx-auto'}>
<div className={'flex flex-col space-y-16'}>
<div className={'flex flex-col space-y-12 xl:space-y-24'}>
<SitePageHeader
title={t('marketing:blog')}
subtitle={t('marketing:blogSubtitle')}

View File

@@ -26,18 +26,16 @@ async function DocsPage() {
const cards = docs.filter((item) => !item.parentId);
return (
<div className={'flex flex-1 flex-col'}>
<PageBody>
<div className={'flex flex-col items-center space-y-16'}>
<SitePageHeader
title={t('marketing:documentation')}
subtitle={t('marketing:documentationSubtitle')}
/>
<PageBody>
<div className={'flex flex-col items-center space-y-12 xl:space-y-24'}>
<SitePageHeader
title={t('marketing:documentation')}
subtitle={t('marketing:documentationSubtitle')}
/>
<DocsCards cards={cards} />
</div>
</PageBody>
</div>
<DocsCards cards={cards} />
</div>
</PageBody>
);
}

View File

@@ -68,7 +68,7 @@ async function FAQPage() {
/>
<div className={'container mx-auto'}>
<div className={'flex flex-col space-y-16'}>
<div className={'flex flex-col space-y-12 xl:space-y-24'}>
<SitePageHeader
title={t('marketing:faq')}
subtitle={t('marketing:faqSubtitle')}

View File

@@ -9,7 +9,7 @@ async function SiteLayout(props: React.PropsWithChildren) {
const user = await getUser();
return (
<div className={'flex flex-col space-y-8'}>
<div className={'flex flex-col space-y-6 xl:space-y-10 2xl:space-y-12'}>
<SiteHeader user={user} />
{props.children}

View File

@@ -13,57 +13,50 @@ import { withI18n } from '~/lib/i18n/with-i18n';
function Home() {
return (
<div className={'flex flex-col space-y-16'}>
<div className={'container mx-auto'}>
<div className={'flex flex-col space-y-24'}>
<div className={'container mx-auto flex flex-col space-y-24'}>
<div
className={
'mt-4 flex flex-col items-center md:flex-row xl:mt-12' +
'flex flex-col items-center md:flex-row' +
' mx-auto flex-1 justify-center animate-in fade-in ' +
' duration-1000 slide-in-from-top-12'
}
>
<div className={'flex w-full flex-1 flex-col items-center space-y-8'}>
<div
className={'flex w-full flex-1 flex-col items-center space-y-12'}
>
<Pill>
<span>The leading SaaS Starter Kit for ambitious developers</span>
</Pill>
<HeroTitle>
<span>The SaaS Starter Kit</span>
<div className={'flex flex-col items-center space-y-8'}>
<HeroTitle>
<span>The SaaS Starter Kit</span>
<span>straight from the future</span>
</HeroTitle>
<span>without compromises</span>
</HeroTitle>
<div>
<Heading
level={3}
className={'text-center font-medium text-muted-foreground'}
>
<span>Here you can write a short description of your SaaS</span>
</Heading>
<div>
<Heading
level={3}
className={'text-center font-medium text-muted-foreground'}
>
<span>Build and launch a SaaS in days, not months</span>
</Heading>
<Heading
level={3}
className={'text-center font-medium text-muted-foreground'}
>
<span>
This subheading is usually laid out on multiple lines
</span>
</Heading>
<Heading
level={3}
className={'text-center font-medium text-muted-foreground'}
>
<span>Impress your customers, straight to the point.</span>
</Heading>
<Heading
level={3}
className={'text-center font-medium text-muted-foreground'}
>
<span>
<span>Focus on your business, not on the tech</span>
</span>
</Heading>
</div>
</div>
<div className={'flex flex-col items-center space-y-4'}>
<div>
<MainCallToActionButton />
<span className={'text-xs text-muted-foreground'}>
Free plan. No credit card required.
</span>
</div>
</div>
</div>
@@ -222,8 +215,7 @@ function HeroTitle({ children }: React.PropsWithChildren) {
return (
<h1
className={
'text-center font-sans text-4xl md:text-5xl' +
' flex flex-col font-bold xl:text-7xl 2xl:text-[5rem]'
'flex flex-col text-center text-5xl font-bold xl:text-6xl 2xl:text-7xl'
}
>
{children}
@@ -233,7 +225,7 @@ function HeroTitle({ children }: React.PropsWithChildren) {
function Pill(props: React.PropsWithChildren) {
return (
<h2 className={'rounded-full px-4 py-2 text-sm shadow'}>
<h2 className={'rounded-full border-primary px-4 py-2 text-sm shadow'}>
{props.children}
</h2>
);
@@ -266,14 +258,14 @@ function RightFeatureContainer(props: React.PropsWithChildren) {
function MainCallToActionButton() {
return (
<Button className={'rounded-full'}>
<Button className={'h-12 rounded-full px-5 text-[1em]'}>
<Link href={'/auth/sign-up'}>
<span className={'flex items-center space-x-0.5'}>
<span>Get Started</span>
<ChevronRight
className={
'h-4 animate-in fade-in slide-in-from-left-8' +
'h-5 animate-in fade-in slide-in-from-left-8' +
' delay-1000 duration-1000 zoom-in fill-mode-both'
}
/>

View File

@@ -18,7 +18,7 @@ async function PricingPage() {
const { t } = await createI18nServerInstance();
return (
<div className={'container mx-auto mt-8 flex flex-col space-y-12'}>
<div className={'container mx-auto mt-8 flex flex-col space-y-24'}>
<SitePageHeader
title={t('marketing:pricing')}
subtitle={t('marketing:pricingSubtitle')}

View File

@@ -1,7 +0,0 @@
import { AdminGuard } from '@kit/admin/components/admin-guard';
function AccountPage() {
return <div></div>;
}
export default AdminGuard(AccountPage);

View File

@@ -0,0 +1,45 @@
import { cache } from 'react';
import { AdminAccountPage } from '@kit/admin/components/admin-account-page';
import { AdminGuard } from '@kit/admin/components/admin-guard';
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
interface Params {
params: {
id: string;
};
}
export const generateMetadata = async ({ params }: Params) => {
const account = await loadAccount(params.id);
return {
title: `Admin | ${account.name}`,
};
};
async function AccountPage({ params }: Params) {
const account = await loadAccount(params.id);
return <AdminAccountPage account={account} />;
}
export default AdminGuard(AccountPage);
const loadAccount = cache(async (id: string) => {
const client = getSupabaseServerComponentClient({
admin: true,
});
const { data, error } = await client
.from('accounts')
.select('*, memberships: accounts_memberships (*)')
.eq('id', id)
.single();
if (error) {
throw error;
}
return data;
});

View File

@@ -1,6 +1,6 @@
import { ServerDataLoader } from '@makerkit/data-loader-supabase-nextjs';
import { AccountsTable } from '@kit/admin/components/accounts-table';
import { AdminAccountsTable } from '@kit/admin/components/admin-accounts-table';
import { AdminGuard } from '@kit/admin/components/admin-guard';
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
import { PageBody, PageHeader } from '@kit/ui/page';
@@ -8,8 +8,13 @@ import { PageBody, PageHeader } from '@kit/ui/page';
interface SearchParams {
page?: string;
account_type?: 'all' | 'team' | 'personal';
query?: string;
}
export const metadata = {
title: `Accounts`,
};
function AccountsPage({ searchParams }: { searchParams: SearchParams }) {
const client = getSupabaseServerComponentClient({
admin: true,
@@ -34,7 +39,7 @@ function AccountsPage({ searchParams }: { searchParams: SearchParams }) {
>
{({ data, page, pageSize, pageCount }) => {
return (
<AccountsTable
<AdminAccountsTable
page={page}
pageSize={pageSize}
pageCount={pageCount}
@@ -54,7 +59,8 @@ function AccountsPage({ searchParams }: { searchParams: SearchParams }) {
function getFilters(params: SearchParams) {
const filters: {
[key: string]: {
eq: boolean;
eq?: boolean | string;
like?: string;
};
} = {};
@@ -64,6 +70,12 @@ function getFilters(params: SearchParams) {
};
}
if (params.query) {
filters.name = {
like: `%${params.query}%`,
};
}
return filters;
}

View File

@@ -2,6 +2,10 @@ import { Page } from '@kit/ui/page';
import { AdminSidebar } from '~/admin/_components/admin-sidebar';
export const metadata = {
title: `Admin`,
};
export default function AdminLayout(props: React.PropsWithChildren) {
return <Page sidebar={<AdminSidebar />}>{props.children}</Page>;
}