1597 lines
57 KiB
TypeScript
1597 lines
57 KiB
TypeScript
// frontend\src\components\ui\Icons.tsx
|
|
|
|
'use client'
|
|
|
|
import type { JSX, ReactNode, SVGProps } from 'react'
|
|
|
|
export type IconProps = SVGProps<SVGSVGElement> & {
|
|
title?: string
|
|
}
|
|
|
|
type IconComponent = (props: IconProps) => JSX.Element
|
|
|
|
function iconClassName(className: string | undefined, extra: string) {
|
|
return [className, extra].filter(Boolean).join(' ')
|
|
}
|
|
|
|
function IconBase({
|
|
title,
|
|
children,
|
|
viewBox = '0 0 24 24',
|
|
className,
|
|
...props
|
|
}: IconProps & {
|
|
children: ReactNode
|
|
}) {
|
|
return (
|
|
<svg
|
|
viewBox={viewBox}
|
|
fill="none"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
className={className}
|
|
stroke="currentColor"
|
|
strokeWidth={1.8}
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
aria-hidden={title ? undefined : true}
|
|
role={title ? 'img' : undefined}
|
|
{...props}
|
|
>
|
|
{title ? <title>{title}</title> : null}
|
|
{children}
|
|
</svg>
|
|
)
|
|
}
|
|
|
|
/* ---------------------------------- */
|
|
/* Einzelne Icons */
|
|
/* ---------------------------------- */
|
|
|
|
export function FemaleBreastIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<g transform="translate(0 1.5)">
|
|
<path d="M4.5 6.5C2.7 8.1 2.4 11.5 4.1 13.7C5.8 15.9 8.8 16.2 10.7 12.7C11.1 11.9 11.5 10.9 12 9.7C12.5 10.9 12.9 11.9 13.3 12.7C15.2 16.2 18.2 15.9 19.9 13.7C21.6 11.5 21.3 8.1 19.5 6.5" />
|
|
<circle cx="8" cy="12.2" r="0.8" fill="currentColor" stroke="none" />
|
|
<circle cx="16" cy="12.2" r="0.8" fill="currentColor" stroke="none" />
|
|
</g>
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function ButtocksIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
{/* obere Kante */}
|
|
<path d="M8 4.5H16" />
|
|
|
|
{/* linke Außenkontur */}
|
|
<path d="M8 4.5C8 6.3 7.3 7.7 6.5 9.2C5.5 11 5 13.1 5 15.4C5 17.8 5.8 19.9 7 21H10" />
|
|
|
|
{/* rechte Außenkontur */}
|
|
<path d="M16 4.5C16 6.3 16.7 7.7 17.5 9.2C18.5 11 19 13.1 19 15.4C19 17.8 18.2 19.9 17 21H14" />
|
|
|
|
{/* mittlere Falte */}
|
|
<path d="M12 9.8V21" />
|
|
|
|
{/* innere Po-Linien */}
|
|
<path d="M8.8 13.7C10.2 14.6 11.3 13.9 12 11.4" />
|
|
<path d="M15.2 13.7C13.8 14.6 12.7 13.9 12 11.4" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function FemaleGenitaliaIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
{/* äußere Form */}
|
|
<path d="M12 2.6C10.7 2.8 9.5 4 8.3 5.9C6.9 8.1 6 10.6 6 13.3C6 18.4 8.8 21.5 12 22C15.2 21.5 18 18.4 18 13.3C18 10.6 17.1 8.1 15.7 5.9C14.5 4 13.3 2.8 12 2.6Z" />
|
|
|
|
{/* mittlere Form */}
|
|
<path d="M12 4.6C11 4.8 10.2 5.8 9.5 7.3C8.8 8.9 8.4 10.9 8.4 13C8.4 17.2 9.9 20.1 12 20.8C14.1 20.1 15.6 17.2 15.6 13C15.6 10.9 15.2 8.9 14.5 7.3C13.8 5.8 13 4.8 12 4.6Z" />
|
|
|
|
{/* obere kleine Form */}
|
|
<path d="M12 4.8C11.4 4.9 10.9 5.5 10.6 6.4C10.2 7.4 10.3 8.5 10.8 9.3C11.1 9.8 11.5 10.1 12 10.2C12.5 10.1 12.9 9.8 13.2 9.3C13.7 8.5 13.8 7.4 13.4 6.4C13.1 5.5 12.6 4.9 12 4.8Z" />
|
|
|
|
{/* innere längliche Form */}
|
|
<path d="M12 10.8C11.4 10.9 10.9 11.6 10.5 12.8C10.1 14 9.9 15.5 9.9 17C9.9 19.7 10.8 21.5 12 22C13.2 21.5 14.1 19.7 14.1 17C14.1 15.5 13.9 14 13.5 12.8C13.1 11.6 12.6 10.9 12 10.8Z" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function FingeringIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
{/* stilisierte Vulva weiter rechts */}
|
|
<path d="M18.2 3.6C16.7 4.8 15.5 7.2 15.5 10.7C15.5 15.8 16.8 19.7 18.2 21C19.6 19.7 20.9 15.8 20.9 10.7C20.9 7.2 19.7 4.8 18.2 3.6Z" />
|
|
<path d="M18.2 6.9C17.4 8.4 16.9 10.4 16.9 12.8C16.9 15.5 17.4 17.7 18.2 19.1C19 17.7 19.5 15.5 19.5 12.8C19.5 10.4 19 8.4 18.2 6.9Z" />
|
|
<path d="M18.2 9.8V17.2" />
|
|
|
|
{/* Zeige- und Mittelfinger seitlich von links */}
|
|
<path d="M4.2 11.2H15.5" />
|
|
<path d="M4.7 13.6H15.5" />
|
|
<path d="M15.5 11.2C16.3 11.2 16.8 11.8 16.8 12.4C16.8 13 16.3 13.6 15.5 13.6" />
|
|
|
|
{/* Handfläche / Handkante - bewusst weiter weg von der Vulva */}
|
|
<path d="M4.7 13.6C3.4 13.6 2.5 14.5 2.5 15.8V16.6C2.5 18.8 4.3 20.5 6.5 20.5H9.7C11.4 20.5 12.8 19.5 13.3 17.9" />
|
|
|
|
{/* angedeutete eingeklappte Finger / Knöchel */}
|
|
<path d="M5.7 15.4C6.3 14.9 7.2 14.9 7.8 15.4" />
|
|
<path d="M7.9 15.5C8.5 15 9.4 15 10 15.5" />
|
|
<path d="M10.1 15.6C10.6 15.2 11.4 15.2 11.9 15.6" />
|
|
|
|
{/* Daumen */}
|
|
<path d="M4.8 16.2L3.3 15.1C2.7 14.7 2.6 13.9 3 13.4C3.4 12.8 4.2 12.7 4.8 13.1L5.7 13.8" />
|
|
|
|
{/* kleine Bewegungslinien */}
|
|
<path d="M21.5 10.6L22.7 9.9" />
|
|
<path d="M21.7 13.2H22.9" />
|
|
<path d="M21.5 15.8L22.7 16.5" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function BlowjobIcon(props: IconProps) {
|
|
return (
|
|
<IconBase
|
|
{...props}
|
|
className={iconClassName(props.className, 'origin-center scale-[1.35]')}
|
|
viewBox="30 20 230 390"
|
|
>
|
|
<g
|
|
transform="translate(0,432) scale(0.1,-0.1)"
|
|
fill="currentColor"
|
|
stroke="none"
|
|
>
|
|
<path d="M703 3936 c-174 -57 -260 -250 -185 -419 28 -62 103 -132 169 -157 245 -92 484 149 392 394 -25 68 -92 140 -157 168 -58 26 -162 33 -219 14z" />
|
|
<path d="M812 3271 c-60 -21 -114 -68 -143 -124 -11 -20 -94 -163 -184 -317 -112 -190 -165 -289 -165 -309 0 -23 31 -66 148 -205 81 -96 174 -209 207 -250 61 -77 87 -96 130 -96 15 0 42 -18 73 -47 l49 -48 -13 -355 c-9 -254 -22 -438 -44 -648 l-32 -293 24 -47 c42 -84 142 -112 222 -62 60 37 70 72 115 410 52 400 59 460 50 466 -4 2 -69 85 -143 184 -127 168 -136 183 -136 224 0 35 6 50 29 75 28 30 47 36 101 31 34 -3 58 -23 125 -103 32 -37 59 -66 62 -64 2 3 11 63 18 134 l15 128 -35 205 c-19 113 -51 302 -70 420 -67 404 -95 542 -120 586 -30 51 -83 92 -143 110 -58 18 -76 17 -140 -5z m-87 -770 c14 -85 23 -156 21 -158 -7 -7 -136 181 -136 197 0 18 83 137 87 124 1 -5 14 -78 28 -163z" />
|
|
<path d="M1580 2564 c-157 -60 -228 -142 -238 -274 -7 -111 39 -224 115 -278 16 -11 58 -30 93 -42 170 -57 341 27 391 192 48 156 -14 308 -153 379 -43 22 -173 36 -208 23z" />
|
|
<path d="M2055 2186 c-38 -16 -84 -82 -92 -130 -7 -46 20 -119 54 -146 15 -11 49 -27 77 -35 93 -27 151 -68 180 -127 15 -29 26 -70 26 -92 1 -41 1 -41 15 -15 25 46 48 187 43 268 -11 195 -166 337 -303 277z" />
|
|
<path d="M1603 1854 c-17 -9 -83 -69 -145 -135 -76 -80 -120 -119 -134 -119 -15 0 -46 30 -104 101 -45 55 -93 105 -106 111 -49 23 -113 -24 -100 -75 3 -12 31 -56 62 -97 217 -284 203 -269 251 -270 23 0 47 13 92 51 l61 51 0 -73 c0 -62 4 -77 26 -106 28 -37 72 -63 106 -63 13 0 42 9 66 20 l43 19 45 -62 c69 -94 124 -191 130 -228 4 -33 1 -36 -162 -168 -91 -73 -174 -147 -185 -165 -38 -62 -16 -158 44 -191 30 -16 64 -16 472 -8 484 9 489 10 515 72 9 23 9 38 0 66 -21 62 -58 72 -308 80 l-214 7 124 65 c67 36 134 75 146 87 52 46 77 133 60 209 -9 43 -25 65 -127 176 -64 69 -137 153 -162 186 -48 64 -136 209 -187 311 -61 121 -119 164 -219 164 -32 0 -72 -7 -90 -16z" />
|
|
</g>
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function HandjobIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
{/* Penis vertikal */}
|
|
<path d="M12 3.6C13.6 3.6 14.9 4.9 14.9 6.5V18.2" />
|
|
<path d="M12 3.6C10.4 3.6 9.1 4.9 9.1 6.5V18.2" />
|
|
<path d="M9.1 7H14.9" />
|
|
|
|
{/* Hoden */}
|
|
<circle cx="9.6" cy="19.1" r="1.6" />
|
|
<circle cx="14.4" cy="19.1" r="1.6" />
|
|
|
|
{/* Hand umfasst den Schaft */}
|
|
<path d="M6.1 11.4C6.1 10.6 6.7 10 7.5 10H15.8C17.1 10 18.1 11 18.1 12.3V14.6C18.1 16.3 16.8 17.6 15.1 17.6H8.6C7.2 17.6 6.1 16.5 6.1 15.1V11.4Z" />
|
|
|
|
{/* Finger über dem Schaft */}
|
|
<path d="M7.4 10.1V7.9C7.4 7.2 7.9 6.7 8.6 6.7C9.3 6.7 9.8 7.2 9.8 7.9V10" />
|
|
<path d="M9.8 10V7.2C9.8 6.5 10.3 6 11 6C11.7 6 12.2 6.5 12.2 7.2V10" />
|
|
<path d="M12.2 10V7.7C12.2 7 12.7 6.5 13.4 6.5C14.1 6.5 14.6 7 14.6 7.7V10" />
|
|
<path d="M14.6 10V8.8C14.6 8.1 15.1 7.6 15.8 7.6C16.5 7.6 17 8.1 17 8.8V11.1" />
|
|
|
|
{/* Daumen */}
|
|
<path d="M6.3 14.2L4.5 13.1C3.9 12.7 3.7 11.9 4.1 11.3C4.5 10.7 5.3 10.5 5.9 10.9L7.3 11.7" />
|
|
|
|
{/* Griff-/Bewegungslinien */}
|
|
<path d="M18.9 10.2L20.2 9.4" />
|
|
<path d="M19.3 13H20.8" />
|
|
<path d="M18.9 15.8L20.2 16.6" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function SixtyNineIcon(props: IconProps) {
|
|
return (
|
|
<IconBase
|
|
{...props}
|
|
className={iconClassName(props.className, 'origin-center scale-[1.65]')}
|
|
viewBox="45 45 410 165"
|
|
>
|
|
<g transform="translate(0,262) scale(0.1,-0.1)" fill="currentColor" stroke="none">
|
|
<path d="M2794 2030 c-72 -15 -162 -68 -239 -142 -41 -39 -75 -74 -75 -79 0 -4 19 1 43 11 85 39 155 21 264 -68 71 -58 104 -68 164 -52 81 22 130 100 116 185 -8 50 -33 81 -91 114 -57 33 -121 44 -182 31z" />
|
|
<path d="M3213 1780 c-85 -17 -177 -89 -219 -170 -26 -52 -30 -165 -9 -231 24 -72 110 -159 179 -182 63 -21 149 -22 210 -1 64 22 147 100 177 166 71 161 -20 356 -192 409 -65 20 -81 21 -146 9z" />
|
|
<path d="M1672 1714 c-29 -14 -65 -42 -80 -61 -15 -19 -103 -188 -197 -376 l-170 -342 -205 -7 c-365 -14 -433 -21 -474 -49 -40 -27 -70 -89 -60 -123 11 -37 46 -66 98 -81 72 -22 732 -21 824 0 120 28 123 31 280 273 126 194 147 222 181 235 63 26 179 45 313 52 122 7 127 7 140 -14 12 -19 21 -21 130 -21 l118 0 0 -32 c-1 -18 -11 -120 -24 -227 -18 -148 -21 -201 -13 -219 23 -49 43 -52 370 -52 361 0 388 3 428 42 56 57 27 149 -52 162 -19 3 -133 11 -254 17 -121 6 -220 12 -221 13 0 0 26 114 59 251 69 292 73 341 34 407 -32 55 -71 85 -133 104 -36 11 -87 11 -272 3 -263 -12 -297 -10 -523 36 -201 42 -230 43 -297 9z" />
|
|
<path d="M3632 1304 l-264 -175 -234 1 -233 1 -6 -23 c-27 -117 -35 -161 -32 -164 2 -3 94 -9 203 -15 109 -6 216 -15 237 -20 91 -23 132 -110 88 -185 -12 -20 -19 -39 -16 -42 8 -8 123 26 181 55 80 39 204 142 280 232 37 45 73 81 80 81 6 0 87 -64 179 -142 225 -193 241 -203 326 -203 61 0 72 3 95 27 40 40 45 118 12 190 -21 44 -56 82 -204 218 -267 246 -381 340 -412 340 -10 0 -136 -79 -280 -176z" />
|
|
<path d="M1335 1431 c-117 -56 -179 -153 -178 -276 0 -67 20 -136 43 -150 5 -3 61 97 125 225 129 258 129 258 10 201z" />
|
|
<path d="M1902 1125 c-159 -81 -188 -288 -57 -403 66 -59 84 -62 349 -62 132 0 257 3 277 6 l37 6 -16 28 c-15 25 -14 43 7 229 13 111 20 205 17 209 -4 4 -132 8 -284 10 l-277 3 -53 -26z" />
|
|
</g>
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function CowgirlIcon(props: IconProps) {
|
|
return (
|
|
<IconBase
|
|
{...props}
|
|
className={iconClassName(props.className, 'origin-center scale-[1.35]')}
|
|
viewBox="45 15 350 270"
|
|
>
|
|
<g transform="translate(0,300) scale(0.1,-0.1)" fill="currentColor" stroke="none">
|
|
<path d="M2253 2766 c-91 -30 -148 -80 -190 -171 -70 -151 -4 -326 151 -399 112 -53 245 -29 341 63 151 143 101 407 -93 493 -58 26 -154 32 -209 14z" />
|
|
<path d="M2672 2283 c-42 -20 -69 -55 -82 -104 -17 -62 2 -111 71 -185 33 -36 67 -80 75 -99 18 -45 18 -116 -1 -162 -20 -48 -19 -50 11 -22 42 39 114 139 147 204 39 77 48 182 23 250 -43 111 -152 164 -244 118z" />
|
|
<path d="M2255 2076 c-48 -22 -89 -73 -156 -196 -147 -269 -157 -302 -107 -378 30 -45 83 -67 145 -60 32 4 34 2 48 -46 43 -144 61 -386 34 -439 -8 -14 -99 -117 -202 -228 -104 -112 -195 -219 -203 -237 -22 -54 -18 -150 9 -202 40 -82 36 -81 482 -78 l390 3 55 30 c37 20 65 45 87 78 35 53 308 280 331 275 7 -2 91 -70 188 -153 97 -82 195 -160 217 -173 55 -30 143 -31 180 -2 32 26 51 81 44 131 -11 86 -40 120 -295 362 -291 273 -306 287 -336 287 -15 0 -139 -84 -322 -218 -398 -289 -416 -302 -442 -302 -12 0 -22 4 -22 8 0 4 69 59 153 122 153 113 194 155 215 219 21 61 13 103 -58 305 -79 223 -93 291 -110 521 -7 88 -19 184 -27 213 -17 63 -70 127 -128 153 -47 22 -127 24 -170 5z" />
|
|
<path d="M664 766 c-218 -71 -285 -346 -124 -506 148 -149 397 -105 490 85 35 70 35 189 2 257 -30 60 -87 117 -147 147 -58 29 -161 37 -221 17z" />
|
|
<path d="M1265 676 c-56 -25 -107 -78 -130 -133 -35 -83 -6 -202 66 -270 62 -59 82 -62 345 -63 132 0 246 -1 255 0 13 0 11 10 -13 56 -23 47 -28 70 -28 128 0 90 26 150 101 230 30 32 56 62 57 67 2 5 -127 9 -300 9 -296 0 -304 -1 -353 -24z" />
|
|
</g>
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function CunnilingusIcon(props: IconProps) {
|
|
return (
|
|
<IconBase
|
|
{...props}
|
|
className={iconClassName(props.className, 'origin-center scale-[1.8]')}
|
|
viewBox="15 40 455 125"
|
|
>
|
|
<g transform="translate(0,204) scale(0.1,-0.1)" fill="currentColor" stroke="none">
|
|
<path d="M3140 1498 c-23 -16 -68 -76 -133 -181 -94 -150 -100 -157 -131 -157 -22 0 -40 -8 -55 -24 -23 -25 -24 -44 -6 -103 6 -18 -7 -36 -76 -106 -46 -46 -117 -110 -157 -141 -41 -32 -87 -79 -104 -105 -27 -42 -29 -52 -26 -121 4 -89 26 -128 91 -162 57 -29 153 -29 342 1 163 25 232 25 419 -5 122 -19 159 -11 217 47 100 100 105 222 13 297 -92 75 -239 176 -272 187 -24 9 -46 10 -69 3 -31 -8 -38 -6 -79 27 -24 20 -44 43 -44 52 0 8 43 94 96 191 110 201 124 250 82 289 -37 34 -68 37 -108 11z m-125 -678 l29 -30 -47 0 -48 0 16 30 c9 17 17 30 18 30 2 0 16 -13 32 -30z" />
|
|
<path d="M2422 1199 c-96 -48 -154 -157 -138 -262 9 -59 58 -131 110 -162 75 -43 83 -42 166 26 113 91 200 181 200 204 0 64 -83 171 -156 201 -50 21 -132 18 -182 -7z" />
|
|
<path d="M1975 974 c-55 -14 -212 -52 -350 -84 -291 -68 -292 -68 -342 -114 -34 -30 -56 -38 -173 -66 -351 -83 -332 -80 -592 -80 -259 0 -275 -3 -317 -56 -26 -33 -28 -95 -4 -135 33 -55 55 -59 344 -59 374 0 698 23 864 61 72 16 137 32 145 34 11 4 19 -5 25 -27 6 -19 21 -38 35 -45 31 -16 640 -18 721 -3 97 19 129 83 68 134 -30 26 -31 26 -212 26 -100 0 -188 4 -195 9 -9 5 19 16 80 30 51 12 107 30 124 40 143 87 115 307 -44 351 -50 14 -62 12 -177 -16z" />
|
|
<path d="M3816 856 c-94 -35 -148 -106 -154 -202 -10 -146 87 -254 228 -254 155 0 264 142 225 292 -33 128 -180 208 -299 164z" />
|
|
<path d="M4229 645 c-36 -20 -59 -58 -59 -99 0 -56 16 -84 67 -116 98 -62 223 -31 348 85 33 31 51 53 40 50 -61 -21 -81 -24 -116 -16 -38 9 -79 33 -137 83 -37 32 -98 37 -143 13z" />
|
|
</g>
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function DoggyIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props} viewBox="25 20 285 275">
|
|
<g transform="translate(0,322) scale(0.1,-0.1)" fill="currentColor" stroke="none">
|
|
<path d="M1251 2965 c-129 -36 -221 -159 -221 -296 0 -119 91 -248 201 -284 113 -38 251 -5 326 78 58 65 78 120 77 212 -1 95 -17 137 -77 202 -79 86 -194 119 -306 88z" />
|
|
<path d="M1074 2314 c-65 -23 -120 -76 -143 -139 -22 -58 -153 -470 -233 -730 -56 -181 -56 -206 -8 -292 25 -45 35 -84 65 -279 19 -125 35 -237 35 -250 l0 -24 -182 0 c-207 0 -238 -8 -295 -73 -57 -65 -53 -154 9 -214 62 -60 77 -63 431 -70 178 -3 335 -3 350 1 48 12 57 48 57 218 0 84 -9 262 -19 396 l-19 242 24 83 c81 267 127 413 133 420 4 4 15 -16 24 -45 14 -43 43 -83 157 -213 267 -304 302 -331 375 -301 70 30 83 89 34 156 -38 52 -28 63 51 55 188 -18 183 -18 219 7 58 39 76 72 76 137 -1 95 -51 147 -153 157 -85 9 -150 -15 -213 -78 -27 -27 -59 -68 -70 -91 l-21 -41 -22 30 c-11 16 -31 40 -44 53 -13 13 -49 57 -79 98 -53 73 -55 77 -115 301 -33 125 -67 254 -76 287 -44 170 -191 254 -348 199z" />
|
|
<path d="M2485 1737 c-103 -34 -171 -97 -205 -187 -75 -202 71 -415 283 -413 267 3 401 313 222 511 -71 79 -207 119 -300 89z" />
|
|
<path d="M1383 1280 c-58 -12 -95 -33 -133 -76 -67 -77 -76 -153 -36 -294 20 -71 76 -377 76 -418 0 -6 -10 -12 -22 -12 -65 -1 -68 -5 -68 -99 0 -54 -5 -96 -14 -113 -12 -23 -12 -27 1 -32 8 -3 94 -6 192 -6 242 0 221 -27 221 286 0 229 1 245 18 241 9 -3 86 -16 171 -29 l153 -23 25 -50 c72 -144 179 -184 272 -101 l24 21 -6 -35 c-18 -107 -29 -230 -23 -253 11 -45 48 -49 384 -40 l304 8 29 33 c32 36 37 67 14 99 -22 32 -64 39 -280 53 -104 7 -193 14 -196 16 -3 1 12 97 32 211 21 114 38 222 39 239 0 45 -49 135 -89 161 -51 34 -93 37 -238 18 -91 -12 -158 -16 -213 -11 l-80 6 -43 -45 c-41 -43 -46 -45 -98 -45 -66 1 -108 24 -169 95 -104 120 -185 205 -194 204 -6 -1 -30 -5 -53 -9z" />
|
|
</g>
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function MissionaryIcon(props: IconProps) {
|
|
return (
|
|
<IconBase
|
|
{...props}
|
|
className={iconClassName(props.className, 'origin-center scale-[1.55]')}
|
|
viewBox="25 35 415 195"
|
|
>
|
|
<g transform="translate(0,266) scale(0.1,-0.1)" fill="currentColor" stroke="none">
|
|
<path d="M2750 2166 c-72 -19 -117 -45 -156 -88 -78 -86 -103 -208 -65 -309 64 -170 253 -252 411 -178 72 34 117 79 153 157 26 57 29 71 25 135 -9 141 -90 240 -228 281 -63 19 -79 19 -140 2z" />
|
|
<path d="M2194 1771 c-30 -14 -385 -243 -413 -267 -10 -8 173 -420 186 -417 5 1 92 47 192 102 101 56 187 99 191 96 4 -2 13 -18 20 -34 10 -26 9 -36 -9 -74 -12 -24 -21 -61 -21 -84 l0 -40 -167 -7 c-93 -4 -183 -8 -201 -9 l-34 -2 -104 235 c-57 129 -104 239 -104 245 0 5 23 25 51 43 28 19 47 37 43 42 -5 4 -54 33 -110 64 -117 65 -166 72 -225 33 -47 -31 -82 -101 -75 -152 3 -22 26 -218 51 -435 25 -217 53 -419 61 -447 36 -128 178 -182 366 -138 177 41 378 65 622 75 219 10 256 9 288 -4 88 -37 163 27 146 124 -1 8 4 35 11 60 10 36 11 56 1 98 -15 67 -50 108 -149 175 -42 28 -79 55 -83 61 -7 10 -60 143 -173 434 -28 75 -60 138 -79 160 -66 75 -192 104 -282 63z" />
|
|
<path d="M1360 1199 c-16 -23 -35 -61 -41 -83 -6 -23 -14 -48 -18 -55 -7 -14 -165 -131 -270 -202 l-44 -29 -317 0 c-312 0 -318 0 -350 -23 -75 -50 -95 -143 -48 -215 47 -70 53 -71 455 -78 l358 -7 196 95 196 95 -28 249 c-16 137 -30 258 -31 268 -5 34 -26 28 -58 -15z" />
|
|
<path d="M3222 1154 c-136 -42 -233 -205 -203 -343 41 -191 223 -297 407 -234 67 23 154 110 177 177 67 197 -61 399 -261 411 -44 3 -85 -1 -120 -11z" />
|
|
<path d="M3785 911 c-48 -12 -82 -39 -105 -85 -40 -84 -17 -152 72 -213 122 -81 280 -41 450 116 38 35 67 65 66 67 -2 1 -30 -6 -62 -17 -90 -31 -154 -12 -248 70 -45 40 -104 72 -130 70 -7 -1 -27 -4 -43 -8z" />
|
|
</g>
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function ReverseCowgirlIcon(props: IconProps) {
|
|
return (
|
|
<IconBase
|
|
{...props}
|
|
className={iconClassName(props.className, 'origin-center scale-[1.35]')}
|
|
viewBox="45 15 350 270"
|
|
>
|
|
<g transform="translate(0,300) scale(0.1,-0.1)" fill="currentColor" stroke="none">
|
|
<path d="M2422 2770 c-64 -14 -142 -60 -175 -105 -54 -74 -69 -122 -65 -205 7 -126 69 -214 186 -268 46 -21 65 -24 126 -20 120 8 212 71 261 179 24 55 27 71 23 138 -4 60 -11 88 -34 131 -60 110 -200 175 -322 150z" />
|
|
<path d="M2026 2290 c-69 -21 -136 -130 -136 -221 0 -49 32 -147 67 -202 30 -49 124 -169 128 -165 2 2 -3 27 -11 57 -23 89 9 174 100 259 49 47 62 84 53 154 -6 46 -45 93 -94 114 -36 16 -64 16 -107 4z" />
|
|
<path d="M2415 2079 c-45 -13 -110 -72 -133 -121 -15 -32 -23 -83 -32 -193 -21 -272 -34 -341 -106 -549 -91 -265 -90 -261 -70 -330 14 -46 29 -70 69 -110 29 -28 68 -59 87 -69 33 -16 14 -17 -443 -17 -523 0 -511 1 -581 -60 -105 -93 -106 -251 -1 -353 71 -69 49 -68 927 -65 782 3 787 3 815 24 52 39 68 80 67 174 l0 86 65 52 c36 28 75 52 86 51 11 0 94 -63 185 -141 91 -77 185 -153 209 -169 116 -75 236 -29 234 91 -1 90 -34 131 -318 402 -143 136 -271 251 -284 254 -38 11 -65 -4 -249 -140 -200 -147 -167 -145 -283 -14 -62 70 -68 81 -75 134 -8 69 9 222 39 342 l22 87 50 0 c71 0 112 20 136 66 30 61 25 107 -24 201 -155 295 -179 331 -241 359 -44 20 -101 23 -151 8z" />
|
|
<path d="M635 746 c-69 -32 -112 -70 -140 -127 -37 -73 -48 -132 -35 -196 32 -150 146 -246 295 -247 59 0 79 4 130 31 111 58 165 146 165 269 0 123 -65 221 -181 274 -64 29 -168 27 -234 -4z" />
|
|
</g>
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function StandingSexIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props} viewBox="20 20 195 375">
|
|
<g transform="translate(0,420) scale(0.1,-0.1)" fill="currentColor" stroke="none">
|
|
<path d="M1280 3832 c-54 -22 -119 -62 -142 -88 -35 -40 -71 -135 -71 -190 0 -143 70 -239 213 -295 192 -74 404 76 404 286 0 116 -66 222 -171 275 -64 32 -169 38 -233 12z" />
|
|
<path d="M510 3776 c-135 -29 -233 -154 -233 -298 0 -225 235 -369 438 -269 210 104 227 392 32 525 -34 23 -73 39 -111 45 -33 6 -62 11 -65 10 -3 0 -31 -6 -61 -13z" />
|
|
<path d="M1763 3400 c-70 -31 -107 -115 -85 -188 7 -22 38 -64 76 -104 36 -37 72 -83 81 -104 18 -43 20 -108 4 -153 -6 -18 -9 -34 -7 -36 8 -8 110 129 138 185 81 160 74 276 -22 367 -59 56 -113 66 -185 33z" />
|
|
<path d="M1345 3166 c-27 -12 -145 -133 -256 -261 -54 -63 -99 -134 -99 -155 0 -9 14 -45 31 -79 33 -66 67 -91 124 -91 24 0 25 -2 25 -67 l0 -68 108 -77 c59 -42 150 -99 202 -127 52 -29 103 -62 112 -74 61 -80 -4 -227 -101 -227 -40 0 -123 30 -233 86 -37 19 -72 34 -78 34 -5 0 -10 -22 -10 -48 0 -45 -3 -51 -42 -83 -135 -107 -466 -403 -476 -424 -17 -37 -15 -85 6 -122 17 -31 324 -386 390 -450 41 -40 84 -43 133 -10 51 34 53 100 5 148 -13 13 -74 84 -135 157 -110 133 -124 160 -98 192 13 17 111 80 198 127 158 86 434 261 464 295 48 52 70 131 56 200 -50 249 -61 485 -36 723 19 183 19 221 -6 275 -41 90 -113 140 -201 140 -29 -1 -66 -7 -83 -14z" />
|
|
<path d="M592 3101 c-65 -22 -126 -79 -148 -138 -24 -61 -16 -139 56 -573 33 -201 66 -405 74 -454 17 -101 46 -154 109 -195 32 -21 37 -29 37 -64 0 -21 4 -37 9 -35 5 2 83 68 173 147 89 80 166 147 170 150 4 3 -2 60 -12 126 -10 66 -16 122 -15 124 6 6 195 -90 195 -98 0 -11 154 -81 210 -96 52 -14 81 -6 104 27 19 27 21 98 4 120 -7 9 -58 42 -113 73 -55 32 -137 84 -183 116 -45 33 -86 59 -90 59 -22 1 -81 74 -143 178 -70 115 -71 119 -94 249 -13 72 -33 149 -44 171 -28 54 -82 98 -143 117 -66 19 -91 19 -156 -4z" />
|
|
<path d="M1370 1623 c-91 -57 -173 -107 -182 -110 -16 -5 -18 -23 -18 -192 0 -175 1 -187 20 -199 30 -18 70 -106 70 -151 0 -30 -7 -49 -29 -73 l-28 -33 30 -215 c36 -264 41 -286 73 -307 33 -21 103 -21 136 1 54 36 58 97 29 460 l-19 229 49 336 c53 363 53 361 42 360 -5 0 -82 -48 -173 -106z" />
|
|
<path d="M1033 1419 c-29 -17 -53 -36 -53 -42 0 -7 25 -39 55 -72 l54 -60 1 103 c0 56 -1 102 -2 102 -2 0 -27 -14 -55 -31z" />
|
|
<path d="M744 1108 c7 -93 5 -105 -53 -367 -34 -149 -61 -288 -61 -309 0 -80 75 -152 158 -152 42 0 104 32 126 64 9 15 44 137 77 273 60 242 61 247 42 263 -11 8 -75 78 -142 155 -68 77 -130 147 -138 155 -14 13 -15 4 -9 -82z" />
|
|
</g>
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function StandingDoggySexIcon(props: IconProps) {
|
|
return (
|
|
<IconBase
|
|
{...props}
|
|
className={iconClassName(props.className, 'origin-center scale-[1.25]')}
|
|
viewBox="0 0 212 402"
|
|
>
|
|
<g
|
|
transform="translate(0,402) scale(0.1,-0.1)"
|
|
fill="currentColor"
|
|
stroke="none"
|
|
>
|
|
<path d="M325 3703 c-70 -25 -107 -55 -148 -115 -47 -73 -60 -119 -54 -193 12 -158 133 -275 294 -283 60 -4 80 0 127 21 194 89 246 330 106 490 -73 83 -217 118 -325 80z" />
|
|
<path d="M1503 3640 c-64 -26 -137 -95 -166 -158 -16 -36 -22 -66 -22 -127 0 -94 24 -154 88 -218 60 -60 117 -82 212 -82 98 0 155 23 219 90 143 146 99 391 -86 486 -62 32 -176 36 -245 9z" />
|
|
<path d="M1070 3281 c-73 -26 -134 -92 -156 -169 -20 -69 -15 -214 12 -317 l18 -69 11 54 c21 102 64 147 180 185 44 15 92 36 106 46 59 42 78 148 37 209 -51 75 -116 94 -208 61z" />
|
|
<path d="M450 3045 c-87 -27 -162 -113 -175 -202 -8 -46 146 -989 171 -1052 9 -23 38 -61 66 -86 l50 -45 16 -353 16 -353 -28 -129 c-15 -72 -43 -199 -63 -283 -23 -103 -33 -165 -29 -188 8 -39 47 -89 87 -109 63 -33 174 -3 204 55 9 17 48 158 87 313 l70 282 14 415 14 415 -30 194 c-17 106 -28 196 -25 199 3 4 16 0 28 -8 36 -23 309 -156 359 -175 59 -22 93 -14 118 28 43 69 19 114 -92 172 -91 48 -281 173 -330 217 -20 18 -68 88 -106 155 -67 118 -70 126 -90 247 -12 69 -30 143 -41 164 -29 56 -92 108 -152 126 -63 19 -80 19 -139 1z" />
|
|
<path d="M1431 2974 c-51 -19 -117 -81 -137 -129 -8 -19 -30 -117 -49 -217 -19 -101 -46 -223 -60 -271 -14 -48 -25 -89 -25 -91 0 -8 125 -83 198 -120 49 -25 76 -45 87 -65 17 -34 20 -88 6 -124 -14 -36 -61 -76 -96 -83 -35 -6 -145 30 -246 82 -36 19 -70 34 -76 34 -6 0 -20 -26 -33 -59 -17 -46 -20 -69 -15 -107 8 -58 35 -121 62 -150 12 -12 35 -75 57 -160 21 -76 55 -202 76 -279 21 -77 48 -177 59 -222 l21 -82 -45 -283 c-44 -280 -45 -309 -20 -371 16 -39 110 -61 156 -37 27 15 47 59 64 142 8 40 39 181 69 313 l55 240 -14 109 c-29 218 -75 609 -75 637 0 15 5 40 11 56 11 26 13 21 39 -80 31 -126 53 -157 111 -157 29 0 43 7 63 31 15 17 26 43 26 59 0 16 -21 168 -46 338 -38 264 -43 317 -34 352 l11 41 54 -6 c79 -10 137 19 161 81 16 42 16 48 0 107 -22 78 -138 348 -171 399 -47 71 -157 103 -244 72z" />
|
|
</g>
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function MaleGenitaliaIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M12 4.5C13.9 4.5 15.5 6.1 15.5 8V12.8C15.5 14.7 13.9 16.3 12 16.3C10.1 16.3 8.5 14.7 8.5 12.8V8C8.5 6.1 10.1 4.5 12 4.5Z" />
|
|
<circle cx="9.2" cy="18.2" r="1.8" />
|
|
<circle cx="14.8" cy="18.2" r="1.8" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function AnusIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<circle cx="12" cy="12" r="4.2" />
|
|
<circle cx="12" cy="12" r="1.2" />
|
|
<path d="M12 3.5V5.2" />
|
|
<path d="M12 18.8V20.5" />
|
|
<path d="M3.5 12H5.2" />
|
|
<path d="M18.8 12H20.5" />
|
|
<path d="M6 6L7.2 7.2" />
|
|
<path d="M16.8 16.8L18 18" />
|
|
<path d="M18 6L16.8 7.2" />
|
|
<path d="M7.2 16.8L6 18" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function CoveredContentIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<circle cx="12" cy="12" r="8.5" />
|
|
<path d="M6 6L18 18" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function MaleBreastIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M6 9.5C7.2 8.2 9.1 7.5 12 7.5C14.9 7.5 16.8 8.2 18 9.5" />
|
|
<path d="M6.5 15.5C8 14.3 9.8 13.8 12 13.8C14.2 13.8 16 14.3 17.5 15.5" />
|
|
<circle cx="12" cy="11.1" r="0.9" fill="currentColor" stroke="none" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function BellyIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M9 4.5C8.4 6.6 8 8.8 8 11C8 14.8 9.2 17.8 12 19.5C14.8 17.8 16 14.8 16 11C16 8.8 15.6 6.6 15 4.5" />
|
|
<circle cx="12" cy="12.7" r="0.8" fill="currentColor" stroke="none" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function FeetIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M8.2 6.5C8.2 9.8 7.6 12.1 6 14.5C5.2 15.7 5.2 17.3 6.3 18.1C7.1 18.7 8.2 18.7 9.1 18.2L11.2 17" />
|
|
<path d="M15.8 6.5C15.8 9.8 16.4 12.1 18 14.5C18.8 15.7 18.8 17.3 17.7 18.1C16.9 18.7 15.8 18.7 14.9 18.2L12.8 17" />
|
|
<path d="M9.3 7.2H9.31" />
|
|
<path d="M14.7 7.2H14.71" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function FaceIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<circle cx="12" cy="12" r="8.5" />
|
|
<circle cx="9" cy="10" r="0.8" fill="currentColor" stroke="none" />
|
|
<circle cx="15" cy="10" r="0.8" fill="currentColor" stroke="none" />
|
|
<path d="M9.2 15C10 15.7 10.9 16 12 16C13.1 16 14 15.7 14.8 15" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function FemalePersonIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<circle cx="12" cy="5.2" r="2.1" />
|
|
<path d="M8.7 10.2C9.4 8.8 10.5 8.1 12 8.1C13.5 8.1 14.6 8.8 15.3 10.2" />
|
|
<path d="M9.2 10.5L7.2 16.2H16.8L14.8 10.5" />
|
|
<path d="M12 16.2V21" />
|
|
<path d="M9.2 21H14.8" />
|
|
<path d="M8.2 13.2L5.6 15.8" />
|
|
<path d="M15.8 13.2L18.4 15.8" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function MalePersonIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<circle cx="12" cy="5.2" r="2.1" />
|
|
<path d="M8.8 10.2C9.5 8.8 10.6 8.1 12 8.1C13.4 8.1 14.5 8.8 15.2 10.2" />
|
|
<path d="M8.8 10.5H15.2V16.4H8.8V10.5Z" />
|
|
<path d="M10.2 16.4L9.2 21" />
|
|
<path d="M13.8 16.4L14.8 21" />
|
|
<path d="M8.8 12.2L5.8 15.2" />
|
|
<path d="M15.2 12.2L18.2 15.2" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function ClothingIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M9 4.5L12 6L15 4.5" />
|
|
<path d="M8.2 5L4.8 7.2L6.3 10.2L8 9.4V20H16V9.4L17.7 10.2L19.2 7.2L15.8 5" />
|
|
<path d="M10 6.2C10.4 7.2 11.1 7.8 12 7.8C12.9 7.8 13.6 7.2 14 6.2" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function CropTopIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
{/* Träger */}
|
|
<path d="M9.2 4.5L12 6.2L14.8 4.5" />
|
|
<path d="M8.2 5.2L5.4 7.6" />
|
|
<path d="M15.8 5.2L18.6 7.6" />
|
|
|
|
{/* kurze Top-Form */}
|
|
<path d="M8.2 5.2C8.5 7.1 9.6 8.4 12 8.4C14.4 8.4 15.5 7.1 15.8 5.2" />
|
|
<path d="M7.2 8.2L6.3 15.2H17.7L16.8 8.2" />
|
|
<path d="M7.2 8.2C8.4 9.2 10 9.8 12 9.8C14 9.8 15.6 9.2 16.8 8.2" />
|
|
|
|
{/* Crop-Kante */}
|
|
<path d="M6.3 15.2C8.1 16 10 16.4 12 16.4C14 16.4 15.9 16 17.7 15.2" />
|
|
|
|
{/* leichte Stofffalten */}
|
|
<path d="M9.2 10.8L8.8 14.5" />
|
|
<path d="M14.8 10.8L15.2 14.5" />
|
|
<path d="M12 10.2V15.5" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function BraIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M4.5 8.5C6.4 7.4 8.8 7.6 10.2 9.2C11 10.1 11.5 11.5 12 13.2C12.5 11.5 13 10.1 13.8 9.2C15.2 7.6 17.6 7.4 19.5 8.5" />
|
|
<path d="M5 8.8C5.2 12.5 7 15.5 9.4 15.5C10.8 15.5 11.6 14.6 12 13.2" />
|
|
<path d="M19 8.8C18.8 12.5 17 15.5 14.6 15.5C13.2 15.5 12.4 14.6 12 13.2" />
|
|
<path d="M4.5 8.5L3.5 6.5" />
|
|
<path d="M19.5 8.5L20.5 6.5" />
|
|
<path d="M9.8 15.5H14.2" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function UnderwearIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M5 7.5H19" />
|
|
<path d="M6 7.5L8.2 18.5H10.6L12 14.8L13.4 18.5H15.8L18 7.5" />
|
|
<path d="M8.2 7.5C8.9 10.1 10.1 12.2 12 14.8C13.9 12.2 15.1 10.1 15.8 7.5" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function PantsIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M8 4.5H16" />
|
|
<path d="M8 4.5L6.8 20H10.2L12 10.8L13.8 20H17.2L16 4.5" />
|
|
<path d="M12 4.8V10.8" />
|
|
<path d="M9.2 6.5H10.2" />
|
|
<path d="M13.8 6.5H14.8" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function DressIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M9 4.5H15" />
|
|
<path d="M9 4.5C9.2 6.8 10 8.2 12 9.4C14 8.2 14.8 6.8 15 4.5" />
|
|
<path d="M12 9.4L7.2 20H16.8L12 9.4Z" />
|
|
<path d="M8.4 13.8H15.6" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function ShoesIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M4.5 14.5C6.7 14.6 8.4 14.1 9.8 12.8L12 15.5H5.2C4.6 15.5 4.2 15.1 4.5 14.5Z" />
|
|
<path d="M12 14.5C14.2 14.6 15.9 14.1 17.3 12.8L19.5 15.5H12.7C12.1 15.5 11.7 15.1 12 14.5Z" />
|
|
<path d="M7.2 13.9L8.1 15.4" />
|
|
<path d="M14.7 13.9L15.6 15.4" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function SockIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M9 3.8H15" />
|
|
<path d="M9.5 3.8V12.7L6.2 15.9C5.2 16.9 5.4 18.5 6.6 19.2C7.5 19.8 8.7 19.7 9.5 18.9L14.5 14.1V3.8" />
|
|
<path d="M9.5 8H14.5" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function CondomIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M12 4.5C14.2 4.5 16 6.3 16 8.5V15.2C16 17.4 14.2 19.2 12 19.2C9.8 19.2 8 17.4 8 15.2V8.5C8 6.3 9.8 4.5 12 4.5Z" />
|
|
<path d="M10 19.2H14" />
|
|
<path d="M9.3 8.5H14.7" />
|
|
<path d="M12 6.2V7.2" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function ToyIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M12 4.5C13.7 4.5 15 5.8 15 7.5V15.5C15 17.2 13.7 18.5 12 18.5C10.3 18.5 9 17.2 9 15.5V7.5C9 5.8 10.3 4.5 12 4.5Z" />
|
|
<path d="M10 18.5H14" />
|
|
<path d="M10.2 7.8H13.8" />
|
|
<path d="M10.2 10.5H13.8" />
|
|
<circle cx="12" cy="14.5" r="0.8" fill="currentColor" stroke="none" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function BottleIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M10 3.8H14" />
|
|
<path d="M10.7 3.8V7.3C9.4 8.1 8.5 9.5 8.5 11.1V18.5C8.5 19.4 9.1 20 10 20H14C14.9 20 15.5 19.4 15.5 18.5V11.1C15.5 9.5 14.6 8.1 13.3 7.3V3.8" />
|
|
<path d="M8.5 12.5H15.5" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function BedIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M4.5 10.5V19" />
|
|
<path d="M19.5 13.5V19" />
|
|
<path d="M4.5 14H19.5" />
|
|
<path d="M4.5 10.5H10.5C11.3 10.5 12 11.2 12 12V14" />
|
|
<path d="M12 12H17.2C18.5 12 19.5 13 19.5 14.3V14" />
|
|
<path d="M6 8.5H9.5" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function ChairIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M8 4.5H16V12H8V4.5Z" />
|
|
<path d="M6.5 12H17.5" />
|
|
<path d="M8 12V20" />
|
|
<path d="M16 12V20" />
|
|
<path d="M9 16H15" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function PhoneIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<rect x="8" y="3.5" width="8" height="17" rx="1.8" />
|
|
<path d="M10.5 6H13.5" />
|
|
<circle cx="12" cy="17.5" r="0.7" fill="currentColor" stroke="none" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function CameraIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M8.5 7L9.8 5H14.2L15.5 7H18.5C19.3 7 20 7.7 20 8.5V17C20 17.8 19.3 18.5 18.5 18.5H5.5C4.7 18.5 4 17.8 4 17V8.5C4 7.7 4.7 7 5.5 7H8.5Z" />
|
|
<circle cx="12" cy="12.8" r="3" />
|
|
<circle cx="17" cy="9.5" r="0.6" fill="currentColor" stroke="none" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function RopeIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M8.5 5.5C10.5 3.7 13.5 3.7 15.5 5.5C17.6 7.4 17.6 10.6 15.5 12.5L12 15.8L8.5 12.5C6.4 10.6 6.4 7.4 8.5 5.5Z" />
|
|
<path d="M12 15.8V21" />
|
|
<path d="M10.5 18L13.5 16.8" />
|
|
<path d="M10.5 20.2L13.5 19" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function HandIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M8.5 12V6.5C8.5 5.7 9.1 5.1 9.9 5.1C10.7 5.1 11.3 5.7 11.3 6.5V11" />
|
|
<path d="M11.3 11V5.5C11.3 4.7 11.9 4.1 12.7 4.1C13.5 4.1 14.1 4.7 14.1 5.5V11.5" />
|
|
<path d="M14.1 11.5V7.2C14.1 6.4 14.7 5.8 15.5 5.8C16.3 5.8 16.9 6.4 16.9 7.2V14.5C16.9 18.2 14.7 20.5 11.7 20.5C9.7 20.5 8.2 19.5 7 17.8L5.5 15.6C5.1 15 5.3 14.2 5.9 13.8C6.5 13.4 7.2 13.6 7.7 14.1L8.5 15" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function MouthIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M4.5 12C6.5 9.8 8.4 8.8 12 10.8C15.6 8.8 17.5 9.8 19.5 12" />
|
|
<path d="M4.5 12C6.5 15.2 9.1 16.5 12 16.5C14.9 16.5 17.5 15.2 19.5 12" />
|
|
<path d="M7.5 12.2H16.5" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function TongueIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
{/* äußere Lippenkontur */}
|
|
<path d="M3.8 10.2C5.7 7.6 8 6.6 10.3 7.4C11.1 7.7 11.5 8 12 8C12.5 8 12.9 7.7 13.7 7.4C16 6.6 18.3 7.6 20.2 10.2" />
|
|
<path d="M3.8 10.2C5.1 12.7 7.1 14.2 9.4 14.9" />
|
|
<path d="M20.2 10.2C18.9 12.7 16.9 14.2 14.6 14.9" />
|
|
|
|
{/* innere Lippen / Mundöffnung */}
|
|
<path d="M6.2 10.8C7.8 9.6 9.5 9.6 10.9 10.3C11.4 10.6 11.7 10.8 12 10.8C12.3 10.8 12.6 10.6 13.1 10.3C14.5 9.6 16.2 9.6 17.8 10.8" />
|
|
<path d="M6.2 10.8C7.6 12.3 9.1 13 10.6 13.2" />
|
|
<path d="M17.8 10.8C16.4 12.3 14.9 13 13.4 13.2" />
|
|
|
|
{/* Zunge */}
|
|
<path d="M9.4 12.8C9.4 16.8 10.4 20.2 12 20.2C13.6 20.2 14.6 16.8 14.6 12.8" />
|
|
<path d="M9.4 12.8C10.2 13.4 11 13.7 12 13.7C13 13.7 13.8 13.4 14.6 12.8" />
|
|
<path d="M12 14.4V18.6" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function BathIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M5 11.5H20" />
|
|
<path d="M6 11.5V14.5C6 17.3 8.2 19.5 11 19.5H14C16.8 19.5 19 17.3 19 14.5V11.5" />
|
|
<path d="M8 19.5L7 21" />
|
|
<path d="M17 19.5L18 21" />
|
|
<path d="M5 11.5V7.5C5 5.6 6.4 4.2 8.2 4.2C9.8 4.2 11 5.4 11 7" />
|
|
<path d="M9.8 7H12.2" />
|
|
<circle cx="9" cy="9" r="0.5" fill="currentColor" stroke="none" />
|
|
<circle cx="12" cy="9.5" r="0.5" fill="currentColor" stroke="none" />
|
|
<circle cx="15" cy="9" r="0.5" fill="currentColor" stroke="none" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function ShowerIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M7 8.5C7 5.7 9.2 3.5 12 3.5C14.8 3.5 17 5.7 17 8.5" />
|
|
<path d="M8.5 8.5H15.5" />
|
|
<path d="M8 11.5L7.2 13" />
|
|
<path d="M11 11.5L10.2 13.2" />
|
|
<path d="M14 11.5L13.2 13.2" />
|
|
<path d="M17 11.5L16.2 13" />
|
|
<path d="M9 16L8.2 17.5" />
|
|
<path d="M12 16L11.2 17.8" />
|
|
<path d="M15 16L14.2 17.5" />
|
|
<path d="M17 8.5V20" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function BlindfoldIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M4 11C6.2 9.2 8.7 8.5 12 8.5C15.3 8.5 17.8 9.2 20 11" />
|
|
<path d="M4 11C6.2 12.8 8.7 13.5 12 13.5C15.3 13.5 17.8 12.8 20 11" />
|
|
<path d="M7 10.2L9.2 12.6" />
|
|
<path d="M10.8 8.7L13.8 13.2" />
|
|
<path d="M15.2 9.2L17.2 11.8" />
|
|
<path d="M4 11L2.8 10.2" />
|
|
<path d="M20 11L21.2 10.2" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function CollarIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M6 8.5C7.7 7.2 9.7 6.5 12 6.5C14.3 6.5 16.3 7.2 18 8.5" />
|
|
<path d="M6 8.5V12C6 13.6 8.7 15 12 15C15.3 15 18 13.6 18 12V8.5" />
|
|
<path d="M6 12C7.7 13.3 9.7 14 12 14C14.3 14 16.3 13.3 18 12" />
|
|
<circle cx="12" cy="16.8" r="1.3" />
|
|
<path d="M12 15V15.6" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function ButtPlugIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M12 4.5C14.2 6.2 15.2 8.1 15.2 10.2C15.2 12.4 13.8 14 12 14C10.2 14 8.8 12.4 8.8 10.2C8.8 8.1 9.8 6.2 12 4.5Z" />
|
|
<path d="M10 14H14" />
|
|
<path d="M9 17H15" />
|
|
<path d="M10.5 14L9 17" />
|
|
<path d="M13.5 14L15 17" />
|
|
<path d="M8.2 19.5H15.8" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function StrapOnIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M6 13.5C7.8 11.8 9.8 11 12 11C14.2 11 16.2 11.8 18 13.5" />
|
|
<path d="M7.5 14.5C8.8 15.8 10.3 16.5 12 16.5C13.7 16.5 15.2 15.8 16.5 14.5" />
|
|
<path d="M12 5C13.5 5 14.7 6.2 14.7 7.7V11.4" />
|
|
<path d="M12 5C10.5 5 9.3 6.2 9.3 7.7V11.4" />
|
|
<path d="M12 5V3.8" />
|
|
<path d="M9 18.5H15" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function TowelIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
{/* äußere Handtuchform */}
|
|
<rect x="6" y="3.8" width="12" height="15.2" rx="1.6" />
|
|
|
|
{/* obere innere Faltkante */}
|
|
<path d="M14.3 3.8V9.8" />
|
|
|
|
{/* gefaltete Lagen unten */}
|
|
<path d="M6 12.2H18" />
|
|
<path d="M6 15H18" />
|
|
|
|
{/* kleiner Aufhänger / untere Lasche */}
|
|
<path d="M10.2 19V20.8H13.2V19" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function BikiniIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M5 8.5C6.2 7.2 8.7 7.3 10.2 9.1C11 10.1 11.5 11.5 12 13C12.5 11.5 13 10.1 13.8 9.1C15.3 7.3 17.8 7.2 19 8.5" />
|
|
<path d="M6 9C6.2 11.8 7.4 13.8 9.3 13.8C10.5 13.8 11.3 13.1 12 13" />
|
|
<path d="M18 9C17.8 11.8 16.6 13.8 14.7 13.8C13.5 13.8 12.7 13.1 12 13" />
|
|
<path d="M8 17.5H16" />
|
|
<path d="M8 17.5L10 20H14L16 17.5" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function FishnetIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M8 4.5H16" />
|
|
<path d="M8.5 4.5L6.5 20" />
|
|
<path d="M15.5 4.5L17.5 20" />
|
|
<path d="M7.4 9H16.6" />
|
|
<path d="M6.9 13.5H17.1" />
|
|
<path d="M6.5 18H17.5" />
|
|
<path d="M9 5L16.5 19.5" />
|
|
<path d="M15 5L7.5 19.5" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function HotpantsIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<path d="M6 7.5H18" />
|
|
<path d="M6.5 7.5L7.5 16.5H10.7L12 12.5L13.3 16.5H16.5L17.5 7.5" />
|
|
<path d="M8.5 9.8H10" />
|
|
<path d="M14 9.8H15.5" />
|
|
<path d="M12 7.8V12.5" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
export function UnknownContentIcon(props: IconProps) {
|
|
return (
|
|
<IconBase {...props}>
|
|
<circle cx="12" cy="12" r="9" />
|
|
<path d="M12 8V12" />
|
|
<circle cx="12" cy="16" r="0.7" fill="currentColor" stroke="none" />
|
|
</IconBase>
|
|
)
|
|
}
|
|
|
|
/* ---------------------------------- */
|
|
/* Label-Mapping */
|
|
/* ---------------------------------- */
|
|
|
|
type SegmentLabelMeta = {
|
|
match: string[]
|
|
text: string
|
|
icon: IconComponent
|
|
}
|
|
|
|
const SEGMENT_LABEL_META: SegmentLabelMeta[] = [
|
|
// Sex positions
|
|
{
|
|
match: ['69', 'sixty_nine', 'sixty-nine', 'sixtynine'],
|
|
text: '69',
|
|
icon: SixtyNineIcon,
|
|
},
|
|
{
|
|
match: ['missionary'],
|
|
text: 'Missionary',
|
|
icon: MissionaryIcon,
|
|
},
|
|
{
|
|
match: ['reverse_cowgirl', 'reverse-cowgirl', 'reverse cowgirl'],
|
|
text: 'Reverse Cowgirl',
|
|
icon: ReverseCowgirlIcon,
|
|
},
|
|
{
|
|
match: ['cowgirl', 'riding', 'ride'],
|
|
text: 'Cowgirl',
|
|
icon: CowgirlIcon,
|
|
},
|
|
{
|
|
match: ['blowjob', 'fellatio'],
|
|
text: 'Blowjob',
|
|
icon: BlowjobIcon,
|
|
},
|
|
{
|
|
match: ['cunnilingus'],
|
|
text: 'Cunnilingus',
|
|
icon: CunnilingusIcon,
|
|
},
|
|
{
|
|
match: ['facesitting', 'face_sitting', 'face-sitting', 'face sitting'],
|
|
text: 'Facesitting',
|
|
icon: FemalePersonIcon,
|
|
},
|
|
{
|
|
match: ['oral'],
|
|
text: 'Oral',
|
|
icon: MouthIcon,
|
|
},
|
|
{
|
|
match: ['anal'],
|
|
text: 'Anal',
|
|
icon: AnusIcon,
|
|
},
|
|
{
|
|
match: ['handjob', 'hand_job', 'hand-job', 'manual'],
|
|
text: 'Handjob',
|
|
icon: HandjobIcon,
|
|
},
|
|
{
|
|
match: ['fingering', 'fingered'],
|
|
text: 'Fingering',
|
|
icon: FingeringIcon,
|
|
},
|
|
{
|
|
match: ['solo', 'masturbation'],
|
|
text: 'Solo',
|
|
icon: HandIcon,
|
|
},
|
|
{
|
|
match: ['standing_doggy', 'standing-doggy', 'standing doggy'],
|
|
text: 'Standing Doggy',
|
|
icon: StandingDoggySexIcon,
|
|
},
|
|
{
|
|
match: ['standing', 'standing_sex', 'standing-sex', 'standing sex'],
|
|
text: 'Stehend',
|
|
icon: StandingSexIcon,
|
|
},
|
|
{
|
|
match: ['doggy', 'doggystyle', 'doggy_style'],
|
|
text: 'Doggy',
|
|
icon: DoggyIcon,
|
|
},
|
|
{
|
|
match: ['unknown'],
|
|
text: 'Unbekannt',
|
|
icon: UnknownContentIcon,
|
|
},
|
|
// People
|
|
{
|
|
match: ['person_female', 'female_person'],
|
|
text: 'Weibliche Person',
|
|
icon: FemalePersonIcon,
|
|
},
|
|
{
|
|
match: ['person_male', 'male_person'],
|
|
text: 'Männliche Person',
|
|
icon: MalePersonIcon,
|
|
},
|
|
{
|
|
match: ['person_unknown', 'person'],
|
|
text: 'Person',
|
|
icon: UnknownContentIcon,
|
|
},
|
|
|
|
// Bodyparts
|
|
{
|
|
match: ['anus_exposed', 'anus'],
|
|
text: 'Anus',
|
|
icon: AnusIcon,
|
|
},
|
|
{
|
|
match: ['ass', 'buttocks_exposed', 'buttocks', 'bottom'],
|
|
text: 'Hintern',
|
|
icon: ButtocksIcon,
|
|
},
|
|
{
|
|
match: ['breasts', 'female_breast_exposed', 'breast_exposed', 'breasts_exposed', 'female_breast'],
|
|
text: 'Brüste',
|
|
icon: FemaleBreastIcon,
|
|
},
|
|
{
|
|
match: ['penis', 'male_genitalia_exposed', 'penis_exposed'],
|
|
text: 'Penis',
|
|
icon: MaleGenitaliaIcon,
|
|
},
|
|
{
|
|
match: ['tongue'],
|
|
text: 'Zunge',
|
|
icon: TongueIcon,
|
|
},
|
|
{
|
|
match: ['mouth', 'lips'],
|
|
text: 'Mund',
|
|
icon: MouthIcon,
|
|
},
|
|
{
|
|
match: ['pussy', 'female_genitalia_exposed', 'vulva_exposed', 'labia_exposed', 'vagina'],
|
|
text: 'Vagina',
|
|
icon: FemaleGenitaliaIcon,
|
|
},
|
|
{
|
|
match: ['belly_exposed', 'stomach_exposed', 'abdomen_exposed', 'navel_exposed', 'belly', 'stomach', 'abdomen', 'navel'],
|
|
text: 'Bauch',
|
|
icon: BellyIcon,
|
|
},
|
|
{
|
|
match: ['feet_exposed', 'foot_exposed', 'feet', 'foot'],
|
|
text: 'Füße',
|
|
icon: FeetIcon,
|
|
},
|
|
{
|
|
match: ['face_female', 'face_male', 'face', 'female_face', 'male_face'],
|
|
text: 'Gesicht',
|
|
icon: FaceIcon,
|
|
},
|
|
{
|
|
match: ['hand', 'hands', 'finger', 'fingers'],
|
|
text: 'Hand',
|
|
icon: HandIcon,
|
|
},
|
|
|
|
// Objects
|
|
{
|
|
match: ['bath', 'bathtub', 'tub'],
|
|
text: 'Badewanne',
|
|
icon: BathIcon,
|
|
},
|
|
{
|
|
match: ['blindfold'],
|
|
text: 'Augenbinde',
|
|
icon: BlindfoldIcon,
|
|
},
|
|
{
|
|
match: ['buttplug', 'butt_plug'],
|
|
text: 'Buttplug',
|
|
icon: ButtPlugIcon,
|
|
},
|
|
{
|
|
match: ['collar', 'choker'],
|
|
text: 'Halsband / Choker',
|
|
icon: CollarIcon,
|
|
},
|
|
{
|
|
match: ['dildo'],
|
|
text: 'Dildo',
|
|
icon: ToyIcon,
|
|
},
|
|
{
|
|
match: ['handcuffs', 'cuffs'],
|
|
text: 'Handschellen',
|
|
icon: RopeIcon,
|
|
},
|
|
{
|
|
match: ['rope', 'tie', 'restraint', 'restraints'],
|
|
text: 'Seil',
|
|
icon: RopeIcon,
|
|
},
|
|
{
|
|
match: ['shower'],
|
|
text: 'Dusche',
|
|
icon: ShowerIcon,
|
|
},
|
|
{
|
|
match: ['strapon', 'strap_on', 'strap-on'],
|
|
text: 'Strap-on',
|
|
icon: StrapOnIcon,
|
|
},
|
|
{
|
|
match: ['towel'],
|
|
text: 'Handtuch',
|
|
icon: TowelIcon,
|
|
},
|
|
{
|
|
match: ['vibrator'],
|
|
text: 'Vibrator',
|
|
icon: ToyIcon,
|
|
},
|
|
{
|
|
match: ['toy', 'plug'],
|
|
text: 'Toy',
|
|
icon: ToyIcon,
|
|
},
|
|
{
|
|
match: ['condom'],
|
|
text: 'Kondom',
|
|
icon: CondomIcon,
|
|
},
|
|
{
|
|
match: ['bottle', 'lotion', 'lubricant', 'lube'],
|
|
text: 'Flasche',
|
|
icon: BottleIcon,
|
|
},
|
|
{
|
|
match: ['bed', 'mattress', 'pillow', 'blanket', 'sheet', 'sheets'],
|
|
text: 'Bett',
|
|
icon: BedIcon,
|
|
},
|
|
{
|
|
match: ['chair', 'sofa', 'couch', 'bench', 'stool'],
|
|
text: 'Möbel',
|
|
icon: ChairIcon,
|
|
},
|
|
{
|
|
match: ['phone', 'smartphone', 'mobile'],
|
|
text: 'Handy',
|
|
icon: PhoneIcon,
|
|
},
|
|
{
|
|
match: ['camera', 'webcam'],
|
|
text: 'Kamera',
|
|
icon: CameraIcon,
|
|
},
|
|
|
|
// Clothing
|
|
{
|
|
match: ['bikini'],
|
|
text: 'Bikini',
|
|
icon: BikiniIcon,
|
|
},
|
|
{
|
|
match: ['bra', 'brassiere'],
|
|
text: 'BH',
|
|
icon: BraIcon,
|
|
},
|
|
{
|
|
match: ['dress'],
|
|
text: 'Kleid',
|
|
icon: DressIcon,
|
|
},
|
|
{
|
|
match: ['fishnet', 'fishnets'],
|
|
text: 'Fishnet',
|
|
icon: FishnetIcon,
|
|
},
|
|
{
|
|
match: ['heels', 'heel', 'high_heels', 'high-heels'],
|
|
text: 'High Heels',
|
|
icon: ShoesIcon,
|
|
},
|
|
{
|
|
match: ['hotpants', 'shorts'],
|
|
text: 'Hotpants',
|
|
icon: HotpantsIcon,
|
|
},
|
|
{
|
|
match: ['lingerie'],
|
|
text: 'Lingerie',
|
|
icon: UnderwearIcon,
|
|
},
|
|
{
|
|
match: ['panties', 'underwear', 'briefs', 'boxers', 'thong'],
|
|
text: 'Panties',
|
|
icon: UnderwearIcon,
|
|
},
|
|
{
|
|
match: ['shirt', 'tshirt', 't-shirt', 'blouse', 'hoodie', 'sweater', 'jacket', 'coat'],
|
|
text: 'Shirt',
|
|
icon: ClothingIcon,
|
|
},
|
|
{
|
|
match: ['skirt'],
|
|
text: 'Rock',
|
|
icon: DressIcon,
|
|
},
|
|
{
|
|
match: ['stockings', 'stocking', 'socks', 'sock'],
|
|
text: 'Stockings',
|
|
icon: SockIcon,
|
|
},
|
|
{
|
|
match: ['top', 'crop_top', 'crop-top', 'croptop'],
|
|
text: 'Crop Top',
|
|
icon: CropTopIcon,
|
|
},
|
|
{
|
|
match: ['pants', 'jeans', 'trousers', 'leggings'],
|
|
text: 'Hose',
|
|
icon: PantsIcon,
|
|
},
|
|
{
|
|
match: ['shoe', 'shoes', 'boot', 'boots', 'sneaker', 'sneakers'],
|
|
text: 'Schuhe',
|
|
icon: ShoesIcon,
|
|
},
|
|
{
|
|
match: ['clothing', 'clothes', 'garment', 'outfit'],
|
|
text: 'Kleidung',
|
|
icon: ClothingIcon,
|
|
},
|
|
]
|
|
|
|
function normalizeSegmentLabel(label?: string): string {
|
|
return String(label || '').trim().toLowerCase()
|
|
}
|
|
|
|
function normalizeLabelKey(value?: string): string {
|
|
return String(value || '')
|
|
.trim()
|
|
.toLowerCase()
|
|
.replaceAll('-', '_')
|
|
.replaceAll(' ', '_')
|
|
}
|
|
|
|
function labelMatches(normalizedLabel: string, key: string): boolean {
|
|
const label = normalizeLabelKey(normalizedLabel)
|
|
const matchKey = normalizeLabelKey(key)
|
|
|
|
if (!label || !matchKey) return false
|
|
|
|
return (
|
|
label === matchKey ||
|
|
label.startsWith(`${matchKey}_`) ||
|
|
label.endsWith(`_${matchKey}`) ||
|
|
label.includes(`_${matchKey}_`)
|
|
)
|
|
}
|
|
|
|
function findSegmentLabelMeta(label?: string): SegmentLabelMeta | null {
|
|
const normalized = normalizeSegmentLabel(label)
|
|
if (!normalized) return null
|
|
|
|
const labelKey = normalizeLabelKey(normalized)
|
|
|
|
// Wichtig:
|
|
// Personen-Labels exakt vor jedem Fuzzy-Matching behandeln.
|
|
// Sonst kann "person" auch "person_male" / "person_female" matchen.
|
|
if (labelKey === 'person_male' || labelKey === 'male_person') {
|
|
return {
|
|
match: ['person_male', 'male_person'],
|
|
text: 'Männliche Person',
|
|
icon: MalePersonIcon,
|
|
}
|
|
}
|
|
|
|
if (labelKey === 'person_female' || labelKey === 'female_person') {
|
|
return {
|
|
match: ['person_female', 'female_person'],
|
|
text: 'Weibliche Person',
|
|
icon: FemalePersonIcon,
|
|
}
|
|
}
|
|
|
|
if (labelKey === 'person' || labelKey === 'person_unknown') {
|
|
return {
|
|
match: ['person_unknown', 'person'],
|
|
text: 'Person',
|
|
icon: UnknownContentIcon,
|
|
}
|
|
}
|
|
|
|
// Erst exakte Matches prüfen.
|
|
for (const item of SEGMENT_LABEL_META) {
|
|
if (item.match.some((key) => labelKey === normalizeLabelKey(key))) {
|
|
return item
|
|
}
|
|
}
|
|
|
|
// Danach erst weiche Matches prüfen.
|
|
for (const item of SEGMENT_LABEL_META) {
|
|
if (item.match.some((key) => labelMatches(normalized, key))) {
|
|
return item
|
|
}
|
|
}
|
|
|
|
if (normalized.includes('_covered') || normalized.includes('covered_')) {
|
|
return {
|
|
match: [],
|
|
text: prettifyUnknownLabel(normalized).replace(/\bExposed\b/g, '').trim() || 'Bedeckt',
|
|
icon: CoveredContentIcon,
|
|
}
|
|
}
|
|
|
|
if (normalized.includes('ass') || normalized.includes('butt') || normalized.includes('bottom')) {
|
|
return { match: [], text: 'Hintern', icon: ButtocksIcon }
|
|
}
|
|
|
|
if (
|
|
normalized.includes('pussy') ||
|
|
normalized.includes('vagina') ||
|
|
normalized.includes('vulva') ||
|
|
normalized.includes('labia')
|
|
) {
|
|
return { match: [], text: 'Vagina', icon: FemaleGenitaliaIcon }
|
|
}
|
|
|
|
if (normalized.includes('penis')) {
|
|
return { match: [], text: 'Penis', icon: MaleGenitaliaIcon }
|
|
}
|
|
|
|
if (normalized.includes('breast')) {
|
|
return { match: [], text: 'Brüste', icon: FemaleBreastIcon }
|
|
}
|
|
|
|
if (normalized.includes('tongue')) {
|
|
return { match: [], text: 'Zunge', icon: TongueIcon }
|
|
}
|
|
|
|
if (normalized.includes('mouth') || normalized.includes('lips')) {
|
|
return { match: [], text: 'Mund', icon: MouthIcon }
|
|
}
|
|
|
|
if (normalized.includes('bath') || normalized.includes('tub')) {
|
|
return { match: [], text: 'Badewanne', icon: BathIcon }
|
|
}
|
|
|
|
if (normalized.includes('shower')) {
|
|
return { match: [], text: 'Dusche', icon: ShowerIcon }
|
|
}
|
|
|
|
if (normalized.includes('blindfold')) {
|
|
return { match: [], text: 'Augenbinde', icon: BlindfoldIcon }
|
|
}
|
|
|
|
if (normalized.includes('collar')) {
|
|
return { match: [], text: 'Halsband', icon: CollarIcon }
|
|
}
|
|
|
|
if (normalized.includes('buttplug') || normalized.includes('butt_plug')) {
|
|
return { match: [], text: 'Buttplug', icon: ButtPlugIcon }
|
|
}
|
|
|
|
if (
|
|
normalized.includes('strapon') ||
|
|
normalized.includes('strap_on') ||
|
|
normalized.includes('strap-on')
|
|
) {
|
|
return { match: [], text: 'Strap-on', icon: StrapOnIcon }
|
|
}
|
|
|
|
if (normalized.includes('dildo')) {
|
|
return { match: [], text: 'Dildo', icon: ToyIcon }
|
|
}
|
|
|
|
if (normalized.includes('vibrator')) {
|
|
return { match: [], text: 'Vibrator', icon: ToyIcon }
|
|
}
|
|
|
|
if (normalized.includes('handcuff') || normalized.includes('cuff')) {
|
|
return { match: [], text: 'Handschellen', icon: RopeIcon }
|
|
}
|
|
|
|
if (normalized.includes('rope') || normalized.includes('restraint') || normalized.includes('tie')) {
|
|
return { match: [], text: 'Seil', icon: RopeIcon }
|
|
}
|
|
|
|
if (normalized.includes('towel')) {
|
|
return { match: [], text: 'Handtuch', icon: TowelIcon }
|
|
}
|
|
|
|
if (normalized.includes('bikini')) {
|
|
return { match: [], text: 'Bikini', icon: BikiniIcon }
|
|
}
|
|
|
|
if (normalized.includes('bra')) {
|
|
return { match: [], text: 'BH', icon: BraIcon }
|
|
}
|
|
|
|
if (normalized.includes('dress')) {
|
|
return { match: [], text: 'Kleid', icon: DressIcon }
|
|
}
|
|
|
|
if (normalized.includes('skirt')) {
|
|
return { match: [], text: 'Rock', icon: DressIcon }
|
|
}
|
|
|
|
if (normalized.includes('fishnet')) {
|
|
return { match: [], text: 'Fishnet', icon: FishnetIcon }
|
|
}
|
|
|
|
if (normalized.includes('heel')) {
|
|
return { match: [], text: 'High Heels', icon: ShoesIcon }
|
|
}
|
|
|
|
if (normalized.includes('hotpants') || normalized.includes('shorts')) {
|
|
return { match: [], text: 'Hotpants', icon: HotpantsIcon }
|
|
}
|
|
|
|
if (
|
|
normalized.includes('lingerie') ||
|
|
normalized.includes('panties') ||
|
|
normalized.includes('underwear') ||
|
|
normalized.includes('briefs') ||
|
|
normalized.includes('thong')
|
|
) {
|
|
return { match: [], text: 'Unterwäsche', icon: UnderwearIcon }
|
|
}
|
|
|
|
if (normalized.includes('stocking') || normalized.includes('sock')) {
|
|
return { match: [], text: 'Stockings', icon: SockIcon }
|
|
}
|
|
|
|
if (
|
|
normalized === 'top' ||
|
|
normalized.includes('crop_top') ||
|
|
normalized.includes('crop-top') ||
|
|
normalized.includes('croptop')
|
|
) {
|
|
return { match: [], text: 'Crop Top', icon: CropTopIcon }
|
|
}
|
|
|
|
if (
|
|
normalized.includes('shirt') ||
|
|
normalized.includes('tshirt') ||
|
|
normalized.includes('t-shirt') ||
|
|
normalized.includes('blouse') ||
|
|
normalized.includes('hoodie') ||
|
|
normalized.includes('sweater') ||
|
|
normalized.includes('jacket') ||
|
|
normalized.includes('coat') ||
|
|
normalized.includes('clothing')
|
|
) {
|
|
return { match: [], text: 'Oberteil', icon: ClothingIcon }
|
|
}
|
|
|
|
if (
|
|
normalized.includes('pants') ||
|
|
normalized.includes('jeans') ||
|
|
normalized.includes('trousers') ||
|
|
normalized.includes('leggings')
|
|
) {
|
|
return { match: [], text: 'Hose', icon: PantsIcon }
|
|
}
|
|
|
|
if (
|
|
normalized.includes('shoe') ||
|
|
normalized.includes('boot') ||
|
|
normalized.includes('sneaker')
|
|
) {
|
|
return { match: [], text: 'Schuhe', icon: ShoesIcon }
|
|
}
|
|
|
|
if (
|
|
normalized === 'face' ||
|
|
normalized === 'face_female' ||
|
|
normalized === 'face_male' ||
|
|
normalized === 'female_face' ||
|
|
normalized === 'male_face' ||
|
|
normalized.includes('face_exposed') ||
|
|
normalized.includes('face_covered') ||
|
|
normalized.endsWith('_face') ||
|
|
normalized.startsWith('face_')
|
|
) {
|
|
return { match: [], text: 'Gesicht', icon: FaceIcon }
|
|
}
|
|
|
|
if (
|
|
normalized.includes('belly') ||
|
|
normalized.includes('stomach') ||
|
|
normalized.includes('abdomen') ||
|
|
normalized.includes('navel')
|
|
) {
|
|
return { match: [], text: 'Bauch', icon: BellyIcon }
|
|
}
|
|
|
|
if (normalized.includes('foot') || normalized.includes('feet')) {
|
|
return { match: [], text: 'Füße', icon: FeetIcon }
|
|
}
|
|
|
|
if (normalized.includes('male_breast')) {
|
|
return { match: [], text: 'Männliche Brust', icon: MaleBreastIcon }
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
function prettifyUnknownLabel(label?: string): string {
|
|
const normalized = normalizeSegmentLabel(label)
|
|
if (!normalized) return 'Unbekannt'
|
|
|
|
return normalized
|
|
.replaceAll('_', ' ')
|
|
.replace(/\bcrop top\b/g, 'Crop Top')
|
|
.replace(/\bcroptop\b/g, 'Crop Top')
|
|
.replace(/\bmale\b/g, 'männlich')
|
|
.replace(/\bfemale\b/g, 'weiblich')
|
|
.replace(/\bgenitalia\b/g, 'Genitalien')
|
|
.replace(/\bbreasts\b/g, 'Brüste')
|
|
.replace(/\bbreast\b/g, 'Brust')
|
|
.replace(/\bbuttocks\b/g, 'Gesäß')
|
|
.replace(/\bass\b/g, 'Hintern')
|
|
.replace(/\bback\b/g, 'Rücken')
|
|
.replace(/\banus\b/g, 'Anus')
|
|
.replace(/\bpussy\b/g, 'Vagina')
|
|
.replace(/\bpenis\b/g, 'Penis')
|
|
.replace(/\btongue\b/g, 'Zunge')
|
|
.replace(/\bbath\b/g, 'Badewanne')
|
|
.replace(/\bblindfold\b/g, 'Augenbinde')
|
|
.replace(/\bbuttplug\b/g, 'Buttplug')
|
|
.replace(/\bbutt plug\b/g, 'Buttplug')
|
|
.replace(/\bcollar\b/g, 'Halsband')
|
|
.replace(/\bdildo\b/g, 'Dildo')
|
|
.replace(/\bhandcuffs\b/g, 'Handschellen')
|
|
.replace(/\brope\b/g, 'Seil')
|
|
.replace(/\bshower\b/g, 'Dusche')
|
|
.replace(/\bstrapon\b/g, 'Strap-on')
|
|
.replace(/\bstrap on\b/g, 'Strap-on')
|
|
.replace(/\btowel\b/g, 'Handtuch')
|
|
.replace(/\bvibrator\b/g, 'Vibrator')
|
|
.replace(/\bbikini\b/g, 'Bikini')
|
|
.replace(/\bbra\b/g, 'BH')
|
|
.replace(/\bdress\b/g, 'Kleid')
|
|
.replace(/\bfishnet\b/g, 'Fishnet')
|
|
.replace(/\bheels\b/g, 'High Heels')
|
|
.replace(/\bheel\b/g, 'High Heel')
|
|
.replace(/\bhotpants\b/g, 'Hotpants')
|
|
.replace(/\blingerie\b/g, 'Lingerie')
|
|
.replace(/\bpanties\b/g, 'Panties')
|
|
.replace(/\bshirt\b/g, 'Shirt')
|
|
.replace(/\bskirt\b/g, 'Rock')
|
|
.replace(/\bstockings\b/g, 'Stockings')
|
|
.replace(/\bstocking\b/g, 'Stocking')
|
|
.replace(/\btop\b/g, 'Crop Top')
|
|
.replace(/\bbelly\b/g, 'Bauch')
|
|
.replace(/\bstomach\b/g, 'Bauch')
|
|
.replace(/\babdomen\b/g, 'Bauch')
|
|
.replace(/\bnavel\b/g, 'Bauchnabel')
|
|
.replace(/\bfeet\b/g, 'Füße')
|
|
.replace(/\bfoot\b/g, 'Fuß')
|
|
.replace(/\bface\b/g, 'Gesicht')
|
|
.replace(/\bfacesitting\b/g, 'Facesitting')
|
|
.replace(/\bface sitting\b/g, 'Facesitting')
|
|
.replace(/\bfingering\b/g, 'Fingering')
|
|
.replace(/\bfingered\b/g, 'Fingering')
|
|
.replace(/\bblowjob\b/g, 'Blowjob')
|
|
.replace(/\bfellatio\b/g, 'Blowjob')
|
|
.replace(/\bhandjob\b/g, 'Handjob')
|
|
.replace(/\bhand job\b/g, 'Handjob')
|
|
.replace(/\bcovered\b/g, 'bedeckt')
|
|
.replace(/\bexposed\b/g, 'erkannt')
|
|
.replace(/\s+/g, ' ')
|
|
.trim()
|
|
.replace(/^./, (char) => char.toUpperCase())
|
|
}
|
|
|
|
export function getSegmentIcon(label?: string): IconComponent {
|
|
return findSegmentLabelMeta(label)?.icon ?? UnknownContentIcon
|
|
}
|
|
|
|
export function getSegmentLabelText(label?: string): string {
|
|
return findSegmentLabelMeta(label)?.text ?? prettifyUnknownLabel(label)
|
|
}
|
|
|
|
export function SegmentLabelIcon({
|
|
label,
|
|
...props
|
|
}: IconProps & {
|
|
label?: string
|
|
}) {
|
|
const Icon = getSegmentIcon(label)
|
|
return <Icon {...props} />
|
|
}
|
|
|
|
export type SegmentLabelItem = {
|
|
key: string
|
|
text: string
|
|
icon: IconComponent
|
|
}
|
|
|
|
export function getSegmentLabelItem(label?: string): SegmentLabelItem {
|
|
const meta = findSegmentLabelMeta(label)
|
|
|
|
if (meta) {
|
|
return {
|
|
key: normalizeSegmentLabel(label) || meta.text,
|
|
text: meta.text,
|
|
icon: meta.icon,
|
|
}
|
|
}
|
|
|
|
return {
|
|
key: normalizeSegmentLabel(label) || 'unknown',
|
|
text: prettifyUnknownLabel(label),
|
|
icon: UnknownContentIcon,
|
|
}
|
|
}
|
|
|
|
export function getSegmentLabelItems(labels: Array<string | undefined | null>): SegmentLabelItem[] {
|
|
const out: SegmentLabelItem[] = []
|
|
const seen = new Set<string>()
|
|
|
|
for (const raw of labels) {
|
|
const item = getSegmentLabelItem(raw || undefined)
|
|
const dedupeKey = `${item.text}::${item.icon.name}`
|
|
|
|
if (seen.has(dedupeKey)) continue
|
|
seen.add(dedupeKey)
|
|
out.push(item)
|
|
}
|
|
|
|
return out
|
|
}
|
|
|
|
export function getHighestPrioritySegmentLabelItem(
|
|
labels: Array<string | undefined | null>
|
|
): SegmentLabelItem {
|
|
const items = getSegmentLabelItems(labels)
|
|
|
|
if (items.length === 0) {
|
|
return getSegmentLabelItem(undefined)
|
|
}
|
|
|
|
const priority = (item: SegmentLabelItem): number => {
|
|
switch (item.text) {
|
|
case 'Vagina':
|
|
return 0
|
|
case 'Brüste':
|
|
return 1
|
|
case 'Gesäß':
|
|
return 2
|
|
case 'Penis':
|
|
return 3
|
|
case 'Anus':
|
|
return 4
|
|
case 'Männliche Brust':
|
|
return 5
|
|
case 'Bauch':
|
|
return 6
|
|
case 'Füße':
|
|
return 7
|
|
case 'Gesicht':
|
|
return 8
|
|
default:
|
|
return 999
|
|
}
|
|
}
|
|
|
|
return [...items].sort((a, b) => {
|
|
const pa = priority(a)
|
|
const pb = priority(b)
|
|
|
|
if (pa !== pb) return pa - pb
|
|
return a.text.localeCompare(b.text, 'de')
|
|
})[0]
|
|
} |