feat: Add base project structure with API and web components

This commit is contained in:
Ke Sun
2025-12-02 20:28:01 +08:00
parent f3de6d6cc9
commit c1adc62ec6
817 changed files with 111226 additions and 106 deletions

View File

@@ -0,0 +1,97 @@
import { type FC, type ReactNode } from 'react'
import { Card } from 'antd';
import clsx from 'clsx';
interface RbCardProps {
headerClassName?: string;
title?: string | ReactNode | (() => ReactNode);
subTitle?: string | ReactNode;
extra?: ReactNode;
children?: ReactNode;
avatar?: ReactNode;
avatarUrl?: string;
bodyPadding?: string;
bodyClassName?: string;
headerType?: 'border' | 'borderless' | 'borderBL' | 'borderL';
bgColor?: string;
height?: string;
className?: string;
onClick?: () => void;
}
const RbCard: FC<RbCardProps> = ({
headerClassName,
title,
subTitle,
extra,
children,
avatar,
avatarUrl,
bodyPadding,
bodyClassName: bodyClassNames,
headerType = 'border',
bgColor = '#FBFDFF',
height = 'auto',
className,
...props
}) => {
const bodyClassName = bodyPadding
? `rb:p-[${bodyPadding}]!`
: headerType === 'borderL'
? 'rb:p-[0_16px_12px_16px]!'
: avatarUrl || avatar
? 'rb:p-[16px_20px_16px_16px]!'
: (headerType === 'borderless')
? 'rb:p-[0_20px_16px_16px]!'
: (headerType === 'border' && !avatarUrl && !avatar) || headerType === 'borderBL'
? 'rb:p-[16px_16px_20px_16px]!'
: ''
return (
<Card
{...props}
title={typeof title === 'function' ? title() : title ?
<div className="rb:flex rb:items-center">
{avatarUrl
? <img src={avatarUrl} className="rb:mr-[13px] rb:w-[48px] rb:h-[48px] rb:rounded-[8px]" />
: avatar ? avatar : null
}
<div className={
clsx(
{
'rb:max-w-full': !avatarUrl && !avatar,
'rb:max-w-[calc(100%-60px)]': avatarUrl || avatar,
}
)
}>
<div className="rb:w-full rb:text-ellipsis rb:overflow-hidden rb:whitespace-nowrap">{title}</div>
{subTitle && <div className="rb:text-[#5B6167] rb:text-[12px]">{subTitle}</div>}
</div>
</div> : null
}
extra={extra}
classNames={{
header: clsx(
'rb:font-medium',
{
'rb:border-[0]! rb:text-[16px] rb:p-[0_16px]!': headerType === 'borderless',
'rb:border-[0]! rb:text-[16px] rb:p-[16px_16px_0_16px]!': avatarUrl || avatar,
'rb:text-[18px] rb:p-[0]! rb:m-[0_20px]!': headerType === 'border' && !avatarUrl && !avatar,
"rb:m-[0_16px]! rb:p-[0]! rb:relative rb:before:content-[''] rb:before:w-[4px] rb:before:h-[16px] rb:before:bg-[#5B6167] rb:before:absolute rb:before:top-[50%] rb:before:left-[-16px] rb:before:translate-y-[-50%] rb:before:bg-[#5B6167]! rb:before:h-[16px]!": headerType === 'borderBL',
"rb:m-[0_16px]! rb:p-[0]! rb:leading-[20px] rb:min-h-[48px]! rb:relative rb:border-[0]! rb:before:content-[''] rb:before:w-[4px] rb:before:h-[16px] rb:before:bg-[#5B6167] rb:before:absolute rb:before:top-[50%] rb:before:left-[-16px] rb:before:translate-y-[-50%] rb:before:bg-[#5B6167]! rb:before:h-[16px]!": headerType === 'borderL',
},
headerClassName,
),
body: bodyClassNames ? bodyClassNames : children ? bodyClassName : 'rb:p-[0]!',
}}
style={{
background: bgColor,
height: height
}}
className={`rb:hover:shadow-[0px_2px_4px_0px_rgba(0,0,0,0.15)] ${className}`}
>
{children}
</Card>
)
}
export default RbCard

View File

@@ -0,0 +1,73 @@
import { type FC, type ReactNode } from 'react'
import { Card } from 'antd';
import clsx from 'clsx';
interface RbCardProps {
title?: string | ReactNode;
subTitle?: string;
extra?: ReactNode;
children: ReactNode;
avatar?: ReactNode;
className?: string;
}
const RbCard: FC<RbCardProps> = ({
title,
subTitle,
extra,
children,
avatar,
className,
}) => {
if (avatar) {
return (
<Card
classNames={{
header: 'rb:p-[0]! rb:m-[0_20px]!',
body: 'rb:p-[16px_20px_16px_16px]',
}}
style={{
background: '#FBFDFF'
}}
>
{title &&
<div className={clsx("rb:text-[#212332] rb:text-[16px] rb:font-medium rb:flex rb:items-center rb:mb-[20px]", {
'rb:justify-between': extra
})}>
<div className="rb:flex rb:items-center">
<div className="rb:mr-[13px] rb:w-[48px] rb:h-[48px] rb:rounded-[8px] rb:overflow-hidden">{avatar}</div>
<div className="rb:truncate">{title}</div>
</div>
{subTitle && <div className="rb:text-[#5B6167] rb:text-[12px]">{subTitle}</div>}
{extra}
</div>
}
{children}
</Card>
)
}
return (
<Card
title={ title ?
<div className={clsx("rb:text-[#212332] rb:text-[18px] rb:font-medium rb:flex rb:items-center", {
'rb:justify-between': extra
})}>
<div className="rb:truncate">{title}</div>
{subTitle && <div className="rb:text-[#5B6167] rb:text-[12px]">{subTitle}</div>}
{extra}
</div> : null
}
classNames={{
header: 'rb:p-[0]! rb:m-[0_20px]!',
body: `rb:p-[16px_20px_20px_16px] ${className || ''}`,
}}
style={{
background: '#FBFDFF'
}}
>
{children}
</Card>
)
}
export default RbCard