diff --git a/.env b/.env deleted file mode 100644 index c459b80a..00000000 --- a/.env +++ /dev/null @@ -1,5 +0,0 @@ -# this is to prevent warnings in webpack builds -GENERATE_SOURCEMAP=false - -# uncomment and add the following line to `.env.local` if you are running behind a proxy or on a subdirectory -# PUBLIC_URL=https://your-domain.com/directory-here diff --git a/index.html b/index.html new file mode 100644 index 00000000..822f74f3 --- /dev/null +++ b/index.html @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + movie-web + + + +
+ + + diff --git a/package.json b/package.json index 0e789eb5..5350bbe1 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,13 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-router-dom": "^5.2.0", - "react-scripts": "5.0.1", "srt-webvtt": "^2.0.0", "unpacker": "^1.0.1" }, "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", + "dev": "vite", + "build": "vite build", + "preview": "vite preview", "lint": "eslint --ext .tsx,.ts src", "lint:strict": "eslint --ext .tsx,.ts --max-warnings 0 src" }, @@ -44,7 +44,8 @@ "@types/react-router-dom": "^5.3.3", "@typescript-eslint/eslint-plugin": "^5.13.0", "@typescript-eslint/parser": "^5.13.0", - "autoprefixer": "^10.4.2", + "@vitejs/plugin-react-swc": "^3.0.0", + "autoprefixer": "^10.4.13", "eslint": "^8.10.0", "eslint-config-airbnb": "19.0.4", "eslint-config-prettier": "^8.5.0", @@ -53,11 +54,12 @@ "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "7.29.4", "eslint-plugin-react-hooks": "4.3.0", - "postcss": "^8.4.6", + "postcss": "^8.4.20", "prettier": "^2.5.1", "prettier-plugin-tailwindcss": "^0.1.7", - "tailwind-scrollbar": "^1.3.1", - "tailwindcss": "^3.0.20", - "typescript": "^4.6.4" + "tailwind-scrollbar": "^2.0.1", + "tailwindcss": "^3.2.4", + "typescript": "^4.6.4", + "vite": "^4.0.1" } } diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..33ad091d --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/public/index.html b/public/index.html deleted file mode 100644 index 9705cefa..00000000 --- a/public/index.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - movie-web - - - -
- - diff --git a/src/App.tsx b/src/App.tsx index e67c09b8..b427c62e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,8 +1,8 @@ -import { MWMediaType } from "providers"; import { Redirect, Route, Switch } from "react-router-dom"; -import { BookmarkContextProvider } from "state/bookmark"; -import { WatchedContextProvider } from "state/watched"; -import { NotFoundPage } from "views/notfound/NotFoundView"; +import { MWMediaType } from "@/providers"; +import { BookmarkContextProvider } from "@/state/bookmark"; +import { WatchedContextProvider } from "@/state/watched"; +import { NotFoundPage } from "@/views/notfound/NotFoundView"; import "./index.css"; import { MediaView } from "./views/MediaView"; import { SearchView } from "./views/SearchView"; diff --git a/src/components/Dropdown.tsx b/src/components/Dropdown.tsx index 32c89cb8..9ebef561 100644 --- a/src/components/Dropdown.tsx +++ b/src/components/Dropdown.tsx @@ -1,7 +1,7 @@ -import { Icon, Icons } from "components/Icon"; import React, { Fragment } from "react"; import { Listbox, Transition } from "@headlessui/react"; +import { Icon, Icons } from "@/components/Icon"; export interface OptionItem { id: string; @@ -14,48 +14,46 @@ interface DropdownProps { options: Array; } -export const Dropdown = React.forwardRef( - (props: DropdownProps) => ( -
- - {({ open }) => ( - <> - - {props.selectedItem.name} - - - - - - - {props.options.map((opt) => ( - - `relative cursor-default select-none py-2 pl-10 pr-4 ${ - active ? "bg-denim-400 text-bink-700" : "text-white" - }` - } - key={opt.id} - value={opt} - > - {opt.name} - - ))} - - - - )} - -
- ) -); +export function Dropdown(props: DropdownProps) { +
+ + {({ open }) => ( + <> + + {props.selectedItem.name} + + + + + + + {props.options.map((opt) => ( + + `relative cursor-default select-none py-2 pl-10 pr-4 ${ + active ? "bg-denim-400 text-bink-700" : "text-white" + }` + } + key={opt.id} + value={opt} + > + {opt.name} + + ))} + + + + )} + +
; +} diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx index 9caef7da..4cd6a6de 100644 --- a/src/components/SearchBar.tsx +++ b/src/components/SearchBar.tsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { MWMediaType, MWQuery } from "providers"; +import { MWMediaType, MWQuery } from "@/providers"; import { DropdownButton } from "./buttons/DropdownButton"; import { Icons } from "./Icon"; import { TextInputControl } from "./text-inputs/TextInputControl"; diff --git a/src/components/buttons/DropdownButton.tsx b/src/components/buttons/DropdownButton.tsx index 0dbfcb71..5c1a12c5 100644 --- a/src/components/buttons/DropdownButton.tsx +++ b/src/components/buttons/DropdownButton.tsx @@ -1,12 +1,12 @@ -import { Icon, Icons } from "components/Icon"; import React, { MouseEventHandler, SyntheticEvent, useEffect, useState, } from "react"; +import { Icon, Icons } from "@/components/Icon"; -import { Backdrop, useBackdrop } from "components/layout/Backdrop"; +import { Backdrop, useBackdrop } from "@/components/layout/Backdrop"; import { ButtonControlProps, ButtonControl } from "./ButtonControl"; export interface OptionItem { @@ -33,7 +33,7 @@ export interface OptionProps { function Option({ option, onClick, tabIndex }: OptionProps) { return (
@@ -95,7 +95,7 @@ export const DropdownButton = React.forwardRef< > {selectedItem.name} @@ -105,7 +105,7 @@ export const DropdownButton = React.forwardRef< />
{props.children} diff --git a/src/components/buttons/IconPatch.tsx b/src/components/buttons/IconPatch.tsx index 1a80061c..f14a3f56 100644 --- a/src/components/buttons/IconPatch.tsx +++ b/src/components/buttons/IconPatch.tsx @@ -1,4 +1,4 @@ -import { Icon, Icons } from "components/Icon"; +import { Icon, Icons } from "@/components/Icon"; export interface IconPatchProps { active?: boolean; @@ -12,11 +12,11 @@ export function IconPatch(props: IconPatchProps) { return (
diff --git a/src/components/layout/Backdrop.tsx b/src/components/layout/Backdrop.tsx index cc5b68f2..65d3a81d 100644 --- a/src/components/layout/Backdrop.tsx +++ b/src/components/layout/Backdrop.tsx @@ -1,5 +1,5 @@ -import { useFade } from "hooks/useFade"; import { useEffect, useState } from "react"; +import { useFade } from "@/hooks/useFade"; interface BackdropProps { onClick?: (e: MouseEvent) => void; diff --git a/src/components/layout/BrandPill.tsx b/src/components/layout/BrandPill.tsx index b2b8eabd..842cf8a3 100644 --- a/src/components/layout/BrandPill.tsx +++ b/src/components/layout/BrandPill.tsx @@ -1,11 +1,11 @@ -import { Icon, Icons } from "components/Icon"; +import { Icon, Icons } from "@/components/Icon"; export function BrandPill(props: { clickable?: boolean }) { return (
diff --git a/src/components/layout/ErrorBoundary.tsx b/src/components/layout/ErrorBoundary.tsx index 3bd20e88..75aab1e1 100644 --- a/src/components/layout/ErrorBoundary.tsx +++ b/src/components/layout/ErrorBoundary.tsx @@ -1,9 +1,9 @@ -import { IconPatch } from "components/buttons/IconPatch"; -import { Icons } from "components/Icon"; -import { Link } from "components/text/Link"; -import { Title } from "components/text/Title"; -import { DISCORD_LINK, GITHUB_LINK } from "mw_constants"; import { Component } from "react"; +import { IconPatch } from "@/components/buttons/IconPatch"; +import { Icons } from "@/components/Icon"; +import { Link } from "@/components/text/Link"; +import { Title } from "@/components/text/Title"; +import { DISCORD_LINK, GITHUB_LINK } from "@/mw_constants"; interface ErrorBoundaryState { hasError: boolean; diff --git a/src/components/layout/Navigation.tsx b/src/components/layout/Navigation.tsx index dfc8891f..0a255395 100644 --- a/src/components/layout/Navigation.tsx +++ b/src/components/layout/Navigation.tsx @@ -1,8 +1,8 @@ -import { IconPatch } from "components/buttons/IconPatch"; -import { Icons } from "components/Icon"; -import { DISCORD_LINK, GITHUB_LINK } from "mw_constants"; import { ReactNode } from "react"; import { Link } from "react-router-dom"; +import { IconPatch } from "@/components/buttons/IconPatch"; +import { Icons } from "@/components/Icon"; +import { DISCORD_LINK, GITHUB_LINK } from "@/mw_constants"; import { BrandPill } from "./BrandPill"; export interface NavigationProps { @@ -11,8 +11,8 @@ export interface NavigationProps { export function Navigation(props: NavigationProps) { return ( -
-
+
+
@@ -20,7 +20,11 @@ export function Navigation(props: NavigationProps) {
{props.children}
-
+
-
+
{!props.error ? ( <> -
-
-
+
+
+
) : (
diff --git a/src/components/layout/SectionHeading.tsx b/src/components/layout/SectionHeading.tsx index e341496b..fd89d47a 100644 --- a/src/components/layout/SectionHeading.tsx +++ b/src/components/layout/SectionHeading.tsx @@ -1,6 +1,6 @@ -import { Icon, Icons } from "components/Icon"; -import { ArrowLink } from "components/text/ArrowLink"; import { ReactNode } from "react"; +import { Icon, Icons } from "@/components/Icon"; +import { ArrowLink } from "@/components/text/ArrowLink"; interface SectionHeadingProps { icon?: Icons; @@ -15,7 +15,7 @@ export function SectionHeading(props: SectionHeadingProps) { return (
-

+

{props.icon ? ( diff --git a/src/components/media/MediaCard.tsx b/src/components/media/MediaCard.tsx index 1e8ceb02..2171f7cb 100644 --- a/src/components/media/MediaCard.tsx +++ b/src/components/media/MediaCard.tsx @@ -1,13 +1,13 @@ +import { Link } from "react-router-dom"; import { convertMediaToPortable, getProviderFromId, MWMediaMeta, MWMediaType, -} from "providers"; -import { Link } from "react-router-dom"; -import { Icon, Icons } from "components/Icon"; -import { serializePortableMedia } from "hooks/usePortableMedia"; -import { DotList } from "components/text/DotList"; +} from "@/providers"; +import { Icon, Icons } from "@/components/Icon"; +import { serializePortableMedia } from "@/hooks/usePortableMedia"; +import { DotList } from "@/components/text/DotList"; export interface MediaCardProps { media: MWMediaMeta; @@ -30,7 +30,7 @@ function MediaCardContent({ return (

@@ -38,12 +38,12 @@ function MediaCardContent({ {watchedPercentage > 0 ? (
-
+
) : null} @@ -54,7 +54,7 @@ function MediaCardContent({

{media.title} {series && media.seasonId && media.episodeId ? ( - + S{media.seasonId} E{media.episodeId} ) : null} diff --git a/src/components/media/VideoPlayer.tsx b/src/components/media/VideoPlayer.tsx index 92ea4d1c..0009922e 100644 --- a/src/components/media/VideoPlayer.tsx +++ b/src/components/media/VideoPlayer.tsx @@ -1,9 +1,9 @@ -import { IconPatch } from "components/buttons/IconPatch"; -import { Icons } from "components/Icon"; -import { Loading } from "components/layout/Loading"; -import { MWMediaCaption, MWMediaStream } from "providers"; import { ReactElement, useEffect, useRef, useState } from "react"; import Hls from "hls.js"; +import { IconPatch } from "@/components/buttons/IconPatch"; +import { Icons } from "@/components/Icon"; +import { Loading } from "@/components/layout/Loading"; +import { MWMediaCaption, MWMediaStream } from "@/providers"; export interface VideoPlayerProps { source: MWMediaStream; @@ -14,7 +14,7 @@ export interface VideoPlayerProps { export function SkeletonVideoPlayer(props: { error?: boolean }) { return ( -
+
{props.error ? (
@@ -44,8 +44,7 @@ export function VideoPlayer(props: VideoPlayerProps) { // hls support if (mustUseHls) { - if (!videoRef.current) - return; + if (!videoRef.current) return; if (!Hls.isSupported()) { setLoading(false); @@ -55,7 +54,7 @@ export function VideoPlayer(props: VideoPlayerProps) { const hls = new Hls(); - if (videoRef.current.canPlayType('application/vnd.apple.mpegurl')) { + if (videoRef.current.canPlayType("application/vnd.apple.mpegurl")) { videoRef.current.src = props.source.url; return; } @@ -81,8 +80,7 @@ export function VideoPlayer(props: VideoPlayerProps) { <> {skeletonUi}