Skip to content

Commit 2a57a28

Browse files
authored
Merge pull request #44 from classmethod/revert-43-revert-42-feature/og-tags
Revert "Revert "Enhance Open Graph tags for better link previews""
2 parents bd03e56 + 2ebdc6a commit 2a57a28

2 files changed

Lines changed: 153 additions & 3 deletions

File tree

src/App.tsx

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import code, {
4242
PageMetadata,
4343
StructuredDataOptions,
4444
BrandingOptions,
45+
SocialPreviewOptions,
4546
SeoOptions,
4647
AnalyticsOptions,
4748
CachingOptions,
@@ -155,6 +156,13 @@ export default function App() {
155156
twitterHandle: "",
156157
faviconUrl: "",
157158
});
159+
const [socialPreview, setSocialPreview] = useState<SocialPreviewOptions>({
160+
defaultImage: "",
161+
imageWidth: 1200,
162+
imageHeight: 630,
163+
twitterCardType: "summary_large_image",
164+
locale: "",
165+
});
158166
const [seo, setSeo] = useState<SeoOptions>({
159167
aiAttribution: "",
160168
});
@@ -279,6 +287,17 @@ export default function App() {
279287
setCopied(false);
280288
}
281289

290+
function handleSocialPreviewChange(
291+
field: keyof SocialPreviewOptions,
292+
value: string | number,
293+
): void {
294+
setSocialPreview({
295+
...socialPreview,
296+
[field]: value,
297+
});
298+
setCopied(false);
299+
}
300+
282301
function handleSeoChange(field: keyof SeoOptions, value: string): void {
283302
setSeo({
284303
...seo,
@@ -442,6 +461,7 @@ export default function App() {
442461
pageMetadata,
443462
structuredData,
444463
branding,
464+
socialPreview,
445465
seo,
446466
analytics,
447467
caching,
@@ -930,6 +950,99 @@ export default function App() {
930950
/>
931951
</Box>
932952

953+
<Box sx={{ mt: 3, pt: 2, borderTop: 1, borderColor: "grey.300" }}>
954+
<Typography
955+
variant="subtitle2"
956+
color="text.secondary"
957+
gutterBottom
958+
>
959+
Social Preview
960+
</Typography>
961+
<TextField
962+
fullWidth
963+
label="Default OG Image URL"
964+
margin="dense"
965+
placeholder="https://example.com/og-image.jpg"
966+
helperText="Fallback image for pages without a specific OG image"
967+
onChange={(e) =>
968+
handleSocialPreviewChange("defaultImage", e.target.value)
969+
}
970+
value={socialPreview.defaultImage}
971+
variant="outlined"
972+
size="small"
973+
/>
974+
<Stack direction="row" spacing={2}>
975+
<TextField
976+
type="number"
977+
label="Image Width"
978+
margin="dense"
979+
placeholder="1200"
980+
helperText="og:image:width"
981+
onChange={(e) =>
982+
handleSocialPreviewChange(
983+
"imageWidth",
984+
Number(e.target.value),
985+
)
986+
}
987+
value={socialPreview.imageWidth}
988+
variant="outlined"
989+
size="small"
990+
sx={{ flex: 1 }}
991+
/>
992+
<TextField
993+
type="number"
994+
label="Image Height"
995+
margin="dense"
996+
placeholder="630"
997+
helperText="og:image:height"
998+
onChange={(e) =>
999+
handleSocialPreviewChange(
1000+
"imageHeight",
1001+
Number(e.target.value),
1002+
)
1003+
}
1004+
value={socialPreview.imageHeight}
1005+
variant="outlined"
1006+
size="small"
1007+
sx={{ flex: 1 }}
1008+
/>
1009+
</Stack>
1010+
<FormControl fullWidth size="small" margin="dense">
1011+
<InputLabel id="twitterCardTypeLabel">
1012+
Twitter Card Type
1013+
</InputLabel>
1014+
<Select
1015+
labelId="twitterCardTypeLabel"
1016+
label="Twitter Card Type"
1017+
value={socialPreview.twitterCardType}
1018+
onChange={(e) =>
1019+
handleSocialPreviewChange(
1020+
"twitterCardType",
1021+
e.target.value,
1022+
)
1023+
}
1024+
>
1025+
<MenuItem value="summary_large_image">
1026+
summary_large_image (recommended)
1027+
</MenuItem>
1028+
<MenuItem value="summary">summary</MenuItem>
1029+
</Select>
1030+
</FormControl>
1031+
<TextField
1032+
fullWidth
1033+
label="Locale"
1034+
margin="dense"
1035+
placeholder="en_US, ja_JP, etc."
1036+
helperText="og:locale for language targeting"
1037+
onChange={(e) =>
1038+
handleSocialPreviewChange("locale", e.target.value)
1039+
}
1040+
value={socialPreview.locale}
1041+
variant="outlined"
1042+
size="small"
1043+
/>
1044+
</Box>
1045+
9331046
<Box sx={{ mt: 3, pt: 2, borderTop: 1, borderColor: "grey.300" }}>
9341047
<Typography
9351048
variant="subtitle2"

src/code.ts

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
3341
export 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
@@ -582,10 +602,11 @@ ${
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'
@@ -666,6 +687,22 @@ ${
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

Comments
 (0)