Skip to content

Commit

Permalink
Merge pull request #132 from JohnsonMao/feature/button-component
Browse files Browse the repository at this point in the history
✨ add button component
  • Loading branch information
JohnsonMao authored Feb 27, 2024
2 parents 1361aaf + 0d43186 commit 55cc338
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 32 deletions.
2 changes: 1 addition & 1 deletion src/app/[lang]/(home)/Article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function Article({
/>
)}
</div>
<div className="prose prose-zinc dark:prose-invert">
<div id={id} className="prose prose-zinc dark:prose-invert">
<H2>
<Link href={`/posts/${id}`}>{title}</Link>
</H2>
Expand Down
11 changes: 9 additions & 2 deletions src/app/[lang]/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import type { Metadata } from 'next';

import { getDictionary } from '~/data/i18n';
import Container from '@/components/Container';
import { H1 } from '@/components/Heading';
import { H1, H2 } from '@/components/Heading';
import Button from '@/components/Button';
import List from '@/components/List';
import { getAllDataFrontmatter } from '@/utils/mdx';

Expand All @@ -22,6 +23,7 @@ export async function generateMetadata({
async function RootPage({ params: { lang } }: RootParams) {
const posts = await getAllDataFrontmatter('posts');
const { homePage, common } = await getDictionary(lang);
const nextPostId = posts.at(4)?.id || '';

return (
<>
Expand All @@ -30,8 +32,13 @@ async function RootPage({ params: { lang } }: RootParams) {
<p className="text-xl">{homePage.description}</p>
</Container>
<Container as="main" className="py-8">
<p className="mb-4 text-lg">{common.latestPosts}</p>
<H2 className="mb-6 text-center text-2xl">{common.latestPosts}</H2>
<List Item={Article} items={posts.slice(0, 4)} />
<div className="my-4 flex justify-center">
<Button href={`/posts#${nextPostId}`} className="text-lg">
{common.morePosts}
</Button>
</div>
</Container>
</>
);
Expand Down
8 changes: 1 addition & 7 deletions src/app/[lang]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import ThemeSwitcher from '@/components/ThemeSwitcher';
import Header, { Avatar } from './Header';
import Footer from './Footer';
import Menu, { MenuProps } from './Menu';
import cn from '@/utils/cn';

export async function generateStaticParams() {
return locales.map((lang) => ({ lang }));
Expand Down Expand Up @@ -60,12 +59,7 @@ async function I18nLayout({
<>
<Header avatar={<Avatar src={avatar.src} alt={avatar.alt} />}>
<Menu menu={menu} />
<ThemeSwitcher
className={cn(
'neon-box rounded-full p-3 backdrop-blur-sm',
'bg-zinc-100/80 dark:bg-zinc-900/80'
)}
/>
<ThemeSwitcher />
</Header>
{children}
<Footer copyright={copyright} />
Expand Down
14 changes: 10 additions & 4 deletions src/app/[lang]/posts/InfiniteList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { memo } from 'react';
import { useSearchParams } from 'next/navigation';
import Link from '@/components/Link';
import Button from '@/components/Button';
import List from '@/components/List';
import { clamp } from '@/utils/math';
import Article from '../(home)/Article';
Expand All @@ -24,9 +24,15 @@ function InfiniteList({ items, morePostsText }: InfiniteListProps) {
<>
<List Item={MemoArticle} items={items.slice(0, limit)} />
{limit < total && (
<Link href={`?limit=${clampLimit(limit + 10)}`} replace scroll={false}>
{morePostsText}
</Link>
<div className="my-4 flex justify-center">
<Button
href={`?limit=${clampLimit(limit + 10)}`}
scroll={false}
replace
>
{morePostsText}
</Button>
</div>
)}
</>
);
Expand Down
39 changes: 39 additions & 0 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use client';

import type { AriaAttributes, ButtonHTMLAttributes } from 'react';
import cn from '@/utils/cn';
import Link, { LinkProps } from './Link';

type BaseButtonProps = {
href?: never;
} & ButtonHTMLAttributes<HTMLButtonElement>;

type ButtonProps = BaseButtonProps | LinkProps;

function Button({
children,
className,
...props
}: ButtonProps & AriaAttributes) {
const buttonOrLinkClassName = cn(
'neon-box rounded-full px-5 py-1.5 backdrop-blur-sm',
'bg-zinc-100/80 dark:bg-zinc-900/80',
className
);

if (props.href) {
return (
<Link className={buttonOrLinkClassName} {...props}>
{children}
</Link>
);
}

return (
<button className={buttonOrLinkClassName} {...props}>
{children}
</button>
);
}

export default Button;
2 changes: 1 addition & 1 deletion src/components/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { HiExternalLink } from 'react-icons/hi';
import cn from '@/utils/cn';
import getLocale from '@/utils/getLocale';

type LinkProps<T extends string = string> = (
export type LinkProps<T extends string = string> = (
| NextLinkProps<T>
| LinkWithoutLocalePathProps
| ExternalLinkProps
Expand Down
21 changes: 5 additions & 16 deletions src/components/ThemeSwitcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@
import { useTheme } from 'next-themes';
import { BsSunFill, BsMoonFill } from 'react-icons/bs';
import useIsMounted from '@/hooks/useIsMounted';
import Button from './Button';

type ThemeSwitcherProps = {
className?: string;
};

function ThemeSwitcher({ className }: ThemeSwitcherProps) {
function ThemeSwitcher() {
const isMounted = useIsMounted();
const { resolvedTheme, setTheme } = useTheme();
const isDarkTheme = resolvedTheme === 'dark';
Expand All @@ -18,25 +15,17 @@ function ThemeSwitcher({ className }: ThemeSwitcherProps) {
};

if (!isMounted) {
return (
<div className={className}>
<div className="h-5 w-5 animate-spin rounded-full border-2 border-white/80 border-t-white/20"></div>
</div>
);
return <div></div>;
}

return (
<button
aria-label="theme switcher"
className={className}
onClick={handleClick}
>
<Button aria-label="theme switcher" className="p-3" onClick={handleClick}>
{isDarkTheme ? (
<BsMoonFill size="1.25rem" />
) : (
<BsSunFill size="1.25rem" />
)}
</button>
</Button>
);
}

Expand Down
4 changes: 3 additions & 1 deletion types/link.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ type DynamicRoutesWithoutLocalePath =
: never;

type LinkWithoutLocalePathProps = {
href: DynamicRoutesWithoutLocalePath;
href:
| DynamicRoutesWithoutLocalePath
| `${DynamicRoutesWithoutLocalePath}#${string}`;
};

type ExternalLinkProps = {
Expand Down

0 comments on commit 55cc338

Please sign in to comment.