Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 

92 řádky
2.7 KiB

  1. import type { Metadata } from "next";
  2. import { GeistSans } from "geist/font/sans";
  3. import { GeistMono } from "geist/font/mono";
  4. import fs from "fs/promises";
  5. import path from "path";
  6. import { getPortals } from "@/lib/db";
  7. import { DEFAULT_FONT } from "@/lib/config";
  8. import "./globals.css";
  9. export const metadata: Metadata = {
  10. title: "Captive Portal",
  11. description: "Welcome",
  12. };
  13. function fontFormat(ext: string): string {
  14. switch (ext.toLowerCase()) {
  15. case ".woff2": return "woff2";
  16. case ".woff": return "woff";
  17. case ".ttf": return "truetype";
  18. case ".otf": return "opentype";
  19. default: return "woff2";
  20. }
  21. }
  22. async function findItalicSibling(regularFilename: string): Promise<string | null> {
  23. const m = regularFilename.match(/^(.*)(\.(?:woff2?|ttf|otf))$/i);
  24. if (!m) return null;
  25. const [, base, ext] = m;
  26. const candidates = [
  27. `${base}-Italic${ext}`, `${base}-italic${ext}`,
  28. `${base}_Italic${ext}`, `${base}_italic${ext}`,
  29. `${base} Italic${ext}`, `${base} italic${ext}`,
  30. `${base}Italic${ext}`, `${base}italic${ext}`,
  31. ];
  32. try {
  33. const files = await fs.readdir(path.join(process.cwd(), "data", "fonts"));
  34. for (const c of candidates) {
  35. if (files.includes(c)) return c;
  36. }
  37. } catch {}
  38. return null;
  39. }
  40. export default async function RootLayout({
  41. children,
  42. }: Readonly<{ children: React.ReactNode }>) {
  43. // Leggi il portale per scegliere il font
  44. let chosenFont = DEFAULT_FONT;
  45. try {
  46. const portals = await getPortals();
  47. const portal = portals[0];
  48. if (portal && portal.fontFamily !== undefined) chosenFont = portal.fontFamily;
  49. } catch {}
  50. let fontStyleCss = "";
  51. if (chosenFont) {
  52. const regularExt = path.extname(chosenFont);
  53. const italicFile = await findItalicSibling(chosenFont);
  54. const italicExt = italicFile ? path.extname(italicFile) : "";
  55. const regularUrl = `/api/fonts?name=${encodeURIComponent(chosenFont)}`;
  56. const italicUrl = italicFile ? `/api/fonts?name=${encodeURIComponent(italicFile)}` : "";
  57. fontStyleCss = `
  58. @font-face {
  59. font-family: 'PortalFont';
  60. src: url('${regularUrl}') format('${fontFormat(regularExt)}');
  61. font-style: normal;
  62. font-display: swap;
  63. }${italicFile ? `
  64. @font-face {
  65. font-family: 'PortalFont';
  66. src: url('${italicUrl}') format('${fontFormat(italicExt)}');
  67. font-style: italic;
  68. font-display: swap;
  69. }` : ""}
  70. body { font-family: 'PortalFont', Arial, Helvetica, sans-serif; }
  71. `;
  72. }
  73. return (
  74. <html
  75. lang="it"
  76. className={`${GeistSans.variable} ${GeistMono.variable} h-full antialiased`}
  77. >
  78. <head>
  79. {fontStyleCss && <style dangerouslySetInnerHTML={{ __html: fontStyleCss }} />}
  80. </head>
  81. <body className="min-h-full flex flex-col">{children}</body>
  82. </html>
  83. );
  84. }