mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-29 16:07:40 +01:00
added flares, themes and footer
Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>
This commit is contained in:
parent
e93644b688
commit
eb57f1958f
10 changed files with 256 additions and 10 deletions
|
@ -10,6 +10,7 @@
|
|||
"@sentry/integrations": "^7.49.0",
|
||||
"@sentry/react": "^7.49.0",
|
||||
"@use-gesture/react": "^10.2.24",
|
||||
"classnames": "^2.3.2",
|
||||
"core-js": "^3.29.1",
|
||||
"crypto-js": "^4.1.1",
|
||||
"dompurify": "^3.0.1",
|
||||
|
@ -95,6 +96,7 @@
|
|||
"prettier-plugin-tailwindcss": "^0.1.7",
|
||||
"tailwind-scrollbar": "^2.0.1",
|
||||
"tailwindcss": "^3.2.4",
|
||||
"tailwindcss-themer": "^3.1.0",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^4.0.1",
|
||||
"vite-plugin-checker": "^0.5.6",
|
||||
|
|
78
src/components/layout/Footer.tsx
Normal file
78
src/components/layout/Footer.tsx
Normal file
|
@ -0,0 +1,78 @@
|
|||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { BrandPill } from "@/components/layout/BrandPill";
|
||||
import { WideContainer } from "@/components/layout/WideContainer";
|
||||
|
||||
function FooterLink(props: {
|
||||
href: string;
|
||||
children: React.ReactNode;
|
||||
icon: Icons;
|
||||
}) {
|
||||
return (
|
||||
<a
|
||||
href={props.href}
|
||||
target="_blank"
|
||||
className="inline-flex items-center space-x-3 transition-colors duration-200 hover:text-type-emphasis"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Icon icon={props.icon} className="text-2xl" />
|
||||
<span className="font-medium">{props.children}</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
export function Footer() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<footer className="mt-16 border-t border-type-divider py-16 md:py-8">
|
||||
<WideContainer ultraWide classNames="grid md:grid-cols-2 gap-16 md:gap-8">
|
||||
<div>
|
||||
<div className="inline-block">
|
||||
<BrandPill />
|
||||
</div>
|
||||
<p className="mt-4 lg:max-w-[400px]">{t("footer.tagline")}</p>
|
||||
<div className="mt-8 space-x-[2rem]">
|
||||
<FooterLink icon={Icons.GITHUB} href="https://github.com/movie-web">
|
||||
{t("footer.links.github")}
|
||||
</FooterLink>
|
||||
<FooterLink
|
||||
icon={Icons.DISCORD}
|
||||
href="https://github.com/movie-web"
|
||||
>
|
||||
{t("footer.links.github")}
|
||||
</FooterLink>
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:text-right">
|
||||
<h3 className="font-semibold text-type-emphasis">
|
||||
{t("footer.legal.disclaimer")}
|
||||
</h3>
|
||||
<p className="mt-3">{t("footer.legal.disclaimerText")}</p>
|
||||
<div className="mt-8">
|
||||
<FooterLink icon={Icons.DRAGON} href="https://youtu.be/-WOonkg_ZCo">
|
||||
{t("footer.links.dmca")}
|
||||
</FooterLink>
|
||||
</div>
|
||||
</div>
|
||||
</WideContainer>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
|
||||
export function FooterView(props: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={["flex min-h-screen flex-col", props.className || ""].join(
|
||||
" "
|
||||
)}
|
||||
>
|
||||
<div style={{ flex: "1 0 auto" }}>{props.children}</div>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -3,14 +3,15 @@ import { ReactNode } from "react";
|
|||
interface WideContainerProps {
|
||||
classNames?: string;
|
||||
children?: ReactNode;
|
||||
ultraWide?: boolean;
|
||||
}
|
||||
|
||||
export function WideContainer(props: WideContainerProps) {
|
||||
return (
|
||||
<div
|
||||
className={`mx-auto w-[700px] max-w-full px-8 sm:px-4 ${
|
||||
props.classNames || ""
|
||||
}`}
|
||||
className={`mx-auto max-w-full px-8 ${
|
||||
props.ultraWide ? "w-[1300px] sm:px-16" : "w-[900px] sm:px-8"
|
||||
} ${props.classNames || ""}`}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,10 @@ interface MediaGridProps {
|
|||
export const MediaGrid = forwardRef<HTMLDivElement, MediaGridProps>(
|
||||
(props, ref) => {
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-6 sm:grid-cols-3" ref={ref}>
|
||||
<div
|
||||
className="grid grid-cols-2 gap-6 sm:grid-cols-3 md:grid-cols-4"
|
||||
ref={ref}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
|
|
75
src/components/utils/Flare.tsx
Normal file
75
src/components/utils/Flare.tsx
Normal file
|
@ -0,0 +1,75 @@
|
|||
import c from "classnames";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
export interface FlareProps {
|
||||
className?: string;
|
||||
backgroundClass: string;
|
||||
flareSize?: number;
|
||||
cssColorVar?: string;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
const SIZE_DEFAULT = 200;
|
||||
const CSS_VAR_DEFAULT = "--colors-global-accentA";
|
||||
|
||||
export function Flare(props: FlareProps) {
|
||||
const outerRef = useRef<HTMLDivElement>(null);
|
||||
const size = props.flareSize ?? SIZE_DEFAULT;
|
||||
const cssVar = props.cssColorVar ?? CSS_VAR_DEFAULT;
|
||||
|
||||
useEffect(() => {
|
||||
function mouseMove(e: MouseEvent) {
|
||||
if (!outerRef.current) return;
|
||||
outerRef.current.style.setProperty(
|
||||
"--bg-x",
|
||||
`${(e.clientX - size / 2).toFixed(0)}px`
|
||||
);
|
||||
outerRef.current.style.setProperty(
|
||||
"--bg-y",
|
||||
`${(e.clientY - size / 2).toFixed(0)}px`
|
||||
);
|
||||
}
|
||||
document.addEventListener("mousemove", mouseMove);
|
||||
|
||||
return () => document.removeEventListener("mousemove", mouseMove);
|
||||
}, [size]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={outerRef}
|
||||
className={c(
|
||||
"overflow-hidden, pointer-events-none absolute inset-0 hidden",
|
||||
props.className,
|
||||
{
|
||||
"!block": props.enabled ?? false,
|
||||
}
|
||||
)}
|
||||
style={{
|
||||
backgroundImage: `radial-gradient(circle at center, rgba(var(${cssVar}), 1), rgba(var(${cssVar}), 0) 70%)`,
|
||||
backgroundPosition: `var(--bg-x) var(--bg-y)`,
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundAttachment: "fixed",
|
||||
backgroundSize: "200px 200px",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={c(
|
||||
"absolute inset-[2px] overflow-hidden",
|
||||
props.className,
|
||||
props.backgroundClass
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className="absolute inset-0 opacity-5"
|
||||
style={{
|
||||
background: `radial-gradient(circle at center, rgba(var(${cssVar}), 1), rgba(var(${cssVar}), 0) 70%)`,
|
||||
backgroundPosition: `var(--bg-x) var(--bg-y)`,
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundAttachment: "fixed",
|
||||
backgroundSize: "200px 200px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -131,5 +131,16 @@
|
|||
},
|
||||
"errors": {
|
||||
"offline": "Check your internet connection"
|
||||
},
|
||||
"footer": {
|
||||
"tagline": "Watch your favorite shows and movies with this open source streaming app.",
|
||||
"links": {
|
||||
"github": "GitHub",
|
||||
"dmca": "DMCA"
|
||||
},
|
||||
"legal": {
|
||||
"disclaimer": "Disclaimer",
|
||||
"disclaimerText": "movie-web does not host any files, it merely links to 3rd party services. Legal issues should be taken up with the file hosts and providers. movie-web is not responsible for any media files shown by the video providers."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ function NewDomainModal() {
|
|||
|
||||
export function HomeView() {
|
||||
return (
|
||||
<div className="mb-16">
|
||||
<div>
|
||||
<EmbedMigration />
|
||||
<NewDomainModal />
|
||||
<Bookmarks />
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Helmet } from "react-helmet";
|
|||
import { useTranslation } from "react-i18next";
|
||||
import Sticky from "react-stickynode";
|
||||
|
||||
import { FooterView } from "@/components/layout/Footer";
|
||||
import { Navigation } from "@/components/layout/Navigation";
|
||||
import { ThinContainer } from "@/components/layout/ThinContainer";
|
||||
import { WideContainer } from "@/components/layout/WideContainer";
|
||||
|
@ -25,7 +26,7 @@ export function SearchView() {
|
|||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FooterView>
|
||||
<div className="relative z-10 mb-16 sm:mb-24">
|
||||
<Helmet>
|
||||
<title>{t("global.name")}</title>
|
||||
|
@ -61,6 +62,6 @@ export function SearchView() {
|
|||
<WideContainer>
|
||||
<SearchResultsPartial search={search} />
|
||||
</WideContainer>
|
||||
</>
|
||||
</FooterView>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
const themer = require("tailwindcss-themer");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
||||
|
@ -42,5 +44,30 @@ module.exports = {
|
|||
animation: { "loading-pin": "loading-pin 1.8s ease-in-out infinite" }
|
||||
}
|
||||
},
|
||||
plugins: [require("tailwind-scrollbar")]
|
||||
plugins: [
|
||||
require("tailwind-scrollbar"),
|
||||
themer({
|
||||
defaultTheme: {
|
||||
extend: {
|
||||
colors: {
|
||||
background: {
|
||||
main: "#0A0A10",
|
||||
accentA: "#6E3B80",
|
||||
accentB: "#1F1F50"
|
||||
},
|
||||
global: {
|
||||
accentA: "#505DBD",
|
||||
accentB: "#3440A1"
|
||||
},
|
||||
type: {
|
||||
emphasis: "#FFFFFF",
|
||||
text: "#73739D",
|
||||
dimmed: "#926CAD",
|
||||
divider: "#353549"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
};
|
||||
|
|
52
yarn.lock
52
yarn.lock
|
@ -2147,7 +2147,7 @@ chokidar@^3.5.1, chokidar@^3.5.3:
|
|||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
classnames@^2.0.0:
|
||||
classnames@^2.0.0, classnames@^2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924"
|
||||
integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==
|
||||
|
@ -2184,11 +2184,27 @@ color-name@1.1.3:
|
|||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||
|
||||
color-name@^1.1.4, color-name@~1.1.4:
|
||||
color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
color-string@^1.9.0:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
|
||||
integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
|
||||
dependencies:
|
||||
color-name "^1.0.0"
|
||||
simple-swizzle "^0.2.2"
|
||||
|
||||
color@^4.1.0:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a"
|
||||
integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==
|
||||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
color-string "^1.9.0"
|
||||
|
||||
combined-stream@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
|
@ -3410,6 +3426,11 @@ is-array-buffer@^3.0.1, is-array-buffer@^3.0.2:
|
|||
get-intrinsic "^1.2.0"
|
||||
is-typed-array "^1.1.10"
|
||||
|
||||
is-arrayish@^0.3.1:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
|
||||
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
|
||||
|
||||
is-bigint@^1.0.1:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
|
||||
|
@ -3761,6 +3782,11 @@ jsonpointer@^5.0.0:
|
|||
array-includes "^3.1.5"
|
||||
object.assign "^4.1.3"
|
||||
|
||||
just-unique@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/just-unique/-/just-unique-4.2.0.tgz#80927360b92f5039fad7e7f5f8bc48904d9177b6"
|
||||
integrity sha512-cxQGGUiit6CGUpuuiezY8N4m1wgF4o7127rXEXDFcxeDUFfdV7gSkwA26Fe2wWBiNQq2SZOgN4gSmMxB/StA8Q==
|
||||
|
||||
language-subtag-registry@~0.3.2:
|
||||
version "0.3.22"
|
||||
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d"
|
||||
|
@ -3840,6 +3866,11 @@ lodash.merge@^4.6.2:
|
|||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
||||
|
||||
lodash.mergewith@^4.6.2:
|
||||
version "4.6.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
|
||||
integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
|
||||
|
||||
lodash.pick@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
|
||||
|
@ -4859,6 +4890,13 @@ signal-exit@^4.0.1:
|
|||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.2.tgz#ff55bb1d9ff2114c13b400688fa544ac63c36967"
|
||||
integrity sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==
|
||||
|
||||
simple-swizzle@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
|
||||
integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==
|
||||
dependencies:
|
||||
is-arrayish "^0.3.1"
|
||||
|
||||
slash@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
||||
|
@ -5124,6 +5162,16 @@ tailwind-scrollbar@^2.0.1:
|
|||
resolved "https://registry.yarnpkg.com/tailwind-scrollbar/-/tailwind-scrollbar-2.1.0.tgz#46e0b8788cef75387f9d163a5ec82b8cacd66c44"
|
||||
integrity sha512-zpvY5mDs0130YzYjZKBiDaw32rygxk5RyJ4KmeHjGnwkvbjm/PszON1m4Bbt2DkMRIXlXsfNevykAESgURN4KA==
|
||||
|
||||
tailwindcss-themer@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tailwindcss-themer/-/tailwindcss-themer-3.1.0.tgz#4440d62d7edc54f8f0aaef3404bb71844fa556d6"
|
||||
integrity sha512-IfgxpCxWm5rRK3Q7aTvVyhQ/7tyyn8EJl5tFak5tS+/n8oXT7OGfv8praYepR7+IsM92waAuBDZng1HgnstrYA==
|
||||
dependencies:
|
||||
color "^4.1.0"
|
||||
just-unique "^4.2.0"
|
||||
lodash.merge "^4.6.2"
|
||||
lodash.mergewith "^4.6.2"
|
||||
|
||||
tailwindcss@^3.2.4:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.1.tgz#b6662fab6a9b704779e48d083a9fef5a81d2b81e"
|
||||
|
|
Loading…
Reference in a new issue