move darkMode to a context instead of passing props
This commit is contained in:
parent
06344f9759
commit
70438ee947
4 changed files with 160 additions and 158 deletions
246
src/App.tsx
246
src/App.tsx
|
@ -17,7 +17,7 @@ import {
|
|||
} from "@chakra-ui/react";
|
||||
import Editor from "@monaco-editor/react";
|
||||
import { editor } from "monaco-editor/esm/vs/editor/editor.api";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import { HiUserGroup, HiUser } from "react-icons/hi";
|
||||
import { FaMoon, FaSun } from "react-icons/fa";
|
||||
import {
|
||||
|
@ -36,6 +36,7 @@ import Rustpad, { UserInfo } from "./rustpad";
|
|||
import useHash from "./useHash";
|
||||
import UserList from "./User";
|
||||
import React, { Component } from 'react';
|
||||
import { ThemeContext, DarkModeToggle } from "./Theme";
|
||||
|
||||
|
||||
function getWsUri(id: string) {
|
||||
|
@ -65,6 +66,8 @@ function App() {
|
|||
const [hue, setHue] = useStorage("hue", generateHue);
|
||||
const [editor, setEditor] = useState<editor.IStandaloneCodeEditor>();
|
||||
const [darkMode, setDarkMode] = useStorage("darkMode", () => false);
|
||||
|
||||
|
||||
const rustpad = useRef<Rustpad>();
|
||||
const id = useHash();
|
||||
|
||||
|
@ -142,7 +145,7 @@ function App() {
|
|||
}
|
||||
|
||||
|
||||
function handleDarkMode() {
|
||||
function toggleDarkMode() {
|
||||
setDarkMode(!darkMode);
|
||||
}
|
||||
|
||||
|
@ -172,141 +175,120 @@ function App() {
|
|||
|
||||
|
||||
return (
|
||||
<Flex
|
||||
direction="column"
|
||||
h="100vh"
|
||||
overflow="hidden"
|
||||
bgColor={darkMode ? "#1e1e1e" : "white"}
|
||||
color={darkMode ? "#cbcaca" : "inherit"}
|
||||
>
|
||||
|
||||
<Box
|
||||
flexShrink={2}
|
||||
bgColor={darkMode ? "#333333" : "#e8e8e8"}
|
||||
color={darkMode ? "#cccccc" : "#383838"}
|
||||
textAlign="center"
|
||||
fontSize="sm"
|
||||
<ThemeContext.Provider value={{ darkMode, toggleDarkMode }}>
|
||||
<Flex
|
||||
direction="column"
|
||||
h="100vh"
|
||||
overflow="hidden"
|
||||
bgColor={darkMode ? "#1e1e1e" : "white"}
|
||||
color={darkMode ? "#cbcaca" : "inherit"}
|
||||
>
|
||||
<Flex spacing={0} px={2} alignItems="center">
|
||||
<ConnectionStatus darkMode={darkMode} connection={connection} />
|
||||
|
||||
<Button
|
||||
h="1.4rem"
|
||||
fontWeight="normal"
|
||||
rounded="none"
|
||||
_hover={{ bg: darkMode ? "#575759" : "gray.200" }}
|
||||
bgColor={darkMode ? "#333333" : "gray.200"}
|
||||
px={2}
|
||||
onClick={aboutDrawer.onOpen}
|
||||
>
|
||||
Rustpad
|
||||
</Button>
|
||||
|
||||
<Tooltip label="Syntax highlighting">
|
||||
<Select
|
||||
maxWidth="10em"
|
||||
size="xs"
|
||||
bgColor={darkMode ? "#3c3c3c" : "white"}
|
||||
_hover={{ bgColor: darkMode ? "#575757" : "dddddd" }}
|
||||
borderColor={darkMode ? "#3c3c3c" : "white"}
|
||||
value={language}
|
||||
onChange={(event) => handleChangeLanguage(event.target.value)}
|
||||
|
||||
>
|
||||
{languages.map((lang) => (
|
||||
<option key={lang} value={lang} style={{ color: "black" }}>
|
||||
{lang}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</Tooltip>
|
||||
<Spacer />
|
||||
<Users
|
||||
users={users}
|
||||
darkMode={darkMode}
|
||||
me={{ name, hue }}
|
||||
setName={setName}
|
||||
setHue={setHue}
|
||||
id={id}
|
||||
handleCopy={handleCopy}
|
||||
/>
|
||||
<DarkModeToggle darkMode={darkMode} toggle={handleDarkMode} />
|
||||
</Flex>
|
||||
</Box >
|
||||
<Flex flex="1 0" minH={0}>
|
||||
|
||||
<Drawer
|
||||
isOpen={aboutDrawer.isOpen}
|
||||
onClose={aboutDrawer.onClose}
|
||||
placement="left"
|
||||
<Box
|
||||
flexShrink={2}
|
||||
bgColor={darkMode ? "#333333" : "#e8e8e8"}
|
||||
color={darkMode ? "#cccccc" : "#383838"}
|
||||
textAlign="center"
|
||||
fontSize="sm"
|
||||
>
|
||||
<AboutDrawer loadSample={handleLoadSample} darkMode={darkMode} />
|
||||
</Drawer>
|
||||
<Flex flex={1} minW={0} h="100%" direction="column" overflow="hidden">
|
||||
<HStack
|
||||
h={6}
|
||||
spacing={1}
|
||||
color="#888888"
|
||||
fontWeight="medium"
|
||||
fontSize="13px"
|
||||
px={3.5}
|
||||
flexShrink={0}
|
||||
>
|
||||
<Icon as={VscFolderOpened} fontSize="md" color="blue.500" />
|
||||
<Text>rustpad</Text>
|
||||
<Icon as={VscChevronRight} fontSize="md" />
|
||||
<Link onClick={handleCopy} color="#bbbbbb" _hover={{ color: "#ffffff" }} >
|
||||
<HStack spacing={1} >
|
||||
<Icon as={VscGist} fontSize="md" color="purple.500" />
|
||||
<Text>{id}</Text>
|
||||
<Icon as={VscLink} fontSize="md" color="grey.500" />
|
||||
</HStack>
|
||||
</Link>
|
||||
</HStack>
|
||||
<Box flex={1} minH={0}>
|
||||
<Editor
|
||||
theme={darkMode ? "vs-dark" : "vs"}
|
||||
language={language}
|
||||
options={{
|
||||
automaticLayout: true,
|
||||
fontSize: 13,
|
||||
}}
|
||||
onMount={(editor) => setEditor(editor)}
|
||||
<Flex spacing={0} px={2} alignItems="center">
|
||||
<ConnectionStatus connection={connection} />
|
||||
|
||||
<Button
|
||||
h="1.4rem"
|
||||
fontWeight="normal"
|
||||
rounded="none"
|
||||
_hover={{ bg: darkMode ? "#575759" : "gray.200" }}
|
||||
bgColor={darkMode ? "#333333" : "gray.200"}
|
||||
px={2}
|
||||
onClick={aboutDrawer.onOpen}
|
||||
>
|
||||
Rustpad
|
||||
</Button>
|
||||
|
||||
<Tooltip label="Syntax highlighting">
|
||||
<Select
|
||||
maxWidth="10em"
|
||||
size="xs"
|
||||
bgColor={darkMode ? "#3c3c3c" : "white"}
|
||||
_hover={{ bgColor: darkMode ? "#575757" : "dddddd" }}
|
||||
borderColor={darkMode ? "#3c3c3c" : "white"}
|
||||
value={language}
|
||||
onChange={(event) => handleChangeLanguage(event.target.value)}
|
||||
|
||||
>
|
||||
{languages.map((lang) => (
|
||||
<option key={lang} value={lang} style={{ color: "black" }}>
|
||||
{lang}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</Tooltip>
|
||||
<Spacer />
|
||||
<Users
|
||||
users={users}
|
||||
me={{ name, hue }}
|
||||
setName={setName}
|
||||
setHue={setHue}
|
||||
id={id}
|
||||
handleCopy={handleCopy}
|
||||
/>
|
||||
</Box>
|
||||
<DarkModeToggle />
|
||||
</Flex>
|
||||
</Box >
|
||||
<Flex flex="1 0" minH={0}>
|
||||
|
||||
<Drawer
|
||||
isOpen={aboutDrawer.isOpen}
|
||||
onClose={aboutDrawer.onClose}
|
||||
placement="left"
|
||||
>
|
||||
<AboutDrawer loadSample={handleLoadSample} />
|
||||
</Drawer>
|
||||
<Flex flex={1} minW={0} h="100%" direction="column" overflow="hidden">
|
||||
<HStack
|
||||
h={6}
|
||||
spacing={1}
|
||||
color="#888888"
|
||||
fontWeight="medium"
|
||||
fontSize="13px"
|
||||
px={3.5}
|
||||
flexShrink={0}
|
||||
>
|
||||
<Icon as={VscFolderOpened} fontSize="md" color="blue.500" />
|
||||
<Text>rustpad</Text>
|
||||
<Icon as={VscChevronRight} fontSize="md" />
|
||||
<Link onClick={handleCopy} color="#bbbbbb" _hover={{ color: "#ffffff" }} >
|
||||
<HStack spacing={1} >
|
||||
<Icon as={VscGist} fontSize="md" color="purple.500" />
|
||||
<Text>{id}</Text>
|
||||
<Icon as={VscLink} fontSize="md" color="grey.500" />
|
||||
</HStack>
|
||||
</Link>
|
||||
</HStack>
|
||||
<Box flex={1} minH={0}>
|
||||
<Editor
|
||||
theme={darkMode ? "vs-dark" : "vs"}
|
||||
language={language}
|
||||
options={{
|
||||
automaticLayout: true,
|
||||
fontSize: 13,
|
||||
}}
|
||||
onMount={(editor) => setEditor(editor)}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Footer />
|
||||
</Flex >
|
||||
<Footer />
|
||||
</Flex >
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
type DarkModeProps = {
|
||||
darkMode: boolean;
|
||||
toggle: () => unknown;
|
||||
}
|
||||
|
||||
function DarkModeToggle({ darkMode, toggle }: DarkModeProps) {
|
||||
return (
|
||||
<Tooltip label="Toggle dark mode">
|
||||
<IconButton
|
||||
aria-label="Toggle dark mode"
|
||||
size="xs"
|
||||
rounded="none"
|
||||
onClick={toggle}
|
||||
bgColor={darkMode ? "#333333" : "#e8e8e8"}
|
||||
_hover={{ bg: darkMode ? "#575757" : "gray.200" }}
|
||||
icon={darkMode ? <FaSun /> : <FaMoon />}
|
||||
/>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
type UsersProps = {
|
||||
users: Record<number, UserInfo>;
|
||||
darkMode: boolean;
|
||||
me: UserInfo;
|
||||
setName: (name: string) => unknown;
|
||||
setHue: (hue: number) => unknown;
|
||||
|
@ -315,11 +297,12 @@ type UsersProps = {
|
|||
};
|
||||
|
||||
|
||||
function Users({ users, darkMode, me, setName, setHue, id, handleCopy }: UsersProps) {
|
||||
function Users({ users, me, setName, setHue, id, handleCopy }: UsersProps) {
|
||||
const [usersIsOpen, setUsersIsOpen] = useState(false)
|
||||
const open = () => setUsersIsOpen(!usersIsOpen)
|
||||
const close = () => setUsersIsOpen(false)
|
||||
const userCount = () => Object.entries(users).length
|
||||
const darkMode = useContext(ThemeContext).darkMode;
|
||||
|
||||
return (
|
||||
<Popover
|
||||
|
@ -360,7 +343,6 @@ function Users({ users, darkMode, me, setName, setHue, id, handleCopy }: UsersPr
|
|||
me={me}
|
||||
onChangeName={(name) => name.length > 0 && setName(name)}
|
||||
onChangeColor={() => setHue(generateHue())}
|
||||
darkMode={darkMode}
|
||||
/>
|
||||
|
||||
<Heading mt={4} mb={1.5} size="sm">
|
||||
|
@ -396,11 +378,12 @@ function Users({ users, darkMode, me, setName, setHue, id, handleCopy }: UsersPr
|
|||
|
||||
type AboutBoxProps = {
|
||||
loadSample: () => unknown;
|
||||
darkMode: boolean;
|
||||
}
|
||||
|
||||
|
||||
function AboutDrawer({ darkMode, loadSample }: AboutBoxProps) {
|
||||
function AboutDrawer({ loadSample }: AboutBoxProps) {
|
||||
const darkMode = useContext(ThemeContext).darkMode;
|
||||
|
||||
return (
|
||||
<>
|
||||
<DrawerOverlay />
|
||||
|
@ -434,7 +417,7 @@ function AboutDrawer({ darkMode, loadSample }: AboutBoxProps) {
|
|||
for details.
|
||||
</Text>
|
||||
|
||||
<LoadSampleButton darkMode={darkMode} loadSample={loadSample} />
|
||||
<LoadSampleButton loadSample={loadSample} />
|
||||
|
||||
</DrawerBody>
|
||||
</DrawerContent>
|
||||
|
@ -442,9 +425,10 @@ function AboutDrawer({ darkMode, loadSample }: AboutBoxProps) {
|
|||
)
|
||||
}
|
||||
|
||||
function LoadSampleButton({ darkMode, loadSample }: AboutBoxProps) {
|
||||
function LoadSampleButton({ loadSample }: AboutBoxProps) {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure()
|
||||
const cancelRef = useRef<HTMLButtonElement>(null)
|
||||
const darkMode = useContext(ThemeContext).darkMode;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -2,10 +2,9 @@ import { Tooltip, Spinner } from "@chakra-ui/react";
|
|||
|
||||
type ConnectionStatusProps = {
|
||||
connection: "connected" | "disconnected" | "desynchronized";
|
||||
darkMode: boolean;
|
||||
};
|
||||
|
||||
function ConnectionStatus({ connection, darkMode }: ConnectionStatusProps) {
|
||||
function ConnectionStatus({ connection }: ConnectionStatusProps) {
|
||||
return (
|
||||
<Tooltip label={
|
||||
{
|
||||
|
|
26
src/Theme.tsx
Normal file
26
src/Theme.tsx
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { IconButton, Tooltip } from "@chakra-ui/react";
|
||||
import React, { useContext } from "react";
|
||||
import { FaSun, FaMoon } from "react-icons/fa";
|
||||
|
||||
|
||||
export const ThemeContext = React.createContext({
|
||||
darkMode: false,
|
||||
toggleDarkMode: () => { }
|
||||
})
|
||||
|
||||
export function DarkModeToggle() {
|
||||
const { darkMode, toggleDarkMode } = useContext(ThemeContext)
|
||||
return (
|
||||
<Tooltip label="Toggle dark mode">
|
||||
<IconButton
|
||||
aria-label="Toggle dark mode"
|
||||
size="xs"
|
||||
rounded="none"
|
||||
onClick={toggleDarkMode}
|
||||
bgColor={darkMode ? "#333333" : "#e8e8e8"}
|
||||
_hover={{ bg: darkMode ? "#575757" : "gray.200" }}
|
||||
icon={darkMode ? <FaSun /> : <FaMoon />}
|
||||
/>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
43
src/User.tsx
43
src/User.tsx
|
@ -15,39 +15,35 @@ import {
|
|||
import { FaPalette } from "react-icons/fa";
|
||||
import { VscAccount, VscClose, VscEdit } from "react-icons/vsc";
|
||||
import { UserInfo } from "./rustpad";
|
||||
import React from "react";
|
||||
import React, { useContext } from "react";
|
||||
import { ThemeContext } from "./Theme";
|
||||
|
||||
type UserProps = {
|
||||
info: UserInfo;
|
||||
darkMode: boolean;
|
||||
};
|
||||
|
||||
function makeColor(hue: number, darkMode: boolean): string {
|
||||
function makeColor(hue: number): string {
|
||||
const darkMode = useContext(ThemeContext).darkMode
|
||||
return `hsl(${hue}, 90%, ${darkMode ? "70%" : "25%"})`;
|
||||
}
|
||||
|
||||
function User({
|
||||
info,
|
||||
darkMode,
|
||||
}: UserProps) {
|
||||
function User({ name, hue }: UserInfo) {
|
||||
|
||||
return (
|
||||
<HStack>
|
||||
<Icon as={VscAccount}></Icon>
|
||||
<Text fontWeight="medium" color={makeColor(info.hue, darkMode)}>
|
||||
{info.name}
|
||||
<Text fontWeight="medium" color={makeColor(hue)}>
|
||||
{name}
|
||||
</Text>
|
||||
</HStack>
|
||||
);
|
||||
}
|
||||
|
||||
function EditableControls({ darkMode }: UserProps) {
|
||||
function EditableControls() {
|
||||
const {
|
||||
isEditing,
|
||||
getEditButtonProps,
|
||||
getCancelButtonProps,
|
||||
} = useEditableControls();
|
||||
|
||||
const darkMode = useContext(ThemeContext).darkMode;
|
||||
|
||||
return isEditing ? (
|
||||
<IconButton aria-label="cancel" colorScheme={darkMode ? "white" : "gray"} size="xs" icon={<VscClose />} {...getCancelButtonProps()} />
|
||||
) : (
|
||||
|
@ -59,17 +55,15 @@ type UserEditProps = {
|
|||
me: UserInfo;
|
||||
onChangeName: (name: string) => unknown;
|
||||
onChangeColor?: () => unknown;
|
||||
darkMode: boolean;
|
||||
}
|
||||
|
||||
function UserEdit({
|
||||
me,
|
||||
onChangeName,
|
||||
onChangeColor,
|
||||
darkMode,
|
||||
}: UserEditProps) {
|
||||
const colorScheme = darkMode ? "white" : "gray"
|
||||
|
||||
const theme = useContext(ThemeContext);
|
||||
const colorScheme = theme.darkMode ? "white" : "gray"
|
||||
|
||||
return (
|
||||
<Editable placeholder={me.name} defaultValue={me.name} submitOnBlur={true} onSubmit={onChangeName}>
|
||||
|
@ -79,17 +73,17 @@ function UserEdit({
|
|||
colorScheme={colorScheme}
|
||||
size="xxs"
|
||||
aria-label="change color"
|
||||
color={makeColor(me.hue, darkMode)}
|
||||
color={makeColor(me.hue)}
|
||||
icon={<FaPalette />}
|
||||
onClick={onChangeColor}></IconButton>
|
||||
</Tooltip>
|
||||
<EditableInput fontWeight="medium" color={makeColor(me.hue, darkMode)} textAlign="left" maxLength={32} />
|
||||
<EditableInput fontWeight="medium" color={makeColor(me.hue)} textAlign="left" maxLength={32} />
|
||||
<Tooltip label="Edit your display name">
|
||||
<EditablePreview fontWeight="medium" color={makeColor(me.hue, darkMode)} textAlign="left" />
|
||||
<EditablePreview fontWeight="medium" color={makeColor(me.hue)} textAlign="left" />
|
||||
</Tooltip>
|
||||
<YouLabel />
|
||||
<Spacer />
|
||||
<EditableControls info={me} darkMode={darkMode} />
|
||||
<EditableControls />
|
||||
</HStack >
|
||||
</Editable>
|
||||
);
|
||||
|
@ -103,17 +97,16 @@ function YouLabel() {
|
|||
return <Box {...getEditButtonProps()} textAlign="left"> {isEditing ? "" : "(you)"}</Box>
|
||||
}
|
||||
|
||||
function UserList({ users, me, onChangeName, onChangeColor, darkMode }: UserListProps) {
|
||||
function UserList({ users, me, onChangeName, onChangeColor }: UserListProps) {
|
||||
return (
|
||||
<Stack spacing={0} mb={1.5} fontSize="sm">
|
||||
{Object.entries(users).map(([id, info]) => (
|
||||
<User key={id} info={info} darkMode={darkMode} />
|
||||
<User key={id} {...info} />
|
||||
))}
|
||||
<UserEdit
|
||||
me={me}
|
||||
onChangeName={onChangeName}
|
||||
onChangeColor={onChangeColor}
|
||||
darkMode={darkMode}
|
||||
/>
|
||||
</Stack>
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue