Update stuff & add admin link in nav for admins
This commit is contained in:
@@ -4,7 +4,7 @@ import type { Metadata, Viewport } from 'next';
|
|||||||
import NextError from 'next/error';
|
import NextError from 'next/error';
|
||||||
import { Geist, Geist_Mono } from 'next/font/google';
|
import { Geist, Geist_Mono } from 'next/font/google';
|
||||||
|
|
||||||
import '@/app/styles.css';
|
import '@/app/(frontend)/styles.css';
|
||||||
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import Footer from '@/components/layout/footer';
|
import Footer from '@/components/layout/footer';
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import type { Metadata, Viewport } from 'next';
|
import type { Metadata, Viewport } from 'next';
|
||||||
import { Geist, Geist_Mono } from 'next/font/google';
|
import { Geist, Geist_Mono } from 'next/font/google';
|
||||||
import { env } from '@/env';
|
import { env } from '@/env';
|
||||||
|
|
||||||
import '@/app/(frontend)/styles.css';
|
import '@/app/(frontend)/styles.css';
|
||||||
|
|
||||||
import Footer from '@/components/layout/footer';
|
import Footer from '@/components/layout/footer';
|
||||||
import Header from '@/components/layout/header';
|
import Header from '@/components/layout/header';
|
||||||
import { ConvexClientProvider } from '@/components/providers';
|
import { ConvexClientProvider } from '@/components/providers';
|
||||||
import { generateMetadata } from '@/lib/metadata';
|
import { generateMetadata } from '@/lib/metadata';
|
||||||
import { ConvexAuthNextjsServerProvider } from '@convex-dev/auth/nextjs/server';
|
import { ConvexAuthNextjsServerProvider } from '@convex-dev/auth/nextjs/server';
|
||||||
import PlausibleProvider from 'next-plausible';
|
import PlausibleProvider from 'next-plausible';
|
||||||
|
|
||||||
import { ThemeProvider, Toaster } from '@gib/ui';
|
import { ThemeProvider, Toaster } from '@gib/ui';
|
||||||
|
import { preloadQuery } from 'convex/nextjs';
|
||||||
|
import { api } from '@gib/backend/convex/_generated/api.js';
|
||||||
|
|
||||||
|
|
||||||
export const metadata: Metadata = generateMetadata();
|
export const metadata: Metadata = generateMetadata();
|
||||||
|
|
||||||
@@ -31,11 +31,12 @@ const geistMono = Geist_Mono({
|
|||||||
variable: '--font-geist-mono',
|
variable: '--font-geist-mono',
|
||||||
});
|
});
|
||||||
|
|
||||||
const RootLayout = ({
|
const RootLayout = async ({
|
||||||
children,
|
children,
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) => {
|
}>) => {
|
||||||
|
const preloadedUser = await preloadQuery(api.auth.getUser, {});
|
||||||
return (
|
return (
|
||||||
<ConvexAuthNextjsServerProvider>
|
<ConvexAuthNextjsServerProvider>
|
||||||
<PlausibleProvider
|
<PlausibleProvider
|
||||||
@@ -54,7 +55,9 @@ const RootLayout = ({
|
|||||||
>
|
>
|
||||||
<ConvexClientProvider>
|
<ConvexClientProvider>
|
||||||
<div className='flex min-h-screen flex-col'>
|
<div className='flex min-h-screen flex-col'>
|
||||||
<Header />
|
<Header
|
||||||
|
preloadedUser={preloadedUser}
|
||||||
|
/>
|
||||||
{children}
|
{children}
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export const defaultLandingPageContent: LandingPageContent = {
|
|||||||
badgeEmoji: '🚀',
|
badgeEmoji: '🚀',
|
||||||
badgeText: 'Production-ready monorepo template',
|
badgeText: 'Production-ready monorepo template',
|
||||||
headingPrefix: 'Build Full-Stack Apps with',
|
headingPrefix: 'Build Full-Stack Apps with',
|
||||||
headingHighlight: 'convex monorepo',
|
headingHighlight: 'convex-monorepo',
|
||||||
description:
|
description:
|
||||||
'A Turborepo starter with Next.js, Expo, and self-hosted Convex. Ship web and mobile apps faster with shared code, type-safe backend, and complete control over your infrastructure.',
|
'A Turborepo starter with Next.js, Expo, and self-hosted Convex. Ship web and mobile apps faster with shared code, type-safe backend, and complete control over your infrastructure.',
|
||||||
primaryCta: {
|
primaryCta: {
|
||||||
|
|||||||
@@ -1,17 +1,26 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
import type { ComponentProps } from 'react';
|
import type { ComponentProps } from 'react';
|
||||||
|
import { type Preloaded, usePreloadedQuery } from 'convex/react';
|
||||||
import { Kanit } from 'next/font/google';
|
import { Kanit } from 'next/font/google';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Coffee, Server, Wrench } from 'lucide-react';
|
import { Coffee, Server, User, Wrench } from 'lucide-react';
|
||||||
|
|
||||||
import { Controls } from './controls';
|
import { Controls } from './controls';
|
||||||
|
import { api } from '@gib/backend/convex/_generated/api.js';
|
||||||
|
|
||||||
|
type HeaderProps = {
|
||||||
|
preloadedUser: Preloaded<typeof api.auth.getUser>;
|
||||||
|
headerProps?: ComponentProps<'header'>;
|
||||||
|
};
|
||||||
|
|
||||||
const kanitSans = Kanit({
|
const kanitSans = Kanit({
|
||||||
subsets: ['latin'],
|
subsets: ['latin'],
|
||||||
weight: ['400', '500', '600', '700'],
|
weight: ['400', '500', '600', '700'],
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function Header(headerProps: ComponentProps<'header'>) {
|
export default function Header({preloadedUser, headerProps}: HeaderProps) {
|
||||||
|
const user = usePreloadedQuery(preloadedUser);
|
||||||
return (
|
return (
|
||||||
<header
|
<header
|
||||||
className='border-border/40 bg-background/95 supports-backdrop-filter:bg-background/60 sticky top-0 z-50 w-full border-b backdrop-blur'
|
className='border-border/40 bg-background/95 supports-backdrop-filter:bg-background/60 sticky top-0 z-50 w-full border-b backdrop-blur'
|
||||||
@@ -31,14 +40,14 @@ export default function Header(headerProps: ComponentProps<'header'>) {
|
|||||||
className='w-10 lg:w-15 invert dark:invert-0'
|
className='w-10 lg:w-15 invert dark:invert-0'
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className={`font-extrabold hidden sm:inline sm:text-xl sm:mb-1 lg:mb-3 lg:text-5xl ${kanitSans.className}`}
|
className={`font-extrabold hidden md:inline sm:text-lg sm:mb-1 lg:mb-3 lg:text-4xl xl:text-5xl ${kanitSans.className}`}
|
||||||
>
|
>
|
||||||
convex monorepo
|
convex-monorepo
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* Navigation */}
|
{/* Navigation */}
|
||||||
<nav className='hidden items-center gap-6 text-xs lg:text-base font-medium sm:flex'>
|
<nav className='hidden items-center gap-4 md:gap-6 text-xs lg:text-base font-medium sm:flex'>
|
||||||
<Link
|
<Link
|
||||||
href='/#features'
|
href='/#features'
|
||||||
className='text-foreground/60 hover:text-foreground flex items-center gap-2 transition-colors'
|
className='text-foreground/60 hover:text-foreground flex items-center gap-2 transition-colors'
|
||||||
@@ -62,6 +71,18 @@ export default function Header(headerProps: ComponentProps<'header'>) {
|
|||||||
<Coffee width={20} height={20} />
|
<Coffee width={20} height={20} />
|
||||||
Repository
|
Repository
|
||||||
</Link>
|
</Link>
|
||||||
|
{user?.isAdmin && (
|
||||||
|
<Link
|
||||||
|
href='/admin'
|
||||||
|
target='_blank'
|
||||||
|
rel='noopener noreferrer'
|
||||||
|
className='text-foreground/60 hover:text-foreground
|
||||||
|
flex items-center gap-2 transition-colors'
|
||||||
|
>
|
||||||
|
<User width={18} height={18} />
|
||||||
|
Admin
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{/* Controls (Theme + Auth) */}
|
{/* Controls (Theme + Auth) */}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ const applicationTables = {
|
|||||||
phoneVerificationTime: v.optional(v.number()),
|
phoneVerificationTime: v.optional(v.number()),
|
||||||
isAnonymous: v.optional(v.boolean()),
|
isAnonymous: v.optional(v.boolean()),
|
||||||
/* Fields below here are custom & not defined in authTables */
|
/* Fields below here are custom & not defined in authTables */
|
||||||
|
isAdmin: v.optional(v.boolean()),
|
||||||
themePreference: v.optional(
|
themePreference: v.optional(
|
||||||
v.union(v.literal('light'), v.literal('dark'), v.literal('system')),
|
v.union(v.literal('light'), v.literal('dark'), v.literal('system')),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user