Files
soroban-abacus-flashcards/apps/web/src/app/layout.tsx
Thomas Hallock 8a9afa86bc fix(practice): disable auto-scroll and add modern PWA meta tag
- Add scroll: false to all router.push() calls in practice pages
- Add scroll={false} to Link component in not-found page
- Fixes Next.js warning about auto-scroll with fixed position header
- Add mobile-web-app-capable meta tag alongside deprecated apple-mobile-web-app-capable

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 11:25:53 -06:00

101 lines
2.5 KiB
TypeScript

import type { Metadata, Viewport } from 'next'
import './globals.css'
import { ClientProviders } from '@/components/ClientProviders'
import { getRequestLocale } from '@/i18n/request'
import { getMessages } from '@/i18n/messages'
export const metadata: Metadata = {
metadataBase: new URL('https://abaci.one'),
title: {
default: 'Abaci.One - Interactive Soroban Learning',
template: '%s | Abaci.One',
},
description:
'Master the Japanese abacus (soroban) with interactive tutorials, arcade-style math games, and beautiful flashcards. Learn arithmetic through play with Rithmomachia, Complement Race, and more.',
keywords: [
'soroban',
'abacus',
'Japanese abacus',
'mental arithmetic',
'math games',
'abacus tutorial',
'soroban learning',
'arithmetic practice',
'educational games',
'Rithmomachia',
'number bonds',
'complement training',
],
authors: [{ name: 'Abaci.One' }],
creator: 'Abaci.One',
publisher: 'Abaci.One',
// Open Graph
openGraph: {
type: 'website',
locale: 'en_US',
alternateLocale: ['de_DE', 'ja_JP', 'hi_IN', 'es_ES', 'la'],
url: 'https://abaci.one',
title: 'Abaci.One - Interactive Soroban Learning',
description: 'Master the Japanese abacus through interactive games, tutorials, and practice',
siteName: 'Abaci.One',
},
// Twitter
twitter: {
card: 'summary_large_image',
title: 'Abaci.One - Interactive Soroban Learning',
description: 'Master the Japanese abacus through games and practice',
},
// Icons
icons: {
icon: [
{ url: '/favicon.ico', sizes: 'any' },
{ url: '/icon', type: 'image/svg+xml' },
],
apple: '/apple-touch-icon.png',
},
// Manifest
manifest: '/manifest.json',
// App-specific
applicationName: 'Abaci.One',
appleWebApp: {
capable: true,
statusBarStyle: 'default',
title: 'Abaci.One',
},
// Modern web app capable meta tag (non-Apple browsers)
other: {
'mobile-web-app-capable': 'yes',
},
// Category
category: 'education',
}
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
maximumScale: 1,
userScalable: false,
}
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const locale = await getRequestLocale()
const messages = await getMessages(locale)
return (
<html lang={locale}>
<body>
<ClientProviders initialLocale={locale} initialMessages={messages}>
{children}
</ClientProviders>
</body>
</html>
)
}