Diseño

Los archivos de diseño están hechos de funciones de TypeScript. Puedes definir tantas propiedades como desees siempre que devuelvas una cadena. Luego, haz que cada página de tu proyecto pase los datos relevantes a esta función.

Simplemente usar archivos TypeScript reduce la cantidad de lenguajes en este proyecto. No necesitas aprender otro lenguaje de plantillas más. Para facilitar la interacción con el HTML en TypeScript, he utilizado el comentario `/* HTML */` para permitir cadenas de varias líneas. Eso es reconocido por 2 extensiones que considero útiles.

  • 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>
              &copy; ${new Date().getFullYear()} ${baseUrl}
            </p>
            <div>
              ${[...props.languageOptions]
                .map((option) => {
                  return `<a href="${option.url}" >${option.name}</a>`;
                })
                .join(" | ")}
            </div>
          </div>
        </footer>
      </body>
    </html>
  `;
}