@chakra-ui/react#Tooltip TypeScript Examples

The following examples show how to use @chakra-ui/react#Tooltip. 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: ActionButton.tsx    From openchakra with MIT License 6 votes vote down vote up
ActionButton = ({
  icon,
  as,
  label,
  onClick,
  colorScheme,
  isLoading,
  ...props
}: Props) => {
  return (
    <Tooltip hasArrow aria-label={label} label={label} zIndex={11} {...props}>
      <IconButton
        variant="ghost"
        as={as}
        isLoading={isLoading}
        onClick={onClick}
        icon={icon}
        aria-label={label}
        colorScheme={colorScheme}
        size="xs"
      />
    </Tooltip>
  )
}
Example #2
Source File: Header.tsx    From openchakra with MIT License 6 votes vote down vote up
CodeSandboxButton = () => {
  const components = useSelector(getComponents)
  const [isLoading, setIsLoading] = useState(false)

  return (
    <Tooltip
      zIndex={100}
      hasArrow
      bg="yellow.100"
      aria-label="Builder mode help"
      label="Export in CodeSandbox"
    >
      <Button
        onClick={async () => {
          setIsLoading(true)
          const code = await generateCode(components)
          setIsLoading(false)
          const parameters = buildParameters(code)

          window.open(
            `https://codesandbox.io/api/v1/sandboxes/define?parameters=${parameters}`,
            '_blank',
          )
        }}
        isLoading={isLoading}
        rightIcon={<ExternalLinkIcon path="" />}
        variant="ghost"
        size="xs"
      >
        Export code
      </Button>
    </Tooltip>
  )
}
Example #3
Source File: ModifiedTooltip.tsx    From lucide with ISC License 6 votes vote down vote up
ModifiedTooltip = ({}) => {
  const { colorMode } = useColorMode();

  return (
    <Tooltip
      hasArrow
      label="This is new or modified icon"
      bg={colorMode === 'light' ? theme.colors.white : theme.colors.gray[700]}
      color={colorMode === 'dark' ? theme.colors.white : null}
    >
      <Box
        {
          ...{
            position: 'absolute',
            height: '8px',
            width: '8px',
            background: '#F56565',
            top: '8px',
            right: '8px',
            borderRadius: '4px'
          }
        }
      />
    </Tooltip>
  )
}
Example #4
Source File: SimpleTooltip.tsx    From rari-dApp with GNU Affero General Public License v3.0 6 votes vote down vote up
SimpleTooltip = ({
  label,
  children,
  placement,
}: {
  label: string;
  placement?:
    | "top"
    | "right"
    | "bottom"
    | "left"
    | "auto"
    | "auto-start"
    | "auto-end"
    | "top-start"
    | "top-end"
    | "bottom-start"
    | "bottom-end"
    | "right-start"
    | "right-end"
    | "left-start"
    | "left-end";
  children: ReactNode;
}) => {
  return (
    <Tooltip
      p={1}
      hasArrow
      bg="#000"
      textAlign="center"
      zIndex={999999999}
      placement={placement ?? "top"}
      aria-label={label}
      label={label}
    >
      {children}
    </Tooltip>
  );
}
Example #5
Source File: WebhooksTable.tsx    From bluebubbles-server with Apache License 2.0 5 votes vote down vote up
WebhooksTable = ({ webhooks }: { webhooks: Array<WebhookItem> }): JSX.Element => {
    const dispatch = useAppDispatch();
    const dialogRef = useRef(null);
    const [selectedId, setSelectedId] = useState(undefined as number | undefined);
    return (
        <Box>
            <Table variant="striped" colorScheme="blue">
                <TableCaption>These are callbacks to receive events from the BlueBubbles Server</TableCaption>
                <Thead>
                    <Tr>
                        <Th>URL</Th>
                        <Th>Event Subscriptions</Th>
                        <Th isNumeric>Actions</Th>
                    </Tr>
                </Thead>
                <Tbody>
                    {webhooks.map(item => (
                        <Tr key={item.id}>
                            <Td>{item.url}</Td>
                            <Td>{JSON.parse(item.events).map((e: string) => webhookEventValueToLabel(e)).join(', ')}</Td>
                            <Td isNumeric>
                                <Grid templateColumns="repeat(2, 1fr)">
                                    <Tooltip label='Edit' placement='bottom'>
                                        <GridItem _hover={{ cursor: 'pointer' }} onClick={() => setSelectedId(item.id)}>
                                            <Icon as={AiOutlineEdit} />
                                        </GridItem>
                                    </Tooltip>
                                    
                                    <Tooltip label='Delete' placement='bottom'>
                                        <GridItem _hover={{ cursor: 'pointer' }} onClick={() => dispatch(remove(item.id))}>
                                            <Icon as={FiTrash} />
                                        </GridItem>
                                    </Tooltip>
                                </Grid>
                            </Td>
                        </Tr>
                    ))}
                </Tbody>
            </Table>

            <AddWebhookDialog
                existingId={selectedId}
                modalRef={dialogRef}
                isOpen={!!selectedId}
                onClose={() => {
                    setSelectedId(undefined);
                }}
            />
        </Box>
    );
}
Example #6
Source File: TrackStreamOptionsSelector.tsx    From takeout-app with MIT License 5 votes vote down vote up
TrackStreamOptionsSelector: React.FC<Props> = ({
  track,
  streamOptionsState: [options, setOptions],
  instance,
}) => {
  const handleOnChange = (key: "caption" | "interpretation") => {
    return (e: React.ChangeEvent<HTMLInputElement>) => {
      const newOptions = { ...options, [`${key}`]: e.target.checked };
      setOptions(newOptions);
    };
  };
  const enAndJa = (track.card?.topic?.labels?.indexOf("EN & JA") ?? -1) !== -1;
  const interpretationLabel = enAndJa ? "English track" : "Japanese to English interpretation";
  return (
    <Box>
      <Stack direction={["row", "row", "row", "column"]} spacing={0}>
        <Tooltip label="Caption (English only)" aria-label="">
          <FormControl display="flex" alignItems="center" h="30px">
            <FormLabel htmlFor={`TrackStreamOptions_${instance}__CC`} aria-hidden="true" m={0} mr={1}>
              <ClosedCaptionIcon w="24px" h="24px" />
            </FormLabel>
            <Switch
              aria-label="Closed Caption"
              id={`TrackStreamOptions_${instance}__CC`}
              isChecked={options.caption}
              onChange={handleOnChange("caption")}
            />
          </FormControl>
        </Tooltip>

        {track.interpretation && track.card?.interpretation ? (
          <Tooltip label={interpretationLabel} aria-label="">
            <FormControl display="flex" alignItems="center" h="30px">
              <FormLabel htmlFor={`TrackStreamOptions_${instance}__interpret`} aria-hidden="true" m={0} mr={1}>
                <TranslateIcon w="24px" h="24px" />
              </FormLabel>
              <Switch
                aria-label={interpretationLabel}
                id={`TrackStreamOptions_${instance}__interpret`}
                isChecked={options.interpretation}
                onChange={handleOnChange("interpretation")}
              />
            </FormControl>
          </Tooltip>
        ) : null}
      </Stack>
    </Box>
  );
}
Example #7
Source File: ChatMessageView.tsx    From takeout-app with MIT License 5 votes vote down vote up
ChatMessageAuthor: React.FC<{ author: ChatSender; highlight: boolean; pinned: boolean }> = ({
  author,
  highlight,
  pinned,
}) => {
  const defaultBg = pinned ? Colors.baseLight : Colors.backgroundColor;
  const { bg, fg } = [
    author.isAdmin ? Colors.nameHighlightOrgz : null,
    highlight && author.isSpeaker ? Colors.nameHighlightSpeaker : null,
    highlight && author.isCommitter ? Colors.nameHighlightCore : null,
    highlight ? Colors.nameHighlightSpeaker : null,
    author.isSpeaker ? { bg: defaultBg, fg: Colors.nameSpeaker } : null,
    author.isCommitter ? { bg: defaultBg, fg: Colors.nameCore } : null,
    pinned ? { bg: defaultBg, fg: Colors.dark } : null,
  ].filter((v) => !!v)[0] || { bg: defaultBg, fg: Colors.textMuted };

  const icons: JSX.Element[] = [];
  if (author.isAdmin) icons.push(<CampaignIcon key="admin" color={fg} />);
  if (author.isStaff) icons.push(<LunchDiningIcon key="staff" color={fg} />);
  if (author.isSpeaker) icons.push(<MicIcon key="speaker" color={fg} />);
  if (author.isCommitter) icons.push(<CommitterIcon key="committer" color={fg} />);

  const tooltipContents: string[] = [];
  if (author.isAdmin) tooltipContents.push("Official Announcement");
  if (author.isStaff) tooltipContents.push("RubyKaigi Staff");
  if (author.isSpeaker) tooltipContents.push("Speaker");
  if (author.isCommitter) tooltipContents.push("Ruby Committer");
  if (author.isAnonymous) tooltipContents.push(`Anonymous ${author.handle}`);

  return (
    <Tooltip label={tooltipContents.length > 0 ? tooltipContents.join(", ") : undefined} display="inline-block">
      <Flex
        display="inline"
        alignItems="center"
        direction="row"
        bgColor={bg}
        borderRadius="4px"
        ml="-4px"
        px="4px"
        py="1px"
      >
        <ChatAuthorName author={author} fg={fg} />
        {icons.length > 0 ? (
          <Text as="span" ml={1} color={fg}>
            {icons}
          </Text>
        ) : null}
      </Flex>
    </Tooltip>
  );
}
Example #8
Source File: repositories-list.tsx    From portfolio with MIT License 5 votes vote down vote up
RepositoriesList = () => {
  const [activeTab, setActiveTab] = React.useState("live");

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

  const handleClick = (type) => {
    activeTab === "live" ? play({ id: "on" }) : play({ id: "off" });
    setActiveTab(type)
  }

  return (
    <PageSlideFade>
      <VStack align="start" spacing={3}>
        <HStack justifyContent={"space-between"} width={"100%"}>
          <Header underlineColor={TURQUOISE} mt={0} mb={0}>
            Open Source
          </Header>
          <HStack>
          <Tooltip hasArrow label="Live github repos" placement="top">
            <IconButton
              aria-label={"live"}
              size="md"
              colorScheme={"linkedin"}
              icon={<RiSignalTowerLine />}
              isActive={activeTab === "live"}
              onClick={() => handleClick('live')}
              {...iconProps}
            />
            </Tooltip>
          <Tooltip hasArrow label="Local github repos" placement="top">
            <IconButton
              aria-label={"live"}
              size="md"
              colorScheme={"linkedin"}
              icon={<RiWifiOffLine />}
              isActive={activeTab === "offline"}
              onClick={() => handleClick('offline')}
              {...iconProps}
            />
            </Tooltip>
          </HStack>
        </HStack>
        <Text
          color={useColorModeValue("gray.500", "gray.200")}
          textAlign="left"
        >
          This page lists some of the open source repositories I have published
          or contributed to.
        </Text>
      </VStack>
      {activeTab === "live" ? <LiveData /> : <OfflineData />}
    </PageSlideFade>
  );
}
Example #9
Source File: Setup.tsx    From bluebubbles-server with Apache License 2.0 5 votes vote down vote up
NavBar = (): JSX.Element => {
    const { colorMode, toggleColorMode } = useColorMode();

    return (
        <Flex
            height="20"
            alignItems="center"
            borderBottomWidth="1px"
            borderBottomColor={useColorModeValue('gray.200', 'gray.700')}
            justifyContent='space-between'
            p={4}
            pl={6}
        >
            <Flex alignItems="center" justifyContent='flex-start'>
                <img src={logo} className="logo" alt="logo" height={48} />
                <Text fontSize="1xl" ml={2}>BlueBubbles</Text>
            </Flex>
            <Flex justifyContent='flex-end'>
                <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="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>
                    <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>
        </Flex>
    );
}
Example #10
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 #11
Source File: IconDetailOverlay.tsx    From lucide with ISC License 4 votes vote down vote up
IconDetailOverlay = ({ open = true, close, icon }) => {
  const toast = useToast();
  const { colorMode } = useColorMode();
  const { tags = [], name } = icon;
  const {color, strokeWidth, size} = useContext(IconStyleContext);
  const iconRef = useRef<SVGSVGElement>(null);
  const [isMobile] = useMediaQuery("(max-width: 560px)")
  const { isOpen, onOpen, onClose } = useDisclosure()

  const handleClose = () => {
    onClose();
    close();
  };

  useEffect(() => {
    if(open) {
      onOpen()
    }
  }, [open])

  const iconStyling = (isLight) => ({
    height: "25vw",
    width: "25vw",
    minHeight: "160px",
    minWidth: "160px",
    maxHeight: "240px",
    maxWidth: "240px",
    color: color,
  });

  const downloadIcon = ({src, name} : IconDownload) => download(src, `${name}.svg`, 'image/svg+xml');

  const copyIcon = ({src, name} : IconDownload) => {
    copy(src);
    toast({
      title: "Copied!",
      description: `Icon "${name}" copied to clipboard.`,
      status: "success",
      duration: 1500,
      isClosable: true
    });
  }

  const downloadPNG = ({src, name}: IconDownload) => {
    const canvas = document.createElement('canvas');
    canvas.width = size;
    canvas.height = size;
    const ctx = canvas.getContext("2d");

    const image = new Image();
    image.src = `data:image/svg+xml;base64,${btoa(src)}`;
    image.onload = function() {
      ctx.drawImage(image, 0, 0);

      const link = document.createElement('a');
      link.download = `${name}.png`;
      link.href = canvas.toDataURL('image/png')
      link.click();
    }
  }

  return (
    <Box
      position="fixed"
      bottom={0}
      zIndex={2}
      width="100%"
      left={0}
      height={0}
      key={name}
    >
      <Slide direction="bottom" in={isOpen} style={{ zIndex: 10 }}>
      <Flex
        alignItems="center"
        justifyContent="space-between"
        pt={4}
        pb={4}
        maxW="850px"
        margin="0 auto"
        w="full"
        px={8}
      >

          <Box
            borderWidth="1px"
            rounded="lg"
            width="full"
            boxShadow={theme.shadows.xl}
            position="relative"
            bg={
              colorMode == "light"
                ? theme.colors.white
                : theme.colors.gray[700]
            }
            padding={8}
          >
            <IconButton
              size="sm"
              aria-label="Close overlay"
              variant="ghost"
              color="current"
              ml="3"
              position="absolute"
              top={4}
              right={4}
              onClick={handleClose}
              icon={<Close />}
          />
            <Flex direction={['column', 'row']} alignItems={['center', 'flex-start']}>
              <Flex>
                <Box
                  borderWidth="1px"
                  rounded="md"
                  position="relative"
                  bg={
                    colorMode == "light"
                      ? theme.colors.whiteAlpha[800]
                      : theme.colors.blackAlpha[500]
                  }
                  padding={0}
                >
                  <div
                    style={iconStyling(colorMode == "light")}
                    className="icon-large"
                  >
                    <IconWrapper
                      content={icon.content}
                      stroke={color}
                      strokeWidth={strokeWidth}
                      height={size}
                      width={size}
                      ref={iconRef}
                    />
                  </div>

                  <svg className="icon-grid" width="24" height="24" viewBox={`0 0 ${size} ${size}`} fill="none" stroke={colorMode == "light" ? '#E2E8F0' : theme.colors.gray[600]} strokeWidth="0.1" xmlns="http://www.w3.org/2000/svg">
                    { Array.from({ length:(size - 1) }, (_, i) => (
                      <g key={`grid-${i}`}>
                        <line key={`horizontal-${i}`} x1={0} y1={i + 1} x2={size} y2={i + 1} />
                        <line key={`vertical-${i}`} x1={i + 1} y1={0} x2={i + 1} y2={size} />
                      </g>
                    )) }
                  </svg>
                </Box>
              </Flex>
              <Flex marginLeft={[0, 8]} w="100%">
                <Box w="100%">
                  <Flex
                    justify={isMobile ? 'center' : 'flex-start'}
                    marginTop={isMobile ? 10 : 0}
                  >
                    <Box
                      position="relative"
                      mb={1}
                      display="inline-block"
                      style={{ cursor: "pointer" }}
                      pr={6}
                    >
                      <Text fontSize="3xl">
                        {icon.name}
                      </Text>
                      { icon?.contributors?.length ? ( <ModifiedTooltip/> ) : null}
                    </Box>
                  </Flex>
                  <Box mb={4}>
                    { tags?.length ? (
                      <Text
                        fontSize="xl"
                        fontWeight="bold"
                        color={
                          colorMode === "light"
                          ? 'gray.600'
                          : 'gray.500'
                        }
                      >
                        { tags.join(' • ') }
                      </Text>
                    ) : ''}

                  {/* <Button size="sm" fontSize="md" variant="ghost" onClick={() => downloadIcon(icon)}>
                    Edit Tags
                  </Button> */}
                  </Box>
                  <Box overflowY="auto" w="100%" pt={1} pb={1}>
                    <ButtonGroup spacing={4}>
                      <Button variant="solid" onClick={() => downloadIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
                        Download SVG
                      </Button>
                      <Button variant="solid" onClick={() => copyIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
                        Copy SVG
                      </Button>
                      <Button variant="solid" onClick={() => downloadPNG({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
                        Download PNG
                      </Button>
                    </ButtonGroup>
                  </Box>
                  { icon?.contributors?.length ? (
                    <>
                      <Heading as="h5" size="sm" marginTop={4} marginBottom={2}>
                        Contributors:
                      </Heading>
                      <AvatarGroup size="md">
                        { icon.contributors.map((commit, index) => (
                          <Link href={`https://github.com/${commit.author}`} isExternal key={`${index}_${commit.sha}`}>
                            <Tooltip label={commit.author} key={commit.sha}>
                              <Avatar name={commit.author} src={`https://github.com/${commit.author}.png?size=88`} />
                            </Tooltip>
                          </Link>
                        )) }
                      </AvatarGroup>
                    </>
                  ) : null }
                </Box>
              </Flex>
            </Flex>
          </Box>

      </Flex>
      </Slide>
    </Box>
  );
}
Example #12
Source File: ContactsTable.tsx    From bluebubbles-server with Apache License 2.0 4 votes vote down vote up
ContactsTable = ({
    contacts,
    onCreate,
    onDelete,
    onUpdate,
    onAddressAdd,
    onAddressDelete
}: {
    contacts: Array<ContactItem>,
    onCreate?: (contact: ContactItem) => void,
    onDelete?: (contactId: number | string) => void,
    onUpdate?: (contact: Partial<ContactItem>) => void,
    onAddressAdd?: (contactId: number | string, address: string) => void;
    onAddressDelete?: (contactAddressId: number) => void;
}): JSX.Element => {
    const dialogRef = useRef(null);
    const [dialogOpen, setDialogOpen] = useBoolean();
    const [selectedContact, setSelectedContact] = useState(null as any | null);

    return (
        <Box>
            <Table variant="striped" colorScheme="blue" size='sm'>
                <Thead>
                    <Tr>
                        <Th>Edit</Th>
                        <Th>Display Name</Th>
                        <Th isNumeric>Addresses</Th>
                    </Tr>
                </Thead>
                <Tbody>
                    {contacts.map(item => {
                        const name = (item.displayName && item.displayName.length > 0)
                            ? item.displayName
                            : [item?.firstName, item?.lastName].filter((e) => e && e.length > 0).join(' ');
                        const addresses = [
                            ...(item.phoneNumbers ?? []).map(e => e.address),
                            ...(item.emails ?? []).map(e => e.address)
                        ];
                        return (
                            <Tr key={`${item.sourceType}-${item.id}-${name}-${addresses.join('_')}`}>
                                <Td _hover={{ cursor: (item?.sourceType === 'api') ? 'auto' : 'pointer' }} onClick={() => {
                                    if (item?.sourceType === 'api') return;
                                    setSelectedContact(item);
                                    setDialogOpen.on();
                                }}>
                                    {(item?.sourceType === 'api') ? (
                                        <Tooltip label="Not Editable" hasArrow aria-label='not editable tooltip'>
                                            <span>
                                                <Icon as={MdOutlineEditOff} />
                                            </span>
                                        </Tooltip>
                                    ): (
                                        <Tooltip label="Click to Edit" hasArrow aria-label='editable tooltip'>
                                            <span>
                                                <Icon as={AiOutlineEdit} />
                                            </span>
                                        </Tooltip>
                                    )}
                                </Td>
                                <Td>{name}</Td>
                                <Td isNumeric>{addresses.map((addr) => (
                                    <Badge ml={2} key={`${name}-${addr}-${addresses.length}`}>{addr}</Badge>
                                ))}</Td>
                            </Tr>
                        );
                    })}
                </Tbody>
            </Table>

            <ContactDialog
                modalRef={dialogRef}
                isOpen={dialogOpen}
                existingContact={selectedContact}
                onDelete={onDelete}
                onCreate={onCreate}
                onUpdate={onUpdate}
                onAddressAdd={onAddressAdd}
                onAddressDelete={onAddressDelete}
                onClose={() => {
                    setSelectedContact(null);
                    setDialogOpen.off();
                }}
            />
        </Box>
    );
}
Example #13
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 #14
Source File: ChatForm.tsx    From takeout-app with MIT License 4 votes vote down vote up
ChatForm: React.FC<Props> = ({ track, channel }) => {
  const chat = useChat();

  const { data: session } = Api.useSession();
  const isStaff = session?.attendee?.is_staff;

  const [errorAlert, setErrorAlert] = React.useState<JSX.Element | null>(null);
  const [isRequesting, setIsRequesting] = React.useState<boolean>(false);

  const { register, handleSubmit, reset, setFocus, watch } = useForm<{
    message: string;
    asAdmin: boolean;
  }>({
    defaultValues: {
      message: "",
      asAdmin: false,
    },
  });

  const asAdmin = watch("asAdmin");

  const onSubmit = handleSubmit(async (data) => {
    if (!chat.session || !channel) return;
    if (isRequesting) return;
    setIsRequesting(true);
    setErrorAlert(null);

    try {
      if (data.asAdmin && isStaff) {
        await Api.sendChatMessage(track.slug, data.message, true);
      } else {
        // Workaround: aws-sdk-v3 sigv4 fails to generate correct signature for payload containing emoji...
        if (/\p{Extended_Pictographic}/u.test(data.message)) {
          await Api.sendChatMessage(track.slug, data.message, false);
        } else {
          await chat.session.postMessage(channel, data.message);
        }
      }
      reset({ message: "", asAdmin: false });
    } catch (e) {
      setErrorAlert(
        <Box my={2}>
          <ErrorAlert error={e} />
        </Box>,
      );
    }
    setFocus("message");
    setIsRequesting(false);
  });

  const shouldDisable = !session?.attendee || !chat.session || !channel;

  // TODO: errorAlert to toast

  return (
    <Box p="16px" bgColor="#ffffff" borderTop="1px solid" borderColor={Colors.chatBorder}>
      {errorAlert}
      <form onSubmit={onSubmit}>
        <VStack w="100%">
          {session && !session.attendee?.is_ready ? (
            <Box w="100%">
              <Alert status="warning">
                <AlertIcon />
                <Text as="span">
                  Set your name at{" "}
                  <Link as={RouterLink} to="/attendee" textDecoration="underline">
                    Settings
                  </Link>{" "}
                  page
                </Text>
              </Alert>
            </Box>
          ) : null}
          <Box w="100%">
            <Textarea
              as={TextareaAutoSize}
              {...register("message")}
              size="sm"
              placeholder={asAdmin ? "SAY SOMETHING AS ADMIN..." : "Send a message"}
              isRequired
              isDisabled={shouldDisable}
              autoComplete="off"
              rows={1}
              minRows={1}
              maxRows={4}
              onKeyPress={(e) => {
                if (e.key == "Enter") {
                  e.preventDefault();
                  onSubmit();
                }
              }}
              css={{ resize: "none" }}
            />
          </Box>
          <Flex w="100%" alignItems="flex-end" direction="row-reverse" justifyContent="space-between">
            <IconButton
              icon={<SendIcon boxSize="14px" />}
              minW="30px"
              w="30px"
              h="30px"
              aria-label="Send"
              type="submit"
              isLoading={isRequesting}
              isDisabled={shouldDisable}
            />
            {isStaff ? (
              <Tooltip label="Send as an official announcement" aria-label="">
                <FormControl display="flex" alignSelf="center" h="30px">
                  <FormLabel htmlFor="ChatForm__asAdmin" aria-hidden="true" m={0} mr={1}>
                    <CampaignIcon w="24px" h="24px" />
                  </FormLabel>
                  <Switch
                    aria-label="Send as an official announcement"
                    id="ChatForm__asAdmin"
                    size="sm"
                    isChecked={asAdmin}
                    isDisabled={shouldDisable}
                    {...register("asAdmin")}
                  />
                </FormControl>
              </Tooltip>
            ) : null}
          </Flex>
        </VStack>
      </form>
    </Box>
  );
}
Example #15
Source File: Header.tsx    From openchakra with MIT License 4 votes vote down vote up
Header = () => {
  const showLayout = useSelector(getShowLayout)
  const showCode = useSelector(getShowCode)
  const dispatch = useDispatch()

  return (
    <DarkMode>
      <Flex
        justifyContent="space-between"
        bg="#1a202c"
        as="header"
        height="3rem"
        px="1rem"
      >
        <Flex
          width="14rem"
          height="100%"
          backgroundColor="#1a202c"
          color="white"
          as="a"
          fontSize="xl"
          flexDirection="row"
          alignItems="center"
          aria-label="Chakra UI, Back to homepage"
        >
          <Box fontSize="2xl" as={AiFillThunderbolt} mr={1} color="teal.100" />{' '}
          <Box fontWeight="bold">open</Box>chakra
        </Flex>

        <Flex flexGrow={1} justifyContent="space-between" alignItems="center">
          <HStack spacing={4} justify="center" align="center">
            <Box>
              <HeaderMenu />
            </Box>
            <FormControl flexDirection="row" display="flex" alignItems="center">
              <Tooltip
                zIndex={100}
                hasArrow
                bg="yellow.100"
                aria-label="Builder mode help"
                label="Builder mode adds extra padding/borders"
              >
                <FormLabel
                  cursor="help"
                  color="gray.200"
                  fontSize="xs"
                  htmlFor="preview"
                  pb={0}
                  mb={0}
                  mr={2}
                  whiteSpace="nowrap"
                >
                  Builder mode
                </FormLabel>
              </Tooltip>
              <LightMode>
                <Switch
                  isChecked={showLayout}
                  colorScheme="teal"
                  size="sm"
                  onChange={() => dispatch.app.toggleBuilderMode()}
                  id="preview"
                />
              </LightMode>
            </FormControl>

            <FormControl display="flex" flexDirection="row" alignItems="center">
              <FormLabel
                color="gray.200"
                fontSize="xs"
                mr={2}
                mb={0}
                htmlFor="code"
                pb={0}
                whiteSpace="nowrap"
              >
                Code panel
              </FormLabel>
              <LightMode>
                <Switch
                  isChecked={showCode}
                  id="code"
                  colorScheme="teal"
                  onChange={() => dispatch.app.toggleCodePanel()}
                  size="sm"
                />
              </LightMode>
            </FormControl>
          </HStack>

          <Stack direction="row">
            <CodeSandboxButton />
            <Popover>
              {({ onClose }) => (
                <>
                  <PopoverTrigger>
                    <Button
                      ml={4}
                      rightIcon={<SmallCloseIcon path="" />}
                      size="xs"
                      variant="ghost"
                    >
                      Clear
                    </Button>
                  </PopoverTrigger>
                  <LightMode>
                    <PopoverContent zIndex={100} bg="white">
                      <PopoverArrow />
                      <PopoverCloseButton />
                      <PopoverHeader>Are you sure?</PopoverHeader>
                      <PopoverBody fontSize="sm">
                        Do you really want to remove all components on the
                        editor?
                      </PopoverBody>
                      <PopoverFooter display="flex" justifyContent="flex-end">
                        <Button
                          size="sm"
                          variant="ghost"
                          colorScheme="red"
                          rightIcon={<CheckIcon path="" />}
                          onClick={() => {
                            dispatch.components.reset()
                            if (onClose) {
                              onClose()
                            }
                          }}
                        >
                          Yes, clear
                        </Button>
                      </PopoverFooter>
                    </PopoverContent>
                  </LightMode>
                </>
              )}
            </Popover>
          </Stack>
        </Flex>

        <Stack
          justifyContent="flex-end"
          width="13rem"
          align="center"
          direction="row"
          spacing="2"
        >
          <Link isExternal href="https://github.com/premieroctet/openchakra">
            <Box as={DiGithubBadge} size={32} color="gray.200" />
          </Link>
          <Box lineHeight="shorter" color="white" fontSize="xs">
            by{' '}
            <Link isExternal href="https://premieroctet.com" color="teal.100">
              Premier Octet
            </Link>
          </Box>
        </Stack>
      </Flex>
    </DarkMode>
  )
}
Example #16
Source File: HomeLayout.tsx    From bluebubbles-server with Apache License 2.0 4 votes vote down vote up
HomeLayout = (): JSX.Element => {
    const address = useAppSelector(state => state.config.server_address);
    const fcmClient = useAppSelector(state => state.config.fcm_client);
    const password = useAppSelector(state => state.config.password);
    const port = useAppSelector(state => state.config.socket_port);
    const qrCode = fcmClient ? buildQrData(password, address, fcmClient) : null;

    return (
        <Box p={3} borderRadius={10}>
            <Flex flexDirection="column">
                <Stack direction='column' p={5}>
                    <Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
                        <Text fontSize='2xl'>Connection Details</Text>
                        <Popover trigger='hover'>
                            <PopoverTrigger>
                                <Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
                                    <AiOutlineInfoCircle />
                                </Box>
                            </PopoverTrigger>
                            <PopoverContent>
                                <PopoverArrow />
                                <PopoverCloseButton />
                                <PopoverHeader>Information</PopoverHeader>
                                <PopoverBody>
                                    <Text>
                                        This page will detail your current connection details. This includes your&nbsp;
                                        server address and your local port.
                                    </Text>
                                    <br />
                                    <UnorderedList>
                                        <ListItem><strong>Server Address:</strong> This is the address that your clients will connect to</ListItem>
                                        <ListItem><strong>Local Port:</strong> This is the port that the HTTP server is running on, 
                                            and the port you will use when port forwarding&nbsp;
                                            for a dynamic DNS
                                        </ListItem>
                                    </UnorderedList>
                                </PopoverBody>
                            </PopoverContent>
                        </Popover>
                    </Flex>
                    <Divider orientation='horizontal' />
                    <Spacer />
                    <Flex flexDirection="row" justifyContent="space-between">
                        <Stack>
                            <Flex flexDirection="row" alignItems='center'>
                                <Text fontSize='md' fontWeight='bold' mr={2}>Server Address: </Text>
                                {(!address) ? (
                                    <SkeletonText noOfLines={1} />
                                ) : (
                                    <Text fontSize='md'>{address}</Text>
                                )}
                                <Tooltip label='Copy Address'>
                                    <IconButton
                                        ml={3}
                                        size='md'
                                        aria-label='Copy Address'
                                        icon={<BiCopy size='22px' />}
                                        onClick={() => copyToClipboard(address)}
                                    />
                                </Tooltip>
                                <Popover placement='bottom' isLazy={true}>
                                    <PopoverTrigger>
                                        <Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }} >
                                            <Tooltip label='Show QR Code'>
                                                <IconButton
                                                    ml={1}
                                                    size='md'
                                                    aria-label='Show QR Code'
                                                    icon={<AiOutlineQrcode size='24px' />}
                                                />
                                            </Tooltip>
                                        </Box>
                                    </PopoverTrigger>
                                    <PopoverContent>
                                        <PopoverArrow />
                                        <PopoverCloseButton />
                                        <PopoverHeader>QR Code</PopoverHeader>
                                        <PopoverBody>
                                            <Flex justifyContent='center' flexDirection='column' alignItems='center'>
                                                <Text>
                                                    Your QR Code contains your server configuration so that clients can connect.
                                                    Your QR Code should remain <strong>private</strong> as it contains sensitive information!
                                                </Text>
                                                <Box border="5px solid" borderColor='white' mt={4} height='266px' width='266px' borderRadius='lg' mb={3}>
                                                    {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
                                                    {/* @ts-ignore: ts2876 */}
                                                    {(qrCode) ? <QRCode value={qrCode as string} /> : null}
                                                </Box>
                                            </Flex>
                                        </PopoverBody>
                                    </PopoverContent>
                                </Popover>
                            </Flex>
                            <Flex flexDirection="row">
                                <Text fontSize='md' fontWeight='bold' mr={2}>Local Port: </Text>
                                {(!port) ? (
                                    <SkeletonText noOfLines={1} />
                                ) : (
                                    <Text fontSize='md'>{port}</Text>
                                )}
                            </Flex>
                        </Stack>
                        <Divider orientation="vertical" />
                    </Flex>
                </Stack>
                <Stack direction='column' p={5}>
                    <Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
                        <Text fontSize='2xl'>iMessage Highlights</Text>
                        <Popover trigger='hover'>
                            <PopoverTrigger>
                                <Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
                                    <AiOutlineInfoCircle />
                                </Box>
                            </PopoverTrigger>
                            <PopoverContent>
                                <PopoverArrow />
                                <PopoverCloseButton />
                                <PopoverHeader>Information</PopoverHeader>
                                <PopoverBody>
                                    <Text>
                                        These are just some fun stats that I included to give you a quick "snapshot"
                                        of your iMessage history on the Mac Device. This does not include messages that
                                        are on Apple's servers, only what is local to this device.
                                    </Text>
                                </PopoverBody>
                            </PopoverContent>
                        </Popover>
                    </Flex>
                    <Divider orientation='horizontal' />
                    <Spacer />
                    { /* Delays are so older systems do not freeze when requesting data from the databases */ }
                    <SimpleGrid columns={3} spacing={5}>
                        <TotalMessagesStatBox />
                        <TopGroupStatBox delay={200} />
                        <BestFriendStatBox delay={400} />
                        <DailyMessagesStatBox delay={600} />
                        <TotalPicturesStatBox delay={800} />
                        <TotalVideosStatBox delay={1000} />
                    </SimpleGrid>
                </Stack>
            </Flex>
        </Box>
    );
}
Example #17
Source File: index.tsx    From ksana.in with Apache License 2.0 4 votes vote down vote up
export function UrlForm({ user, onSuccess }: IUrlFormProps) {
  const { showAlert, hideAlert } = useAlertContext()

  const [url, setUrl] = useState<string>('')
  const [slug, setSlug] = useState<string>('')
  const [isCheckPass, setIsCheckPass] = useState<boolean>(false)
  const [isDynamic, setIsDynamic] = useState<boolean>(false)
  const [errorUrl, setErrorUrl] = useState<boolean | string>(false)
  const [errorSlug, setErrorSlug] = useState<boolean | string>(false)
  const [loading, setLoading] = useState<boolean>(false)

  const handleChangeUrl = (e: ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value
    setUrl(value)
    setErrorUrl('')
  }

  const handleChangeSlug = (e: ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value
    setSlug(value)
    setErrorSlug('')
  }

  const handleChangeIsDynamic = (e: ChangeEvent<HTMLInputElement>) => {
    const value = e.target.checked
    setIsDynamic(value)
  }

  const resetErrorMessage = () => {
    setErrorUrl('')
    setErrorSlug('')
  }

  const checkIsEmpty = () => {
    if (url === '') {
      setErrorUrl('URL dan slug tidak bisa dikosongkan')
      return true
    }

    if (url.indexOf('http://') === -1 && url.indexOf('https://') === -1) {
      setErrorUrl('Pastikan URL dimulai dengan http:// atau https://')
      return true
    }

    if (slug === '') {
      setErrorSlug('URL dan slug tidak bisa dikosongkan')
      return true
    }

    return false
  }

  const checkParamRequired = () => {
    const params = url.match(/{param}/g) || []

    if (isDynamic && !params.length) {
      setErrorUrl('Tautan dinamis membutuhkan teks {param} di dalamnya')
      return false
    }

    if (isDynamic && params.length > 1) {
      setErrorUrl('Teks {param} cukup satu saja')
      return false
    }

    return true
  }

  const handleCheckAvailability = async () => {
    setLoading(true)
    resetErrorMessage()
    const isEmpty = checkIsEmpty()
    const hasParam = checkParamRequired()
    if (!isEmpty && hasParam) {
      const response = await checkSlug({ slug: sanitizeSlug(slug) })
      if (response.error) {
        setIsCheckPass(true)
        resetErrorMessage()
      } else {
        setErrorSlug(`Slug ${slug} telah digunakan, coba slug lain`)
      }
    }
    setLoading(false)
  }

  const handleSaveNew = async () => {
    setLoading(true)
    const isEmpty = checkIsEmpty()
    if (!isEmpty) {
      const { error: errorInsert } = await saveUrl({
        url: url,
        slug: sanitizeSlug(slug),
        is_dynamic: isDynamic,
        userId: user?.id
      })

      if (!errorInsert) {
        showAlert({
          title: 'Sukses menyimpan tautan baru',
          message: 'Tautan telah disimpan dalam basis data kami, silahkan mulai bagikan',
          onClose: () => {
            hideAlert()
            mutate(apiUrlsGet(user?.id))
            setUrl('')
            setSlug('')
            setIsCheckPass(false)
            resetErrorMessage()
            onSuccess()
          }
        })
      } else {
        showAlert({
          title: 'Terjadi galat pada saat berusaha menyimpan data',
          message: `Pesan: ${errorInsert.message}`,
          onClose: () => {
            hideAlert()
            setIsCheckPass(false)
            resetErrorMessage()
          }
        })
      }
    }
    setLoading(false)
  }

  return (
    <Box width={{ base: '100%' }}>
      <Stack spacing={4} direction={{ base: 'column' }}>
        <FormControl id="url" isRequired>
          <Input
            isRequired
            isInvalid={Boolean(errorUrl)}
            size="lg"
            name="url"
            placeholder={'Tautan yang akan dipercantik'}
            variant="filled"
            value={url}
            onChange={handleChangeUrl}
          />
          {errorUrl && <FormHelperText color="red.500">Error: {errorUrl}</FormHelperText>}
          <FormHelperText>
            Membutuhkan tautan dalam bentuk utuh, termasuk awalan https://
          </FormHelperText>
          {isDynamic && (
            <FormHelperText>
              Sisipkan teks <code>{'{param}'}</code> pada tautan
            </FormHelperText>
          )}
        </FormControl>

        <FormControl display="flex" alignItems="center">
          <FormLabel htmlFor="is-dynamic" mb="0" display="flex">
            Tautan dinamis{' '}
            <Tooltip
              label="Kamu bisa membuat tautan dinamis macam: https://mazipan.space/{param}"
              placement="bottom"
            >
              <i>
                <HiQuestionMarkCircle />
              </i>
            </Tooltip>
          </FormLabel>
          <Switch id="is-dynamic" onChange={handleChangeIsDynamic} />
        </FormControl>

        <FormControl id="slug" isRequired>
          <InputGroup size="lg">
            <InputLeftAddon
              color={'orange.400'}
              fontWeight="bold"
              px={2}
              children={HOME?.replace('https://', '').replace('http://', '')}
              fontSize="xs"
            />
            <Input
              isRequired
              isInvalid={Boolean(errorSlug)}
              size="lg"
              name="slug"
              placeholder={'Slug cantik dambaanmu'}
              variant="filled"
              value={slug}
              onChange={handleChangeSlug}
            />
          </InputGroup>
          {errorSlug && <FormHelperText color="red.500">Error: {errorSlug}</FormHelperText>}
          <FormHelperText>
            Hanya diperbolehkan menggunakan huruf, angka, karakter titik dan strip saja
          </FormHelperText>
        </FormControl>

        {isCheckPass ? (
          <Button
            isLoading={loading}
            loadingText="Processing"
            size="lg"
            px={6}
            mt="4"
            color={'white'}
            bg={'green.400'}
            _hover={{
              bg: 'green.500'
            }}
            _focus={{
              bg: 'green.500'
            }}
            onClick={handleSaveNew}
          >
            Simpan sekarang
          </Button>
        ) : (
          <Button
            isLoading={loading}
            loadingText="Processing"
            size="lg"
            px={6}
            my="4"
            color={'white'}
            bg={'orange.400'}
            _hover={{
              bg: 'orange.500'
            }}
            _focus={{
              bg: 'orange.500'
            }}
            onClick={handleCheckAvailability}
          >
            Cek ketersediaan
          </Button>
        )}
      </Stack>
    </Box>
  )
}
Example #18
Source File: repositories-list-item.tsx    From notebook with MIT License 4 votes vote down vote up
RepositoriesListItem: React.SFC<RepositoriesListItemProps> = ({
  repo
}) => {
  const [repoId, setRepoId] = React.useState<number>(0);
  const bg = useColorModeValue("white", "#2f3244");
  const textColor = useColorModeValue("gray.600", "#b5b1b1");
  const { isOpen, onOpen, onClose } = useDisclosure();

  const handleClick = (id: number) => {
    setRepoId(id);
    onOpen();
  };

  return (
    <>
      <Center>
        <Box
          maxW="sm"
          height="fit-content"
          borderWidth="1px"
          borderRadius="lg"
          overflow="hidden"
          boxShadow="md"
          mx="5px"
          mb="10px"
          mt="10px"
          _hover={{ boxShadow: "lg" }}
        >
          {/* <Image
          height={{ base: "28vh", lg: "32vh" }}
          cursor={repo.coverImage ? "pointer" : "auto"}
          width={"100%"}
          src={repo.coverImage}
          objectFit="cover"
          alt="cover image"
          fallbackSrc="https://via.placeholder.com/320x216/DCDFDF/ffffff/?text=CoverImage"
          fallbackSrc={placeholder}
          onClick={() => handleClick(repo.coverImage)}
        /> */}
          <LazyImage
            id={repo.id}
            src={repo.coverImage}
            blurHash={repo.blurHash}
            handleClick={handleClick}
          />

          <Box p="5" bg={bg}>
            <Flex justifyContent="space-between" alignItems="center">
              <Box
                mt="1"
                fontWeight="semibold"
                as="h6"
                fontSize="md"
                lineHeight="tight"
                textAlign="left"
                isTruncated
              >
                <Link
                  href={repo.liveLink || repo.githubLink}
                  textDecoration={"none !important"}
                  isExternal
                >
                  {repo.title}
                  <ExternalLinkIcon mx="3px" />
                </Link>
              </Box>
              <Box mt="1">
                {repo.stars ? (
                  <Link
                    href={repo.githubLink}
                    textDecoration={"none !important"}
                    isExternal
                  >
                    <Tooltip hasArrow label="Github stars" placement="top-end">
                      <Box>
                        <StarIcon color="teal.300" fontSize="sm" />
                        <Box as="span" ml="2" color={textColor} fontSize="sm">
                          {repo.stars}
                        </Box>
                      </Box>
                    </Tooltip>
                  </Link>
                ) : (
                  ""
                )}
              </Box>
            </Flex>
            <Box textAlign="left">
              <HStack spacing="1" mt="2" mb="2">
                {repo.technologies.map((tech, index) => (
                  <Badge
                    borderRadius="full"
                    px="1"
                    colorScheme={tech.color}
                    textTransform="lowercase"
                    key={index}
                  >
                    {tech.name}
                  </Badge>
                ))}
              </HStack>
            </Box>
            <Box color={textColor} fontSize="md" textAlign="left">
              {repo.desc}
            </Box>
          </Box>
        </Box>
      </Center>
      <Carousel
        repoId={repoId}
        onOpen={onOpen}
        onClose={onClose}
        isOpen={isOpen}
      />
    </>
  );
}
Example #19
Source File: post-card.tsx    From portfolio with MIT License 4 votes vote down vote up
PostCard: React.SFC<PostCardProps> = ({ article }) => {
  const textColor = useColorModeValue("gray.500", "gray.200");
  const devIcon = useColorModeValue(dev, dev2);

  return (
    <CardTransition>
      <VStack
        spacing={1}
        p={4}
        isExternal
        _hover={{ shadow: "md", textDecoration: "none" }}
        borderWidth="1px"
        position="relative"
        rounded="md"
        bg={useColorModeValue("white", "gray.800")}
        align="left"
      >
        {article.external ? (
          <Tooltip hasArrow label="Dev.to" placement="top">
            <Image
              src={devIcon}
              width="2rem"
              height="2rem"
              position="absolute"
              color="#cbd5e0"
              right="0.5rem"
              top="-14px"
            />
          </Tooltip>
        ) : (
          <Tooltip hasArrow label="mahmad.me" placement="top">
            <Box position="absolute" color="#cbd5e0" right="0.5rem" top="-14px">
              <Badge ml="1" variant="solid" colorScheme="blackAlpha">
                Website
              </Badge>
            </Box>
          </Tooltip>
        )}
        <Heading fontSize="lg" align="left" mt={0}>
          {article.external ? (
            <Text as={Link} href={article.link} target="_blank">
              {article.title}
            </Text>
          ) : (
            <Link as={NavLink} to={article.link}>
              {article.title}
            </Link>
          )}
          {article.isNew && (
            <Badge
              ml="1"
              mb="1"
              colorScheme="green"
              fontSize="0.7em"
              lineHeight={1.5}
            >
              New
            </Badge>
          )}
        </Heading>
        <HStack spacing={2} isInline>
          <Tooltip hasArrow label="Published" placement="top">
            <Text fontSize="sm" fontWeight="400" color={textColor}>
              {article.published}
            </Text>
          </Tooltip>
          <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}
              >
                {article.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}
            >
              {article.readTime}
            </Text>
          </Tooltip>
          <HStack spacing={1} alignItems="center" d={["none", "none", "flex"]}>
            {article.tags.map(tag => (
              <Tag
                size="sm"
                padding="0 3px"
                key={tag}
                colorScheme={getTagColor(tag)}
              >
                {tag}
              </Tag>
            ))}
          </HStack>
        </HStack>
        <HStack spacing={1} alignItems="center" d={["flex", "flex", "none"]}>
          {article.tags.map(tag => (
            <Tag
              size="sm"
              padding="0 3px"
              key={tag}
              colorScheme={getTagColor(tag)}
            >
              {tag}
            </Tag>
          ))}
        </HStack>
        <Text align="left" fontSize="md" noOfLines={4} color={textColor}>
          {article.desc}
        </Text>
      </VStack>
    </CardTransition>
  );
}
Example #20
Source File: index.tsx    From jsonschema-editor-react with Apache License 2.0 4 votes vote down vote up
SchemaRoot: React.FunctionComponent<SchemaArrayProps> = (
	props: React.PropsWithChildren<SchemaArrayProps>
) => {
	const state = useState(props.schemaState);
	const isReadOnlyState = useState(props.isReadOnly);

	return (
		<>
			{props.onSchemaChange(JSON.stringify(state.value))}
			<Flex
				data-testid="jsonschema-editor"
				direction="row"
				wrap="nowrap"
				size="sm"
				mt={2}
				mr={5}
			>
				<Input isDisabled placeholder="root" margin={2} variant="outline" />
				<Tooltip
					hasArrow
					aria-label="All Required"
					label="All Required"
					placement="top"
				>
					<Checkbox
						isDisabled={isReadOnlyState.value}
						margin={2}
						width={20}
						colorScheme="blue"
					/>
				</Tooltip>

				<Select
					variant="outline"
					isDisabled={isReadOnlyState.value}
					value={state.type.value ?? ""}
					size="sm"
					margin={2}
					placeholder="Choose root data type"
					onChange={(evt: React.ChangeEvent<HTMLSelectElement>) => {
						const newSchema = handleTypeChange(
							evt.target.value as JSONSchema7TypeName,
							false
						);
						state.set(newSchema as JSONSchema7);
					}}
				>
					<option key="object" value="object">
						object
					</option>
					<option key="array" value="array">
						array
					</option>
				</Select>
				<Input
					value={state.value?.title ?? ""}
					isDisabled={isReadOnlyState.value}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Title"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						state.title.set(evt.target.value);
					}}
				/>
				<Input
					value={state.value?.description ?? ""}
					isDisabled={isReadOnlyState.value}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Description"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						state.description.set(evt.target.value);
					}}
				/>

				{state.value?.type === "object" && (
					<>
						<Tooltip
							hasArrow
							aria-label="Add Child Node"
							label="Add Child Node"
							placement="top"
						>
							<IconButton
								isRound
								isDisabled={isReadOnlyState.value}
								size="sm"
								mt={2}
								mb={2}
								mr={2}
								variant="link"
								colorScheme="green"
								fontSize="16px"
								icon={<IoIosAddCircleOutline />}
								aria-label="Add Child Node"
								onClick={() => {
									const fieldName = `field_${random()}`;
									(state.properties as State<{
										[key: string]: JSONSchema7;
									}>)[fieldName].set(getDefaultSchema(DataType.string));
								}}
							/>
						</Tooltip>
					</>
				)}
			</Flex>
		</>
	);
}
Example #21
Source File: index.tsx    From jsonschema-editor-react with Apache License 2.0 4 votes vote down vote up
SchemaItem: React.FunctionComponent<SchemaItemProps> = (
	props: React.PropsWithChildren<SchemaItemProps>
) => {
	const {
		name,
		itemStateProp,
		showadvanced,
		required,
		parentStateProp,
		isReadOnly,
	} = props;

	// const itemState = useState(itemStateProp);
	const parentState = useState(parentStateProp);
	const parentStateOrNull: State<JSONSchema7> | undefined = parentState.ornull;
	const propertiesOrNull:
		| State<{
				[key: string]: JSONSchema7Definition;
		  }>
		| undefined = parentStateOrNull.properties.ornull;

	const nameState = useState(name);
	const isReadOnlyState = useState(isReadOnly);

	const itemState = useState(
		(parentStateProp.properties as State<{
			[key: string]: JSONSchema7;
		}>).nested(nameState.value)
	);

	const { length } = parentState.path.filter((name) => name !== "properties");
	const tagPaddingLeftStyle = {
		paddingLeft: `${20 * (length + 1)}px`,
	};

	const isRequired = required
		? required.length > 0 && required.includes(name)
		: false;
	const toast = useToast();

	// Debounce callback
	const debounced = useDebouncedCallback(
		// function
		(newValue: string) => {
			// Todo: make toast for duplicate properties
			if (propertiesOrNull && propertiesOrNull[newValue].value) {
				toast({
					title: "Duplicate Property",
					description: "Property already exists!",
					status: "error",
					duration: 1000,
					isClosable: true,
					position: "top",
				});
			} else {
				const oldName = name;
				const proptoupdate = newValue;

				const newobj = renameKeys(
					{ [oldName]: proptoupdate },
					parentState.properties.value
				);
				parentStateOrNull.properties.set(JSON.parse(JSON.stringify(newobj)));
			}
		},
		// delay in ms
		1000
	);

	if (!itemState.value) {
		return <></>;
	}

	return (
		<div>
			<Flex
				alignContent="space-evenly"
				direction="row"
				wrap="nowrap"
				className="schema-item"
				style={tagPaddingLeftStyle}
			>
				<Input
					isDisabled={isReadOnlyState.value}
					defaultValue={nameState.value}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Enter property name"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						debounced(evt.target.value);
					}}
				/>
				<Checkbox
					isDisabled={isReadOnlyState.value}
					isChecked={isRequired}
					margin={2}
					colorScheme="blue"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						if (!evt.target.checked && required.includes(name)) {
							(parentState.required as State<string[]>)[
								required.indexOf(name)
							].set(none);
						} else {
							parentState.required.merge([name]);
						}
					}}
				/>
				<Select
					isDisabled={false}
					variant="outline"
					value={itemState.type.value}
					size="sm"
					margin={2}
					placeholder="Choose data type"
					onChange={(evt: React.ChangeEvent<HTMLSelectElement>) => {
						const newSchema = handleTypeChange(
							evt.target.value as JSONSchema7TypeName,
							false
						);
						itemState.set(newSchema as JSONSchema7);
					}}
				>
					{SchemaTypes.map((item, index) => {
						return (
							<option key={String(index)} value={item}>
								{item}
							</option>
						);
					})}
				</Select>
				<Input
					isDisabled={isReadOnlyState.value}
					value={itemState.title.value || ""}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Title"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						itemState.title.set(evt.target.value);
					}}
				/>
				<Input
					isDisabled={isReadOnlyState.value}
					value={itemState.description.value || ""}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Description"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						itemState.description.set(evt.target.value);
					}}
				/>

				{itemState.type.value !== "object" && itemState.type.value !== "array" && (
					<Tooltip
						hasArrow
						aria-label="Advanced Settings"
						label="Advanced Settings"
						placement="top"
					>
						<IconButton
							isRound
							isDisabled={isReadOnlyState.value}
							size="sm"
							mt={2}
							mb={2}
							ml={1}
							variant="link"
							colorScheme="blue"
							fontSize="16px"
							icon={<FiSettings />}
							aria-label="Advanced Settings"
							onClick={() => {
								showadvanced(name);
							}}
						/>
					</Tooltip>
				)}

				<Tooltip
					hasArrow
					aria-label="Remove Node"
					label="Remove Node"
					placement="top"
				>
					<IconButton
						isRound
						isDisabled={isReadOnlyState.value}
						size="sm"
						mt={2}
						mb={2}
						ml={1}
						variant="link"
						colorScheme="red"
						fontSize="16px"
						icon={<AiOutlineDelete />}
						aria-label="Remove Node"
						onClick={() => {
							const updatedState = deleteKey(
								nameState.value,
								JSON.parse(JSON.stringify(parentState.properties.value))
							);
							parentState.properties.set(updatedState);
						}}
					/>
				</Tooltip>

				{itemState.type?.value === "object" ? (
					<DropPlus
						isDisabled={isReadOnlyState.value}
						parentStateProp={parentState}
						itemStateProp={itemStateProp}
					/>
				) : (
					<Tooltip
						hasArrow
						aria-label="Add Sibling Node"
						label="Add Sibling Node"
						placement="top"
					>
						<IconButton
							isRound
							isDisabled={isReadOnlyState.value}
							size="sm"
							mt={2}
							mb={2}
							mr={2}
							variant="link"
							colorScheme="green"
							fontSize="16px"
							icon={<IoIosAddCircleOutline />}
							aria-label="Add Sibling Node"
							onClick={() => {
								if (propertiesOrNull) {
									const fieldName = `field_${random()}`;
									propertiesOrNull
										?.nested(fieldName)
										.set(getDefaultSchema(DataType.string) as JSONSchema7);
								}
							}}
						/>
					</Tooltip>
				)}
			</Flex>
			{itemState.type?.value === "object" && (
				<SchemaObject isReadOnly={isReadOnlyState} schemaState={itemState} />
			)}
			{itemState.type?.value === "array" && (
				<SchemaArray isReadOnly={isReadOnlyState} schemaState={itemState} />
			)}
		</div>
	);
}
Example #22
Source File: index.tsx    From jsonschema-editor-react with Apache License 2.0 4 votes vote down vote up
SchemaArray: React.FunctionComponent<SchemaArrayProps> = (
	props: React.PropsWithChildren<SchemaArrayProps>
) => {
	const { schemaState, isReadOnly } = props;

	const state = useState(schemaState.items as JSONSchema7);
	const isReadOnlyState = useState(isReadOnly);

	const { length } = state.path.filter((name) => name !== "properties");
	const tagPaddingLeftStyle = {
		paddingLeft: `${20 * (length + 1)}px`,
	};

	const onCloseAdvanced = (): void => {
		localState.isAdvancedOpen.set(false);
	};

	const showadvanced = (): void => {
		localState.isAdvancedOpen.set(true);
	};

	const focusRef = React.createRef<HTMLElement>();

	const localState = useState({
		isAdvancedOpen: false,
	});

	return (
		<>
			<Flex
				direction="row"
				wrap="nowrap"
				className="array-item"
				mt={2}
				mr={5}
				style={tagPaddingLeftStyle}
			>
				<Input
					key="Items"
					isDisabled
					value="Items"
					size="sm"
					flexShrink={1}
					margin={2}
					variant="outline"
				/>
				<Checkbox isDisabled margin={2} colorScheme="blue" />
				<Select
					variant="outline"
					isDisabled={isReadOnlyState.value}
					value={state.type.value as JSONSchema7TypeName}
					size="sm"
					margin={2}
					placeholder="Choose data type"
					onChange={(evt: React.ChangeEvent<HTMLSelectElement>) => {
						const newSchema = handleTypeChange(
							evt.target.value as JSONSchema7TypeName,
							false
						);
						state.set(newSchema as JSONSchema7);
					}}
				>
					{SchemaTypes.map((item, index) => {
						return (
							<option key={String(index)} value={item}>
								{item}
							</option>
						);
					})}
				</Select>
				<Input
					value={state.title.value}
					isDisabled={isReadOnlyState.value}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Title"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						state.title.set(evt.target.value);
					}}
				/>
				<Input
					value={state.description.value}
					isDisabled={isReadOnlyState.value}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Description"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						state.description.set(evt.target.value);
					}}
				/>
				<Tooltip
					hasArrow
					aria-label="Advanced Settings"
					label="Advanced Settings"
					placement="top"
				>
					<IconButton
						isRound
						isDisabled={isReadOnlyState.value}
						size="sm"
						mt={2}
						mb={2}
						ml={1}
						variant="link"
						colorScheme="blue"
						fontSize="16px"
						icon={<FiSettings />}
						aria-label="Advanced Settings"
						onClick={() => {
							showadvanced();
						}}
					/>
				</Tooltip>

				{state.type.value === "object" && (
					<Tooltip
						hasArrow
						aria-label="Add Child Node"
						label="Add Child Node"
						placement="top"
					>
						<IconButton
							isRound
							isDisabled={isReadOnlyState.value}
							size="sm"
							mt={2}
							mb={2}
							mr={2}
							variant="link"
							colorScheme="green"
							fontSize="16px"
							icon={<IoIosAddCircleOutline />}
							aria-label="Add Child Node"
							onClick={() => {
								const fieldName = `field_${random()}`;
								(state.properties as State<{
									[key: string]: JSONSchema7;
								}>)[fieldName].set(getDefaultSchema(DataType.string));
							}}
						/>
					</Tooltip>
				)}
			</Flex>
			{state.type?.value === "object" && (
				<SchemaObject isReadOnly={isReadOnlyState} schemaState={state} />
			)}
			{state.type?.value === "array" && (
				<SchemaArray isReadOnly={isReadOnlyState} schemaState={state} />
			)}
			<Modal
				isOpen={localState.isAdvancedOpen.get()}
				finalFocusRef={focusRef}
				size="lg"
				onClose={onCloseAdvanced}
			>
				<ModalOverlay />
				<ModalContent>
					<ModalHeader textAlign="center">Advanced Schema Settings</ModalHeader>

					<ModalBody>
						<AdvancedSettings itemStateProp={state} />
					</ModalBody>

					<ModalFooter>
						<Button
							colorScheme="blue"
							variant="ghost"
							mr={3}
							onClick={onCloseAdvanced}
						>
							Close
						</Button>
					</ModalFooter>
				</ModalContent>
			</Modal>
		</>
	);
}
Example #23
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>
    </>
  );
}
Example #24
Source File: offline-data-card.tsx    From portfolio with MIT License 4 votes vote down vote up
RepositoryCard = (props: RepositoryCardProps) => {
  const {
    key,
    title,
    description,
    cover,
    blurHash,
    technologies,
    url,
    live,
    stars,
    fork,
  } = props;
  const { isOpen, onOpen, onClose } = useDisclosure();

  const handleClick = () => {
    onOpen();
    // window.open(link);
    // if (type == "link" || type == "article") {
    //   window.open(link);
    // } else {
    //   onOpen();
    // }
  };

  const handleLinkClick = (
    e: React.MouseEvent<HTMLParagraphElement, MouseEvent>,
    link: string
  ) => {
    window.open(link);
    e.stopPropagation();
  };

  const transition = { duration: 0.5, ease: [0.43, 0.13, 0.23, 0.96] };

  const thumbnailVariants = {
    initial: { scale: 0.9, opacity: 0 },
    enter: { scale: 1, opacity: 1, transition },
    exit: {
      scale: 0.5,
      opacity: 0,
      transition: { duration: 1.5, ...transition }
    }
  };

  const imageVariants = {
    hover: { scale: 1.1 }
  };

  return (
    <CardTransition>
      <Box onClick={handleClick} cursor="pointer" size="xl">
        <VStack
          //   w="100%"
          rounded="xl"
          borderWidth="1px"
          bg={useColorModeValue("white", "gray.800")}
          borderColor={useColorModeValue("gray.100", "gray.700")}
          _hover={{
            shadow: "lg",
            textDecoration: "none"
          }}
          overflow="hidden"
          align="start"
          spacing={0}
        >
          <Box position="relative" w="100%">
            <MotionBox variants={thumbnailVariants}>
              <MotionBox
                whileHover="hover"
                variants={imageVariants}
                transition={transition}
              >
                <AspectRatio
                  ratio={1.85 / 1}
                  maxW="400px"
                  w="100%"
                  borderBottomWidth="1px"
                  borderColor={useColorModeValue("gray.100", "gray.700")}
                >
                  {/* <Image
                    src={cover}
                    fallback={<Skeleton />}
                    objectFit="cover"
                  /> */}
                  <LazyImage
                    src={cover}
                    blurHash={blurHash}
                  />
                </AspectRatio>
              </MotionBox>
            </MotionBox>
          </Box>

          <VStack py={2} px={[2, 4]} spacing={1} align="start" w="100%">
            <Flex justifyContent={"space-between"} width="100%">
              <Tooltip hasArrow label="Github link" placement="top">
                <HStack>
                  <Icon as={FiGithub} boxSize="0.9em" mt={"1px"} />
                  {/* <Link href={url} isExternal> */}
                  <Text
                    fontSize="sm"
                    noOfLines={1}
                    fontWeight="600"
                    align="left"
                    onClick={e => handleLinkClick(e, url)}
                  >
                    {title}
                  </Text>
                </HStack>
              </Tooltip>
              {/* </Link> */}
              <Flex>
                <Icon as={AiOutlineStar} boxSize="0.9em" mt={"1px"} />
                <Box as="span" ml="1" fontSize="sm">
                  {stars}
                </Box>
              </Flex>
            </Flex>
            <Flex justifyContent={"space-between"} width="100%">
              <Box>
                <HStack spacing="1">
                  {technologies.map(tech => (
                    <Tag size="sm" colorScheme={getTagColor(tech)}>
                      <Text fontSize={["0.55rem", "inherit", "inherit"]}>
                        {tech}
                      </Text>
                    </Tag>
                  ))}
                </HStack>
              </Box>
            </Flex>
            {/* <Flex justifyContent={"space-between"} width="100%">
              <Flex>
                <AiOutlineStar color="teal.300" />
                <Box as="span" ml="1" fontSize="sm">
                  {stars}
                </Box>
              </Flex>
              <Box >
              <Text
                fontSize="xs"
                fontWeight="400"
                color={useColorModeValue("gray.400", "gray.500")}
              >
                {created}
              </Text>
            </Box>
            </Flex> */}
          </VStack>
        </VStack>
        <Modal isOpen={isOpen} onClose={onClose} isCentered allowPinchZoom>
          <ModalOverlay />
          <ModalContent bg="none" maxW={"28rem"} w="auto">
            <ModalBody p={0} rounded="lg" overflow="hidden" bg="none">
              <Center>
                <Image src={cover} rounded="lg" />
                {/* {type == "image" ? (
                <Image src={cover} rounded="lg" />
              ) : (
                <ReactPlayer url={link} controls playing />
              )} */}
              </Center>
            </ModalBody>
          </ModalContent>
        </Modal>
      </Box>
    </CardTransition>
  );
}
Example #25
Source File: live-data-card.tsx    From portfolio with MIT License 4 votes vote down vote up
RepositoryCard = (props: RepositoryCardProps) => {
  const {
    title,
    description,
    language,
    url,
    stargazers_count,
    forks_count,
  } = props;

  const handleLinkClick = (
    e: React.MouseEvent<HTMLParagraphElement, MouseEvent>,
    link: string
  ) => {
    window.open(link);
    e.stopPropagation();
  };

  return (
    <MotionBox whileHover={{ y: -5 }}>
      <Box
        size="xl"
        py={2}
        px={[2, 4]}
        mt={2}
        rounded="xl"
        borderWidth="1px"
        bg={useColorModeValue("white", "gray.800")}
        borderColor={useColorModeValue("gray.100", "gray.700")}
        _hover={{
          shadow: "lg",
          textDecoration: "none"
        }}
      >
        <VStack overflow="hidden" align="start" spacing={1}>
          <VStack spacing={1} align="start" w="100%">
            <Flex
              justifyContent={"space-between"}
              width="100%"
              onClick={e => handleLinkClick(e, url)}
            >
              <Tooltip hasArrow label="Github link" placement="top">
                <HStack cursor={"pointer"}>
                  <Icon as={FiGithub} boxSize="0.9em" mt={"1px"} />
                  <Text
                    fontSize="sm"
                    noOfLines={1}
                    fontWeight="600"
                    align="left"
                    color={"blue.500"}
                  >
                    {title}
                  </Text>
                </HStack>
              </Tooltip>
              <HStack cursor={"pointer"} onClick={e => handleLinkClick(e, url)}>
                {forks_count && (
                  <Box _hover={{ color: "blue.500" }}>
                    <Icon as={BiGitRepoForked} boxSize="0.9em" mt={"1px"} />
                    <Box as="span" ml="1" fontSize="sm">
                      {forks_count}
                    </Box>
                  </Box>
                )}
                <Box _hover={{ color: "blue.500" }}>
                  <Icon as={BiStar} boxSize="0.9em" mt={"1px"} />
                  <Box as="span" ml="1" fontSize="sm">
                    {stargazers_count}
                  </Box>
                </Box>
              </HStack>
            </Flex>
            {language && (
              <Flex justifyContent={"space-between"} width="100%">
                <Box>
                  <HStack spacing="1">
                    <Tag size="sm" colorScheme={getTagColor(language)}>
                      <Text fontSize={["0.55rem", "inherit", "inherit"]}>
                        {language}
                      </Text>
                    </Tag>
                  </HStack>
                </Box>
              </Flex>
            )}
          </VStack>
          <Box>
            <Text color="gray.500" fontSize="sm" noOfLines={2} textAlign="left">
              {description}
            </Text>
          </Box>{" "}
        </VStack>
      </Box>
    </MotionBox>
  );
}