refactor: consolidate configuration and utility files
- Move menu, footer, and social links to `config.tsx` - Create `constants.ts` for shared constants like `POSTS_PER_PAGE` - Extract translation utility to `translator.ts` - Move table of contents generation to `lib/blog/toc.ts` - Update import paths across multiple components - Simplify email configuration using `siteConfig`
This commit is contained in:
parent
4f5f216296
commit
c7ab08f01d
@ -1,7 +1,7 @@
|
|||||||
import BlogGrid from '@/components/blog/blog-grid';
|
import BlogGrid from '@/components/blog/blog-grid';
|
||||||
import EmptyGrid from '@/components/shared/empty-grid';
|
import EmptyGrid from '@/components/shared/empty-grid';
|
||||||
import CustomPagination from '@/components/shared/pagination';
|
import CustomPagination from '@/components/shared/pagination';
|
||||||
import { POSTS_PER_PAGE } from '@/lib/constants';
|
import { POSTS_PER_PAGE } from '@/constants';
|
||||||
import { allPosts, allCategories } from 'content-collections';
|
import { allPosts, allCategories } from 'content-collections';
|
||||||
import { siteConfig } from '@/config/site';
|
import { siteConfig } from '@/config/site';
|
||||||
import { constructMetadata } from '@/lib/metadata';
|
import { constructMetadata } from '@/lib/metadata';
|
||||||
|
@ -3,7 +3,7 @@ import { Metadata } from 'next';
|
|||||||
import BlogGrid from '@/components/blog/blog-grid';
|
import BlogGrid from '@/components/blog/blog-grid';
|
||||||
import EmptyGrid from '@/components/shared/empty-grid';
|
import EmptyGrid from '@/components/shared/empty-grid';
|
||||||
import CustomPagination from '@/components/shared/pagination';
|
import CustomPagination from '@/components/shared/pagination';
|
||||||
import { POSTS_PER_PAGE } from '@/lib/constants';
|
import { POSTS_PER_PAGE } from '@/constants';
|
||||||
import { NextPageProps } from '@/types/next-page-props';
|
import { NextPageProps } from '@/types/next-page-props';
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
|
@ -2,7 +2,7 @@ import AllPostsButton from '@/components/blog/all-posts-button';
|
|||||||
import { BlogToc } from '@/components/blog/blog-toc';
|
import { BlogToc } from '@/components/blog/blog-toc';
|
||||||
import { Mdx } from '@/components/shared/mdx-component';
|
import { Mdx } from '@/components/shared/mdx-component';
|
||||||
import { LocaleLink } from '@/i18n/navigation';
|
import { LocaleLink } from '@/i18n/navigation';
|
||||||
import { getTableOfContents } from '@/lib/toc';
|
import { getTableOfContents } from '@/lib/blog/toc';
|
||||||
import { getBaseUrl } from '@/lib/urls/get-base-url';
|
import { getBaseUrl } from '@/lib/urls/get-base-url';
|
||||||
import { estimateReadingTime, getLocaleDate } from '@/lib/utils';
|
import { estimateReadingTime, getLocaleDate } from '@/lib/utils';
|
||||||
import type { NextPageProps } from '@/types/next-page-props';
|
import type { NextPageProps } from '@/types/next-page-props';
|
||||||
|
@ -5,7 +5,7 @@ import { Routes } from '@/routes';
|
|||||||
|
|
||||||
export const metadata = constructMetadata({
|
export const metadata = constructMetadata({
|
||||||
title: 'Auth Error',
|
title: 'Auth Error',
|
||||||
description: 'Auth Error',
|
description: 'Auth Error',
|
||||||
canonicalUrl: `${getBaseUrl()}${Routes.AuthError}`,
|
canonicalUrl: `${getBaseUrl()}${Routes.AuthError}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import BlogCard, { BlogCardSkeleton } from '@/components/blog/blog-card';
|
import BlogCard, { BlogCardSkeleton } from '@/components/blog/blog-card';
|
||||||
import { POSTS_PER_PAGE } from '@/lib/constants';
|
import { POSTS_PER_PAGE } from '@/constants';
|
||||||
import { Post } from 'content-collections';
|
import { Post } from 'content-collections';
|
||||||
|
|
||||||
interface BlogGridProps {
|
interface BlogGridProps {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMounted } from '@/hooks/use-mounted';
|
import { useMounted } from '@/hooks/use-mounted';
|
||||||
import type { TableOfContents } from '@/lib/toc';
|
import type { TableOfContents } from '@/lib/blog/toc';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export default function Error({ reset }: { reset: () => void }) {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
const t = useTranslations('ErrorPage');
|
const t = useTranslations('ErrorPage');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex min-h-screen flex-col items-center justify-center gap-8">
|
<div className="flex min-h-screen flex-col items-center justify-center gap-8">
|
||||||
<Logo className="size-12" />
|
<Logo className="size-12" />
|
||||||
|
@ -4,11 +4,7 @@ import Container from '@/components/container';
|
|||||||
import { ThemeSwitcherHorizontal } from '@/components/layout/theme-switcher-horizontal';
|
import { ThemeSwitcherHorizontal } from '@/components/layout/theme-switcher-horizontal';
|
||||||
import { Logo } from '@/components/logo';
|
import { Logo } from '@/components/logo';
|
||||||
import BuiltWithButton from '@/components/shared/built-with-button';
|
import BuiltWithButton from '@/components/shared/built-with-button';
|
||||||
import {
|
import { createTranslator, getFooterLinks, getSocialLinks } from '@/config';
|
||||||
createTranslator,
|
|
||||||
getFooterLinks,
|
|
||||||
getSocialLinks,
|
|
||||||
} from '@/config/config';
|
|
||||||
import { siteConfig } from '@/config/site';
|
import { siteConfig } from '@/config/site';
|
||||||
import { LocaleLink } from '@/i18n/navigation';
|
import { LocaleLink } from '@/i18n/navigation';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
@ -9,7 +9,8 @@ import {
|
|||||||
CollapsibleContent,
|
CollapsibleContent,
|
||||||
CollapsibleTrigger,
|
CollapsibleTrigger,
|
||||||
} from '@/components/ui/collapsible';
|
} from '@/components/ui/collapsible';
|
||||||
import { createTranslator, getMenuLinks } from '@/config/config';
|
import { getMenuLinks } from '@/config';
|
||||||
|
import { createTranslator } from '@/i18n/translator';
|
||||||
import { siteConfig } from '@/config/site';
|
import { siteConfig } from '@/config/site';
|
||||||
import { LocaleLink, useLocalePathname } from '@/i18n/navigation';
|
import { LocaleLink, useLocalePathname } from '@/i18n/navigation';
|
||||||
import { authClient } from '@/lib/auth-client';
|
import { authClient } from '@/lib/auth-client';
|
||||||
|
@ -17,7 +17,8 @@ import {
|
|||||||
NavigationMenuTrigger,
|
NavigationMenuTrigger,
|
||||||
navigationMenuTriggerStyle,
|
navigationMenuTriggerStyle,
|
||||||
} from '@/components/ui/navigation-menu';
|
} from '@/components/ui/navigation-menu';
|
||||||
import { createTranslator, getMenuLinks } from '@/config/config';
|
import { getMenuLinks } from '@/config';
|
||||||
|
import { createTranslator } from '@/i18n/translator';
|
||||||
import { siteConfig } from '@/config/site';
|
import { siteConfig } from '@/config/site';
|
||||||
import { useScroll } from '@/hooks/use-scroll';
|
import { useScroll } from '@/hooks/use-scroll';
|
||||||
import { LocaleLink, useLocalePathname } from '@/i18n/navigation';
|
import { LocaleLink, useLocalePathname } from '@/i18n/navigation';
|
||||||
|
@ -17,7 +17,7 @@ import {
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu';
|
} from '@/components/ui/dropdown-menu';
|
||||||
import { createTranslator, getAvatarLinks } from '@/config/config';
|
import { createTranslator, getAvatarLinks } from '@/config';
|
||||||
import { useMediaQuery } from '@/hooks/use-media-query';
|
import { useMediaQuery } from '@/hooks/use-media-query';
|
||||||
import { LocaleLink, useLocaleRouter } from '@/i18n/navigation';
|
import { LocaleLink, useLocaleRouter } from '@/i18n/navigation';
|
||||||
import { authClient } from '@/lib/auth-client';
|
import { authClient } from '@/lib/auth-client';
|
||||||
|
@ -32,25 +32,7 @@ import {
|
|||||||
ThumbsUpIcon,
|
ThumbsUpIcon,
|
||||||
WandSparklesIcon,
|
WandSparklesIcon,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
import { TranslationFunction } from './i18n/translator';
|
||||||
type TranslationFunction = (key: string, ...args: any[]) => string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a translation function that works with our menu functions
|
|
||||||
* @param t - The next-intl translation function
|
|
||||||
* @returns A translation function that accepts string keys
|
|
||||||
*/
|
|
||||||
export function createTranslator(t: any): TranslationFunction {
|
|
||||||
return (key: string) => {
|
|
||||||
try {
|
|
||||||
// @ts-ignore - We know this is a valid key because we've defined it in our messages
|
|
||||||
return t(key);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Translation key not found: ${key}`);
|
|
||||||
return key.split('.').pop() || key;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get menu links with translations
|
* Get menu links with translations
|
1
src/constants.ts
Normal file
1
src/constants.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const POSTS_PER_PAGE = 6;
|
18
src/i18n/translator.ts
Normal file
18
src/i18n/translator.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export type TranslationFunction = (key: string, ...args: any[]) => string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a translation function that works with our menu functions
|
||||||
|
* @param t - The next-intl translation function
|
||||||
|
* @returns A translation function that accepts string keys
|
||||||
|
*/
|
||||||
|
export function createTranslator(t: any): TranslationFunction {
|
||||||
|
return (key: string) => {
|
||||||
|
try {
|
||||||
|
// @ts-ignore - We know this is a valid key because we've defined it in our messages
|
||||||
|
return t(key);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Translation key not found: ${key}`);
|
||||||
|
return key.split('.').pop() || key;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
export const POSTS_PER_PAGE = 6;
|
|
||||||
|
|
||||||
export const EMAIL_FROM = process.env.EMAIL_FROM;
|
|
@ -20,7 +20,7 @@ export function constructMetadata({
|
|||||||
} = {}): Metadata {
|
} = {}): Metadata {
|
||||||
const fullTitle = title ? `${title} - ${siteConfig.title}` : siteConfig.title;
|
const fullTitle = title ? `${title} - ${siteConfig.title}` : siteConfig.title;
|
||||||
const ogImageUrl = new URL(`${getBaseUrl()}/${image}`);
|
const ogImageUrl = new URL(`${getBaseUrl()}/${image}`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: fullTitle,
|
title: fullTitle,
|
||||||
description,
|
description,
|
||||||
|
@ -11,12 +11,7 @@ type VerifyEmailProps = {
|
|||||||
name: string;
|
name: string;
|
||||||
} & BaseMailProps;
|
} & BaseMailProps;
|
||||||
|
|
||||||
export function VerifyEmail({
|
export function VerifyEmail({ url, name, locale, messages }: VerifyEmailProps) {
|
||||||
url,
|
|
||||||
name,
|
|
||||||
locale,
|
|
||||||
messages,
|
|
||||||
}: VerifyEmailProps) {
|
|
||||||
const t = createTranslator({
|
const t = createTranslator({
|
||||||
locale,
|
locale,
|
||||||
messages,
|
messages,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { EMAIL_FROM } from '@/lib/constants';
|
import { siteConfig } from '@/config/site';
|
||||||
import { Resend } from 'resend';
|
|
||||||
import { SendEmailHandler } from '@/mail/types';
|
import { SendEmailHandler } from '@/mail/types';
|
||||||
|
import { Resend } from 'resend';
|
||||||
|
|
||||||
export const resend = new Resend(process.env.RESEND_API_KEY);
|
export const resend = new Resend(process.env.RESEND_API_KEY);
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ export const sendEmail: SendEmailHandler = async ({ to, subject, html }) => {
|
|||||||
Authorization: `Bearer ${process.env.RESEND_API_KEY}`,
|
Authorization: `Bearer ${process.env.RESEND_API_KEY}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
from: EMAIL_FROM,
|
from: siteConfig.mail,
|
||||||
to,
|
to,
|
||||||
subject,
|
subject,
|
||||||
html,
|
html,
|
||||||
|
Loading…
Reference in New Issue
Block a user