feat: import animal-island-ui snapshot
@@ -0,0 +1,465 @@
|
||||
import React, { useState, useEffect, useCallback, Suspense, lazy } from 'react';
|
||||
import { Cursor, Loading } from '../src';
|
||||
import '../src/styles/index.less';
|
||||
import '@fontsource/nunito/latin-500.css';
|
||||
import '@fontsource/nunito/latin-700.css';
|
||||
import '@fontsource/nunito/latin-900.css';
|
||||
import '@fontsource/noto-sans-sc/latin-400.css';
|
||||
import '@fontsource/noto-sans-sc/latin-500.css';
|
||||
import '@fontsource/noto-sans-sc/latin-700.css';
|
||||
import '@fontsource/noto-sans-sc/chinese-simplified-400.css';
|
||||
import '@fontsource/noto-sans-sc/chinese-simplified-500.css';
|
||||
import '@fontsource/noto-sans-sc/chinese-simplified-700.css';
|
||||
import '@fontsource/zen-maru-gothic/latin-500.css';
|
||||
import '@fontsource/zen-maru-gothic/latin-700.css';
|
||||
import '@fontsource/zen-maru-gothic/latin-900.css';
|
||||
import '@fontsource/zen-maru-gothic/japanese-500.css';
|
||||
import '@fontsource/zen-maru-gothic/japanese-700.css';
|
||||
import '@fontsource/zen-maru-gothic/japanese-900.css';
|
||||
import HomePage from './HomePage';
|
||||
import { PAGE_INFO } from './pageInfo';
|
||||
import { useIsMobile } from './tools';
|
||||
|
||||
// Lazy-load ComponentPage so homepage does not pull in every demo on initial load
|
||||
const ComponentPage = lazy(() => import('./ComponentPage'));
|
||||
|
||||
// ============================================
|
||||
// Simple hash router
|
||||
// ============================================
|
||||
const useHash = () => {
|
||||
const [hash, setHash] = useState(
|
||||
() => window.location.hash.slice(1) || '/'
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const onHashChange = () =>
|
||||
setHash(window.location.hash.slice(1) || '/');
|
||||
window.addEventListener('hashchange', onHashChange);
|
||||
return () => window.removeEventListener('hashchange', onHashChange);
|
||||
}, []);
|
||||
|
||||
const navigate = useCallback((path: string) => {
|
||||
window.location.hash = path;
|
||||
}, []);
|
||||
|
||||
return { hash, navigate };
|
||||
};
|
||||
|
||||
interface MenuItemChild {
|
||||
key: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
interface MenuItem {
|
||||
key: string;
|
||||
label: string;
|
||||
children?: MenuItemChild[];
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Menu config
|
||||
// ============================================
|
||||
const MENU_ITEMS: MenuItem[] = [
|
||||
{
|
||||
key: 'cat-basic',
|
||||
label: '── 基础组件 ──',
|
||||
children: [
|
||||
{ key: 'button', label: 'Button 按钮' },
|
||||
{ key: 'input', label: 'Input 输入框' },
|
||||
{ key: 'switch', label: 'Switch 开关' },
|
||||
{ key: 'card', label: 'Card 卡片' },
|
||||
{ key: 'collapse', label: 'Collapse 折叠面板' },
|
||||
{ key: 'cursor', label: 'Cursor 光标' },
|
||||
{ key: 'modal', label: 'Modal 弹窗' },
|
||||
{ key: 'typewriter', label: 'Typewriter 打字机' },
|
||||
{ key: 'divider-comp', label: 'Divider 分割线' },
|
||||
{ key: 'icon', label: 'Icon 图标' },
|
||||
{ key: 'select', label: 'Select 选择器' },
|
||||
{ key: 'checkbox', label: 'Checkbox 多选框' },
|
||||
{ key: 'tabs', label: 'Tabs 标签页' },
|
||||
{ key: 'footer', label: 'Footer 页脚' },
|
||||
{ key: 'codeblock', label: 'CodeBlock 代码高亮' },
|
||||
{ key: 'loading', label: 'Loading 加载' },
|
||||
{ key: 'table', label: 'Table 表格' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'cat-complex',
|
||||
label: '── 复杂组件 ──',
|
||||
children: [
|
||||
{ key: 'time', label: 'Time 时间' },
|
||||
{ key: 'phone', label: 'Phone 手机' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
// ============================================
|
||||
// Shared styles
|
||||
// ============================================
|
||||
const S = {
|
||||
layout: {
|
||||
display: 'flex',
|
||||
height: '100dvh',
|
||||
overflow: 'hidden',
|
||||
fontFamily: "Nunito, 'Noto Sans SC', 'Zen Maru Gothic', -apple-system, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif",
|
||||
background: `url(${new URL('./img/content_bg_pc.jpg', import.meta.url).href}) center / auto repeat`,
|
||||
} as React.CSSProperties,
|
||||
sidebar: {
|
||||
width: 220,
|
||||
minWidth: 220,
|
||||
background: `url(${new URL('./img/menu_bg.svg', import.meta.url).href}) center/cover no-repeat`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
overflow: 'hidden',
|
||||
} as React.CSSProperties,
|
||||
homeBg: {
|
||||
background: `url(${new URL('./img/home_bg.webp', import.meta.url).href}) 0 0 / auto repeat, #7DC395`,
|
||||
animation: 'bgScroll 80s linear infinite',
|
||||
} as React.CSSProperties,
|
||||
sidebarHeader: {
|
||||
padding: '20px 16px 12px',
|
||||
borderBottom: '1px solid #e8e2d6',
|
||||
fontWeight: 700,
|
||||
fontSize: 15,
|
||||
color: '#725d42',
|
||||
letterSpacing: -0.3,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
} as React.CSSProperties,
|
||||
menuList: {
|
||||
flex: 1,
|
||||
overflow: 'auto',
|
||||
padding: '8px 0',
|
||||
} as React.CSSProperties,
|
||||
menuItem: (active: boolean) =>
|
||||
({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
margin: '1px 5px',
|
||||
height: 40,
|
||||
padding: '0 16px',
|
||||
fontFamily: "Nunito, 'Noto Sans SC', 'Zen Maru Gothic', -apple-system, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif",
|
||||
fontStyle: 'normal',
|
||||
fontWeight: 600,
|
||||
fontSize: 14,
|
||||
paddingLeft: 26,
|
||||
color: active ? '#fff' : '#8a7b66',
|
||||
background: active ? '#B7C6E5' : 'transparent',
|
||||
borderRadius: 12,
|
||||
borderRight: 'none',
|
||||
transition: 'all 0.15s',
|
||||
}) as React.CSSProperties,
|
||||
main: {
|
||||
flex: 1,
|
||||
overflow: 'auto',
|
||||
padding: '32px 40px',
|
||||
} as React.CSSProperties,
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// Sidebar content (shared between desktop & mobile drawer)
|
||||
// ============================================
|
||||
const SidebarContent: React.FC<{
|
||||
activeKey: string;
|
||||
onNavigate: (path: string) => void;
|
||||
}> = ({ activeKey, onNavigate }) => (
|
||||
<>
|
||||
<div style={S.sidebarHeader} onClick={() => onNavigate('/')}>
|
||||
<img
|
||||
src={new URL('./img/nook-phone/nook1.svg', import.meta.url).href}
|
||||
style={{ width: 24, height: 24, marginRight: 8 }}
|
||||
alt="nook"
|
||||
/>
|
||||
集合啦!Animal
|
||||
</div>
|
||||
<nav style={S.menuList}>
|
||||
{MENU_ITEMS.map((item) => {
|
||||
if (item.children) {
|
||||
return (
|
||||
<div key={item.key}>
|
||||
<div
|
||||
style={{
|
||||
padding: '12px 16px 4px',
|
||||
fontSize: 11,
|
||||
color: '#a0936e',
|
||||
fontWeight: 600,
|
||||
letterSpacing: 0.5,
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
</div>
|
||||
{item.children.map((child) => (
|
||||
<div
|
||||
key={child.key}
|
||||
style={S.menuItem(activeKey === child.key)}
|
||||
onClick={() => onNavigate(`/${child.key}`)}
|
||||
onMouseEnter={(e) => {
|
||||
if (activeKey !== child.key)
|
||||
e.currentTarget.style.background = '#d6dff0';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (activeKey !== child.key)
|
||||
e.currentTarget.style.background = 'transparent';
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: activeKey === child.key ? '#fff' : '#8a7b66',
|
||||
}}
|
||||
>
|
||||
{child.label}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div
|
||||
key={item.key}
|
||||
style={S.menuItem(activeKey === item.key)}
|
||||
onClick={() => onNavigate(`/${item.key}`)}
|
||||
onMouseEnter={(e) => {
|
||||
if (activeKey !== item.key)
|
||||
e.currentTarget.style.background = '#d6dff0';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (activeKey !== item.key)
|
||||
e.currentTarget.style.background = 'transparent';
|
||||
}}
|
||||
>
|
||||
<span style={{ color: activeKey === item.key ? '#fff' : '#8a7b66' }}>
|
||||
{item.label}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
</>
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// App
|
||||
// ============================================
|
||||
const App: React.FC = () => {
|
||||
const { hash, navigate } = useHash();
|
||||
const isMobile = useIsMobile();
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
const [loadingActive, setLoadingActive] = useState(false);
|
||||
const [loadingMounted, setLoadingMounted] = useState(false);
|
||||
const mainRef = React.useRef<HTMLElement>(null);
|
||||
|
||||
const activeKey =
|
||||
hash.startsWith('/') && hash.length > 1 ? hash.slice(1) : 'home';
|
||||
const isHomePage = activeKey === 'home';
|
||||
|
||||
// Close drawer when switching to desktop
|
||||
useEffect(() => {
|
||||
if (!isMobile) setDrawerOpen(false);
|
||||
}, [isMobile]);
|
||||
|
||||
// Close drawer when route changes + scroll main to top
|
||||
useEffect(() => {
|
||||
setDrawerOpen(false);
|
||||
mainRef.current?.scrollTo({ top: 0 });
|
||||
}, [activeKey]);
|
||||
|
||||
const handleNavigate = useCallback(
|
||||
(path: string) => {
|
||||
navigate(path);
|
||||
setDrawerOpen(false);
|
||||
},
|
||||
[navigate]
|
||||
);
|
||||
|
||||
// 首页跳转到组件页时显示 2s Loading 覆盖层
|
||||
const handleHomeNavigate = useCallback(
|
||||
(path: string) => {
|
||||
setLoadingMounted(true);
|
||||
setLoadingActive(true);
|
||||
navigate(path);
|
||||
// 2s 后开始关闭,再多留 1.5s 给关闭扩散动画后卸载
|
||||
window.setTimeout(() => setLoadingActive(false), 2000);
|
||||
window.setTimeout(() => setLoadingMounted(false), 3500);
|
||||
},
|
||||
[navigate]
|
||||
);
|
||||
|
||||
return (
|
||||
<Cursor>
|
||||
<style>{`
|
||||
@keyframes bgScroll {
|
||||
0% { background-position: 100% 0%; }
|
||||
100% { background-position: 0% 100%; }
|
||||
}
|
||||
`}</style>
|
||||
{isHomePage ? (
|
||||
/* Home page — full screen, no sidebar */
|
||||
<div
|
||||
style={{
|
||||
...S.layout,
|
||||
...S.homeBg,
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<HomePage onNavigate={handleHomeNavigate} />
|
||||
</div>
|
||||
) : (
|
||||
/* Component page — with sidebar */
|
||||
<div style={S.layout}>
|
||||
{/* Desktop sidebar */}
|
||||
{!isMobile && (
|
||||
<aside style={S.sidebar}>
|
||||
<SidebarContent
|
||||
activeKey={activeKey}
|
||||
onNavigate={handleNavigate}
|
||||
/>
|
||||
</aside>
|
||||
)}
|
||||
|
||||
{/* Mobile top bar */}
|
||||
{isMobile && (
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: 52,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
padding: '0 12px',
|
||||
background: 'rgba(255,252,244,0.92)',
|
||||
backdropFilter: 'blur(8px)',
|
||||
borderBottom: '1px solid #e8e2d6',
|
||||
zIndex: 50,
|
||||
fontFamily: S.layout.fontFamily,
|
||||
}}
|
||||
>
|
||||
<button
|
||||
onClick={() => navigate('/')}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
fontSize: 20,
|
||||
color: '#725d42',
|
||||
padding: '4px 8px',
|
||||
borderRadius: 8,
|
||||
lineHeight: 1,
|
||||
}}
|
||||
>
|
||||
←
|
||||
</button>
|
||||
<span
|
||||
style={{
|
||||
fontWeight: 700,
|
||||
fontSize: 15,
|
||||
color: '#725d42',
|
||||
}}
|
||||
>
|
||||
{PAGE_INFO[activeKey]?.title ?? '组件文档'}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => setDrawerOpen(true)}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
fontSize: 20,
|
||||
color: '#725d42',
|
||||
padding: '4px 8px',
|
||||
borderRadius: 8,
|
||||
lineHeight: 1,
|
||||
}}
|
||||
>
|
||||
☰
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Mobile drawer overlay */}
|
||||
{isMobile && drawerOpen && (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
background: 'rgba(0,0,0,0.35)',
|
||||
zIndex: 98,
|
||||
}}
|
||||
onClick={() => setDrawerOpen(false)}
|
||||
/>
|
||||
<aside
|
||||
style={{
|
||||
...S.sidebar,
|
||||
position: 'fixed',
|
||||
left: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
width: 240,
|
||||
zIndex: 99,
|
||||
boxShadow: '4px 0 24px rgba(0,0,0,0.15)',
|
||||
}}
|
||||
>
|
||||
<SidebarContent
|
||||
activeKey={activeKey}
|
||||
onNavigate={handleNavigate}
|
||||
/>
|
||||
</aside>
|
||||
</>
|
||||
)}
|
||||
|
||||
<main
|
||||
ref={mainRef}
|
||||
style={{
|
||||
...S.main,
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
padding: isMobile ? '16px' : '32px 40px',
|
||||
paddingTop: isMobile ? 68 : 32,
|
||||
}}
|
||||
>
|
||||
<Suspense fallback={null}>
|
||||
<ComponentPage activeKey={activeKey} />
|
||||
</Suspense>
|
||||
</main>
|
||||
|
||||
{!isMobile && (
|
||||
<img
|
||||
src={
|
||||
new URL('./img/guide-bg-line.webp', import.meta.url).href
|
||||
}
|
||||
alt=""
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
style={{
|
||||
position: 'fixed',
|
||||
left: 220,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
width: 'calc(100% - 220px)',
|
||||
pointerEvents: 'none',
|
||||
zIndex: 0,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{/* 首页跳转组件页的过场 Loading,全屏覆盖 */}
|
||||
{loadingMounted && (
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
zIndex: 9999,
|
||||
pointerEvents: loadingActive ? 'auto' : 'none',
|
||||
}}
|
||||
>
|
||||
<Loading active={loadingActive} />
|
||||
</div>
|
||||
)}
|
||||
</Cursor>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,578 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Card, Divider, Button, Switch, Collapse, Typewriter } from '../src';
|
||||
import { useIsMobile } from './tools';
|
||||
|
||||
// ============================================
|
||||
// Syntax highlighting
|
||||
// ============================================
|
||||
const HL_TOKENS: { pattern: RegExp; style: React.CSSProperties }[] = [
|
||||
{
|
||||
pattern: /(\/\/.*$|\/\*[\s\S]*?\*\/)/gm,
|
||||
style: { color: '#6b5e50', fontStyle: 'italic', fontWeight: 400 },
|
||||
},
|
||||
{
|
||||
pattern: /("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`)/g,
|
||||
style: { color: '#a8d4a0' },
|
||||
},
|
||||
{ pattern: /(<\/?[\w.]+|\/?>)/g, style: { color: '#f0a870' } },
|
||||
{
|
||||
pattern:
|
||||
/\b(import|from|const|let|var|function|return|export|default|true|false|null|undefined)\b/g,
|
||||
style: { color: '#d4a0e0' },
|
||||
},
|
||||
{ pattern: /\b(npm|yarn|pnpm)\b/g, style: { color: '#f0a870' } },
|
||||
{
|
||||
pattern: /(install|uninstall|run|add|remove)\b/g,
|
||||
style: { color: '#a8d4a0' },
|
||||
},
|
||||
{ pattern: /(\{|\})/g, style: { color: '#d4b896' } },
|
||||
{ pattern: /(=>)/g, style: { color: '#d4a0e0' } },
|
||||
{ pattern: /(--[\w-]+)(?=\s*:)/g, style: { color: '#e8c87a' } },
|
||||
{ pattern: /(:root)/g, style: { color: '#f0a870' } },
|
||||
{ pattern: /(#[0-9a-fA-F]{3,8})\b/g, style: { color: '#8ab8e0' } },
|
||||
];
|
||||
|
||||
const highlightCode = (code: string): React.ReactNode[] => {
|
||||
const parts: React.ReactNode[] = [];
|
||||
const lines = code.split('\n');
|
||||
lines.forEach((line, li) => {
|
||||
type Seg = { start: number; end: number; style: React.CSSProperties };
|
||||
const segs: Seg[] = [];
|
||||
for (const t of HL_TOKENS) {
|
||||
const re = new RegExp(t.pattern.source, t.pattern.flags);
|
||||
let m: RegExpExecArray | null;
|
||||
while ((m = re.exec(line)) !== null) {
|
||||
const s =
|
||||
m.index + (m[0] !== m[1] && m[1] ? m[0].indexOf(m[1]) : 0);
|
||||
const text = m[1] || m[0];
|
||||
segs.push({ start: s, end: s + text.length, style: t.style });
|
||||
}
|
||||
}
|
||||
segs.sort((a, b) => a.start - b.start);
|
||||
const merged: Seg[] = [];
|
||||
for (const seg of segs) {
|
||||
if (
|
||||
merged.length === 0 ||
|
||||
seg.start >= merged[merged.length - 1].end
|
||||
)
|
||||
merged.push(seg);
|
||||
}
|
||||
let idx = 0;
|
||||
for (const seg of merged) {
|
||||
if (seg.start > idx) parts.push(line.slice(idx, seg.start));
|
||||
parts.push(
|
||||
<span key={`${li}-${seg.start}`} style={seg.style}>
|
||||
{line.slice(seg.start, seg.end)}
|
||||
</span>
|
||||
);
|
||||
idx = seg.end;
|
||||
}
|
||||
if (idx < line.length) parts.push(line.slice(idx));
|
||||
if (li < lines.length - 1) parts.push('\n');
|
||||
});
|
||||
return parts;
|
||||
};
|
||||
|
||||
const CodeBlock: React.FC<{ code: string }> = ({ code }) => (
|
||||
<pre style={S.codeBox}>{highlightCode(code)}</pre>
|
||||
);
|
||||
|
||||
const FeatureCard: React.FC<{ feature: typeof features[0] }> = ({ feature }) => {
|
||||
const [hovered, setHovered] = useState(false);
|
||||
return (
|
||||
<Card
|
||||
style={{
|
||||
...S.featureCard,
|
||||
transform: hovered ? 'translateY(-4px)' : 'none',
|
||||
boxShadow: hovered
|
||||
? '0 8px 24px rgba(114, 93, 66, 0.15)'
|
||||
: 'none',
|
||||
transition: 'all 0.3s ease',
|
||||
}}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
>
|
||||
<img
|
||||
src={
|
||||
new URL(
|
||||
`./img/nook-phone/${feature.icon}`,
|
||||
import.meta.url
|
||||
).href
|
||||
}
|
||||
style={{
|
||||
width: 42,
|
||||
height: 42,
|
||||
transform: hovered
|
||||
? 'scale(1.1) rotate(-4deg)'
|
||||
: 'scale(1) rotate(0deg)',
|
||||
transition: 'transform 0.3s ease',
|
||||
animation: hovered ? 'iconBounce 0.4s ease forwards' : 'none',
|
||||
}}
|
||||
alt={feature.title}
|
||||
/>
|
||||
<style>
|
||||
{`
|
||||
@keyframes iconBounce {
|
||||
0% { transform: scale(1) rotate(0deg); }
|
||||
50% { transform: scale(1.2) rotate(-5deg); }
|
||||
100% { transform: scale(1.1) rotate(-4deg); }
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
<div style={S.featureTitle}>{feature.title}</div>
|
||||
<div style={S.featureDesc}>{feature.desc}</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// Styles
|
||||
// ============================================
|
||||
const S = {
|
||||
page: {
|
||||
width: '100%',
|
||||
minHeight: '100vh',
|
||||
overflowY: 'auto',
|
||||
overflowX: 'hidden',
|
||||
} as React.CSSProperties,
|
||||
|
||||
// Hero
|
||||
hero: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
minHeight: '100vh',
|
||||
padding: '60px 40px 40px',
|
||||
position: 'relative',
|
||||
} as React.CSSProperties,
|
||||
heroContent: {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '1fr 1fr',
|
||||
gap: 150,
|
||||
alignItems: 'center',
|
||||
maxWidth: 880,
|
||||
width: '100%',
|
||||
} as React.CSSProperties,
|
||||
heroContentMobile: {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '1fr',
|
||||
gap: 32,
|
||||
alignItems: 'center',
|
||||
maxWidth: 880,
|
||||
width: '100%',
|
||||
} as React.CSSProperties,
|
||||
heroText: {
|
||||
textAlign: 'left' as const,
|
||||
} as React.CSSProperties,
|
||||
heroLogo: {
|
||||
fontSize: 72,
|
||||
lineHeight: 1,
|
||||
marginBottom: 16,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
} as React.CSSProperties,
|
||||
heroTitle: {
|
||||
fontFamily: "Nunito, 'Zen Maru Gothic', -apple-system, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif",
|
||||
fontSize: 55,
|
||||
fontWeight: 800,
|
||||
lineHeight: 1.1,
|
||||
color: '#FFF9E6',
|
||||
textShadow: '0px 4px 1px rgba(0, 0, 0, 0.4)',
|
||||
margin: '0 0 12px',
|
||||
} as React.CSSProperties,
|
||||
heroVersion: {
|
||||
display: 'inline-block',
|
||||
fontSize: 12,
|
||||
fontWeight: 600,
|
||||
padding: '2px 10px',
|
||||
borderRadius: 10,
|
||||
background: '#e6f9f6',
|
||||
color: '#19c8b9',
|
||||
marginLeft: 8,
|
||||
verticalAlign: 'middle',
|
||||
textShadow: 'none',
|
||||
} as React.CSSProperties,
|
||||
heroSubtitle: {
|
||||
fontSize: 17,
|
||||
color: '#7c5734',
|
||||
lineHeight: 1.7,
|
||||
margin: '0 0 28px',
|
||||
maxWidth: 520,
|
||||
} as React.CSSProperties,
|
||||
heroActions: {
|
||||
display: 'flex',
|
||||
gap: 16,
|
||||
alignItems: 'center',
|
||||
} as React.CSSProperties,
|
||||
|
||||
// Sections
|
||||
section: {
|
||||
padding: '48px 40px',
|
||||
maxWidth: 960,
|
||||
margin: '0 auto',
|
||||
} as React.CSSProperties,
|
||||
sectionTitle: {
|
||||
fontFamily: "Nunito, 'Zen Maru Gothic', -apple-system, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif",
|
||||
fontSize: 24,
|
||||
fontWeight: 700,
|
||||
color: '#725d42',
|
||||
margin: '0 0 8px',
|
||||
textAlign: 'center' as const,
|
||||
} as React.CSSProperties,
|
||||
sectionDesc: {
|
||||
fontSize: 14,
|
||||
color: '#7c5734',
|
||||
textAlign: 'center' as const,
|
||||
marginBottom: 32,
|
||||
} as React.CSSProperties,
|
||||
|
||||
// Features
|
||||
features: {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
|
||||
gap: 16,
|
||||
} as React.CSSProperties,
|
||||
featureCard: {
|
||||
padding: '24px 20px',
|
||||
textAlign: 'center' as const,
|
||||
} as React.CSSProperties,
|
||||
featureIcon: { fontSize: 32, marginBottom: 12 } as React.CSSProperties,
|
||||
featureTitle: {
|
||||
fontSize: 15,
|
||||
fontWeight: 700,
|
||||
color: '#725d42',
|
||||
marginBottom: 6,
|
||||
} as React.CSSProperties,
|
||||
featureDesc: {
|
||||
fontSize: 13,
|
||||
color: '#7c5734',
|
||||
lineHeight: 1.6,
|
||||
display: '-webkit-box' as const,
|
||||
WebkitLineClamp: 3,
|
||||
WebkitBoxOrient: 'vertical' as const,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis' as const,
|
||||
} as React.CSSProperties,
|
||||
|
||||
// Component grid
|
||||
compGrid: {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
|
||||
gap: 12,
|
||||
} as React.CSSProperties,
|
||||
compCard: {
|
||||
padding: '16px 20px',
|
||||
cursor: 'pointer',
|
||||
} as React.CSSProperties,
|
||||
compName: {
|
||||
fontSize: 15,
|
||||
fontWeight: 700,
|
||||
color: '#725d42',
|
||||
marginBottom: 4,
|
||||
} as React.CSSProperties,
|
||||
compDesc: {
|
||||
fontSize: 12,
|
||||
color: '#7c5734',
|
||||
lineHeight: 1.5,
|
||||
} as React.CSSProperties,
|
||||
|
||||
// Code block
|
||||
codeBox: {
|
||||
maxWidth: 600,
|
||||
margin: '0 auto',
|
||||
padding: '20px 28px',
|
||||
background: '#2b2118',
|
||||
border: '1px solid #3d3028',
|
||||
borderRadius: 20,
|
||||
fontFamily: "'SF Mono', 'Fira Code', Consolas, monospace",
|
||||
fontSize: 13,
|
||||
fontWeight: 600,
|
||||
color: '#e8d5bc',
|
||||
textAlign: 'left' as const,
|
||||
lineHeight: 1.8,
|
||||
whiteSpace: 'pre' as const,
|
||||
overflow: 'auto' as const,
|
||||
tabSize: 4,
|
||||
} as React.CSSProperties,
|
||||
|
||||
// Footer
|
||||
footer: {
|
||||
padding: '32px 40px',
|
||||
textAlign: 'center' as const,
|
||||
fontSize: 12,
|
||||
color: '#7c5734',
|
||||
marginTop: 32,
|
||||
} as React.CSSProperties,
|
||||
footerLinks: {
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
gap: 20,
|
||||
marginBottom: 12,
|
||||
} as React.CSSProperties,
|
||||
footerLink: {
|
||||
fontSize: 13,
|
||||
color: '#7c5734',
|
||||
cursor: 'pointer',
|
||||
} as React.CSSProperties,
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// Data
|
||||
// ============================================
|
||||
const features = [
|
||||
{
|
||||
icon: 'nook1.svg',
|
||||
title: 'Animal风格',
|
||||
desc: 'SVG 有机形状裁切,3D 按压按钮,温暖质朴的自然 UI 质感',
|
||||
},
|
||||
{
|
||||
icon: 'Property-Shopping.svg',
|
||||
title: '18 个组件',
|
||||
desc: 'Button / Input / Switch / Modal / Typewriter / Card / Collapse / Cursor / Divider / Time / Phone / Footer / Icon / Checkbox / Select / Tabs / CodeBlock / Loading 等',
|
||||
},
|
||||
{
|
||||
icon: 'Property-Camera.svg',
|
||||
title: '主题定制',
|
||||
desc: '40+ CSS 自定义属性,运行时换肤无需重新构建',
|
||||
},
|
||||
{
|
||||
icon: 'Property-Recipes.svg',
|
||||
title: '开箱即用',
|
||||
desc: 'ESM + CJS 双格式输出,TypeScript 类型声明完整',
|
||||
},
|
||||
];
|
||||
|
||||
const components = [
|
||||
{
|
||||
key: 'button',
|
||||
name: 'Button',
|
||||
desc: '5 种类型、3 种尺寸、加载/危险/幽灵模式',
|
||||
},
|
||||
{ key: 'input', name: 'Input', desc: '前后缀、一键清空、校验状态' },
|
||||
{
|
||||
key: 'switch',
|
||||
name: 'Switch',
|
||||
desc: '受控/非受控、自定义文案、加载状态',
|
||||
},
|
||||
{ key: 'checkbox', name: 'Checkbox', desc: '多选框组件,支持水平/垂直排列' },
|
||||
{
|
||||
key: 'select',
|
||||
name: 'Select',
|
||||
desc: '下拉选择器,支持搜索和禁用',
|
||||
},
|
||||
{ key: 'tabs', name: 'Tabs', desc: '标签页组件,支持受控/非受控模式' },
|
||||
{ key: 'modal', name: 'Modal', desc: 'SVG 有机形状弹窗、ESC 关闭' },
|
||||
{
|
||||
key: 'typewriter',
|
||||
name: 'Typewriter',
|
||||
desc: '逐字打字机效果,支持多行与富内容',
|
||||
},
|
||||
{ key: 'card', name: 'Card', desc: '默认/标题两种卡片风格' },
|
||||
{ key: 'collapse', name: 'Collapse', desc: 'FAQ 折叠面板、平滑展开动画' },
|
||||
{ key: 'cursor', name: 'Cursor', desc: '自定义手指光标,支持多种尺寸' },
|
||||
{ key: 'divider-comp', name: 'Divider', desc: '装饰性水平分割线' },
|
||||
{ key: 'icon', name: 'Icon', desc: 'SVG 图标库' },
|
||||
{ key: 'footer', name: 'Footer', desc: '页脚组件' },
|
||||
{ key: 'time', name: 'Time', desc: '可爱风格时间显示' },
|
||||
{ key: 'phone', name: 'Phone', desc: 'Phone 模拟器' },
|
||||
{ key: 'codeblock', name: 'CodeBlock', desc: '代码语法高亮组件' },
|
||||
{ key: 'loading', name: 'Loading', desc: '动森风格小岛加载动画' },
|
||||
];
|
||||
|
||||
// ============================================
|
||||
// HomePage
|
||||
// ============================================
|
||||
interface HomePageProps {
|
||||
onNavigate?: (path: string) => void;
|
||||
}
|
||||
|
||||
const HomePage: React.FC<HomePageProps> = ({ onNavigate }) => {
|
||||
const isMobile = useIsMobile();
|
||||
const [showScrollHint, setShowScrollHint] = useState(true);
|
||||
const pageRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
const handleScroll = () => {
|
||||
if (pageRef.current) {
|
||||
if (pageRef.current.scrollTop > 70) {
|
||||
setShowScrollHint(false);
|
||||
} else {
|
||||
setShowScrollHint(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div ref={pageRef} style={{ ...S.page, overflow: 'auto' }} onScroll={handleScroll}>
|
||||
{/* Hero */}
|
||||
<div style={{ ...S.hero }}>
|
||||
<div style={isMobile ? S.heroContentMobile : S.heroContent}>
|
||||
{isMobile && (
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<img
|
||||
src={
|
||||
new URL('./img/animal_icon.png', import.meta.url).href
|
||||
}
|
||||
style={{ width: 180, height: 112 }}
|
||||
alt="logo"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div style={isMobile ? { textAlign: 'center' as const } : S.heroText}>
|
||||
<h1 style={{ ...S.heroTitle, fontSize: isMobile ? 37 : 60 }}>
|
||||
{isMobile ? 'Animal Island UI' : <>Animal <br /> Island UI</>}
|
||||
<span style={S.heroVersion}>v0.8.1</span>
|
||||
</h1>
|
||||
<Typewriter speed={60}>
|
||||
<p style={{ ...S.heroSubtitle, fontSize: isMobile ? 14 : 17 }}>
|
||||
Animal风格的 React 组件库,基于 TypeScript + Vite 构建,让 Web 应用充满温暖质感
|
||||
</p>
|
||||
</Typewriter>
|
||||
<div style={{ ...S.heroActions, justifyContent: isMobile ? 'center' : 'flex-start' }}>
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
onClick={() => onNavigate?.('/button')}
|
||||
>
|
||||
开始使用 →
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{!isMobile && (
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<img
|
||||
src={
|
||||
new URL('./img/animal_icon.png', import.meta.url).href
|
||||
}
|
||||
style={{ width: 320, height: 200 }}
|
||||
alt="logo"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
position: 'absolute',
|
||||
bottom: 40,
|
||||
left: '50%',
|
||||
transform: 'translateX(-50%)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
gap: 4,
|
||||
cursor: 'pointer',
|
||||
animation: showScrollHint ? 'bounce 2s ease-in-out infinite' : 'none',
|
||||
opacity: showScrollHint ? 1 : 0,
|
||||
transition: 'opacity 0.3s ease',
|
||||
pointerEvents: showScrollHint ? 'auto' : 'none'
|
||||
}}>
|
||||
<span style={{ color: '#FFF9E6', fontSize: 12, textShadow: '0 1px 2px rgba(0,0,0,0.3)' }}>向下滑动</span>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M12 5v14M5 12l7 7 7-7" stroke="#FFF9E6" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
<style>{`
|
||||
@keyframes bounce {
|
||||
0%, 100% { transform: translateX(-50%) translateY(0); opacity: 1; }
|
||||
50% { transform: translateX(-50%) translateY(-8px); opacity: 0.7; }
|
||||
}
|
||||
`}</style>
|
||||
|
||||
{/* Features */}
|
||||
<div style={{ ...S.section, padding: isMobile ? '32px 16px' : '48px 40px' }}>
|
||||
<div style={S.sectionTitle}>特性</div>
|
||||
<div style={S.sectionDesc}>为什么选择 animal-island-ui</div>
|
||||
<div style={S.features}>
|
||||
{features.map((f) => (
|
||||
<FeatureCard key={f.title} feature={f} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider style={{ width: isMobile ? '90%' : 800, margin: '0 auto' }} />
|
||||
|
||||
{/* Components */}
|
||||
<div style={{ ...S.section, padding: isMobile ? '32px 16px' : '48px 40px' }}>
|
||||
<div style={S.sectionTitle}>组件一览</div>
|
||||
<div style={S.sectionDesc}>点击卡片查看详细文档和在线演示</div>
|
||||
<div style={S.compGrid}>
|
||||
{components.map((c) => (
|
||||
<Card
|
||||
key={c.key}
|
||||
style={S.compCard}
|
||||
onClick={() => onNavigate?.(`/${c.key}`)}
|
||||
>
|
||||
<div style={S.compName}>{c.name}</div>
|
||||
<div style={S.compDesc}>{c.desc}</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider style={{ width: isMobile ? '90%' : 800, margin: '0 auto' }} />
|
||||
|
||||
{/* Install */}
|
||||
<div style={{ ...S.section, padding: isMobile ? '32px 16px' : '48px 40px' }}>
|
||||
<div style={S.sectionTitle}>安装</div>
|
||||
<div style={S.sectionDesc}>一行命令即可安装</div>
|
||||
<CodeBlock
|
||||
code={`// 使用 npm 安装\nnpm install animal-island-ui`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Divider style={{ width: isMobile ? '90%' : 800, margin: '0 auto' }} />
|
||||
|
||||
{/* Quick Start */}
|
||||
<div style={{ ...S.section, padding: isMobile ? '32px 16px' : '48px 40px' }}>
|
||||
<div style={S.sectionTitle}>快速上手</div>
|
||||
<div style={S.sectionDesc}>引入组件即可使用,样式自动加载</div>
|
||||
<CodeBlock
|
||||
code={`// 1. 引入组件\nimport { Button, Modal, Switch } from 'animal-island-ui';\nimport 'animal-island-ui/style';\n\nfunction App() {\n return <Button>开始</Button>;\n}`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Divider style={{ width: isMobile ? '90%' : 800, margin: '0 auto' }} />
|
||||
|
||||
{/* Theme */}
|
||||
<div style={{ ...S.section, padding: isMobile ? '32px 16px' : '48px 40px' }}>
|
||||
<div style={S.sectionTitle}>主题定制</div>
|
||||
<div style={S.sectionDesc}>
|
||||
通过覆盖 CSS 自定义属性实现运行时换肤,无需重新构建
|
||||
</div>
|
||||
<CodeBlock
|
||||
code={`/* 覆盖主题变量 */\n:root {\n --animal-primary-color: #19c8b9;\n --animal-text-color: #827157;\n --animal-font-family: 'Noto Sans SC', sans-serif;\n --animal-border-radius-base: 18px;\n /* ... 40+ 设计令牌 */\n}`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div style={{ ...S.footer, padding: isMobile ? '24px 16px' : '32px 40px' }}>
|
||||
<div style={S.footerLinks}>
|
||||
<span
|
||||
style={S.footerLink}
|
||||
onClick={() => onNavigate?.('/button')}
|
||||
>
|
||||
组件文档
|
||||
</span>
|
||||
<span
|
||||
style={S.footerLink}
|
||||
onClick={() =>
|
||||
window.open(
|
||||
'https://github.com/guokaigdg/animal-island-ui',
|
||||
'_blank'
|
||||
)
|
||||
}
|
||||
>
|
||||
GitHub
|
||||
</span>
|
||||
</div>
|
||||
<div>MIT License · React + TypeScript + Vite</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default HomePage;
|
||||
@@ -0,0 +1,128 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Checkbox } from '../../../src';
|
||||
import {
|
||||
labelStyle,
|
||||
ApiTable,
|
||||
CodeBlock,
|
||||
ApiRow,
|
||||
sectionStyle,
|
||||
sectionTitleStyle,
|
||||
tagStyle,
|
||||
demoBoxStyle,
|
||||
} from '../../tools';
|
||||
|
||||
const CHECKBOX_API: ApiRow[] = [
|
||||
{ prop: 'options', desc: '选项列表', type: 'CheckboxOption[]', defaultVal: '-', required: true },
|
||||
{ prop: 'value', desc: '受控选中值列表', type: 'Array<string | number>', defaultVal: '-' },
|
||||
{ prop: 'defaultValue', desc: '默认选中值列表', type: 'Array<string | number>', defaultVal: '[]' },
|
||||
{ prop: 'size', desc: '尺寸', type: "'small' | 'middle' | 'large'", defaultVal: "'middle'" },
|
||||
{ prop: 'disabled', desc: '禁用全部选项', type: 'boolean', defaultVal: 'false' },
|
||||
{ prop: 'direction', desc: '排列方向', type: "'horizontal' | 'vertical'", defaultVal: "'horizontal'" },
|
||||
{ prop: 'onChange', desc: '选中值变化回调', type: '(values: Array<string | number>) => void', defaultVal: '-' },
|
||||
{ prop: 'className', desc: '自定义类名', type: 'string', defaultVal: '-' },
|
||||
{ prop: 'style', desc: '自定义样式', type: 'React.CSSProperties', defaultVal: '-' },
|
||||
];
|
||||
|
||||
const islandOptions = [
|
||||
{ label: '🌊 海滩', value: 'beach' },
|
||||
{ label: '🌳 森林', value: 'forest' },
|
||||
{ label: '🌸 花园', value: 'garden' },
|
||||
{ label: '🏡 村庄', value: 'village' },
|
||||
];
|
||||
|
||||
const critterOptions = [
|
||||
{ label: '🦋 蝴蝶', value: 'butterfly' },
|
||||
{ label: '🐟 鲈鱼', value: 'bass' },
|
||||
{ label: '🦀 螃蟹', value: 'crab', disabled: true },
|
||||
{ label: '🐛 毛毛虫', value: 'caterpillar' },
|
||||
{ label: '🌊 水母', value: 'jellyfish' },
|
||||
];
|
||||
|
||||
const CheckboxDemo: React.FC = () => {
|
||||
const [selected1, setSelected1] = useState<Array<string | number>>(['beach', 'garden']);
|
||||
const [selected2, setSelected2] = useState<Array<string | number>>([]);
|
||||
|
||||
return (
|
||||
<div style={sectionStyle}>
|
||||
<div style={sectionTitleStyle}>
|
||||
Checkbox <span style={tagStyle}>基础用法</span>
|
||||
</div>
|
||||
|
||||
<div style={labelStyle}>默认水平排列(受控)</div>
|
||||
<div style={{ marginBottom: 8, fontSize: 13, color: '#a08060' }}>
|
||||
已选中:{' '}
|
||||
<span style={{ color: '#19c8b9', fontWeight: 600 }}>
|
||||
{selected1.length > 0
|
||||
? islandOptions
|
||||
.filter((o) => selected1.includes(o.value))
|
||||
.map((o) => o.label)
|
||||
.join('、')
|
||||
: '无'}
|
||||
</span>
|
||||
</div>
|
||||
<div style={demoBoxStyle}>
|
||||
<Checkbox options={islandOptions} value={selected1} onChange={setSelected1} style={{ gap: 20 }} />
|
||||
</div>
|
||||
|
||||
<div style={labelStyle}>垂直排列 + 含禁用选项</div>
|
||||
<div style={demoBoxStyle}>
|
||||
<Checkbox
|
||||
options={critterOptions}
|
||||
value={selected2}
|
||||
onChange={setSelected2}
|
||||
direction="vertical"
|
||||
style={{ gap: 12 }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={labelStyle}>小尺寸</div>
|
||||
<div style={demoBoxStyle}>
|
||||
<Checkbox options={islandOptions} defaultValue={['forest']} size="small" />
|
||||
</div>
|
||||
|
||||
<div style={labelStyle}>中尺寸(默认)</div>
|
||||
<div style={demoBoxStyle}>
|
||||
<Checkbox options={islandOptions} defaultValue={['beach']} size="middle" />
|
||||
</div>
|
||||
|
||||
<div style={labelStyle}>大尺寸</div>
|
||||
<div style={demoBoxStyle}>
|
||||
<Checkbox options={islandOptions.slice(0, 3)} defaultValue={['beach']} size="large" />
|
||||
</div>
|
||||
|
||||
<div style={labelStyle}>全部禁用</div>
|
||||
<div style={demoBoxStyle}>
|
||||
<Checkbox options={islandOptions} defaultValue={['garden', 'village']} disabled />
|
||||
</div>
|
||||
|
||||
<CodeBlock
|
||||
code={`import React, { useState } from 'react';
|
||||
import { Checkbox } from 'animal-island-ui';
|
||||
|
||||
const options = [
|
||||
{ label: '🌊 海滩', value: 'beach' },
|
||||
{ label: '🌳 森林', value: 'forest' },
|
||||
{ label: '🌸 花园', value: 'garden' },
|
||||
];
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<div>
|
||||
{/* 非受控 */}
|
||||
<Checkbox options={options} defaultValue={['beach']} />
|
||||
{/* 受控 */}
|
||||
<Checkbox options={options} value={values} onChange={setValues} />
|
||||
{/* 垂直排列 */}
|
||||
<Checkbox options={options} direction="vertical" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;`}
|
||||
/>
|
||||
<ApiTable rows={CHECKBOX_API} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CheckboxDemo;
|
||||
@@ -0,0 +1,97 @@
|
||||
import React from 'react';
|
||||
import { CodeBlock } from '../../../src';
|
||||
import {
|
||||
labelStyle,
|
||||
ApiTable,
|
||||
ApiRow,
|
||||
sectionStyle,
|
||||
sectionTitleStyle,
|
||||
tagStyle,
|
||||
demoBoxStyle,
|
||||
CodeBlock as CodeBlockBase,
|
||||
} from '../../tools';
|
||||
|
||||
const CODEBLOCK_API: ApiRow[] = [
|
||||
{ prop: 'code', desc: '代码字符串', type: 'string', defaultVal: '-', required: true },
|
||||
{ prop: 'style', desc: '自定义样式', type: 'CSSProperties', defaultVal: '-' },
|
||||
{ prop: 'className', desc: '自定义类名', type: 'string', defaultVal: '-' },
|
||||
];
|
||||
|
||||
const CodeBlockDemo: React.FC = () => {
|
||||
return (
|
||||
<div style={sectionStyle}>
|
||||
<div style={sectionTitleStyle}>
|
||||
CodeBlock <span style={tagStyle}>代码高亮</span>
|
||||
</div>
|
||||
<div style={labelStyle}>基础用法</div>
|
||||
<div style={demoBoxStyle}>
|
||||
<CodeBlock
|
||||
code={`import React from 'react';
|
||||
import { Button } from 'animal-island-ui';
|
||||
|
||||
const App = () => (
|
||||
<Button type="primary">按钮</Button>
|
||||
);
|
||||
|
||||
export default App;`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={labelStyle}>自定义样式</div>
|
||||
<div style={demoBoxStyle}>
|
||||
<CodeBlock
|
||||
code={`import React from 'react';
|
||||
import { CodeBlock } from 'animal-island-ui';
|
||||
|
||||
<CodeBlock
|
||||
code={codeString}
|
||||
style={{ borderRadius: 5, backgroundColor: '#242c46ff' }}
|
||||
className="custom-code"
|
||||
/>`}
|
||||
style={{ borderRadius: 5, backgroundColor: '#242c46ff' }}
|
||||
/>
|
||||
</div>
|
||||
<CodeBlockBase
|
||||
code={`import React from 'react';
|
||||
import { CodeBlock } from 'animal-island-ui';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<div>
|
||||
{/* 基础用法 */}
|
||||
<CodeBlock code={'
|
||||
import React from 'react';
|
||||
import { Footer } from 'animal-island-ui';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<div>
|
||||
{/* sea 类型(默认) */}
|
||||
<Footer type="sea" />
|
||||
{/* tree 类型 */}
|
||||
<Footer type="tree" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;'}
|
||||
/>
|
||||
{/* 自定义样式 */}
|
||||
<CodeBlock
|
||||
code={codeString}
|
||||
style={{ borderRadius: 5, backgroundColor: '#242c46ff' }}
|
||||
className="custom-code"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;`}
|
||||
/>
|
||||
|
||||
<ApiTable rows={CODEBLOCK_API} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CodeBlockDemo;
|
||||
@@ -0,0 +1,45 @@
|
||||
import React from 'react';
|
||||
import { Footer as FooterComponent } from '../../../src';
|
||||
import { CodeBlock, ApiTable, ApiRow, sectionStyle, sectionTitleStyle, tagStyle, demoBodyStyle, labelStyle } from '../../tools';
|
||||
|
||||
const FooterDemo: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div style={sectionStyle}>
|
||||
<div style={sectionTitleStyle}>
|
||||
Footer <span style={tagStyle}>底部装饰</span>
|
||||
</div>
|
||||
<div style={labelStyle}>
|
||||
Footer 组件 — 页面底部装饰图片,支持 sea(海)和 tree(树)两种类型。
|
||||
</div>
|
||||
<div style={{ ...demoBodyStyle, padding: '40px 0' }}>
|
||||
<div style={labelStyle}>tree 类型(默认)</div>
|
||||
<FooterComponent />
|
||||
</div>
|
||||
<div style={{ ...demoBodyStyle, padding: '40px 0' }}>
|
||||
<div style={labelStyle}>sea 类型</div>
|
||||
<FooterComponent type="sea" />
|
||||
</div>
|
||||
<CodeBlock
|
||||
code={`import React from 'react';
|
||||
import { Footer } from 'animal-island-ui';
|
||||
|
||||
const App = () => (
|
||||
<div>
|
||||
<Footer />
|
||||
<Footer type="sea" />
|
||||
</div>
|
||||
);`}
|
||||
/>
|
||||
<ApiTable rows={FOOTER_API} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const FOOTER_API: ApiRow[] = [
|
||||
{ prop: 'type', desc: 'Footer 类型', type: "'sea' | 'tree'", defaultVal: "'tree'" },
|
||||
{ prop: 'className', desc: '自定义类名', type: 'string', defaultVal: '-' },
|
||||
{ prop: 'style', desc: '自定义样式', type: 'CSSProperties', defaultVal: '-' },
|
||||
];
|
||||
|
||||
export default FooterDemo;
|
||||
@@ -0,0 +1,120 @@
|
||||
import React from 'react';
|
||||
import { Icon, ICON_LIST } from '../../../src';
|
||||
import { ApiTable, ApiRow, sectionStyle, sectionTitleStyle, tagStyle, CodeBlock, labelStyle } from '../../tools';
|
||||
|
||||
const ICON_API: ApiRow[] = [
|
||||
{
|
||||
prop: 'name',
|
||||
desc: '图标名称',
|
||||
type: 'IconName',
|
||||
defaultVal: '-',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
prop: 'size',
|
||||
desc: '图标尺寸',
|
||||
type: 'number | string',
|
||||
defaultVal: '24',
|
||||
},
|
||||
{
|
||||
prop: 'bounce',
|
||||
desc: '弹跳动画',
|
||||
type: 'boolean',
|
||||
defaultVal: 'false',
|
||||
},
|
||||
{
|
||||
prop: 'className',
|
||||
desc: '自定义类名',
|
||||
type: 'string',
|
||||
defaultVal: '-',
|
||||
},
|
||||
{
|
||||
prop: 'style',
|
||||
desc: '自定义样式',
|
||||
type: 'CSSProperties',
|
||||
defaultVal: '-',
|
||||
},
|
||||
];
|
||||
|
||||
const IconDemo: React.FC = () => (
|
||||
<div style={sectionStyle}>
|
||||
<div style={sectionTitleStyle}>
|
||||
Icon <span style={tagStyle}>10 icons</span>
|
||||
</div>
|
||||
<div style={labelStyle}>基础用法</div>
|
||||
<div style={{ display: 'flex', gap: 20, flexWrap: 'wrap' as const, alignItems: 'center' }}>
|
||||
<Icon name="icon-miles" size={32} />
|
||||
<Icon name="icon-camera" size={32} />
|
||||
<Icon name="icon-chat" size={32} />
|
||||
<Icon name="icon-design" size={32} />
|
||||
<Icon name="icon-map" size={32} />
|
||||
</div>
|
||||
<div style={labelStyle}>size 尺寸</div>
|
||||
<div style={{ display: 'flex', gap: 20, alignItems: 'center' }}>
|
||||
<Icon name="icon-miles" size={16} />
|
||||
<Icon name="icon-miles" size={24} />
|
||||
<Icon name="icon-miles" size={32} />
|
||||
<Icon name="icon-miles" size={48} />
|
||||
</div>
|
||||
<div style={labelStyle}>bounce 弹跳动画(鼠标悬停查看效果)</div>
|
||||
<div style={{ display: 'flex', gap: 20, alignItems: 'center' }}>
|
||||
<Icon name="icon-miles" size={32} bounce />
|
||||
<Icon name="icon-camera" size={32} bounce />
|
||||
<Icon name="icon-chat" size={32} bounce />
|
||||
</div>
|
||||
<div style={labelStyle}>图标列表</div>
|
||||
<div style={{
|
||||
border: '1px solid #e8e2d6',
|
||||
borderRadius: 12,
|
||||
overflow: 'hidden',
|
||||
padding: '5px 16px',
|
||||
}}>
|
||||
{ICON_LIST.map((icon, index) => (
|
||||
<div
|
||||
key={icon.name}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 20,
|
||||
padding: '12px 5px',
|
||||
borderBottom: index < ICON_LIST.length - 1 ? '1px dashed #f0e8d8' : 'none',
|
||||
background: '#fff',
|
||||
}}
|
||||
>
|
||||
<Icon name={icon.name} size={32} />
|
||||
<span style={{ fontSize: 14, color: '#725d42', fontFamily: 'inherit' }}>
|
||||
{icon.label}
|
||||
</span>
|
||||
<span style={{
|
||||
marginLeft: 'auto',
|
||||
fontSize: 12,
|
||||
color: '#a0936e',
|
||||
fontFamily: "'SF Mono', 'Fira Code', Consolas, monospace",
|
||||
}}>
|
||||
{icon.name}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<CodeBlock
|
||||
code={`import React from 'react';
|
||||
import { Icon } from 'animal-island-ui';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<div>
|
||||
{/* 基础用法 */}
|
||||
<Icon name="icon-miles" size={32} />
|
||||
{/* 弹跳动画 */}
|
||||
<Icon name="icon-camera" size={48} bounce />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;`}
|
||||
/>
|
||||
<ApiTable rows={ICON_API} />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default IconDemo;
|
||||
@@ -0,0 +1,75 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Loading as LoadingComponent, Button } from '../../../src';
|
||||
import { CodeBlock, ApiTable, ApiRow, sectionStyle, sectionTitleStyle, tagStyle, demoBodyStyle, labelStyle } from '../../tools';
|
||||
|
||||
const LoadingDemo: React.FC = () => {
|
||||
const [active, setActive] = useState(true);
|
||||
|
||||
return (
|
||||
<div style={sectionStyle}>
|
||||
<div style={sectionTitleStyle}>
|
||||
Loading <span style={tagStyle}>加载动画</span>
|
||||
</div>
|
||||
<div style={labelStyle}>
|
||||
动森风格小岛 Loading 动画组件,带有漂浮的小岛、摇曳的树叶和游动的鱼。关闭时会从中间圆形透明扩散,露出底层内容。
|
||||
</div>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<Button type={active ? 'default' : 'primary'} onClick={() => setActive(!active)}>
|
||||
{active ? '关闭 Loading' : '开启 Loading'}
|
||||
</Button>
|
||||
</div>
|
||||
<div style={{ ...demoBodyStyle, position: 'relative', height: 800, padding: 0, overflow: 'hidden' }}>
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
background: 'linear-gradient(135deg, #ffd6a5 0%, #fdffb6 25%, #caffbf 50%, #9bf6ff 75%, #a0c4ff 100%)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontSize: 28,
|
||||
fontWeight: 600,
|
||||
color: '#333',
|
||||
}}
|
||||
>
|
||||
底层内容 · Underlying Content
|
||||
</div>
|
||||
<LoadingComponent
|
||||
active={active}
|
||||
style={{ height: '100%', position: 'absolute', inset: 0 }}
|
||||
/>
|
||||
</div>
|
||||
<CodeBlock
|
||||
code={`import React, { useState } from 'react';
|
||||
import { Loading } from 'animal-island-ui';
|
||||
|
||||
const App = () => {
|
||||
const [active, setActive] = useState(true);
|
||||
return (
|
||||
<div style={{ position: 'relative', height: 800 }}>
|
||||
{/* 底层内容 */}
|
||||
<div style={{ position: 'absolute', inset: 0 }}>Underlying Content</div>
|
||||
{/* Loading 覆盖层,关闭时透明圆形扩散露出底层 */}
|
||||
<Loading
|
||||
active={active}
|
||||
style={{ position: 'absolute', inset: 0, height: '100%' }}
|
||||
/>
|
||||
<button onClick={() => setActive(!active)}>
|
||||
{active ? '关闭 Loading' : '开启 Loading'}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};`}
|
||||
/>
|
||||
<ApiTable rows={LOADING_API} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const LOADING_API: ApiRow[] = [
|
||||
{ prop: 'active', desc: '是否显示加载动画', type: 'boolean', defaultVal: 'true' },
|
||||
{ prop: 'className', desc: '自定义类名', type: 'string', defaultVal: '-' },
|
||||
{ prop: 'style', desc: '自定义样式', type: 'CSSProperties', defaultVal: '-' },
|
||||
];
|
||||
|
||||
export default LoadingDemo;
|
||||
@@ -0,0 +1,48 @@
|
||||
import React from 'react';
|
||||
import { Phone } from '../../../src';
|
||||
import {
|
||||
CodeBlock,
|
||||
ApiTable,
|
||||
ApiRow,
|
||||
sectionStyle,
|
||||
sectionTitleStyle,
|
||||
tagStyle,
|
||||
demoBodyStyle,
|
||||
labelStyle,
|
||||
} from '../../tools';
|
||||
|
||||
const PhoneDemo: React.FC = () => (
|
||||
<div style={sectionStyle}>
|
||||
<div style={sectionTitleStyle}>
|
||||
Phone <span style={tagStyle}>手机</span>
|
||||
</div>
|
||||
<div style={labelStyle}>
|
||||
Phone 组件 — 手机界面组件。
|
||||
</div>
|
||||
<div style={{ ...demoBodyStyle, transform: 'scale(0.6)', transformOrigin: 'top left', height: 473 }}>
|
||||
<Phone />
|
||||
</div>
|
||||
<CodeBlock
|
||||
code={`import React from 'react';
|
||||
import { Phone } from 'animal-island-ui';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<div>
|
||||
{/* 手机界面 */}
|
||||
<Phone />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;`}
|
||||
/>
|
||||
<ApiTable rows={PHONE_API} />
|
||||
</div>
|
||||
);
|
||||
|
||||
const PHONE_API: ApiRow[] = [
|
||||
{ prop: 'className', desc: '自定义类名', type: 'string', defaultVal: '-' },
|
||||
];
|
||||
|
||||
export default PhoneDemo;
|
||||
@@ -0,0 +1,182 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Table, Button } from '../../../src';
|
||||
import { CodeBlock, ApiTable, ApiRow, sectionStyle, sectionTitleStyle, tagStyle, demoBodyStyle, labelStyle } from '../../tools';
|
||||
|
||||
const TableDemo: React.FC = () => {
|
||||
const [striped, setStriped] = useState(true);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '岛民',
|
||||
dataIndex: 'name',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '年龄',
|
||||
dataIndex: 'age',
|
||||
width: 80,
|
||||
align: 'center' as const,
|
||||
},
|
||||
{
|
||||
title: '岛屿',
|
||||
dataIndex: 'island',
|
||||
},
|
||||
{
|
||||
title: '喜欢的水果',
|
||||
dataIndex: 'fruit',
|
||||
},
|
||||
{
|
||||
title: '爱好',
|
||||
dataIndex: 'hobby',
|
||||
render: (value: unknown) => {
|
||||
const hobby = value as string;
|
||||
const tagStyles: Record<string, { bg: string; color: string }> = {
|
||||
'音乐': { bg: 'rgba(147, 112, 219, 0.15)', color: '#9370db' },
|
||||
'运动': { bg: 'rgba(255, 140, 0, 0.15)', color: '#ff8c00' },
|
||||
'唱歌': { bg: 'rgba(255, 99, 71, 0.15)', color: '#ff6347' },
|
||||
'钓鱼': { bg: 'rgba(30, 144, 255, 0.15)', color: '#1e90ff' },
|
||||
'画画': { bg: 'rgba(255, 105, 180, 0.15)', color: '#ff69b4' },
|
||||
};
|
||||
const style = tagStyles[hobby] || { bg: 'rgba(25, 200, 185, 0.15)', color: '#19c8b9' };
|
||||
return (
|
||||
<span style={{
|
||||
padding: '4px 12px',
|
||||
background: style.bg,
|
||||
borderRadius: 20,
|
||||
color: style.color,
|
||||
fontWeight: 600,
|
||||
fontSize: 12,
|
||||
}}>
|
||||
{hobby}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const dataSource = [
|
||||
{ key: '1', name: '豆狸', age: 26, island: '彩虹岛', fruit: '苹果', hobby: '音乐' },
|
||||
{ key: '2', name: '粒狸', age: 24, island: '彩虹岛', fruit: '橘子', hobby: '运动' },
|
||||
{ key: '3', name: '西施惠', age: 28, island: '好评岛', fruit: '樱桃', hobby: '唱歌' },
|
||||
{ key: '4', name: '喻哥', age: 30, island: '无人岛', fruit: '梨', hobby: '钓鱼' },
|
||||
{ key: '5', name: '小润', age: 22, island: '摸鱼岛', fruit: '桃子', hobby: '画画' },
|
||||
] as Record<string, unknown>[];
|
||||
|
||||
const handleLoading = () => {
|
||||
setLoading(true);
|
||||
setTimeout(() => setLoading(false), 2000);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={sectionStyle}>
|
||||
<div style={sectionTitleStyle}>
|
||||
Table <span style={tagStyle}>表格</span>
|
||||
</div>
|
||||
<div style={labelStyle}>
|
||||
数据表格组件,支持斑马纹、边框、加载状态等常用功能。
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: 16, display: 'flex', gap: 16, flexWrap: 'wrap' }}>
|
||||
<Button type={striped ? 'primary' : 'default'} onClick={() => setStriped(!striped)}>
|
||||
斑马纹 {striped ? '✓' : '✗'}
|
||||
</Button>
|
||||
<Button type="primary" onClick={handleLoading} disabled={loading}>
|
||||
{loading ? '加载中...' : '模拟加载'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div style={{ ...demoBodyStyle, padding: 0, overflow: 'hidden' }}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={dataSource}
|
||||
striped={striped}
|
||||
loading={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<CodeBlock
|
||||
code={`import React, { useState } from 'react';
|
||||
import { Table } from 'animal-island-ui';
|
||||
|
||||
interface Person {
|
||||
key: string;
|
||||
name: string;
|
||||
age: number;
|
||||
island: string;
|
||||
fruit: string;
|
||||
hobby: string;
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '岛民',
|
||||
dataIndex: 'name',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '年龄',
|
||||
dataIndex: 'age',
|
||||
width: 80,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '岛屿',
|
||||
dataIndex: 'island',
|
||||
},
|
||||
{
|
||||
title: '喜欢的水果',
|
||||
dataIndex: 'fruit',
|
||||
},
|
||||
{
|
||||
title: '爱好',
|
||||
dataIndex: 'hobby',
|
||||
render: (value) => (
|
||||
<span style={{
|
||||
padding: '4px 12px',
|
||||
background: 'rgba(25, 200, 185, 0.15)',
|
||||
borderRadius: 20,
|
||||
color: '#19c8b9',
|
||||
}}>
|
||||
{value}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ key: '1', name: '豆狸', age: 26, island: '彩虹岛', fruit: '苹果', hobby: '音乐' },
|
||||
{ key: '2', name: '粒狸', age: 24, island: '彩虹岛', fruit: '橘子', hobby: '运动' },
|
||||
{ key: '3', name: '西施惠', age: 28, island: '好评岛', fruit: '樱桃', hobby: '唱歌' },
|
||||
];
|
||||
|
||||
const App = () => {
|
||||
const [striped, setStriped] = useState(true);
|
||||
|
||||
return (
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
striped={striped}
|
||||
/>
|
||||
);
|
||||
};`}
|
||||
/>
|
||||
<ApiTable rows={TABLE_API} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TABLE_API: ApiRow[] = [
|
||||
{ prop: 'columns', desc: '表格列配置', type: 'TableColumn[]', defaultVal: '[]' },
|
||||
{ prop: 'dataSource', desc: '表格数据源', type: 'T[]', defaultVal: '[]' },
|
||||
{ prop: 'rowKey', desc: '行唯一标识字段名或函数', type: 'string | (record) => string', defaultVal: 'key' },
|
||||
{ prop: 'striped', desc: '是否显示斑马纹', type: 'boolean', defaultVal: 'true' },
|
||||
{ prop: 'showHeader', desc: '是否显示表头', type: 'boolean', defaultVal: 'true' },
|
||||
{ prop: 'loading', desc: '加载状态', type: 'boolean', defaultVal: 'false' },
|
||||
{ prop: 'emptyText', desc: '空数据显示文本', type: 'ReactNode', defaultVal: '暂无数据' },
|
||||
{ prop: 'className', desc: '自定义类名', type: 'string', defaultVal: '-' },
|
||||
{ prop: 'style', desc: '自定义样式', type: 'CSSProperties', defaultVal: '-' },
|
||||
];
|
||||
|
||||
export default TableDemo;
|
||||
@@ -0,0 +1,110 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Tabs } from '../../../src';
|
||||
import type { TabItem } from '../../../src';
|
||||
import { labelStyle, ApiTable, CodeBlock, sectionStyle, sectionTitleStyle, tagStyle, demoBoxStyle } from '../../tools';
|
||||
|
||||
const TABS_API = [
|
||||
{ prop: 'items', desc: '标签页配置列表', type: 'TabItem[]', defaultVal: '-', required: true },
|
||||
{ prop: 'defaultActiveKey', desc: '默认激活的标签', type: 'string', defaultVal: '第一个标签' },
|
||||
{ prop: 'activeKey', desc: '受控模式当前激活标签', type: 'string', defaultVal: '-' },
|
||||
{ prop: 'onChange', desc: '标签切换回调', type: '(key: string) => void', defaultVal: '-' },
|
||||
{ prop: 'shadow', desc: '是否显示选中状态阴影', type: 'boolean', defaultVal: 'true' },
|
||||
{ prop: 'leafAnimation', desc: '是否启用叶子动画', type: 'boolean', defaultVal: 'true' },
|
||||
{ prop: 'className', desc: '自定义类名', type: 'string', defaultVal: '-' },
|
||||
{ prop: 'style', desc: '自定义样式', type: 'CSSProperties', defaultVal: '-' },
|
||||
];
|
||||
|
||||
const TabsDemo: React.FC = () => {
|
||||
const [activeKey, setActiveKey] = useState('tab1');
|
||||
const items: TabItem[] = [
|
||||
{
|
||||
key: 'tab1',
|
||||
label: '岛屿概况',
|
||||
children: (
|
||||
<div>
|
||||
<p style={{ marginBottom: 12 }}>这里是一座无人岛,环境优美,气候宜人。</p>
|
||||
<p>可以钓鱼、捉虫、种植各种植物。</p>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'tab2',
|
||||
label: '商店',
|
||||
children: (
|
||||
<div>
|
||||
<p style={{ marginBottom: 12 }}>狸然超市营业中!</p>
|
||||
<p>各种商品应有尽有,价格实惠。</p>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'tab3',
|
||||
label: '服务台',
|
||||
children: (
|
||||
<div>
|
||||
<p style={{ marginBottom: 12 }}>欢迎来到服务台!</p>
|
||||
<p>可以办理各种服务业务。</p>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div style={sectionStyle}>
|
||||
<div style={sectionTitleStyle}>Tab <span style={tagStyle}>基础用法</span></div>
|
||||
<div style={labelStyle}>shadow 阴影控制</div>
|
||||
<div style={{ display: 'flex', gap: 16, flexWrap: 'wrap' }}>
|
||||
<div style={demoBoxStyle}>
|
||||
<Tabs items={[{ key: 'a', label: '鱼类', children: <p>鲈鱼、鲷鱼...</p> }, { key: 'b', label: '昆虫', children: <p>蝴蝶、瓢虫...</p> }]} defaultActiveKey="a" />
|
||||
</div>
|
||||
<div style={demoBoxStyle}>
|
||||
<Tabs items={[{ key: 'a', label: '鱼类', children: <p>鲈鱼、鲷鱼...</p> }, { key: 'b', label: '昆虫', children: <p>蝴蝶、瓢虫...</p> }]} defaultActiveKey="a" shadow={false} />
|
||||
</div>
|
||||
</div>
|
||||
<div style={labelStyle}>非受控模式</div>
|
||||
<div style={demoBoxStyle}>
|
||||
<Tabs items={[{ key: 'a', label: '鱼类', children: <p>鲈鱼、鲷鱼、河童...</p> }, { key: 'b', label: '昆虫', children: <p>蝴蝶、瓢虫、蜻蜓...</p> }, { key: 'c', label: '海洋生物', children: <p>海星、珊瑚、小丑鱼...</p> }]} defaultActiveKey="a" />
|
||||
</div>
|
||||
<div style={labelStyle}>受控模式</div>
|
||||
<div style={demoBoxStyle}>
|
||||
<Tabs items={items} activeKey={activeKey} onChange={setActiveKey} />
|
||||
</div>
|
||||
<div style={{ marginTop: 16, fontSize: 13, color: '#a08060' }}>当前选中: <span style={{ color: '#19c8b9', fontWeight: 600 }}>{items.find(i => i.key === activeKey)?.label}</span></div>
|
||||
<div style={labelStyle}>leafAnimation 叶子动画控制</div>
|
||||
<div style={{ display: 'flex', gap: 16, flexWrap: 'wrap' }}>
|
||||
<div style={demoBoxStyle}>
|
||||
<Tabs items={[{ key: 'a', label: '鱼类', children: <p>鲈鱼、鲷鱼...</p> }, { key: 'b', label: '昆虫', children: <p>蝴蝶、瓢虫...</p> }]} defaultActiveKey="a" leafAnimation={true} />
|
||||
<div style={{ fontSize: 12, color: '#a0936e', marginTop: 8 }}>leafAnimation=true (默认)</div>
|
||||
</div>
|
||||
<div style={demoBoxStyle}>
|
||||
<Tabs items={[{ key: 'a', label: '鱼类', children: <p>鲈鱼、鲷鱼...</p> }, { key: 'b', label: '昆虫', children: <p>蝴蝶、瓢虫...</p> }]} defaultActiveKey="a" leafAnimation={false} />
|
||||
<div style={{ fontSize: 12, color: '#a0936e', marginTop: 8 }}>leafAnimation=false</div>
|
||||
</div>
|
||||
</div>
|
||||
<CodeBlock code={`import React, { useState } from 'react';
|
||||
import { Tabs } from 'animal-island-ui';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<div>
|
||||
{/* 非受控模式 */}
|
||||
<Tabs
|
||||
items={[
|
||||
{ key: 'tab1', label: '标签一', children: <p>内容一</p> },
|
||||
{ key: 'tab2', label: '标签二', children: <p>内容二</p> },
|
||||
]}
|
||||
defaultActiveKey="tab1"
|
||||
/>
|
||||
{/* 受控模式 */}
|
||||
<Tabs items={items} activeKey={activeKey} onChange={setActiveKey} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;`} />
|
||||
<ApiTable rows={TABS_API} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TabsDemo;
|
||||
@@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
import { Time as TimeComponent } from '../../../src';
|
||||
import { CodeBlock, ApiTable, ApiRow, sectionStyle, sectionTitleStyle, tagStyle, demoBodyStyle, labelStyle } from '../../tools';
|
||||
|
||||
const TimeDemo: React.FC = () => (
|
||||
<div style={sectionStyle}>
|
||||
<div style={sectionTitleStyle}>
|
||||
Time <span style={tagStyle}>时间</span>
|
||||
</div>
|
||||
<div style={labelStyle}>
|
||||
Time 组件 — 动森经典 HUD 风格的时间显示组件,实时更新时间,支持星期、日期和时间显示。
|
||||
</div>
|
||||
<div style={demoBodyStyle}>
|
||||
<TimeComponent />
|
||||
</div>
|
||||
<CodeBlock
|
||||
code={`import React from 'react';
|
||||
import { Time } from 'animal-island-ui';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<div>
|
||||
{/* 时间显示 */}
|
||||
<Time />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;`}
|
||||
/>
|
||||
<ApiTable rows={TIME_API} />
|
||||
</div>
|
||||
);
|
||||
|
||||
const TIME_API: ApiRow[] = [
|
||||
{ prop: 'className', desc: '自定义类名', type: 'string', defaultVal: '-' },
|
||||
];
|
||||
|
||||
export default TimeDemo;
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 296 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,20 @@
|
||||
<svg width="1080" height="2280" viewBox="0 0 1080 2280" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_54_2368" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="1080" height="2280">
|
||||
<rect width="1080" height="2280" fill="#F8F4E8"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_54_2368)">
|
||||
<rect width="1080" height="2280" fill="#F8F4E8"/>
|
||||
<path d="M1148.1 2565.96H-119.49V1996.02H1148.1V2565.96Z" fill="#8ACED7"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2214.89L22.8619 2210.99C44.5808 2208.4 90.3047 2201.9 134.885 2181.12C180.609 2159.03 225.19 2122.66 270.914 2125.26C315.495 2127.86 361.219 2170.73 405.8 2195.41C451.524 2220.09 496.104 2226.58 518.966 2229.18L541.828 2233.08V2251.26H518.966C496.104 2251.26 451.524 2251.26 405.8 2251.26C361.219 2251.26 315.495 2251.26 270.914 2251.26C225.19 2251.26 180.609 2251.26 134.885 2251.26C90.3047 2251.26 44.5808 2251.26 22.8619 2251.26H0V2214.89Z" fill="#2EBDAD"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M542 2214.89L519.138 2210.99C497.419 2208.4 451.695 2201.9 407.115 2181.12C361.391 2159.03 316.81 2122.66 271.086 2125.26C226.505 2127.86 180.781 2170.73 136.2 2195.41C90.4765 2220.09 45.8957 2226.58 23.0337 2229.18L0.171753 2233.08V2251.26H23.0337C45.8957 2251.26 90.4765 2251.26 136.2 2251.26C180.781 2251.26 226.505 2251.26 271.086 2251.26C316.81 2251.26 361.391 2251.26 407.115 2251.26C451.695 2251.26 497.419 2251.26 519.138 2251.26H542V2214.89Z" fill="#2EBDAD"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M500 2214.89L522.862 2210.99C544.581 2208.4 590.305 2201.9 634.885 2181.12C680.609 2159.03 725.19 2122.66 770.914 2125.26C815.495 2127.86 861.219 2170.73 905.8 2195.41C951.524 2220.09 996.104 2226.58 1018.97 2229.18L1041.83 2233.08V2251.26H1018.97C996.104 2251.26 951.524 2251.26 905.8 2251.26C861.219 2251.26 815.495 2251.26 770.914 2251.26C725.19 2251.26 680.609 2251.26 634.885 2251.26C590.305 2251.26 544.581 2251.26 522.862 2251.26H500V2214.89Z" fill="#2EBDAD"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1080 2214.67L1055.53 2210.77C1032.28 2208.18 983.333 2201.69 935.612 2180.93C886.667 2158.87 838.945 2122.54 790 2125.13C742.278 2127.73 693.333 2170.55 645.612 2195.2C596.667 2219.86 548.945 2226.34 524.473 2228.94L500 2232.83V2251H524.473C548.945 2251 596.667 2251 645.612 2251C693.333 2251 742.278 2251 790 2251C838.945 2251 886.667 2251 935.612 2251C983.333 2251 1032.28 2251 1055.53 2251H1080V2214.67Z" fill="#2EBDAD"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1542 2214.89L1519.14 2210.99C1497.42 2208.4 1451.7 2201.9 1407.11 2181.12C1361.39 2159.03 1316.81 2122.66 1271.09 2125.26C1226.51 2127.86 1180.78 2170.73 1136.2 2195.41C1090.48 2220.09 1045.9 2226.58 1023.03 2229.18L1000.17 2233.08V2251.26H1023.03C1045.9 2251.26 1090.48 2251.26 1136.2 2251.26C1180.78 2251.26 1226.51 2251.26 1271.09 2251.26C1316.81 2251.26 1361.39 2251.26 1407.11 2251.26C1451.7 2251.26 1497.42 2251.26 1519.14 2251.26H1542V2214.89Z" fill="#2EBDAD"/>
|
||||
<path d="M1255.59 2805.94H-12V2236H1255.59V2805.94Z" fill="#2EBDAD"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 1959.89L22.8619 1955.99C44.5808 1953.4 90.3047 1946.9 134.885 1926.12C180.609 1904.03 225.19 1867.66 270.914 1870.26C315.495 1872.86 361.219 1915.73 405.8 1940.41C451.524 1965.09 496.104 1971.58 518.966 1974.18L541.828 1978.08V1996.26H518.966C496.104 1996.26 451.524 1996.26 405.8 1996.26C361.219 1996.26 315.495 1996.26 270.914 1996.26C225.19 1996.26 180.609 1996.26 134.885 1996.26C90.3047 1996.26 44.5808 1996.26 22.8619 1996.26H0V1959.89Z" fill="#8ACED7"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M542 1959.89L519.138 1955.99C497.419 1953.4 451.695 1946.9 407.115 1926.12C361.391 1904.03 316.81 1867.66 271.086 1870.26C226.505 1872.86 180.781 1915.73 136.2 1940.41C90.4765 1965.09 45.8957 1971.58 23.0337 1974.18L0.171753 1978.08V1996.26H23.0337C45.8957 1996.26 90.4765 1996.26 136.2 1996.26C180.781 1996.26 226.505 1996.26 271.086 1996.26C316.81 1996.26 361.391 1996.26 407.115 1996.26C451.695 1996.26 497.419 1996.26 519.138 1996.26H542V1959.89Z" fill="#8ACED7"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M498.709 1955.99H522.862C544.581 1953.4 590.305 1946.9 634.886 1926.12C680.61 1904.03 725.191 1867.66 770.915 1870.26C815.495 1872.86 861.219 1915.73 905.8 1940.41C951.524 1965.09 996.105 1971.58 1018.97 1974.18L1041.83 1978.08V1996.26H1018.97C996.105 1996.26 951.524 1996.26 905.8 1996.26C861.219 1996.26 815.495 1996.26 770.915 1996.26C725.191 1996.26 680.61 1996.26 634.886 1996.26C590.305 1996.26 544.581 1996.26 522.862 1996.26H500.001L498.709 1955.99Z" fill="#8ACED7"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1080 1959.67L1055.53 1955.77C1032.28 1953.18 983.333 1946.69 935.612 1925.93C886.667 1903.87 838.945 1867.54 790 1870.13C742.278 1872.73 693.333 1915.55 645.612 1940.2C596.667 1964.86 548.945 1971.35 524.473 1973.94L500 1977.83V1996H524.473C548.945 1996 596.667 1996 645.612 1996C693.333 1996 742.278 1996 790 1996C838.945 1996 886.667 1996 935.612 1996C983.333 1996 1032.28 1996 1055.53 1996H1080V1959.67Z" fill="#8ACED7"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1542 1959.89L1519.14 1955.99C1497.42 1953.4 1451.7 1946.9 1407.11 1926.12C1361.39 1904.03 1316.81 1867.66 1271.09 1870.26C1226.51 1872.86 1180.78 1915.73 1136.2 1940.41C1090.48 1965.09 1045.9 1971.58 1023.03 1974.18L1000.17 1978.08V1996.26H1023.03C1045.9 1996.26 1090.48 1996.26 1136.2 1996.26C1180.78 1996.26 1226.51 1996.26 1271.09 1996.26C1316.81 1996.26 1361.39 1996.26 1407.11 1996.26C1451.7 1996.26 1497.42 1996.26 1519.14 1996.26H1542V1959.89Z" fill="#8ACED7"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
@@ -0,0 +1,15 @@
|
||||
<svg width="75" height="96" viewBox="0 0 75 96" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M73.4776 42.6469C74.3136 43.1559 74.8239 44.0639 74.8239 45.0427L74.8238 91.3169C74.8238 93.4535 72.5304 94.8056 70.6609 93.7711L57.1138 86.2752C57.0003 86.2124 56.8922 86.1424 56.79 86.0659C56.6721 86.15 56.5468 86.2257 56.4148 86.2917L38.2551 95.3748C37.2348 95.8851 36.1174 95.7104 35.3137 95.1075L17.4432 85.8943L4.19306 93.4406C2.32316 94.5055 5.73555e-06 93.1551 5.49234e-06 91.0032L0 44.0708C0 43.0455 0.559409 42.1019 1.45893 41.6099L15.2233 34.0814C15.7573 33.5984 16.4698 33.3238 17.2092 33.3496C17.9055 33.3344 18.5765 33.5852 19.0941 34.0247L36.8163 43.2084C36.9627 43.2843 37.1006 43.3721 37.229 43.4702L55.2861 34.1782C55.8761 33.5561 56.7392 33.2153 57.6166 33.3053C58.4756 33.294 59.2896 33.6875 59.8246 34.3346L73.4776 42.6469Z" fill="#F7F3E1"/>
|
||||
<path d="M6.52377 82.0731V48.0332L14.8739 42.4786C17.2846 40.5949 18.8918 41.3573 20.3426 42.2992C24.7996 44.5635 34.0799 49.3192 35.5458 50.2277C37.0117 51.1363 38.7848 50.6063 39.4881 50.2277C43.6624 47.9953 52.6388 43.2341 55.1504 42.0491C56.9845 41.0167 58.6538 41.4091 59.4364 42.0491L68.3122 47.8817C68.3025 58.2423 68.2888 79.5382 68.3122 81.8371C68.3355 84.136 66.3569 83.6355 65.3647 83.0979C63.993 82.2183 60.8645 80.1598 59.3237 78.9635C57.8528 77.6733 55.9286 78.4259 55.1504 78.9635C50.6606 81.3572 41.2617 86.3554 39.5842 87.1988C37.9067 88.0422 36.1662 87.5502 35.5056 87.1988L19.857 78.9518C17.6359 77.4557 16.3856 78.4383 15.5177 78.9518C14.6499 79.4653 12.4948 80.8085 10.8174 82.0731C7.10015 84.4843 6.40613 83.0778 6.52377 82.0731Z" fill="#59C9C0"/>
|
||||
<path d="M24.4086 53.0932L25.9292 53.9876C29.5476 56.129 28.0535 53.5144 28.4666 52.4232C28.9404 51.1717 30.4401 51.7871 31.1307 52.2511C32.3216 52.8804 34.9841 54.3144 36.1063 55.0167C37.2284 55.7191 38.4265 55.3094 38.8852 55.0167L42.1137 53.3136C45.1875 51.4254 45.5405 53.0253 45.5405 54.1388C45.5405 55.9531 46.5898 55.4428 47.2036 55.1748L50.8837 53.214C52.8302 52.0448 54.2425 52.7848 54.2425 53.7721L54.0151 62.4485C54.0028 63.9623 54.5399 63.953 54.9876 63.8289C56.63 63.0316 57.2343 64.1081 57.2343 64.8255V66.6648C57.2111 68.5931 56.2002 69.1815 55.6078 69.1815C54.3706 69.2098 54.237 69.3934 54.237 71.8833C54.237 73.1405 53.8679 72.9251 51.9192 73.9787L39.4953 80.499C37.2996 81.6669 37.5424 81.5421 35.4914 80.499L24.4086 74.7195C21.2306 72.9533 21.2561 73.6566 21.2561 71.2639V54.8819C21.1967 51.3641 23.3701 52.4597 24.4086 53.0932Z" fill="#45A86F"/>
|
||||
<path d="M6.78223 76.2303L17.3863 69.5098L37.534 79.8364L57.2739 69.5098L67.0623 75.5746" stroke="#299187" stroke-opacity="0.5" stroke-width="1.12197" stroke-dasharray="2.24 0.56"/>
|
||||
<path d="M6.61914 65.6479L17.2373 59.1045L37.341 69.0619L57.1615 59.1045L66.9302 65.6479" stroke="#299187" stroke-opacity="0.5" stroke-width="1.12197" stroke-dasharray="2.24 0.56"/>
|
||||
<path d="M6.02734 55.1539L17.5332 48.3486L37.5258 59.0074L57.1919 48.3486L67.1473 55.1539" stroke="#299187" stroke-opacity="0.5" stroke-width="1.12197" stroke-dasharray="2.24 0.56"/>
|
||||
<path d="M22.1572 43.4854L22.2822 80.2499" stroke="#299187" stroke-opacity="0.5" stroke-width="1.12197" stroke-dasharray="2.24 0.56"/>
|
||||
<path d="M32.5498 48.7334L32.6634 85.5838" stroke="#299187" stroke-opacity="0.5" stroke-width="1.12197" stroke-dasharray="2.24 0.56"/>
|
||||
<path d="M42.4062 48.7334L42.5199 85.5838" stroke="#299187" stroke-opacity="0.5" stroke-width="1.12197" stroke-dasharray="2.24 0.56"/>
|
||||
<path d="M52.7871 43.3994L52.9018 80.2498" stroke="#299187" stroke-opacity="0.5" stroke-width="1.12197" stroke-dasharray="2.24 0.56"/>
|
||||
<path d="M63.0068 44.748L63.1267 81.3965" stroke="#299187" stroke-opacity="0.5" stroke-width="1.12197" stroke-dasharray="2.24 0.56"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M54.0825 34.8346C57.006 31.1652 58.7544 26.5095 58.7544 21.4436C58.7544 9.60064 49.1992 0 37.4123 0C25.6255 0 16.0703 9.60064 16.0703 21.4436C16.0703 26.5613 17.8546 31.2602 20.8321 34.9467L34.047 57.2165C35.5684 59.7805 39.2797 59.7805 40.8011 57.2165L54.0825 34.8346Z" fill="#4C3C33"/>
|
||||
<ellipse cx="37.4124" cy="22.2135" rx="7.25612" ry="7.29066" fill="#F7F2D9"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
@@ -0,0 +1,7 @@
|
||||
<svg width="85" height="66" viewBox="0 0 85 66" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="5.94434" y="4.92773" width="15.5386" height="16.1112" rx="1.78001" fill="#FF66AD"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.585 0H54.7227C56.8954 0.0509226 61.251 1.72121 61.2917 7.99496C61.2917 10.9719 62.9303 12.1182 64.1666 12.4312H70.5935C78.4581 12.4312 84.8336 18.8067 84.8336 26.6712V51.0976C84.8336 58.9622 78.4581 65.3377 70.5935 65.3377H14.2401C6.37551 65.3377 0 58.9622 0 51.0976V26.6712C0 18.8067 6.37549 12.4312 14.2401 12.4312H21.3539C22.5467 12.1169 24.1915 11.0856 24.1915 8.63043C24.1915 4.37225 26.5803 0 30.585 0Z" fill="#4C3C33"/>
|
||||
<path d="M47.2051 7.81382H38.5511C36.0335 8.96867 36.4298 12.6061 37.9934 12.6061H48.3218C50.0712 10.9311 48.3218 7.69332 47.2051 7.81382Z" fill="#F9F6E5"/>
|
||||
<ellipse cx="42.9035" cy="39.4683" rx="19.7658" ry="19.7652" fill="#F9F6E5"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M57.5033 39.468C57.5033 47.5323 50.9659 54.0697 42.9016 54.0697C34.8372 54.0697 28.2998 47.5323 28.2998 39.468C28.2998 31.4036 34.8372 24.8662 42.9016 24.8662C50.9659 24.8662 57.5033 31.4036 57.5033 39.468ZM53.8936 40.9628C53.8936 42.2078 52.8844 43.2171 51.6394 43.2171C50.3945 43.2171 49.3852 42.2078 49.3852 40.9628C49.3852 39.7179 50.3945 38.7086 51.6394 38.7086C52.8844 38.7086 53.8936 39.7179 53.8936 40.9628ZM43.9772 28.6918C42.996 28.6022 41.2035 28.6918 41.0334 30.4128C40.8416 32.3543 42.5052 32.8329 43.9772 32.8866C44.9658 32.9228 47.5574 33.3182 49.1556 35.9975C49.4861 36.571 50.5237 37.5062 52.0306 36.6586C53.5375 35.811 52.4715 33.7908 51.7502 32.8866C50.94 31.6534 48.251 29.0878 43.9772 28.6918Z" fill="#9364DE"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,7 @@
|
||||
<svg width="80" height="67" viewBox="0 0 80 67" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.6992 9.64355C12.1012 9.64355 2.69922 19.0456 2.69922 30.6436V38.4145C2.69922 50.0125 12.1012 59.4145 23.6992 59.4145H34.8603L40.1597 66.2754C40.56 66.7937 41.3422 66.7937 41.7425 66.2754L47.042 59.4145H58.203C69.801 59.4145 79.203 50.0124 79.203 38.4145V30.6436C79.203 19.0456 69.801 9.64355 58.203 9.64355H23.6992Z" fill="#F5F1E6"/>
|
||||
<circle cx="20.8502" cy="35.8365" r="5.78961" fill="#5E483B"/>
|
||||
<circle cx="40.4293" cy="35.8365" r="5.78961" fill="#5E483B"/>
|
||||
<circle cx="60.0084" cy="35.8365" r="5.78961" fill="#5E483B"/>
|
||||
<rect width="33.5693" height="19.2872" rx="9" fill="#F583A4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 742 B |
@@ -0,0 +1,13 @@
|
||||
<svg width="103" height="65" viewBox="0 0 103 65" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.431 31.5628C20.2041 32.4932 19.8918 33.7738 17.4399 34.2157C13.698 35.1891 5.8384 38.0279 5.26856 42.9666C4.55625 49.1399 15.5053 52.3044 18.7308 52.578C19.616 52.6531 26.9921 52.5983 29.5966 52.578L31.6721 58.3161H16.9859C16.2866 58.3161 14.5745 58.2834 10.8006 55.6755C9.9796 55.3954 8.18736 55.3294 7.1325 56.6568C5.81394 58.3161 6.5831 60.1383 7.1325 60.7609C7.1585 60.7904 7.18882 60.8257 7.22362 60.8661C7.92438 61.6812 10.4396 64.6068 15.9265 64.6596C20.534 64.7039 54.6051 64.678 71.0647 64.6596C71.888 64.5599 73.5226 63.7715 73.4745 61.4154C73.4264 59.0592 71.8479 58.4301 71.0647 58.4101L55.8638 58.3161L53.7578 52.578C53.4557 52.03 53.2558 50.8363 54.8734 50.4459C56.8954 49.9578 60.9394 46.7505 62.7522 42.1487C66.0444 41.1904 80.6847 36.9405 87.5933 34.9353C87.6719 34.9125 87.7568 34.8855 87.8464 34.857C88.5629 34.6292 89.5833 34.3048 90.1443 35.2399L93.3713 39.8807H101.535L98.308 31.0954C98.0889 30.5973 97.8419 29.1829 98.6068 27.5096C99.3718 25.8362 101.47 20.6918 102.424 18.3287C102.636 17.5633 102.615 16.1242 100.834 16.4916H95.1811C94.8176 16.4916 93.9075 16.6318 92.9879 18.1337L89.244 23.6611C88.9563 24.0728 88.1347 24.9806 85.3506 25.2216L61.2418 28.777C61.2418 28.1865 60.6171 26.0927 55.9709 22.3835L26.1287 22.8192C24.6471 24.3397 21.4875 28.0641 20.7021 30.7981C20.5716 30.9861 20.506 31.2554 20.431 31.5628ZM37.0636 52.1857L39.1573 58.1004H48.7882L46.3805 52.1857H37.0636Z" fill="#4C3C33"/>
|
||||
<path d="M10.9122 40.1817C10.6651 39.202 11.4844 38.0471 12.1666 37.673C13.2889 36.8477 15.7383 35.4415 16.557 36.4186C17.3756 37.3957 16.8981 38.1681 16.557 38.4322L13.7511 39.9507C13.2229 40.2918 11.786 40.4333 10.9122 40.1817Z" fill="#FAF5E5"/>
|
||||
<path d="M10.2909 45.4017C9.99041 46.3604 10.8375 47.5317 11.5627 47.9266C12.7488 48.7835 15.3506 50.2635 16.2692 49.3285C17.1877 48.3936 16.6973 47.6128 16.3373 47.3393L13.3537 45.7352C12.794 45.3786 11.2445 45.1856 10.2909 45.4017Z" fill="#FAF5E5"/>
|
||||
<path d="M11.4234 42.7699C12.226 43.7714 12.7738 44.0845 13.9554 44.1649C15.286 44.2554 17.5885 44.4232 17.9339 43.2161C18.2792 42.009 17.3786 41.3555 16.9526 41.2845L14.1365 41.2845C12.1233 41.6272 11.9979 42.1519 11.4234 42.7699Z" fill="#FAF5E5"/>
|
||||
<path d="M27.8366 38.0261C25.1869 38.0261 26.1688 34.5025 26.991 32.7407C28.2313 29.7527 29.411 29.2924 30.0565 29.1114C30.4738 29.0533 31.924 28.9351 33.6153 28.9351C36.4963 28.785 36.7979 29.4841 36.6457 30.7674C36.4577 31.4017 36.1242 33.2763 35.1657 35.4186C34.2073 37.5609 32.6287 38.0496 31.9592 38.0261H27.8366Z" fill="#F9F6E5"/>
|
||||
<path d="M44.0776 28.9156C42.4632 28.8812 41.5444 30.5614 41.2868 31.4057C41.2009 31.6204 40.9949 32.5049 40.8575 34.3253C40.7201 36.1458 42.0597 36.515 42.7466 36.4721C43.0472 36.4864 44.2064 36.5065 46.439 36.4721C48.6717 36.4378 49.3157 35.7136 49.3586 35.3558C49.5161 34.8835 49.8825 33.4323 50.0885 31.4057C50.2946 29.3792 49.4302 28.9012 48.9722 28.9156C48.0133 28.9299 45.692 28.9499 44.0776 28.9156Z" fill="#F9F6E5"/>
|
||||
<path d="M42.3243 1.75967C40.2543 1.75967 14.9108 0.708353 2.4957 0.108886C-1.20529 1.24532 -0.436366 7.43593 2.4957 8.03971C15.322 7.73285 40.1705 6.84297 42.3243 6.84297C43.4265 6.84297 69.8824 7.5412 82.9866 8.0284C87.3415 4.97586 84.6693 -0.193929 82.3393 0.00561061C79.7804 0.224947 44.4896 1.75967 42.3243 1.75967Z" fill="#FFAD00"/>
|
||||
<ellipse cx="18.6724" cy="17.4369" rx="2.0992" ry="3.79239" fill="#7B7B73"/>
|
||||
<path d="M29.2576 15.7934C30.7747 16.3638 30.7747 18.5098 29.2576 19.0801L20.6055 22.3328C19.4575 22.7644 18.232 21.9159 18.232 20.6895L18.232 14.184C18.232 12.9576 19.4575 12.1091 20.6055 12.5407L29.2576 15.7934Z" fill="#FFAD00"/>
|
||||
<path d="M22.528 19.205C24.851 12.236 34.33 10.4141 38.7791 10.3743V2.70085C38.7791 0.603806 40.2843 0.0265152 41.0369 0H44.6843C46.2445 0.0362842 47.0517 2.36727 47.0517 2.85737V10.3743C58.4673 11.1024 62.5788 18.6106 62.875 19.8547C63.1119 20.8499 63.5029 21.0884 63.6687 21.0832C64.386 21.1749 65.8254 21.8187 65.8454 23.6601C65.8654 25.5015 64.6567 26.0005 64.0498 26.0198H20.666C18.5375 23.8913 20.0865 21.9402 21.1271 21.2308C21.4592 21.0043 22.2303 20.6553 22.528 19.205Z" fill="#FFD103"/>
|
||||
<rect x="25.6084" y="19.0068" width="34.0957" height="2.37974" rx="1.17044" fill="#4C3C33"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,8 @@
|
||||
<svg width="91" height="82" viewBox="0 0 91 82" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="11.7194" height="29.2229" rx="5.85971" transform="matrix(0.835401 0.549641 -0.539556 0.84195 64.2549 50.3584)" fill="#FAD12B"/>
|
||||
<rect x="1.18652" y="1.29688" width="57.27" height="74.7502" rx="8" fill="#F7F3E1"/>
|
||||
<rect x="7.08887" y="7.21875" width="45.4652" height="62.9072" rx="3" fill="#E68E6D"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M42.6888 35.5469C30.6862 30.2339 19.8407 34.0493 15.9183 36.6212C13.8852 52.7036 18.98 56.7398 27.1072 60.3539C27.6614 60.5307 28.9816 61.3837 29.8281 63.3814C29.7361 61.4936 31.0417 60.5765 31.7061 60.3539C42.6889 56.3496 46.6113 48.1457 42.6888 35.5469ZM37.1053 41.2027C37.3954 41.7241 37.3952 42.3441 37.395 42.919L37.395 42.9614C37.395 43.1244 37.382 43.3738 37.3668 43.6646L37.3668 43.6647C37.3272 44.4205 37.2731 45.4562 37.395 45.9848C37.6452 47.0696 39.9601 47.9483 40.8106 46.2544C41.491 44.8992 41.0941 41.5758 40.8106 40.0835C39.5653 36.3328 35.86 38.9643 37.1053 41.2027ZM37.626 52.0231C38.7863 52.0231 39.7269 51.0863 39.7269 49.9307C39.7269 48.7751 38.7863 47.8383 37.626 47.8383C36.4657 47.8383 35.5252 48.7751 35.5252 49.9307C35.5252 51.0863 36.4657 52.0231 37.626 52.0231Z" fill="#4C3C33"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.0104 34.2474C19.387 31.7516 31.3738 28.0935 44.3081 33.4268C47.3301 29.9873 44.3081 14.2375 30.0067 20.1733C29.2398 18.8106 29.6872 16.6112 30.0067 15.6818C30.211 15.2695 30.4971 14.3835 30.0067 14.1377C29.3937 13.8305 26.7941 13.8305 25.9569 14.9276C26.813 16.1477 28.0035 19.5124 27.9069 19.6726C27.8983 19.687 27.7513 19.6701 27.4942 19.6407C24.8861 19.3419 10.9446 17.7447 15.0104 34.2474ZM17.2549 24.576C17.5476 23.4308 19.682 21.1593 25.8783 21.2342C26.5807 22.0837 26.9027 22.5042 26.9758 22.6084C24.5926 22.65 19.3119 23.1019 17.2549 24.576ZM29.2407 25.608C21.6914 25.119 17.8094 26.9325 16.812 27.9004V26.3665C21.2575 24.2181 26.1818 23.989 28.0882 24.1429C28.1916 24.1687 28.5667 24.4977 29.2407 25.608ZM16.7432 30.899C18.771 29.7217 21.8219 28.1461 31.2604 28.5446L30.1014 27.0166C27.2762 26.9223 20.6493 27.2302 16.7432 29.2161V30.899Z" fill="#FAD12B"/>
|
||||
<path d="M85.2042 67.1151C83.0668 58.9215 77.189 59.3095 74.5173 60.5278C70.9837 58.1866 63.1911 53.0321 60.2899 51.143C59.7256 46.616 55.1638 46.7113 54.0351 47.0131C53.546 47.4451 52.1306 47.1931 51.484 47.0131C51.5976 47.1282 51.3557 47.0415 49.4797 45.7743C47.6038 44.5071 48.3475 42.5817 48.9539 41.7773C51.0074 38.5782 55.3014 31.8643 56.0494 30.6012C56.7973 29.3382 58.3693 29.5604 59.0618 29.8294C59.2118 29.9229 59.8305 30.2644 61.1048 30.8819C62.379 31.4994 62.5822 32.7765 62.5245 33.3379C62.9123 38.0814 67.3375 37.982 69.784 37.982C73.0553 40.0977 80.8635 45.3292 85.926 49.3296C91.2509 54.8708 90.2805 63.5056 89.2118 66.5737C88.1431 69.6418 85.6495 68.7845 85.2042 67.1151Z" fill="#4C3C33"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,6 @@
|
||||
<svg width="71" height="102" viewBox="0 0 71 102" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.35156 37.6318C7.73431 36.0515 10.642 31.3027 11.2109 24.95C11.7798 18.5972 13.7394 14.4805 14.6481 13.2163C15.8525 11.5407 19.9545 6.49634 25.173 5.80196C27.9297 5.43522 34.7153 5.33636 36.9296 10.7419C37.4507 11.7566 38.6388 13.1771 39.2217 10.7419C39.8045 8.30677 41.1465 3.75719 41.7446 1.7868C41.8872 0.650267 42.699 -1.10802 44.8049 0.951045C45.9827 2.21621 46.5858 2.85586 46.7401 3.01754C47.3749 3.68254 47.7481 4.75898 46.0837 5.80196L41.7446 10.3282C41.6745 10.4642 41.6028 10.5951 41.5335 10.7215C40.8661 11.939 40.4245 12.7446 43.8929 13.8254C49.2551 15.4963 49.6473 18.9449 49.4979 25.5929C49.4922 27.7517 48.5101 32.943 44.6272 36.4376C43.9371 37.0587 43.2631 37.6013 42.6144 38.0741C43.2465 37.1271 43.5855 35.8959 43.5855 34.3764C43.5855 30.2947 40.6459 26.818 36.641 26.818C32.6361 26.818 29.7905 29.4779 29.7905 33.5597C29.7905 37.6415 33.1299 40.4599 37.1348 40.4599C37.6446 40.4599 38.1291 40.4275 38.5865 40.3624C37.4973 40.8019 36.6539 40.9844 36.167 41.0122C32.6149 41.2019 24.0809 41.3374 18.3609 40.3618C12.6409 39.5812 7.97135 38.2166 6.35156 37.6318Z" fill="#409B5E"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M60.0691 40.8215H67.1206C68.7774 40.8215 70.1206 39.4784 70.1206 37.8215V35.5485C70.1206 33.8917 68.7774 32.5485 67.1206 32.5485H56.7823C56.6085 32.5371 56.4354 32.5373 56.264 32.5485H56.0204C54.9415 32.5485 53.9955 33.1182 53.4669 33.9731C53.1679 34.3324 52.9274 34.7512 52.7651 35.2198L49.1837 45.5611H0V58.4033C0 66.1352 6.26801 72.4033 14 72.4033H36.8272C37.9123 72.4033 38.972 72.2953 39.9964 72.0894L38.9452 75.1249L4.09012 75.1246C2.43326 75.1245 1.09009 76.4677 1.09009 78.1246V80.0307C1.09009 81.6876 2.43324 83.0307 4.09009 83.0307H5.73181C4.69681 84.4841 4.09037 86.2483 4.09037 88.1504C4.09037 93.121 8.23174 97.1504 13.3404 97.1504C18.449 97.1504 22.5904 93.121 22.5904 88.1504C22.5904 86.2483 21.9839 84.4841 20.9489 83.0307H27.7318C26.6968 84.4841 26.0904 86.2483 26.0904 88.1504C26.0904 93.121 30.2317 97.1504 35.3404 97.1504C40.449 97.1504 44.5904 93.121 44.5904 88.1504C44.5904 86.2857 44.0075 84.5535 43.0095 83.1168C44.4915 82.9562 45.8202 81.9654 46.3415 80.46L60.0691 40.8215ZM8.31396 50.0458C8.31396 49.4936 8.76168 49.0458 9.31396 49.0458H11.431C11.9833 49.0458 12.431 49.4936 12.431 50.0458V66.0649C12.431 66.6172 11.9833 67.0649 11.431 67.0649H9.31396C8.76168 67.0649 8.31396 66.6172 8.31396 66.0649V50.0458ZM18.781 49.0458C18.2287 49.0458 17.781 49.4936 17.781 50.0458V66.0649C17.781 66.6172 18.2287 67.0649 18.781 67.0649H20.8981C21.4504 67.0649 21.8981 66.6172 21.8981 66.0649V50.0458C21.8981 49.4936 21.4504 49.0458 20.8981 49.0458H18.781ZM27.2481 50.0458C27.2481 49.4936 27.6958 49.0458 28.2481 49.0458H30.3651C30.9174 49.0458 31.3651 49.4936 31.3651 50.0458V66.0649C31.3651 66.6172 30.9174 67.0649 30.3651 67.0649H28.2481C27.6958 67.0649 27.2481 66.6172 27.2481 66.0649V50.0458ZM37.7151 49.0458C37.1628 49.0458 36.7151 49.4936 36.7151 50.0458V66.0649C36.7151 66.6172 37.1628 67.0649 37.7151 67.0649H39.8322C40.3845 67.0649 40.8322 66.6172 40.8322 66.0649V50.0458C40.8322 49.4936 40.3845 49.0458 39.8322 49.0458H37.7151Z" fill="#4A3D37"/>
|
||||
<ellipse cx="12.9968" cy="88.6746" rx="2.99679" ry="2.91579" fill="#F5FCEA"/>
|
||||
<ellipse cx="35.49" cy="88.6746" rx="2.99679" ry="2.91579" fill="#F5FCEA"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,11 @@
|
||||
<svg width="94" height="104" viewBox="0 0 94 104" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18.5704 51.2672C20.1382 47.5048 23.6707 45.5342 25.4343 45.0117C23.6734 43.9782 19.9354 40.3391 19.6027 32.9953C10.7666 33.4922 5.22798 29.0074 3.5632 26.7029C-2.5944 15.7943 1.2284 11.8209 2.05308 10.3364C2.87776 8.85203 6.20221 6.93342 10.1607 7.31827C14.1191 7.70312 16.5932 10.7269 15.8785 18.6439C15.3067 24.9774 18.123 26.6555 19.6027 26.7029C19.8497 12.3783 38.5262 7.17892 47.8605 6.22668H61.0065C60.9316 6.2097 60.6876 5.45528 60.4309 3.52975C60.1682 1.55967 62.4557 0.355715 63.6323 0H68.3112C70.1828 0 71.2433 1.97008 71.5396 2.95512V7.91826C77.8629 8.68473 84.0869 15.4689 84.3665 20.3155C84.5902 24.1928 87.4859 25.5401 88.9058 25.7291H93.0804C93.7846 37.2469 78.5536 44.5877 77.6498 44.7615C76.9268 44.9005 77.1294 45.4489 77.3211 45.7057C79.28 46.7111 83.2015 49.5912 83.2015 51.3733C82.7428 58.0241 77.2769 58.0624 74.6013 57.2501C71.5912 55.8884 64.625 53.0216 60.8409 52.4483C56.1107 51.7316 46.0054 53.0933 42.852 53.165C40.3293 53.2223 30.7041 56.9351 26.2069 58.7843C24.0484 59.2616 18.5704 55.5783 18.5704 51.2672Z" fill="#4D3E36"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M83.6368 17.5752C84.0789 18.2418 85.027 20.004 85.2826 21.7197C85.5381 23.4354 86.4233 24.3206 86.834 24.5488C85.4347 27.7886 81.6503 34.3047 77.7078 34.4507C72.7796 34.6333 71 34.5876 68.9466 31.0284C66.8932 27.4692 67.6234 22.541 70.9088 20.4876C73.8911 18.6237 77.4701 18.2392 82.1689 17.7345C82.6465 17.6832 83.1356 17.6307 83.6368 17.5752ZM78.2167 29.6498C79.8959 29.6498 81.2571 28.2886 81.2571 26.6094C81.2571 24.9303 79.8959 23.569 78.2167 23.569C76.5376 23.569 75.1763 24.9303 75.1763 26.6094C75.1763 28.2886 76.5376 29.6498 78.2167 29.6498Z" fill="#EBCD55"/>
|
||||
<path d="M5.08344 18.6624C3.47727 17.6914 1.32688 18.6341 0.452449 19.2268C0.204931 17.7093 -0.207434 14.3276 0.123246 12.9404C0.536596 11.2065 3.1348 7.27628 8.9217 6.9295C13.5512 6.65207 15.5747 10.4359 16.0077 12.3625V18.2C15.4172 18.9899 13.5748 20.5928 10.9294 20.6853C7.6226 20.8009 7.09115 19.8761 5.08344 18.6624Z" fill="#EBCD55"/>
|
||||
<path d="M67.6838 3.63792C64.9471 5.08683 66.1857 8.44504 67.1471 9.94307L69.3606 8.80278C69.9419 6.47748 69.3606 2.75012 67.6838 3.63792Z" fill="#8A7B60"/>
|
||||
<circle cx="47.2224" cy="104.709" r="45.8825" fill="#B3BFFF"/>
|
||||
<path d="M6.04234 92.2489C4.12914 92.0872 3.80803 89.9585 3.88663 88.9143C10.919 71.7363 24.5276 63.6598 30.4529 61.7687C33.057 60.954 38.5951 59.7288 39.9143 61.3459C41.5634 63.3673 40.8186 65.0164 39.6246 67.8453C38.6025 73.7087 42.8147 72.5908 45.4879 72.5908C48.2832 71.887 51.4333 71.9617 52.9447 72.1831C54.1015 72.6027 56.2347 74.0523 55.5131 76.4949C54.611 79.5481 48.921 81.0708 42.8147 82.1849C37.9296 83.0762 33.5547 87.3458 31.9778 89.3692C30.5025 91.4282 27.1723 95.342 25.6548 94.5249C24.1373 93.7077 24.1567 88.5309 24.3561 86.0447C24.2592 85.5467 23.7276 84.9347 22.929 85.3284C22.2678 85.966 20.3144 86.2107 19.8126 85.6636C18.8246 84.4594 19.7354 82.1 20.3144 81.0708C20.7389 79.7457 20.847 77.1187 17.8829 77.2113C14.9188 77.3039 11.7291 83.3417 10.4855 86.5033C9.8016 88.4859 7.95555 92.4106 6.04234 92.2489Z" fill="#5ABF98"/>
|
||||
<path d="M76.8657 73.8091C78.3322 73.7829 80.7752 74.7737 81.8133 75.2723C91.1148 84.9418 93.3753 100.183 93.0805 102.188C92.7857 104.193 90.3091 106.021 88.2453 104.842C82.7616 100.537 86.7689 95.1464 87.8341 93.7448C89.6699 90.7341 87.7423 90.7769 86.549 91.1746C85.5088 91.8172 82.9142 93.1022 80.8581 93.1022C72.597 92.1843 72.4463 83.237 72.5118 79.3087C72.5773 75.3804 75.0324 73.8419 76.8657 73.8091Z" fill="#5ABF98"/>
|
||||
<path d="M57.4213 89.2585C54.2281 92.5335 56.0908 94.5122 57.4213 95.0922C58.1164 95.3951 58.4814 95.6386 58.4814 96.6214C58.4814 98.7314 58.8161 99.6819 59.4856 99.9927C60.2645 100.372 61.9451 101.56 62.4364 103.28C62.9276 104.999 64.0739 104.815 64.5856 104.508C64.8927 104.986 66.1618 104.672 68.7818 99.5954C71.4019 94.5191 67.0761 89.7702 64.5856 88.0303C63.528 87.0751 60.6146 85.9834 57.4213 89.2585Z" fill="#5ABF98"/>
|
||||
<path d="M71.4918 112.273C68.3595 111.586 69.8047 107.085 70.9188 104.92C72.1485 102.919 73.2107 102.437 74.6432 104.156C75.7891 105.531 76.1465 107.759 76.2738 108.746C76.4203 109.881 74.6241 112.961 71.4918 112.273Z" fill="#5ABF98"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,7 @@
|
||||
<svg width="98" height="72" viewBox="0 0 98 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.335777 10.1492C4.89272 4.90487 15.8067 0.905744 20.33 0C22.2521 5.66649 23.6648 7.58058 31.4973 8.31653C39.3299 9.05248 42.7776 1.90327 42.7776 0.0974021C46.7848 1.07591 49.301 2.84653 56.5233 6.71395C62.3011 9.80789 62.955 12.1036 62.5598 12.8647C59.1326 19.2015 54.8059 25.4431 52.631 25.4431C51.1506 25.4431 49.4913 24.2734 49.0295 22.7651C48.5678 21.2568 46.998 21.0413 47.7675 23.2576C48.537 25.4739 51.2217 42.2647 51.1609 42.3863C51.1 42.508 40.1516 45.4883 31.8187 45.8533C23.4858 46.2182 11.9884 42.9227 10.9875 39.6866C9.98669 36.4505 13.2561 26.1083 14.4572 23.039C15.418 20.5836 14.0568 21.7046 13.2561 22.572C12.3154 23.6242 10.0697 25.5898 8.61345 25.035C7.15721 24.4803 2.36158 16.8418 0.145802 13.092C-0.00407374 12.3316 -0.155879 11.1351 0.335777 10.1492Z" fill="#F7F3E1"/>
|
||||
<circle cx="31.2875" cy="15.763" r="3.88316" fill="#59433A"/>
|
||||
<circle cx="31.2875" cy="25.8568" r="3.88316" fill="#59433A"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M72.9897 8.06671L43.1696 38.9087L43.1757 38.9148C42.5864 39.3622 41.205 40.9237 40.3256 43.6513C39.4422 46.3915 36.0168 58.2743 34.4145 63.8732C33.7432 66.3763 33.9857 71.3165 40.3256 71.053C46.4057 69.5775 56.89 66.0908 61.3721 64.5319C62.628 64.0928 65.3476 62.8852 66.1791 61.5678C66.1756 61.5644 66.1721 61.561 66.1685 61.5575L95.882 30.8258C98.7075 27.9035 98.6611 23.2113 95.7784 20.3454L83.3251 7.96458C80.4425 5.0987 75.8151 5.14442 72.9897 8.06671Z" fill="#59433A"/>
|
||||
<path d="M42.4894 39.7568C40.4231 41.1563 37.7123 51.2246 36.6152 56.0838C38.3518 57.788 43.3351 62.6673 49.3763 68.5511C59.1201 66.2132 64.0929 63.486 65.3614 62.4147C58.3623 55.5701 43.9892 41.4562 42.4894 39.7568Z" fill="#FFCF4F"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from './App';
|
||||
|
||||
document.body.style.margin = '0';
|
||||
|
||||
const globalStyle = document.createElement('style');
|
||||
globalStyle.textContent = `
|
||||
*::-webkit-scrollbar { display: none; }
|
||||
`;
|
||||
document.head.appendChild(globalStyle);
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
@@ -0,0 +1,71 @@
|
||||
// 独立的轻量页面元信息,供 App 等场景静态导入,避免拉入整个 ComponentPage bundle
|
||||
export const PAGE_INFO: Record<string, { title: string; desc: string }> = {
|
||||
button: {
|
||||
title: 'Button 按钮',
|
||||
desc: '按钮组件 — 支持 primary / dashed / text / link 等类型,danger / ghost / loading / disabled 状态,icon 图标,block 块级,三种尺寸',
|
||||
},
|
||||
input: {
|
||||
title: 'Input 输入框',
|
||||
desc: '输入框组件 — 支持三种尺寸、clearable 清除、prefix / suffix 前后缀、error / warning 校验状态、disabled 禁用',
|
||||
},
|
||||
switch: {
|
||||
title: 'Switch 开关',
|
||||
desc: '开关组件 — 支持受控 / 非受控、自定义文案、small 尺寸、loading 状态',
|
||||
},
|
||||
card: {
|
||||
title: 'Card 卡片',
|
||||
desc: '卡片容器组件 — 支持 default / title 两种类型,13 种背景颜色',
|
||||
},
|
||||
collapse: {
|
||||
title: 'Collapse 折叠面板',
|
||||
desc: '折叠面板组件 — 支持展开/收起、默认展开、禁用状态',
|
||||
},
|
||||
cursor: {
|
||||
title: 'Cursor 光标',
|
||||
desc: '光标组件 — 自定义手指光标,支持自定义尺寸、点击动画',
|
||||
},
|
||||
time: {
|
||||
title: 'Time 时间',
|
||||
desc: '经典 HUD 风格的时间显示组件,实时更新时间',
|
||||
},
|
||||
phone: {
|
||||
title: 'Phone 手机',
|
||||
desc: '动森风格手机界面,包含对话框和背包功能',
|
||||
},
|
||||
footer: {
|
||||
title: 'Footer 底部装饰',
|
||||
desc: '页面底部装饰图片,支持树和海两种类型',
|
||||
},
|
||||
modal: {
|
||||
title: 'Modal 弹窗',
|
||||
desc: '模态弹窗组件 — SVG 有机形状裁切、支持标题、关闭按钮、自定义 Footer、ESC / 遮罩关闭',
|
||||
},
|
||||
typewriter: {
|
||||
title: 'Typewriter 打字机',
|
||||
desc: '打字机组件 — 按字符逐个显示文本,支持多行与 ReactNode 富内容,不改变原有样式',
|
||||
},
|
||||
'divider-comp': {
|
||||
title: 'Divider 分割线',
|
||||
desc: '分割线组件 — 装饰性分割线',
|
||||
},
|
||||
icon: {
|
||||
title: 'Icon 图标',
|
||||
desc: '图标组件 — 动森风格图标集,包含 10 个可爱图标,支持自定义尺寸',
|
||||
},
|
||||
select: {
|
||||
title: 'Select 选择器',
|
||||
desc: '下拉选择器组件 — 支持自定义选项列表,高亮当前选中项',
|
||||
},
|
||||
checkbox: {
|
||||
title: 'Checkbox 多选框',
|
||||
desc: '多选框组件 — 支持受控/非受控、水平/垂直排列、三种尺寸、禁用单项或全部禁用',
|
||||
},
|
||||
codeblock: {
|
||||
title: 'CodeBlock 代码高亮',
|
||||
desc: '代码高亮组件 — 语法高亮显示,支持自定义样式和类名',
|
||||
},
|
||||
loading: {
|
||||
title: 'Loading 加载',
|
||||
desc: '动森风格小岛 Loading 动画组件,支持自定义样式和类名',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,162 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { CodeBlock as CodeBlockBase } from '../../src';
|
||||
|
||||
export const useIsMobile = (breakpoint = 768) => {
|
||||
const [isMobile, setIsMobile] = useState(() => window.innerWidth < breakpoint);
|
||||
useEffect(() => {
|
||||
const handler = () => setIsMobile(window.innerWidth < breakpoint);
|
||||
window.addEventListener('resize', handler);
|
||||
return () => window.removeEventListener('resize', handler);
|
||||
}, [breakpoint]);
|
||||
return isMobile;
|
||||
};
|
||||
|
||||
export interface ApiRow {
|
||||
prop: string;
|
||||
desc: string;
|
||||
type: string;
|
||||
defaultVal?: string;
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
export const sectionStyle: React.CSSProperties = {
|
||||
marginBottom: 36,
|
||||
padding: 24,
|
||||
background: '#fff',
|
||||
borderRadius: 12,
|
||||
border: '1px solid #e8e2d6',
|
||||
};
|
||||
|
||||
export const sectionTitleStyle: React.CSSProperties = {
|
||||
fontSize: 18,
|
||||
fontWeight: 600,
|
||||
color: '#725d42',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
};
|
||||
|
||||
export const tagStyle: React.CSSProperties = {
|
||||
fontSize: 10,
|
||||
padding: '2px 8px',
|
||||
borderRadius: 20,
|
||||
background: '#f0e8d8',
|
||||
color: '#a08060',
|
||||
fontWeight: 500,
|
||||
};
|
||||
|
||||
export const labelStyle: React.CSSProperties = {
|
||||
fontSize: 14,
|
||||
color: '#a0936e',
|
||||
marginTop: 20,
|
||||
marginBottom: 20,
|
||||
fontWeight: 500,
|
||||
};
|
||||
|
||||
export const textStyle: React.CSSProperties = {
|
||||
fontSize: 13,
|
||||
color: '#8a7b66',
|
||||
margin: 0,
|
||||
};
|
||||
|
||||
export const demoBodyStyle: React.CSSProperties = {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
};
|
||||
|
||||
export const demoBoxStyle: React.CSSProperties = {
|
||||
marginTop: 12,
|
||||
padding: 16,
|
||||
background: '#faf8f3',
|
||||
borderRadius: 12,
|
||||
border: '1px solid #e8e2d6',
|
||||
};
|
||||
|
||||
export const demoDashedBoxStyle: React.CSSProperties = {
|
||||
display: 'flex',
|
||||
gap: 16,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
padding: 16,
|
||||
background: 'rgb(250, 248, 242)',
|
||||
border: '1px dashed rgb(224, 216, 200)',
|
||||
borderRadius: 18,
|
||||
};
|
||||
|
||||
const codeLabelStyle: React.CSSProperties = {
|
||||
fontSize: 14,
|
||||
fontWeight: 600,
|
||||
color: '#e7e4e0',
|
||||
marginBottom: 0,
|
||||
padding: '6px 12px',
|
||||
background: '#3d3028',
|
||||
borderRadius: '10px 10px 0 0',
|
||||
display: 'inline-block',
|
||||
};
|
||||
|
||||
export const ApiTable: React.FC<{ rows: ApiRow[] }> = ({ rows }) => (
|
||||
<div style={{ marginTop: 24 }}>
|
||||
<div style={codeLabelStyle}>API</div>
|
||||
<div
|
||||
style={{
|
||||
background: '#2b2118',
|
||||
borderRadius: '0 20px 20px 20px',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<table
|
||||
style={{
|
||||
width: '100%',
|
||||
borderCollapse: 'collapse',
|
||||
fontSize: 13,
|
||||
}}
|
||||
>
|
||||
<thead>
|
||||
<tr
|
||||
style={{
|
||||
background: '#3d3028',
|
||||
color: '#e8d5bc',
|
||||
}}
|
||||
>
|
||||
<th style={{ padding: '10px 16px', textAlign: 'left', fontWeight: 600 }}>属性</th>
|
||||
<th style={{ padding: '10px 16px', textAlign: 'left', fontWeight: 600 }}>说明</th>
|
||||
<th style={{ padding: '10px 16px', textAlign: 'left', fontWeight: 600 }}>类型</th>
|
||||
<th style={{ padding: '10px 16px', textAlign: 'left', fontWeight: 600 }}>默认值</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((row, i) => (
|
||||
<tr
|
||||
key={i}
|
||||
style={{
|
||||
color: '#c8bba8',
|
||||
borderTop: '1px solid #3d3028',
|
||||
}}
|
||||
>
|
||||
<td style={{ padding: '10px 16px' }}>
|
||||
<span style={{ color: '#e8c87a' }}>{row.prop}</span>
|
||||
{row.required && <span style={{ color: '#f0a870', marginLeft: 4 }}>*</span>}
|
||||
</td>
|
||||
<td style={{ padding: '10px 16px' }}>{row.desc}</td>
|
||||
<td style={{ padding: '10px 16px', color: '#d4a0e0' }}>{row.type}</td>
|
||||
<td style={{ padding: '10px 16px', color: '#a8d4a0' }}>{row.defaultVal}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const CodeBlock: React.FC<{ code: string }> = ({ code }) => (
|
||||
<div style={{ marginTop: 36 }}>
|
||||
<div style={codeLabelStyle}>使用示例</div>
|
||||
|
||||
<CodeBlockBase
|
||||
style={{
|
||||
marginTop: 0,
|
||||
borderRadius: '0 20px 20px 20px',
|
||||
}}
|
||||
code={code} />
|
||||
</div>
|
||||
);
|
||||