diff --git a/client/public/images/horoskop-og.jpg b/client/public/images/horoskop-og.jpg new file mode 100644 index 0000000..c425fc5 Binary files /dev/null and b/client/public/images/horoskop-og.jpg differ diff --git a/client/src/pages/horoscope.tsx b/client/src/pages/horoscope.tsx index fd7bd25..086c403 100644 --- a/client/src/pages/horoscope.tsx +++ b/client/src/pages/horoscope.tsx @@ -370,7 +370,6 @@ function SignDetail({ signIndex, onNavigate, aiHoroscopes }: { signIndex: number } export default function HoroscopePage() { - usePageMeta("Horoskop - Volksmusik & Schlager", "Tägliches Horoskop für alle Sternzeichen. Ihr persönliches Tageshoroskop bei FOLX TV – dem Volksmusik & Schlager Sender."); const params = useParams<{ sign?: string }>(); const [selected, setSelected] = useState(null); const detailRef = useRef(null); @@ -386,6 +385,27 @@ export default function HoroscopePage() { } }, [params.sign]); + const selectedSign = selected !== null ? SIGNS[selected] : null; + const selectedAi = selected !== null ? aiHoroscopes.find(h => h.signIndex === selected) : null; + const today = new Date().toLocaleDateString("de-AT", { day: "numeric", month: "long", year: "numeric" }); + + const metaTitle = selectedSign + ? `${selectedSign.symbol} ${selectedSign.name} Horoskop – Tages-, Wochen- & Monatshoroskop` + : "Horoskop – Tages-, Wochen- & Monatshoroskop für alle Sternzeichen"; + + const metaDesc = selectedSign + ? `${selectedSign.name} Horoskop für heute, ${today}. Tägliches, wöchentliches und monatliches Horoskop für ${selectedSign.name} (${selectedSign.date}). Liebe, Beruf & Gesundheit bei FOLX TV.` + : `Kostenloses Tageshoroskop, Wochenhoroskop & Monatshoroskop für alle 12 Sternzeichen. Liebe, Beruf, Gesundheit – Ihr persönliches Horoskop bei FOLX TV, ${today}.`; + + const ogImage = "https://folx.tv/images/horoskop-og.jpg"; + + usePageMeta(metaTitle, metaDesc, { + ogTitle: metaTitle, + ogDescription: metaDesc, + ogImage, + ogType: "website", + }); + const handleSelect = (i: number) => { setSelected(i); setTimeout(() => { diff --git a/server/static.ts b/server/static.ts index e604337..d812718 100644 --- a/server/static.ts +++ b/server/static.ts @@ -95,6 +95,49 @@ export function serveStatic(app: Express) { } } + if (url.match(/^\/horoskop(\/|$|\?)/)) { + let template = await fs.promises.readFile(indexPath, "utf-8"); + template = stripExistingMeta(template); + const signMatch = url.match(/^\/horoskop\/([^?#]+)/); + const signName = signMatch ? decodeURIComponent(signMatch[1]) : null; + const capitalSign = signName ? signName.charAt(0).toUpperCase() + signName.slice(1) : null; + + const title = capitalSign + ? `${capitalSign} Horoskop – Tages-, Wochen- & Monatshoroskop | Folx Music Television` + : "Horoskop – Tages-, Wochen- & Monatshoroskop für alle Sternzeichen | Folx Music Television"; + const desc = capitalSign + ? `${capitalSign} Horoskop: Tägliches, wöchentliches und monatliches Horoskop. Liebe, Beruf & Gesundheit bei FOLX TV.` + : "Kostenloses Tageshoroskop, Wochenhoroskop & Monatshoroskop für alle 12 Sternzeichen. Liebe, Beruf, Gesundheit bei FOLX TV."; + const horoUrl = `${canonicalBase}${signName ? `/horoskop/${signName}` : "/horoskop"}`; + const horoImage = `${canonicalBase}/images/horoskop-og.jpg`; + + const horoTags = [ + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + `${escapeHtml(title)}`, + ].join("\n "); + + template = template.replace(/[^<]*<\/title>/, horoTags); + res.status(200).set({ "Content-Type": "text/html" }).end(template); + return; + } + let template = await fs.promises.readFile(indexPath, "utf-8"); res.status(200).set({ "Content-Type": "text/html" }).end(template); }); diff --git a/server/vite.ts b/server/vite.ts index 9725476..4b229e2 100644 --- a/server/vite.ts +++ b/server/vite.ts @@ -113,6 +113,46 @@ export async function setupVite(server: Server, app: Express) { } } + if (url.match(/^\/horoskop(\/|$|\?)/)) { + template = stripExistingMeta(template); + const signMatch = url.match(/^\/horoskop\/([^?#]+)/); + const signName = signMatch ? decodeURIComponent(signMatch[1]) : null; + const capitalSign = signName ? signName.charAt(0).toUpperCase() + signName.slice(1) : null; + + const title = capitalSign + ? `${capitalSign} Horoskop – Tages-, Wochen- & Monatshoroskop | Folx Music Television` + : "Horoskop – Tages-, Wochen- & Monatshoroskop für alle Sternzeichen | Folx Music Television"; + const desc = capitalSign + ? `${capitalSign} Horoskop: Tägliches, wöchentliches und monatliches Horoskop. Liebe, Beruf & Gesundheit bei FOLX TV.` + : "Kostenloses Tageshoroskop, Wochenhoroskop & Monatshoroskop für alle 12 Sternzeichen. Liebe, Beruf, Gesundheit bei FOLX TV."; + const horoUrl = `${canonicalBase}${signName ? `/horoskop/${signName}` : "/horoskop"}`; + const horoImage = `${canonicalBase}/images/horoskop-og.jpg`; + + const horoTags = [ + `<meta property="og:title" content="${escapeHtml(title)}" />`, + `<meta property="og:description" content="${escapeHtml(desc)}" />`, + `<meta property="og:type" content="website" />`, + `<meta property="og:url" content="${escapeHtml(horoUrl)}" />`, + `<meta property="og:image" content="${escapeHtml(horoImage)}" />`, + `<meta property="og:image:secure_url" content="${escapeHtml(horoImage)}" />`, + `<meta property="og:image:width" content="1200" />`, + `<meta property="og:image:height" content="675" />`, + `<meta property="og:image:type" content="image/jpeg" />`, + `<meta property="og:site_name" content="Folx Music Television" />`, + `<meta property="og:locale" content="de_DE" />`, + `<meta name="twitter:card" content="summary_large_image" />`, + `<meta name="twitter:title" content="${escapeHtml(title)}" />`, + `<meta name="twitter:description" content="${escapeHtml(desc)}" />`, + `<meta name="twitter:image" content="${escapeHtml(horoImage)}" />`, + `<meta name="description" content="${escapeHtml(desc)}" />`, + `<meta name="keywords" content="Horoskop, Tageshoroskop, Wochenhoroskop, Monatshoroskop, Sternzeichen, Volksmusik, FOLX TV${capitalSign ? `, ${capitalSign}` : ""}" />`, + `<link rel="canonical" href="${escapeHtml(horoUrl)}" />`, + `<title>${escapeHtml(title)}`, + ].join("\n "); + + template = template.replace(/[^<]*<\/title>/, horoTags); + } + const page = await vite.transformIndexHtml(url, template); res.status(200).set({ "Content-Type": "text/html" }).end(page); } catch (e) {