mirror of
https://github.com/movie-web/movie-web.git
synced 2024-11-11 00:35:07 +01:00
error handle pages + migration page
Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>
This commit is contained in:
parent
7731938729
commit
6a125a593d
@ -67,3 +67,33 @@ export function Button(props: Props) {
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
interface ButtonPlainProps {
|
||||
onClick?: () => void;
|
||||
children?: ReactNode;
|
||||
theme?: "white" | "purple" | "secondary";
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function ButtonPlain(props: ButtonPlainProps) {
|
||||
let colorClasses = "bg-white hover:bg-gray-200 text-black";
|
||||
if (props.theme === "purple")
|
||||
colorClasses =
|
||||
"bg-video-buttons-purple hover:bg-video-buttons-purpleHover text-white";
|
||||
if (props.theme === "secondary")
|
||||
colorClasses =
|
||||
"bg-video-buttons-cancel hover:bg-video-buttons-cancelHover transition-colors duration-100 text-white";
|
||||
|
||||
const classes = classNames(
|
||||
"cursor-pointer inline-flex items-center justify-center rounded-lg font-medium transition-[transform,background-color] duration-100 active:scale-105 md:px-8",
|
||||
"px-4 py-3",
|
||||
props.className,
|
||||
colorClasses
|
||||
);
|
||||
|
||||
return (
|
||||
<button type="button" onClick={props.onClick} className={classes}>
|
||||
{props.children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
@ -1,114 +0,0 @@
|
||||
import { Component } from "react";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
import { IconPatch } from "@/components/buttons/IconPatch";
|
||||
import { Icons } from "@/components/Icon";
|
||||
import { Link } from "@/components/text/Link";
|
||||
import { Title } from "@/components/text/Title";
|
||||
import { conf } from "@/setup/config";
|
||||
|
||||
interface ErrorShowcaseProps {
|
||||
error: {
|
||||
name: string;
|
||||
description: string;
|
||||
path: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function ErrorShowcase(props: ErrorShowcaseProps) {
|
||||
return (
|
||||
<div className="w-4xl mt-12 max-w-full rounded bg-denim-300 px-6 py-4">
|
||||
<p className="mb-1 break-words font-bold text-white">
|
||||
{props.error.name} - {props.error.description}
|
||||
</p>
|
||||
<p className="break-words">{props.error.path}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface ErrorMessageProps {
|
||||
error?: {
|
||||
name: string;
|
||||
description: string;
|
||||
path: string;
|
||||
};
|
||||
localSize?: boolean;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export function ErrorMessage(props: ErrorMessageProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${
|
||||
props.localSize ? "h-full" : "min-h-screen"
|
||||
} flex w-full flex-col items-center justify-center px-4 py-12`}
|
||||
>
|
||||
<div className="flex flex-col items-center justify-start text-center">
|
||||
<IconPatch icon={Icons.WARNING} className="mb-6 text-red-400" />
|
||||
<Title>{t("media.errors.genericTitle")}</Title>
|
||||
{props.children ? (
|
||||
<p className="my-6 max-w-lg">{props.children}</p>
|
||||
) : (
|
||||
<p className="my-6 max-w-lg">
|
||||
<Trans i18nKey="media.errors.videoFailed">
|
||||
<Link url={conf().DISCORD_LINK} newTab />
|
||||
<Link url={conf().GITHUB_LINK} newTab />
|
||||
</Trans>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{props.error ? <ErrorShowcase error={props.error} /> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface ErrorBoundaryState {
|
||||
hasError: boolean;
|
||||
error?: {
|
||||
name: string;
|
||||
description: string;
|
||||
path: string;
|
||||
};
|
||||
}
|
||||
|
||||
export class ErrorBoundary extends Component<
|
||||
Record<string, unknown>,
|
||||
ErrorBoundaryState
|
||||
> {
|
||||
constructor(props: { children: any }) {
|
||||
super(props);
|
||||
this.state = {
|
||||
hasError: false,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromError() {
|
||||
return {
|
||||
hasError: true,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidCatch(error: any, errorInfo: any) {
|
||||
console.error("Render error caught", error, errorInfo);
|
||||
if (error instanceof Error) {
|
||||
const realError: Error = error as Error;
|
||||
this.setState((s) => ({
|
||||
...s,
|
||||
hasError: true,
|
||||
error: {
|
||||
name: realError.name,
|
||||
description: realError.message,
|
||||
path: errorInfo.componentStack.split("\n")[1],
|
||||
},
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.hasError) return this.props.children as any;
|
||||
|
||||
return <ErrorMessage error={this.state.error} />;
|
||||
}
|
||||
}
|
@ -144,13 +144,13 @@ export function ProgressBar() {
|
||||
>
|
||||
<div
|
||||
className={[
|
||||
"relative w-full h-1 bg-video-progress-background bg-opacity-25 rounded-full transition-[height] duration-100 group-hover:h-1.5",
|
||||
"relative w-full h-1 bg-progress-background bg-opacity-25 rounded-full transition-[height] duration-100 group-hover:h-1.5",
|
||||
dragging ? "!h-1.5" : "",
|
||||
].join(" ")}
|
||||
>
|
||||
{/* Pre-loaded content bar */}
|
||||
<div
|
||||
className="absolute top-0 left-0 h-full rounded-full bg-video-progress-preloaded bg-opacity-50 flex justify-end items-center"
|
||||
className="absolute top-0 left-0 h-full rounded-full bg-progress-preloaded bg-opacity-50 flex justify-end items-center"
|
||||
style={{
|
||||
width: `${(buffered / duration) * 100}%`,
|
||||
}}
|
||||
@ -158,7 +158,7 @@ export function ProgressBar() {
|
||||
|
||||
{/* Actual progress bar */}
|
||||
<div
|
||||
className="absolute top-0 left-0 h-full rounded-full bg-video-progress-watched flex justify-end items-center"
|
||||
className="absolute top-0 left-0 h-full rounded-full bg-progress-filled flex justify-end items-center"
|
||||
style={{
|
||||
width: `${
|
||||
Math.max(
|
||||
|
@ -31,11 +31,15 @@ export function EmbedOption(props: {
|
||||
const setSource = usePlayerStore((s) => s.setSource);
|
||||
const setSourceId = usePlayerStore((s) => s.setSourceId);
|
||||
const progress = usePlayerStore((s) => s.progress.time);
|
||||
|
||||
const unknownEmbedName = "Unknown";
|
||||
|
||||
const embedName = useMemo(() => {
|
||||
if (!props.embedId) return "...";
|
||||
if (!props.embedId) return unknownEmbedName;
|
||||
const sourceMeta = providers.getMetadata(props.embedId);
|
||||
return sourceMeta?.name ?? "...";
|
||||
return sourceMeta?.name ?? unknownEmbedName;
|
||||
}, [props.embedId]);
|
||||
|
||||
const [request, run] = useAsyncFn(async () => {
|
||||
const result = await providers.runEmbedScraper({
|
||||
id: props.embedId,
|
||||
@ -46,26 +50,14 @@ export function EmbedOption(props: {
|
||||
router.close();
|
||||
}, [props.embedId, props.sourceId, meta, router]);
|
||||
|
||||
let content: ReactNode = null;
|
||||
if (request.loading)
|
||||
content = (
|
||||
<Menu.TextDisplay noIcon>
|
||||
<Loading />
|
||||
</Menu.TextDisplay>
|
||||
);
|
||||
else if (request.error)
|
||||
content = (
|
||||
<Menu.TextDisplay title="Failed to scrape">
|
||||
We were unable to find any videos for this source. Don't come
|
||||
bitchin' to us about it, just try another source.
|
||||
</Menu.TextDisplay>
|
||||
);
|
||||
|
||||
return (
|
||||
<SelectableLink onClick={run}>
|
||||
<SelectableLink
|
||||
loading={request.loading}
|
||||
error={request.error}
|
||||
onClick={run}
|
||||
>
|
||||
<span className="flex flex-col">
|
||||
<span>{embedName}</span>
|
||||
{content}
|
||||
</span>
|
||||
</SelectableLink>
|
||||
);
|
||||
|
@ -6,7 +6,7 @@ import { HelmetProvider } from "react-helmet-async";
|
||||
import { BrowserRouter, HashRouter } from "react-router-dom";
|
||||
import { registerSW } from "virtual:pwa-register";
|
||||
|
||||
import { ErrorBoundary } from "@/components/layout/ErrorBoundary";
|
||||
import { ErrorBoundary } from "@/pages/errors/ErrorBoundary";
|
||||
import App from "@/setup/App";
|
||||
import { conf } from "@/setup/config";
|
||||
import i18n from "@/setup/i18n";
|
||||
|
@ -9,6 +9,7 @@ import { HomeLayout } from "@/pages/layouts/HomeLayout";
|
||||
import { BookmarksPart } from "@/pages/parts/home/BookmarksPart";
|
||||
import { HeroPart } from "@/pages/parts/home/HeroPart";
|
||||
import { WatchingPart } from "@/pages/parts/home/WatchingPart";
|
||||
import { MigrationPart } from "@/pages/parts/migrations/MigrationPart";
|
||||
import { SearchListPart } from "@/pages/parts/search/SearchListPart";
|
||||
import { SearchLoadingPart } from "@/pages/parts/search/SearchLoadingPart";
|
||||
|
||||
@ -38,6 +39,8 @@ export function HomePage() {
|
||||
const [search] = searchParams;
|
||||
const s = useSearch(search);
|
||||
|
||||
return <MigrationPart />;
|
||||
|
||||
return (
|
||||
<HomeLayout showBg={showBg}>
|
||||
<div className="mb-16 sm:mb-24">
|
||||
|
@ -1,80 +1,12 @@
|
||||
import { OverlayAnchor } from "@/components/overlays/OverlayAnchor";
|
||||
import { Overlay, OverlayDisplay } from "@/components/overlays/OverlayDisplay";
|
||||
import { OverlayPage } from "@/components/overlays/OverlayPage";
|
||||
import { OverlayRouter } from "@/components/overlays/OverlayRouter";
|
||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
import { useState } from "react";
|
||||
|
||||
// simple empty view, perfect for putting in tests
|
||||
import { Button } from "@/components/Button";
|
||||
|
||||
// mostly empty view, add whatever you need
|
||||
export default function TestView() {
|
||||
const router = useOverlayRouter("test");
|
||||
const [val, setVal] = useState(false);
|
||||
|
||||
return (
|
||||
<OverlayDisplay>
|
||||
<div className="h-[400px] w-[800px] flex justify-center items-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
router.open();
|
||||
}}
|
||||
>
|
||||
Open
|
||||
</button>
|
||||
<OverlayAnchor
|
||||
id={router.id}
|
||||
className="h-20 w-20 hover:w-24 mt-[50rem] bg-white"
|
||||
/>
|
||||
<Overlay id={router.id}>
|
||||
<OverlayRouter id={router.id}>
|
||||
<OverlayPage id={router.id} path="/" width={400} height={400}>
|
||||
<div className="bg-blue-900 p-4">
|
||||
<p>HOME</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
router.navigate("/two");
|
||||
}}
|
||||
>
|
||||
open page two
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
router.navigate("/one");
|
||||
}}
|
||||
>
|
||||
open page one
|
||||
</button>
|
||||
</div>
|
||||
</OverlayPage>
|
||||
<OverlayPage id={router.id} path="/one" width={300} height={300}>
|
||||
<div className="bg-blue-900 p-4">
|
||||
<p>ONE</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
router.navigate("/");
|
||||
}}
|
||||
>
|
||||
back home
|
||||
</button>
|
||||
</div>
|
||||
</OverlayPage>
|
||||
<OverlayPage id={router.id} path="/two" width={200} height={200}>
|
||||
<div className="bg-blue-900 p-4">
|
||||
<p>TWO</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
router.navigate("/");
|
||||
}}
|
||||
>
|
||||
back home
|
||||
</button>
|
||||
</div>
|
||||
</OverlayPage>
|
||||
</OverlayRouter>
|
||||
</Overlay>
|
||||
</div>
|
||||
</OverlayDisplay>
|
||||
);
|
||||
if (val) throw new Error("I crashed");
|
||||
|
||||
return <Button onClick={() => setVal(true)}>Crash me!</Button>;
|
||||
}
|
||||
|
44
src/pages/errors/ErrorBoundary.tsx
Normal file
44
src/pages/errors/ErrorBoundary.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import { Component } from "react";
|
||||
|
||||
import { ErrorPart } from "@/pages/parts/errors/ErrorPart";
|
||||
|
||||
interface ErrorBoundaryState {
|
||||
error?: {
|
||||
error: any;
|
||||
errorInfo: any;
|
||||
};
|
||||
}
|
||||
|
||||
export class ErrorBoundary extends Component<
|
||||
Record<string, unknown>,
|
||||
ErrorBoundaryState
|
||||
> {
|
||||
constructor(props: { children: any }) {
|
||||
super(props);
|
||||
this.state = {
|
||||
error: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidCatch(error: any, errorInfo: any) {
|
||||
console.error("Render error caught", error, errorInfo);
|
||||
this.setState((s) => ({
|
||||
...s,
|
||||
error: {
|
||||
error,
|
||||
errorInfo,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.error) return this.props.children as any;
|
||||
|
||||
return (
|
||||
<ErrorPart
|
||||
error={this.state.error.error}
|
||||
errorInfo={this.state.error.errorInfo}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,23 +1,5 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { IconPatch } from "@/components/buttons/IconPatch";
|
||||
import { Icons } from "@/components/Icon";
|
||||
import { ArrowLink } from "@/components/text/ArrowLink";
|
||||
import { Title } from "@/components/text/Title";
|
||||
import { ErrorWrapperPart } from "@/pages/parts/errors/ErrorWrapperPart";
|
||||
import { NotFoundPart } from "@/pages/parts/errors/ErrorWrapperPart";
|
||||
|
||||
export function NotFoundPage() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<ErrorWrapperPart>
|
||||
<IconPatch
|
||||
icon={Icons.EYE_SLASH}
|
||||
className="mb-6 text-xl text-bink-600"
|
||||
/>
|
||||
<Title>{t("notFound.page.title")}</Title>
|
||||
<p className="mb-12 mt-5 max-w-sm">{t("notFound.page.description")}</p>
|
||||
<ArrowLink to="/" linkText={t("notFound.backArrow")} />
|
||||
</ErrorWrapperPart>
|
||||
);
|
||||
return <NotFoundPart />;
|
||||
}
|
||||
|
@ -1,6 +1,16 @@
|
||||
import { FooterView } from "@/components/layout/Footer";
|
||||
import { Navigation } from "@/components/layout/Navigation";
|
||||
|
||||
export function BlurEllipsis() {
|
||||
return (
|
||||
<>
|
||||
{/* Blur elipsis */}
|
||||
<div className="absolute top-0 -right-48 rotate-[32deg] w-[50rem] h-[15rem] rounded-[70rem] bg-background-accentA blur-[100px] pointer-events-none opacity-25" />
|
||||
<div className="absolute top-0 right-48 rotate-[32deg] w-[50rem] h-[15rem] rounded-[70rem] bg-background-accentB blur-[100px] pointer-events-none opacity-25" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function SubPageLayout(props: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div
|
||||
@ -10,10 +20,7 @@ export function SubPageLayout(props: { children: React.ReactNode }) {
|
||||
"linear-gradient(to bottom, var(--tw-gradient-from), var(--tw-gradient-to) 800px)",
|
||||
}}
|
||||
>
|
||||
{/* Blur elipsis */}
|
||||
<div className="absolute top-0 -right-48 rotate-[32deg] w-[50rem] h-[15rem] rounded-[70rem] bg-background-accentA blur-[100px] pointer-events-none opacity-25" />
|
||||
<div className="absolute top-0 right-48 rotate-[32deg] w-[50rem] h-[15rem] rounded-[70rem] bg-background-accentB blur-[100px] pointer-events-none opacity-25" />
|
||||
|
||||
<BlurEllipsis />
|
||||
{/* Main page */}
|
||||
<FooterView>
|
||||
<Navigation noLightbar />
|
||||
|
33
src/pages/parts/errors/ErrorPart.tsx
Normal file
33
src/pages/parts/errors/ErrorPart.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import { ButtonPlain } from "@/components/Button";
|
||||
import { Icons } from "@/components/Icon";
|
||||
import { IconPill } from "@/components/layout/IconPill";
|
||||
import { Title } from "@/components/text/Title";
|
||||
import { Paragraph } from "@/components/utils/Text";
|
||||
import { ErrorContainer, ErrorLayout } from "@/pages/layouts/ErrorLayout";
|
||||
|
||||
export function ErrorPart(props: { error: any; errorInfo: any }) {
|
||||
const data = JSON.stringify({
|
||||
error: props.error,
|
||||
errorInfo: props.errorInfo,
|
||||
});
|
||||
return (
|
||||
<div className="relative flex flex-1 flex-col">
|
||||
<div className="flex h-full flex-1 flex-col items-center justify-center p-5 text-center">
|
||||
<ErrorLayout>
|
||||
<ErrorContainer>
|
||||
<IconPill icon={Icons.EYE_SLASH}>It broke</IconPill>
|
||||
<Title>Failed to load meta data</Title>
|
||||
<Paragraph>{data}</Paragraph>
|
||||
<ButtonPlain
|
||||
theme="purple"
|
||||
className="mt-6 md:px-12 p-2.5"
|
||||
onClick={() => window.location.reload()}
|
||||
>
|
||||
Reload the page
|
||||
</ButtonPlain>
|
||||
</ErrorContainer>
|
||||
</ErrorLayout>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,10 +1,15 @@
|
||||
import { ReactNode } from "react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { Button } from "@/components/Button";
|
||||
import { Icons } from "@/components/Icon";
|
||||
import { IconPill } from "@/components/layout/IconPill";
|
||||
import { Navigation } from "@/components/layout/Navigation";
|
||||
import { Title } from "@/components/text/Title";
|
||||
import { Paragraph } from "@/components/utils/Text";
|
||||
import { ErrorContainer, ErrorLayout } from "@/pages/layouts/ErrorLayout";
|
||||
|
||||
export function ErrorWrapperPart(props: { children?: ReactNode }) {
|
||||
export function NotFoundPart() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
@ -14,7 +19,28 @@ export function ErrorWrapperPart(props: { children?: ReactNode }) {
|
||||
</Helmet>
|
||||
<Navigation />
|
||||
<div className="flex h-full flex-1 flex-col items-center justify-center p-5 text-center">
|
||||
{props.children}
|
||||
<ErrorLayout>
|
||||
<ErrorContainer>
|
||||
<IconPill icon={Icons.EYE_SLASH}>
|
||||
{t("notFound.genericTitle")}
|
||||
</IconPill>
|
||||
<Title>Failed to load meta data</Title>
|
||||
<Paragraph>
|
||||
Oh, my apowogies, sweetie! The itty-bitty movie-web did its utmost
|
||||
bestest, but alas, no wucky videos to be spotted anywhere (´⊙ω⊙`)
|
||||
Please don't be angwy, wittle movie-web ish twying so hard.
|
||||
Can you find it in your heart to forgive? UwU 💖
|
||||
</Paragraph>
|
||||
<Button
|
||||
href="/"
|
||||
theme="purple"
|
||||
padding="md:px-12 p-2.5"
|
||||
className="mt-6"
|
||||
>
|
||||
Go home
|
||||
</Button>
|
||||
</ErrorContainer>
|
||||
</ErrorLayout>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
26
src/pages/parts/migrations/MigrationPart.tsx
Normal file
26
src/pages/parts/migrations/MigrationPart.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import { BrandPill } from "@/components/layout/BrandPill";
|
||||
import { Loading } from "@/components/layout/Loading";
|
||||
import { BlurEllipsis } from "@/pages/layouts/SubPageLayout";
|
||||
|
||||
export function MigrationPart() {
|
||||
return (
|
||||
<div className="flex flex-col justify-center items-center h-screen text-center font-medium">
|
||||
{/* Overlaid elements */}
|
||||
<BlurEllipsis />
|
||||
<div className="right-[calc(2rem+env(safe-area-inset-right))] top-6 absolute">
|
||||
<BrandPill />
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<Loading />
|
||||
<p className="max-w-[19rem] mt-3 mb-12 text-type-secondary">
|
||||
Please hold, we are migrating your data. This shouldn't take long.
|
||||
Also, fuck you.
|
||||
</p>
|
||||
<div className="w-[8rem] h-1 rounded-full bg-progress-background bg-opacity-25 mb-2">
|
||||
<div className="w-1/4 h-full bg-progress-filled rounded-full" />
|
||||
</div>
|
||||
<p>25%</p>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -26,23 +26,23 @@ module.exports = {
|
||||
"ash-400": "#3D394D",
|
||||
"ash-300": "#2C293A",
|
||||
"ash-200": "#2B2836",
|
||||
"ash-100": "#1E1C26",
|
||||
"ash-100": "#1E1C26"
|
||||
},
|
||||
|
||||
/* fonts */
|
||||
fontFamily: {
|
||||
"open-sans": "'Open Sans'",
|
||||
"open-sans": "'Open Sans'"
|
||||
},
|
||||
|
||||
/* animations */
|
||||
keyframes: {
|
||||
"loading-pin": {
|
||||
"0%, 40%, 100%": { height: "0.5em", "background-color": "#282336" },
|
||||
"20%": { height: "1em", "background-color": "white" },
|
||||
},
|
||||
"20%": { height: "1em", "background-color": "white" }
|
||||
}
|
||||
},
|
||||
animation: { "loading-pin": "loading-pin 1.8s ease-in-out infinite" },
|
||||
},
|
||||
animation: { "loading-pin": "loading-pin 1.8s ease-in-out infinite" }
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
require("tailwind-scrollbar"),
|
||||
@ -52,31 +52,31 @@ module.exports = {
|
||||
colors: {
|
||||
// Branding
|
||||
pill: {
|
||||
background: "#1C1C36",
|
||||
background: "#1C1C36"
|
||||
},
|
||||
|
||||
// meta data for the theme itself
|
||||
global: {
|
||||
accentA: "#505DBD",
|
||||
accentB: "#3440A1",
|
||||
accentB: "#3440A1"
|
||||
},
|
||||
|
||||
// light bar
|
||||
lightBar: {
|
||||
light: "#2A2A71",
|
||||
light: "#2A2A71"
|
||||
},
|
||||
|
||||
// Buttons
|
||||
buttons: {
|
||||
toggle: "#8D44D6",
|
||||
toggleDisabled: "#202836",
|
||||
toggleDisabled: "#202836"
|
||||
},
|
||||
|
||||
// only used for body colors/textures
|
||||
background: {
|
||||
main: "#0A0A10",
|
||||
accentA: "#6E3B80",
|
||||
accentB: "#1F1F50",
|
||||
accentB: "#1F1F50"
|
||||
},
|
||||
|
||||
// typography
|
||||
@ -85,7 +85,7 @@ module.exports = {
|
||||
text: "#73739D",
|
||||
dimmed: "#926CAD",
|
||||
divider: "#262632",
|
||||
secondary: "#64647B",
|
||||
secondary: "#64647B"
|
||||
},
|
||||
|
||||
// search bar
|
||||
@ -94,7 +94,7 @@ module.exports = {
|
||||
focused: "#24243C",
|
||||
placeholder: "#4A4A71",
|
||||
icon: "#545476",
|
||||
text: "#FFFFFF",
|
||||
text: "#FFFFFF"
|
||||
},
|
||||
|
||||
// media cards
|
||||
@ -106,7 +106,7 @@ module.exports = {
|
||||
barColor: "#4B4B63",
|
||||
barFillColor: "#BA7FD6",
|
||||
badge: "#151522",
|
||||
badgeText: "#5F5F7A",
|
||||
badgeText: "#5F5F7A"
|
||||
},
|
||||
|
||||
// Error page
|
||||
@ -115,14 +115,20 @@ module.exports = {
|
||||
border: "#252534",
|
||||
|
||||
type: {
|
||||
secondary: "#62627D",
|
||||
},
|
||||
secondary: "#62627D"
|
||||
}
|
||||
},
|
||||
|
||||
// About page
|
||||
about: {
|
||||
circle: "#262632",
|
||||
circleText: "#9A9AC3",
|
||||
circleText: "#9A9AC3"
|
||||
},
|
||||
|
||||
progress: {
|
||||
background: "#8787A8",
|
||||
preloaded: "#8787A8",
|
||||
filled: "#A75FC9"
|
||||
},
|
||||
|
||||
// video player
|
||||
@ -134,17 +140,11 @@ module.exports = {
|
||||
error: "#E44F4F",
|
||||
success: "#40B44B",
|
||||
loading: "#B759D8",
|
||||
noresult: "#64647B",
|
||||
},
|
||||
|
||||
progress: {
|
||||
background: "#8787A8",
|
||||
preloaded: "#8787A8",
|
||||
watched: "#A75FC9",
|
||||
noresult: "#64647B"
|
||||
},
|
||||
|
||||
audio: {
|
||||
set: "#A75FC9",
|
||||
set: "#A75FC9"
|
||||
},
|
||||
|
||||
buttons: {
|
||||
@ -157,7 +157,7 @@ module.exports = {
|
||||
purple: "#6b298a",
|
||||
purpleHover: "#7f35a1",
|
||||
cancel: "#252533",
|
||||
cancelHover: "#3C3C4A",
|
||||
cancelHover: "#3C3C4A"
|
||||
},
|
||||
|
||||
context: {
|
||||
@ -177,19 +177,19 @@ module.exports = {
|
||||
|
||||
buttons: {
|
||||
list: "#161C26",
|
||||
active: "#0D1317",
|
||||
active: "#0D1317"
|
||||
},
|
||||
|
||||
type: {
|
||||
main: "#617A8A",
|
||||
secondary: "#374A56",
|
||||
accent: "#A570FA",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
accent: "#A570FA"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user