@@ -30,6 +30,14 @@ export interface BrandingOptions {
3030 faviconUrl ?: string ;
3131}
3232
33+ export interface SocialPreviewOptions {
34+ defaultImage ?: string ;
35+ imageWidth ?: number ;
36+ imageHeight ?: number ;
37+ twitterCardType ?: "summary" | "summary_large_image" ;
38+ locale ?: string ;
39+ }
40+
3341export interface SeoOptions {
3442 aiAttribution ?: string ;
3543}
@@ -78,6 +86,7 @@ export interface CodeData {
7886 pageMetadata : Record < string , PageMetadata > ;
7987 structuredData : StructuredDataOptions ;
8088 branding : BrandingOptions ;
89+ socialPreview : SocialPreviewOptions ;
8190 seo : SeoOptions ;
8291 analytics : AnalyticsOptions ;
8392 caching : CachingOptions ;
@@ -111,6 +120,7 @@ export default function code(data: CodeData): string {
111120 pageMetadata,
112121 structuredData,
113122 branding,
123+ socialPreview,
114124 seo,
115125 analytics,
116126 caching,
@@ -170,6 +180,16 @@ ${slugs
170180 const TWITTER_HANDLE = '${ branding ?. twitterHandle || "" } ';
171181 const FAVICON_URL = '${ branding ?. faviconUrl || "" } ';
172182
183+ /*
184+ * Step 3.3.1: social preview configuration (optional)
185+ * Enhance Open Graph and Twitter Card meta tags for better link previews
186+ */
187+ const DEFAULT_OG_IMAGE = '${ socialPreview ?. defaultImage || "" } ';
188+ const OG_IMAGE_WIDTH = ${ socialPreview ?. imageWidth || 1200 } ;
189+ const OG_IMAGE_HEIGHT = ${ socialPreview ?. imageHeight || 630 } ;
190+ const TWITTER_CARD_TYPE = '${ socialPreview ?. twitterCardType || "summary_large_image" } ';
191+ const OG_LOCALE = '${ socialPreview ?. locale || "" } ';
192+
173193 /*
174194 * Step 3.4: SEO configuration (optional)
175195 * AI attribution for proper citation in AI-generated content
582602 element.setAttribute('content', pageDescription);
583603 }
584604 }
585- // Set custom OG image if specified (Issue #11)
586- if (ogImage && (element.getAttribute('property') === 'og:image'
605+ // Set custom OG image if specified, fallback to default (Issue #11, #34)
606+ const effectiveOgImage = ogImage || DEFAULT_OG_IMAGE;
607+ if (effectiveOgImage && (element.getAttribute('property') === 'og:image'
587608 || element.getAttribute('name') === 'twitter:image')) {
588- element.setAttribute('content', ogImage );
609+ element.setAttribute('content', effectiveOgImage );
589610 }
590611 // Set canonical URL for og:url and twitter:url (Issue #9)
591612 if (element.getAttribute('property') === 'og:url'
666687 element.append(\`<meta name="twitter:creator" content="\${TWITTER_HANDLE}">\`, { html: true });
667688 }
668689
690+ // Add enhanced Open Graph and Twitter Card tags (Issue #34)
691+ element.append(\`<meta property="og:type" content="website">\`, { html: true });
692+ element.append(\`<meta name="twitter:card" content="\${TWITTER_CARD_TYPE}">\`, { html: true });
693+
694+ // Add OG image dimensions if image is set
695+ const effectiveOgImage = this.metadata.ogImage || DEFAULT_OG_IMAGE;
696+ if (effectiveOgImage) {
697+ element.append(\`<meta property="og:image:width" content="\${OG_IMAGE_WIDTH}">\`, { html: true });
698+ element.append(\`<meta property="og:image:height" content="\${OG_IMAGE_HEIGHT}">\`, { html: true });
699+ }
700+
701+ // Add locale if configured
702+ if (OG_LOCALE !== '') {
703+ element.append(\`<meta property="og:locale" content="\${OG_LOCALE}">\`, { html: true });
704+ }
705+
669706 // Add AI crawler attribution meta tags (Issue #13)
670707 if (AI_ATTRIBUTION !== '') {
671708 element.append(\`<meta name="ai:source_url" content="\${canonicalUrl}">\`, { html: true });
0 commit comments