mirror of
https://github.com/DefectingCat/DefectingCat.github.io
synced 2025-07-16 01:01:38 +00:00
App projects page
This commit is contained in:
148
app/projects/page.tsx
Normal file
148
app/projects/page.tsx
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import {
|
||||||
|
SiGitea,
|
||||||
|
SiNextdotjs,
|
||||||
|
SiRedux,
|
||||||
|
SiThreedotjs,
|
||||||
|
SiTsnode,
|
||||||
|
SiVim,
|
||||||
|
} from 'react-icons/si';
|
||||||
|
import { VscGithubInverted } from 'react-icons/vsc';
|
||||||
|
import { HiPhoto } from 'react-icons/hi2';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import ProjectCard from './project-card';
|
||||||
|
|
||||||
|
const iconMap = {
|
||||||
|
gitea: <SiGitea />,
|
||||||
|
nextjs: <SiNextdotjs />,
|
||||||
|
github: <VscGithubInverted />,
|
||||||
|
vim: <SiVim />,
|
||||||
|
tsnode: <SiTsnode />,
|
||||||
|
three: <SiThreedotjs />,
|
||||||
|
photos: <HiPhoto />,
|
||||||
|
redux: <SiRedux />,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Project = {
|
||||||
|
id: number;
|
||||||
|
icon?: keyof typeof iconMap;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const projects: Project[] = [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
icon: 'three',
|
||||||
|
name: '3d-globe',
|
||||||
|
description: 'A 3d globe made by three.js.',
|
||||||
|
url: 'https://github.com/DefectingCat/3d-globe',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
icon: 'nextjs',
|
||||||
|
name: 'Blog',
|
||||||
|
description: 'This site.',
|
||||||
|
url: 'https://github.com/DefectingCat/DefectingCat.github.io',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
icon: 'tsnode',
|
||||||
|
name: 'boring-avatars-services',
|
||||||
|
description: 'Random avatars.',
|
||||||
|
url: 'https://github.com/DefectingCat/boring-avatars-services',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
icon: 'tsnode',
|
||||||
|
name: 'RUA DDNS',
|
||||||
|
description: 'DDNS Script for DNSPod',
|
||||||
|
url: 'https://github.com/DefectingCat/rua-ddns',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
icon: 'vim',
|
||||||
|
name: 'Dotfiles',
|
||||||
|
description: 'Some dotfiles.',
|
||||||
|
url: 'https://github.com/DefectingCat/dotfiles',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
icon: 'redux',
|
||||||
|
name: 'RUA-Context',
|
||||||
|
description: 'A global store for React.',
|
||||||
|
url: 'https://github.com/rua-plus/rua-context',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
icon: 'three',
|
||||||
|
name: 'RUA-Three',
|
||||||
|
description: 'A three.js hooks for React.',
|
||||||
|
url: 'https://github.com/rua-plus/rua-three',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const selfHosts: Project[] = [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
icon: 'gitea',
|
||||||
|
name: 'Gitea',
|
||||||
|
description: 'Selfhost git.',
|
||||||
|
url: 'https://git.rua.plus/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
icon: 'photos',
|
||||||
|
name: 'Photos',
|
||||||
|
description: 'Some photos.',
|
||||||
|
url: 'https://photos.rua.plus/browse',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<main className="max-w-4xl px-8 py-8 mx-auto lg:px-0">
|
||||||
|
<div>
|
||||||
|
{/* Git projects */}
|
||||||
|
<div>
|
||||||
|
<h1 className="mb-4 text-2xl">Projects</h1>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
'grid grid-cols-1 lg:grid-cols-3',
|
||||||
|
'md:grid-cols-2 gap-5'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{projects.map((item) => (
|
||||||
|
<ProjectCard
|
||||||
|
key={item.id}
|
||||||
|
icon={iconMap[item.icon ?? 'github']}
|
||||||
|
project={item}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-6">
|
||||||
|
<div>
|
||||||
|
<h1 className="mb-4 text-2xl">Seft Hosts</h1>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
'grid grid-cols-1 lg:grid-cols-3',
|
||||||
|
'md:grid-cols-2 gap-5'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{selfHosts.map((item) => (
|
||||||
|
<ProjectCard
|
||||||
|
key={item.id}
|
||||||
|
icon={iconMap[item.icon ?? 'github']}
|
||||||
|
project={item}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
62
app/projects/project-card.tsx
Normal file
62
app/projects/project-card.tsx
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import clsx from 'clsx';
|
||||||
|
import { Children, cloneElement, isValidElement, ReactElement } from 'react';
|
||||||
|
import { VscGithubInverted } from 'react-icons/vsc';
|
||||||
|
import { Project } from './page';
|
||||||
|
|
||||||
|
type ProjectCardProps = {
|
||||||
|
project: Project;
|
||||||
|
icon?: ReactElement<{ className?: string }>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ProjectCard = ({ project, icon }: ProjectCardProps) => {
|
||||||
|
const Icon = Children.map(icon, (child) => {
|
||||||
|
if (!isValidElement(child)) return child;
|
||||||
|
return cloneElement(child, {
|
||||||
|
className: 'w-8 h-8',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
'py-3 px-4 rounded-lg bg-slate-100',
|
||||||
|
'hover:bg-slate-200',
|
||||||
|
'transition-all duration-300',
|
||||||
|
'flex items-center cursor-pointer',
|
||||||
|
'justify-between dark:bg-rua-gray-800',
|
||||||
|
'hover:dark:bg-rua-gray-700'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{Icon ? Icon : <VscGithubInverted className="w-8 h-8" />}
|
||||||
|
|
||||||
|
<a
|
||||||
|
href={project.url}
|
||||||
|
className="w-[calc(100%_-_40px)]"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
<h2
|
||||||
|
className={clsx(
|
||||||
|
'text-xl overflow-hidden',
|
||||||
|
'text-ellipsis whitespace-nowrap'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{project.name}
|
||||||
|
</h2>
|
||||||
|
<span
|
||||||
|
className={clsx(
|
||||||
|
'overflow-hidden break-keep text-ellipsis',
|
||||||
|
'whitespace-nowrap inline-block',
|
||||||
|
'w-[inherit]'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{project.description}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProjectCard;
|
Reference in New Issue
Block a user