Update UI and improve i18n loading logic
Major changes include enhancements to the UI and modifications to the i18n loading logic to more effectively handle namespaces. Several components were updated to improve readability and layout consistency. The i18n loading logic now includes additional handling for waiting until all namespaces are loaded before the i18n instance is returned, with a warning if it takes longer than expected. Furthermore, code have been refactored for fonts, buttons, and other UI elements.
This commit is contained in:
@@ -7,8 +7,8 @@ import appConfig from '~/config/app.config';
|
||||
|
||||
export function SiteFooter() {
|
||||
return (
|
||||
<footer className={'mt-auto border-t py-8 2xl:py-14'}>
|
||||
<div className={'px-8'}>
|
||||
<footer className={'mt-auto py-8 2xl:py-16 relative w-full site-footer'}>
|
||||
<div className={'container'}>
|
||||
<div className={'flex flex-col space-y-8 lg:flex-row lg:space-y-0'}>
|
||||
<div
|
||||
className={
|
||||
|
||||
@@ -5,7 +5,7 @@ import Link from 'next/link';
|
||||
|
||||
import type { User } from '@supabase/supabase-js';
|
||||
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import { ArrowRightIcon } from 'lucide-react';
|
||||
|
||||
import { PersonalAccountDropdown } from '@kit/accounts/personal-account-dropdown';
|
||||
import { useSignOut } from '@kit/supabase/hooks/use-sign-out';
|
||||
@@ -64,17 +64,14 @@ function SuspendedPersonalAccountDropdown(props: { user: User | null }) {
|
||||
}
|
||||
|
||||
function AuthButtons() {
|
||||
const textClassName =
|
||||
'text-gray-600 hover:text-current dark:text-gray-400 dark:hover:text-white';
|
||||
|
||||
return (
|
||||
<div className={'flex space-x-2'}>
|
||||
<div className={'hidden space-x-0.5 md:flex'}>
|
||||
<If condition={features.enableThemeToggle}>
|
||||
<ModeToggle className={textClassName} />
|
||||
<ModeToggle />
|
||||
</If>
|
||||
|
||||
<Button asChild variant={'ghost'} className={textClassName}>
|
||||
<Button asChild variant={'ghost'}>
|
||||
<Link href={pathsConfig.auth.signIn}>
|
||||
<Trans i18nKey={'auth:signIn'} />
|
||||
</Link>
|
||||
@@ -85,7 +82,7 @@ function AuthButtons() {
|
||||
<Link href={pathsConfig.auth.signUp}>
|
||||
<Trans i18nKey={'auth:signUp'} />
|
||||
|
||||
<ChevronRight
|
||||
<ArrowRightIcon
|
||||
className={
|
||||
'ml-1 h-4 w-4 transition-transform duration-500 group-hover:translate-x-1'
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ export function SiteHeader(props: { user?: User | null }) {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
'sticky top-0 z-10 w-full bg-background/80 shadow-sm backdrop-blur-md dark:bg-background/50 dark:shadow-primary/10'
|
||||
'sticky top-0 z-10 w-full bg-background/80 backdrop-blur-md dark:bg-background/50 py-2 site-header'
|
||||
}
|
||||
>
|
||||
<div className={'px-4 lg:px-8'}>
|
||||
<div className={'container'}>
|
||||
<div className="grid h-14 grid-cols-3 items-center">
|
||||
<div>
|
||||
<AppLogo />
|
||||
|
||||
@@ -12,7 +12,7 @@ const getClassName = (path: string, currentPathName: string) => {
|
||||
return cn(
|
||||
`text-sm font-medium px-2.5 py-2 border rounded-lg border-transparent transition-colors duration-100`,
|
||||
{
|
||||
'hover:border-border dark:text-gray-400 text-gray-600 hover:text-current dark:hover:text-white':
|
||||
'dark:text-gray-300 dark:hover:text-white':
|
||||
!isActive,
|
||||
'dark:text-white text-current': isActive,
|
||||
},
|
||||
|
||||
@@ -30,6 +30,10 @@ const links = {
|
||||
label: 'marketing:faq',
|
||||
path: '/faq',
|
||||
},
|
||||
Contact: {
|
||||
label: 'marketing:contact',
|
||||
path: '/contact',
|
||||
}
|
||||
};
|
||||
|
||||
export function SiteNavigation() {
|
||||
@@ -44,7 +48,7 @@ export function SiteNavigation() {
|
||||
return (
|
||||
<>
|
||||
<div className={'hidden items-center justify-center md:flex'}>
|
||||
<NavigationMenu>
|
||||
<NavigationMenu className={'border border-gray-100 dark:border-primary/10 rounded-full py-2 px-4'}>
|
||||
<NavigationMenuList className={'space-x-1'}>
|
||||
{NavItems}
|
||||
</NavigationMenuList>
|
||||
|
||||
@@ -8,11 +8,11 @@ export function SitePageHeader(props: {
|
||||
return (
|
||||
<div className={cn('border-b py-8 xl:py-10 2xl:py-12', props.className)}>
|
||||
<div className={'container flex flex-col space-y-2 lg:space-y-4'}>
|
||||
<h1 className={'font-base font-heading text-3xl xl:text-5xl'}>
|
||||
<h1 className={'font-medium font-heading text-3xl xl:text-5xl dark:text-white tracking-tight'}>
|
||||
{props.title}
|
||||
</h1>
|
||||
|
||||
<h2 className={'text-lg text-muted-foreground 2xl:text-2xl'}>
|
||||
<h2 className={'text-lg text-muted-foreground 2xl:text-2xl tracking-tight'}>
|
||||
{props.subtitle}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ export function PostHeader({ post }: { post: Cms.ContentItem }) {
|
||||
<div className={'flex flex-1 flex-col'}>
|
||||
<div className={cn('border-b py-8')}>
|
||||
<div className={'mx-auto flex max-w-3xl flex-col space-y-4'}>
|
||||
<h1 className={'font-heading text-3xl font-semibold xl:text-5xl'}>
|
||||
<h1 className={'font-heading text-3xl font-semibold xl:text-5xl dark:text-white'}>
|
||||
{title}
|
||||
</h1>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ async function DocsLayout({ children }: React.PropsWithChildren) {
|
||||
const pages = await getDocs(resolvedLanguage);
|
||||
|
||||
return (
|
||||
<div className={'flex'}>
|
||||
<div className={'flex container'}>
|
||||
<DocsNavigation pages={buildDocumentationTree(pages)} />
|
||||
|
||||
{children}
|
||||
|
||||
@@ -2,7 +2,7 @@ import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
|
||||
import {
|
||||
ChevronRight,
|
||||
ArrowRightIcon,
|
||||
CreditCard,
|
||||
LayoutDashboard,
|
||||
Lock,
|
||||
@@ -21,7 +21,7 @@ import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
function Home() {
|
||||
return (
|
||||
<div className={'mt-4 flex flex-col space-y-24 py-16'}>
|
||||
<div className={'mt-4 flex flex-col space-y-24 py-14'}>
|
||||
<div className={'container mx-auto flex flex-col space-y-20'}>
|
||||
<div
|
||||
className={
|
||||
@@ -32,7 +32,7 @@ function Home() {
|
||||
>
|
||||
<div
|
||||
className={
|
||||
'flex w-full flex-1 flex-col items-center space-y-8 xl:space-y-12 2xl:space-y-14'
|
||||
'flex w-full flex-1 flex-col items-center space-y-6 xl:space-y-8 2xl:space-y-10'
|
||||
}
|
||||
>
|
||||
<Pill>
|
||||
@@ -41,46 +41,27 @@ function Home() {
|
||||
|
||||
<div className={'flex flex-col items-center space-y-8'}>
|
||||
<HeroTitle>
|
||||
<span>The SaaS Starter Kit</span>
|
||||
<span>The ultimate SaaS Starter</span>
|
||||
|
||||
<span>
|
||||
<span>for ambitious developers</span>
|
||||
</span>
|
||||
<span>for your next project</span>
|
||||
</HeroTitle>
|
||||
|
||||
<div className={'flex flex-col'}>
|
||||
<div className={'flex max-w-2xl flex-col space-y-1'}>
|
||||
<Heading
|
||||
level={2}
|
||||
level={3}
|
||||
className={
|
||||
'p-0 text-center font-sans text-2xl font-normal text-muted-foreground'
|
||||
'p-0 text-center font-sans font-normal text-muted-foreground'
|
||||
}
|
||||
>
|
||||
<span>Build and launch a SaaS in days, not months</span>
|
||||
</Heading>
|
||||
|
||||
<Heading
|
||||
level={2}
|
||||
className={
|
||||
'p-0 text-center font-sans text-2xl font-normal text-muted-foreground'
|
||||
}
|
||||
>
|
||||
<span>Focus on your business, not on the tech</span>
|
||||
</Heading>
|
||||
|
||||
<Heading
|
||||
level={2}
|
||||
className={
|
||||
'p-0 text-center font-sans text-2xl font-normal text-muted-foreground'
|
||||
}
|
||||
>
|
||||
Ship something great, today.
|
||||
Build and Ship a SaaS faster than ever before with the
|
||||
next-gen SaaS Starter Kit. Ship your SaaS in days, not months.
|
||||
</Heading>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<MainCallToActionButton />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={
|
||||
@@ -101,44 +82,15 @@ function Home() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={'container mx-auto'}>
|
||||
<div
|
||||
className={
|
||||
'flex flex-col items-center justify-center space-y-8 py-8 xl:space-y-16 xl:py-16'
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={
|
||||
'flex max-w-3xl flex-col items-center space-y-8 text-center'
|
||||
}
|
||||
>
|
||||
<Pill>
|
||||
<span>A modern, scalable, and secure SaaS Starter Kit</span>
|
||||
</Pill>
|
||||
|
||||
<div className={'flex flex-col space-y-2'}>
|
||||
<Heading level={1}>The best tool in the space</Heading>
|
||||
|
||||
<Heading
|
||||
level={2}
|
||||
className={'font-sans font-normal text-muted-foreground'}
|
||||
>
|
||||
Unbeatable Features and Benefits for Your SaaS Business
|
||||
</Heading>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={'container mx-auto'}>
|
||||
<div
|
||||
className={'flex flex-col space-y-16 xl:space-y-32 2xl:space-y-36'}
|
||||
>
|
||||
<FeatureShowcaseContainer>
|
||||
<FeatureContainer>
|
||||
<div className={'flex flex-col space-y-6'}>
|
||||
<IconContainer className={'bg-green-50 dark:bg-green-500/10'}>
|
||||
<Lock className={'h-5 text-green-500'} />
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<IconContainer className={'border'}>
|
||||
<Lock className={'h-5'} />
|
||||
</IconContainer>
|
||||
|
||||
<div className={'flex flex-col'}>
|
||||
@@ -146,7 +98,7 @@ function Home() {
|
||||
|
||||
<Heading
|
||||
level={3}
|
||||
className={'font-sans font-normal text-muted-foreground'}
|
||||
className={'font-sans font-normal text-muted-foreground tracking-normal'}
|
||||
>
|
||||
Secure and Easy-to-Use Authentication for Your SaaS Website
|
||||
and API
|
||||
@@ -154,12 +106,12 @@ function Home() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className={'text-muted-foreground'}>
|
||||
Our authentication system is built on top of the
|
||||
industry-leading PaaS such as Supabase and Firebase. It is
|
||||
secure, easy-to-use, and fully customizable. It supports
|
||||
email/password, social logins, and more.
|
||||
</div>
|
||||
</p>
|
||||
</FeatureContainer>
|
||||
|
||||
<FeatureContainer>
|
||||
@@ -185,9 +137,9 @@ function Home() {
|
||||
</FeatureContainer>
|
||||
|
||||
<FeatureContainer>
|
||||
<div className={'flex flex-col space-y-6'}>
|
||||
<IconContainer className={'bg-indigo-50 dark:bg-indigo-500/10'}>
|
||||
<LayoutDashboard className={'h-5 text-indigo-500'} />
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<IconContainer className={'border'}>
|
||||
<LayoutDashboard className={'h-5'} />
|
||||
</IconContainer>
|
||||
|
||||
<div className={'flex flex-col'}>
|
||||
@@ -195,26 +147,26 @@ function Home() {
|
||||
|
||||
<Heading
|
||||
level={3}
|
||||
className={'font-sans font-normal text-muted-foreground'}
|
||||
className={'font-sans font-normal text-muted-foreground tracking-normal'}
|
||||
>
|
||||
A fantastic dashboard to manage your SaaS business
|
||||
</Heading>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className={'text-muted-foreground'}>
|
||||
Our dashboard offers an overview of your SaaS business. It shows
|
||||
at a glance all you need to know about your business. It is
|
||||
fully customizable and extendable.
|
||||
</div>
|
||||
</p>
|
||||
</FeatureContainer>
|
||||
</FeatureShowcaseContainer>
|
||||
|
||||
<FeatureShowcaseContainer>
|
||||
<FeatureContainer>
|
||||
<div className={'flex flex-col space-y-6'}>
|
||||
<IconContainer className={'bg-blue-50 dark:bg-blue-500/10'}>
|
||||
<CreditCard className={'h-5 text-blue-500'} />
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<IconContainer className={'border'}>
|
||||
<CreditCard className={'h-5'} />
|
||||
</IconContainer>
|
||||
|
||||
<div className={'flex flex-col'}>
|
||||
@@ -222,18 +174,18 @@ function Home() {
|
||||
|
||||
<Heading
|
||||
level={3}
|
||||
className={'font-sans font-normal text-muted-foreground'}
|
||||
className={'font-sans font-normal text-muted-foreground tracking-normal'}
|
||||
>
|
||||
A powerful billing system for your SaaS business
|
||||
</Heading>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className={'text-muted-foreground'}>
|
||||
Powerful billing system that supports multiple payment gateways
|
||||
such as Stripe, Lemon Squeezy and Paddle. Fully customizable and
|
||||
easy to use.
|
||||
</div>
|
||||
</p>
|
||||
</FeatureContainer>
|
||||
|
||||
<FeatureContainer>
|
||||
@@ -255,16 +207,16 @@ function Home() {
|
||||
'flex flex-col items-center justify-center space-y-16 py-16'
|
||||
}
|
||||
>
|
||||
<div className={'flex flex-col items-center space-y-8 text-center'}>
|
||||
<div className={'flex flex-col items-center space-y-4 text-center'}>
|
||||
<Pill>Get started for free. No credit card required.</Pill>
|
||||
|
||||
<div className={'flex flex-col space-y-2'}>
|
||||
<Heading level={1}>
|
||||
<div className={'flex flex-col'}>
|
||||
<Heading level={2}>
|
||||
Fair pricing for all types of businesses
|
||||
</Heading>
|
||||
|
||||
<Heading
|
||||
level={2}
|
||||
level={3}
|
||||
className={'font-sans font-normal text-muted-foreground'}
|
||||
>
|
||||
Get started on our free plan and upgrade when you are ready.
|
||||
@@ -293,7 +245,7 @@ function HeroTitle({ children }: React.PropsWithChildren) {
|
||||
return (
|
||||
<h1
|
||||
className={
|
||||
'flex flex-col text-center font-heading text-5xl font-semibold tracking-tight sm:text-6xl lg:text-7xl'
|
||||
'flex flex-col space-y-1 text-center font-sans text-4xl font-medium tracking-tight dark:text-white sm:text-6xl lg:max-w-5xl lg:text-7xl xl:text-[4.5rem]'
|
||||
}
|
||||
>
|
||||
{children}
|
||||
@@ -305,10 +257,10 @@ function Pill(props: React.PropsWithChildren) {
|
||||
return (
|
||||
<h2
|
||||
className={
|
||||
'rounded-full px-4 py-2 text-center text-sm text-muted-foreground shadow dark:shadow-primary/20'
|
||||
'rounded-full border border-gray-100 px-2.5 py-2 text-center text-sm font-medium dark:border-primary/10'
|
||||
}
|
||||
>
|
||||
<Sparkle className={'inline-block h-4'} />
|
||||
<Sparkle className={'mr-2 inline-block h-4'} />
|
||||
{props.children}
|
||||
</h2>
|
||||
);
|
||||
@@ -346,21 +298,18 @@ function FeatureContainer(
|
||||
|
||||
function MainCallToActionButton() {
|
||||
return (
|
||||
<div className={'flex space-x-2'}>
|
||||
<Button asChild variant={'link'}>
|
||||
<Link href={'/docs'}>
|
||||
<Trans i18nKey={'common:documentation'} />
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
<Button asChild>
|
||||
<div className={'flex space-x-4'}>
|
||||
<Button
|
||||
className={'h-12 px-4 rounded-xl text-base font-semibold'}
|
||||
asChild
|
||||
>
|
||||
<Link href={'/auth/sign-up'}>
|
||||
<span className={'flex items-center space-x-0.5'}>
|
||||
<span>
|
||||
<Trans i18nKey={'common:getStarted'} />
|
||||
</span>
|
||||
|
||||
<ChevronRight
|
||||
<ArrowRightIcon
|
||||
className={
|
||||
'h-4 animate-in fade-in slide-in-from-left-8' +
|
||||
' delay-800 duration-1000 zoom-in fill-mode-both'
|
||||
@@ -369,6 +318,16 @@ function MainCallToActionButton() {
|
||||
</span>
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant={'link'}
|
||||
className={'h-12 px-4 rounded-xl text-base font-semibold'}
|
||||
asChild
|
||||
>
|
||||
<Link href={'/contact'}>
|
||||
<Trans i18nKey={'common:contactUs'} />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -36,15 +36,19 @@ function getClassName(theme?: string) {
|
||||
const dark = theme === 'dark';
|
||||
const light = !dark;
|
||||
|
||||
return cn(
|
||||
'min-h-screen bg-background antialiased',
|
||||
sans.variable,
|
||||
heading.variable,
|
||||
{
|
||||
const font = [sans.variable, heading.variable].reduce<string[]>(
|
||||
(acc, curr) => {
|
||||
if (acc.includes(curr)) return acc;
|
||||
|
||||
return [...acc, curr];
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return cn('min-h-screen bg-background antialiased', ...font, {
|
||||
dark,
|
||||
light,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function getTheme() {
|
||||
|
||||
@@ -10,9 +10,9 @@ Makerkit is a SaaS Starter Kit that helps you build a SaaS. It provides you with
|
||||
|
||||
## Getting started
|
||||
|
||||
To get started with Makerkit, follow these steps:
|
||||
To get started follow these steps:
|
||||
|
||||
1. Sign up for an account on the [Makerkit website](https://makerkit.dev).
|
||||
1. Sign up for an account on the [website](#).
|
||||
2. Create a new project by clicking on the "New Project" button.
|
||||
3. Choose a template for your project. Makerkit provides several templates to help you get started quickly.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Urbanist as HeadingFont, Inter as SansFont } from 'next/font/google';
|
||||
import { Inter as SansFont } from 'next/font/google';
|
||||
|
||||
/**
|
||||
* @sans
|
||||
@@ -16,15 +16,8 @@ const sans = SansFont({
|
||||
/**
|
||||
* @heading
|
||||
* @description Define here the heading font.
|
||||
* By default, it uses the Urbanist font from Google Fonts.
|
||||
*/
|
||||
const heading = HeadingFont({
|
||||
subsets: ['latin'],
|
||||
variable: '--font-heading',
|
||||
fallback: ['system-ui', 'Helvetica Neue', 'Helvetica', 'Arial'],
|
||||
preload: true,
|
||||
weight: ['500', '600'],
|
||||
});
|
||||
const heading = sans;
|
||||
|
||||
// we export these fonts into the root layout
|
||||
export { sans, heading };
|
||||
|
||||
@@ -95,3 +95,24 @@ Optimize dropdowns for mobile
|
||||
[data-radix-menu-content] [role="menuitem"] {
|
||||
@apply md:min-h-0 min-h-12;
|
||||
}
|
||||
|
||||
.site-header > .container:before,
|
||||
.site-footer > .container:before {
|
||||
background: radial-gradient(62.87% 100% at 50% 100%, theme('colors.gray.200') 0%, rgba(255, 255, 255, 0) 100%);
|
||||
|
||||
bottom: 0;
|
||||
content: "";
|
||||
height: 1px;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dark .site-header > .container:before,
|
||||
.dark .site-footer > .container:before {
|
||||
background: radial-gradient(62.87% 100% at 50% 100%, rgba(255, 255, 255, .16) 0%, rgba(255, 255, 255, 0) 100%);
|
||||
}
|
||||
|
||||
.site-footer > .container:before {
|
||||
top: 0;
|
||||
}
|
||||
@@ -377,7 +377,7 @@ function PlanIntervalSwitcher(
|
||||
{
|
||||
'rounded-r-none border-r-transparent': index === 0,
|
||||
'rounded-l-none': index === props.intervals.length - 1,
|
||||
['hover:text-primary border']: !selected,
|
||||
['hover:text-primary border text-muted-foreground']: !selected,
|
||||
['font-semibold cursor-default hover:text-initial hover:bg-background']:
|
||||
selected,
|
||||
},
|
||||
@@ -444,7 +444,7 @@ function DefaultCheckoutButton(
|
||||
<Link className={'w-full'} href={linkHref}>
|
||||
<Button
|
||||
size={'lg'}
|
||||
className={'ring-primary w-full ring-2'}
|
||||
className={'border-primary w-full border rounded-lg'}
|
||||
variant={props.highlighted ? 'default' : 'outline'}
|
||||
>
|
||||
<span>
|
||||
|
||||
@@ -13,12 +13,14 @@ export async function initializeServerI18n(
|
||||
resolver: (language: string, namespace: string) => Promise<object>,
|
||||
) {
|
||||
const i18nInstance = createInstance();
|
||||
const loadedNamespaces = new Set<string>();
|
||||
|
||||
await i18nInstance
|
||||
.use(
|
||||
resourcesToBackend(async (language, namespace, callback) => {
|
||||
try {
|
||||
const data = await resolver(language, namespace);
|
||||
loadedNamespaces.add(namespace);
|
||||
|
||||
return callback(null, data);
|
||||
} catch (error) {
|
||||
@@ -27,16 +29,50 @@ export async function initializeServerI18n(
|
||||
error,
|
||||
);
|
||||
|
||||
return {};
|
||||
return callback(null, {});
|
||||
}
|
||||
}),
|
||||
)
|
||||
.use(initReactI18next)
|
||||
.init(settings, (error) => {
|
||||
if (error) {
|
||||
console.error('Error initializing i18n server', error);
|
||||
.init(settings);
|
||||
|
||||
const namespaces = settings.ns as string[];
|
||||
|
||||
// If all namespaces are already loaded, return the i18n instance
|
||||
if (loadedNamespaces.size === namespaces.length) {
|
||||
return i18nInstance;
|
||||
}
|
||||
|
||||
// Otherwise, wait for all namespaces to be loaded
|
||||
|
||||
const maxWaitTime = 0.1; // 100 milliseconds
|
||||
const checkIntervalMs = 5; // 5 milliseconds
|
||||
|
||||
async function waitForNamespaces() {
|
||||
const startTime = Date.now();
|
||||
|
||||
while (Date.now() - startTime < maxWaitTime) {
|
||||
const allNamespacesLoaded = namespaces.every((ns) =>
|
||||
loadedNamespaces.has(ns),
|
||||
);
|
||||
|
||||
if (allNamespacesLoaded) {
|
||||
return true;
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, checkIntervalMs));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const success = await waitForNamespaces();
|
||||
|
||||
if (!success) {
|
||||
console.warn(
|
||||
`Not all namespaces were loaded after ${maxWaitTime}ms. Initialization may be incomplete.`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return i18nInstance;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export function Heading({
|
||||
return (
|
||||
<h1
|
||||
className={cn(
|
||||
`scroll-m-20 font-heading text-4xl font-bold tracking-tight dark:text-white`,
|
||||
`scroll-m-20 font-heading text-3xl lg:text-4xl font-bold tracking-tight dark:text-white`,
|
||||
className,
|
||||
)}
|
||||
>
|
||||
@@ -23,7 +23,7 @@ export function Heading({
|
||||
return (
|
||||
<h2
|
||||
className={cn(
|
||||
`scroll-m-20 pb-2 font-heading text-3xl font-semibold tracking-tight transition-colors first:mt-0`,
|
||||
`scroll-m-20 pb-2 font-heading text-2xl lg:text-3xl font-semibold tracking-tight transition-colors first:mt-0`,
|
||||
className,
|
||||
)}
|
||||
>
|
||||
@@ -34,7 +34,7 @@ export function Heading({
|
||||
return (
|
||||
<h3
|
||||
className={cn(
|
||||
'scroll-m-20 font-heading text-2xl font-semibold tracking-tight',
|
||||
'scroll-m-20 font-heading text-xl lg:text-2xl font-semibold tracking-tight',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
@@ -45,7 +45,7 @@ export function Heading({
|
||||
return (
|
||||
<h4
|
||||
className={cn(
|
||||
'scroll-m-20 font-heading text-xl font-semibold tracking-tight',
|
||||
'scroll-m-20 font-heading text-lg lg:text-xl font-semibold tracking-tight',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
@@ -56,7 +56,7 @@ export function Heading({
|
||||
return (
|
||||
<h5
|
||||
className={cn(
|
||||
'scroll-m-20 font-heading text-lg font-medium',
|
||||
'scroll-m-20 font-heading text-base lg:text-lg font-medium',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user