Dark mode
This commit is contained in:
parent
112f72b4d9
commit
282b67deed
|
@ -6278,6 +6278,19 @@
|
|||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@theme-toggles/react": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@theme-toggles/react/-/react-4.1.0.tgz",
|
||||
"integrity": "sha512-h3SuJMsej8DfelHt5fjNIlaMfJOK52Vku4pPDVoHaTwjAcoTr4fn8hzeur2oiqWBYFYfKugvv1RdQaBFXaiPKg==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/alfiejones"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16 || ^17 || ^18",
|
||||
"react-dom": "^16 || ^17 || ^18"
|
||||
}
|
||||
},
|
||||
"node_modules/@tsconfig/node10": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
|
||||
|
@ -16261,10 +16274,12 @@
|
|||
"@icons-pack/react-simple-icons": "^9.6.0",
|
||||
"@nextui-org/react": "^2.2.9",
|
||||
"@sc07-canvas/lib": "^1.0.0",
|
||||
"@theme-toggles/react": "^4.1.0",
|
||||
"@typescript-eslint/parser": "^7.1.0",
|
||||
"eventemitter3": "^5.0.1",
|
||||
"framer-motion": "^11.3.2",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"next-themes": "^0.3.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
@ -16472,6 +16487,15 @@
|
|||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"packages/client/node_modules/next-themes": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz",
|
||||
"integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8 || ^17 || ^18",
|
||||
"react-dom": "^16.8 || ^17 || ^18"
|
||||
}
|
||||
},
|
||||
"packages/lib": {
|
||||
"name": "@sc07-canvas/lib",
|
||||
"version": "1.0.0",
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import { useTheme } from "next-themes";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
|
||||
export const ToastWrapper = () => {
|
||||
const { theme } = useTheme()
|
||||
|
||||
return (
|
||||
<ToastContainer
|
||||
position="bottom-right"
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -10,6 +10,7 @@ import { AccountsPage } from "./pages/Accounts/Accounts/page.tsx";
|
|||
import { ServiceSettingsPage } from "./pages/Service/settings.tsx";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
import { AuditLog } from "./pages/AuditLog/auditlog.tsx";
|
||||
import { ToastWrapper } from "./components/ToastWrapper.tsx";
|
||||
|
||||
const router = createBrowserRouter(
|
||||
[
|
||||
|
@ -47,7 +48,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
|
|||
<ThemeProvider defaultTheme="system">
|
||||
<RouterProvider router={router} />
|
||||
|
||||
<ToastContainer position="bottom-right" />
|
||||
<ToastWrapper />
|
||||
</ThemeProvider>
|
||||
</NextUIProvider>
|
||||
</React.StrictMode>
|
||||
|
|
|
@ -27,10 +27,12 @@
|
|||
"@icons-pack/react-simple-icons": "^9.6.0",
|
||||
"@nextui-org/react": "^2.2.9",
|
||||
"@sc07-canvas/lib": "^1.0.0",
|
||||
"@theme-toggles/react": "^4.1.0",
|
||||
"@typescript-eslint/parser": "^7.1.0",
|
||||
"eventemitter3": "^5.0.1",
|
||||
"framer-motion": "^11.3.2",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"next-themes": "^0.3.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
|
|
@ -19,6 +19,7 @@ import { WelcomeModal } from "./Welcome/WelcomeModal";
|
|||
import { InfoSidebar } from "./Info/InfoSidebar";
|
||||
import { ModModal } from "./Moderation/ModModal";
|
||||
import { DynamicModals } from "./DynamicModals";
|
||||
import { ToastWrapper } from "./ToastWrapper";
|
||||
|
||||
const Chat = lazy(() => import("./Chat/Chat"));
|
||||
|
||||
|
@ -152,7 +153,7 @@ const AppInner = () => {
|
|||
<WelcomeModal />
|
||||
<ModModal />
|
||||
|
||||
<ToastContainer position="top-left" />
|
||||
<ToastWrapper />
|
||||
<DynamicModals />
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { Badge, Button, Link } from "@nextui-org/react";
|
||||
import { useChatContext } from "../../contexts/ChatContext";
|
||||
import { useAppContext } from "../../contexts/AppContext";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faComments } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
const OpenChatButton = () => {
|
||||
const { config } = useAppContext();
|
||||
|
@ -13,7 +15,15 @@ const OpenChatButton = () => {
|
|||
color="danger"
|
||||
size="sm"
|
||||
>
|
||||
{config?.chat?.element_host && <Button onPress={doLogin}>Chat</Button>}
|
||||
{
|
||||
config?.chat?.element_host &&
|
||||
<Button
|
||||
onPress={doLogin}
|
||||
variant="ghost"
|
||||
>
|
||||
<FontAwesomeIcon icon={faComments} />
|
||||
<p>Chat</p>
|
||||
</Button>}
|
||||
</Badge>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,18 +1,8 @@
|
|||
import { Button, Card, CardBody, Link } from "@nextui-org/react";
|
||||
import { Card, CardBody } from "@nextui-org/react";
|
||||
import { useAppContext } from "../../contexts/AppContext";
|
||||
import { User } from "./User";
|
||||
import { Debug } from "@sc07-canvas/lib/src/debug";
|
||||
import React, { lazy } from "react";
|
||||
import { AccountStanding } from "./AccountStanding";
|
||||
import { EventInfoOverlay } from "../EventInfoOverlay";
|
||||
|
||||
const OpenChatButton = lazy(() => import("../Chat/OpenChatButton"));
|
||||
|
||||
const DynamicChat = () => {
|
||||
const { loadChat } = useAppContext();
|
||||
|
||||
return <React.Suspense>{loadChat && <OpenChatButton />}</React.Suspense>;
|
||||
};
|
||||
import { HeaderLeft } from "./HeaderLeft";
|
||||
import { HeaderRight } from "./HeaderRight";
|
||||
|
||||
export const Header = () => {
|
||||
const { connected } = useAppContext();
|
||||
|
@ -20,8 +10,8 @@ export const Header = () => {
|
|||
return (
|
||||
<header id="main-header">
|
||||
{import.meta.env.VITE_INCLUDE_EVENT_INFO && <EventInfoOverlay />}
|
||||
<div className="flex justify-between w-full">
|
||||
<HeaderLeft />
|
||||
<div className="spacer"></div>
|
||||
{!connected && (
|
||||
<div>
|
||||
<Card>
|
||||
|
@ -29,39 +19,10 @@ export const Header = () => {
|
|||
</Card>
|
||||
</div>
|
||||
)}
|
||||
<div className="spacer"></div>
|
||||
<HeaderRight />
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
const HeaderLeft = () => {
|
||||
const { setInfoSidebar } = useAppContext();
|
||||
|
||||
return (
|
||||
<div className="box">
|
||||
<AccountStanding />
|
||||
<Button onPress={() => setInfoSidebar(true)}>Info</Button>
|
||||
{import.meta.env.DEV && (
|
||||
<Button onPress={() => Debug.openDebugTools()}>Debug Tools</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const HeaderRight = () => {
|
||||
const { setSettingsSidebar, hasAdmin } = useAppContext();
|
||||
|
||||
return (
|
||||
<div className="box">
|
||||
<User />
|
||||
<Button onClick={() => setSettingsSidebar(true)}>Settings</Button>
|
||||
{hasAdmin && (
|
||||
<Button href="/admin" target="_blank" as={Link}>
|
||||
Admin
|
||||
</Button>
|
||||
)}
|
||||
<DynamicChat />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import { Button } from "@nextui-org/react";
|
||||
import { useAppContext } from "../../contexts/AppContext";
|
||||
import { AccountStanding } from "./AccountStanding";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Debug } from "@sc07-canvas/lib/src/debug";
|
||||
import { faInfoCircle, faTools } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
export const HeaderLeft = () => {
|
||||
const { setInfoSidebar } = useAppContext();
|
||||
|
||||
return (
|
||||
<div className="box gap-2 flex">
|
||||
<AccountStanding />
|
||||
<Button
|
||||
onPress={() => setInfoSidebar(true)}
|
||||
variant="ghost"
|
||||
>
|
||||
<FontAwesomeIcon icon={faInfoCircle} />
|
||||
<p>Info</p>
|
||||
</Button>
|
||||
{import.meta.env.DEV && (
|
||||
<Button
|
||||
onPress={() => Debug.openDebugTools()}
|
||||
variant="ghost"
|
||||
>
|
||||
<FontAwesomeIcon icon={faTools} />
|
||||
<p>Debug Tools</p>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
import { Button, Link } from "@nextui-org/react";
|
||||
import { useAppContext } from "../../contexts/AppContext";
|
||||
import { User } from "./User";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { ThemeSwitcher } from "./ThemeSwitcher";
|
||||
import { faGear, faHammer } from "@fortawesome/free-solid-svg-icons";
|
||||
import React, { lazy } from "react";
|
||||
|
||||
const OpenChatButton = lazy(() => import("../Chat/OpenChatButton"));
|
||||
|
||||
const DynamicChat = () => {
|
||||
const { loadChat } = useAppContext();
|
||||
|
||||
return <React.Suspense>{loadChat && <OpenChatButton />}</React.Suspense>;
|
||||
};
|
||||
|
||||
export const HeaderRight = () => {
|
||||
const { setSettingsSidebar, hasAdmin } = useAppContext();
|
||||
|
||||
return (
|
||||
<div className="box flex flex-col gap-2">
|
||||
<User />
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
onClick={() => setSettingsSidebar(true)}
|
||||
variant="ghost"
|
||||
>
|
||||
<FontAwesomeIcon icon={faGear} />
|
||||
<p>Settings</p>
|
||||
</Button>
|
||||
<ThemeSwitcher />
|
||||
{hasAdmin && (
|
||||
<Button href="/admin" target="_blank" as={Link} variant="ghost" >
|
||||
<FontAwesomeIcon icon={faHammer} />
|
||||
<p>Admin</p>
|
||||
</Button>
|
||||
)}
|
||||
<DynamicChat />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
import "@theme-toggles/react/css/Classic.css"
|
||||
import { Classic } from "@theme-toggles/react"
|
||||
|
||||
import {useTheme} from "next-themes";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Button } from "@nextui-org/react";
|
||||
|
||||
export function ThemeSwitcher() {
|
||||
const [mounted, setMounted] = useState(false)
|
||||
const { theme, setTheme } = useTheme()
|
||||
const [isToggled, setToggle] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true)
|
||||
setToggle(theme === 'dark')
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (isToggled) {
|
||||
setTheme('dark')
|
||||
} else {
|
||||
setTheme('light')
|
||||
}
|
||||
}, [isToggled])
|
||||
|
||||
if(!mounted) return null
|
||||
|
||||
return (
|
||||
<Button onClick={() => { setToggle(!isToggled) }} variant="ghost">
|
||||
<Classic toggled={isToggled} placeholder={undefined} />
|
||||
<p>{theme === 'dark' ? "Dark" : "Light"}</p>
|
||||
</Button>
|
||||
)
|
||||
};
|
|
@ -24,13 +24,13 @@ export const InfoSidebar = () => {
|
|||
transition={{ type: 'spring', stiffness: 50 }}
|
||||
/>
|
||||
<motion.div
|
||||
className="min-w-[20rem] max-w-[75vw] md:max-w-[30vw] bg-white text-black flex flex-col justify-between fixed left-0 h-full shadow-xl overflow-y-auto z-50 top-0"
|
||||
className="min-w-[20rem] max-w-[75vw] md:max-w-[30vw] bg-white dark:bg-black flex flex-col justify-between fixed left-0 h-full shadow-xl overflow-y-auto z-50 top-0"
|
||||
initial={{ x: '-150%' }}
|
||||
animate={{ x: infoSidebar ? '-50%' : '-150%' }}
|
||||
transition={{ type: 'spring', stiffness: 50 }}
|
||||
/>
|
||||
<motion.div
|
||||
className="min-w-[20rem] max-w-[75vw] md:max-w-[30vw] bg-white text-black flex flex-col justify-between fixed left-0 h-full shadow-xl overflow-y-auto z-50 top-0"
|
||||
className="min-w-[20rem] max-w-[75vw] md:max-w-[30vw] bg-white dark:bg-black text-black dark:text-white flex flex-col justify-between fixed left-0 h-full shadow-xl overflow-y-auto z-50 top-0"
|
||||
initial={{ x: '-100%' }}
|
||||
animate={{ x: infoSidebar ? 0 : '-100%' }}
|
||||
transition={{ type: 'spring', stiffness: 50 }}
|
||||
|
|
|
@ -12,7 +12,7 @@ export const SettingsSidebar = () => {
|
|||
|
||||
return (
|
||||
<div
|
||||
className="sidebar sidebar-right"
|
||||
className="sidebar sidebar-right bg-white text-black dark:bg-black dark:text-white"
|
||||
style={{ ...(settingsSidebar ? {} : { display: "none" }) }}
|
||||
>
|
||||
<header>
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import { useTheme } from "next-themes";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
|
||||
export const ToastWrapper = () => {
|
||||
const { theme } = useTheme()
|
||||
|
||||
return (
|
||||
<ToastContainer
|
||||
position="top-left"
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -12,8 +12,6 @@
|
|||
z-index: 10;
|
||||
position: relative;
|
||||
|
||||
background-color: #fff;
|
||||
|
||||
.pallete-colors {
|
||||
// display: flex;
|
||||
// width: 100%;
|
||||
|
|
|
@ -29,7 +29,7 @@ export const Palette = () => {
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<div id="pallete">
|
||||
<div id="pallete" className="bg-[#fff] dark:bg-[#000]">
|
||||
<div className="pallete-colors">
|
||||
<button
|
||||
aria-label="Deselect Color"
|
||||
|
@ -71,12 +71,12 @@ export const Palette = () => {
|
|||
{import.meta.env.VITE_INCLUDE_EVENT_INFO ? (
|
||||
<>The event hasn't started yet</>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex gap-3 items-center">
|
||||
You are not logged in
|
||||
<Button as={Link} href="/api/login" className="user-login">
|
||||
<Button as={Link} href="/api/login" className="user-login" variant="faded">
|
||||
Login
|
||||
</Button>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { NextUIProvider } from "@nextui-org/react";
|
||||
import { ThemeProvider } from 'next-themes'
|
||||
import App from "./components/App";
|
||||
|
||||
import Bugsnag from "@bugsnag/js";
|
||||
|
@ -26,7 +27,11 @@ root.render(
|
|||
<React.StrictMode>
|
||||
<ErrorBoundary>
|
||||
<NextUIProvider>
|
||||
<ThemeProvider attribute="class" defaultTheme="system">
|
||||
<div className="w-screen h-screen bg-[#ddd] dark:bg-[#060606]">
|
||||
<App />
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
</NextUIProvider>
|
||||
</ErrorBoundary>
|
||||
</React.StrictMode>
|
||||
|
|
|
@ -10,8 +10,6 @@ html,
|
|||
body {
|
||||
overscroll-behavior: contain;
|
||||
touch-action: none;
|
||||
|
||||
background-color: #ddd !important;
|
||||
}
|
||||
|
||||
header#main-header {
|
||||
|
@ -150,8 +148,6 @@ main {
|
|||
position: fixed;
|
||||
top: 0;
|
||||
z-index: 9998;
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
height: 100%;
|
||||
|
||||
min-width: 20rem;
|
||||
|
|
Loading…
Reference in New Issue