mirror of
https://github.com/wgh136/nysoure.git
synced 2025-09-27 12:17:24 +00:00
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:
@@ -10,6 +10,7 @@ import {
|
|||||||
} from "react-icons/md";
|
} from "react-icons/md";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import UploadingSideBar from "./uploading_side_bar.tsx";
|
import UploadingSideBar from "./uploading_side_bar.tsx";
|
||||||
|
import { ThemeSwitcher } from "./theme_switcher.tsx";
|
||||||
import { IoLogoGithub } from "react-icons/io";
|
import { IoLogoGithub } from "react-icons/io";
|
||||||
import { useAppContext } from "./AppContext.tsx";
|
import { useAppContext } from "./AppContext.tsx";
|
||||||
|
|
||||||
@@ -140,6 +141,7 @@ export default function Navigator() {
|
|||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<SearchBar />
|
<SearchBar />
|
||||||
<UploadingSideBar />
|
<UploadingSideBar />
|
||||||
|
<ThemeSwitcher />
|
||||||
{app.isLoggedIn() && (
|
{app.isLoggedIn() && (
|
||||||
<button
|
<button
|
||||||
className={"btn btn-circle btn-ghost"}
|
className={"btn btn-circle btn-ghost"}
|
||||||
@@ -150,14 +152,15 @@ export default function Navigator() {
|
|||||||
<MdSettings size={24} />
|
<MdSettings size={24} />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<button
|
<a
|
||||||
className={"btn btn-circle btn-ghost"}
|
href="https://github.com/wgh136/nysoure"
|
||||||
onClick={() => {
|
target="_blank"
|
||||||
window.open("https://github.com/wgh136/nysoure", "_blank");
|
rel="noopener noreferrer"
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<IoLogoGithub size={24} />
|
<button className={"btn btn-circle btn-ghost"}>
|
||||||
</button>
|
<IoLogoGithub size={24} />
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
{app.isLoggedIn() ? (
|
{app.isLoggedIn() ? (
|
||||||
<UserButton />
|
<UserButton />
|
||||||
) : (
|
) : (
|
||||||
|
93
frontend/src/components/theme_switcher.tsx
Normal file
93
frontend/src/components/theme_switcher.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
@@ -205,6 +205,12 @@ export const i18nData = {
|
|||||||
"Show more": "Show more",
|
"Show more": "Show more",
|
||||||
"Show less": "Show less",
|
"Show less": "Show less",
|
||||||
"You need to log in to comment": "You need to log in to comment",
|
"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": {
|
"zh-CN": {
|
||||||
@@ -402,6 +408,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 粉",
|
||||||
|
"Ocean Breeze": "海蓝",
|
||||||
|
"Mint Leaf": "薄荷",
|
||||||
|
"Golden Glow": "微光",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"zh-TW": {
|
"zh-TW": {
|
||||||
@@ -599,6 +611,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 粉",
|
||||||
|
"Ocean Breeze": "海藍",
|
||||||
|
"Mint Leaf": "薄荷",
|
||||||
|
"Golden Glow": "微光",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
@plugin "daisyui";
|
@plugin "daisyui";
|
||||||
|
|
||||||
|
/* Pink Theme */
|
||||||
@plugin "daisyui/theme" {
|
@plugin "daisyui/theme" {
|
||||||
name: "light";
|
name: "pink";
|
||||||
default: true;
|
default: true;
|
||||||
prefersdark: false;
|
prefersdark: false;
|
||||||
color-scheme: "light";
|
color-scheme: "light dark";
|
||||||
--color-base-100: oklch(99% 0.014 343.198);
|
--color-base-100: oklch(99% 0.014 343.198);
|
||||||
--color-base-200: oklch(97% 0.028 342.258);
|
--color-base-200: oklch(97% 0.028 342.258);
|
||||||
--color-base-300: oklch(84% 0.061 343.231);
|
--color-base-300: oklch(84% 0.061 343.231);
|
||||||
@@ -36,31 +37,57 @@
|
|||||||
--noise: 0;
|
--noise: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
--color-base-content: oklch(97.747% 0.007 106.545);
|
||||||
|
--color-primary: oklch(75.461% 0.183 346.812);
|
||||||
|
--color-primary-content: oklch(15.092% 0.036 346.812);
|
||||||
|
--color-secondary: oklch(74.202% 0.148 301.883);
|
||||||
|
--color-secondary-content: oklch(14.84% 0.029 301.883);
|
||||||
|
--color-accent: oklch(83.392% 0.124 66.558);
|
||||||
|
--color-accent-content: oklch(16.678% 0.024 66.558);
|
||||||
|
--color-neutral: oklch(39.445% 0.032 275.524);
|
||||||
|
--color-neutral-content: oklch(87.889% 0.006 275.524);
|
||||||
|
--color-info: oklch(88.263% 0.093 212.846);
|
||||||
|
--color-info-content: oklch(17.652% 0.018 212.846);
|
||||||
|
--color-success: oklch(87.099% 0.219 148.024);
|
||||||
|
--color-success-content: oklch(17.419% 0.043 148.024);
|
||||||
|
--color-warning: oklch(95.533% 0.134 112.757);
|
||||||
|
--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" {
|
@plugin "daisyui/theme" {
|
||||||
name: "dark";
|
name: "ocean";
|
||||||
default: false;
|
default: false;
|
||||||
prefersdark: true;
|
prefersdark: false;
|
||||||
color-scheme: "dark";
|
color-scheme: "light dark";
|
||||||
--color-base-100: oklch(28% 0.022 277.508);
|
--color-base-100: oklch(98% 0.005 240);
|
||||||
--color-base-200: oklch(24% 0.02 277.508);
|
--color-base-200: oklch(96% 0.01 240);
|
||||||
--color-base-300: oklch(40% 0.153 2.432);
|
--color-base-300: oklch(92% 0.015 240);
|
||||||
--color-base-content: oklch(97.747% 0.007 106.545);
|
--color-base-content: oklch(20% 0.01 240);
|
||||||
--color-primary: oklch(75.461% 0.183 346.812);
|
--color-primary: oklch(50% 0.2 240);
|
||||||
--color-primary-content: oklch(15.092% 0.036 346.812);
|
--color-primary-content: oklch(98% 0.005 240);
|
||||||
--color-secondary: oklch(74.202% 0.148 301.883);
|
--color-secondary: oklch(60% 0.15 210);
|
||||||
--color-secondary-content: oklch(14.84% 0.029 301.883);
|
--color-secondary-content: oklch(98% 0.005 210);
|
||||||
--color-accent: oklch(83.392% 0.124 66.558);
|
--color-accent: oklch(70% 0.18 220);
|
||||||
--color-accent-content: oklch(16.678% 0.024 66.558);
|
--color-accent-content: oklch(98% 0.005 220);
|
||||||
--color-neutral: oklch(39.445% 0.032 275.524);
|
--color-neutral: oklch(25% 0.02 240);
|
||||||
--color-neutral-content: oklch(87.889% 0.006 275.524);
|
--color-neutral-content: oklch(98% 0.005 240);
|
||||||
--color-info: oklch(88.263% 0.093 212.846);
|
--color-info: oklch(65% 0.15 231);
|
||||||
--color-info-content: oklch(17.652% 0.018 212.846);
|
--color-info-content: oklch(98% 0.005 231);
|
||||||
--color-success: oklch(87.099% 0.219 148.024);
|
--color-success: oklch(60% 0.13 145);
|
||||||
--color-success-content: oklch(17.419% 0.043 148.024);
|
--color-success-content: oklch(98% 0.005 145);
|
||||||
--color-warning: oklch(95.533% 0.134 112.757);
|
--color-warning: oklch(80% 0.15 90);
|
||||||
--color-warning-content: oklch(19.106% 0.026 112.757);
|
--color-warning-content: oklch(20% 0.05 90);
|
||||||
--color-error: oklch(68.22% 0.206 24.43);
|
--color-error: oklch(60% 0.19 27);
|
||||||
--color-error-content: oklch(13.644% 0.041 24.43);
|
--color-error-content: oklch(98% 0.005 27);
|
||||||
--radius-selector: 1rem;
|
--radius-selector: 1rem;
|
||||||
--radius-field: 1.5rem;
|
--radius-field: 1.5rem;
|
||||||
--radius-box: 1rem;
|
--radius-box: 1rem;
|
||||||
@@ -71,6 +98,153 @@
|
|||||||
--noise: 0;
|
--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 {
|
html {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
Reference in New Issue
Block a user