feat(saju-ui-v2): OrnamentBloom + TopRibbon + OrnateFrame + TitleBlock
This commit is contained in:
13
src/pages/saju/_shell/OrnamentBloom.jsx
Normal file
13
src/pages/saju/_shell/OrnamentBloom.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function OrnamentBloom({ size = 18, color = '#D4AF37' }) {
|
||||
return (
|
||||
<svg width={size} height={size} viewBox="0 0 18 18" fill="none">
|
||||
<circle cx="9" cy="9" r="2.4" fill={color} />
|
||||
{[0, 60, 120, 180, 240, 300].map((angle) => (
|
||||
<ellipse key={angle} cx="9" cy="4" rx="1.6" ry="3" fill={color} opacity="0.7"
|
||||
transform={`rotate(${angle} 9 9)`} />
|
||||
))}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
36
src/pages/saju/_shell/OrnateFrame.jsx
Normal file
36
src/pages/saju/_shell/OrnateFrame.jsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import hexA from './helpers/hexA';
|
||||
|
||||
export default function OrnateFrame({
|
||||
children, color = '#D4AF37', bg = 'transparent', radius = 14, padding = '20px',
|
||||
style = {}, double = false,
|
||||
}) {
|
||||
return (
|
||||
<div style={{
|
||||
position: 'relative', borderRadius: radius,
|
||||
background: bg, padding,
|
||||
border: `1px solid ${hexA(color, 0.45)}`,
|
||||
boxShadow: 'var(--shadow-card)',
|
||||
...style,
|
||||
}}>
|
||||
{double && (
|
||||
<div style={{
|
||||
position: 'absolute', inset: 4, borderRadius: radius - 4,
|
||||
border: `1px solid ${hexA(color, 0.3)}`, pointerEvents: 'none',
|
||||
}} />
|
||||
)}
|
||||
{[[0,0,0],[0,1,90],[1,1,180],[1,0,270]].map(([x,y,r], i) => (
|
||||
<svg key={i} width="12" height="12" viewBox="0 0 12 12" style={{
|
||||
position: 'absolute',
|
||||
[x ? 'right' : 'left']: 6,
|
||||
[y ? 'bottom' : 'top']: 6,
|
||||
transform: `rotate(${r}deg)`,
|
||||
pointerEvents: 'none',
|
||||
}}>
|
||||
<path d="M0 4 L0 0 L4 0" stroke={color} strokeWidth="1.2" fill="none" strokeLinecap="round" />
|
||||
</svg>
|
||||
))}
|
||||
<div style={{ position: 'relative', zIndex: 1 }}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
37
src/pages/saju/_shell/TitleBlock.jsx
Normal file
37
src/pages/saju/_shell/TitleBlock.jsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import OrnamentBloom from './OrnamentBloom';
|
||||
|
||||
export default function TitleBlock({
|
||||
title, subtitle, color = '#1F2A44', subColor = '#6B6B6B',
|
||||
center = true, withBloom = true, gold = '#D4AF37',
|
||||
}) {
|
||||
return (
|
||||
<div style={{ textAlign: center ? 'center' : 'left' }}>
|
||||
{withBloom && center && (
|
||||
<div style={{
|
||||
display: 'flex', justifyContent: 'center', gap: 12,
|
||||
alignItems: 'center', marginBottom: 10, color: gold,
|
||||
}}>
|
||||
<svg width="40" height="6" viewBox="0 0 40 6">
|
||||
<path d="M0 3 L36 3" stroke={gold} strokeWidth="1" />
|
||||
<circle cx="38" cy="3" r="1.5" fill={gold} />
|
||||
</svg>
|
||||
<OrnamentBloom size={18} color={gold} />
|
||||
<svg width="40" height="6" viewBox="0 0 40 6">
|
||||
<circle cx="2" cy="3" r="1.5" fill={gold} />
|
||||
<path d="M4 3 L40 3" stroke={gold} strokeWidth="1" />
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
<h1 className="font-title" style={{
|
||||
margin: 0, fontSize: 30, color, letterSpacing: '-0.02em',
|
||||
}}>{title}</h1>
|
||||
{subtitle && (
|
||||
<div style={{
|
||||
marginTop: 6, fontSize: 13, color: subColor, lineHeight: 1.55,
|
||||
letterSpacing: '-0.01em',
|
||||
}}>{subtitle}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
21
src/pages/saju/_shell/TopRibbon.jsx
Normal file
21
src/pages/saju/_shell/TopRibbon.jsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
|
||||
function CloudOrnament({ width = 90, color = '#D4AF37', opacity = 0.85 }) {
|
||||
return (
|
||||
<svg width={width} height={width / 3.5} viewBox="0 0 90 26" fill="none" opacity={opacity}>
|
||||
<path d="M5 18 Q12 6 24 12 Q36 4 48 14 Q60 6 72 14 Q82 8 88 18"
|
||||
stroke={color} strokeWidth="1" fill="none" />
|
||||
<circle cx="24" cy="12" r="1.4" fill={color} />
|
||||
<circle cx="48" cy="14" r="1.4" fill={color} />
|
||||
<circle cx="72" cy="14" r="1.4" fill={color} />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default function TopRibbon({ color = '#D4AF37', opacity = 0.5 }) {
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', padding: '4px 0 0', opacity }}>
|
||||
<CloudOrnament width={90} color={color} opacity={0.85} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user