social networks

This commit is contained in:
hamid zarghami
2025-07-31 10:47:14 +03:30
parent f40a6ecee3
commit 0b79f870ee
6 changed files with 358 additions and 164 deletions
@@ -1,6 +1,7 @@
import { FC } from 'react'
import React, { FC } from 'react'
import { SocialType, SocialNetworkType, SocialIconSize, SocialIconStyle, ElementType, PersonalityDataType, HorizontalAlignment, VerticalAlignment } from '../types/Types'
import { usePersonalityStore } from '../store/Store'
import { getSocialIconPath, hasPngIcon, getSocialColor as getSocialColorFromUtils, getSocialSvgIcon } from '../utils/socialIcons'
interface SocialRendererProps {
socials: SocialType[]
@@ -26,109 +27,28 @@ const SocialRenderer: FC<SocialRendererProps> = ({ socials, itemId, sectionKey }
}
const getSocialIcon = (networkType: SocialNetworkType) => {
const getSvgIcon = (networkType: SocialNetworkType) => {
switch (networkType) {
case SocialNetworkType.FACEBOOK:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" />
</svg>
)
case SocialNetworkType.TWITTER:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z" />
</svg>
)
case SocialNetworkType.INSTAGRAM:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z" />
</svg>
)
case SocialNetworkType.LINKEDIN:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
</svg>
)
case SocialNetworkType.YOUTUBE:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" />
</svg>
)
case SocialNetworkType.TELEGRAM:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z" />
</svg>
)
case SocialNetworkType.WHATSAPP:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893A11.821 11.821 0 0020.525 3.488" />
</svg>
)
case SocialNetworkType.TIKTOK:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.15 1.07-.14 1.61.24 1.64 1.82 3.02 3.5 2.87 1.12-.01 2.19-.66 2.77-1.61.19-.33.4-.67.41-1.06.1-1.79.06-3.57.07-5.36.01-4.03-.01-8.05.02-12.07z" />
</svg>
)
case SocialNetworkType.PINTEREST:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M12.017 0C5.396 0 .029 5.367.029 11.987c0 5.079 3.158 9.417 7.618 11.174-.105-.949-.199-2.403.041-3.439.219-.937 1.406-5.957 1.406-5.957s-.359-.72-.359-1.781c0-1.663.967-2.911 2.168-2.911 1.024 0 1.518.769 1.518 1.688 0 1.029-.653 2.567-.992 3.992-.285 1.193.6 2.165 1.775 2.165 2.128 0 3.768-2.245 3.768-5.487 0-2.861-2.063-4.869-5.008-4.869-3.41 0-5.409 2.562-5.409 5.199 0 1.033.394 2.143.889 2.741.097.118.112.222.085.345-.09.375-.293 1.199-.334 1.363-.053.225-.172.271-.402.165-1.495-.69-2.433-2.878-2.433-4.646 0-3.776 2.748-7.252 7.92-7.252 4.158 0 7.392 2.967 7.392 6.923 0 4.135-2.607 7.462-6.233 7.462-1.214 0-2.357-.629-2.746-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24.009 12.017 24c6.624 0 11.99-5.367 11.99-12C24.007 5.367 18.641.001.017 0z" />
</svg>
)
case SocialNetworkType.SNAPCHAT:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M12.017 0C5.396 0 .029 5.367.029 11.987c0 5.079 3.158 9.417 7.618 11.174-.105-.949-.199-2.403.041-3.439.219-.937 1.406-5.957 1.406-5.957s-.359-.72-.359-1.781c0-1.663.967-2.911 2.168-2.911 1.024 0 1.518.769 1.518 1.688 0 1.029-.653 2.567-.992 3.992-.285 1.193.6 2.165 1.775 2.165 2.128 0 3.768-2.245 3.768-5.487 0-2.861-2.063-4.869-5.008-4.869-3.41 0-5.409 2.562-5.409 5.199 0 1.033.394 2.143.889 2.741.097.118.112.222.085.345-.09.375-.293 1.199-.334 1.363-.053.225-.172.271-.402.165-1.495-.69-2.433-2.878-2.433-4.646 0-3.776 2.748-7.252 7.92-7.252 4.158 0 7.392 2.967 7.392 6.923 0 4.135-2.607 7.462-6.233 7.462-1.214 0-2.357-.629-2.746-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24.009 12.017 24c6.624 0 11.99-5.367 11.99-12C24.007 5.367 18.641.001.017 0z" />
</svg>
)
case SocialNetworkType.GITHUB:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</svg>
)
case SocialNetworkType.DISCORD:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419-.0002 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1568 2.4189Z" />
</svg>
)
default:
return (
<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z" />
</svg>
)
}
// Check if PNG icon is available, if so use it
if (hasPngIcon(networkType)) {
const iconPath = getSocialIconPath(networkType)
return (
<img
src={iconPath}
alt={`${networkType} icon`}
style={{
width: '100%',
height: '100%',
objectFit: 'contain',
display: 'block'
}}
/>
)
}
return getSvgIcon(networkType)
// Use shared SVG function
return getSocialSvgIcon(networkType, true) as React.ReactElement
}
const getSocialColor = (networkType: SocialNetworkType) => {
const colors = {
[SocialNetworkType.FACEBOOK]: '#1877F2',
[SocialNetworkType.TWITTER]: '#1DA1F2',
[SocialNetworkType.INSTAGRAM]: '#E4405F',
[SocialNetworkType.LINKEDIN]: '#0A66C2',
[SocialNetworkType.YOUTUBE]: '#FF0000',
[SocialNetworkType.TELEGRAM]: '#0088CC',
[SocialNetworkType.WHATSAPP]: '#25D366',
[SocialNetworkType.TIKTOK]: '#000000',
[SocialNetworkType.PINTEREST]: '#BD081C',
[SocialNetworkType.SNAPCHAT]: '#FFFC00',
[SocialNetworkType.GITHUB]: '#333333',
[SocialNetworkType.DISCORD]: '#5865F2',
}
return colors[networkType] || '#000000'
}
const getSocialColor = getSocialColorFromUtils
const getIconSize = (size: SocialIconSize) => {
switch (size) {
@@ -152,7 +72,6 @@ const SocialRenderer: FC<SocialRendererProps> = ({ socials, itemId, sectionKey }
justifyContent: 'center',
textDecoration: 'none',
color: social.color || getSocialColor(social.networkType),
backgroundColor: social.backgroundColor || 'transparent',
transition: 'all 0.2s ease',
margin: '2px',
cursor: 'pointer',
@@ -164,19 +83,16 @@ const SocialRenderer: FC<SocialRendererProps> = ({ socials, itemId, sectionKey }
return {
...baseStyle,
borderRadius: '50%',
border: `1px solid ${social.color || getSocialColor(social.networkType)}`,
}
case SocialIconStyle.SQUARE:
return {
...baseStyle,
borderRadius: '0',
border: `1px solid ${social.color || getSocialColor(social.networkType)}`,
}
case SocialIconStyle.ROUNDED:
return {
...baseStyle,
borderRadius: '8px',
border: `1px solid ${social.color || getSocialColor(social.networkType)}`,
}
default:
return baseStyle
@@ -3,10 +3,11 @@ import ColorPicker from '@/components/ColorPicker'
import Input from '@/components/Input'
import Select from '@/components/Select'
import { AlignRight, AlignBottom, AlignHorizontally, AlignLeft, AlignTop, AlignVertically, Add, Edit, Trash, Link2 } from 'iconsax-react'
import { FC, useState, useEffect } from 'react'
import React, { FC, useState, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { usePersonalityStore } from '../store/Store'
import { SocialNetworkType, SocialIconSize, SocialIconStyle, HorizontalAlignment, VerticalAlignment, ElementType } from '../types/Types'
import { getSocialIconPath, hasPngIcon, getSocialSvgIcon } from '../utils/socialIcons'
const SocialSidebar: FC = () => {
@@ -25,7 +26,6 @@ const SocialSidebar: FC = () => {
const [size, setSize] = useState<SocialIconSize>(SocialIconSize.MEDIUM)
const [style, setStyle] = useState<SocialIconStyle>(SocialIconStyle.CIRCLE)
const [color, setColor] = useState<string>('#000000')
const [backgroundColor, setBackgroundColor] = useState<string>('#ffffff')
const [horizontalAlignment, setHorizontalAlignment] = useState<HorizontalAlignment>(HorizontalAlignment.CENTER)
const [verticalAlignment, setVerticalAlignment] = useState<VerticalAlignment>(VerticalAlignment.MIDDLE)
@@ -57,7 +57,6 @@ const SocialSidebar: FC = () => {
setSize(social.size);
setStyle(social.style);
setColor(social.color || '#000000');
setBackgroundColor(social.backgroundColor || '#ffffff');
setHorizontalAlignment(social.alignment || HorizontalAlignment.CENTER);
setVerticalAlignment(social.verticalAlignment || VerticalAlignment.MIDDLE);
} else {
@@ -73,7 +72,6 @@ const SocialSidebar: FC = () => {
setSize(SocialIconSize.MEDIUM)
setStyle(SocialIconStyle.CIRCLE)
setColor('#000000')
setBackgroundColor('#ffffff')
setHorizontalAlignment(HorizontalAlignment.CENTER)
setVerticalAlignment(VerticalAlignment.MIDDLE)
}
@@ -114,7 +112,6 @@ const SocialSidebar: FC = () => {
size,
style,
color,
backgroundColor,
alignment: horizontalAlignment,
verticalAlignment,
})
@@ -125,7 +122,6 @@ const SocialSidebar: FC = () => {
setSize(SocialIconSize.MEDIUM)
setStyle(SocialIconStyle.CIRCLE)
setColor('#000000')
setBackgroundColor('#ffffff')
setHorizontalAlignment(HorizontalAlignment.CENTER)
setVerticalAlignment(VerticalAlignment.MIDDLE)
}
@@ -143,7 +139,6 @@ const SocialSidebar: FC = () => {
size,
style,
color,
backgroundColor,
alignment: horizontalAlignment,
verticalAlignment,
}
@@ -171,6 +166,86 @@ const SocialSidebar: FC = () => {
setSelectedElement(null);
}
// Preview component for selected social network
const renderPreview = () => {
const getIconSize = () => {
switch (size) {
case SocialIconSize.SMALL:
return { width: '24px', height: '24px' }
case SocialIconSize.MEDIUM:
return { width: '32px', height: '32px' }
case SocialIconSize.LARGE:
return { width: '40px', height: '40px' }
default:
return { width: '32px', height: '32px' }
}
}
const getIconStyle = () => {
const iconSize = getIconSize()
const baseStyle = {
...iconSize,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
color: color,
transition: 'all 0.2s ease',
}
switch (style) {
case SocialIconStyle.CIRCLE:
return {
...baseStyle,
borderRadius: '50%',
}
case SocialIconStyle.SQUARE:
return {
...baseStyle,
borderRadius: '0',
}
case SocialIconStyle.ROUNDED:
return {
...baseStyle,
borderRadius: '8px',
}
default:
return baseStyle
}
}
const renderIcon = () => {
if (hasPngIcon(networkType)) {
const iconPath = getSocialIconPath(networkType)
return (
<img
src={iconPath}
alt={`${networkType} icon`}
style={{
width: '100%',
height: '100%',
objectFit: 'contain',
display: 'block'
}}
/>
)
}
// Use shared SVG function for fallback
return getSocialSvgIcon(networkType, true) as React.ReactElement
}
return (
<div className='mt-4 p-4 bg-gray-50 rounded-lg'>
<div className='text-sm text-gray-600 mb-2'>{t('setting.preview')}</div>
<div className='flex justify-center'>
<div style={getIconStyle()}>
{renderIcon()}
</div>
</div>
</div>
)
}
return (
<div>
<div className='text-lg flex items-center justify-between'>
@@ -193,6 +268,9 @@ const SocialSidebar: FC = () => {
/>
</div>
{/* Preview of selected social network */}
{renderPreview()}
<div className='mt-5'>
<Input
label={t('setting.social_link')}
@@ -231,13 +309,7 @@ const SocialSidebar: FC = () => {
/>
</div>
<div className='mt-5'>
<ColorPicker
label={t('setting.background_color')}
defaultColor={backgroundColor}
changeColor={setBackgroundColor}
/>
</div>
<div className='mt-5 flex justify-between'>
<div>
+26 -16
View File
@@ -250,7 +250,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
item.id === itemId
? {
...item,
texts: [...item.texts, { ...text, id: uuidv4() }],
texts: [...(item.texts || []), { ...text, id: uuidv4() }],
}
: item
),
@@ -272,7 +272,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
index === activeIndex
? {
...item,
texts: [...item.texts, { ...text, id: uuidv4() }],
texts: [...(item.texts || []), { ...text, id: uuidv4() }],
}
: item
);
@@ -302,7 +302,10 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
item.id === itemId
? {
...item,
buttons: [...item.buttons, { ...button, id: uuidv4() }],
buttons: [
...(item.buttons || []),
{ ...button, id: uuidv4() },
],
}
: item
),
@@ -324,7 +327,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
index === activeIndex
? {
...item,
buttons: [...item.buttons, { ...button, id: uuidv4() }],
buttons: [...(item.buttons || []), { ...button, id: uuidv4() }],
}
: item
);
@@ -355,7 +358,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
item.id === itemId
? {
...item,
texts: item.texts.map((text) =>
texts: (item.texts || []).map((text) =>
text.id === textId ? { ...text, ...updates } : text
),
}
@@ -380,7 +383,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
item.id === itemId
? {
...item,
buttons: item.buttons.map((button) =>
buttons: (item.buttons || []).map((button) =>
button.id === buttonId ? { ...button, ...updates } : button
),
}
@@ -404,7 +407,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
item.id === itemId
? {
...item,
images: [...item.images, { ...image, id: uuidv4() }],
images: [...(item.images || []), { ...image, id: uuidv4() }],
}
: item
),
@@ -426,7 +429,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
index === activeIndex
? {
...item,
images: [...item.images, { ...image, id: uuidv4() }],
images: [...(item.images || []), { ...image, id: uuidv4() }],
}
: item
);
@@ -457,7 +460,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
item.id === itemId
? {
...item,
images: item.images.map((image) =>
images: (item.images || []).map((image) =>
image.id === imageId ? { ...image, ...updates } : image
),
}
@@ -481,7 +484,9 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
item.id === itemId
? {
...item,
texts: item.texts.filter((text) => text.id !== textId),
texts: (item.texts || []).filter(
(text) => text.id !== textId
),
}
: item
),
@@ -505,7 +510,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
item.id === itemId
? {
...item,
buttons: item.buttons.filter(
buttons: (item.buttons || []).filter(
(button) => button.id !== buttonId
),
}
@@ -531,7 +536,9 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
item.id === itemId
? {
...item,
images: item.images.filter((image) => image.id !== imageId),
images: (item.images || []).filter(
(image) => image.id !== imageId
),
}
: item
),
@@ -555,7 +562,10 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
item.id === itemId
? {
...item,
socials: [...item.socials, { ...social, id: uuidv4() }],
socials: [
...(item.socials || []),
{ ...social, id: uuidv4() },
],
}
: item
),
@@ -577,7 +587,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
index === activeIndex
? {
...item,
socials: [...item.socials, { ...social, id: uuidv4() }],
socials: [...(item.socials || []), { ...social, id: uuidv4() }],
}
: item
);
@@ -608,7 +618,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
item.id === itemId
? {
...item,
socials: item.socials.map((social) =>
socials: (item.socials || []).map((social) =>
social.id === socialId ? { ...social, ...updates } : social
),
}
@@ -632,7 +642,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
item.id === itemId
? {
...item,
socials: item.socials.filter(
socials: (item.socials || []).filter(
(social) => social.id !== socialId
),
}
@@ -168,7 +168,6 @@ export type SocialType = {
size: SocialIconSize;
style: SocialIconStyle;
color?: string;
backgroundColor?: string;
alignment?: HorizontalAlignment;
verticalAlignment?: VerticalAlignment;
};
+128 -29
View File
@@ -8,7 +8,17 @@ import {
ButtonType,
ImageType,
SectionType,
SocialType,
SocialNetworkType,
SocialIconSize,
SocialIconStyle,
} from "../types/Types";
import {
getSocialIconPath,
hasPngIcon,
getSocialColor,
getSocialSvgIcon,
} from "./socialIcons";
export const exportPersonalityToHTML = async (
data: PersonalityDataType
@@ -233,6 +243,80 @@ export const exportPersonalityToHTML = async (
.join("");
};
// Render SocialRenderer equivalent
const renderSocials = (socials: SocialType[]) => {
if (!socials || socials.length === 0) return "";
const getIconSize = (size: SocialIconSize) => {
switch (size) {
case SocialIconSize.SMALL:
return "24px";
case SocialIconSize.MEDIUM:
return "32px";
case SocialIconSize.LARGE:
return "40px";
default:
return "32px";
}
};
const getIconStyle = (social: SocialType) => {
const size = getIconSize(social.size);
const baseStyle = `width: ${size}; height: ${size}; display: inline-flex; align-items: center; justify-content: center; text-decoration: none; color: ${
social.color || getSocialColor(social.networkType)
}; margin: 2px;`;
switch (social.style) {
case SocialIconStyle.CIRCLE:
return `${baseStyle} border-radius: 50%;`;
case SocialIconStyle.SQUARE:
return `${baseStyle} border-radius: 0;`;
case SocialIconStyle.ROUNDED:
return `${baseStyle} border-radius: 8px;`;
default:
return baseStyle;
}
};
const getSocialIcon = (networkType: SocialNetworkType) => {
// Check if PNG icon is available, if so use it
if (hasPngIcon(networkType)) {
const iconPath = getSocialIconPath(networkType);
return `<img src="${iconPath}" alt="${networkType} icon" style="width: 100%; height: 100%; object-fit: contain; display: block;" />`;
}
// Use shared SVG function
return getSocialSvgIcon(networkType, false) as string;
};
return `<table width="100%" cellpadding="0" cellspacing="0" border="0" style="border-collapse: collapse;">
<tbody>
<tr>
<td align="${getHorizontalAlign(
socials[0]?.alignment
)}" valign="${getVerticalAlign(
socials[0]?.verticalAlignment
)}" style="padding: 4px 0;">
<div style="display: flex; justify-content: ${getHorizontalAlign(
socials[0]?.alignment
)}; gap: 4px; flex-wrap: wrap;">
${socials
.map(
(social) =>
`<a href="${social.link || "#"}" style="${getIconStyle(
social
)} text-decoration: none;">
${getSocialIcon(social.networkType)}
</a>`
)
.join("")}
</div>
</td>
</tr>
</tbody>
</table>`;
};
// Helper functions for button alignment (same as in React components)
const getButtonHorizontalAlign = (button?: {
alignment?: HorizontalAlignment;
@@ -289,6 +373,10 @@ export const exportPersonalityToHTML = async (
item?.buttons && item.buttons.length > 0;
const hasTexts =
item?.texts && item.texts.length > 0;
const hasImages =
item?.images && item.images.length > 0;
const hasSocials =
item?.socials && item.socials.length > 0;
let result = `<td style="width: ${
100 / section.columnsCount
@@ -310,35 +398,45 @@ export const exportPersonalityToHTML = async (
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="border-collapse: collapse; height: ${sectionHeight};">
<tbody>`;
// اگر فقط دکمه داریم و متن نداریم
if (!hasTexts && hasButtons) {
result += `<tr>
<td width="100%" height="${sectionHeight}" align="${getButtonHorizontalAlign(
item.buttons[0]
)}" valign="${getButtonVerticalAlign(
item.buttons[0]
)}" style="padding: 8px;">
${renderButtons(item.buttons)}
</td>
</tr>`;
} else {
// ردیف اصلی برای متن و تصاویر
const mainHeight = hasButtons
? sectionHeight === "123px"
? "60"
// اگر محتوایی وجود دارد (متن، دکمه، تصویر، یا شبکه اجتماعی)
if (
hasTexts ||
hasButtons ||
hasImages ||
hasSocials
) {
// اگر فقط دکمه داریم و متن نداریم
if (!hasTexts && hasButtons) {
result += `<tr>
<td width="100%" height="${sectionHeight}" align="${getButtonHorizontalAlign(
item.buttons[0]
)}" valign="${getButtonVerticalAlign(
item.buttons[0]
)}" style="padding: 8px;">
${renderImages(item?.images || [])}
${renderSocials(item?.socials || [])}
${renderButtons(item.buttons)}
</td>
</tr>`;
} else {
// ردیف اصلی برای متن و تصاویر
const mainHeight = hasButtons
? sectionHeight === "123px"
? "60"
: sectionHeight === "246px"
? "203"
: "40"
: sectionHeight === "123px"
? "87"
: sectionHeight === "246px"
? "203"
: "40"
: sectionHeight === "123px"
? "87"
: sectionHeight === "246px"
? "230"
: "67";
? "230"
: "67";
result += `<tr>
result += `<tr>
<td width="100%" height="${mainHeight}" style="padding: 20px; vertical-align: top; font-size: 15px; line-height: 1.8;">
${renderTexts(item?.texts || [])}
${renderImages(item?.images || [])}
${renderSocials(item?.socials || [])}
${
isContentSection
? '<div style="margin: 0; text-align: right;">{{content}}</div>'
@@ -347,17 +445,18 @@ export const exportPersonalityToHTML = async (
</td>
</tr>`;
// ردیف دکمه‌ها
if (hasButtons) {
result += `<tr>
// ردیف دکمه‌ها
if (hasButtons) {
result += `<tr>
<td width="100%" height="27" align="${getButtonHorizontalAlign(
item.buttons[0]
)}" valign="${getButtonVerticalAlign(
item.buttons[0]
)}" style="padding: 0 8px 8px 8px;">
item.buttons[0]
)}" style="padding: 0 8px 8px 8px;">
${renderButtons(item.buttons)}
</td>
</tr>`;
}
}
}
@@ -0,0 +1,98 @@
import React from "react";
import { SocialNetworkType } from "../types/Types";
// Map social network types to their corresponding icon file names
export const getSocialIconPath = (networkType: SocialNetworkType): string => {
const iconMap: Record<SocialNetworkType, string> = {
[SocialNetworkType.FACEBOOK]:
"https://dmail-admin.danakcorp.com/facebook.png",
[SocialNetworkType.TWITTER]:
"https://dmail-admin.danakcorp.com/twitter.png",
[SocialNetworkType.INSTAGRAM]:
"https://dmail-admin.danakcorp.com/instagram.png",
[SocialNetworkType.LINKEDIN]:
"https://dmail-admin.danakcorp.com/linkedin.png",
[SocialNetworkType.TELEGRAM]:
"https://dmail-admin.danakcorp.com/telegram.png",
[SocialNetworkType.WHATSAPP]:
"https://dmail-admin.danakcorp.com/whatsapp.png",
// For social networks without PNG icons, we'll use a default or keep SVG
[SocialNetworkType.YOUTUBE]: "", // Will fallback to SVG
[SocialNetworkType.TIKTOK]: "", // Will fallback to SVG
[SocialNetworkType.PINTEREST]: "", // Will fallback to SVG
[SocialNetworkType.SNAPCHAT]: "", // Will fallback to SVG
[SocialNetworkType.GITHUB]: "", // Will fallback to SVG
[SocialNetworkType.DISCORD]: "", // Will fallback to SVG
};
return iconMap[networkType] || "";
};
// Check if a PNG icon is available for the social network
export const hasPngIcon = (networkType: SocialNetworkType): boolean => {
const iconPath = getSocialIconPath(networkType);
return iconPath !== "";
};
// Get social network colors (keeping the existing colors)
export const getSocialColor = (networkType: SocialNetworkType): string => {
const colors = {
[SocialNetworkType.FACEBOOK]: "#1877F2",
[SocialNetworkType.TWITTER]: "#1DA1F2",
[SocialNetworkType.INSTAGRAM]: "#E4405F",
[SocialNetworkType.LINKEDIN]: "#0A66C2",
[SocialNetworkType.YOUTUBE]: "#FF0000",
[SocialNetworkType.TELEGRAM]: "#0088CC",
[SocialNetworkType.WHATSAPP]: "#25D366",
[SocialNetworkType.TIKTOK]: "#000000",
[SocialNetworkType.PINTEREST]: "#BD081C",
[SocialNetworkType.SNAPCHAT]: "#FFFC00",
[SocialNetworkType.GITHUB]: "#333333",
[SocialNetworkType.DISCORD]: "#5865F2",
};
return colors[networkType] || "#000000";
};
// Get SVG icons for social networks that don't have PNG icons
export const getSocialSvgIcon = (
networkType: SocialNetworkType,
isReactElement = true
): string | React.ReactElement => {
const svgContent: Record<string, string> = {
[SocialNetworkType.YOUTUBE]:
"M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z",
[SocialNetworkType.TIKTOK]:
"M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.15 1.07-.14 1.61.24 1.64 1.82 3.02 3.5 2.87 1.12-.01 2.19-.66 2.77-1.61.19-.33.4-.67.41-1.06.1-1.79.06-3.57.07-5.36.01-4.03-.01-8.05.02-12.07z",
[SocialNetworkType.PINTEREST]:
"M12.017 0C5.396 0 .029 5.367.029 11.987c0 5.079 3.158 9.417 7.618 11.174-.105-.949-.199-2.403.041-3.439.219-.937 1.406-5.957 1.406-5.957s-.359-.72-.359-1.781c0-1.663.967-2.911 2.168-2.911 1.024 0 1.518.769 1.518 1.688 0 1.029-.653 2.567-.992 3.992-.285 1.193.6 2.165 1.775 2.165 2.128 0 3.768-2.245 3.768-5.487 0-2.861-2.063-4.869-5.008-4.869-3.41 0-5.409 2.562-5.409 5.199 0 1.033.394 2.143.889 2.741.097.118.112.222.085.345-.09.375-.293 1.199-.334 1.363-.053.225-.172.271-.402.165-1.495-.69-2.433-2.878-2.433-4.646 0-3.776 2.748-7.252 7.92-7.252 4.158 0 7.392 2.967 7.392 6.923 0 4.135-2.607 7.462-6.233 7.462-1.214 0-2.357-.629-2.746-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24.009 12.017 24c6.624 0 11.99-5.367 11.99-12C24.007 5.367 18.641.001.017 0z",
[SocialNetworkType.SNAPCHAT]:
"M12.017 0C5.396 0 .029 5.367.029 11.987c0 5.079 3.158 9.417 7.618 11.174-.105-.949-.199-2.403.041-3.439.219-.937 1.406-5.957 1.406-5.957s-.359-.72-.359-1.781c0-1.663.967-2.911 2.168-2.911 1.024 0 1.518.769 1.518 1.688 0 1.029-.653 2.567-.992 3.992-.285 1.193.6 2.165 1.775 2.165 2.128 0 3.768-2.245 3.768-5.487 0-2.861-2.063-4.869-5.008-4.869-3.41 0-5.409 2.562-5.409 5.199 0 1.033.394 2.143.889 2.741.097.118.112.222.085.345-.09.375-.293 1.199-.334 1.363-.053.225-.172.271-.402.165-1.495-.69-2.433-2.878-2.433-4.646 0-3.776 2.748-7.252 7.92-7.252 4.158 0 7.392 2.967 7.392 6.923 0 4.135-2.607 7.462-6.233 7.462-1.214 0-2.357-.629-2.746-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24.009 12.017 24c6.624 0 11.99-5.367 11.99-12C24.007 5.367 18.641.001.017 0z",
[SocialNetworkType.GITHUB]:
"M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12",
[SocialNetworkType.DISCORD]:
"M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419-.0002 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1568 2.4189Z",
default:
"M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z",
};
const pathData = svgContent[networkType] || svgContent.default;
if (isReactElement) {
// برای استفاده در React components
return React.createElement(
"svg",
{
viewBox: "0 0 24 24",
width: "100%",
height: "100%",
fill: "currentColor",
},
React.createElement("path", { d: pathData })
) as React.ReactElement;
} else {
// برای استفاده در HTML strings
return `<svg viewBox="0 0 24 24" width="100%" height="100%" fill="currentColor">
<path d="${pathData}" />
</svg>`;
}
};