E3R

contoh _route

E3R
Jul 23rd, 2026
13
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.55 KB | None | 0 0
  1. import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
  2. import {
  3. Outlet,
  4. Link,
  5. createRootRouteWithContext,
  6. useRouter,
  7. HeadContent,
  8. Scripts,
  9. } from "@tanstack/react-router";
  10. import { useEffect, type ReactNode } from "react";
  11.  
  12. import appCss from "../styles.css?url";
  13. import { reportLovableError } from "../lib/lovable-error-reporting";
  14.  
  15. const SITE_NAME = "REEL THAI EDITORIAL";
  16.  
  17. function NotFoundComponent() {
  18. return (
  19. <div className="flex min-h-screen items-center justify-center px-4">
  20. <div className="max-w-md text-center">
  21. <h1 className="serif text-7xl">404</h1>
  22. <p className="mt-4 text-muted-foreground">ไม่พบหน้าที่คุณกำลังค้นหา</p>
  23. <Link to="/" className="link mt-6 inline-block">กลับสู่หน้าหลัก</Link>
  24. </div>
  25. </div>
  26. );
  27. }
  28.  
  29. function ErrorComponent({ error, reset }: { error: Error; reset: () => void }) {
  30. const router = useRouter();
  31. useEffect(() => {
  32. reportLovableError(error, { boundary: "tanstack_root_error_component" });
  33. }, [error]);
  34. return (
  35. <div className="flex min-h-screen items-center justify-center px-4">
  36. <div className="max-w-md text-center">
  37. <h1 className="serif text-2xl">เกิดข้อผิดพลาด</h1>
  38. <p className="mt-2 text-sm text-muted-foreground">โปรดลองใหม่อีกครั้ง</p>
  39. <button
  40. onClick={() => { router.invalidate(); reset(); }}
  41. className="link mt-4"
  42. >ลองอีกครั้ง</button>
  43. </div>
  44. </div>
  45. );
  46. }
  47. function Histats() {
  48. useEffect(() => {
  49. (window as any)._Hasync = (window as any)._Hasync || [];
  50. (window as any)._Hasync.push([
  51. "Histats.start",
  52. "1,5014113,0,0,0,0,00000000",
  53. ]);
  54. (window as any)._Hasync.push(["Histats.fasi", "1"]);
  55. (window as any)._Hasync.push(["Histats.track_hits", ""]);
  56.  
  57. const script = document.createElement("script");
  58. script.src = "https://s10.histats.com/js15_as.js";
  59. script.async = true;
  60.  
  61. document.body.appendChild(script);
  62.  
  63. return () => {
  64. script.remove();
  65. };
  66. }, []);
  67.  
  68. return (
  69. <div style={{ display: "none" }}>
  70. <div id="histats_counter"></div>
  71. <noscript>
  72. <a href="/">
  73. <img
  74. src="https://sstatic1.histats.com/0.gif?5014113&101"
  75. alt="Histats"
  76. border={0}
  77. />
  78. </a>
  79. </noscript>
  80. </div>
  81. );
  82. }
  83.  
  84. export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()({
  85. head: () => ({
  86. meta: [
  87. { charSet: "utf-8" },
  88. { name: "viewport", content: "width=device-width, initial-scale=1" },
  89. { property: "og:site_name", content: SITE_NAME },
  90. { property: "og:locale", content: "th_TH" },
  91. { property: "og:type", content: "article" },
  92. { name: "twitter:card", content: "summary_large_image" },
  93. { name: "google-site-verification", content: "f9QvvK0LCyE7g6jlpe2HFnbch6-eF3FLIhKuPM9g59M" },
  94. { title: '~(ดูหนังใหม่‼️)▷ "สไปเดอร์-แมน: แบรนด์ นิว เดย์" (2026) เต็มเรื่อง พากย์ไทย ดูฟรี! - HD' },
  95. { property: "og:title", content: '~(ดูหนังใหม่‼️)▷ "Spider-Man: Brand New Day" (2026) เต็มเรื่อง พากย์ไทย' },
  96. { name: "twitter:title", content: '~(ดูหนังใหม่‼️)▷ "Spider-Man: Brand New Day" (2026) เต็มเรื่อง พากย์ไทย' },
  97. {
  98. name: "description",
  99. content: "คุณกำลังมองหา สไปเดอร์-แมน: แบรนด์ นิว เดย์ (2026) เต็มเรื่อง พากย์ไทย อยู่ใช่ไหม? อ่านข้อมูลอัปเดตล่าสุด บทวิจารณ์ฉบับเต็ม และรายละเอียดภาพยนตร์มาร์เวล"
  100. },
  101. {
  102. property: "og:description",
  103. content: "สไปเดอร์-แมน: แบรนด์ นิว เดย์ – ข้อมูลภาพยนตร์ทั้งหมด: ตัวอย่างหนัง, นักแสดง, เรื่องย่อ และรายละเอียดการผลิตภาพยนตร์มาร์เวล"
  104. },
  105. { name: "keywords", content: "สไปเดอร์-แมน 2026, Spider-Man 4 Thai, ดูหนังออนไลน์, เต็มเรื่อง, ซับไทย, พากย์ไทย, Marvel Thailand" },
  106. { property: "og:image", content: "https://images.tmdb.org/t/p/original/mBa33S596pBuhC9otMTZpS3C1oA.jpg" },
  107. { name: "twitter:image", content: "https://images.tmdb.org/t/p/original/mBa33S596pBuhC9otMTZpS3C1oA.jpg" },
  108. ],
  109. links: [
  110. { rel: "stylesheet", href: appCss },
  111. { rel: "icon", href: "/favicon.ico", type: "image/x-icon" },
  112. { rel: "preconnect", href: "https://fonts.googleapis.com" },
  113. { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" as any },
  114. { rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;900&family=Sarabun:wght@300;400;500;600;700&display=swap" },
  115. ],
  116. scripts: [
  117. {
  118. type: "application/ld+json",
  119. children: JSON.stringify({
  120. "@context": "https://schema.org",
  121. "@type": "NewsArticle",
  122. "headline": "สไปเดอร์-แมน: แบรนด์ นิว เดย์ (2026) – ข้อมูลอัปเดตล่าสุดและบทวิเคราะห์",
  123. "image": ["https://images.tmdb.org/t/p/original/mBa33S596pBuhC9otMTZpS3C1oA.jpg"],
  124. "datePublished": "2024-05-14T10:00:00+07:00",
  125. "author": [{
  126. "@type": "Person",
  127. "name": "กองบรรณาธิการ REEL THAI",
  128. "url": "https://siamreel.up.railway.app"
  129. }]
  130. }),
  131. },
  132. ],
  133. }),
  134. shellComponent: RootShell,
  135. component: RootComponent,
  136. notFoundComponent: NotFoundComponent,
  137. errorComponent: ErrorComponent,
  138. });
  139.  
  140. function RootShell({ children }: { children: ReactNode }) {
  141. return (
  142. <html lang="th">
  143. <head>
  144. <HeadContent />
  145. </head>
  146. <body>
  147. {children}
  148.  
  149. <Histats />
  150.  
  151. <Scripts />
  152. </body>
  153. </html>
  154. );
  155. }
  156.  
  157. function RootComponent() {
  158. const { queryClient } = Route.useRouteContext();
  159.  
  160. useEffect(() => {
  161. (window as any)._Hasync = (window as any)._Hasync || [];
  162. (window as any)._Hasync.push(["Histats.start", "1,4925760,4,0,0,0,00010000"]);
  163. const hs = document.createElement("script");
  164. hs.type = "text/javascript";
  165. hs.async = true;
  166. hs.src = "https://s10.histats.com/js15_as.js";
  167. document.body.appendChild(hs);
  168.  
  169. // Adsterra global scripts (social bar / popunder)
  170. const ads1 = document.createElement("script");
  171. ads1.src = "https://pl30414546.effectivecpmnetwork.com/32/8e/48/328e48a141a04d4779bf7ce01917f31f.js";
  172. ads1.async = true;
  173. document.body.appendChild(ads1);
  174.  
  175. const ads2 = document.createElement("script");
  176. ads2.src = "https://pl30414547.effectivecpmnetwork.com/85/fe/e9/85fee95a99292ac49c9255203f17ecc6.js";
  177. ads2.async = true;
  178. document.body.appendChild(ads2);
  179. }, []);
  180.  
  181. return (
  182. <QueryClientProvider client={queryClient}>
  183. <div className="min-h-screen flex flex-col">
  184. {/* HEADER */}
  185. <header className="rule-bottom">
  186. <div className="mx-auto max-w-6xl px-6 py-6">
  187. <div className="flex items-center justify-between text-[10px] tracking-[0.32em] uppercase text-muted-foreground">
  188. <span>ฉบับ · ภาพยนตร์และวัฒนธรรม</span>
  189. <span>{new Date().toLocaleDateString("th-TH", { year: "numeric", month: "long", day: "numeric" })}</span>
  190. </div>
  191. <div className="mt-4 text-center">
  192. <Link to="/" className="serif text-5xl md:text-6xl font-black tracking-tight text-gold">
  193. {SITE_NAME}
  194. </Link>
  195. <p className="mt-2 text-[11px] tracking-[0.4em] uppercase text-muted-foreground">
  196. คู่มือชมภาพยนตร์ระดับพรีเมียม
  197. </p>
  198. </div>
  199. </div>
  200. </header>
  201.  
  202. {/* MAIN */}
  203. <main className="flex-1">
  204. <Outlet />
  205. </main>
  206.  
  207. {/* FOOTER */}
  208. <footer className="rule-top mt-20">
  209. <div className="mx-auto max-w-6xl px-6 py-10">
  210. <nav className="flex flex-wrap items-center justify-center gap-8 text-sm tracking-wide">
  211. <Link to="/about" className="link">เกี่ยวกับเรา</Link>
  212. <Link to="/disclaimer" className="link">ข้อจำกัดความรับผิดชอบ</Link>
  213. <Link to="/privacy" className="link">นโยบายความเป็นส่วนตัว</Link>
  214. </nav>
  215. <p className="mt-6 text-center text-xs text-muted-foreground tracking-widest">
  216. © {new Date().getFullYear()} {SITE_NAME} — สงวนลิขสิทธิ์
  217. </p>
  218. </div>
  219. </footer>
  220. </div>
  221. </QueryClientProvider>
  222. );
  223. }
  224.  
Advertisement
Add Comment
Please, Sign In to add comment