Sfoglia il codice sorgente

move darkMode to a context instead of passing props

Jonathan Goren 3 anni fa
parent
commit
70438ee947
4 ha cambiato i file con 159 aggiunte e 157 eliminazioni
  1. 114 130
      src/App.tsx
  2. 1 2
      src/ConnectionStatus.tsx
  3. 26 0
      src/Theme.tsx
  4. 18 25
      src/User.tsx

+ 114 - 130
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)}
 
+        <Box
+          flexShrink={2}
+          bgColor={darkMode ? "#333333" : "#e8e8e8"}
+          color={darkMode ? "#cccccc" : "#383838"}
+          textAlign="center"
+          fontSize="sm"
+        >
+          <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}
             >
-              {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}>
+              Rustpad
+            </Button>
 
-        <Drawer
-          isOpen={aboutDrawer.isOpen}
-          onClose={aboutDrawer.onClose}
-          placement="left"
-        >
-          <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)}
+            <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 (
     <>

+ 1 - 2
src/ConnectionStatus.tsx

@@ -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 - 0
src/Theme.tsx

@@ -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>
+  )
+}

+ 18 - 25
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>
   )