เค้าโครง
ไฟล์เลย์เอาต์ถูกสร้างจากฟังก์ชัน TypeScript คุณสามารถกำหนดคุณสมบัติได้มากเท่าที่คุณต้องการตราบใดที่คุณส่งคืนเป็นสตริง จากนั้นให้แต่ละหน้าที่อยู่ในโปรเจกต์ของคุณส่งข้อมูลที่เกี่ยวข้องไปยังฟังก์ชันนี้
การใช้ไฟล์ TypeScript เพียงอย่างเดียวช่วยลดจำนวนภาษาในโปรเจกต์นี้ คุณไม่จำเป็นต้องเรียนรู้ภาษาเทมเพลตอีกแล้ว เพื่อทำให้การโต้ตอบกับ HTML ใน TypeScript ง่ายขึ้น ฉันได้ใช้ความคิดเห็น `/* HTML */` เพื่ออนุญาตให้มีข้อความหลายบรรทัด ซึ่งได้รับการรับรู้จาก 2 ส่วนขยายที่ฉันพบบ่อย ๆ ว่ามีประโยชน์
- esbenp.prettier-vscode
- tobermory.es6-string-html
TypeScript - src/Layout.ts
import { LanguageOption } from "./GlobalSitesCore/LanguageOption";
import i18next from "./GlobalSitesCore/i18n";
import { languageSettings } from "./GlobalSitesCore/languages";
import { urlBuilder } from "./GlobalSitesCore/urlBuilder";
interface LayoutProps {
content: string;
lang: string;
description: string;
title: string;
languageOptions: LanguageOption[];
}
export function Layout(props: LayoutProps): string {
const baseUrl = "https://www.globalsites.ai";
var currentLanguageOption = props.languageOptions.find(
(option) => option.code == props.lang
);
var defaultLanguageOption = props.languageOptions.find(
(option) => option.code == languageSettings.defaultLanguage
);
return /* HTML */ `
<!DOCTYPE html>
<html lang="${props.lang}">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="${props.description}" />
<meta property="og:title" content="${props.title}" />
<meta property="og:description" content="${props.description}" />
<meta property="og:url" content="${currentLanguageOption?.url}" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Global Sites" />
<meta property="og:locale" content="${props.lang}" />
<meta property="og:image" content="${baseUrl}/ogImage.jpg" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@benwmaddox" />
<meta name="twitter:creator" content="@benwmaddox" />
<meta name="twitter:title" content="${props.title}" />
<meta name="twitter:description" content="${props.description}" />
<meta name="twitter:image" content="${baseUrl}/ogImage.jpg" />
<link
rel="sitemap"
type="application/xml"
title="Sitemap"
href="/sitemap.xml"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/dark.min.css"
/>
<link rel="stylesheet" href="/styles.css" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>
${props.title ? props.title + " - " : ""}${i18next.t(`Global Sites`)}
</title>
<style>
body {
height: 100vh;
}
</style>
${props.languageOptions
.map((option) => {
return option.code == languageSettings.defaultLanguage
? `<link rel="alternate" href="${baseUrl}${option.url}" hreflang="${option.code}"/>
<link rel="alternate" href="${baseUrl}${option.url}" hreflang="x-default"/>`
: `<link rel="alternate" href="${baseUrl}${option.url}" hreflang="${option.code}"/>`;
})
.join("
")}
<script>
function switchLanguage() {
var selectedLanguageUrl =
document.getElementById("language-select").value;
window.location.href = selectedLanguageUrl;
}
</script>
</head>
<body>
<header>
<div class="flex">
<div class="logo">
<a
href="${props.lang === "en" ? "/" : `/${props.lang}/`}"
style="display:inline-block;"
>
<img src="/logo.svg" alt="Logo"
/></a>
</div>
<div class="language-switcher">
<select id="language-select" onchange="switchLanguage()">
${[...props.languageOptions]
.sort((a, b) =>
a.code == props.lang ? 1 : a.code.localeCompare(b.code)
)
.map((option) => {
return `<option value="${option.url}" ${
option.code === props.lang ? "selected" : ""
}>${option.name}</option>`;
})
.join("")}
</select>
</div>
<nav>
<a href="/${urlBuilder(undefined, undefined)}"
>${i18next.t("Home")}</a
>
|
<a href="/${urlBuilder(undefined, "documentation")}"
>${i18next.t("Documentation")}</a
>
|
<a href="/${urlBuilder(undefined, "contact-us")}"
>${i18next.t("Contact Us")}</a
>
|
<a href="/${urlBuilder(undefined, "privacy-policy")}"
>${i18next.t("Privacy Policy")}</a
>
|
<a href="/${urlBuilder(undefined, "faq")}">${i18next.t("FAQ")}</a>
</nav>
</div>
</header>
<main>
<div class="container">${props.content}</div>
</main>
<footer>
<div class="footer-content">
<p>
<a href="/${urlBuilder(undefined, "contact-us")}"
>${i18next.t("Contact Us")}</a
>
|
<a href="/${urlBuilder(undefined, "privacy-policy")}"
>${i18next.t("Privacy Policy")}</a
>
|
<a href="/${urlBuilder(undefined, "faq")}">${i18next.t("FAQ")}</a>
© ${new Date().getFullYear()} ${baseUrl}
</p>
<div>
${[...props.languageOptions]
.map((option) => {
return `<a href="${option.url}" >${option.name}</a>`;
})
.join(" | ")}
</div>
</div>
</footer>
</body>
</html>
`;
}