From bb8badde96fffb1ca767eeab50bd198ffce9434b Mon Sep 17 00:00:00 2001 From: triesmon <63887617+triesmon@users.noreply.github.com> Date: Sun, 28 Jun 2026 23:03:20 -0400 Subject: [PATCH 1/5] feat: add light theme --- public/logo_full_light.svg | 21 + public/logo_stacked_light.svg | 21 + src/components/Common/SeerrLogo/index.tsx | 39 + src/components/Layout/Sidebar/index.tsx | 11 +- src/components/Layout/UserDropdown/index.tsx | 32 + src/components/Login/index.tsx | 4 +- .../ResetPassword/RequestResetLink.tsx | 4 +- src/components/ResetPassword/index.tsx | 4 +- src/components/Setup/index.tsx | 4 +- src/components/TitleCard/index.tsx | 2 +- src/hooks/useTheme.ts | 141 ++++ src/i18n/locale/en.json | 2 + src/pages/_app.tsx | 54 +- src/pages/_document.tsx | 28 +- src/styles/theme-light.css | 783 ++++++++++++++++++ 15 files changed, 1107 insertions(+), 43 deletions(-) create mode 100644 public/logo_full_light.svg create mode 100644 public/logo_stacked_light.svg create mode 100644 src/components/Common/SeerrLogo/index.tsx create mode 100644 src/hooks/useTheme.ts create mode 100644 src/styles/theme-light.css diff --git a/public/logo_full_light.svg b/public/logo_full_light.svg new file mode 100644 index 0000000000..a0e06901ff --- /dev/null +++ b/public/logo_full_light.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/public/logo_stacked_light.svg b/public/logo_stacked_light.svg new file mode 100644 index 0000000000..a433d17c6d --- /dev/null +++ b/public/logo_stacked_light.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/Common/SeerrLogo/index.tsx b/src/components/Common/SeerrLogo/index.tsx new file mode 100644 index 0000000000..0258b49123 --- /dev/null +++ b/src/components/Common/SeerrLogo/index.tsx @@ -0,0 +1,39 @@ +import Image, { type ImageProps } from 'next/image'; + +type SeerrLogoVariant = 'full' | 'stacked'; + +interface SeerrLogoProps extends Omit { + alt?: string; + variant: SeerrLogoVariant; +} + +const getLogoSrc = (variant: SeerrLogoVariant, light = false) => + `/logo_${variant}${light ? '_light' : ''}.svg`; + +const withLogoClass = (className: string | undefined, logoClass: string) => + [className, 'seerr-logo', logoClass].filter(Boolean).join(' '); + +const SeerrLogo = ({ + alt = 'Logo', + className, + variant, + ...props +}: SeerrLogoProps) => ( + <> + {alt} + + +); + +export default SeerrLogo; diff --git a/src/components/Layout/Sidebar/index.tsx b/src/components/Layout/Sidebar/index.tsx index 60b32291a6..8f9dab1043 100644 --- a/src/components/Layout/Sidebar/index.tsx +++ b/src/components/Layout/Sidebar/index.tsx @@ -1,4 +1,5 @@ import Badge from '@app/components/Common/Badge'; +import SeerrLogo from '@app/components/Common/SeerrLogo'; import VersionStatus from '@app/components/Layout/VersionStatus'; import useClickOutside from '@app/hooks/useClickOutside'; import { Permission, useUser } from '@app/hooks/useUser'; @@ -15,7 +16,6 @@ import { UsersIcon, XMarkIcon, } from '@heroicons/react/24/outline'; -import Image from 'next/image'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { Fragment, useEffect, useRef } from 'react'; @@ -192,7 +192,7 @@ const Sidebar = ({
- Logo +
@@ -255,12 +255,7 @@ const Sidebar = ({
- Logo +
diff --git a/src/components/Layout/UserDropdown/index.tsx b/src/components/Layout/UserDropdown/index.tsx index 545a63e202..27d0b7c912 100644 --- a/src/components/Layout/UserDropdown/index.tsx +++ b/src/components/Layout/UserDropdown/index.tsx @@ -1,11 +1,14 @@ import CachedImage from '@app/components/Common/CachedImage'; import MiniQuotaDisplay from '@app/components/Layout/UserDropdown/MiniQuotaDisplay'; +import useTheme from '@app/hooks/useTheme'; import { Permission, useUser } from '@app/hooks/useUser'; import defineMessages from '@app/utils/defineMessages'; import { Menu, Transition } from '@headlessui/react'; import { ArrowRightOnRectangleIcon, ClockIcon, + MoonIcon, + SunIcon, } from '@heroicons/react/24/outline'; import { CogIcon, UserIcon } from '@heroicons/react/24/solid'; import axios from 'axios'; @@ -18,6 +21,8 @@ const messages = defineMessages('components.Layout.UserDropdown', { myprofile: 'Profile', settings: 'Settings', requests: 'Requests', + switchtodark: 'Switch to Dark Theme', + switchtolight: 'Switch to Light Theme', signout: 'Sign Out', }); @@ -37,6 +42,7 @@ ForwardedLink.displayName = 'ForwardedLink'; const UserDropdown = () => { const intl = useIntl(); const { user, revalidate, hasPermission } = useUser(); + const { theme, toggleTheme } = useTheme(); const logout = async () => { const response = await axios.post('/api/v1/auth/logout'); @@ -154,6 +160,32 @@ const UserDropdown = () => { )} + + {({ active }) => ( + + )} + {({ active }) => ( {
- Logo +
diff --git a/src/components/ResetPassword/RequestResetLink.tsx b/src/components/ResetPassword/RequestResetLink.tsx index 9bebb8b065..087322ec11 100644 --- a/src/components/ResetPassword/RequestResetLink.tsx +++ b/src/components/ResetPassword/RequestResetLink.tsx @@ -1,12 +1,12 @@ import Button from '@app/components/Common/Button'; import ImageFader from '@app/components/Common/ImageFader'; import PageTitle from '@app/components/Common/PageTitle'; +import SeerrLogo from '@app/components/Common/SeerrLogo'; import LanguagePicker from '@app/components/Layout/LanguagePicker'; import defineMessages from '@app/utils/defineMessages'; import { ArrowLeftIcon, EnvelopeIcon } from '@heroicons/react/24/solid'; import axios from 'axios'; import { Field, Form, Formik } from 'formik'; -import Image from 'next/image'; import Link from 'next/link'; import { useState } from 'react'; import { useIntl } from 'react-intl'; @@ -57,7 +57,7 @@ const ResetPassword = () => {
- Logo +

{intl.formatMessage(messages.resetpassword)} diff --git a/src/components/ResetPassword/index.tsx b/src/components/ResetPassword/index.tsx index 57053e936c..b6a03019ab 100644 --- a/src/components/ResetPassword/index.tsx +++ b/src/components/ResetPassword/index.tsx @@ -1,5 +1,6 @@ import Button from '@app/components/Common/Button'; import ImageFader from '@app/components/Common/ImageFader'; +import SeerrLogo from '@app/components/Common/SeerrLogo'; import SensitiveInput from '@app/components/Common/SensitiveInput'; import LanguagePicker from '@app/components/Layout/LanguagePicker'; import globalMessages from '@app/i18n/globalMessages'; @@ -7,7 +8,6 @@ import defineMessages from '@app/utils/defineMessages'; import { LifebuoyIcon } from '@heroicons/react/24/outline'; import axios from 'axios'; import { Form, Formik } from 'formik'; -import Image from 'next/image'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { useState } from 'react'; @@ -67,7 +67,7 @@ const ResetPassword = () => {

- Logo +

{intl.formatMessage(messages.resetpassword)} diff --git a/src/components/Setup/index.tsx b/src/components/Setup/index.tsx index 947104d352..13d07d7750 100644 --- a/src/components/Setup/index.tsx +++ b/src/components/Setup/index.tsx @@ -5,6 +5,7 @@ import AppDataWarning from '@app/components/AppDataWarning'; import Button from '@app/components/Common/Button'; import ImageFader from '@app/components/Common/ImageFader'; import PageTitle from '@app/components/Common/PageTitle'; +import SeerrLogo from '@app/components/Common/SeerrLogo'; import LanguagePicker from '@app/components/Layout/LanguagePicker'; import SettingsJellyfin from '@app/components/Settings/SettingsJellyfin'; import SettingsPlex from '@app/components/Settings/SettingsPlex'; @@ -17,7 +18,6 @@ import defineMessages from '@app/utils/defineMessages'; import { MediaServerType } from '@server/constants/server'; import type { Library } from '@server/lib/settings'; import axios from 'axios'; -import Image from 'next/image'; import { useRouter } from 'next/router'; import { useCallback, useEffect, useState } from 'react'; import { useIntl } from 'react-intl'; @@ -159,7 +159,7 @@ const Setup = () => {

- Logo +