guardia-messenger/components/LineIcon.tsx

340 lines
15 KiB
TypeScript

/**
* GUARDiA Messenger — 라인 아이콘 컴포넌트 (React Native)
* react-native-svg 없이 View + StyleSheet만 사용하여 선 아이콘을 구현.
* 폐쇄망/온프레미스 환경 호환.
* stroke 스타일은 View border로 표현, 복잡한 패스는 Text 유니코드 대체.
*/
import { View, StyleSheet, Text } from 'react-native'
interface Props {
name: keyof typeof ICONS
size?: number
color?: string
}
/** 아이콘 이름 → 렌더 함수 맵 */
const ICONS = {
dashboard: (s: number, c: string) => <DashboardIcon size={s} color={c} />,
sr: (s: number, c: string) => <SrIcon size={s} color={c} />,
chat: (s: number, c: string) => <ChatIcon size={s} color={c} />,
bell: (s: number, c: string) => <BellIcon size={s} color={c} />,
settings: (s: number, c: string) => <SettingsIcon size={s} color={c} />,
server: (s: number, c: string) => <ServerIcon size={s} color={c} />,
alert: (s: number, c: string) => <AlertIcon size={s} color={c} />,
check: (s: number, c: string) => <CheckIcon size={s} color={c} />,
sync: (s: number, c: string) => <SyncIcon size={s} color={c} />,
user: (s: number, c: string) => <UserIcon size={s} color={c} />,
lock: (s: number, c: string) => <LockIcon size={s} color={c} />,
globe: (s: number, c: string) => <GlobeIcon size={s} color={c} />,
mail: (s: number, c: string) => <MailIcon size={s} color={c} />,
send: (s: number, c: string) => <SendIcon size={s} color={c} />,
mic: (s: number, c: string) => <MicIcon size={s} color={c} />,
building: (s: number, c: string) => <BuildingIcon size={s} color={c} />,
ai: (s: number, c: string) => <AiIcon size={s} color={c} />,
zap: (s: number, c: string) => <ZapIcon size={s} color={c} />,
} as const
export default function LineIcon({ name, size = 22, color = '#00A0C8' }: Props) {
const renderer = ICONS[name]
if (!renderer) return null
return renderer(size, color)
}
/* ─── 개별 아이콘 구현 ───────────────────────────── */
function DashboardIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, justifyContent: 'flex-end', gap: 2, flexDirection: 'row', alignItems: 'flex-end' }}>
<View style={{ width: size * 0.22, height: size * 0.45, borderWidth: b, borderColor: color, borderRadius: 2 }} />
<View style={{ width: size * 0.22, height: size * 0.65, borderWidth: b, borderColor: color, borderRadius: 2 }} />
<View style={{ width: size * 0.22, height: size * 0.85, borderWidth: b, borderColor: color, borderRadius: 2 }} />
</View>
)
}
function SrIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
<View style={{ width: size * 0.72, height: size * 0.82, borderWidth: b, borderColor: color, borderRadius: 3 }}>
<View style={{ marginTop: size * 0.22, marginHorizontal: size * 0.1 }}>
<View style={{ height: b, backgroundColor: color, marginBottom: size * 0.1 }} />
<View style={{ height: b, backgroundColor: color, width: '75%', marginBottom: size * 0.1 }} />
<View style={{ height: b, backgroundColor: color, width: '55%' }} />
</View>
</View>
</View>
)
}
function ChatIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
<View style={{
width: size * 0.82, height: size * 0.68,
borderWidth: b, borderColor: color, borderRadius: size * 0.14,
position: 'relative',
}}>
<View style={{
position: 'absolute', bottom: -size * 0.22, left: size * 0.1,
width: size * 0.18, height: size * 0.18,
borderRightWidth: b, borderBottomWidth: b, borderColor: color,
transform: [{ rotate: '45deg' }],
}} />
</View>
</View>
)
}
function BellIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
<View style={{
width: size * 0.62, height: size * 0.55,
borderWidth: b, borderColor: color,
borderTopLeftRadius: size * 0.31, borderTopRightRadius: size * 0.31,
borderBottomWidth: 0, marginTop: size * 0.1,
}} />
<View style={{ width: size * 0.75, height: b, backgroundColor: color }} />
<View style={{
width: size * 0.28, height: size * 0.14,
borderWidth: b, borderColor: color,
borderTopWidth: 0, borderRadius: size * 0.07,
marginTop: -b,
}} />
</View>
)
}
function SettingsIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
const r = (size - b * 2) / 2
const innerR = r * 0.3
return (
<View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
<View style={{
width: size * 0.55, height: size * 0.55,
borderWidth: b, borderColor: color, borderRadius: size,
}} />
<View style={{
position: 'absolute',
width: size * 0.22, height: size * 0.22,
borderWidth: b, borderColor: color, borderRadius: size,
backgroundColor: 'transparent',
}} />
</View>
)
}
function ServerIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center', gap: size * 0.06 }}>
<View style={{ width: size * 0.82, height: size * 0.32, borderWidth: b, borderColor: color, borderRadius: 3 }}>
<View style={{ width: size * 0.08, height: size * 0.08, borderRadius: size, backgroundColor: color,
position: 'absolute', top: '50%', left: size * 0.05, marginTop: -size * 0.04 }} />
</View>
<View style={{ width: size * 0.82, height: size * 0.32, borderWidth: b, borderColor: color, borderRadius: 3 }}>
<View style={{ width: size * 0.08, height: size * 0.08, borderRadius: size, backgroundColor: color,
position: 'absolute', top: '50%', left: size * 0.05, marginTop: -size * 0.04 }} />
</View>
</View>
)
}
function AlertIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
<View style={{
width: 0, height: 0,
borderLeftWidth: size * 0.45, borderRightWidth: size * 0.45,
borderBottomWidth: size * 0.8,
borderLeftColor: 'transparent', borderRightColor: 'transparent',
borderBottomColor: color,
opacity: 0.15,
position: 'absolute',
}} />
<View style={{
width: 0, height: 0,
borderLeftWidth: size * 0.41, borderRightWidth: size * 0.41,
borderBottomWidth: size * 0.73,
borderLeftColor: 'transparent', borderRightColor: 'transparent',
borderBottomColor: 'white',
position: 'absolute', bottom: size * 0.04,
}} />
<View style={{ position: 'absolute', bottom: size * 0.23, alignItems: 'center', gap: 2 }}>
<View style={{ width: b * 1.5, height: size * 0.22, backgroundColor: color, borderRadius: 2 }} />
<View style={{ width: b * 1.5, height: b * 1.5, backgroundColor: color, borderRadius: size }} />
</View>
</View>
)
}
function CheckIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
<View style={{
width: size * 0.82, height: size * 0.82,
borderWidth: b, borderColor: color, borderRadius: size,
}}>
<View style={{ position: 'absolute', top: '35%', left: '20%',
width: size * 0.2, height: b * 1.5, backgroundColor: color,
transform: [{ rotate: '45deg' }] }} />
<View style={{ position: 'absolute', top: '22%', left: '32%',
width: size * 0.38, height: b * 1.5, backgroundColor: color,
transform: [{ rotate: '-55deg' }] }} />
</View>
</View>
)
}
function SyncIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
<View style={{
width: size * 0.7, height: size * 0.7,
borderWidth: b, borderColor: color, borderRadius: size,
borderTopColor: 'transparent',
}} />
<View style={{
position: 'absolute', top: size * 0.04,
width: 0, height: 0,
borderLeftWidth: size * 0.1, borderRightWidth: size * 0.1,
borderBottomWidth: size * 0.15,
borderLeftColor: 'transparent', borderRightColor: 'transparent',
borderBottomColor: color,
}} />
</View>
)
}
function UserIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, alignItems: 'center', paddingTop: size * 0.05 }}>
<View style={{ width: size * 0.38, height: size * 0.38, borderWidth: b, borderColor: color, borderRadius: size }} />
<View style={{
width: size * 0.7, height: size * 0.35,
borderWidth: b, borderColor: color,
borderTopLeftRadius: size * 0.35, borderTopRightRadius: size * 0.35,
borderBottomWidth: 0, marginTop: size * 0.04,
}} />
</View>
)
}
function LockIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
<View style={{
width: size * 0.5, height: size * 0.26,
borderWidth: b, borderColor: color,
borderTopLeftRadius: size * 0.25, borderTopRightRadius: size * 0.25,
borderBottomWidth: 0, marginBottom: -b,
}} />
<View style={{ width: size * 0.7, height: size * 0.42, borderWidth: b, borderColor: color, borderRadius: 5 }}>
<View style={{ width: b * 2, height: b * 2, backgroundColor: color, borderRadius: size,
alignSelf: 'center', marginTop: size * 0.12 }} />
</View>
</View>
)
}
function GlobeIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
<View style={{ width: size * 0.82, height: size * 0.82, borderWidth: b, borderColor: color, borderRadius: size }} />
<View style={{ position: 'absolute', width: size * 0.82, height: b, backgroundColor: color, top: '50%', marginTop: -b / 2 }} />
<View style={{ position: 'absolute', height: size * 0.82, width: b, backgroundColor: color, left: '50%', marginLeft: -b / 2 }} />
</View>
)
}
function MailIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
<View style={{ width: size * 0.82, height: size * 0.6, borderWidth: b, borderColor: color, borderRadius: 4 }}>
<View style={{ position: 'absolute', top: 0, left: 0, right: 0, height: size * 0.26,
borderBottomWidth: b, borderBottomColor: color, transform: [{ skewX: '0deg' }] }}>
<View style={{ width: '100%', height: '100%', opacity: 0.3, backgroundColor: color, borderRadius: 2 }} />
</View>
</View>
</View>
)
}
function SendIcon({ size, color }: { size: number; color: string }) {
return (
<Text style={{ fontSize: size * 0.7, color, lineHeight: size }}></Text>
)
}
function MicIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, alignItems: 'center' }}>
<View style={{ width: size * 0.32, height: size * 0.48, borderWidth: b, borderColor: color,
borderRadius: size * 0.16, marginTop: size * 0.06 }} />
<View style={{
width: size * 0.55, height: size * 0.28,
borderWidth: b, borderColor: color,
borderTopLeftRadius: size * 0.28, borderTopRightRadius: size * 0.28,
borderBottomWidth: 0, marginTop: size * 0.02,
}} />
<View style={{ width: b, height: size * 0.12, backgroundColor: color }} />
<View style={{ width: size * 0.3, height: b, backgroundColor: color }} />
</View>
)
}
function BuildingIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, justifyContent: 'flex-end', alignItems: 'center' }}>
<View style={{ width: size * 0.7, height: size * 0.7, borderWidth: b, borderColor: color, borderRadius: 2 }}>
<View style={{ position: 'absolute', top: size * 0.1, left: size * 0.1,
width: size * 0.15, height: size * 0.15, borderWidth: b, borderColor: color }} />
<View style={{ position: 'absolute', top: size * 0.1, right: size * 0.1,
width: size * 0.15, height: size * 0.15, borderWidth: b, borderColor: color }} />
<View style={{ position: 'absolute', top: size * 0.3, left: size * 0.1,
width: size * 0.15, height: size * 0.15, borderWidth: b, borderColor: color }} />
<View style={{ position: 'absolute', top: size * 0.3, right: size * 0.1,
width: size * 0.15, height: size * 0.15, borderWidth: b, borderColor: color }} />
</View>
<View style={{ width: b, height: size * 0.15, backgroundColor: color, position: 'absolute', bottom: 0, left: size * 0.2 }} />
<View style={{ width: b, height: size * 0.15, backgroundColor: color, position: 'absolute', bottom: 0, right: size * 0.2 }} />
</View>
)
}
function AiIcon({ size, color }: { size: number; color: string }) {
const b = size * 0.07
return (
<View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
<View style={{ width: size * 0.82, height: size * 0.55, borderWidth: b, borderColor: color, borderRadius: 5 }}>
<View style={{ flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center', flex: 1, paddingHorizontal: size * 0.06 }}>
{[0,1,2].map(i => (
<View key={i} style={{ width: size * 0.12, height: size * 0.12, borderWidth: b, borderColor: color, borderRadius: size }} />
))}
</View>
</View>
</View>
)
}
function ZapIcon({ size, color }: { size: number; color: string }) {
return (
<Text style={{ fontSize: size * 0.75, color, lineHeight: size }}></Text>
)
}