mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-24 18:21:53 +01:00
correct languages + settings page styling
Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>
This commit is contained in:
parent
1cbf9f3c45
commit
9ff603f87c
@ -8,6 +8,7 @@
|
||||
"@headlessui/react": "^1.5.0",
|
||||
"@movie-web/providers": "^1.0.2",
|
||||
"@react-spring/web": "^9.7.1",
|
||||
"@sozialhelden/ietf-language-tags": "^5.4.2",
|
||||
"classnames": "^2.3.2",
|
||||
"core-js": "^3.29.1",
|
||||
"dompurify": "^3.0.1",
|
||||
|
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
@ -17,6 +17,9 @@ dependencies:
|
||||
'@react-spring/web':
|
||||
specifier: ^9.7.1
|
||||
version: 9.7.3(react-dom@17.0.2)(react@17.0.2)
|
||||
'@sozialhelden/ietf-language-tags':
|
||||
specifier: ^5.4.2
|
||||
version: 5.4.2
|
||||
classnames:
|
||||
specifier: ^2.3.2
|
||||
version: 2.3.2
|
||||
@ -1956,6 +1959,13 @@ packages:
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@sozialhelden/ietf-language-tags@5.4.2:
|
||||
resolution: {integrity: sha512-aCN7bVOfX9sBN0EHyWJT14H8bx+VYBo8tdcynai35wgoxKMfVtgEECkQ1gs8nEL6GHGes8lPIfo6AjIch44N3w==}
|
||||
dependencies:
|
||||
lodash.compact: 3.0.1
|
||||
typescript: 4.9.5
|
||||
dev: false
|
||||
|
||||
/@surma/rollup-plugin-off-main-thread@2.2.3:
|
||||
resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
|
||||
dependencies:
|
||||
@ -4456,6 +4466,10 @@ packages:
|
||||
p-locate: 5.0.0
|
||||
dev: true
|
||||
|
||||
/lodash.compact@3.0.1:
|
||||
resolution: {integrity: sha512-2ozeiPi+5eBXW1CLtzjk8XQFhQOEMwwfxblqeq6EGyTxZJ1bPATqilY0e6g2SLQpP4KuMeuioBhEnWz5Pr7ICQ==}
|
||||
dev: false
|
||||
|
||||
/lodash.debounce@4.0.8:
|
||||
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
||||
dev: true
|
||||
@ -5986,7 +6000,6 @@ packages:
|
||||
resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==}
|
||||
engines: {node: '>=4.2.0'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/ufo@1.3.0:
|
||||
resolution: {integrity: sha512-bRn3CsoojyNStCZe0BG0Mt4Nr/4KF+rhFlnNXybgqt5pXHNFRlqinSoQaTrGyzE4X8aHplSb+TorH+COin9Yxw==}
|
||||
|
@ -95,10 +95,6 @@ export async function searchSubtitles(
|
||||
});
|
||||
}
|
||||
|
||||
export function languageIdToName(langId: string): string | null {
|
||||
return languageMap[langId]?.nativeName ?? null;
|
||||
}
|
||||
|
||||
export async function downloadSrt(legacySubId: string): Promise<string> {
|
||||
// TODO there is cloudflare protection so this may not always work. what to do about that?
|
||||
// TODO also there is ratelimit on the page itself
|
||||
|
@ -8,7 +8,7 @@ interface Props {
|
||||
icon?: Icons;
|
||||
onClick?: () => void;
|
||||
children?: ReactNode;
|
||||
theme?: "white" | "purple" | "secondary";
|
||||
theme?: "white" | "purple" | "secondary" | "danger";
|
||||
padding?: string;
|
||||
className?: string;
|
||||
href?: string;
|
||||
@ -26,6 +26,8 @@ export function Button(props: Props) {
|
||||
if (props.theme === "secondary")
|
||||
colorClasses =
|
||||
"bg-video-buttons-cancel hover:bg-video-buttons-cancelHover transition-colors duration-100 text-white";
|
||||
if (props.theme === "danger")
|
||||
colorClasses = "bg-buttons-danger hover:bg-buttons-dangerHover text-white";
|
||||
|
||||
let 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",
|
||||
|
@ -1,9 +1,11 @@
|
||||
import classNames from "classnames";
|
||||
import { ReactNode } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import { IconPatch } from "@/components/buttons/IconPatch";
|
||||
import { Icons } from "@/components/Icon";
|
||||
import { Lightbar } from "@/components/utils/Lightbar";
|
||||
import { BlurEllipsis } from "@/pages/layouts/SubPageLayout";
|
||||
import { conf } from "@/setup/config";
|
||||
import { useBannerSize } from "@/stores/banner";
|
||||
|
||||
@ -13,10 +15,12 @@ export interface NavigationProps {
|
||||
children?: ReactNode;
|
||||
bg?: boolean;
|
||||
noLightbar?: boolean;
|
||||
doBackground?: boolean;
|
||||
}
|
||||
|
||||
export function Navigation(props: NavigationProps) {
|
||||
const bannerHeight = useBannerSize();
|
||||
|
||||
return (
|
||||
<>
|
||||
{!props.noLightbar ? (
|
||||
@ -37,7 +41,17 @@ export function Navigation(props: NavigationProps) {
|
||||
top: `${bannerHeight}px`,
|
||||
}}
|
||||
>
|
||||
<div className="fixed left-0 right-0 flex items-center">
|
||||
<div
|
||||
className={classNames(
|
||||
"fixed left-0 right-0 flex items-center",
|
||||
props.doBackground
|
||||
? "bg-background-main border-b border-utils-divider border-opacity-50 overflow-hidden"
|
||||
: null
|
||||
)}
|
||||
>
|
||||
{props.doBackground ? (
|
||||
<BlurEllipsis positionClass="absolute" />
|
||||
) : null}
|
||||
<div
|
||||
className={`${
|
||||
props.bg ? "opacity-100" : "opacity-0"
|
||||
|
@ -3,16 +3,13 @@ import { ReactNode, useRef, useState } from "react";
|
||||
import { useAsync, useAsyncFn } from "react-use";
|
||||
import { convert } from "subsrt-ts";
|
||||
|
||||
import {
|
||||
SubtitleSearchItem,
|
||||
languageIdToName,
|
||||
subtitleTypeList,
|
||||
} from "@/backend/helpers/subs";
|
||||
import { SubtitleSearchItem, subtitleTypeList } from "@/backend/helpers/subs";
|
||||
import { FlagIcon } from "@/components/FlagIcon";
|
||||
import { useCaptions } from "@/components/player/hooks/useCaptions";
|
||||
import { Menu } from "@/components/player/internals/ContextMenu";
|
||||
import { Input } from "@/components/player/internals/ContextMenu/Input";
|
||||
import { SelectableLink } from "@/components/player/internals/ContextMenu/Links";
|
||||
import { getLanguageFromIETF } from "@/components/player/utils/language";
|
||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import { useSubtitleStore } from "@/stores/subtitles";
|
||||
@ -35,6 +32,7 @@ export function CaptionOption(props: {
|
||||
he: "il",
|
||||
ze: "cn",
|
||||
ar: "sa",
|
||||
ja: "jp",
|
||||
};
|
||||
let countryCode =
|
||||
(props.countryCode || "")?.split("-").pop()?.toLowerCase() || "";
|
||||
@ -155,7 +153,8 @@ export function CaptionsView({ id }: { id: string }) {
|
||||
else if (req.error) content = <p>errored!</p>;
|
||||
else if (req.value) {
|
||||
const subs = req.value.map((v) => {
|
||||
const languageName = languageIdToName(v.attributes.language) ?? "unknown";
|
||||
const languageName =
|
||||
getLanguageFromIETF(v.attributes.language) ?? "unknown";
|
||||
return {
|
||||
...v,
|
||||
languageName,
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { useMemo } from "react";
|
||||
|
||||
import { languageIdToName } from "@/backend/helpers/subs";
|
||||
import { Toggle } from "@/components/buttons/Toggle";
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { useCaptions } from "@/components/player/hooks/useCaptions";
|
||||
import { Menu } from "@/components/player/internals/ContextMenu";
|
||||
import { getLanguageFromIETF } from "@/components/player/utils/language";
|
||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import { qualityToString } from "@/stores/player/utils/qualities";
|
||||
@ -26,7 +26,7 @@ export function SettingsMenu({ id }: { id: string }) {
|
||||
const { toggleLastUsed } = useCaptions();
|
||||
|
||||
const selectedLanguagePretty = selectedCaptionLanguage
|
||||
? languageIdToName(selectedCaptionLanguage) ?? "unknown"
|
||||
? getLanguageFromIETF(selectedCaptionLanguage) ?? "unknown"
|
||||
: undefined;
|
||||
|
||||
const source = usePlayerStore((s) => s.source);
|
||||
|
@ -68,13 +68,14 @@ export function CaptionCue({
|
||||
export function SubtitleRenderer() {
|
||||
const videoTime = usePlayerStore((s) => s.progress.time);
|
||||
const srtData = usePlayerStore((s) => s.caption.selected?.srtData);
|
||||
const language = usePlayerStore((s) => s.caption.selected?.language);
|
||||
const styling = useSubtitleStore((s) => s.styling);
|
||||
const overrideCasing = useSubtitleStore((s) => s.overrideCasing);
|
||||
const delay = useSubtitleStore((s) => s.delay);
|
||||
|
||||
const parsedCaptions = useMemo(
|
||||
() => (srtData ? parseSubtitles(srtData) : []),
|
||||
[srtData]
|
||||
() => (srtData ? parseSubtitles(srtData, language) : []),
|
||||
[srtData, language]
|
||||
);
|
||||
|
||||
const visibileCaptions = useMemo(
|
||||
|
@ -47,7 +47,10 @@ export function convertSubtitlesToSrt(text: string): string {
|
||||
return srt;
|
||||
}
|
||||
|
||||
export function parseSubtitles(text: string): CaptionCueType[] {
|
||||
export function parseSubtitles(
|
||||
text: string,
|
||||
_language?: string
|
||||
): CaptionCueType[] {
|
||||
const vtt = convertSubtitlesToVtt(text);
|
||||
return parse(vtt).filter((cue) => cue.type === "caption") as CaptionCueType[];
|
||||
}
|
||||
|
14
src/components/player/utils/language.ts
Normal file
14
src/components/player/utils/language.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { getTag } from "@sozialhelden/ietf-language-tags";
|
||||
|
||||
export function getLanguageFromIETF(ietf: string): string | null {
|
||||
const tag = getTag(ietf, true);
|
||||
|
||||
const lang = tag?.language?.Description?.[0] ?? null;
|
||||
if (!lang) return null;
|
||||
|
||||
const region = tag?.region?.Description?.[0] ?? null;
|
||||
let regionText = "";
|
||||
if (region) regionText = ` (${region})`;
|
||||
|
||||
return `${lang}${regionText}`;
|
||||
}
|
@ -75,4 +75,4 @@
|
||||
100% {
|
||||
transform: rotate(180deg) translateZ(0px) translateY(400px) scaleX(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import classNames from "classnames";
|
||||
import { useEffect, useRef } from "react";
|
||||
import "./Lightbar.css";
|
||||
|
||||
@ -161,7 +162,12 @@ function ParticlesCanvas() {
|
||||
|
||||
export function Lightbar(props: { className?: string }) {
|
||||
return (
|
||||
<div className={props.className}>
|
||||
<div
|
||||
className={classNames(
|
||||
"grid grid-cols-[100%] w-full overflow-x-hidden",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
<div className="lightbar">
|
||||
<ParticlesCanvas />
|
||||
<div className="lightbar-visual" />
|
||||
|
@ -1,13 +1,17 @@
|
||||
interface TextProps {
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
border?: boolean;
|
||||
}
|
||||
|
||||
const borderClass = "pb-4 border-b border-utils-divider border-opacity-50";
|
||||
|
||||
export function Heading1(props: TextProps) {
|
||||
return (
|
||||
<h1
|
||||
className={[
|
||||
"text-5xl font-bold text-white mb-9",
|
||||
props.border ? borderClass : null,
|
||||
props.className ?? "",
|
||||
].join(" ")}
|
||||
>
|
||||
@ -21,6 +25,21 @@ export function Heading2(props: TextProps) {
|
||||
<h2
|
||||
className={[
|
||||
"text-3xl font-bold text-white mt-20 mb-9",
|
||||
props.border ? borderClass : null,
|
||||
props.className ?? "",
|
||||
].join(" ")}
|
||||
>
|
||||
{props.children}
|
||||
</h2>
|
||||
);
|
||||
}
|
||||
|
||||
export function Heading3(props: TextProps) {
|
||||
return (
|
||||
<h2
|
||||
className={[
|
||||
"text-xl font-bold text-white mb-3",
|
||||
props.border ? borderClass : null,
|
||||
props.className ?? "",
|
||||
].join(" ")}
|
||||
>
|
||||
@ -34,6 +53,7 @@ export function Paragraph(props: TextProps) {
|
||||
<p
|
||||
className={[
|
||||
"text-type-text my-9 font-medium",
|
||||
props.border ? borderClass : null,
|
||||
props.className ?? "",
|
||||
].join(" ")}
|
||||
>
|
||||
|
@ -1,7 +1,12 @@
|
||||
import classNames from "classnames";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import Sticky from "react-stickynode";
|
||||
|
||||
import { Button } from "@/components/Button";
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { WideContainer } from "@/components/layout/WideContainer";
|
||||
import { Divider } from "@/components/utils/Divider";
|
||||
import { Heading1 } from "@/components/utils/Text";
|
||||
import { Heading1, Heading2, Heading3 } from "@/components/utils/Text";
|
||||
import { conf } from "@/setup/config";
|
||||
|
||||
import { SubPageLayout } from "./layouts/SubPageLayout";
|
||||
@ -19,27 +24,59 @@ function SidebarSection(props: { title: string; children: React.ReactNode }) {
|
||||
);
|
||||
}
|
||||
|
||||
function SidebarLink(props: { children: React.ReactNode; icon: Icons }) {
|
||||
function SidebarLink(props: {
|
||||
children: React.ReactNode;
|
||||
icon: Icons;
|
||||
active?: boolean;
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
const goToPage = (link: string) => {
|
||||
history.push(link);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full px-2 py-1 flex items-center space-x-3">
|
||||
<a
|
||||
onClick={() => goToPage("/settings")}
|
||||
className={classNames(
|
||||
"w-full px-3 py-2 flex items-center space-x-3 cursor-pointer rounded my-2",
|
||||
props.active
|
||||
? "bg-settings-sidebar-activeLink text-settings-sidebar-type-activated"
|
||||
: null
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
className="text-2xl text-settings-sidebar-type-icon"
|
||||
className={classNames(
|
||||
"text-2xl text-settings-sidebar-type-icon",
|
||||
props.active ? "text-settings-sidebar-type-iconActivated" : null
|
||||
)}
|
||||
icon={props.icon}
|
||||
/>
|
||||
<span>{props.children}</span>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
function SettingsSidebar() {
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
const hostname = location.hostname;
|
||||
const rem = 16;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="sticky top-24 text-settings-sidebar-type-inactive">
|
||||
<Sticky
|
||||
enabled
|
||||
top={10 * rem} // 10rem
|
||||
className="text-settings-sidebar-type-inactive"
|
||||
>
|
||||
<SidebarSection title="Settings">
|
||||
<SidebarLink icon={Icons.WAND}>Account</SidebarLink>
|
||||
{/* I looked over at my bookshelf to come up with these links */}
|
||||
<SidebarLink icon={Icons.WAND}>A war in my name!</SidebarLink>
|
||||
<SidebarLink active icon={Icons.COMPRESS}>
|
||||
TANSTAAFL
|
||||
</SidebarLink>
|
||||
<SidebarLink icon={Icons.AIRPLAY}>We all float down here</SidebarLink>
|
||||
<SidebarLink icon={Icons.BOOKMARK}>My skin is not my own</SidebarLink>
|
||||
</SidebarSection>
|
||||
<Divider />
|
||||
<SidebarSection title="App information">
|
||||
@ -52,7 +89,7 @@ function SettingsSidebar() {
|
||||
<span className="text-right">{hostname}</span>
|
||||
</div>
|
||||
</SidebarSection>
|
||||
</div>
|
||||
</Sticky>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -62,17 +99,118 @@ function SettingsLayout(props: { children: React.ReactNode }) {
|
||||
<WideContainer ultraWide>
|
||||
<div className="grid grid-cols-[260px,1fr] gap-12">
|
||||
<SettingsSidebar />
|
||||
{props.children}
|
||||
<div className="space-y-16">{props.children}</div>
|
||||
</div>
|
||||
</WideContainer>
|
||||
);
|
||||
}
|
||||
|
||||
function SecondaryLabel(props: { children: React.ReactNode }) {
|
||||
return <p className="text-type-text">{props.children}</p>;
|
||||
}
|
||||
|
||||
function Card(props: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
paddingClass?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"w-full rounded-lg bg-settings-card-background bg-opacity-[0.15] border border-settings-card-border",
|
||||
props.paddingClass ?? "px-8 py-6",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function AltCard(props: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
paddingClass?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"w-full rounded-lg bg-settings-card-altBackground bg-opacity-50",
|
||||
props.paddingClass ?? "px-8 py-6",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function AccountSection() {
|
||||
return (
|
||||
<div>
|
||||
<Heading1 border>Account</Heading1>
|
||||
<Card>Beep beep</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DevicesSection() {
|
||||
const devices = [
|
||||
"Jip's iPhone",
|
||||
"Muad'Dib's Nintendo Switch",
|
||||
"Oppenheimer's old-ass phone",
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<Heading2 border className="mt-0 mb-9">
|
||||
Devices
|
||||
</Heading2>
|
||||
<div className="space-y-5">
|
||||
{devices.map((deviceName) => (
|
||||
<Card
|
||||
className="flex justify-between items-center"
|
||||
paddingClass="px-6 py-4"
|
||||
key={deviceName}
|
||||
>
|
||||
<div className="font-medium">
|
||||
<SecondaryLabel>Device name</SecondaryLabel>
|
||||
<p className="text-white">{deviceName}</p>
|
||||
</div>
|
||||
<Button theme="danger">Remove</Button>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ActionsSection() {
|
||||
return (
|
||||
<div>
|
||||
<Heading2 border>Actions</Heading2>
|
||||
<AltCard paddingClass="px-6 py-12" className="grid grid-cols-2 gap-12">
|
||||
<div>
|
||||
<Heading3>Delete account</Heading3>
|
||||
<p className="text-type-text">
|
||||
This action is irreversible. All data will be deleted and nothing
|
||||
can be recovered.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-end items-center">
|
||||
<Button theme="danger">Delete account</Button>
|
||||
</div>
|
||||
</AltCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function SettingsPage() {
|
||||
return (
|
||||
<SubPageLayout>
|
||||
<SettingsLayout>
|
||||
<Heading1>Setting</Heading1>
|
||||
<AccountSection />
|
||||
<DevicesSection />
|
||||
<ActionsSection />
|
||||
</SettingsLayout>
|
||||
</SubPageLayout>
|
||||
);
|
||||
|
@ -1,12 +1,24 @@
|
||||
import classNames from "classnames";
|
||||
|
||||
import { FooterView } from "@/components/layout/Footer";
|
||||
import { Navigation } from "@/components/layout/Navigation";
|
||||
|
||||
export function BlurEllipsis() {
|
||||
export function BlurEllipsis(props: { positionClass?: string }) {
|
||||
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" />
|
||||
<div
|
||||
className={classNames(
|
||||
props.positionClass ?? "fixed",
|
||||
"top-0 -right-48 rotate-[32deg] w-[50rem] h-[15rem] rounded-[70rem] bg-background-accentA blur-[100px] pointer-events-none opacity-25"
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
className={classNames(
|
||||
props.positionClass ?? "fixed",
|
||||
"top-0 right-48 rotate-[32deg] w-[50rem] h-[15rem] rounded-[70rem] bg-background-accentB blur-[100px] pointer-events-none opacity-25"
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -23,7 +35,7 @@ export function SubPageLayout(props: { children: React.ReactNode }) {
|
||||
<BlurEllipsis />
|
||||
{/* Main page */}
|
||||
<FooterView>
|
||||
<Navigation noLightbar />
|
||||
<Navigation doBackground noLightbar />
|
||||
<div className="mt-40">{props.children}</div>
|
||||
</FooterView>
|
||||
</div>
|
||||
|
@ -69,7 +69,9 @@ module.exports = {
|
||||
// Buttons
|
||||
buttons: {
|
||||
toggle: "#8D44D6",
|
||||
toggleDisabled: "#202836"
|
||||
toggleDisabled: "#202836",
|
||||
danger: "#792131",
|
||||
dangerHover: "#8a293b"
|
||||
},
|
||||
|
||||
// only used for body colors/textures
|
||||
@ -111,12 +113,21 @@ module.exports = {
|
||||
|
||||
settings: {
|
||||
sidebar: {
|
||||
activeLink: "#171728",
|
||||
|
||||
type: {
|
||||
secondary: "#4B395F",
|
||||
inactive: "#8D68A9",
|
||||
icon: "#926CAD",
|
||||
iconActivated: "#6942A8",
|
||||
activated: "#CBA1E8"
|
||||
}
|
||||
},
|
||||
|
||||
card: {
|
||||
border: "#2A243E",
|
||||
background: "#29243D",
|
||||
altBackground: "#29243D"
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -17,7 +17,10 @@
|
||||
"jsx": "react-jsx",
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
"@/*": ["./*"],
|
||||
"@sozialhelden/ietf-language-tags": [
|
||||
"../node_modules/@sozialhelden/ietf-language-tags/dist/cjs"
|
||||
]
|
||||
},
|
||||
"types": ["vite/client", "vite-plugin-pwa/vanillajs"]
|
||||
},
|
||||
|
@ -14,10 +14,12 @@ export default defineConfig(({ mode }) => {
|
||||
handlebars({
|
||||
vars: {
|
||||
opensearchEnabled: env.VITE_OPENSEARCH_ENABLED === "true",
|
||||
routeDomain: env.VITE_APP_DOMAIN + (env.VITE_NORMAL_ROUTER !== 'true' ? "/#" : ""),
|
||||
routeDomain:
|
||||
env.VITE_APP_DOMAIN +
|
||||
(env.VITE_NORMAL_ROUTER !== "true" ? "/#" : ""),
|
||||
domain: env.VITE_APP_DOMAIN,
|
||||
env,
|
||||
},
|
||||
env
|
||||
}
|
||||
}),
|
||||
react({
|
||||
babel: {
|
||||
@ -29,23 +31,23 @@ export default defineConfig(({ mode }) => {
|
||||
modules: false,
|
||||
useBuiltIns: "entry",
|
||||
corejs: {
|
||||
version: "3.29",
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
version: "3.29"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}),
|
||||
VitePWA({
|
||||
disable: process.env.VITE_PWA_ENABLED !== "yes",
|
||||
registerType: "autoUpdate",
|
||||
workbox: {
|
||||
globIgnores: ["**ping.txt**"],
|
||||
globIgnores: ["**ping.txt**"]
|
||||
},
|
||||
includeAssets: [
|
||||
"favicon.ico",
|
||||
"apple-touch-icon.png",
|
||||
"safari-pinned-tab.svg",
|
||||
"safari-pinned-tab.svg"
|
||||
],
|
||||
manifest: {
|
||||
name: "movie-web",
|
||||
@ -61,53 +63,57 @@ export default defineConfig(({ mode }) => {
|
||||
src: "android-chrome-192x192.png",
|
||||
sizes: "192x192",
|
||||
type: "image/png",
|
||||
purpose: "any",
|
||||
purpose: "any"
|
||||
},
|
||||
{
|
||||
src: "android-chrome-512x512.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png",
|
||||
purpose: "any",
|
||||
purpose: "any"
|
||||
},
|
||||
{
|
||||
src: "android-chrome-192x192.png",
|
||||
sizes: "192x192",
|
||||
type: "image/png",
|
||||
purpose: "maskable",
|
||||
purpose: "maskable"
|
||||
},
|
||||
{
|
||||
src: "android-chrome-512x512.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png",
|
||||
purpose: "maskable",
|
||||
},
|
||||
],
|
||||
},
|
||||
purpose: "maskable"
|
||||
}
|
||||
]
|
||||
}
|
||||
}),
|
||||
loadVersion(),
|
||||
checker({
|
||||
overlay: {
|
||||
position: "tr",
|
||||
position: "tr"
|
||||
},
|
||||
typescript: true, // check typescript build errors in dev server
|
||||
eslint: {
|
||||
// check lint errors in dev server
|
||||
lintCommand: "eslint --ext .tsx,.ts src",
|
||||
dev: {
|
||||
logLevel: ["error"],
|
||||
},
|
||||
},
|
||||
}),
|
||||
logLevel: ["error"]
|
||||
}
|
||||
}
|
||||
})
|
||||
],
|
||||
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
"@sozialhelden/ietf-language-tags": path.resolve(
|
||||
__dirname,
|
||||
"./node_modules/@sozialhelden/ietf-language-tags/dist/cjs"
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
test: {
|
||||
environment: "jsdom",
|
||||
},
|
||||
environment: "jsdom"
|
||||
}
|
||||
};
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user