2026-07-12 13:16:53 -07:00
|
|
|
import React, { CSSProperties } from 'react';
|
2026-04-05 18:31:16 -07:00
|
|
|
import { useNode, UserComponent } from '@craftjs/core';
|
|
|
|
|
import { cssPropsToString } from '../../utils/style-helpers';
|
|
|
|
|
import { useSiteDesign } from '../../state/SiteDesignContext';
|
2026-07-12 19:45:58 -07:00
|
|
|
import { escapeHtml, escapeAttr, safeUrl, safeImageUrl } from '../../utils/escape';
|
2026-04-05 18:31:16 -07:00
|
|
|
|
|
|
|
|
/* ---------- Types ---------- */
|
|
|
|
|
|
|
|
|
|
interface LogoProps {
|
|
|
|
|
type?: 'text' | 'image';
|
|
|
|
|
text?: string;
|
|
|
|
|
imageSrc?: string;
|
|
|
|
|
imageWidth?: string;
|
|
|
|
|
href?: string;
|
|
|
|
|
fontFamily?: string;
|
|
|
|
|
fontSize?: string;
|
|
|
|
|
fontWeight?: string;
|
|
|
|
|
color?: string;
|
|
|
|
|
style?: CSSProperties;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ---------- Component ---------- */
|
|
|
|
|
|
|
|
|
|
export const Logo: UserComponent<LogoProps> = ({
|
|
|
|
|
type = 'text',
|
|
|
|
|
text = 'MySite',
|
|
|
|
|
imageSrc = '',
|
|
|
|
|
imageWidth = '120px',
|
|
|
|
|
href = '/',
|
|
|
|
|
fontFamily = 'Inter, sans-serif',
|
|
|
|
|
fontSize = '20px',
|
|
|
|
|
fontWeight = '700',
|
|
|
|
|
color,
|
|
|
|
|
style = {},
|
|
|
|
|
}) => {
|
|
|
|
|
const {
|
|
|
|
|
connectors: { connect, drag },
|
|
|
|
|
} = useNode();
|
|
|
|
|
|
|
|
|
|
const { design } = useSiteDesign();
|
|
|
|
|
const resolvedColor = color || design.textColor;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<a
|
|
|
|
|
ref={(ref: HTMLElement | null): void => { if (ref) connect(drag(ref)); }}
|
|
|
|
|
href={href}
|
|
|
|
|
onClick={(e) => e.preventDefault()}
|
|
|
|
|
style={{
|
|
|
|
|
textDecoration: 'none',
|
|
|
|
|
display: 'inline-flex',
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
flexShrink: 0,
|
|
|
|
|
...style,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{type === 'image' && imageSrc ? (
|
|
|
|
|
<img
|
|
|
|
|
src={imageSrc}
|
|
|
|
|
alt={text || 'Logo'}
|
|
|
|
|
style={{ width: imageWidth, height: 'auto', display: 'block' }}
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<span style={{
|
|
|
|
|
fontWeight,
|
|
|
|
|
fontSize,
|
|
|
|
|
fontFamily,
|
|
|
|
|
color: resolvedColor,
|
|
|
|
|
}}>
|
|
|
|
|
{text}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</a>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* ---------- Craft config ---------- */
|
|
|
|
|
|
|
|
|
|
Logo.craft = {
|
|
|
|
|
displayName: 'Logo',
|
|
|
|
|
props: {
|
|
|
|
|
type: 'text',
|
|
|
|
|
text: 'MySite',
|
|
|
|
|
imageSrc: '',
|
|
|
|
|
imageWidth: '120px',
|
|
|
|
|
href: '/',
|
|
|
|
|
fontFamily: 'Inter, sans-serif',
|
|
|
|
|
fontSize: '20px',
|
|
|
|
|
fontWeight: '700',
|
|
|
|
|
color: undefined,
|
|
|
|
|
style: {},
|
|
|
|
|
} as LogoProps,
|
|
|
|
|
rules: {
|
|
|
|
|
canDrag: () => true,
|
|
|
|
|
canMoveIn: () => false,
|
|
|
|
|
canMoveOut: () => true,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* ---------- HTML export ---------- */
|
|
|
|
|
|
|
|
|
|
(Logo as any).toHtml = (props: LogoProps, _childrenHtml: string) => {
|
|
|
|
|
const href = props.href || '/';
|
|
|
|
|
|
|
|
|
|
let innerHtml: string;
|
|
|
|
|
if (props.type === 'image' && props.imageSrc) {
|
|
|
|
|
const imgStyle = cssPropsToString({ width: props.imageWidth || '120px', height: 'auto', display: 'block' });
|
2026-07-12 19:45:58 -07:00
|
|
|
innerHtml = `<img src="${escapeAttr(safeImageUrl(props.imageSrc))}" alt="${escapeAttr(props.text || 'Logo')}"${imgStyle ? ` style="${imgStyle}"` : ''} />`;
|
2026-04-05 18:31:16 -07:00
|
|
|
} else {
|
|
|
|
|
const spanStyle = cssPropsToString({
|
|
|
|
|
fontWeight: props.fontWeight || '700',
|
|
|
|
|
fontSize: props.fontSize || '20px',
|
|
|
|
|
fontFamily: props.fontFamily || 'Inter, sans-serif',
|
|
|
|
|
color: props.color || '#1f2937',
|
|
|
|
|
});
|
2026-07-12 11:49:10 -07:00
|
|
|
innerHtml = `<span${spanStyle ? ` style="${spanStyle}"` : ''}>${escapeHtml(props.text || 'MySite')}</span>`;
|
2026-04-05 18:31:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const aStyle = cssPropsToString({
|
|
|
|
|
textDecoration: 'none',
|
|
|
|
|
display: 'inline-flex',
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
flexShrink: '0',
|
|
|
|
|
...props.style,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
2026-07-12 12:05:57 -07:00
|
|
|
html: `<a href="${escapeAttr(safeUrl(href))}"${aStyle ? ` style="${aStyle}"` : ''}>${innerHtml}</a>`,
|
2026-04-05 18:31:16 -07:00
|
|
|
};
|
|
|
|
|
};
|