@chakra-ui/react#useColorModeValue JavaScript Examples

The following examples show how to use @chakra-ui/react#useColorModeValue. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Container.js    From benjamincarlson.io with MIT License 6 votes vote down vote up
Container = ({ children }) => {
  const router = useRouter()
  return (
    <>
      <Link isExternal href="https://github.com/sponsors/bjcarlson42">
        <Box bgGradient='linear(to-l, #7928CA, #FF0080)'>
          <Flex justify="center" align="center" py={1} color="white">
            <GitHubIcon />
            <Text ml={2}>Sponsor Me On GitHub!</Text>
          </Flex>
        </Box>
      </Link>
      <Box h={8} bgColor={useColorModeValue("rgb(248, 250, 252)", "gray.900")} />
      <Navigation />
      <Box h={8} bgColor={useColorModeValue("rgb(248, 250, 252)", "gray.900")} />
      <Flex
        as="main"
        justifyContent="center"
        flexDirection="column"
        bg={useColorModeValue("#ffffff", "#15161a")}
        color={useColorModeValue("#000000", "#ffffff")}
      >
        {/* hero outside main Flex to avoid px */}
        {router.pathname == '/' && <Hero />}
        <Flex px={4} flexDir="column" minH="90vh">
          {children}
        </Flex>
        <Footer />
      </Flex>
    </>
  )
}
Example #2
Source File: Faq.js    From MeowForm with MIT License 6 votes vote down vote up
function Faq() {

    const textColor = useColorModeValue("gray.700", "gray.100");
	const [check] = useMediaQuery("(min-width: 1025px)");

    return (
        <div className="faq-div">
            <div className="faq-main">
                <div className="heading">
                    <Text
                        align='center'
                        color={textColor}
                        fontSize={check ? "5xl" : "3xl"}
                        fontWeight='extrabold'
                        mt={check ? "0%" : "4%"}>
                        Frequently Asked Questions (FAQ)
                    </Text>
                </div>
                <div className="faq-data">
                    {
                        FAQ_Data.map((data) => (
                            <div className="singleFaq" key={data.id}>
                                <div className="faq-question">
                                    <p><span>Q . </span>{data.question}</p>
                                </div>
                                <div className="faq-answer">
                                    <p><span>A . </span>{data.answer}</p>
                                </div>
                            </div>
                        ))
                    }
                </div>
            </div>
        </div>
    );
}
Example #3
Source File: ColorModeSwitcher.jsx    From realtime-chat-supabase-react with Apache License 2.0 6 votes vote down vote up
ColorModeSwitcher = (props) => {
  const { toggleColorMode } = useColorMode();
  const text = useColorModeValue("dark", "light");
  const SwitchIcon = useColorModeValue(FaMoon, FaSun);

  return (
    <IconButton
      size="md"
      fontSize="lg"
      aria-label={`Switch to ${text} mode`}
      variant="ghost"
      color="current"
      marginLeft="2"
      onClick={toggleColorMode}
      icon={<SwitchIcon />}
      {...props}
    />
  );
}
Example #4
Source File: ColorModeSwitcher.js    From react-sample-projects with MIT License 6 votes vote down vote up
ColorModeSwitcher = props => {
  const { toggleColorMode } = useColorMode();
  const text = useColorModeValue('dark', 'light');
  const SwitchIcon = useColorModeValue(FaMoon, FaSun);

  return (
    <IconButton
      size="md"
      fontSize="lg"
      aria-label={`Switch to ${text} mode`}
      variant="ghost"
      color="current"
      marginLeft="2"
      onClick={toggleColorMode}
      icon={<SwitchIcon />}
      {...props}
    />
  );
}
Example #5
Source File: Highlight.js    From blobs.app with MIT License 6 votes vote down vote up
export default function Highlight({ code, lang }) {
  const theme = useColorModeValue(coy, nord);
  return (
    <SyntaxHighlighter
      language={lang}
      style={{
        ...theme,
        'code[class*="language-"]': {
          ...theme['code[class*="language-"]'],
          fontSize: '15px',
        },
      }}
      customStyle={{
        marginBottom: 0,
        marginTop: 0,
        backgroundColor: 'transparent',
        padding: 0,
      }}
      wrapLines
    >
      {code}
    </SyntaxHighlighter>
  );
}
Example #6
Source File: PatternSetter.js    From blobs.app with MIT License 6 votes vote down vote up
PatternBox = ({ meta, clickHandler, isSelected }) => {
  const patternBg = useColorModeValue('A0AEC0', '4A5568');
  return (
    <Box
      as="button"
      w="60px"
      h="60px"
      mr="3"
      rounded="lg"
      borderColor={isSelected ? 'primary' : 'gray.400'}
      borderWidth="2px"
      _focus={{ outline: 0 }}
      backgroundSize="50%"
      backgroundColor="gray.100"
      backgroundPosition="center"
      _dark={{
        backgroundColor: 'gray.500',
        borderColor: isSelected ? 'primary' : 'gray.600',
      }}
      backgroundImage={`url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='${
        meta.width
      }' height='${meta.height}' viewBox='0 0 ${meta.width} ${
        meta.height
      }'%3E%3Cg fill='%23${
        isSelected ? 'd7819b' : patternBg
      }' fill-opacity='1'%3E%3Cpath fill-rule='evenodd' d='${
        meta.path
      }'/%3E%3C/g%3E%3C/svg%3E")`}
      onClick={() => clickHandler(meta.name)}
    />
  );
}
Example #7
Source File: Layout.js    From blobs.app with MIT License 6 votes vote down vote up
Layout = ({ children }) => {
  const theme = useColorModeValue('light', 'dark');
  const data = useStaticQuery(graphql`
    query SiteTitleQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `);

  return (
    <Provider store={store}>
      <Box className={theme}>
        <Container
          maxW="container.xl"
          flex="1"
          display="flex"
          flexDir="column"
          minH="100vh"
        >
          <Box as="main" flex="1" display="flex" flexDir="column">
            {children}
          </Box>
          <Footer siteTitle={data.site.siteMetadata?.title || 'Title'} />
        </Container>
      </Box>
    </Provider>
  );
}
Example #8
Source File: ThemeSwitch.js    From blobs.app with MIT License 6 votes vote down vote up
export default function ThemeSwitch() {
  const { toggleColorMode: toggleMode } = useColorMode();
  const ToggleIcon = useColorModeValue(SunIcon, MoonIcon);
  return (
    <Button
      leftIcon={<ToggleIcon fontSize="18px" />}
      variant="silent"
      aria-label="Toggle Theme"
      onClick={toggleMode}
    >
      Switch theme
    </Button>
  );
}
Example #9
Source File: useCustomColorModes.js    From scaffold-directory with MIT License 6 votes vote down vote up
useCustomColorModes = () => {
  const primaryFontColor = useColorModeValue("gray.700", "gray.200");
  const codeFontColor = primaryFontColor;
  const secondaryFontColor = useColorModeValue("gray.600", "gray.400");
  const dividerColor = useColorModeValue("gray.200", "gray.700");
  const borderColor = dividerColor;
  const codeBgColor = useColorModeValue("gray.100", "gray.900");
  const iconBgColor = codeBgColor;

  return {
    primaryFontColor,
    secondaryFontColor,
    dividerColor,
    borderColor,
    codeFontColor,
    codeBgColor,
    iconBgColor,
  };
}
Example #10
Source File: ColorModeSwitcher.jsx    From scaffold-directory with MIT License 6 votes vote down vote up
ColorModeSwitcher = () => {
  const { toggleColorMode } = useColorMode();
  const Icon = useColorModeValue(<SunIcon color="gray.400" h={4} w={4} />, <MoonIcon h={4} w={4} />);

  return (
    <Flex pos="fixed" bottom={0} right={0} p={6}>
      <Switch onChange={toggleColorMode} mr={4} align="center" />
      {Icon}
    </Flex>
  );
}
Example #11
Source File: SavedBlobs.js    From blobs.app with MIT License 5 votes vote down vote up
SavedBlobs = ({ savedBlobs = [], deleteBlob, loadBlobs }) => {
  const cardHoverBg = useColorModeValue('gray.100', 'gray.700');
  useEffect(() => {
    if (!savedBlobs) loadBlobs();
  }, [savedBlobs]);
  return (
    <Box>
      {savedBlobs?.length === 0 && (
        <Box textAlign="center">
          <Text my="20" fontSize="2xl">
            No saved blobs found!
          </Text>
        </Box>
      )}
      <SimpleGrid
        columns={{ sm: 2, md: 4 }}
        spacing="40px"
        mb="20"
        justifyContent="center"
      >
        {savedBlobs?.map((blob) => (
          <LinkBox
            // h="200"
            rounded="2xl"
            p="5"
            borderWidth="1px"
            _hover={{ boxShadow: '2xl', background: cardHoverBg }}
            role="group"
          >
            <Text
              fontSize="sm"
              display="flex"
              alignItems="center"
              justifyContent="space-between"
            >
              <LinkOverlay
                style={{ textTransform: 'uppercase', fontWeight: 600 }}
                href={blob.url}
              >
                {blob.name}
              </LinkOverlay>
              <Button
                variant="unstyled"
                visibility="hidden"
                h="auto"
                _groupHover={{ visibility: 'visible' }}
                onClick={() => {
                  deleteBlob(blob.id);
                }}
              >
                <TrashIcon color="tomato" />
              </Button>
            </Text>
            <Divider mt="4" />

            <Blob {...blob} />
          </LinkBox>
        ))}
      </SimpleGrid>
    </Box>
  );
}
Example #12
Source File: Home.js    From MeowForm with MIT License 4 votes vote down vote up
function Home(props) {
	const textColor = useColorModeValue("gray.700", "gray.100");
	const [check] = useMediaQuery("(min-width: 1025px)");

	return (
		<>
			<div>
				<Box ml='5%'>
					<Bounce top>
						<Text
							align='center'
							color={textColor}
							fontSize={check ? "5xl" : "3xl"}
							fontWeight='extrabold'
							mt={check ? "0%" : "4%"}>
							Functional Forms Solution for
						</Text>
						<Text
							align='center'
							bgGradient='linear(to-l, #ec9f05 ,#ff4e00)'
							bgClip='text'
							fontSize={check ? "7xl" : "4xl"}
							fontWeight='extrabold'
							mt={check ? "0%" : "4%"}>
							<Typewriter
								options={{
									strings: [
										"React ",
										"Flutter ",
										"Html ",
										"React Native",
										"Vue",
										"Angular",
									],
									autoStart: true,
									loop: true,
								}}
							/>
						</Text>
					</Bounce>
					<Flip top>
						<Box
							bgColor='#333'
							ml={check ? "20%" : "5%"}
							mt={check ? "8%" : "12%"}
							width={check ? "60%" : "90%"}
							borderRadius='25'>
							<Text color='#fff' padding='5%'>
								<Typewriter
									options={{
										strings: [
											`<form action="https://server.meowform.xyz/YourEmail&FormName method="post"`,
										],
										autoStart: true,
										loop: true,
									}}
								/>
							</Text>
						</Box>
						<Flex flexDirection='row' ml={check ? "40%" : "23%"}>
							<Box margin='1%'>
								<a
									rel='noreferrer'
									href='https://docs.meowform.xyz/docs/intro'
									target='_blank'>
									<Button margin='1%'> View docs</Button>
								</a>
							</Box>
							<Box margin='1%'>
								<Link to='/dashboard'>
									<Button colorScheme='orange'>
										{" "}
										Try it
									</Button>
								</Link>
							</Box>
						</Flex>
					</Flip>
					<Image
						lazyLoad={true}
						position={check ? "absolute" : "static"}
						src='https://res.cloudinary.com/dd0mtkqbr/image/upload/v1629015408/kitekat_ezvxgy.png'
						width={check ? "24%" : "40%"}
						height={check ? "8%" : "80%"}
						mt={check ? "-20%" : "5%"}
						ml={check ? "-15%" : "28%"}
						transform={check ? "rotate(60deg)" : ""}
						opacity={check ? "0.9" : "1"}></Image>
				</Box>
				<Box></Box>

				<Box mt='10%'>.</Box>
			</div>

			<div ml='25%' mt='10%'>
				.
			</div>

			<Box ml='10%' mt='5%'>
				<Flex flexDirection={check ? "row" : "column-reverse"}>
					<Image
						src='https://res.cloudinary.com/dd0mtkqbr/image/upload/v1629017773/kitekat-19_1_nsknib.png'
						width='40%'
						height='30%'
						ml={check ? "0%" : "25%"}
					/>
					<Fade right>
						<Text
							align='center'
							color={textColor}
							fontSize={check ? "5xl" : "3xl"}
							fontWeight='extrabold'
							mt={check ? "7%" : "4%"}
							ml={check ? "" : "-5%"}>
							Make backend-less forms with MeowForm and get
							<Text
								bgGradient='linear(to-l, #ec9f05 ,#ff4e00)'
								bgClip='text'>
								Unlimited Responses{" "}
							</Text>{" "}
							in your inbox .
						</Text>
					</Fade>
				</Flex>
				<Flex flexDirection={check ? "row" : "column"} mt='5%'>
					<Fade left>
						<Text
							align='center'
							color={textColor}
							fontSize={check ? "5xl" : "3xl"}
							fontWeight='extrabold'
							mt={check ? "7%" : "4%"}
							ml={check ? "" : "-5%"}>
							Choose your fontend , Use our API to handle things
							for
							<Text
								bgGradient='linear(to-l, #ec9f05 ,#ff4e00)'
								bgClip='text'>
								{" "}
								Free{" "}
							</Text>
						</Text>
					</Fade>
					<Image
						src='https://res.cloudinary.com/dd0mtkqbr/image/upload/v1629029065/kitekat-8_ein5pc.png'
						width='40%'
						height='30%'
						ml={check ? "0%" : "25%"}
					/>
				</Flex>
				<Flex flexDirection={check ? "row-reverse" : "column"} mt='5%'>
					<Fade right>
						<Text
							align='center'
							color={textColor}
							fontSize={check ? "5xl" : "3xl"}
							fontWeight='extrabold'
							mt={check ? "7%" : "4%"}
							ml={check ? "" : "-5%"}>
							Missed a response ? don't worry view all responses
							in out dashboard
							<Text
								bgGradient='linear(to-l, #ec9f05 ,#ff4e00)'
								bgClip='text'>
								{" "}
							</Text>
						</Text>
					</Fade>
					<Image
						src='https://res.cloudinary.com/dd0mtkqbr/image/upload/v1630156150/kitekat-2_kzxgrr.png'
						width='40%'
						height='30%'
						ml={check ? "0%" : "25%"}
					/>
				</Flex>
			</Box>
			<Box margin='10%'></Box>
			<Box
				margin={check ? "5%" : "1%"}
				padding={check ? "5%" : "1%"}
				alignContent='center'
				align='center'>
				<Flip top>
					<iframe
						title='demo video'
						width={check ? "640" : "300"}
						height={check ? "360" : "200"}
						align='center'
						src='https://www.loom.com/embed/c8cdc167f9b0405ca37e0b8a6f7ffe13'
						frameborder='0'
						webkitallowfullscreen
						mozallowfullscreen
						allowfullscreen='true'></iframe>
				</Flip>
				<h1 margin='15%'> Meow Form in action</h1>
			</Box>
			<div className="Reviews">
				{/* <Reviews /> */}
			</div>
			<div className="faq">
				<Faq />
			</div>
		</>
	);
}
Example #13
Source File: FormCard.js    From MeowForm with MIT License 4 votes vote down vote up
function FormCard({formName , responses ,formData ,redirectUrl ,email }) {
    const  formBackground = useColorModeValue("gray.100","gray.700");
    const [check] = useMediaQuery("(min-width: 1025px)")
    const { isOpen, onOpen, onClose } = useDisclosure()
    const [size, setSize] = React.useState("md")
    const [url, setUrl] = React.useState();
    const [edit , setEdit] = React.useState(false);
    let apiKey = process.env.REACT_APP_APIKEY ;
    let  apiUrl = process.env.REACT_APP_HOSTURL ;

    function isValidURL(string) {
        var res = string.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
        return (res !== null)
      };
      const sendResponse = async(serverUrl)=> {
        let meow = await  axios({
            method: 'post',
            url: serverUrl,
            data: {
              url: url,
              formName: formName
            }
          });

      }
    const checkUrl = () => {
        if(url === "" || url === undefined){
            toast.error(' Url not saved');
            setEdit(!edit)


        }else if(isValidURL(url)){
            let serverUrl = apiUrl + 'url/' + email + '&' + apiKey;
            sendResponse(serverUrl);
          
            toast.success('Url is saved, it will some time to reflect');

            setEdit(!edit)
        }else{
            toast.error('The url is not valid :( ');

  
        }
   
    }


    return (
       <Box  id={formName}mt="1%"    borderRadius={25}  padding="2%" display="flex" flexDirection={check ?   "row" : "column"} backgroundColor ="#fff" background={formBackground} >
          
                  <Box width="100%" ml="5%" >
                  <Flex  justifyContent="space-between"  >
                      <Text> {formName}</Text>
                      <Text> {responses} Responses</Text>
                      <Button colorScheme="orange" onClick={onOpen}> View</Button>
                   </Flex>
 
                          {/* {console.log(formData)} */}
                   </Box>
                   <Drawer onClose={onClose} isOpen={isOpen} size={check ? "xl" :"xs"}>
                     <DrawerOverlay />
                     <DrawerContent>
                       <DrawerHeader align="center"> 

                           <Text
                           margin="1%"
                           fontWeight="extraBold"
                           fontSize="3xl"
                           bgGradient="linear(to-l, #ec9f05 ,#ff4e00)"
                           bgClip="text"
                           >

                          {formName}
                           </Text>
                       <Text
                        
                       >
                         {responses} Responses

      
                        </Text>
                           </DrawerHeader>
                       <DrawerBody>
                       
                        <Box>
                
                     {formData.length > 0 &&
                     <>
                            <FormHeading obj={formData[0]}></FormHeading>
                      
                          {
                              formData.map(x=>
                              <FormData obj={x}></FormData>
                                  )
                          } 
                            
                    </>
                     }   
                     {/* <Flex>
                         <Text margin="5%">Redirect Url </Text>
                         <Text margin="5%"> { redirectUrl } </Text>
                     </Flex>  */}
                     {/* { edit && */}
                    {/* <Flex>
                      <Input placeholder={redirectUrl} isDisabled={!edit}   value={url} onChange={ (e)=>(setUrl(e.target.value))}
                      />  
                     {edit === false ?
                       <Button onClick={()=>{setEdit(!edit)}}>
                           edit
                       </Button>
                       :
                       <Button  onClick={()=>(checkUrl())}> Save</Button>
                     }
                    </Flex> */}
                     {/* }  */}
                           {/* <Text> * you one need Redirect url if you are just using html css , check docs here </Text>  */}
                        </Box>
                        <Box>
                      
                          
                        </Box>
                       </DrawerBody>
                     </DrawerContent>
                   </Drawer>



       </Box>
    );
}
Example #14
Source File: SubmissionReviewView.jsx    From scaffold-directory with MIT License 4 votes vote down vote up
export default function SubmissionReviewView({ userProvider }) {
  const address = useUserAddress(userProvider);
  const [challenges, setChallenges] = React.useState([]);
  const [isLoadingChallenges, setIsLoadingChallenges] = React.useState(true);
  const [draftBuilds, setDraftBuilds] = React.useState([]);
  const [isLoadingDraftBuilds, setIsLoadingDraftBuilds] = React.useState(true);
  const toast = useToast({ position: "top", isClosable: true });
  const toastVariant = useColorModeValue("subtle", "solid");
  const { secondaryFontColor } = useCustomColorModes();

  const fetchSubmittedChallenges = useCallback(async () => {
    setIsLoadingChallenges(true);
    let fetchedChallenges;
    try {
      fetchedChallenges = await getSubmittedChallenges(address);
    } catch (error) {
      toast({
        description: "There was an error getting the submitted challenges. Please try again",
        status: "error",
        variant: toastVariant,
      });
      setIsLoadingChallenges(false);
      return;
    }
    setChallenges(fetchedChallenges.sort(bySubmittedTimestamp));
    setIsLoadingChallenges(false);
  }, [address, toastVariant, toast]);

  const fetchSubmittedBuilds = useCallback(async () => {
    setIsLoadingDraftBuilds(true);
    let fetchedDraftBuilds;
    try {
      fetchedDraftBuilds = await getDraftBuilds(address);
    } catch (error) {
      toast({
        description: "There was an error getting the draft builds. Please try again",
        status: "error",
        variant: toastVariant,
      });
      setIsLoadingDraftBuilds(false);
      return;
    }
    setDraftBuilds(fetchedDraftBuilds.sort(bySubmittedTimestamp));
    setIsLoadingDraftBuilds(false);
  }, [address, toastVariant, toast]);

  useEffect(() => {
    if (!address) {
      return;
    }
    fetchSubmittedChallenges();
    // eslint-disable-next-line
  }, [address]);

  useEffect(() => {
    if (!address) {
      return;
    }
    fetchSubmittedBuilds();
    // eslint-disable-next-line
  }, [address]);

  const handleSendChallengeReview = reviewType => async (userAddress, challengeId, comment) => {
    let signMessage;
    try {
      signMessage = await getChallengeReviewSignMessage(address, userAddress, challengeId, reviewType);
    } catch (error) {
      toast({
        description: " Sorry, the server is overloaded. ???",
        status: "error",
        variant: toastVariant,
      });
      return;
    }

    let signature;
    try {
      signature = await userProvider.send("personal_sign", [signMessage, address]);
    } catch (error) {
      toast({
        description: "Couldn't get a signature from the Wallet",
        status: "error",
        variant: toastVariant,
      });
      console.error(error);
      return;
    }

    try {
      await patchChallengeReview(address, signature, { userAddress, challengeId, newStatus: reviewType, comment });
    } catch (error) {
      if (error.status === 401) {
        toast({
          status: "error",
          description: "Submission Error. You don't have the required role.",
          variant: toastVariant,
        });
        return;
      }
      toast({
        status: "error",
        description: "Submission Error. Please try again.",
        variant: toastVariant,
      });
      return;
    }
    toast({
      description: "Review submitted successfully",
      status: "success",
      variant: toastVariant,
    });
    fetchSubmittedChallenges();
  };

  const handleSendBuildReview = reviewType => async (userAddress, buildId) => {
    let signMessage;
    try {
      signMessage = await getBuildReviewSignMessage(address, buildId, reviewType);
    } catch (error) {
      toast({
        description: " Sorry, the server is overloaded. ???",
        status: "error",
        variant: toastVariant,
      });
      return;
    }

    let signature;
    try {
      signature = await userProvider.send("personal_sign", [signMessage, address]);
    } catch (error) {
      toast({
        description: "Couldn't get a signature from the Wallet",
        status: "error",
        variant: toastVariant,
      });
      return;
    }

    try {
      await patchBuildReview(address, signature, { userAddress, buildId, newStatus: reviewType });
    } catch (error) {
      if (error.status === 401) {
        toast({
          status: "error",
          description: "Submission Error. You don't have the required role.",
          variant: toastVariant,
        });
        return;
      }
      toast({
        status: "error",
        description: "Submission Error. Please try again.",
        variant: toastVariant,
      });
      return;
    }

    toast({
      description: "Review submitted successfully",
      status: "success",
      variant: toastVariant,
    });
    fetchSubmittedBuilds();
  };

  return (
    <Container maxW="container.lg">
      <Container maxW="container.md" centerContent>
        <Heading as="h1">Review Submissions</Heading>
        <Text color={secondaryFontColor}>Pending submissions to validate.</Text>
        <Text color={secondaryFontColor} mb="6">
          Check our{" "}
          <Link href={RUBRIC_URL} color="teal.500" isExternal>
            Grading Rubric
          </Link>
          .
        </Text>
      </Container>
      <Heading as="h2" size="lg" mt={6} mb={4}>
        Challenges
      </Heading>
      <Box overflowX="auto">
        {isLoadingChallenges ? (
          <ChallengesTableSkeleton />
        ) : (
          <Table>
            <Thead>
              <Tr>
                <Th>Builder</Th>
                <Th>Challenge</Th>
                <Th>Submitted time</Th>
                <Th>Actions</Th>
              </Tr>
            </Thead>
            <Tbody>
              {!challenges || challenges.length === 0 ? (
                <Tr>
                  <Td colSpan={6}>
                    <Text color={secondaryFontColor} textAlign="center" mb={4}>
                      <Icon as={HeroIconInbox} w={6} h={6} color={secondaryFontColor} mt={6} mb={4} />
                      <br />
                      All challenges have been reviewed
                    </Text>
                  </Td>
                </Tr>
              ) : (
                challenges.map(challenge => (
                  <ChallengeReviewRow
                    key={`${challenge.userAddress}_${challenge.id}`}
                    challenge={challenge}
                    isLoading={isLoadingChallenges}
                    approveClick={handleSendChallengeReview("ACCEPTED")}
                    rejectClick={handleSendChallengeReview("REJECTED")}
                    userProvider={userProvider}
                  />
                ))
              )}
            </Tbody>
          </Table>
        )}
      </Box>
      <Heading as="h2" size="lg" mt={6} mb={4}>
        Builds
      </Heading>
      <Box overflowX="auto">
        {isLoadingDraftBuilds ? (
          <BuildsTableSkeleton />
        ) : (
          <Table mb={4}>
            <Thead>
              <Tr>
                <Th>Builder</Th>
                <Th>Build Name</Th>
                <Th>Description</Th>
                <Th>Branch URL</Th>
                <Th>Submitted time</Th>
                <Th>Actions</Th>
              </Tr>
            </Thead>
            <Tbody>
              {!draftBuilds || draftBuilds.length === 0 ? (
                <Tr>
                  <Td colSpan={5}>
                    <Text color={secondaryFontColor} textAlign="center" mb={4}>
                      <Icon as={HeroIconInbox} w={6} h={6} color={secondaryFontColor} mt={6} mb={4} />
                      <br />
                      All builds have been reviewed
                    </Text>
                  </Td>
                </Tr>
              ) : (
                draftBuilds.map(build => (
                  <BuildReviewRow
                    key={`${build.userAddress}_${build.id}`}
                    build={build}
                    isLoading={isLoadingDraftBuilds}
                    approveClick={handleSendBuildReview("ACCEPTED")}
                    rejectClick={handleSendBuildReview("REJECTED")}
                  />
                ))
              )}
            </Tbody>
          </Table>
        )}
      </Box>
    </Container>
  );
}
Example #15
Source File: BuilderProfileView.jsx    From scaffold-directory with MIT License 4 votes vote down vote up
export default function BuilderProfileView({ serverUrl, mainnetProvider, address, userProvider, userRole }) {
  const { builderAddress } = useParams();
  const { primaryFontColor, secondaryFontColor, borderColor, iconBgColor } = useCustomColorModes();
  const [builder, setBuilder] = useState();
  const [challengeEvents, setChallengeEvents] = useState([]);
  const [isLoadingBuilder, setIsLoadingBuilder] = useState(false);
  const [isBuilderOnBg, setIsBuilderOnBg] = useState(false);
  const [isLoadingTimestamps, setIsLoadingTimestamps] = useState(false);
  const toast = useToast({ position: "top", isClosable: true });
  const toastVariant = useColorModeValue("subtle", "solid");
  const challenges = builder?.challenges ? Object.entries(builder.challenges) : undefined;
  const acceptedChallenges = getAcceptedChallenges(builder?.challenges);
  const isMyProfile = builderAddress === address;

  const fetchBuilder = async () => {
    setIsLoadingBuilder(true);
    const fetchedBuilder = await axios.get(serverUrl + `/builders/${builderAddress}`);
    setBuilder(fetchedBuilder.data);

    try {
      await axios.get(bgBackendUrl + `/builders/${builderAddress}`);
    } catch (e) {
      // Builder Not found in BG
      setIsLoadingBuilder(false);
      return;
    }

    setIsBuilderOnBg(true);
    setIsLoadingBuilder(false);
  };

  useEffect(() => {
    fetchBuilder();
    // eslint-disable-next-line
  }, [builderAddress]);

  useEffect(() => {
    if (!builderAddress) {
      return;
    }

    async function fetchChallengeEvents() {
      setIsLoadingTimestamps(true);
      try {
        const fetchedChallengeEvents = await getChallengeEventsForUser(builderAddress);
        setChallengeEvents(fetchedChallengeEvents.sort(byTimestamp).reverse());
        setIsLoadingTimestamps(false);
      } catch (error) {
        toast({
          description: "Can't get challenges metadata. Please try again",
          status: "error",
          variant: toastVariant,
        });
      }
    }
    fetchChallengeEvents();
    // eslint-disable-next-line
  }, [builderAddress]);

  return (
    <Container maxW="container.xl">
      <SimpleGrid gap={14} columns={{ base: 1, xl: 4 }}>
        <GridItem colSpan={1}>
          <BuilderProfileCard
            builder={builder}
            mainnetProvider={mainnetProvider}
            isMyProfile={isMyProfile}
            userProvider={userProvider}
            fetchBuilder={fetchBuilder}
            userRole={userRole}
          />
        </GridItem>
        {isBuilderOnBg ? (
          <GridItem colSpan={{ base: 1, xl: 3 }}>
            <Box borderColor={borderColor} borderWidth={1} p={5}>
              <Flex direction="column" align="center" justify="center">
                <Image src="/assets/bg.png" mb={3} />
                <Text mb={3} fontSize="lg" fontWeight="bold">
                  This builder has upgraded to BuidlGuidl.
                </Text>
                <Button as={Link} href={`${BG_FRONTEND_URL}/builders/${builderAddress}`} isExternal colorScheme="blue">
                  View their profile on Buidlguidl
                </Button>
              </Flex>
            </Box>
          </GridItem>
        ) : (
          <GridItem colSpan={{ base: 1, xl: 3 }}>
            <HStack spacing={4} mb={8}>
              <Flex borderRadius="lg" borderColor={borderColor} borderWidth={1} p={4} w="full" justify="space-between">
                <Flex bg={iconBgColor} borderRadius="lg" w={12} h={12} justify="center" align="center">
                  <InfoOutlineIcon w={5} h={5} />
                </Flex>
                <div>
                  <Text fontSize="xl" fontWeight="medium" textAlign="right">
                    {acceptedChallenges.length}
                  </Text>
                  <Text fontSize="sm" color={secondaryFontColor} textAlign="right">
                    challenges completed
                  </Text>
                </div>
              </Flex>
              <Flex borderRadius="lg" borderColor={borderColor} borderWidth={1} p={4} w="full" justify="space-between">
                <Flex bg={iconBgColor} borderRadius="lg" w={12} h={12} justify="center" align="center">
                  <InfoOutlineIcon w={5} h={5} />
                </Flex>
                <div>
                  <Text fontSize="xl" fontWeight="medium" textAlign="right">
                    {builder?.function ? (
                      <Tag colorScheme={userFunctionDescription[builder?.function].colorScheme} variant="solid">
                        {userFunctionDescription[builder?.function].label}
                      </Tag>
                    ) : (
                      "-"
                    )}
                  </Text>
                  <Text fontSize="sm" color={secondaryFontColor} textAlign="right">
                    Role
                  </Text>
                </div>
              </Flex>
            </HStack>
            <Flex mb={4}>
              <Text fontSize="2xl" fontWeight="bold">
                Challenges
              </Text>
              <Spacer />
            </Flex>
            {isLoadingBuilder && <BuilderProfileChallengesTableSkeleton />}
            {!isLoadingBuilder &&
              (challenges ? (
                <Box overflowX="auto">
                  <Table>
                    {isMyProfile && (
                      <TableCaption>
                        <Button as={RouteLink} colorScheme="blue" to="/">
                          Start a challenge
                        </Button>
                      </TableCaption>
                    )}
                    <Thead>
                      <Tr>
                        <Th>Name</Th>
                        <Th>Contract</Th>
                        <Th>Live Demo</Th>
                        <Th>Updated</Th>
                        <Th>Status</Th>
                      </Tr>
                    </Thead>
                    <Tbody>
                      {challenges.map(([challengeId, lastSubmission]) => {
                        if (!challengeInfo[challengeId]) {
                          return null;
                        }
                        const lastEventForChallenge = challengeEvents.filter(
                          event => event.payload.challengeId === challengeId,
                        )[0];
                        return (
                          <Tr key={challengeId}>
                            <Td>
                              <Link as={RouteLink} to={`/challenge/${challengeId}`} fontWeight="700" color="teal.500">
                                {challengeInfo[challengeId].label}
                              </Link>
                            </Td>
                            <Td>
                              <Link
                                // Legacy branchUrl
                                href={lastSubmission.contractUrl || lastSubmission.branchUrl}
                                color="teal.500"
                                target="_blank"
                                rel="noopener noreferrer"
                              >
                                Code
                              </Link>
                            </Td>
                            <Td>
                              <Link
                                href={lastSubmission.deployedUrl}
                                color="teal.500"
                                target="_blank"
                                rel="noopener noreferrer"
                              >
                                Demo
                              </Link>
                            </Td>
                            <Td>
                              {isLoadingTimestamps ? (
                                <SkeletonText noOfLines={1} />
                              ) : (
                                <DateWithTooltip timestamp={lastEventForChallenge?.timestamp} />
                              )}
                            </Td>
                            <Td>
                              <ChallengeStatusTag
                                status={lastSubmission.status}
                                comment={lastSubmission.reviewComment}
                                autograding={lastSubmission.autograding}
                              />
                            </Td>
                          </Tr>
                        );
                      })}
                    </Tbody>
                  </Table>
                </Box>
              ) : (
                <Flex
                  justify="center"
                  align="center"
                  borderRadius="lg"
                  borderColor={borderColor}
                  borderWidth={1}
                  py={36}
                  w="full"
                >
                  {isMyProfile ? (
                    <Box maxW="xs" textAlign="center">
                      <Text fontWeight="medium" color={primaryFontColor} mb={2}>
                        Start a new challenge
                      </Text>
                      <Text color={secondaryFontColor} mb={4}>
                        Show off your skills. Learn everything you need to build on Ethereum!
                      </Text>
                      <Button as={RouteLink} colorScheme="blue" to="/">
                        Start a challenge
                      </Button>
                    </Box>
                  ) : (
                    <Box maxW="xs" textAlign="center">
                      <Text color={secondaryFontColor} mb={4}>
                        This builder hasn't completed any challenges.
                      </Text>
                    </Box>
                  )}
                </Flex>
              ))}
          </GridItem>
        )}
      </SimpleGrid>
    </Container>
  );
}
Example #16
Source File: Header.jsx    From scaffold-directory with MIT License 4 votes vote down vote up
export default function Header({
  injectedProvider,
  userRole,
  address,
  mainnetProvider,
  userProvider,
  loadWeb3Modal,
  logoutOfWeb3Modal,
  setUserRole,
}) {
  const { secondaryFontColor, borderColor } = useCustomColorModes();
  const primaryColorString = useColorModeValue("var(--chakra-colors-gray-700)", "var(--chakra-colors-gray-200)");
  const isSignerProviderConnected =
    injectedProvider && injectedProvider.getSigner && injectedProvider.getSigner()._isSigner;
  const userIsRegistered = userRole && USER_ROLES.anonymous !== userRole;

  return (
    <Box
      borderBottom="1px"
      borderColor={borderColor}
      mb={10}
      px={{ base: 4, lg: 8 }}
      h={{ base: userIsRegistered ? "120px" : "80px", lg: "80px" }}
    >
      {ENVIRONMENT !== "production" && (
        <Box pos="fixed" p="2px" fontSize={14} w="100%" bgColor="yellow.200" left={0} textAlign="center">
          Working on a {ENVIRONMENT} environment.
        </Box>
      )}
      <Flex
        align={{ base: userIsRegistered ? "start" : "center", lg: "center" }}
        h="full"
        fontWeight="semibold"
        pos="relative"
      >
        <Flex shrink={0} mr={9} mt={{ base: userIsRegistered ? 5 : 0, lg: 0 }}>
          <NavLink to="/" exact>
            <span role="img" aria-label="castle icon">
              ?‍♀️
            </span>{" "}
            <chakra.strong display={{ base: "none", md: "inline-block" }}>SpeedRunEthereum.com</chakra.strong>
            <chakra.strong display={{ base: "inline-block", md: "none" }}>
              {isSignerProviderConnected ? "SRE" : "SpeedRunEthereum.com"}
            </chakra.strong>
          </NavLink>
        </Flex>
        <HStack
          as="ul"
          mr={{ base: 0, lg: 6 }}
          style={{ listStyle: "none" }}
          spacing={{ base: 6, lg: 9 }}
          pos={{ base: "absolute", lg: "static" }}
          justifyContent={{ base: "center", lg: "left" }}
          top="80px"
          left={0}
        >
          {userRole && USER_ROLES.anonymous !== userRole && (
            <chakra.li key="/portfolio" color={secondaryFontColor} _hover={{ color: primaryColorString }}>
              <NavLink
                to="/portfolio"
                isActive={(match, location) => location.pathname.includes("/builders/")}
                activeStyle={{
                  color: primaryColorString,
                }}
              >
                Portfolio
              </NavLink>
            </chakra.li>
          )}
          {/* ToDo. At least Builder */}
          {(USER_ROLES.builder === userRole || USER_ROLES.admin === userRole) && (
            <>
              <chakra.li key="/builders" color={secondaryFontColor} _hover={{ color: primaryColorString }}>
                <NavLink
                  to="/builders"
                  exact
                  activeStyle={{
                    color: primaryColorString,
                  }}
                >
                  Builders
                </NavLink>
              </chakra.li>
            </>
          )}
          {USER_ROLES.admin === userRole && (
            <>
              <chakra.li key="/submission-review" color={secondaryFontColor} _hover={{ color: primaryColorString }}>
                <NavLink
                  to="/submission-review"
                  exact
                  activeStyle={{
                    color: primaryColorString,
                  }}
                >
                  Review Submissions
                </NavLink>
              </chakra.li>
              <chakra.li key="/activity" color={secondaryFontColor} _hover={{ color: primaryColorString }}>
                <NavLink
                  to="/activity"
                  exact
                  activeStyle={{
                    color: primaryColorString,
                  }}
                >
                  Activity
                </NavLink>
              </chakra.li>
            </>
          )}
        </HStack>
        <Spacer />
        <Box mt={{ base: userIsRegistered ? 3 : 0, lg: 0 }}>
          <Account
            address={address}
            connectText="Connect Wallet"
            ensProvider={mainnetProvider}
            isWalletConnected={isSignerProviderConnected}
            loadWeb3Modal={loadWeb3Modal}
            logoutOfWeb3Modal={() => {
              logoutOfWeb3Modal();
              setUserRole(null);
            }}
            setUserRole={setUserRole}
            userProvider={userProvider}
            userRole={userRole}
          />
        </Box>
      </Flex>
    </Box>
  );
}
Example #17
Source File: BuilderProfileCard.jsx    From scaffold-directory with MIT License 4 votes vote down vote up
BuilderProfileCard = ({ builder, mainnetProvider, isMyProfile, userProvider, fetchBuilder, userRole }) => {
  const address = useUserAddress(userProvider);
  const ens = useDisplayAddress(mainnetProvider, builder?.id);
  const [updatedSocials, setUpdatedSocials] = useState({});
  const [isUpdatingReachedOutFlag, setIsUpdatingReachedOutFlag] = useState(false);
  const [isUpdatingSocials, setIsUpdatingSocials] = useState(false);
  const { isOpen, onOpen, onClose } = useDisclosure();
  const { hasCopied, onCopy } = useClipboard(builder?.id);
  const { borderColor, secondaryFontColor } = useCustomColorModes();
  const shortAddress = ellipsizedAddress(builder?.id);
  const hasEns = ens !== shortAddress;

  const toast = useToast({ position: "top", isClosable: true });
  const toastVariant = useColorModeValue("subtle", "solid");

  const joinedDate = new Date(builder?.creationTimestamp);
  const joinedDateDisplay = joinedDate.toLocaleString("default", { month: "long" }) + " " + joinedDate.getFullYear();

  // INFO: conditional chaining and coalescing didn't work when also checking the length
  const hasProfileLinks = builder?.socialLinks ? Object.keys(builder.socialLinks).length !== 0 : false;

  const isAdmin = userRole === USER_ROLES.admin;

  useEffect(() => {
    if (builder) {
      setUpdatedSocials(builder.socialLinks ?? {});
    }
  }, [builder]);

  const handleUpdateSocials = async () => {
    setIsUpdatingSocials(true);

    // Avoid sending socials with empty strings.
    const socialLinkCleaned = Object.fromEntries(Object.entries(updatedSocials).filter(([_, value]) => !!value));

    const invalidSocials = validateSocials(socialLinkCleaned);
    if (invalidSocials.length !== 0) {
      toast({
        description: `The usernames for the following socials are not correct: ${invalidSocials
          .map(([social]) => social)
          .join(", ")}`,
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingSocials(false);
      return;
    }

    let signMessage;
    try {
      signMessage = await getUpdateSocialsSignMessage(address);
    } catch (error) {
      toast({
        description: " Sorry, the server is overloaded. ???",
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingSocials(false);
      return;
    }

    let signature;
    try {
      signature = await userProvider.send("personal_sign", [signMessage, address]);
    } catch (error) {
      toast({
        description: "Couldn't get a signature from the Wallet",
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingSocials(false);
      return;
    }

    try {
      await postUpdateSocials(address, signature, socialLinkCleaned);
    } catch (error) {
      if (error.status === 401) {
        toast({
          status: "error",
          description: "Access error",
          variant: toastVariant,
        });
        setIsUpdatingSocials(false);
        return;
      }
      toast({
        status: "error",
        description: "Can't update your socials. Please try again.",
        variant: toastVariant,
      });
      setIsUpdatingSocials(false);
      return;
    }

    toast({
      description: "Your social links have been updated",
      status: "success",
      variant: toastVariant,
    });
    fetchBuilder();
    setIsUpdatingSocials(false);
    onClose();
  };

  const handleUpdateReachedOutFlag = async reachedOut => {
    setIsUpdatingReachedOutFlag(true);

    let signMessage;
    try {
      signMessage = await getUpdateReachedOutFlagSignMessage(builder.id, reachedOut);
    } catch (error) {
      toast({
        description: " Sorry, the server is overloaded. ???",
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingReachedOutFlag(false);
      return;
    }

    let signature;
    try {
      signature = await userProvider.send("personal_sign", [signMessage, address]);
    } catch (error) {
      toast({
        description: "Couldn't get a signature from the Wallet",
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingReachedOutFlag(false);
      return;
    }

    try {
      await postUpdateReachedOutFlag(address, builder.id, reachedOut, signature);
    } catch (error) {
      if (error.status === 401) {
        toast({
          status: "error",
          description: "Access error",
          variant: toastVariant,
        });
        setIsUpdatingReachedOutFlag(false);
        return;
      }
      toast({
        status: "error",
        description: "Can't update the reached out flag. Please try again.",
        variant: toastVariant,
      });
      setIsUpdatingReachedOutFlag(false);
      return;
    }

    toast({
      description: 'Updated "reached out" flag successfully',
      status: "success",
      variant: toastVariant,
    });
    fetchBuilder();
    setIsUpdatingReachedOutFlag(false);
  };

  return (
    <>
      <BuilderProfileCardSkeleton isLoaded={!!builder}>
        {() => (
          /* delay execution */
          <Flex
            borderRadius="lg"
            borderColor={borderColor}
            borderWidth={1}
            justify={{ base: "space-around", xl: "center" }}
            direction={{ base: "row", xl: "column" }}
            p={4}
            pb={6}
            maxW={{ base: "full", lg: "50%", xl: 60 }}
            margin="auto"
          >
            <Link as={RouteLink} to={`/builders/${builder.id}`}>
              <QRPunkBlockie
                withQr={false}
                address={builder.id?.toLowerCase()}
                w={52}
                borderRadius="lg"
                margin="auto"
              />
            </Link>
            <Flex alignContent="center" direction="column" mt={4}>
              {hasEns ? (
                <>
                  <Text fontSize="2xl" fontWeight="bold" textAlign="center">
                    {ens}
                  </Text>
                  <Text textAlign="center" mb={4} color={secondaryFontColor}>
                    {shortAddress}{" "}
                    <Tooltip label={hasCopied ? "Copied!" : "Copy"} closeOnClick={false}>
                      <CopyIcon cursor="pointer" onClick={onCopy} />
                    </Tooltip>
                  </Text>
                </>
              ) : (
                <Text fontSize="2xl" fontWeight="bold" textAlign="center" mb={8}>
                  {shortAddress}{" "}
                  <Tooltip label={hasCopied ? "Copied!" : "Copy"} closeOnClick={false}>
                    <CopyIcon cursor="pointer" onClick={onCopy} />
                  </Tooltip>
                </Text>
              )}
              {isAdmin && (
                <Center mb={4}>
                  {builder.reachedOut ? (
                    <Badge variant="outline" colorScheme="green" alignSelf="center">
                      Reached Out
                    </Badge>
                  ) : (
                    <Button
                      colorScheme="green"
                      size="xs"
                      onClick={() => handleUpdateReachedOutFlag(true)}
                      isLoading={isUpdatingReachedOutFlag}
                      alignSelf="center"
                    >
                      Mark as reached out
                    </Button>
                  )}
                </Center>
              )}
              <Divider mb={6} />
              {hasProfileLinks ? (
                <Flex mb={4} justifyContent="space-evenly" alignItems="center">
                  {Object.entries(builder.socialLinks)
                    .sort(bySocialWeight)
                    .map(([socialId, socialValue]) => (
                      <SocialLink id={socialId} value={socialValue} />
                    ))}
                </Flex>
              ) : (
                isMyProfile && (
                  <Alert mb={3} status="warning">
                    <Text style={{ fontSize: 11 }}>
                      You haven't set your socials{" "}
                      <Tooltip label="It's our way of reaching out to you. We could sponsor you an ENS, offer to be part of a build or set up an ETH stream for you.">
                        <QuestionOutlineIcon />
                      </Tooltip>
                    </Text>
                  </Alert>
                )
              )}
              {isMyProfile && (
                <Button mb={3} size="xs" variant="outline" onClick={onOpen}>
                  Update socials
                </Button>
              )}
              <Text textAlign="center" color={secondaryFontColor}>
                Joined {joinedDateDisplay}
              </Text>
            </Flex>
          </Flex>
        )}
      </BuilderProfileCardSkeleton>
      <Modal isOpen={isOpen} onClose={onClose}>
        <ModalOverlay />
        <ModalContent>
          <ModalHeader>Update your socials</ModalHeader>
          <ModalCloseButton />
          <ModalBody p={6}>
            {Object.entries(socials).map(([socialId, socialData]) => (
              <FormControl id="socialId" key={socialId} mb={3}>
                <FormLabel htmlFor={socialId} mb={0}>
                  <strong>{socialData.label}:</strong>
                </FormLabel>
                <Input
                  type="text"
                  name={socialId}
                  value={updatedSocials[socialId] ?? ""}
                  placeholder={socialData.placeholder}
                  onChange={e => {
                    const value = e.target.value;
                    setUpdatedSocials(prevSocials => ({
                      ...prevSocials,
                      [socialId]: value,
                    }));
                  }}
                />
              </FormControl>
            ))}
            <Button colorScheme="blue" onClick={handleUpdateSocials} isLoading={isUpdatingSocials} isFullWidth mt={4}>
              Update
            </Button>
          </ModalBody>
        </ModalContent>
      </Modal>
    </>
  );
}
Example #18
Source File: Blob.js    From blobs.app with MIT License 4 votes vote down vote up
Blob = ({
  size,
  isOutline,
  type,
  svgPath,
  color,
  colors,
  image,
  pattern,
}) => {
  const ref = useRef(null);
  const [imgLoaded, setImgLoaded] = useState(false);
  const pattenBgColor = useColorModeValue('#d1d8e0', '#6c7c93');

  const props = {
    fill: color,
  };
  if (type === 'gradient') {
    props.fill = 'url(#gradient)';
  }
  if (isOutline) {
    props.strokeWidth = '7px';
    props.fill = 'none';
    props.stroke = color;
  }
  if (type === 'gradient' && isOutline) {
    props.stroke = 'url(#gradient)';
  }
  if (!svgPath) {
    return (
      <Flex justify="center" alignItems="center" h="100%">
        <Spinner />
      </Flex>
    );
  }

  return (
    <svg
      viewBox={`0 0 ${size} ${size}`}
      xmlns="http://www.w3.org/2000/svg"
      xmlnsXlink="http://www.w3.org/1999/xlink"
      width="100%"
      id="blobSvg"
      ref={ref}
    >
      {type === 'solid' && <path id="blob" d={svgPath} {...props} />}
      {type === 'gradient' && (
        <>
          <defs>
            <linearGradient id="gradient" x1="0%" y1="0%" x2="0%" y2="100%">
              <stop offset="0%" style={{ stopColor: colors[0] }} />
              <stop offset="100%" style={{ stopColor: colors[1] }} />
            </linearGradient>
          </defs>
          <path id="blob" d={svgPath} {...props} />
        </>
      )}
      {type === 'pattern' && (
        <>
          <defs>
            <pattern
              id="pattern"
              x="0"
              y="0"
              width={Patterns[pattern].width}
              height={Patterns[pattern].height}
              patternUnits="userSpaceOnUse"
              fill={pattenBgColor}
            >
              <path d={Patterns[pattern].path} />
            </pattern>
          </defs>
          <path id="blob" d={svgPath} {...props} fill="url(#pattern)" />
        </>
      )}

      {type === 'image' && (
        <>
          <defs>
            <clipPath id="shape">
              <path id="blob" d={svgPath} {...props} />
            </clipPath>
          </defs>
          {!imgLoaded && (
            <image
              x="0"
              y="0"
              width="100%"
              height="100%"
              clipPath="url(#shape)"
              xlinkHref={LoadingImg}
              preserveAspectRatio="none"
            />
          )}
          <image
            x="0"
            y="0"
            width="100%"
            height="100%"
            clipPath="url(#shape)"
            xlinkHref={image}
            preserveAspectRatio="none"
            onLoad={() => {
              setImgLoaded(true);
            }}
          />
        </>
      )}
    </svg>
  );
}
Example #19
Source File: index.js    From benjamincarlson.io with MIT License 4 votes vote down vote up
export default function Index() {
  const { colorMode } = useColorMode()

  const colorSecondary = {
    light: 'gray.600',
    dark: 'gray.400'
  }

  const iconColor = {
    light: 'gray.600',
    dark: 'gray.300'
  }

  const linkColor = {
    light: 'blue.400',
    dark: 'blue.600'
  }

  return (
    <>
      <NextSeo
        title={title}
        description={description}
        canonical={url}
        openGraph={{
          url,
          title,
          description
        }}
      />
      <Container>
        <Flex
          flexDirection="column"
          maxWidth="1000px"
          alignSelf={[null, "center"]}
        >
          {/* hero is defined inside of components/Container.js which allows it to have a different bg color without applying p to a bunch of tags */}
          <motion.div
            initial={{ y: -20, opacity: 0 }}
            animate={{ y: 0, opacity: 1 }}
            transition={{ duration: .7, delay: 2 }}
          >
            <Box as="section" mt={10} mb={20}>
              <Heading letterSpacing="tight" mt={8} size="lg" fontWeight={700} as="h2" mb={4}>About Me</Heading>
              <Text color={colorSecondary[colorMode]}>Hi everyone ?, I'm Benjamin Carlson. I go to <Link color="blue.500" href="https://www2.ccsu.edu/" isExternal>Central Connecticut State University</Link> where I study computer science and mathematics. My personal website is where I showcase my projects, writing, statistics, experience, and more. It also serves as a sandbox to play around with new technologies, as seen by the <Link href="https://github.com/bjcarlson42/benjamincarlson.io#overview" color={linkColor[colorMode]} isExternal>evolution</Link> of this website! Feel free to reach out via email or any social media.</Text>
            </Box>

            <Box as="section" mt={10} mb={20}>
              <Heading letterSpacing="tight" mt={8} size="lg" fontWeight={700} as="h2" mb={4}>Featured Projects ?‍?</Heading>
              <SimpleGrid minChildWidth="300px" spacing="40px">
                <ProjectCard
                  title="coffeeclass.io"
                  description="coffeeclass.io is a tutorial website I started to teach programming and computer science skills in a fun and easy to learn manner."
                  repoHref="https://github.com/carlson-technologies/coffeeclass.io"
                  demoHref="https://www.coffeeclass.io?utm_source=website&utm_campaign=benjamincarlson.io"
                  languageColor="#2b7489"
                  language="TypeScript"
                />
                <ProjectCard
                  title="benjamincarlson.io"
                  description="This website is a personal website I built to showcase my projects and experience."
                  repoHref="https://github.com/bjcarlson42/benjamincarlson.io"
                  demoHref="https://benjamincarlson.io"
                  languageColor="#f1e05a"
                  language="JavaScript"
                />
                <ProjectCard
                  title="Word Of The Day App"
                  description="A word of the day app built using Google's Flutter - a cross platform mobile app framework. View current and past words and save your favorites!"
                  repoHref="https://github.com/bjcarlson42/wotd"
                  youtubeId="https://youtu.be/17wMTF_bnnc"
                  languageColor="#00B4AB"
                  language="Dart"
                />
              </SimpleGrid>
            </Box>

            <Box as="section" mt={10} mb={20}>
              <Heading letterSpacing="tight" mt={8} mb={4} size="lg" fontWeight={700} as="h2">Publications ?</Heading>
              <Text color={colorSecondary[colorMode]}>I began writing about programming back in 2019 on my first blog that is no longer alive. Since then I have expanded to different media outlets and covered a variety of topics from programming, to productivity, to business.</Text>
              {/* <Flex align="center" mt={4}> */}
              <SimpleGrid minChildWidth="200px" spacing="20px" my={10}>
                <Flex flexDir="column">
                  <Icon as={YoutubeIcon} color="red.500" fontSize="2xl" mb={2} />
                  <Heading as="h3" size="md" fontWeight={400} mb={2} letterSpacing="tight">
                    <Link href='https://youtube.com/benjamincarlson' color={linkColor[colorMode]} isExternal>YouTube</Link>
                  </Heading>
                  <Text>I started uploading YouTube videos in 2020 when the pandemic started. I mostly upload programming tutorial videos but I also upload developer vlogs and informational videos. I have uploaded (almost) weekly since then and have grown my channel to an audience of over 4k subscribers and 450k views!</Text>
                </Flex>
                <Flex flexDir="column">
                  <Icon as={SiMedium} fontSize="2xl" mb={2} />
                  <Heading as="h3" size="md" fontWeight={400} mb={2} letterSpacing="tight">
                    <Link href='https://benjamincarlson.medium.com' color={linkColor[colorMode]} isExternal>Medium</Link>
                  </Heading>
                  <Text>Medium was the first publication I started. I wrote my <Link color="blue.500" href="https://levelup.gitconnected.com/using-javascript-to-scramble-a-rubiks-cube-306f52908f18" isExternal>first article</Link> in March 2020, and since then I have written about a dozen more articles. Nowadays I write less for Medium and more for coffeeclass.io.</Text>
                </Flex>
                <Flex flexDir="column">
                  <Icon as={FiCoffee} color="yellow.500" fontSize="2xl" mb={2} />
                  <Heading as="h3" size="md" fontWeight={400} mb={2} letterSpacing="tight">
                    <Link href='https://www.coffeeclass.io' color={linkColor[colorMode]} isExternal>coffeeclass.io</Link>
                  </Heading>
                  <Text>Because I enjoyed uploading YouTube videos about programming and writing about programming on Medium, I decided to start my own programming tutorial website, coffeeclass.io. If you are interested in writing about code, see our <Link color="blue.500" href="https://www.coffeeclass.io/contribute/getting-started" isExternal>getting started</Link> page.</Text>
                </Flex>
                <Flex flexDir="column">
                  <Icon as={BsGear} color="gray.500" fontSize="2xl" mb={2} />
                  <Heading as="h3" size="md" fontWeight={400} mb={2} letterSpacing="tight">
                    <Link href='https://www.engineering.coffeeclass.io' color={linkColor[colorMode]} isExternal>engineering.coffeeclass.io</Link>
                  </Heading>
                  <Text>The behind the scenes look at coffeeclass.io. On this site I write about the development of coffeeclass.io. Everything from the current tech stack, future plans, growing pains, and more.</Text>
                </Flex>
              </SimpleGrid>
              {/* </Flex> */}
              <Flex
                mb={4}
                bgColor={useColorModeValue("gray.100", "gray.900")}
                p={[5, 20, 50]}
                borderRadius={3}
                as="blockquote"
                borderLeft="10px solid"
                borderLeftColor={useColorModeValue("blue.400", "blue.700")}
              >
                <Icon as={GrBlockQuote} fontSize={40} color={colorSecondary[colorMode]} mr={4} />
                <Flex flexDir="column">
                  <Text fontSize="xl" fontStyle="italic" color={colorSecondary[colorMode]}>If You Can Think and Speak and Write, You Are Absolutely Deadly.</Text>
                  <Text fontSize="xl" fontWeight="bold" mt={2}>Jordan B. Peterson</Text>
                </Flex>
              </Flex>
            </Box>

            <Todo />
            <TechStack />

            <Box as="section">
              <Text mt={10}>Looks like you've made it to the end of this page... feel free to <Link href="https://youtube.com/benjamincarlson" isExternal color={linkColor[colorMode]}>check out my YouTube channel</Link> or
                visit <Link href="https://www.coffeeclass.io/?utm_source=website&utm_campaign=benjamincarlson.io" isExternal color={linkColor[colorMode]}>coffeeclass.io</Link> where
                you can find even more programming content.
              </Text>
            </Box>
          </motion.div>

        </Flex>
      </Container>
    </>
  )
}
Example #20
Source File: Todo.js    From benjamincarlson.io with MIT License 4 votes vote down vote up
Todo = () => {
    const toast = useToast()
    const { colorMode } = useColorMode()
    const { isOpen, onOpen, onClose } = useDisclosure()

    const colorSecondary = {
        light: 'gray.600',
        dark: 'gray.400',
    }

    const borderColor = {
        light: 'gray.200',
        dark: 'gray.600',
    }

    const colorSmall = {
        light: 'gray.400',
        dark: 'gray.600',
    }

    const myTodos = [
        {
            completed: false,
            title: 'Improve Final Cut Pro skills ?',
        },
        {
            completed: false,
            title: 'Finish my degree ?',
        },
        {
            completed: false,
            title: 'Grow my YouTube channel ?',
        },
        {
            completed: false,
            title: 'Grow coffeeclass.io ☕',
        },
    ]

    const [todos, setTodos] = useState(myTodos)
    const [input, setInput] = useState('')
    const removeTodo = todo => {
        setTodos(todos.filter(t => t !== todo))
    }

    const toggleCompleted = todo => {
        todo.completed = !todo.completed
        setTodos([...todos])
    }

    const addTodo = () => {
        setTodos(todos.concat({
            completed: false,
            title: input,
        }))
        setInput('')
    }

    return (
        <>
            <Box as="section" w="100%" mt={10} mb={20}>
                <Stack spacing={4} w="100%">
                    <Heading letterSpacing="tight" size="lg" fontWeight={700} as="h2">Todo List ?</Heading>
                    <Text color={colorSecondary[colorMode]}>Here is a list of things I plan to accomplish over the next year. Try it out yourself!</Text>
                    <InputGroup size="md" mt={4} borderColor="gray.500" borderColor={borderColor[colorMode]}>
                        <InputLeftElement
                            pointerEvents="none"
                            children={<Search2Icon color={useColorModeValue("gray.500", "gray.600")} />}
                        />
                        <Input
                            aria-label="Enter a Todo!"
                            placeholder="Improve Python skills ?"
                            value={input}
                            onChange={e => setInput(e.target.value)}
                        />
                        <InputRightElement width="6.75rem">
                            <Button
                                aria-label="Add a TODO!"
                                fontWeight="bold"
                                h="1.75rem"
                                size="md"
                                colorScheme="gray"
                                mr={2}
                                variant="outline"
                                px={10}
                                onClick={() => {
                                    if (input == '')
                                        toast({
                                            title: 'Whoops! There\'s an error!',
                                            description: "Input can't be empty!",
                                            status: "error",
                                            duration: 2000,
                                            isClosable: true,
                                        })
                                    else {
                                        addTodo(input)
                                    }
                                }}
                            >
                                Add Todo!
                            </Button>
                        </InputRightElement>
                    </InputGroup>
                    <Flex flexDir="column">
                        {todos.map((todo, index) => (
                            <Flex
                                key={index}
                                justify="space-between"
                                align="center"
                                my={1}
                            >
                                <Flex align="center">
                                    <Icon fontSize="xl" mr={2} as={ChevronRightIcon} color={colorSecondary[colorMode]} />
                                    <Tooltip label={`Click "${todo.title}" to mark as completed.`} placement="top" hasArrow>
                                        <Text color={colorSecondary[colorMode]} textDecor={todo.completed && "line-through"} _hover={{ cursor: 'pointer' }} onClick={() => toggleCompleted(todo)}>{todo.title}</Text>
                                    </Tooltip>
                                </Flex>
                                <Tooltip label={`Delete "${todo.title}"`} placement="top" hasArrow>
                                    <IconButton aria-label={`Delete "${todo.title}" from Todo list.`} icon={<DeleteIcon color="red.400" />} onClick={() => removeTodo(todo)} />
                                </Tooltip>
                            </Flex>
                        ))}
                    </Flex>
                    <Flex align="center">
                        <Text onClick={() => setTodos(myTodos)} _hover={{ cursor: 'pointer' }} color={colorSmall[colorMode]}>Reset</Text>
                        <Divider orientation="vertical" mx={2} h={4} />
                        <Text onClick={onOpen} _hover={{ cursor: 'pointer' }} color={colorSmall[colorMode]}>Help</Text>
                    </Flex>
                </Stack>
            </Box>
            <Modal isOpen={isOpen} onClose={onClose}>
                <ModalOverlay />
                <ModalContent>
                    <ModalHeader>Todo List Help</ModalHeader>
                    <ModalCloseButton />
                    <ModalBody>
                        <OrderedList>
                            <ListItem>
                                <Text fontWeight="bold">Add a Todo</Text>
                                <Text>Input your Todo and click the "Add Todo!" button to add a new Todo.</Text>
                            </ListItem>
                            <ListItem>
                                <Text fontWeight="bold">Reset</Text>
                                <Text>Click the "Reset" button to reset the list.</Text>
                            </ListItem>
                            <ListItem>
                                <Text fontWeight="bold">Delete</Text>
                                <Text>Click the "Delete" button to delete a Todo.</Text>
                            </ListItem>
                            <ListItem>
                                <Text fontWeight="bold">Completed</Text>
                                <Text>Click a Todo to mark it as completed.</Text>
                            </ListItem>
                            <ListItem>
                                <Text fontWeight="bold">View Code</Text>
                                <Text>Click the "View Code" button to view the code on GitHub for this simple TODO list.</Text>
                            </ListItem>
                        </OrderedList>
                        <Divider my={6} />
                        <Text><strong>Current state of Todo List:</strong> [{todos.map(t => { return `{"${t.title}",${t.completed}},` })}]</Text>
                    </ModalBody>

                    <ModalFooter>
                        <Button colorScheme="blue" mr={3} onClick={onClose}>
                            Close
                        </Button>
                        <Link
                            href="https://github.com/bjcarlson42/benjamincarlson.io/blob/master/components/Todo.js"
                            _hover={{ textDecor: 'none' }}
                            isExternal
                        >
                            <Button variant="ghost">View Code</Button>
                        </Link>
                    </ModalFooter>
                </ModalContent>
            </Modal>
        </>
    )
}
Example #21
Source File: Navigation.js    From benjamincarlson.io with MIT License 4 votes vote down vote up
Navigation = () => {
    const router = useRouter()

    return (
        <Flex
            justify="center"
            flexDirection="row"
            minWidth="356px"
            width="100%"
            bgColor={useColorModeValue("rgb(248, 250, 252)", "gray.900")}
            as="nav"
            px={4}
            py={2}
            pos="sticky"
            zIndex={10}
            top={0}
        >
            <motion.div
                initial={{ y: -20, opacity: 0 }}
                animate={{ y: 0, opacity: 1 }}
                transition={{ duration: .7 }}
            >
                <Box maxWidth="1200px">
                    <DarkModeSwitch />
                    <NextLink href="/statistics" passHref>
                        <Button
                            as="a"
                            variant="ghost"
                            p={[1, 2, 4]}
                            _hover={{ backgroundColor: useColorModeValue("gray.100", "gray.700") }}
                            fontWeight={router.pathname === '/statistics' ? "bold" : "normal"}
                            color={router.pathname === '/statistics' ? useColorModeValue("blue.500", "blue.700") : useColorModeValue("#000000", "#ffffff")}
                            aria-label="Statistics"
                        >
                            Statistics
                        </Button>
                    </NextLink>
                    <NextLink href="/blog" passHref>
                        <Button
                            as="a"
                            variant="ghost"
                            p={[1, 2, 4]}
                            fontWeight={router.pathname.includes('/blog') ? "bold" : "normal"}
                            color={router.pathname.includes('/blog') ? useColorModeValue("blue.500", "blue.700") : useColorModeValue("#000000", "#ffffff")}
                            aria-label="Blog"
                        >
                            Blog
                        </Button>
                    </NextLink>
                    <NextLink href="/projects" passHref>
                        <Button
                            as="a"
                            variant="ghost"
                            p={[1, 2, 4]}
                            fontWeight={router.pathname === '/projects' ? "bold" : "normal"}
                            color={router.pathname === '/projects' ? useColorModeValue("blue.500", "blue.700") : useColorModeValue("#000000", "#ffffff")}
                            aria-label="Projects"
                        >
                            Projects
                        </Button>
                    </NextLink>
                    <NextLink href="/gear" passHref>
                        <Button
                            as="a"
                            variant="ghost"
                            p={[1, 2, 4]}
                            fontWeight={router.pathname === '/gear' ? "bold" : "normal"}
                            color={router.pathname === '/gear' ? useColorModeValue("blue.500", "blue.700") : useColorModeValue("#000000", "#ffffff")}
                            aria-label="Gear"
                        >
                            Gear
                        </Button>
                    </NextLink>
                    <NextLink href="/" passHref>
                        <Button
                            as="a"
                            variant="ghost"
                            p={[1, 2, 4]}
                            fontWeight={router.pathname === '/' ? "bold" : "normal"}
                            color={router.pathname === '/' ? useColorModeValue("blue.500", "blue.700") : useColorModeValue("#000000", "#ffffff")}
                            aria-label="Home"
                        >
                            Home
                        </Button>
                    </NextLink>
                </Box>
            </motion.div>
        </Flex>
    )
}
Example #22
Source File: Hero.js    From benjamincarlson.io with MIT License 4 votes vote down vote up
export default function Hero() {
    return (
        <Box bgColor={useColorModeValue("rgb(248, 250, 252)", "gray.900")}>
            <Flex
                w="100%"
                flexDir={["column", "column", "row"]}
                align="center"
                px={4}
                mt={[8, 8, 16]}
                mb={8}
                maxW="1200px"
                mx="auto"
            >
                <Flex flexDir="column" w={["100%", "100%", "50%"]} mr={[0, 0, 4]}>
                    <motion.div
                        initial={{ y: -20, opacity: 0 }}
                        animate={{ y: 0, opacity: 1 }}
                        transition={{ duration: .7, delay: .4 }}
                    >
                        <Heading
                            letterSpacing="tight"
                            mb={4}
                            as="h1"
                            size="xl"
                            fontWeight={700}
                        >
                            Hello! I'm Benjamin Carlson -
                        </Heading>
                    </motion.div>
                    <motion.div
                        initial={{ y: -20, opacity: 0 }}
                        animate={{ y: 0, opacity: 1 }}
                        transition={{ duration: .7, delay: .8 }}
                    >
                        <Text
                            fontSize="xl"
                            color={useColorModeValue("gray.600", "gray.500")}
                            mb={6}
                        >
                            A <strong>software engineer ?‍?</strong>, <strong>creator ?</strong>, and <strong>student ?‍?</strong> living and working in CT. You've stumbled onto my online portfolio, resume, blog, and all things in between.
                        </Text>
                    </motion.div>
                    <motion.div
                        initial={{ y: -20, opacity: 0 }}
                        animate={{ y: 0, opacity: 1 }}
                        transition={{ duration: .7, delay: 1.2 }}
                    >
                        <Flex flexDir={["column", "row", "row"]}>
                            <Link href="https://youtube.com/benjamincarlson" _hover={{ textDecor: 'none' }} w={["100%", "100%", null]} mr={[0, 2, 2]} mb={[2, 0, 0]} isExternal>
                                <Button
                                    w={["100%", "100%", null]}
                                    colorScheme="red"
                                    size="md"
                                    rightIcon={<YoutubeIcon fontSize="xl" />}
                                    boxShadow={useColorModeValue("0px 8px 26px rgba(0, 0, 0, 0.2)", "0px 8px 26px rgba(0, 0, 0, 0.7)")}
                                    _hover={{ transform: "translateY(-2px)", opacity: .85, bgColor: useColorModeValue("red.400", "red.500") }}
                                >
                                    Visit my YouTube
                                </Button>
                            </Link>
                            <Link href="https://github.com/sponsors/bjcarlson42" _hover={{ textDecor: 'none' }} w={["100%", "100%", null]} isExternal>
                                <Button
                                    w={["100%", "100%", null]}
                                    colorScheme="gray"
                                    variant="outline"
                                    size="md"
                                    rightIcon={<GitHubIcon fontSize="xl" />}
                                    boxShadow={useColorModeValue("0px 8px 26px rgba(0, 0, 0, 0.2)", "0px 8px 26px rgba(0, 0, 0, 0.7)")}
                                    _hover={{ transform: "translateY(-2px)", bgColor: useColorModeValue("gray.100", "gray.800") }}
                                >
                                    Sponsor me on GitHub
                                </Button>
                            </Link>
                        </Flex>
                    </motion.div>
                </Flex>
                <Box mt={[10, 10, 0]} w={["100%", "100%", "50%"]}>
                    <motion.div
                        initial={{ y: -20, opacity: 0 }}
                        animate={{ y: 0, opacity: 1 }}
                        transition={{ duration: .7, delay: 1.6 }}
                    >
                        <AspectRatio ratio={16 / 9}>
                            <iframe src="https://www.youtube.com/embed/uNKBWrkMO_Q" alt="Featured YouTube video" allowFullScreen={true} style={{ borderRadius: 10 }} />
                        </AspectRatio>
                    </motion.div>
                </Box>
            </Flex>
        </Box>
    )
}
Example #23
Source File: Footer.js    From benjamincarlson.io with MIT License 4 votes vote down vote up
Footer = () => {

    const { colorMode } = useColorMode()
    const borderIcon = {
        light: 'gray.400',
        dark: 'gray.500'
    }
    const footerHoverBg = {
        light: 'gray.100',
        dark: 'gray.700',
    }
    return (
        <Box bgColor={useColorModeValue("rgb(248, 250, 252)", "gray.900")} mt={4}>
            <Flex
                align="center"
                my={4}
                direction="column"
            >
                <div>
                    <Link href="https://twitter.com/bjmncrlsn" title="Twitter" isExternal>
                        <IconButton
                            aria-label="Twitter"
                            icon={<FiTwitter />}
                            size="lg"
                            color={borderIcon[colorMode]}
                            variant="ghost"
                            _hover={{ backgroundColor: footerHoverBg[colorMode] }}
                        />
                    </Link>
                    <Link href="https://github.com/bjcarlson42" title="GitHub" isExternal>
                        <IconButton
                            aria-label="GitHub"
                            icon={<FiGithub />}
                            size="lg"
                            color={borderIcon[colorMode]}
                            variant="ghost"
                            _hover={{ backgroundColor: footerHoverBg[colorMode] }}
                        />
                    </Link>
                    <Link
                        href="https://www.linkedin.com/in/bjcarlson42"
                        title="LinkedIn"
                        isExternal
                    >
                        <IconButton
                            aria-label="LinkedIn"
                            icon={<FiLinkedin />}
                            size="lg"
                            color={borderIcon[colorMode]}
                            variant="ghost"
                            _hover={{ backgroundColor: footerHoverBg[colorMode] }}
                        />
                    </Link>
                    <Link
                        href="https://www.youtube.com/benjamincarlson"
                        title="YouTube"
                        isExternal
                    >
                        <IconButton
                            aria-label="YouTube"
                            icon={<FiYoutube />}
                            size="lg"
                            color={borderIcon[colorMode]}
                            variant="ghost"
                            _hover={{ backgroundColor: footerHoverBg[colorMode] }}
                        />
                    </Link>
                    <Link href="mailto:[email protected]" title="Email" isExternal>
                        <IconButton
                            aria-label="Email"
                            icon={<FiMail />}
                            size="lg"
                            color={borderIcon[colorMode]}
                            variant="ghost"
                            _hover={{ backgroundColor: footerHoverBg[colorMode] }}
                        />
                    </Link>
                </div>
            </Flex>
        </Box>
    )
}