Files
textbee/web/app/layout.tsx
isra el 4ce6d00456 fix: resolve hydration, script-tag and invalid HTML nesting console errors
Three distinct issues surfaced by React 19 / Next 16:

1. next-themes script warning + hydration mismatch. ThemeProvider lived in
   the nested (app) layout, so its pre-paint <script> was re-rendered during
   client navigation ("Scripts inside React components are never executed
   when rendering on the client") and shifted the SSR/client tree. Moved it
   to the root layout via app/theme-provider.tsx, its canonical placement.

2. Invalid <p> nesting. Radix's DialogDescription and shadcn's
   CardDescription render a <p>, but call sites pass block content, giving
   "<p> cannot be a descendant of <p>" / "<div> cannot be a descendant of
   <p>". Fixed at the primitives: both now render a <div> (DialogDescription
   uses asChild so aria-describedby wiring is preserved), which fixes every
   call site at once. Also dropped a redundant wrapper in generate-api-key.

3. Nested <main>: the root layout wrapped children in <main> while the (app)
   layout renders its own. Removed the outer one.

Verified by driving the app with Playwright and capturing console output
across navigation and with the API key dialog open: zero hydration, script
tag, or nesting messages (previously several). Dark mode still applies.
Build, lint (0 errors), 28 unit tests, and 16 e2e green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 19:09:43 +03:00

37 lines
982 B
TypeScript

import { PropsWithChildren } from 'react'
import '@/styles/main.css'
import { Metadata } from 'next'
import { Inter } from 'next/font/google'
import ThemeProvider from './theme-provider'
const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
display: 'swap',
})
export const metadata: Metadata = {
title: 'textbee.dev - sms gateway - dashboard',
metadataBase: new URL('https://textbee.dev'),
}
export default async function RootLayout({ children }: PropsWithChildren) {
return (
<html lang='en' suppressHydrationWarning className={inter.variable}>
{/* No <main> here: the (app) layout renders its own, and nesting
<main> inside <main> is invalid HTML. */}
<body className='font-sans antialiased'>
<ThemeProvider
attribute='class'
defaultTheme='system'
enableSystem
disableTransitionOnChange
>
{children}
</ThemeProvider>
</body>
</html>
)
}