diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 2069c48..0000000 --- a/.babelrc +++ /dev/null @@ -1,20 +0,0 @@ -{ - "presets": [ - [ - "babel-preset-gatsby", - { - "reactRuntime": "automatic" - } - ] - ], - "plugins": [ - [ - "prismjs", - { - "languages": [ - "jsx" - ] - } - ] - ] -} diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..1affd3c --- /dev/null +++ b/.env.development @@ -0,0 +1 @@ +NEXT_PUBLIC_API_URL=http://localhost diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..5151fba --- /dev/null +++ b/.env.production @@ -0,0 +1 @@ +NEXT_PUBLIC_API_URL=https://staging.animethemes.moe diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 4588fca..0000000 --- a/.eslintignore +++ /dev/null @@ -1,10 +0,0 @@ -# NPM -/node_modules - -# Gatsby -/.cache -/public - -# IDE (WebStorm) -*.iml -/.idea diff --git a/.eslintrc.json b/.eslintrc.json index d3aa3ce..12eb4e0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,46 +1,47 @@ { - "globals": { - "__PATH_PREFIX__": true - }, - "extends": [ - "react-app", - "plugin:react/recommended" + "extends": [ + "next/core-web-vitals", + "plugin:react/recommended" + ], + "rules": { + "semi": [ + "error", + "always" ], - "rules": { - "quotes": [ - "error", - "double", - { - "allowTemplateLiterals": true - } - ], - "curly": [ - "error", - "all" - ], - "object-curly-spacing": [ - "error", - "always" - ], - "indent": [ - "error", - 4, - { - "SwitchCase": 1 - } - ], - "no-duplicate-imports": "error", - "no-restricted-imports": [ - "error", - { - "patterns": [ - "components/*/*" - ] - } - ], - "react/react-in-jsx-scope": "off", - "react/self-closing-comp": "error", - // For now we don't habe prop-types validation - "react/prop-types": "off" - } + "quotes": [ + "error", + "double", + { + "allowTemplateLiterals": true + } + ], + "curly": [ + "error", + "all" + ], + "object-curly-spacing": [ + "error", + "always" + ], + "indent": [ + "error", + 4, + { + "SwitchCase": 1 + } + ], + "no-duplicate-imports": "error", + "no-restricted-imports": [ + "error", + { + "patterns": [ + "components/*/*" + ] + } + ], + "react/react-in-jsx-scope": "off", + "react/self-closing-comp": "error", + // For now we don't habe prop-types validation + "react/prop-types": "off" + } } diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 78a0967..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: github pages - -on: - push: - branches: - - main - -jobs: - deploy: - services: - mariadb: - image: mariadb:latest - env: - MYSQL_ROOT_PASSWORD: test123 - MYSQL_DATABASE: animethemes - ports: - - 3306 - options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 - runs-on: ubuntu-18.04 - steps: - - uses: actions/checkout@v2 - - - name: Import database dump - env: - PORT: ${{ job.services.mariadb.ports[3306] }} - run: | - sudo /etc/init.d/mysql start - curl -L https://github.com/AnimeThemes/animethemes-db-dump/raw/main/mysql/animethemes-db-dump-create-tables.sql | mysql --user=root --password=test123 --host=127.0.0.1 --port="$PORT" animethemes - - - name: Setup Node - uses: actions/setup-node@v2.1.2 - with: - node-version: '12.x' - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - - - name: Install dependencies - run: npm install - - - name: Build Gatsby pages - run: npm run build-with-paths - env: - GATSBY_PATH_PREFIX: /animethemes-web - GATSBY_CI: true - SOURCE_PLUGIN: DB - DB_USER: root - DB_PASSWORD: test123 - DB_PORT: ${{ job.services.mariadb.ports[3306] }} - - - name: Deploy - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./public diff --git a/.gitignore b/.gitignore index 454fa04..678017d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,37 @@ -# General -.env -.env.* +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. -# NPM -node_modules +# dependencies +/node_modules +/.pnp +.pnp.js -# Gatsby -/.cache -/public -/schema.json +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel # IDE (WebStorm) *.iml diff --git a/.graphqlconfig b/.graphqlconfig deleted file mode 100644 index b35a137..0000000 --- a/.graphqlconfig +++ /dev/null @@ -1,3 +0,0 @@ -{ - "schemaPath": "schema.json" -} diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 5253bb2..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 paranarimasu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 214d366..3117682 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,58 @@ # AnimeThemes Web Client +1. [Configuration](#configuration) +2. [Development](#development) +3. [Deployment](#deployment) +4. [Used technologies](#used-technologies) + +## Configuration + +To get started you need to define some environment variables. This can be done by creating a `.env.local` file in the +root directory. + +This is a list of all available options: + +```ini +; Datebase configuration +; Only username and password are required. +; All other fields take the specified values by default, but can be changed if wanted. +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_USER=... +DB_PASSWORD=... +DB_DATABASE=animethemes + +; (Optional) The URL to the AnimeThemes API to use. +; For development this is "http://localhost" by default. +; For production this is "https://staging.animethemes.moe" by default. +NEXT_PUBLIC_API_URL=http://localhost + +; (Optional) The URL from which video files should be served. +; By default this is "https://animethemes.moe". +NEXT_PUBLIC_VIDEO_URL=https://animethemes.moe + +; (Optional) The base path the app should be hosted on. +; By default the app is hosted on the root path (/). +NEXT_PUBLIC_BASE_PATH=/wiki +``` + +For more information on environment variables see the [Next.js documentation](https://nextjs.org/docs/basic-features/environment-variables). + ## Development 1. `npm install` -2. `npm run develop` +2. `npm run dev` ## Deployment -### Hosting on root path - -1. `npm run build` -2. Upload the contents of `public` to your server. - -### Hosting on sub-path - -1. Adjust `pathPrefix` in `gatsby-config.js` to your server environment. -2. `npm run build-with-paths` -3. Upload the contents of `public` to your server. - -## Configuration - -You can configure certain settings by creating a `.env.development` (for development) or `.env.production` (for deployment) -in the client root directory and include the following: - -```ini -; The URL to the AnimeThemes API to use. -; If not specified, "https://staging.animethemes.moe" is used as a default. -GATSBY_API_URL = http://localhost -``` - -### Apache Configuration - -`.htaccess` files can be placed in `static` and will be copied to the `public` folder during build. +1. `npm install` (If not done already.) +2. `npm run build` generates all static pages and produces a production ready bundle. +3. `npm run start` starts the server. +4. The server is now listening on port 3000 for incoming requests. ## Used technologies -- [Gatsby](https://www.gatsbyjs.com/) +- [Next.js](https://www.nextjs.org/) - [styled-components](https://styled-components.com/) - [react-query](https://react-query.tanstack.com/) - [Font Awesome](https://fontawesome.com/) diff --git a/gatsby-browser.js b/gatsby-browser.js deleted file mode 100644 index d956d30..0000000 --- a/gatsby-browser.js +++ /dev/null @@ -1,6 +0,0 @@ -export function shouldUpdateScroll({ - routerProps, - prevRouterProps -}) { - return routerProps?.location?.pathname !== prevRouterProps?.location?.pathname; -} diff --git a/gatsby-config.esm.js b/gatsby-config.esm.js deleted file mode 100644 index 5b80281..0000000 --- a/gatsby-config.esm.js +++ /dev/null @@ -1,66 +0,0 @@ -import fs from "fs"; -import path from "path"; -import siteConfig from "./site-config"; -import dotenv from "dotenv"; - -// Load environment configuration -dotenv.config({ - path: `.env.${process.env.NODE_ENV}`, -}); - -// Map every path in "src" to its directory name so we can import files like this: -// -// import Button from "components/button"; -// -// Otherwise we would have to provide relative paths which makes refactoring harder. -const aliases = fs.readdirSync(path.join(__dirname, "src")).reduce((obj, directory) => { - obj[directory] = path.join(__dirname, "src", directory); - return obj; -}, {}); - -// If Gatsby already set up a path prefix, use that instead -const pathPrefix = process.env.GATSBY_PATH_PREFIX || siteConfig.pathPrefix; - -const config = { - pathPrefix: pathPrefix, - siteMetadata: { - lang: siteConfig.siteLanguage, - siteName: siteConfig.siteName, - description: siteConfig.description, - titleTemplate: `%s ยท ${siteConfig.siteName}`, - siteUrl: path.posix.join((process.env.SITE_URL || siteConfig.rootUrl), pathPrefix) - }, - plugins: [ - process.env.SOURCE_PLUGIN === "DB" - ? "gatsby-source-animethemes-db" - : "gatsby-source-animethemes", - "gatsby-source-animebracket", - "gatsby-plugin-styled-components", - "gatsby-plugin-react-helmet", - { - resolve: "gatsby-plugin-root-import", - options: aliases - }, - { - resolve: "gatsby-plugin-layout", - options: { - component: require.resolve("./src/layout/index.js"), - } - }, - "gatsby-plugin-fontawesome-css", - { - resolve: "gatsby-plugin-manifest", - options: { - icon: "src/images/icon.png" - } - }, - "gatsby-plugin-eslint", - "gatsby-plugin-sass" - ] -}; - -if (process.env.NODE_ENV === "development") { - config.plugins.push("gatsby-plugin-extract-schema"); -} - -export default config; diff --git a/gatsby-config.js b/gatsby-config.js deleted file mode 100644 index b187c19..0000000 --- a/gatsby-config.js +++ /dev/null @@ -1,3 +0,0 @@ -// eslint-disable-next-line no-native-reassign -require = require("esm")(module); -module.exports = require("./gatsby-config.esm.js"); diff --git a/gatsby-node.esm.js b/gatsby-node.esm.js deleted file mode 100644 index 71ec666..0000000 --- a/gatsby-node.esm.js +++ /dev/null @@ -1,142 +0,0 @@ -import createVideoSlug from "./src/utils/createVideoSlug"; - -const seasonOrder = [ "Winter", "Spring", "Summer", "Fall" ]; - -export async function createPages({ actions: { createPage }, graphql }) { - const { data } = await graphql(` - query { - allAnime { - nodes { - slug - themes { - # We can't use fragments in gatsby-node.js, - # so this is mostly a copy of the fragment found in - # createVideoSlug.fragment.js. - # (https://stackoverflow.com/a/49351248) - slug - entries { - id - version - videos { - id - tags - } - } - } - } - groupedByYear: group(field: year) { - year: fieldValue - nodes { - season - } - } - } - allSeries { - nodes { - slug - } - } - allStudio { - nodes { - slug - } - } - allArtist { - nodes { - slug - } - } - allBracket { - nodes { - slug - } - } - } - `); - - for (const { slug, themes } of data.allAnime.nodes) { - createPage({ - path: `/anime/${slug}`, - component: require.resolve("./src/templates/anime.js"), - context: { slug } - }); - - for (const theme of themes) { - for (const entry of theme.entries) { - for (const video of entry.videos) { - const videoSlug = createVideoSlug(theme, entry, video); - - createPage({ - path: `/anime/${slug}/${videoSlug}`, - component: require.resolve("./src/templates/video.js"), - context: { id: video.id, entryId: entry.id } - }); - } - } - } - } - - for (const { year, nodes } of data.allAnime.groupedByYear) { - const yearNumeric = +year; - - // Get unique seasons - const seasonList = nodes - .map((node) => node.season) - .filter((value, index, self) => self.indexOf(value) === index) - .sort((a, b) => seasonOrder.indexOf(a) - seasonOrder.indexOf(b)); - - createPage({ - path: `/year/${year}`, - component: require.resolve("./src/templates/year.js"), - context: { year: yearNumeric, seasonList } - }); - - for (const season of seasonList) { - createPage({ - path: `/year/${year}/${season.toLowerCase()}`, - component: require.resolve("./src/templates/season.js"), - context: { year: yearNumeric, season, seasonList } - }); - } - } - - for (const { slug } of data.allSeries.nodes) { - createPage({ - path: `/series/${slug}`, - component: require.resolve("./src/templates/series.js"), - context: { slug } - }); - } - - for (const { slug } of data.allStudio.nodes) { - createPage({ - path: `/studio/${slug}`, - component: require.resolve("./src/templates/studio.js"), - context: { slug } - }); - } - - for (const { slug } of data.allArtist.nodes) { - createPage({ - path: `/artist/${slug}`, - component: require.resolve("./src/templates/artist.js"), - context: { slug } - }); - } - - for (const { slug } of data.allBracket.nodes) { - createPage({ - path: `/bracket/${slug}`, - component: require.resolve("./src/templates/bracket.js"), - context: { slug } - }); - } - - for (const entity of [ null, "anime", "theme", "artist", "series", "studio" ]) { - createPage({ - path: `/search${entity ? `/${entity}` : ``}`, - component: require.resolve("./src/templates/search.js"), - context: { entity } - }); - } -} diff --git a/gatsby-node.js b/gatsby-node.js deleted file mode 100644 index 78d2662..0000000 --- a/gatsby-node.js +++ /dev/null @@ -1,3 +0,0 @@ -// eslint-disable-next-line no-native-reassign -require = require("esm")(module); -module.exports = require("./gatsby-node.esm.js"); diff --git a/gatsby-ssr.js b/gatsby-ssr.js deleted file mode 100644 index d2fca4a..0000000 --- a/gatsby-ssr.js +++ /dev/null @@ -1,24 +0,0 @@ -const ThemeInjection = () => { - // language=JavaScript - const injectTheme = ` - (function() { - const body = document.body; - const theme = window.localStorage.getItem("theme"); - - if (theme) { - body.setAttribute("theme", theme); - } - })(); - `; - - return ( -