_app.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import { SWRConfig } from "swr";
  2. import Script from "next/script";
  3. import type { NextPage } from "next";
  4. import { useRouter } from "next/router";
  5. import type { AppProps } from "next/app";
  6. import App, { AppContext } from "next/app";
  7. import { ReactElement, ReactNode, useEffect } from "react";
  8. import { Context } from "../libs/context";
  9. import Layout from "../components/common/Layout";
  10. import "../styles/globals.scss";
  11. import { pageview } from "../libs/gtag";
  12. import { GA_TRACKING_ID } from "../libs/config";
  13. import { get } from "../utils/http";
  14. import Head from "next/head";
  15. export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
  16. getLayout?: (page: ReactElement) => ReactNode;
  17. };
  18. type AppPropsWithLayout = AppProps & {
  19. Component: NextPageWithLayout;
  20. pageProps: {
  21. fallback?: {
  22. [key: string]: any;
  23. };
  24. [key: string]: any;
  25. };
  26. };
  27. const MyApp = ({ Component, pageProps }: AppPropsWithLayout) => {
  28. const { fallback, genre, ...otherProps } = pageProps;
  29. const router = useRouter();
  30. useEffect(() => {
  31. const handleRouteChange = (url: string) => {
  32. pageview(url);
  33. };
  34. router.events.on("routeChangeComplete", handleRouteChange);
  35. router.events.on("hashChangeComplete", handleRouteChange);
  36. return () => {
  37. router.events.off("routeChangeComplete", handleRouteChange);
  38. router.events.off("hashChangeComplete", handleRouteChange);
  39. };
  40. }, [router.events]);
  41. return (
  42. <>
  43. <Head>
  44. <meta charSet="utf-8" />
  45. <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
  46. <meta
  47. name="viewport"
  48. content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"
  49. />
  50. <title>NovelDit - Read Novels Online for Free</title>
  51. <meta
  52. name="description"
  53. content="We are offering free books online read! Read novel updated daily: light novel translations, web novel, chinese novel, japanese novel, korean novel and other novel online."
  54. />
  55. <meta
  56. name="keywords"
  57. content="Novel updates, Free books online, Light Novel, Read light novel, Light novel translations, Free Novels Online"
  58. />
  59. <link rel="manifest" href="/manifest.json" />
  60. <link rel="icon" href="/logo.svg" type="image/svg+xml" />
  61. <link rel="icon" href="/favicon.ico" type="image/x-icon" />
  62. <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
  63. <link rel="mask-icon" href="/logo.svg" color="#000000" />
  64. <link
  65. href="/favicon-16x16.png"
  66. rel="icon"
  67. type="image/png"
  68. sizes="16x16"
  69. />
  70. <link
  71. href="/favicon-32x32.png"
  72. rel="icon"
  73. type="image/png"
  74. sizes="32x32"
  75. />
  76. <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
  77. <meta name="theme-color" content="#111827" />
  78. </Head>
  79. <Script
  80. strategy="afterInteractive"
  81. src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
  82. />
  83. <Context.Provider value={{ genre }}>
  84. <SWRConfig value={{ fallback, revalidateIfStale: false }}>
  85. {Component.getLayout ? (
  86. Component.getLayout(<Component {...otherProps} />)
  87. ) : (
  88. <Layout>
  89. <Component {...otherProps} />
  90. </Layout>
  91. )}
  92. </SWRConfig>
  93. </Context.Provider>
  94. </>
  95. );
  96. };
  97. MyApp.getInitialProps = async function (context: AppContext) {
  98. App.getInitialProps(context);
  99. const { data } = await get("/api/genre/list");
  100. return {
  101. pageProps: { genre: data },
  102. };
  103. };
  104. export default MyApp;