Содержание
Начало работыМакет
Страницы
Переводы
Развертывания
Демонстрационный стенд
Дополнительные ресурсы
Макет
Файлы макетов создаются из функций TypeScript. Вы можете определить столько свойств, сколько вам нужно, при условии, что вы возвращаете строку. После этого каждая страница в вашем проекте должна передать соответствующие данные в эту функцию.
Использование только файлов TypeScript снижает количество языков в этом проекте. Вам не нужно учить еще один язык шаблонов. Чтобы упростить взаимодействие с HTML в TypeScript, я использовал комментарий `/* HTML */`, который позволяет использовать многострочные строки. Он распознается двумя расширениями, которые, на мой взгляд, полезны.
- 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>
`;
}