Add theme_switcher and some theme (#2)

* Add theme_switcher and some theme

* Unify theme with both light & dark version

* Use anchor instead of window.open
This commit is contained in:
Yukko
2025-06-04 22:19:51 +08:00
committed by GitHub
parent 0e6ea060c5
commit e8c4d7f545
4 changed files with 320 additions and 32 deletions

View File

@@ -10,6 +10,7 @@ import {
} from "react-icons/md";
import { useTranslation } from "react-i18next";
import UploadingSideBar from "./uploading_side_bar.tsx";
import { ThemeSwitcher } from "./theme_switcher.tsx";
import { IoLogoGithub } from "react-icons/io";
import { useAppContext } from "./AppContext.tsx";
@@ -140,6 +141,7 @@ export default function Navigator() {
<div className="flex gap-2">
<SearchBar />
<UploadingSideBar />
<ThemeSwitcher />
{app.isLoggedIn() && (
<button
className={"btn btn-circle btn-ghost"}
@@ -150,14 +152,15 @@ export default function Navigator() {
<MdSettings size={24} />
</button>
)}
<button
className={"btn btn-circle btn-ghost"}
onClick={() => {
window.open("https://github.com/wgh136/nysoure", "_blank");
}}
<a
href="https://github.com/wgh136/nysoure"
target="_blank"
rel="noopener noreferrer"
>
<button className={"btn btn-circle btn-ghost"}>
<IoLogoGithub size={24} />
</button>
</a>
{app.isLoggedIn() ? (
<UserButton />
) : (

View File

@@ -0,0 +1,93 @@
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { MdPalette } from "react-icons/md";
interface ThemeOption {
name: string;
displayName: string;
displayColor: string;
}
const themeOptions: ThemeOption[] = [
{
name: "pink",
displayName: "Nyne Pink",
displayColor: "oklch(65% 0.241 354.308)",
},
{
name: "ocean",
displayName: "Ocean Breeze",
displayColor: "oklch(70% 0.18 220)",
},
{
name: "mint",
displayName: "Mint Leaf",
displayColor: "oklch(65% 0.16 160)",
},
{
name: "glow",
displayName: "Golden Glow",
displayColor: "oklch(70% 0.16 70)",
},
];
export function ThemeSwitcher() {
const [currentTheme, setCurrentTheme] = useState("pink");
const { t } = useTranslation();
useEffect(() => {
const savedTheme = localStorage.getItem("theme") || "pink";
setCurrentTheme(savedTheme);
applyTheme(savedTheme);
}, []);
const applyTheme = (themeName: string) => {
const root = document.documentElement;
root.setAttribute("data-theme", themeName);
};
const handleThemeChange = (themeName: string) => {
setCurrentTheme(themeName);
applyTheme(themeName);
localStorage.setItem("theme", themeName);
const activeElement = document.activeElement as HTMLElement;
if (activeElement) {
activeElement.blur();
}
};
return (
<div className="dropdown dropdown-end">
<div tabIndex={0} role="button" className="btn btn-circle btn-ghost">
<MdPalette size={24} />
</div>
<ul
tabIndex={0}
className="dropdown-content menu bg-base-100 rounded-box z-[1] w-max min-w-35 p-2 shadow"
>
{themeOptions.map((theme) => (
<li key={theme.name}>
<a
className={`flex items-center justify-between${
currentTheme === theme.name ? "active" : ""
}`}
onClick={() => handleThemeChange(theme.name)}
>
<div className="flex items-center gap-3">
<div
className="w-4 h-4 rounded-full border-2 border-base-content/20"
style={{ backgroundColor: theme.displayColor }}
/>
<span className="mr-1">{t(theme.displayName)}</span>
</div>
{currentTheme === theme.name && (
<div className="w-2 h-2 bg-primary rounded-full" />
)}
</a>
</li>
))}
</ul>
</div>
);
}

View File

@@ -205,6 +205,12 @@ export const i18nData = {
"Show more": "Show more",
"Show less": "Show less",
"You need to log in to comment": "You need to log in to comment",
// Color Scheme Translation
"Nyne Pink": "Nyne Pink",
"Ocean Breeze": "Ocean Breeze",
"Mint Leaf": "Mint Leaf",
"Golden Glow": "Golden Glow",
},
},
"zh-CN": {
@@ -402,6 +408,12 @@ export const i18nData = {
"Show more": "显示更多",
"Show less": "显示更少",
"You need to log in to comment": "您需要登录才能评论",
// Color Scheme Translation
"Nyne Pink": "Nyne 粉",
"Ocean Breeze": "海蓝",
"Mint Leaf": "薄荷",
"Golden Glow": "微光",
},
},
"zh-TW": {
@@ -599,6 +611,12 @@ export const i18nData = {
"Show more": "顯示更多",
"Show less": "顯示更少",
"You need to log in to comment": "您需要登入才能評論",
// Color Scheme Translation
"Nyne Pink": "Nyne 粉",
"Ocean Breeze": "海藍",
"Mint Leaf": "薄荷",
"Golden Glow": "微光",
},
},
};

View File

@@ -1,11 +1,12 @@
@import "tailwindcss";
@plugin "daisyui";
/* Pink Theme */
@plugin "daisyui/theme" {
name: "light";
name: "pink";
default: true;
prefersdark: false;
color-scheme: "light";
color-scheme: "light dark";
--color-base-100: oklch(99% 0.014 343.198);
--color-base-200: oklch(97% 0.028 342.258);
--color-base-300: oklch(84% 0.061 343.231);
@@ -36,11 +37,8 @@
--noise: 0;
}
@plugin "daisyui/theme" {
name: "dark";
default: false;
prefersdark: true;
color-scheme: "dark";
@media (prefers-color-scheme: dark) {
[data-theme="pink"] {
--color-base-100: oklch(28% 0.022 277.508);
--color-base-200: oklch(24% 0.02 277.508);
--color-base-300: oklch(40% 0.153 2.432);
@@ -61,6 +59,35 @@
--color-warning-content: oklch(19.106% 0.026 112.757);
--color-error: oklch(68.22% 0.206 24.43);
--color-error-content: oklch(13.644% 0.041 24.43);
}
}
/* Ocean Theme */
@plugin "daisyui/theme" {
name: "ocean";
default: false;
prefersdark: false;
color-scheme: "light dark";
--color-base-100: oklch(98% 0.005 240);
--color-base-200: oklch(96% 0.01 240);
--color-base-300: oklch(92% 0.015 240);
--color-base-content: oklch(20% 0.01 240);
--color-primary: oklch(50% 0.2 240);
--color-primary-content: oklch(98% 0.005 240);
--color-secondary: oklch(60% 0.15 210);
--color-secondary-content: oklch(98% 0.005 210);
--color-accent: oklch(70% 0.18 220);
--color-accent-content: oklch(98% 0.005 220);
--color-neutral: oklch(25% 0.02 240);
--color-neutral-content: oklch(98% 0.005 240);
--color-info: oklch(65% 0.15 231);
--color-info-content: oklch(98% 0.005 231);
--color-success: oklch(60% 0.13 145);
--color-success-content: oklch(98% 0.005 145);
--color-warning: oklch(80% 0.15 90);
--color-warning-content: oklch(20% 0.05 90);
--color-error: oklch(60% 0.19 27);
--color-error-content: oklch(98% 0.005 27);
--radius-selector: 1rem;
--radius-field: 1.5rem;
--radius-box: 1rem;
@@ -71,6 +98,153 @@
--noise: 0;
}
@media (prefers-color-scheme: dark) {
[data-theme="ocean"] {
--color-base-100: oklch(15% 0.02 240);
--color-base-200: oklch(12% 0.015 240);
--color-base-300: oklch(25% 0.03 240);
--color-base-content: oklch(90% 0.01 240);
--color-primary: oklch(70% 0.18 240);
--color-primary-content: oklch(15% 0.02 240);
--color-secondary: oklch(75% 0.15 210);
--color-secondary-content: oklch(15% 0.015 210);
--color-accent: oklch(80% 0.16 220);
--color-accent-content: oklch(15% 0.02 220);
--color-neutral: oklch(20% 0.025 240);
--color-neutral-content: oklch(85% 0.01 240);
--color-info: oklch(75% 0.14 231);
--color-info-content: oklch(15% 0.015 231);
--color-success: oklch(70% 0.12 145);
--color-success-content: oklch(15% 0.015 145);
--color-warning: oklch(85% 0.14 90);
--color-warning-content: oklch(15% 0.02 90);
--color-error: oklch(70% 0.18 27);
--color-error-content: oklch(15% 0.015 27);
}
}
/* Mint Theme */
@plugin "daisyui/theme" {
name: "mint";
default: false;
prefersdark: false;
color-scheme: "light dark";
--color-base-100: oklch(98% 0.005 140);
--color-base-200: oklch(96% 0.01 140);
--color-base-300: oklch(92% 0.015 140);
--color-base-content: oklch(20% 0.01 140);
--color-primary: oklch(45% 0.18 140);
--color-primary-content: oklch(98% 0.005 140);
--color-secondary: oklch(55% 0.15 120);
--color-secondary-content: oklch(98% 0.005 120);
--color-accent: oklch(65% 0.16 160);
--color-accent-content: oklch(98% 0.005 160);
--color-neutral: oklch(25% 0.02 140);
--color-neutral-content: oklch(98% 0.005 140);
--color-info: oklch(70% 0.131 231);
--color-info-content: oklch(98% 0.005 231);
--color-success: oklch(55% 0.15 145);
--color-success-content: oklch(98% 0.005 145);
--color-warning: oklch(80% 0.15 90);
--color-warning-content: oklch(20% 0.05 90);
--color-error: oklch(60% 0.19 27);
--color-error-content: oklch(98% 0.005 27);
--radius-selector: 1rem;
--radius-field: 1.5rem;
--radius-box: 1rem;
--size-selector: 0.25rem;
--size-field: 0.25rem;
--border: 1px;
--depth: 1;
--noise: 0;
}
@media (prefers-color-scheme: dark) {
[data-theme="mint"] {
--color-base-100: oklch(15% 0.02 140);
--color-base-200: oklch(12% 0.015 140);
--color-base-300: oklch(25% 0.03 140);
--color-base-content: oklch(90% 0.01 140);
--color-primary: oklch(65% 0.16 140);
--color-primary-content: oklch(15% 0.02 140);
--color-secondary: oklch(70% 0.14 120);
--color-secondary-content: oklch(15% 0.015 120);
--color-accent: oklch(75% 0.15 160);
--color-accent-content: oklch(15% 0.02 160);
--color-neutral: oklch(20% 0.025 140);
--color-neutral-content: oklch(85% 0.01 140);
--color-info: oklch(75% 0.12 231);
--color-info-content: oklch(15% 0.015 231);
--color-success: oklch(70% 0.14 145);
--color-success-content: oklch(15% 0.015 145);
--color-warning: oklch(85% 0.14 90);
--color-warning-content: oklch(15% 0.02 90);
--color-error: oklch(70% 0.18 27);
--color-error-content: oklch(15% 0.015 27);
}
}
/* Glow Theme */
@plugin "daisyui/theme" {
name: "glow";
default: false;
prefersdark: false;
color-scheme: "light dark";
--color-base-100: oklch(98% 0.005 50);
--color-base-200: oklch(96% 0.01 50);
--color-base-300: oklch(92% 0.015 50);
--color-base-content: oklch(20% 0.01 50);
--color-primary: oklch(60% 0.18 50);
--color-primary-content: oklch(98% 0.005 50);
--color-secondary: oklch(65% 0.15 30);
--color-secondary-content: oklch(98% 0.005 30);
--color-accent: oklch(70% 0.16 70);
--color-accent-content: oklch(98% 0.005 70);
--color-neutral: oklch(25% 0.02 50);
--color-neutral-content: oklch(98% 0.005 50);
--color-info: oklch(70% 0.131 231);
--color-info-content: oklch(98% 0.005 231);
--color-success: oklch(60% 0.13 145);
--color-success-content: oklch(98% 0.005 145);
--color-warning: oklch(75% 0.16 60);
--color-warning-content: oklch(20% 0.05 60);
--color-error: oklch(60% 0.19 27);
--color-error-content: oklch(98% 0.005 27);
--radius-selector: 1rem;
--radius-field: 1.5rem;
--radius-box: 1rem;
--size-selector: 0.25rem;
--size-field: 0.25rem;
--border: 1px;
--depth: 1;
--noise: 0;
}
@media (prefers-color-scheme: dark) {
[data-theme="glow"] {
--color-base-100: oklch(15% 0.02 50);
--color-base-200: oklch(12% 0.015 50);
--color-base-300: oklch(25% 0.03 50);
--color-base-content: oklch(90% 0.01 50);
--color-primary: oklch(75% 0.16 50);
--color-primary-content: oklch(15% 0.02 50);
--color-secondary: oklch(80% 0.14 30);
--color-secondary-content: oklch(15% 0.015 30);
--color-accent: oklch(85% 0.15 70);
--color-accent-content: oklch(15% 0.02 70);
--color-neutral: oklch(20% 0.025 50);
--color-neutral-content: oklch(85% 0.01 50);
--color-info: oklch(75% 0.12 231);
--color-info-content: oklch(15% 0.015 231);
--color-success: oklch(70% 0.12 145);
--color-success-content: oklch(15% 0.015 145);
--color-warning: oklch(85% 0.15 60);
--color-warning-content: oklch(15% 0.02 60);
--color-error: oklch(70% 0.18 27);
--color-error-content: oklch(15% 0.015 27);
}
}
html {
width: 100%;
height: 100%;