single selector + footer icons
Made-with: Cursor
This commit is contained in:
parent
a989624fe2
commit
adbf36578b
|
|
@ -122,11 +122,14 @@ export default function App() {
|
|||
</div>
|
||||
</header>
|
||||
|
||||
<div style={{ ...styles.card, padding: 12 }}>
|
||||
<TemplatePicker templates={templates} value={templateId} onChange={handleTemplateChange} />
|
||||
</div>
|
||||
|
||||
<div style={styles.grid}>
|
||||
<aside style={styles.card}>
|
||||
<div style={{ display: 'grid', gap: 14 }}>
|
||||
<BrandEditor brand={brand} onChange={setBrand} />
|
||||
<TemplatePicker templates={templates} value={templateId} onChange={handleTemplateChange} />
|
||||
{template ? <VariablesForm key={templateId} template={template} data={data} onChange={setData} /> : null}
|
||||
|
||||
<div style={{ display: 'grid', gap: 8 }}>
|
||||
|
|
|
|||
|
|
@ -14,12 +14,11 @@ export const brandDefaults: Brand = {
|
|||
email: 'reservation@shitayesuitehotel.com',
|
||||
phone1: '+251 96 688 4400',
|
||||
phone2: '+251 11 46 21000',
|
||||
social: {
|
||||
facebookUrl: '',
|
||||
instagramUrl: '',
|
||||
xUrl: '',
|
||||
youtubeUrl: '',
|
||||
linkedinUrl: '',
|
||||
},
|
||||
|
||||
// Placeholder social links (edit in the Brand editor to match your real profiles).
|
||||
socialFacebookUrl: 'https://facebook.com/yourhotel',
|
||||
socialInstagramUrl: 'https://instagram.com/yourhotel',
|
||||
socialTwitterUrl: 'https://x.com/yourhotel',
|
||||
socialLinkedInUrl: 'https://linkedin.com/company/yourhotel',
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,60 +119,50 @@ export function BrandEditor({ brand, onChange }: BrandEditorProps) {
|
|||
</label>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gap: 10, paddingTop: 4 }}>
|
||||
<div style={{ fontSize: 12, opacity: 0.8 }}>Social links</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
|
||||
<label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<span style={{ fontSize: 12, opacity: 0.8 }}>Facebook URL</span>
|
||||
<input
|
||||
value={brand.footer.social?.facebookUrl || ''}
|
||||
onChange={(e) =>
|
||||
onChange({ ...brand, footer: { ...brand.footer, social: { ...brand.footer.social, facebookUrl: e.target.value } } })
|
||||
}
|
||||
style={{ padding: '8px 10px', border: '1px solid #e5e7eb', borderRadius: 8 }}
|
||||
/>
|
||||
</label>
|
||||
<label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<span style={{ fontSize: 12, opacity: 0.8 }}>Instagram URL</span>
|
||||
<input
|
||||
value={brand.footer.social?.instagramUrl || ''}
|
||||
onChange={(e) =>
|
||||
onChange({ ...brand, footer: { ...brand.footer, social: { ...brand.footer.social, instagramUrl: e.target.value } } })
|
||||
}
|
||||
style={{ padding: '8px 10px', border: '1px solid #e5e7eb', borderRadius: 8 }}
|
||||
/>
|
||||
</label>
|
||||
<label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<span style={{ fontSize: 12, opacity: 0.8 }}>X URL</span>
|
||||
<input
|
||||
value={brand.footer.social?.xUrl || ''}
|
||||
onChange={(e) =>
|
||||
onChange({ ...brand, footer: { ...brand.footer, social: { ...brand.footer.social, xUrl: e.target.value } } })
|
||||
}
|
||||
style={{ padding: '8px 10px', border: '1px solid #e5e7eb', borderRadius: 8 }}
|
||||
/>
|
||||
</label>
|
||||
<label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<span style={{ fontSize: 12, opacity: 0.8 }}>YouTube URL</span>
|
||||
<input
|
||||
value={brand.footer.social?.youtubeUrl || ''}
|
||||
onChange={(e) =>
|
||||
onChange({ ...brand, footer: { ...brand.footer, social: { ...brand.footer.social, youtubeUrl: e.target.value } } })
|
||||
}
|
||||
style={{ padding: '8px 10px', border: '1px solid #e5e7eb', borderRadius: 8 }}
|
||||
/>
|
||||
</label>
|
||||
<label style={{ display: 'flex', flexDirection: 'column', gap: 6, gridColumn: '1 / -1' }}>
|
||||
<span style={{ fontSize: 12, opacity: 0.8 }}>LinkedIn URL</span>
|
||||
<input
|
||||
value={brand.footer.social?.linkedinUrl || ''}
|
||||
onChange={(e) =>
|
||||
onChange({ ...brand, footer: { ...brand.footer, social: { ...brand.footer.social, linkedinUrl: e.target.value } } })
|
||||
}
|
||||
style={{ padding: '8px 10px', border: '1px solid #e5e7eb', borderRadius: 8 }}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginTop: 4 }}>
|
||||
<label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<span style={{ fontSize: 12, opacity: 0.8 }}>Facebook URL</span>
|
||||
<input
|
||||
value={brand.footer.socialFacebookUrl || ''}
|
||||
onChange={(e) =>
|
||||
onChange({ ...brand, footer: { ...brand.footer, socialFacebookUrl: e.target.value } })
|
||||
}
|
||||
style={{ padding: '8px 10px', border: '1px solid #e5e7eb', borderRadius: 8 }}
|
||||
/>
|
||||
</label>
|
||||
<label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<span style={{ fontSize: 12, opacity: 0.8 }}>Instagram URL</span>
|
||||
<input
|
||||
value={brand.footer.socialInstagramUrl || ''}
|
||||
onChange={(e) =>
|
||||
onChange({ ...brand, footer: { ...brand.footer, socialInstagramUrl: e.target.value } })
|
||||
}
|
||||
style={{ padding: '8px 10px', border: '1px solid #e5e7eb', borderRadius: 8 }}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
|
||||
<label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<span style={{ fontSize: 12, opacity: 0.8 }}>Twitter / X URL</span>
|
||||
<input
|
||||
value={brand.footer.socialTwitterUrl || ''}
|
||||
onChange={(e) =>
|
||||
onChange({ ...brand, footer: { ...brand.footer, socialTwitterUrl: e.target.value } })
|
||||
}
|
||||
style={{ padding: '8px 10px', border: '1px solid #e5e7eb', borderRadius: 8 }}
|
||||
/>
|
||||
</label>
|
||||
<label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<span style={{ fontSize: 12, opacity: 0.8 }}>LinkedIn URL</span>
|
||||
<input
|
||||
value={brand.footer.socialLinkedInUrl || ''}
|
||||
onChange={(e) =>
|
||||
onChange({ ...brand, footer: { ...brand.footer, socialLinkedInUrl: e.target.value } })
|
||||
}
|
||||
style={{ padding: '8px 10px', border: '1px solid #e5e7eb', borderRadius: 8 }}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -27,71 +27,6 @@ const DEFAULT_LOGO_PLACEHOLDER =
|
|||
export function EmailShell({ brand, title, previewText, children }: EmailShellProps) {
|
||||
const logoUrl = brand.logoUrl?.trim() ? brand.logoUrl.trim() : DEFAULT_LOGO_PLACEHOLDER
|
||||
|
||||
const phoneColor = brand.textColor
|
||||
const iconColor = brand.primaryColor
|
||||
|
||||
const IconPhone = () => (
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M6.62 10.79C8.05 13.85 10.15 15.95 13.21 17.38L15.46 15.13C15.64 14.95 15.89 14.88 16.13 14.93C17.36 15.18 18.64 15.18 19.87 14.93C20.39 14.82 20.82 15.25 20.71 15.77C20.45 17 20.03 18.16 19.46 19.23C19.27 19.59 18.88 19.78 18.48 19.72C14.3 19.08 10.92 15.7 10.28 11.52C10.22 11.12 10.41 10.73 10.77 10.54C11.84 9.97 13 9.55 14.23 9.29C14.75 9.18 15.18 9.61 15.07 10.13C14.82 11.36 14.82 12.64 15.07 13.87C15.12 14.11 15.05 14.36 14.87 14.54L12.62 16.79"
|
||||
stroke={iconColor}
|
||||
strokeWidth="1.6"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
const IconSocial = ({ kind }: { kind: 'facebook' | 'instagram' | 'x' | 'youtube' | 'linkedin' }) => {
|
||||
const common = { stroke: iconColor, strokeWidth: 1.6, strokeLinecap: 'round' as const, strokeLinejoin: 'round' as const }
|
||||
if (kind === 'facebook') {
|
||||
return (
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M14 8H16V5H14C12.34 5 11 6.34 11 8V10H9V13H11V19H14V13H16L17 10H14V8C14 7.45 14.45 7 15 7H16"
|
||||
{...common}
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
if (kind === 'instagram') {
|
||||
return (
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7 2H17C19.76 2 22 4.24 22 7V17C22 19.76 19.76 22 17 22H7C4.24 22 2 19.76 2 17V7C2 4.24 4.24 2 7 2Z" {...common} />
|
||||
<path d="M17.5 6.5H17.51" {...common} />
|
||||
<path d="M12 17C14.761 17 17 14.761 17 12C17 9.239 14.761 7 12 7C9.239 7 7 9.239 7 12C7 14.761 9.239 17 12 17Z" {...common} />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
if (kind === 'x') {
|
||||
return (
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 4L20 20" {...common} />
|
||||
<path d="M20 4L4 20" {...common} />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
if (kind === 'youtube') {
|
||||
return (
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M22 12C22 12 22 17 21 18C20 19 17 19 12 19C7 19 4 19 3 18C2 17 2 12 2 12C2 12 2 7 3 6C4 5 7 5 12 5C17 5 20 5 21 6C22 7 22 12 22 12Z"
|
||||
{...common}
|
||||
/>
|
||||
<path d="M10 15L15 12L10 9V15Z" {...common} />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
// linkedin
|
||||
return (
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 9H3V21H6V9Z" {...common} />
|
||||
<path d="M4.5 3C5.33 3 6 3.67 6 4.5C6 5.33 5.33 6 4.5 6C3.67 6 3 5.33 3 4.5C3 3.67 3.67 3 4.5 3Z" {...common} />
|
||||
<path d="M21 21H18V14.5C18 13.12 17.88 11 15.5 11C13.1 11 13 13.12 13 14.5V21H10V9H13V10.5H13.04C13.49 9.71 14.49 9 16 9C19 9 21 10.87 21 14.5V21Z" {...common} />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
|
|
@ -125,59 +60,88 @@ export function EmailShell({ brand, title, previewText, children }: EmailShellPr
|
|||
<Section style={{ padding: '18px 0 28px' }}>
|
||||
<Text style={{ margin: 0, color: brand.textColor, fontSize: 12, lineHeight: '18px' }}>
|
||||
{brand.footer.address ? `${brand.footer.address} ` : ''}
|
||||
{brand.footer.email ? `Email: ${brand.footer.email}` : ''}
|
||||
{brand.footer.email ? `\u2709 ${brand.footer.email}` : ''}
|
||||
</Text>
|
||||
|
||||
{(brand.footer.phone1 || brand.footer.phone2) ? (
|
||||
<Section style={{ marginTop: 10 }}>
|
||||
<Section style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<IconPhone />
|
||||
<Text style={{ margin: 0, color: phoneColor, fontSize: 12, lineHeight: '18px' }}>
|
||||
{brand.footer.phone1 ? `Tel: ${brand.footer.phone1}` : ''}
|
||||
{brand.footer.phone1 && brand.footer.phone2 ? ' · ' : ''}
|
||||
{brand.footer.phone2 ? `${brand.footer.phone2}` : ''}
|
||||
</Text>
|
||||
</Section>
|
||||
</Section>
|
||||
) : null}
|
||||
|
||||
{/* Social icons */}
|
||||
{brand.footer.social &&
|
||||
(brand.footer.social.facebookUrl ||
|
||||
brand.footer.social.instagramUrl ||
|
||||
brand.footer.social.xUrl ||
|
||||
brand.footer.social.youtubeUrl ||
|
||||
brand.footer.social.linkedinUrl) ? (
|
||||
<Section style={{ marginTop: 12, display: 'flex', gap: 14, alignItems: 'center' }}>
|
||||
{brand.footer.social.facebookUrl ? (
|
||||
<Link href={brand.footer.social.facebookUrl} style={{ display: 'inline-block' }}>
|
||||
<IconSocial kind="facebook" />
|
||||
</Link>
|
||||
) : null}
|
||||
{brand.footer.social.instagramUrl ? (
|
||||
<Link href={brand.footer.social.instagramUrl} style={{ display: 'inline-block' }}>
|
||||
<IconSocial kind="instagram" />
|
||||
</Link>
|
||||
) : null}
|
||||
{brand.footer.social.xUrl ? (
|
||||
<Link href={brand.footer.social.xUrl} style={{ display: 'inline-block' }}>
|
||||
<IconSocial kind="x" />
|
||||
</Link>
|
||||
) : null}
|
||||
{brand.footer.social.youtubeUrl ? (
|
||||
<Link href={brand.footer.social.youtubeUrl} style={{ display: 'inline-block' }}>
|
||||
<IconSocial kind="youtube" />
|
||||
</Link>
|
||||
) : null}
|
||||
{brand.footer.social.linkedinUrl ? (
|
||||
<Link href={brand.footer.social.linkedinUrl} style={{ display: 'inline-block' }}>
|
||||
<IconSocial kind="linkedin" />
|
||||
</Link>
|
||||
) : null}
|
||||
</Section>
|
||||
) : null}
|
||||
|
||||
<Text style={{ margin: '10px 0 0', color: brand.textColor, fontSize: 12, lineHeight: '18px' }}>
|
||||
{brand.footer.phone1 ? `\u260E ${brand.footer.phone1}` : ''}
|
||||
{brand.footer.phone1 && brand.footer.phone2 ? ' · ' : ''}
|
||||
{brand.footer.phone2 ? brand.footer.phone2 : ''}
|
||||
</Text>
|
||||
|
||||
<Section style={{ margin: '14px 0 0', padding: 0 }}>
|
||||
<Text style={{ margin: '0 0 8px', color: brand.textColor, fontSize: 12, opacity: 0.85, lineHeight: '18px' }}>
|
||||
Follow us
|
||||
</Text>
|
||||
<Link
|
||||
href={brand.footer.socialFacebookUrl || '#'}
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
marginRight: 8,
|
||||
marginBottom: 8,
|
||||
padding: '8px 12px',
|
||||
borderRadius: 999,
|
||||
backgroundColor: brand.primaryColor,
|
||||
color: '#ffffff',
|
||||
textDecoration: 'none',
|
||||
fontSize: 12,
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
f
|
||||
</Link>
|
||||
<Link
|
||||
href={brand.footer.socialInstagramUrl || '#'}
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
marginRight: 8,
|
||||
marginBottom: 8,
|
||||
padding: '8px 12px',
|
||||
borderRadius: 999,
|
||||
backgroundColor: brand.primaryColor,
|
||||
color: '#ffffff',
|
||||
textDecoration: 'none',
|
||||
fontSize: 12,
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
IG
|
||||
</Link>
|
||||
<Link
|
||||
href={brand.footer.socialTwitterUrl || '#'}
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
marginRight: 8,
|
||||
marginBottom: 8,
|
||||
padding: '8px 12px',
|
||||
borderRadius: 999,
|
||||
backgroundColor: brand.primaryColor,
|
||||
color: '#ffffff',
|
||||
textDecoration: 'none',
|
||||
fontSize: 12,
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
X
|
||||
</Link>
|
||||
<Link
|
||||
href={brand.footer.socialLinkedInUrl || '#'}
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
padding: '8px 12px',
|
||||
borderRadius: 999,
|
||||
backgroundColor: brand.primaryColor,
|
||||
color: '#ffffff',
|
||||
textDecoration: 'none',
|
||||
fontSize: 12,
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
in
|
||||
</Link>
|
||||
</Section>
|
||||
|
||||
<Text style={{ margin: '14px 0 0', color: brand.textColor, fontSize: 12, lineHeight: '18px' }}>
|
||||
© {new Date().getFullYear()} {brand.hotelName}. All rights reserved.
|
||||
</Text>
|
||||
</Section>
|
||||
|
|
|
|||
|
|
@ -5,13 +5,11 @@ export type BrandFooter = {
|
|||
email?: string
|
||||
phone1?: string
|
||||
phone2?: string
|
||||
social?: {
|
||||
facebookUrl?: string
|
||||
instagramUrl?: string
|
||||
xUrl?: string
|
||||
youtubeUrl?: string
|
||||
linkedinUrl?: string
|
||||
}
|
||||
|
||||
socialFacebookUrl?: string
|
||||
socialInstagramUrl?: string
|
||||
socialTwitterUrl?: string
|
||||
socialLinkedInUrl?: string
|
||||
}
|
||||
|
||||
export type Brand = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user