@chakra-ui/react#useColorModeValue TypeScript 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: Logo.tsx    From coindrop with GNU General Public License v3.0 6 votes vote down vote up
PiggyLogo: FC<IconProps> = (iconProps) => {
    const theme = useTheme();
    const { colorMode } = useColorMode();
    const logoOutlineColor = useColorModeValue(theme.colors.gray['800'], theme.colors.gray['900']);
    // eslint-disable-next-line react/jsx-props-no-spreading
    return colorMode === 'light'
        ? <PiggyLogoIcon color={logoOutlineColor} {...iconProps} />
        : <PiggyLogoIconDarkMode color={logoOutlineColor} {...iconProps} />;
}
Example #2
Source File: top-nav.tsx    From portfolio with MIT License 6 votes vote down vote up
NavLink = (props: NavLinkProps) => {
  return (
    <Link
      as={RouterNavLink}
      px={2}
      py={1}
      rounded={"md"}
      _hover={{
        textDecoration: "none",
        bg: useColorModeValue("gray.200", "gray.900")
      }}
      _activeLink={{
        color: useColorModeValue("blue.500", "blue.200")
      }}
      onClick={() => props.onClose()}
      to={props.path}
    >
      {props.name}
    </Link>
  );
}
Example #3
Source File: Counter.tsx    From ksana.in with Apache License 2.0 6 votes vote down vote up
export function Counter({ count = 0 }) {
  const textColor = useColorModeValue('gray.500', 'gray.300')
  const arrString: string[] = count.toString().split('')

  return (
    <Stack spacing="2">
      <Stack spacing="2" direction="row" alignItems="center" justify="center" wrap="wrap">
        {arrString.map((c, index) => (
          <Flex
            key={index}
            as="div"
            width={{ base: '40px', md: '60px' }}
            height={{ base: '40px', md: '60px' }}
            fontWeight={700}
            fontSize={{ base: '2xl', md: '4xl' }}
            lineHeight={'110%'}
            bg="orange.400"
            color="white"
            rounded={'md'}
            display="flex"
            alignItems="center"
            justify="center"
          >
            {c}
          </Flex>
        ))}
      </Stack>
      <Text textAlign="center" color={textColor}>
        Tautan telah dipercantik oleh ksana.in dan akan terus bertambah
      </Text>
    </Stack>
  )
}
Example #4
Source File: card-skeleton.tsx    From portfolio with MIT License 6 votes vote down vote up
CardSkeleton = () => {
  const bgColor = useColorModeValue("white", "gray.900");
  const cards:number[] = [1, 2, 3, 4, 5, 6, 7, 8]

  return (
    <>
      {cards.map(id => {
        return (
          <Box
            key={id}
            size="xl"
            py={2}
            rounded="xl"
            borderWidth="1px"
            bg={bgColor}
          >
            <Stack isInline justifyContent="space-between" py={2} px={[2, 3]}>
              <Box width="100%">
                <HStack isInline justifyContent="space-between">
                  <Skeleton height="14px" width="40%" />
                  <Skeleton height="14px" width="20%" />
                </HStack>
                <VStack align="start" marginTop={2}>
                  <Skeleton height="8px" width="30%" />
                </VStack>
                <Box marginTop={2}>
                  <Skeleton height="8px" width="100%" />
                  <Stack spacing={2} mt={1} isInline alignItems="center">
                    <Skeleton height="8px" width="80%" />
                  </Stack>
                </Box>
              </Box>
            </Stack>
          </Box>
        );
      })}
    </>
  );
}
Example #5
Source File: sign-up.tsx    From ksana.in with Apache License 2.0 6 votes vote down vote up
function Register() {
  const bgColor = useColorModeValue('gray.50', 'gray.800')

  return (
    <LayoutAuth minH={'100vh'} bg={bgColor}>
      <MetaHead
        title="Daftar Akun | Ksana.in"
        description="Tertarik mencoba layanan pemendek tautan / URL yang gratis dan sangat mudah digunakan? Mari daftarkan akun baru di Ksana.in"
      />
      <AuthSignUp />
    </LayoutAuth>
  )
}
Example #6
Source File: Timeline.tsx    From portfolio with MIT License 6 votes vote down vote up
TimelineItem: React.FC<TimelineItemProps> = ({
  icon = FiCheckCircle,
  boxProps = {},
  skipTrail = false,
  children,
  ...props
}) => {
  const color = useColorModeValue("gray.700", "gray.500");
  return (
    <Flex minH={20} {...props}>
      <Flex flexDir="column" alignItems="center" mr={4} pos="relative">
        <Circle
          size={12}
          bg={useColorModeValue("gray.600", "gray.500")}
          opacity={useColorModeValue(0.07, 0.15)}
          sx={{}}
        />
        <Box
          as={icon}
          size="1.25rem"
          color={color}
          pos="absolute"
          left="0.875rem"
          top="0.875rem"
        />
        {!skipTrail && <Box w="1px" flex={1} bg={color} my={1} />}
      </Flex>
      <Box pt={3} {...boxProps}>
        {children}
      </Box>
    </Flex>
  );
}
Example #7
Source File: Logo.tsx    From coindrop with GNU General Public License v3.0 6 votes vote down vote up
Logo: FC<Props> = ({ text = 'coindrop', subtitle }) => {
    const theme = useTheme();
    const fontColor = useColorModeValue(theme.colors.gray['600'], theme.colors.gray['50']);
    const LogoText = () => (
        <Text
            fontSize={["4xl", "5xl"]}
            fontFamily="Changa, system-ui, sans-serif"
            fontWeight={500}
            color={fontColor}
            ml={2}
            lineHeight={["1.5rem", "2.5rem"]}
        >
            {text}
        </Text>
    );
    return (
        <Flex
            ml={1}
            mr={2}
            mb={[2, 0]}
            align="center"
        >
            <PiggyLogo boxSize={["48px", "64px"]} />
            <Box>
                <LogoText />
                {subtitle && (
                    <Text textAlign="center">
                        {subtitle}
                    </Text>
                )}
            </Box>
        </Flex>
    );
}
Example #8
Source File: ColorModeSwitcher.tsx    From notebook with MIT License 6 votes vote down vote up
ColorModeSwitcher: React.FC<ColorModeSwitcherProps> = (props) => {
  const { toggleColorMode } = useColorMode()
  const text = useColorModeValue("dark", "light")
  const SwitchIcon = useColorModeValue(FaMoon, FaSun)

  return (
    <IconButton
      size="md"
      fontSize="lg"
      variant="ghost"
      color="current"
      marginLeft="2"
      onClick={toggleColorMode}
      icon={<SwitchIcon />}
      aria-label={`Switch to ${text} mode`}
      {...props}
    />
  )
}
Example #9
Source File: CourseCard.tsx    From fresh-coupons with GNU General Public License v3.0 6 votes vote down vote up
function CourseLanguage({language, ...props}: CourseLanguageProps) {
  return (
    <HStack spacing={1} {...props}>
      <Icon boxSize={8} as={MdLanguage} color="gray.400"/>
      <Text
        fontSize="sm"
        fontWeight="medium"
        color={useColorModeValue('gray.600', 'gray.300')}
      >
        {language}
      </Text>
    </HStack>
  )
}
Example #10
Source File: withColorModeHooks.tsx    From bluebubbles-server with Apache License 2.0 6 votes vote down vote up
withColorModeHooks = (Elem: any): (props: any) => JSX.Element => {
    // eslint-disable-next-line react/display-name
    return (props: any): JSX.Element => {
        return <Elem
            useColorModeValue={useColorModeValue}
            useColorMode={useColorMode()}
            {...props}
        />;
    };
}
Example #11
Source File: PoweredByCoindropLink.tsx    From coindrop with GNU General Public License v3.0 6 votes vote down vote up
PoweredByCoindropLink: FunctionComponent = () => {
    const bgHover = useColorModeValue("gray.50", "gray.600");
    return (
        <Box
            textAlign="center"
            my={6}
        >
            <NextLink href="/" passHref>
                <ChakraLink style={{textDecoration: "none"}}>
                    <Button
                        variant="ghost"
                        _hover={{
                            bg: bgHover,
                        }}
                    >
                        <Flex
                            align="center"
                            justify="center"
                        >
                            <PiggyLogo mr={1} boxSize="2rem" />
                            <Text>
                                Powered by Coindrop
                            </Text>
                        </Flex>

                    </Button>
                </ChakraLink>
            </NextLink>
        </Box>
    );
}
Example #12
Source File: Card.tsx    From fresh-coupons with GNU General Public License v3.0 6 votes vote down vote up
Card = (props: BoxProps) => (
  <Box
    maxW="3xl"
    position="relative"
    mx="auto"
    bg={useColorModeValue('white', 'gray.700')}
    rounded={{ md: 'xl' }}
    padding="10"
    shadow={{ md: 'base' }}
    px={{ base: '6', md: '8' }}
    {...props}
  />
)
Example #13
Source File: CreateCoindropError.tsx    From coindrop with GNU General Public License v3.0 5 votes vote down vote up
CreateCoindropError: FC<{ error: string }> = ({ error }) => {
    const errorTextColor = useColorModeValue("red.500", "red.300");
    return (
        <Text mt={2} textAlign="center" color={errorTextColor}>
            {error}
        </Text>
    );
}
Example #14
Source File: Hero.tsx    From ksana.in with Apache License 2.0 5 votes vote down vote up
export function Hero() {
  const textColor = useColorModeValue('gray.500', 'gray.300')

  return (
    <Box w={'full'}>
      <SimpleGrid columns={{ base: 1, md: 2 }} spacing={10}>
        <Container maxW={'6xl'} as="section" mt="32">
          <VStack spacing={{ base: 8, md: 10 }} px={{ base: 8, md: 10 }}>
            <Heading
              as="h2"
              textAlign="center"
              fontWeight={700}
              fontSize={{ base: '4xl', sm: '5xl', md: '6xl' }}
              lineHeight={'110%'}
            >
              Pemendek tautan yang{' '}
              <Text color="orange.400" as="span">
                mudah
              </Text>{' '}
              dan{' '}
              <Text color="orange.400" as="span">
                gratis
              </Text>
            </Heading>

            <Text
              as="span"
              textAlign="center"
              color={textColor}
              fontSize={{ base: 'lg', sm: 'xl', md: '2xl' }}
              lineHeight={'110%'}
            >
              Percantik tautanmu, jadikan agar mudah diingat, bagikan ke orang lain dengan percaya
              diri
            </Text>

            <Button
              size="lg"
              rounded="full"
              px={6}
              color={'white'}
              bg="orange.400"
              _hover={{
                bg: 'orange.500'
              }}
              as={'a'}
              href={login}
              leftIcon={<HiPlay />}
            >
              Coba sekarang
            </Button>
          </VStack>
        </Container>

        <Flex as="section" mt={{ base: 0, md: 20 }} justifyContent="center">
          <Image
            width={400}
            height={400}
            src={'/images/illustrations/ill_by_manypixels.svg'}
            alt="Women with Internet"
            priority={true}
          />
        </Flex>
      </SimpleGrid>
    </Box>
  )
}
Example #15
Source File: PrivateApiRequirements.tsx    From bluebubbles-server with Apache License 2.0 5 votes vote down vote up
PrivateApiRequirements = (): JSX.Element => {
    const requirements: Array<RequirementsItem> = (useAppSelector(state => state.config.private_api_requirements) ?? []);
    const [showProgress, setShowProgress] = useBoolean();

    const refreshRequirements = () => {
        setShowProgress.on();
        getPrivateApiRequirements().then(requirements => {
            // I like longer spinning
            setTimeout(() => {
                setShowProgress.off();
            }, 1000);
            
            if (!requirements) return;
            store.dispatch(setConfig({ name: 'private_api_requirements', value: requirements }));
        });
    };

    return (
        <Box border='1px solid' borderColor={useColorModeValue('gray.200', 'gray.700')} borderRadius='xl' p={3} width='325px'>
            <Stack direction='row' align='center'>
                <Text fontSize='lg' fontWeight='bold'>Private API Requirements</Text>
                <Box
                    _hover={{ cursor: 'pointer' }}
                    animation={showProgress ? `${spin} infinite 1s linear` : undefined}
                    onClick={refreshRequirements}
                >
                    <BiRefresh />
                </Box>
            </Stack>
            <UnorderedList mt={2} ml={8}>
                {requirements.map(e => (
                    <ListItem key={e.name}>
                        <Stack direction='row' align='center'>
                            <Text fontSize='md'><strong>{e.name}</strong>:&nbsp;
                                <Box as='span' color={e.pass ? 'green' : 'red'}>{e.pass ? 'Pass' : 'Fail'}</Box>
                            </Text>
                            {(!e.pass) ? (
                                <Popover trigger='hover'>
                                    <PopoverTrigger>
                                        <Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
                                            <AiOutlineInfoCircle />
                                        </Box>
                                    </PopoverTrigger>
                                    <PopoverContent>
                                        <PopoverArrow />
                                        <PopoverCloseButton />
                                        <PopoverHeader>How to Fix</PopoverHeader>
                                        <PopoverBody>
                                            <Text>
                                                {e.solution}
                                            </Text>
                                        </PopoverBody>
                                    </PopoverContent>
                                </Popover>
                            ): null}
                        </Stack>
                    </ListItem>
                ))}
            </UnorderedList>
        </Box>
    );
}
Example #16
Source File: TotalStats.tsx    From ksana.in with Apache License 2.0 5 votes vote down vote up
export function TotalStats({ data }: ITotalStatsProps) {
  const bgBox = useColorModeValue('white', 'gray.800')
  const sum = data.reduce((a: number, b: IUrl) => a + b.hit, 0)

  return (
    <>
      {data && data.length > 0 ? (
        <Stack direction="row" justifyContent="center">
          <VStack
            w="full"
            bg={bgBox}
            boxShadow={'2xl'}
            rounded={'md'}
            justifyContent="center"
            textAlign="center"
            overflow={'hidden'}
            py="2"
            position="relative"
          >
            <Text fontSize="xs">Total Tautan</Text>
            <Text fontSize="2xl" color="orange.400" fontWeight="700" zIndex="1">
              {new Intl.NumberFormat('id-ID').format(data.length)}
            </Text>

            <IconButton
              aria-label="Tautan"
              bg="orange.400"
              color="white"
              borderRadius="3xl"
              position="absolute"
              bottom="-.2em"
              right="-.2em"
              opacity="0.5"
              w="12"
              h="12"
              margin="0"
              fontSize="4xl"
              zIndex="0"
              icon={<HiLink />}
            />
          </VStack>
          <VStack
            w="full"
            bg={bgBox}
            boxShadow={'2xl'}
            rounded={'md'}
            justifyContent="center"
            textAlign="center"
            overflow={'hidden'}
            py="2"
            position="relative"
          >
            <Text fontSize="xs">Total Kunjungan</Text>
            <Text fontSize="2xl" color="orange.400" fontWeight="700" zIndex="1">
              {new Intl.NumberFormat('id-ID').format(sum)}
            </Text>

            <IconButton
              aria-label="Tautan"
              bg="orange.400"
              color="white"
              borderRadius="3xl"
              position="absolute"
              bottom="-.2em"
              right="-.2em"
              opacity="0.5"
              w="12"
              h="12"
              margin="0"
              fontSize="4xl"
              zIndex="0"
              icon={<HiChartBar />}
            />
          </VStack>
        </Stack>
      ) : null}
    </>
  )
}
Example #17
Source File: faq.tsx    From coindrop with GNU General Public License v3.0 5 votes vote down vote up
FAQ: FunctionComponent = () => {
    const theme = useTheme();
    const panelBgColor = useColorModeValue("gray.50", undefined);
    return (
        <Box>
            <Box my={6}>
                <Heading as="h1" textAlign="center">
                    FAQ
                </Heading>
                <Text textAlign="center">
                    Frequently Asked Questions
                </Text>
            </Box>
            <Container maxW={theme.breakpoints.lg}>
                <Accordion defaultIndex={-1} allowToggle>
                    {accordionText.map(({title, body}) => (
                        <AccordionItem key={title}>
                            <AccordionButton>
                            <Box flex="1" textAlign="left">
                                {title}
                            </Box>
                            <AccordionIcon />
                            </AccordionButton>
                            <AccordionPanel>
                                <Box
                                    p={4}
                                    bg={panelBgColor}
                                >
                                    {body}
                                </Box>
                            </AccordionPanel>
                        </AccordionItem>
                    ))}
                </Accordion>
            </Container>
            <Text textAlign="center" mt={4} fontSize="sm">
                {"Do you have a question that's not answered here? Send it to "}
                <Link href={`mailto:${coindropEmail}`} isExternal>
                    {coindropEmail}
                </Link>
            </Text>
        </Box>
    );
}
Example #18
Source File: footer.tsx    From portfolio with MIT License 5 votes vote down vote up
Footer = () => {
  return (
    <Stack
      as="footer"
      isInline
      spacing={[1, 2]}
      p={4}
      justifyContent="space-between"
      alignItems="center"
      w={["100%", "85%", "80%"]}
      maxW={800}
      mx="auto"
    >
      <Flex
        flexDirection={["column", "column", "row"]}
        flexFlow={["column-reverse", "column-reverse"]}
        justifyContent={["center", "space-between"]}
        alignItems="center"
        w="100%"
        ju
      >
        {/* <HStack> */}
        <Text
          textAlign="center"
          fontSize="sm"
          color={useColorModeValue("gray.500", "gray.200")}
        >
          © {new Date().getFullYear()} Muhammad Ahmad{" "}
        </Text>
        {/* <Box fontSize="md" textAlign="left">
        Website built with
        <Box
          as="span"
          mx="2"
          _before={{
            cursor: "default",
            content: '"❤️"'
          }}
          _hover={{
            _before: {
              content: '"☕️"'
            }
          }}
        />
        in Pakistan{"  "}??
      </Box> */}
        {/* </HStack> */}
        <Box textAlign="center">
          {siteConfig.author.accounts.map((sc, index) => (
            <IconButton
              key={index}
              as={Link}
              isExternal
              href={sc.url}
              aria-label={sc.label}
              size="lg"
              colorScheme={sc.type}
              icon={sc.icon}
              {...iconProps}
            />
          ))}
        </Box>
      </Flex>
    </Stack>
  );
}
Example #19
Source File: PermissionRequirements.tsx    From bluebubbles-server with Apache License 2.0 5 votes vote down vote up
PermissionRequirements = (): JSX.Element => {
    const permissions: Array<RequirementsItem> = (useAppSelector(state => state.config.permissions) ?? []);
    const [showProgress, setShowProgress] = useBoolean();

    const refreshRequirements = () => {
        setShowProgress.on();
        checkPermissions().then(permissions => {
            // I like longer spinning
            setTimeout(() => {
                setShowProgress.off();
            }, 1000);

            if (!permissions) return;
            store.dispatch(setConfig({ name: 'permissions', value: permissions }));
        });
    };

    return (
        <Box border='1px solid' borderColor={useColorModeValue('gray.200', 'gray.700')} borderRadius='xl' p={3} width='325px'>
            <Stack direction='row' align='center'>
                <Text fontSize='lg' fontWeight='bold'>macOS Permissions</Text>
                <Box
                    _hover={{ cursor: 'pointer' }}
                    animation={showProgress ? `${spin} infinite 1s linear` : undefined}
                    onClick={refreshRequirements}
                >
                    <BiRefresh />
                </Box>
            </Stack>
            <UnorderedList mt={2} ml={8}>
                {permissions.map(e => (
                    <ListItem key={e.name}>
                        <Stack direction='row' align='center'>
                            <Text fontSize='md'><strong>{e.name}</strong>:&nbsp;
                                <Box as='span' color={e.pass ? 'green' : 'red'}>{e.pass ? 'Pass' : 'Fail'}</Box>
                            </Text>
                            {(e.pass) ? (
                                <Popover trigger='hover'>
                                    <PopoverTrigger>
                                        <Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
                                            <AiOutlineInfoCircle />
                                        </Box>
                                    </PopoverTrigger>
                                    <PopoverContent>
                                        <PopoverArrow />
                                        <PopoverCloseButton />
                                        <PopoverHeader>How to Fix</PopoverHeader>
                                        <PopoverBody>
                                            <Text>
                                                {e.solution}
                                            </Text>
                                        </PopoverBody>
                                    </PopoverContent>
                                </Popover>
                            ): null}
                        </Stack>
                    </ListItem>
                ))}
            </UnorderedList>
        </Box>
    );
}
Example #20
Source File: ColorModeSwitcher.tsx    From portfolio with MIT License 5 votes vote down vote up
ColorModeSwitcher: React.FC<ColorModeSwitcherProps> = props => {
  const { toggleColorMode } = useColorMode();
  const text = useColorModeValue("dark", "light");
  const SwitchIcon = useColorModeValue(FaMoon, FaSun);

  const [play] = useSound(lightswitch, {
    volume: 0.05,
    sprite: {
      on: [0, 300],
      off: [500, 300]
    }
  });

  const handleClick = () => {
    text === "dark" ? play({ id: "on" }) : play({ id: "off" });
    toggleColorMode();
  };

  return (
    <Tooltip
      label={text === "dark" ? "Dark mode" : "Light mode"}
      aria-label="A tooltip"
    >
      <IconButton
        size="md"
        fontSize="md"
        variant="ghost"
        color="current"
        marginLeft="2"
        onClick={handleClick}
        icon={<SwitchIcon />}
        aria-label={`Switch to ${text} mode`}
        _hover={{
          bg: useColorModeValue("gray.200", "gray.900")
        }}
        {...props}
      />
    </Tooltip>
  );
}
Example #21
Source File: Layout.tsx    From lucide with ISC License 4 votes vote down vote up
Layout = ({ aside, children }: LayoutProps) => {
  const router = useRouter();
  const { toggleMobileMenu } = useMobileNavigationContext();
  const { toggleColorMode } = useColorMode();
  const currentColorMode = useColorModeValue('dark', 'light');
  const ColorModeToggle = useColorModeValue(Moon, Sun);
  const MobileMenuToggle = useMobileNavigationValue(Menu, X);
  const showBaseNavigation = useBreakpointValue({ base: false, md: true });
  const IconbuttonProps = {
    size: 'md',
    fontSize: 'lg',
    variant: 'ghost',
    color: 'current',
    ml: '3',
  };

  function setQuery(query) {
    router.push({
        pathname: '/',
        query: { query: query },
    },
    undefined,
    { shallow: true })
  }

  useKeyBindings({
    Escape: {
      fn: () => setQuery(''),
    },
    KeyT: {
      fn: () => toggleColorMode(),
    },
  });

  return (
    <Box h="100vh">
      <Flex mb={16} w="full">
        <Flex
          alignItems="center"
          justifyContent="space-between"
          pt={4}
          pb={4}
          margin="0 auto"
          w="full"
          px={5}
        >
          <Flex justifyContent="center" alignItems="center">
            <Logo />
          </Flex>
          <Flex justifyContent="center" alignItems="center">
            {showBaseNavigation ? (
              <>
                <NextLink href="/docs" passHref>
                  <Link marginRight={12} fontSize="xl">
                    Documentation
                  </Link>
                </NextLink>
                <NextLink href="/packages" passHref>
                  <Link marginRight={12} fontSize="xl">
                    Packages
                  </Link>
                </NextLink>
                <NextLink href="/license" passHref>
                  <Link marginRight={12} fontSize="xl">
                    License
                  </Link>
                </NextLink>
                <Link
                  href="https://github.com/lucide-icons/lucide"
                  isExternal
                  marginRight={6}
                  fontSize="xl"
                >
                  Github
                </Link>
              </>
            ) : null}
            <IconButton
              aria-label={`Switch to ${currentColorMode} mode`}
              onClick={toggleColorMode}
              {...IconbuttonProps}
              icon={<ColorModeToggle />}
            />
            {!showBaseNavigation ? (
              <IconButton
                aria-label={`Open Mobile menu`}
                onClick={toggleMobileMenu}
                {...IconbuttonProps}
                icon={<MobileMenuToggle />}
              />
            ) : null}
          </Flex>
        </Flex>
      </Flex>
      <Flex>
        {aside ? <Box as="aside" marginRight={{ base: 0, lg: -240, }}>{aside}</Box> : null}
        <Flex margin="0 auto" direction="column" maxW="1250px" px={5} width="100%">
          {children}
          <Divider mb={6} mt={12} />
          <p style={{ alignSelf: 'center' }}>
            <a href="https://vercel.com?utm_source=lucide&utm_campaign=oss">
              <img src="/vercel.svg" alt="Powered by Vercel" width="200" />
            </a>
          </p>
          <br />
        </Flex>
      </Flex>
    </Box>
  );
}
Example #22
Source File: Item.tsx    From ksana.in with Apache License 2.0 4 votes vote down vote up
export function Item({ user, data }: IUrlItemProps) {
  const { showAlert, hideAlert } = useAlertContext()
  const [updateId, setUpdateId] = useState<string>('')
  const [updateSlug, setUpdateSlug] = useState<string>('')
  const [isSuccessCopy, setSuccessCopy] = useState<boolean>(false)
  const [isLoadingShare, setLoadingShare] = useState<boolean>(false)
  const [isLoadingSave, setLoadingSave] = useState<boolean>(false)
  const isSupportShare: boolean =
    typeof window !== 'undefined' ? navigator.share !== undefined : false

  const bgBox = useColorModeValue('white', 'gray.800')
  const bgInput = useColorModeValue('blackAlpha.100', 'whiteAlpha.100')

  const showSuccessCopy = () => {
    setSuccessCopy(true)
    setTimeout(() => {
      setSuccessCopy(false)
    }, 2000)
  }

  const handleCopy = async (text: string) => {
    if (navigator.clipboard) {
      await navigator.clipboard.writeText(text)
    } else {
      copy(text)
    }
    showSuccessCopy()
  }

  const handleShare = async (url: string) => {
    if (navigator.share) {
      setLoadingShare(true)
      const jsonRes = await getMeta(url)

      const shareObj = {
        title: jsonRes.title,
        text: jsonRes.description,
        url: url
      }

      navigator
        .share(shareObj)
        // eslint-disable-next-line no-console
        .then(() => setLoadingShare(false))
        .catch((error) => {
          setLoadingShare(false)
          // eslint-disable-next-line no-console
          console.error('Error sharing', error, shareObj)
        })
    }
  }

  const handleClickEdit = async (id: string) => {
    if (updateId === id) {
      setUpdateId('')
      setUpdateSlug('')
    } else {
      setUpdateId(id)
      setUpdateSlug('')
    }
  }

  const handleChangeUpdatedSlug = async (e: ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value
    setUpdateSlug(value)
  }

  const handleClickSave = async () => {
    if (updateSlug) {
      setLoadingSave(true)
      const { error } = await patchSlug({
        id: updateId,
        slug: sanitizeSlug(updateSlug),
        userId: user?.id
      })

      if (error) {
        showAlert({
          title: 'Terjadi galat pada saat memperbarui data',
          message: `Pesan: ${error.message}`,
          onClose: () => {
            hideAlert()
            setLoadingSave(false)
          }
        })
      } else {
        mutate(apiUrlsGet(user?.id))
        setUpdateId('')
        setUpdateSlug('')
        setLoadingSave(false)
      }
    }
  }

  const onConfimDelete = async (id: string) => {
    const { error } = await deleteUrl({ id: id, userId: user?.id })

    if (error) {
      hideAlert()

      showAlert({
        title: 'Terjadi galat pada saat berusaha menghapus data',
        message: `Pesan: ${error.message}`,
        onClose: () => {
          hideAlert()
        }
      })
    }

    hideAlert()
    mutate(apiUrlsGet(user?.id))
  }

  const handleDelete = async (id: string, slug: string) => {
    showAlert({
      title: 'Konfirmasi hapus',
      message: `Apakah kamu yakin untuk menghapus data ${HOME}${slug}? Aksi ini juga akan menghilangkan semua data statistik terkait.`,
      cancelText: 'Batalkan',
      confirmText: 'Ya, hapus',
      onConfirm: () => {
        onConfimDelete(id)
      },
      onClose: hideAlert
    })
  }

  return (
    <Box
      key={data.slug}
      w={'full'}
      bg={bgBox}
      boxShadow={'2xl'}
      rounded={'md'}
      overflow={'hidden'}
      p={{ base: '4', md: '6' }}
    >
      {!!data.is_dynamic && (
        <Tag size="sm" colorScheme="green">
          Tautan dinamis
        </Tag>
      )}
      <Flex alignItems="center" mb="4">
        <Link
          as="a"
          fontSize={{ base: 'md', md: 'lg' }}
          fontWeight="700"
          color="orange.400"
          href={`${HOME}${data.slug}${!!data.is_dynamic ? '/{param}' : ''}`}
          display="block"
        >
          {`/${data.slug}`}
          {!!data.is_dynamic && '/{param}'}
        </Link>
      </Flex>

      {updateId && updateId === data.id && (
        <HStack alignItems="center" mb="4" mt="2">
          <Input
            size="lg"
            name="slug"
            placeholder={'Tulis slug baru'}
            bg={bgInput}
            border={0}
            value={updateSlug}
            onChange={handleChangeUpdatedSlug}
          />

          <IconButton
            onClick={handleClickSave}
            aria-label="Simpan slug"
            size="lg"
            bg="orange.400"
            borderRadius="md"
            isLoading={isLoadingSave}
            icon={<HiSave color="#FFF" />}
          />
        </HStack>
      )}

      <Text fontSize="small" color="gray.400" display="block" mb="2">
        {data.real_url}
      </Text>
      <Text fontSize="small" color="gray.400">
        <Text as="span" fontWeight="bold" color="orange.400">
          {new Intl.NumberFormat('id-ID').format(data.hit)}
        </Text>
        {` `} kunjungan
      </Text>
      <HStack spacing={2} mt={4} flexWrap="wrap">
        <IconButton
          onClick={() => {
            handleCopy(`${HOME}${data.slug}`)
          }}
          aria-label="Copy"
          variant="ghost"
          borderRadius="md"
          icon={isSuccessCopy ? <HiCheck color="#48BB78" /> : <HiDuplicate color="#ED8936" />}
        />
        {isSupportShare ? (
          <IconButton
            onClick={() => {
              handleShare(`${HOME}${data.slug}`)
            }}
            aria-label="Copy"
            variant="ghost"
            borderRadius="md"
            isLoading={isLoadingShare}
            icon={<HiShare color="#ED8936" />}
          />
        ) : (
          <SharePopover url={`${HOME}${data.slug}`} />
        )}
        <IconButton
          onClick={() => {
            handleClickEdit(data.id)
          }}
          aria-label="Ubah"
          variant="ghost"
          borderRadius="md"
          icon={<HiPencil color="#ED8936" />}
        />
        <IconButton
          onClick={() => {
            handleDelete(data.id, data.slug)
          }}
          aria-label="Hapus"
          variant="ghost"
          borderRadius="md"
          icon={<HiTrash color="#ED8936" />}
        />
      </HStack>
    </Box>
  )
}
Example #23
Source File: Navigation.tsx    From bluebubbles-server with Apache License 2.0 4 votes vote down vote up
MobileNav = ({ onOpen, onNotificationOpen, unreadCount, ...rest }: MobileProps) => {
    const { colorMode, toggleColorMode } = useColorMode();

    return (
        <Flex
            ml={{ base: 0, md: 60 }}
            px={{ base: 4, md: 4 }}
            height="20"
            alignItems="center"
            borderBottomWidth="1px"
            borderBottomColor={useColorModeValue('gray.200', 'gray.700')}
            justifyContent={{ base: 'space-between', md: 'flex-end' }}
            {...rest}
        >
            <IconButton
                display={{ base: 'flex', md: 'none' }}
                onClick={onOpen}
                variant="outline"
                aria-label="open menu"
                icon={<FiMenu />}
            />

            <Text display={{ base: 'flex', md: 'none' }} fontSize="2xl" fontFamily="monospace" fontWeight="bold">
                <img src={logo} className="logo-small" alt="logo" />
            </Text>

            <HStack spacing={{ base: '0', md: '1' }}>
                <Tooltip label="Website Home" aria-label="website-tip">
                    <Link href="https://bluebubbles.app" style={{ textDecoration: 'none' }} target="_blank">
                        <IconButton size="lg" variant="ghost" aria-label="website" icon={<AiOutlineHome />} />
                    </Link>
                </Tooltip>
                <Tooltip label="BlueBubbles Web" aria-label="website-tip">
                    <Link href="https://bluebubbles.app/web" style={{ textDecoration: 'none' }} target="_blank">
                        <IconButton size="lg" variant="ghost" aria-label="bluebubbles web" icon={<FiMessageCircle />} />
                    </Link>
                </Tooltip>
                <Tooltip label="Sponsor Us" aria-label="sponsor-tip">
                    <Link href="https://github.com/sponsors/BlueBubblesApp" style={{ textDecoration: 'none' }} target="_blank">
                        <IconButton size="lg" variant="ghost" aria-label="donate" icon={<AiOutlineHeart />} />
                    </Link>
                </Tooltip>
                <Tooltip label="Support Us" aria-label="donate-tip">
                    <Link href="https://bluebubbles.app/donate" style={{ textDecoration: 'none' }} target="_blank">
                        <IconButton size="lg" variant="ghost" aria-label="donate" icon={<MdOutlineAttachMoney />} />
                    </Link>
                </Tooltip>
                <Tooltip label="Join our Discord" aria-label="discord-tip">
                    <Link href="https://discord.gg/yC4wr38" style={{ textDecoration: 'none' }} target="_blank">
                        <IconButton size="lg" variant="ghost" aria-label="discord" icon={<FaDiscord />} />
                    </Link>
                </Tooltip>
                <Tooltip label="Read our Source Code" aria-label="github-tip">
                    <Link href="https://github.com/BlueBubblesApp" style={{ textDecoration: 'none' }} target="_blank">
                        <IconButton size="lg" variant="ghost" aria-label="github" icon={<FiGithub />} />
                    </Link>
                </Tooltip>
                <Box position='relative' float='left'>
                    <IconButton
                        size="lg"
                        verticalAlign='middle'
                        zIndex={1}
                        variant="ghost"
                        aria-label="notifications"
                        icon={<FiBell />}
                        onClick={() => onNotificationOpen()}
                    />
                    {(unreadCount > 0) ? (
                        <Badge
                            borderRadius='lg'
                            variant='solid'
                            colorScheme='red'
                            position='absolute'
                            margin={0}
                            top={1}
                            right={1}
                            zIndex={2}
                        >{unreadCount}</Badge>
                    ) : null}
                </Box>
                <Spacer />
                <Divider orientation="vertical" width={1} height={15} borderColor='gray' />
                <Spacer />
                <Spacer />
                <Spacer />
                <FormControl display='flex' alignItems='center'>
                    <Box mr={2}><MdOutlineDarkMode size={20} /></Box>
                    <Switch id='theme-mode-toggle' onChange={toggleColorMode} isChecked={colorMode === 'light'} />
                    <Box ml={2}><MdOutlineLightMode size={20} /></Box>
                </FormControl>
            </HStack>
        </Flex>
    );
}
Example #24
Source File: Form.tsx    From ksana.in with Apache License 2.0 4 votes vote down vote up
export function Form() {
  const router = useRouter()
  const { showAlert, hideAlert } = useAlertContext()
  const bgBox = useColorModeValue('white', 'gray.700')

  const [loading, setLoading] = useState<boolean>(false)
  const [errorForm, setErrorForm] = useState<string>('')
  const [email, setEmail] = useState<string>('')

  const handleChangeEmail = (e: ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value
    setEmail(value)
  }

  const checkIsEmpty = () => {
    if (email === '') {
      setErrorForm('Email tidak boleh dikosongkan.')
      return true
    }

    setErrorForm('')
    return false
  }

  const handleResetPassword = async () => {
    const { error } = await forgetPassword({ email })

    if (!error) {
      showAlert({
        title: 'Lupa password',
        message: 'Tautan untuk melakukan setel ulang kata sandi telah dikirim ke email kamu.',
        onClose: () => {
          hideAlert()
          router.push('/')
        }
      })
    }
  }

  const handleSubmit = async () => {
    setLoading(true)

    const isEmpty = checkIsEmpty()

    if (!isEmpty) {
      await handleResetPassword()
    }

    setLoading(false)
  }

  return (
    <Stack spacing={8} mx={'auto'} mt="20" maxW={'lg'} py={12} px={6}>
      <Stack align={'center'}>
        <Heading fontSize={'4xl'} color="orange.400">
          Lupa password
        </Heading>
      </Stack>
      <Box rounded={'lg'} bg={bgBox} boxShadow={'lg'} p={8}>
        <Stack spacing={4}>
          <FormControl id="email" isRequired>
            <FormLabel>Email</FormLabel>
            <Input
              isInvalid={Boolean(errorForm)}
              type="email"
              name="email"
              value={email}
              onChange={handleChangeEmail}
              autoComplete="username"
            />
          </FormControl>

          <Button
            isLoading={loading}
            loadingText="Memproses"
            w="full"
            bg="orange.400"
            _hover={{
              bg: 'orange.500'
            }}
            onClick={handleSubmit}
          >
            Minta reset password
          </Button>
        </Stack>
      </Box>
    </Stack>
  )
}
Example #25
Source File: ContextMenuList.tsx    From wiregui with MIT License 4 votes vote down vote up
ContextMenuList: React.FC<Props & MotionBoxProps> = ({
  children,
  menuId,
  render,
  ...boxProps
}) => {
  const [contextMenusState, setContextMenusState] =
    useRecoilState(contextMenusAtom);

  const menuRef: RefObject<HTMLDivElement> = useRef(null);

  const menu = useMemo(
    () => contextMenusState.menus.find((m) => m.id === menuId),
    [contextMenusState]
  );

  // where should the menu be shown?
  // the ContextMenuTrigger sets this
  const [position, setPosition] = useState<Position>({
    left: -100,
    right: 0,
    top: -100,
    bottom: 0,
  });

  // TODO: Any less manual way to do this
  // figure out where to show the menu
  useEffect(() => {
    let left: number | undefined;
    let right: number | undefined;
    let top: number | undefined;
    let bottom: number | undefined;

    const x = contextMenusState.position.x;
    const y = contextMenusState.position.y;

    const menuHeight = menuRef?.current?.clientHeight;
    const menuWidth = menuRef?.current?.clientWidth;
    const windowWidth = window.innerWidth;
    const windowHeight = window.innerHeight;
    if (!menuHeight || !menuWidth) {
      return;
    }
    if (x + menuWidth > windowWidth) {
      right = windowWidth - x;
    } else {
      left = x;
    }
    if (y + menuHeight > windowHeight) {
      bottom = windowHeight - y;
    } else {
      top = y;
    }
    setPosition({
      top: `${top}px`,
      bottom: `${bottom}px`,
      left: `${left}px`,
      right: `${right}px`,
    });
  }, [menuRef, contextMenusState.position.x, contextMenusState.position.y]);

  // when clicking outside the menu, close it
  useOutsideClick({
    ref: menuRef,
    handler: () => {
      // close all menus
      closeContextMenus();
    },
  });

  const bgColor = useColorModeValue("gray.50", "gray.300");

  const closeContextMenus = () => {
    setContextMenusState((oldState) => {
      return {
        ...oldState,
        position: {
          x: -100,
          y: -100,
        },
        menus: oldState.menus.map((m) => ({
          ...m,
          isOpen: false,
        })),
      };
    });
  };

  return (
    <MotionBox
      variants={motionVariants}
      animate={menu && menu.isOpen ? "enter" : "exit"}
      ref={menuRef}
      borderWidth={1}
      position="fixed"
      bg={bgColor}
      minW={40}
      w={52}
      // maxW={96}
      borderRadius="md"
      display="flex"
      flexDirection="column"
      zIndex="popover"
      {...position}
      {...boxProps}
    >
      {/* either use the render prop or the children */}
      {render
        ? render({
            menuId,
            closeContextMenus,
            passData: contextMenusState.passData,
          })
        : children}
    </MotionBox>
  );
}
Example #26
Source File: notes-list.tsx    From notebook with MIT License 4 votes vote down vote up
NotesList: React.SFC<NotesListProps> = ({
  notes,
  handleClick,
  setNotes
}) => {
  const bg = useColorModeValue("white", "#2f3244");
  const [selectedNote, setSelectedNote] = React.useState<note>();
  const toast = useToast();
  const { isOpen, onOpen, onClose } = useDisclosure();

  const onDelete = (
    id: string,
    e: React.MouseEvent<SVGElement, MouseEvent>
  ) => {
    const newNotes: note[] = notes.filter((note: note) => note.id !== id);
    setNotes(newNotes);
    showToast();
    e.stopPropagation();
  };

  const onClick = (id: string, e: React.MouseEvent<SVGElement, MouseEvent>) => {
    handleClick(id);
    e.stopPropagation();
  };

  const handleSelectedNote = (note: note) => {
    setSelectedNote(note);
    onOpen();
  };

  const showToast = () => {
    toast({
      title: "Note deleted.",
      status: "success",
      position: "top",
      duration: 2000,
      isClosable: true
    });
  };

  return (
    <>
      <AnimateSharedLayout type="crossfade">
        <Box minH={"50vh"}>
          {/* <SimpleGrid
            columns={[1, 2, 2, 3]}
            mt="40px"
            gridGap="10px"
            position="relative"
            overflow="hidden"
          > */}
          <StackGrid columnWidth={330}>
            {notes.map(note => (
              <Fade in={true}>
                <motion.div
                  whileHover={{ y: -10 }}
                  layoutId={note.id}
                  onClick={() => handleSelectedNote(note)}
                >
                  <Center py={2} px={2} key={note.id}>
                    <Box
                      maxH={"400px"}
                      w="100%"
                      boxShadow={"lg"}
                      rounded={"md"}
                      p={6}
                      overflow={"hidden"}
                      cursor="pointer"
                      _hover={{ boxShadow: "xl" }}
                      bg={bg}
                      role="group"
                      // onClick={() => handleClick(note.id, true)}
                    >
                      <Stack>
                        <Flex
                          _groupHover={{ justifyContent: "space-between" }}
                          justifyContent="center"
                          align="center"
                        >
                          <Box>
                            <Text
                              color={"green.500"}
                              textTransform={"uppercase"}
                              fontWeight={800}
                              fontSize={"sm"}
                              letterSpacing={1.1}
                            >
                              Note
                            </Text>
                          </Box>
                          <Box
                            _groupHover={{ display: "block" }}
                            display="none"
                          >
                            <HStack spacing="2">
                              <Icon
                                color={"green.500"}
                                _hover={{ color: "green.600" }}
                                _groupHover={{ display: "block" }}
                                as={EditIcon}
                                w={4}
                                h={4}
                                onClick={e => onClick(note.id, e)}
                              />
                              <Icon
                                color={"green.500"}
                                _hover={{ color: "#ca364a" }}
                                _groupHover={{ display: "block" }}
                                as={DeleteIcon}
                                w={4}
                                h={4}
                                onClick={e => onDelete(note.id, e)}
                              />
                            </HStack>
                          </Box>
                        </Flex>
                        <Heading
                          fontSize={"xl"}
                          fontFamily={"body"}
                          textTransform="capitalize"
                          noOfLines={2}
                        >
                          {note.title}
                        </Heading>

                        <Text
                          color={"gray.500"}
                          fontSize="md"
                          noOfLines={{ base: 3, md: 4 }}
                        >
                          {note.body}
                        </Text>
                      </Stack>
                    </Box>
                  </Center>
                </motion.div>
              </Fade>
            ))}
          </StackGrid>
          {/* </SimpleGrid> */}
        </Box>
        {isOpen ? (
          <NoteModal
            isOpen={isOpen}
            onClose={onClose}
            selectedNote={selectedNote}
          />
        ) : (
          ""
        )}
      </AnimateSharedLayout>
    </>
  );
}
Example #27
Source File: CompetitorComparisonTable.tsx    From coindrop with GNU General Public License v3.0 4 votes vote down vote up
CompetitorComparisonTable: FunctionComponent = () => {
    const theme = useTheme();
    const green = useColorModeValue(theme.colors.green['500'], theme.colors.green['300']);
    const red = useColorModeValue(theme.colors.red['500'], theme.colors.red['300']);
    const orange = useColorModeValue(theme.colors.orange['500'], theme.colors.orange['300']);
    const logoOutlineColor = useColorModeValue(theme.colors.gray['800'], theme.colors.gray['900']);
    const StyledTd: FunctionComponent<{ value: string | number }> = ({ value }) => {
        let backgroundColor;
        switch (value) {
            case 'Unlimited':
            case 'Any':
            case 'None':
            case 'Freemium':
            case 'Yes':
                backgroundColor = green;
                break;
            case '$9/mo':
                backgroundColor = orange;
                break;
            default:
                backgroundColor = red;
        }
        return (
            <td style={{backgroundColor, color: "white"}}>
                {value}
            </td>
        );
    };
    return (
        <Box>
            <Flex
                id="full-width-comparison-table"
                justify="center"
                textAlign="center"
                display={['none', 'none', 'flex']}
            >
                <table className={styles.comparisontable}>
                    <thead>
                        <tr>
                            <th> </th>
                            <th>
                                <Flex align="center">
                                    {coindropData.displayName}
                                    <PiggyLogoIcon ml={1} size="19px" color={logoOutlineColor} />
                                </Flex>
                            </th>
                            {competitorData.map(obj => (
                                <th key={obj.id}>
                                    {obj.displayName}
                                    {obj.icon}
                                </th>
                            ))}
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>Fees</td>
                            {data.map(obj => (
                                <StyledTd value={obj.fees} key={obj.id} />
                            ))}
                        </tr>
                        <tr>
                            <td>Payment methods</td>
                            {data.map(obj => (
                                <StyledTd value={obj.paymentMethods} key={obj.id} />
                            ))}
                        </tr>
                        <tr>
                            <td># Pages per account</td>
                            {data.map(obj => (
                                <StyledTd value={obj.numPagesPerAccount} key={obj.id} />
                            ))}
                        </tr>
                        <tr>
                            <td>Open-source</td>
                            {data.map(obj => (
                                <StyledTd value={obj.isOpenSource} key={obj.id} />
                            ))}
                        </tr>
                        <tr>
                            <td>Subscribers</td>
                            {data.map(obj => (
                                <StyledTd value={obj.subscriberFeatures} key={obj.id} />
                            ))}
                        </tr>
                    </tbody>
                </table>
            </Flex>

            {competitorData.map(obj => (
                <Flex
                    key={obj.id}
                    id={`partial-width-comparison-table-${obj.id}`}
                    justify="center"
                    textAlign="center"
                    display={['flex', 'flex', 'none']}
                >
                    <table className={styles.comparisontable}>
                        <thead>
                            <tr>
                                <th> </th>
                                <th>
                                    <Flex align="center">
                                        Coindrop
                                        <PiggyLogoIcon ml={1} size="19px" color={logoOutlineColor} />
                                    </Flex>
                                </th>
                                <th>
                                    {obj.displayName}
                                    {obj.icon}
                                </th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td>Fees</td>
                                <StyledTd value={coindropData.fees} />
                                <StyledTd value={obj.fees} />
                            </tr>
                            <tr>
                                <td>Payment methods</td>
                                <StyledTd value={coindropData.paymentMethods} />
                                <StyledTd value={obj.paymentMethods} />
                            </tr>
                            <tr>
                                <td># Pages per account</td>
                                <StyledTd value={coindropData.numPagesPerAccount} />
                                <StyledTd value={obj.numPagesPerAccount} />
                            </tr>
                            <tr>
                                <td>Open-source</td>
                                <StyledTd value={coindropData.isOpenSource} />
                                <StyledTd value={obj.isOpenSource} />
                            </tr>
                            <tr>
                                <td>Subscribers</td>
                                <StyledTd value={coindropData.subscriberFeatures} />
                                <StyledTd value={obj.subscriberFeatures} />
                            </tr>
                        </tbody>
                    </table>
                </Flex>
            ))}
        </Box>
    );
}
Example #28
Source File: AuthForm.tsx    From ksana.in with Apache License 2.0 4 votes vote down vote up
export function AuthForm({ state }: IAuthFormProps) {
  const router = useRouter()
  const { showAlert, hideAlert } = useAlertContext()

  const bgBox = useColorModeValue('white', 'gray.700')
  const [internalState, setInternalState] = useState<any>(state)
  const [isLogin, setIsLogin] = useState<any>(state === 'login')

  const [loading, setLoading] = useState<boolean>(false)
  const [errorForm, setErrorForm] = useState<string>('')
  const [email, setEmail] = useState<string>('')
  const [password, setPassword] = useState<string>('')

  const toggleState = () => {
    if (internalState === 'login') {
      setInternalState('register')
      setIsLogin(false)
    } else {
      setInternalState('login')
      setIsLogin(true)
    }
  }

  const handleChangeEmail = (e: ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value
    setEmail(value)
  }

  const handleChangePassword = (e: ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value
    setPassword(value)
  }

  const checkIsEmpty = () => {
    if (email === '' || password === '') {
      setErrorForm('Email dan password tidak boleh dikosongkan.')
      return true
    }

    setErrorForm('')
    return false
  }

  const handleSubmit = async () => {
    setLoading(true)

    const isEmpty = checkIsEmpty()

    if (!isEmpty) {
      if (isLogin) {
        await handleLogin()
      } else {
        await handleRegister()
      }
    }

    setLoading(false)
  }

  const handleLoginGoogle = async () => {
    setLoading(true)
    await loginWithGoogle()
    setLoading(false)
  }

  const handleLoginGithub = async () => {
    setLoading(true)
    await loginWithGithub()
    setLoading(false)
  }

  const handleLoginTwitter = async () => {
    setLoading(true)
    await loginWithTwitter()
    setLoading(false)
  }

  const processResponse = async ({ session, error, stateType = 'login' }: IProcessResponse) => {
    if (error) {
      setErrorForm(error.message)
      return false
    }

    if (session && !error) {
      if (stateType === 'login') {
        // only set for the login flow
        await setSessionToServer(EVENT_SIGN_IN, session)
      }

      showAlert({
        title: `${stateType === 'login' ? 'Login' : 'Register'} success`,
        message: `${
          stateType === 'login'
            ? 'Selamat datang kembali!'
            : 'Terima kasih telah mendaftar. Silahkan melakukan verifikasi dengan mengklik tautan yang kami kirimkan melalui email.'
        }`,
        onClose: () => {
          hideAlert()

          if (stateType === 'login') {
            setTimeout(() => {
              // trigger hard redirect to dashboard page
              // TODO: mutate SWR to reload the user data
              window.location.assign(dashboard)
            }, 500)
          } else {
            router.push('/')
          }
        }
      })
    }
  }

  const handleLogin = async () => {
    const { session, error } = await login({
      email: email,
      password: password
    })

    processResponse({ session, error, stateType: 'login' })
  }

  const handleRegister = async () => {
    const { session, error } = await register({
      email: email,
      password: password
    })

    processResponse({ session, error, stateType: 'register' })

    if (!error) {
      showAlert({
        title: 'Registrasi Berhasil!',
        message:
          'Terima kasih telah mendaftar. Silahkan melakukan verifikasi dengan mengklik tautan yang kami kirimkan melalui email.'
      })
    } else {
      showAlert({
        title: 'Registrasi Gagal!',
        message: 'Silahkan ulangi proses registrasi!'
      })
    }
  }

  const handleKeyPress = (e: KeyboardEvent) => {
    if (e.code === '13') {
      handleSubmit()
    }
  }

  return (
    <Stack spacing={8} mx={'auto'} mt="20" maxW={'lg'} py={12} px={6}>
      <Stack align={'center'}>
        <Heading
          fontWeight={700}
          fontSize={{ base: '3xl', sm: '4xl', md: '5xl' }}
          lineHeight={'110%'}
          color="orange.400"
        >
          {isLogin ? 'Masuk ke akunmu' : 'Daftarkan akun baru'}
        </Heading>
      </Stack>
      <Box rounded={'lg'} bg={bgBox} boxShadow={'lg'} p={8}>
        <VStack
          direction="row"
          align={'center'}
          justify={'center'}
          borderBottom="1px"
          borderColor="gray.200"
          py="4"
        >
          {isEnableGoogleLogin && (
            <Button
              isLoading={loading}
              loadingText="Memproses"
              variant={'outline'}
              w="full"
              onClick={handleLoginGoogle}
              leftIcon={<FcGoogle />}
            >
              {isLogin ? 'Masuk dengan Google' : 'Daftar dengan Google'}
            </Button>
          )}

          {isEnableTwitterLogin && (
            <Button
              isLoading={loading}
              loadingText="Memproses"
              variant={'outline'}
              w="full"
              onClick={handleLoginTwitter}
              leftIcon={<SiTwitter fill="#1DA1F2" />}
            >
              {isLogin ? 'Masuk dengan Twitter' : 'Daftar dengan Twitter'}
            </Button>
          )}

          {isEnableGithubLogin && (
            <Button
              isLoading={loading}
              loadingText="Memproses"
              variant={'outline'}
              w="full"
              onClick={handleLoginGithub}
              leftIcon={<SiGithub />}
            >
              {isLogin ? 'Masuk dengan Github' : 'Daftar dengan Github'}
            </Button>
          )}
        </VStack>

        <Stack spacing={4} mt="4">
          <FormControl id="email" isRequired>
            <FormLabel>Email</FormLabel>
            <Input
              isInvalid={Boolean(errorForm)}
              type="email"
              name="email"
              value={email}
              onChange={handleChangeEmail}
              onKeyPress={handleKeyPress}
              autoComplete="username"
            />
          </FormControl>

          <FormControl id="password" isRequired>
            <FormLabel>Password</FormLabel>
            <Input
              isInvalid={Boolean(errorForm)}
              type="password"
              name="password"
              value={password}
              onChange={handleChangePassword}
              onKeyPress={handleKeyPress}
              autoComplete={isLogin ? 'current-password' : 'new-password'}
            />
          </FormControl>

          {errorForm && (
            <Text color="red.300" fontSize="xs">
              Galat: {errorForm}
            </Text>
          )}

          <Stack spacing={10}>
            {isLogin ? (
              <Stack
                direction={{ base: 'column', sm: 'row' }}
                align={'start'}
                justify={'space-between'}
              >
                <Button variant="link" as={Link} color={'orange.400'} href={forgetPasword}>
                  Lupa password?
                </Button>
              </Stack>
            ) : null}

            <Button
              isLoading={loading}
              loadingText="Memproses"
              w="full"
              bg="orange.400"
              _hover={{
                bg: 'orange.500'
              }}
              color="white"
              onClick={handleSubmit}
            >
              {isLogin ? 'Masuk' : 'Daftar Sekarang'}
            </Button>
          </Stack>

          {isLogin ? (
            <Stack direction="row" align={'center'} justify={'center'}>
              <Text>Belum punya akun? </Text>
              <Button variant="link" as={Link} color={'orange.400'} onClick={toggleState}>
                Daftar sekarang
              </Button>
            </Stack>
          ) : (
            <Stack direction="row" align={'center'} justify={'center'}>
              <Text>Sudah punya akun? </Text>
              <Button variant="link" as={Link} color={'orange.400'} onClick={toggleState}>
                Masuk
              </Button>
            </Stack>
          )}
        </Stack>
      </Box>
    </Stack>
  )
}
Example #29
Source File: notebook-post.tsx    From portfolio with MIT License 4 votes vote down vote up
NotebookPost: React.SFC<PostProps> = () => {
  const textColor = useColorModeValue("gray.500", "gray.200");
  const post = articles[4];

  return (
    <>
      <VStack mt={0} mb={6} spacing={1} align="start">
        <Heading as="h1" fontSize="3xl" lineHeight="shorter" fontWeight="bold">
          {post.title}
        </Heading>
        <Divider
          orientation="horizontal"
          opacity={1}
          borderBottomWidth={0}
          height={"1px"}
          bg={"gray.200"}
        />
      </VStack>
      <Flex
        justifyContent={"space-between"}
        flexDirection={["column", "row", "row"]}
      >
        <HStack spacing={2} isInline>
          <Text fontSize="sm" fontWeight="400" color={textColor}>
            {post.published}
          </Text>
          <Text fontSize="sm" fontWeight="400" color={textColor}>
            •
          </Text>
          <Tooltip hasArrow label="Views" placement="top">
            <Flex alignItems="center">
              <Text
                fontSize="sm"
                noOfLines={1}
                fontWeight="400"
                align="left"
                color={textColor}
              >
                {post.views}
              </Text>
              <Icon as={FaEye} ml={1} color={textColor} />
            </Flex>
          </Tooltip>

          <Text fontSize="sm" fontWeight="600" color={textColor}>
            •
          </Text>
          <Tooltip hasArrow label="Read time" placement="top">
            <Text
              fontSize="sm"
              noOfLines={1}
              fontWeight="400"
              align="left"
              color={textColor}
            >
              {post.readTime}
            </Text>
          </Tooltip>
        </HStack>
        <HStack spacing={1} alignItems="center">
          {post.tags.map(tag => (
            <Tag
              size="sm"
              padding="0 3px"
              key={tag}
              colorScheme={getTagColor(tag)}
            >
              {tag}
            </Tag>
          ))}
        </HStack>
      </Flex>
      <HStack align="end" mt={5}>
        <Link href={post.live} isExternal>
          <Button
            ml={2}
            variant="outline"
            size={["sm"]}
            color={useColorModeValue("green.600", "green.200")}
            bg={useColorModeValue("white", "gray.800")}
            leftIcon={<BiLinkExternal size={18} />}
          >
            Demo
          </Button>
        </Link>
        <Link href={post.github_url} isExternal>
          <Button
            ml={2}
            variant="outline"
            size={["sm"]}
            color={useColorModeValue("green.600", "green.200")}
            bg={useColorModeValue("white", "gray.800")}
            leftIcon={<FiGithub size={18} />}
          >
            Github link
          </Button>
        </Link>
      </HStack>

      <Box height={["35vh", "45vh", "55vh", "70vh"]} marginTop={5}>
        <Carousel images={post.images} />
      </Box>
      <VStack spacing={5} align={"start"} mt={6}>
        <Header fontSize={"xl"} mt={0} mb={0}>
          What will you learn?
        </Header>
        <Box fontSize="md">
          <UnorderedList textAlign="left" paddingLeft={5} m={0}>
            <ListItem>How to create a CRUD app with react</ListItem>
            <ListItem>How to create a responsive app using ChakraUi</ListItem>
            <ListItem>How to use animations with framer-motion</ListItem>
            <ListItem>How to create slider with framer-motion</ListItem>
          </UnorderedList>
        </Box>
      </VStack>
      <VStack spacing={5} align={"start"} mt={6}>
        <Header fontSize={"xl"} mt={0} mb={0}>
          Built with
        </Header>
        <Box fontSize="md">
          <UnorderedList textAlign="left" paddingLeft={5} m={0}>
            <ListItem>
              Programming language -{" "}
              <Link
                href="https://www.typescriptlang.org/"
                isExternal
                color={"blue.500"}
              >
                Typescript
              </Link>
            </ListItem>
            <ListItem>
              Front-end library -{" "}
              <Link
                href="https://github.com/facebook/react/"
                isExternal
                color={"blue.500"}
              >
                React
              </Link>
            </ListItem>
            <ListItem>
              UI components -{" "}
              <Link href="https://chakra-ui.com/" isExternal color={"blue.500"}>
                Chakra-ui
              </Link>
            </ListItem>
            <ListItem>
              Animation library -{" "}
              <Link
                href="https://www.framer.com/motion/"
                isExternal
                color={"blue.500"}
              >
                Framer motion
              </Link>
            </ListItem>
            <ListItem>
              Notes display -{" "}
              <Link
                href="https://github.com/tsuyoshiwada/react-stack-grid"
                isExternal
                color={"blue.500"}
              >
                react-stack-grid
              </Link>
            </ListItem>
            <ListItem>
              Forms Validation -{" "}
              <Link
                href="https://react-hook-form.com/"
                isExternal
                color={"blue.500"}
              >
                React hook form
              </Link>
            </ListItem>
            <ListItem>
              Icons -{" "}
              <Link
                href="https://react-icons.github.io/react-icons/"
                isExternal
                color={"blue.500"}
              >
                React icons
              </Link>
            </ListItem>
            <ListItem>
              Images placeholder -{" "}
              <Link href="https://blurha.sh/" isExternal color={"blue.500"}>
                blurhash
              </Link>
            </ListItem>
            <ListItem>
              Progressive image loading -{" "}
              <Link
                href="https://github.com/FormidableLabs/react-progressive-image"
                isExternal
                color={"blue.500"}
              >
                react-progressive-image
              </Link>
            </ListItem>
          </UnorderedList>
        </Box>
      </VStack>
    </>
  );
}