@chakra-ui/react#useColorMode JavaScript Examples

The following examples show how to use @chakra-ui/react#useColorMode. 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: ColorModeSwitcher.jsx    From realtime-chat-supabase-react with Apache License 2.0 6 votes vote down vote up
ColorModeSwitcher = (props) => {
  const { toggleColorMode } = useColorMode();
  const text = useColorModeValue("dark", "light");
  const SwitchIcon = useColorModeValue(FaMoon, FaSun);

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

  return (
    <IconButton
      size="md"
      fontSize="lg"
      aria-label={`Switch to ${text} mode`}
      variant="ghost"
      color="current"
      marginLeft="2"
      onClick={toggleColorMode}
      icon={<SwitchIcon />}
      {...props}
    />
  );
}
Example #3
Source File: ThemeSwitch.js    From blobs.app with MIT License 6 votes vote down vote up
export default function ThemeSwitch() {
  const { toggleColorMode: toggleMode } = useColorMode();
  const ToggleIcon = useColorModeValue(SunIcon, MoonIcon);
  return (
    <Button
      leftIcon={<ToggleIcon fontSize="18px" />}
      variant="silent"
      aria-label="Toggle Theme"
      onClick={toggleMode}
    >
      Switch theme
    </Button>
  );
}
Example #4
Source File: _app.js    From benjamincarlson.io with MIT License 6 votes vote down vote up
GlobalStyle = ({ children }) => {
  const { colorMode } = useColorMode()

  return (
    <>
      <Global
        styles={css`
          ${colorMode === 'light' ? prismLightTheme : prismDarkTheme};
          html {
            min-width: 356px;
            scroll-behavior: smooth;
          }
          #__next {
            display: flex;
            flex-direction: column;
            min-height: 100vh;
            background: ${colorMode === 'light' ? 'white' : '#15161a'};
          }
        `}
      />
      {children}
    </>
  )
}
Example #5
Source File: ColorModeSwitcher.jsx    From scaffold-directory with MIT License 6 votes vote down vote up
ColorModeSwitcher = () => {
  const { toggleColorMode } = useColorMode();
  const Icon = useColorModeValue(<SunIcon color="gray.400" h={4} w={4} />, <MoonIcon h={4} w={4} />);

  return (
    <Flex pos="fixed" bottom={0} right={0} p={6}>
      <Switch onChange={toggleColorMode} mr={4} align="center" />
      {Icon}
    </Flex>
  );
}
Example #6
Source File: StatBox.js    From benjamincarlson.io with MIT License 6 votes vote down vote up
export default function StatBox({ title, desc, url }) {
    const { colorMode } = useColorMode()
    const borderColor = {
        light: '#CBD5E0',
        dark: '#4A5568',
    }
    const [opacity, setOpacity] = useState(0)
    
    return (
        <Link
            href={url}
            isExternal
            _hover={{
                textDecoration: 'none'
            }}
            onMouseOver={() => setOpacity(1)}
            onMouseLeave={() => setOpacity(0)}
        >
            <Box p={2} pb={[2, 1, 1]}>
                <StatGroup border={`1px solid ${borderColor[colorMode]}`} borderRadius={5} p={2} w="100%">
                    <Stat>
                        <Flex
                            align="center"
                            justifyContent="space-between"
                        >
                            <StatLabel>{desc}</StatLabel>
                            <ExternalLinkIcon opacity={opacity} />
                        </Flex>
                        <StatNumber>{title}</StatNumber>
                    </Stat>
                </StatGroup>
            </Box>
        </Link>
    )
}
Example #7
Source File: MDXComponents.js    From benjamincarlson.io with MIT License 6 votes vote down vote up
Hr = () => {
    const { colorMode } = useColorMode()
    const borderColor = {
        light: 'gray.200',
        dark: 'gray.600'
    }

    return <Divider borderColor={borderColor[colorMode]} my={4} w="100%" />
}
Example #8
Source File: MDXComponents.js    From benjamincarlson.io with MIT License 6 votes vote down vote up
Quote = (props) => {
    const { colorMode } = useColorMode()
    const bgColor = {
        light: 'blue.50',
        dark: 'blue.900'
    }

    return (
        <Alert
            mt={4}
            w="98%"
            bg={bgColor[colorMode]}
            variant="left-accent"
            status="info"
            css={{
                '> *:first-of-type': {
                    marginTop: 0,
                    marginLeft: 8
                }
            }}
            {...props}
        />
    )
}
Example #9
Source File: MDXComponents.js    From benjamincarlson.io with MIT License 6 votes vote down vote up
CustomLink = (props) => {
    const { colorMode } = useColorMode()
    const color = {
        light: 'hsl(208, 99%, 44%)',
        dark: 'hsl(208, 95%, 68%)'
    }

    const href = props.href
    const isInternalLink = href && (href.startsWith('/') || href.startsWith('#'))

    if (isInternalLink) {
        return (
            <NextLink href={href} passHref>
                <Link color={color[colorMode]} {...props} />
            </NextLink>
        )
    }

    return <Link color={color[colorMode]} isExternal {...props} />
}
Example #10
Source File: GearList.js    From benjamincarlson.io with MIT License 6 votes vote down vote up
Gear = ({ gear }) => {
    const { colorMode } = useColorMode()

    const color = {
        light: 'black',
        dark: 'white'
    }

    const colorSecondary = {
        light: 'gray.600',
        dark: 'gray.400'
    }
    return (
        <div>
            <Text mb={1}><b>{gear.item}:</b> <Link color={colorSecondary[colorMode]} href={gear.url} isExternal>{gear.title}</Link></Text>
        </div>
    )
}
Example #11
Source File: DarkModeSwitch.js    From benjamincarlson.io with MIT License 6 votes vote down vote up
DarkModeSwitch = () => {
  const { colorMode, toggleColorMode } = useColorMode()
  const iconColor = {
    light: 'black',
    dark: 'white'
  }
  return (
    <IconButton
      variant="ghost"
      aria-label="Toggle dark mode"
      icon={colorMode === 'dark' ? <SunIcon /> : <MoonIcon />}
      onClick={toggleColorMode}
      color={iconColor[colorMode]}
    />
  )
}
Example #12
Source File: GitHubSponsorCard.js    From benjamincarlson.io with MIT License 5 votes vote down vote up
GitHubSponsorCard = () => {
    const { colorMode } = useColorMode()

    const colorSecondary = {
        light: 'gray.600',
        dark: 'gray.400'
    }
    return (
        <Box
            w="100%"
            p={5}
            my={4}
            border='1px solid'
            borderColor="lightgray"
            borderRadius={5}
            h="100%"
        >
            <Flex>
                <Image w="75px" h="75px" borderRadius={5} src="/images/portrait.jpeg"></Image>
                <Flex flexDirection={['column', 'row']}>
                    <Flex
                        width="100%"
                        align="flex-start"
                        justifyContent="space-between"
                        flexDirection="column"
                        mx={2}
                    >
                        <Heading as="h3" size="md">
                            Sponsor Benjamin Carlson on GitHub Sponsors
                        </Heading>
                        <Text color={colorSecondary[colorMode]}>
                            Hi ? I'm Benjamin Carlson, a senior college student studying computer science. I post weekly tutorial videos on my YouTube channel and build cool open source projects!
                        </Text>
                    </Flex>
                    <Flex mt={[2, 0, 0]}>
                        <iframe src="https://github.com/sponsors/bjcarlson42/button" title="Sponsor bjcarlson42" height="35" width="116" style={{ border: '0' }}></iframe>
                    </Flex>
                </Flex>
            </Flex>
        </Box>
    )
}
Example #13
Source File: GearList.js    From benjamincarlson.io with MIT License 5 votes vote down vote up
GearList = () => {
    const { data, error } = useSWR('/api/gear', fetcher)
    const { colorMode } = useColorMode()

    const color = {
        light: 'black',
        dark: 'white'
    }

    if (error) return <div>Error loading gear!</div>
    if (!data) return <CircularProgress isIndeterminate color={color[colorMode]}></CircularProgress>

    var software = data.filter(function (g) {
        return g.software == 1
    })

    var hardware = data.filter(function (g) {
        return g.software == 0
    })

    var cameraGear = data.filter(function (g) {
        return g.software == 2
    })

    return (
        <>
            <Heading letterSpacing="tight" mb={2} mt={2} as="h2" size="xl">
                Hardware
            </Heading>
            {hardware.map((g, i) => (
                <Gear key={i} gear={g} />
            ))}
            <Heading letterSpacing="tight" mb={2} mt={4} as="h2" size="xl">
                Software
            </Heading>
            {software.map((g, i) => (
                <Gear key={i} gear={g} />
            ))}
            <Heading letterSpacing="tight" mb={2} mt={4} as="h2" size="xl">
                Camera Gear
            </Heading>
            {cameraGear.map((g, i) => (
                <Gear key={i} gear={g} />
            ))}
        </>
    )
}
Example #14
Source File: ProjectCard.js    From benjamincarlson.io with MIT License 5 votes vote down vote up
export default function ProjectCard({ title, description, repoHref, demoHref, languageColor, language, youtubeId, starCount, stargazersUrl, homepage }) {
    const [opacity, setOpacity] = useState(0)
    const [lineColor, setLineColor] = useState("blue.500")
    const { colorMode } = useColorMode()

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

    const boxShadowColor = {
        light: '0px 8px 26px rgba(0, 0, 0, 0.2)',
        dark: '0px 8px 26px rgba(0, 0, 0, 0.7)'
    }
    return (
        <Flex
            flexDir="column"
            _hover={{ transform: 'scale(1.05)', border: `2px solid ${languageColor}` }}
            transition="transform .5s ease-in-out, border .5s ease-in-out"
            boxShadow={boxShadowColor[colorMode]}
            borderRadius={5}
            border="2px solid transparent"
            onMouseOver={() => { setOpacity(1), setLineColor(languageColor) }}
            onMouseLeave={() => { setOpacity(0), setLineColor("blue.500") }}
        >
            <Flex p={[5, 15, 25]} flexDir="column" justify="space-between" h="100%">
                <Box>
                    <Heading as="h3" size="lg" fontWeight="semibold" mb={2}>{title}</Heading>
                    <Box h={1} w="35%" bgColor={lineColor} transition="background-color .5s ease-in-out" mb={4} />
                    <Text color={colorSecondary[colorMode]}>{description}</Text>
                </Box>
                <Flex justify="space-between" mt={2}>
                    <Flex align="center">

                        {stargazersUrl && (
                            <Link href={stargazersUrl.replace("api.", "").replace("repos/", "")} _hover={{ textDecor: 'none' }} isExternal>
                                <Flex opacity={opacity} transition="opacity .5s ease-in-out">
                                    <Button colorScheme="yellow" leftIcon={<AiOutlineStar />} variant="ghost">{starCount}</Button>
                                </Flex>
                            </Link>
                        )}

                        {homepage && (
                            <Link href={homepage} isExternal>
                                <IconButton icon={homepage.includes("youtu.be") ? <YoutubeIcon /> : <ExternalLinkIcon />} variant="ghost" opacity={opacity} transition="opacity .5s ease-in-out" />
                            </Link>
                        )}

                        {repoHref && (
                            <Link href={repoHref} isExternal>
                                <IconButton icon={<GitHubIcon />} variant="ghost" opacity={opacity} transition="opacity .5s ease-in-out" />
                            </Link>
                        )}
                        {demoHref && (
                            <Link href={demoHref} isExternal>
                                <IconButton icon={<ExternalLinkIcon />} variant="ghost" opacity={opacity} transition="opacity .5s ease-in-out" />
                            </Link>
                        )}
                        {youtubeId && (
                            <Link href={youtubeId} isExternal>
                                <IconButton icon={<YoutubeIcon />} variant="ghost" opacity={opacity} transition="opacity .5s ease-in-out" />
                            </Link>
                        )}
                    </Flex>
                    <Flex align="center">
                        <Box w={3} h={3} mr={1} borderRadius="50%" bgColor={languageColor} />
                        <Text fontSize="sm" color={colorSecondary[colorMode]}>{language}</Text>
                    </Flex>
                </Flex>
            </Flex>
        </Flex>
    )
}
Example #15
Source File: TechStack.js    From benjamincarlson.io with MIT License 5 votes vote down vote up
TechStack = () => {
    const { colorMode } = useColorMode()

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

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

    return (
        <Box as="section" w="100%" mt={10} mb={20}>
            <Heading letterSpacing="tight" size="lg" fontWeight={700} as="h2" mb={4}>
                Tech Stack ⚙️
            </Heading>
            <Text color={colorSecondary[colorMode]} mb={4}>Each piece of technology used in this website is carefully thought out. I believe this is one of the best stacks there is to build websites of any size and domain.</Text>
            <Box flexDir="column" overflowX="auto">
                <Table variant="simple">
                    <Thead>
                        <Tr>
                            <Th>Type</Th>
                            <Th>Name</Th>
                            <Th>Route</Th>
                            <Th>Description</Th>
                        </Tr>
                    </Thead>
                    <Tbody>
                        <Tr>
                            <Td>JS Framework</Td>
                            <Td><Link href="https://nextjs.org" color={linkColor[colorMode]} isExternal>Next JS</Link></Td>
                            <Td>n/a</Td>
                            <Td>Next.js was an easy choice given its large community and ability for rapid development.</Td>
                        </Tr>
                        <Tr>
                            <Td>CSS Framework</Td>
                            <Td><Link href="https://chakra-ui.com" color={linkColor[colorMode]} isExternal>Chakra UI</Link></Td>
                            <Td>n/a</Td>
                            <Td>I use Chakra UI because its components make a beautiful UI out of the box and are highly customizable.</Td>
                        </Tr>
                        <Tr>
                            <Td>Blog</Td>
                            <Td><Code>next-mdx-remote</Code></Td>
                            <Td>/blog/[slug].js</Td>
                            <Td>I use <Link href="https://github.com/hashicorp/next-mdx-remote" color={linkColor[colorMode]} isExternal>next-mdx-remote</Link> for my blog. Posts are stored in <Code>mdx</Code> files and pre-rendered.</Td>
                        </Tr>
                        <Tr>
                            <Td>Real-Time Statistics</Td>
                            <Td>Next.js api routes</Td>
                            <Td>/api/[].js</Td>
                            <Td>Multiple api routes that interact with the GitHub, YouTube, and Strava api to fetch my real-time social media data using Next.JS <Link href="https://nextjs.org/docs/api-routes/introduction" color={linkColor[colorMode]} isExternal>serverless functions</Link>.</Td>
                        </Tr>
                        <Tr>
                            <Td>Realtime Blog Post View/Like Count</Td>
                            <Td>Firebase Realtime Db</Td>
                            <Td>/api</Td>
                            <Td>I use <Link href="https://firebase.google.com" color={linkColor[colorMode]} isExternal>Google's Firebase</Link> to store view and like counts for my blog posts.</Td>
                        </Tr>
                        <Tr>
                            <Td>Deployment</Td>
                            <Td>Vercel</Td>
                            <Td>n/a</Td>
                            <Td>I use <Link href="https://vercel.com" color={linkColor[colorMode]} isExternal>Vercel</Link> to deploy my app. It's free, fast, integrates with GitHub, and overall a great experience.</Td>
                        </Tr>
                        <Tr>
                            <Td>Domain</Td>
                            <Td>Namecheap</Td>
                            <Td>n/a</Td>
                            <Td>My domain name is bought and stored through <Link color="blue.500" href="https://www.namecheap.com/" isExternal>Namecheap</Link>.</Td>
                        </Tr>
                    </Tbody>
                </Table>
            </Box>
        </Box>
    )
}
Example #16
Source File: BlogPost.js    From benjamincarlson.io with MIT License 5 votes vote down vote up
BlogPost = ({ title, summary, href }) => {
    const { colorMode } = useColorMode()
    const secondaryTextColor = {
        light: 'gray.600',
        dark: 'gray.400'
    }

    const { data } = useSWR(`/api/page-views?id=${href}`, fetcher)
    const views = data?.total

    return (
        <NextLink href={`blog/${href}`} passHref>
            <Link w="100%" _hover={{ textDecoration: 'none' }}>
                <Box mb={10} display="block" width="100%">
                    <Flex
                        width="100%"
                        align="flex-start"
                        justifyContent="space-between"
                        flexDirection={['column', 'row']}
                    >
                        <Flex flexDirection="column" align="flex-start" justifyContent="start" width="100%">
                            <Heading size="md" as="h3" mb={1} fontWeight="medium">
                                {title}
                            </Heading>
                        </Flex>

                        <Text
                            color="gray.500"
                            minWidth="105px"
                            textAlign={['left', 'right']}
                            mb={[4, 0]}
                        >
                            {`${views ? formatNum(views) : '–––'} views`}
                        </Text>

                    </Flex>
                    <Text color={secondaryTextColor[colorMode]}>{summary}</Text>
                </Box>
            </Link>
        </NextLink>
    )
}
Example #17
Source File: Preferences.js    From web-client with Apache License 2.0 5 votes vote down vote up
UserPreferences = () => {

    const user = Auth.getLoggedInUser();
    user.preferences = initialiseUserPreferences(user);

    const timezones = CountriesTimezones.getAllTimezones();
    const timezoneKeys = Object.keys(timezones).sort();

    const { setTheme } = useContext(ThemeContext);

    const { setColorMode } = useColorMode();

    const [formValues, setFormValues] = useState({
        timezone: user.timezone,
        theme: user.preferences["web-client.theme"]
    });

    const updateFormValues = ev => {
        setFormValues({ ...formValues, [ev.target.name]: ev.target.value });
    }

    const onFormSubmit = ev => {
        ev.preventDefault();

        user.timezone = formValues.timezone;
        user.preferences = { ...initialiseUserPreferences(user), "web-client.theme": formValues.theme };

        secureApiFetch(`/users/${user.id}`, {
            method: 'PATCH',
            body: JSON.stringify({ timezone: formValues.timezone, preferences: user.preferences })
        })
            .then(() => {
                setTheme(theme => {
                    setThemeColors(formValues.theme);
                    setColorMode(formValues.theme);
                    return formValues.theme;
                });

                localStorage.setItem('user', JSON.stringify(user));

                actionCompletedToast("Your preferences have been saved.");
            })
            .catch(err => console.error(err));
    }

    return <>
        <PageTitle value="Preferences" />
        <div className='heading'>
            <Breadcrumb />
        </div>
        <Title type='User' title='Preferences' icon={<IconPreferences />} />
        <form onSubmit={onFormSubmit}>
            <FormControl>
                <FormLabel>Theme</FormLabel>
                <Select name="theme" onChange={updateFormValues} defaultValue={formValues.theme || "dark"}>
                    <option value="dark">Dark</option>
                    <option value="light">Light</option>
                </Select>
            </FormControl>
            <FormControl>
                <FormLabel>Timezone</FormLabel>
                <Select name="timezone" onChange={updateFormValues} defaultValue={user.timezone}>
                    {timezoneKeys.map((key, index) =>
                        <option key={index} value={timezones[key].name}>{timezones[key].name}</option>
                    )}
                </Select>
            </FormControl>

            <Primary type="submit">Save</Primary>
        </form>
    </>
}
Example #18
Source File: gear.js    From benjamincarlson.io with MIT License 5 votes vote down vote up
Gear = () => {
    const { colorMode } = useColorMode()

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

    return (
        <>
            <NextSeo
                title={title}
                description={description}
                canonical={url}
                openGraph={{
                    url,
                    title,
                    description
                }}
            />
            <Container>
                <Flex
                    flexDirection="column"
                    maxWidth="1000px"
                    alignSelf={[null, "center"]}
                >
                    <motion.div
                        initial={{ y: -20, opacity: 0 }}
                        animate={{ y: 0, opacity: 1 }}
                        transition={{ duration: .7, delay: .4 }}
                    >
                        <Heading letterSpacing="tight" my={4} as="h1" size="2xl">
                            Gear
                        </Heading>
                        <Text color={colorSecondary[colorMode]} mb={2}>
                            Productivity is directly associated with selecting the right software and hardware. Here is a list of all the gear I use on a day to day basis.
                            If you purchase any items through the links below I may earn a small commission.
                        </Text>
                        <GearList />
                    </motion.div>
                </Flex>
            </Container>
        </>
    )
}
Example #19
Source File: AuthContext.js    From web-client with Apache License 2.0 5 votes vote down vote up
function useAuth() {
    const { setColorMode } = useColorMode();

    const [isAuth, setIsAuth] = useState(KeyCloakService.IsAuthenticated);
    const [user, setUser] = useState(Auth.getLoggedInUser());

    const login = useCallback(() => {
        return secureApiFetch(`/users/login`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
        })
            .then(resp => resp.json())
            .then(data => {
                data.preferences = initialiseUserPreferences(data);

                localStorage.setItem('isAuth', true);
                localStorage.setItem('user', JSON.stringify(data));

                setUser(Auth.getLoggedInUser())
                //                setUser(data);

                setThemeColors(data.preferences['web-client.theme']);
                setColorMode(data.preferences['web-client.theme']);

                setIsAuth(KeyCloakService.GetInstance().authenticated)
            })
            .catch(err => {
                throw err;
            });
    }, [setColorMode])

    const logout = () => {
        setIsAuth(false);

        secureApiFetch(`/users/logout`, {
            method: 'POST',
        })
            .finally(() => {
                Auth.removeSession();
                setThemeColors('dark');
                setColorMode('dark');

                KeyCloakService.Logout();
            });
    }

    useEffect(() => {
        login();
    }, [login])

    return { user, isAuth, login, logout };
}
Example #20
Source File: projects.js    From benjamincarlson.io with MIT License 5 votes vote down vote up
Projects = () => {
    const { colorMode } = useColorMode()

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

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

    return (
        <>
            <NextSeo
                title={title}
                description={description}
                canonical={url}
                openGraph={{
                    url,
                    title,
                    description
                }}
            />
            <Container>
                <Flex
                    flexDirection="column"
                    maxWidth="1000px"
                    alignSelf={[null, "center"]}
                >
                    <motion.div
                        initial={{ y: -20, opacity: 0 }}
                        animate={{ y: 0, opacity: 1 }}
                        transition={{ duration: .7, delay: .4 }}
                    >
                        <Heading letterSpacing="tight" my={4} as="h1" size="2xl">
                            Projects
                        </Heading>
                        <Text color={colorSecondary[colorMode]}>Between school, work, youtube, and individual curiosity, I have worked on many projects over the years. If you enjoy or use any of these projects, please consider <Link href="https://github.com/sponsors/bjcarlson42" isExternal color="blue.500">sponsoring me</Link> on GitHub!
                        </Text>
                        <GitHubSponsorCard />
                        <ProjectListFull />
                    </motion.div>
                </Flex>
            </Container>
        </>
    )
}
Example #21
Source File: statistics.js    From benjamincarlson.io with MIT License 5 votes vote down vote up
Statistics = () => {
    const { colorMode } = useColorMode()

    const colorSecondary = {
        light: 'gray.600',
        dark: 'gray.400'
    }
    return (
        <>
            <NextSeo
                title={title}
                description={description}
                canonical={url}
                openGraph={{
                    url,
                    title,
                    description
                }}
            />
            <Container>
                <Flex
                    flexDirection="column"
                    maxWidth="1000px"
                    alignSelf={[null, "center"]}
                >
                    <motion.div
                        initial={{ y: -20, opacity: 0 }}
                        animate={{ y: 0, opacity: 1 }}
                        transition={{ duration: .7, delay: .4 }}
                    >
                        <Heading letterSpacing="tight" my={4} as="h1" size="2xl">
                            Statistics
                        </Heading>
                        <Text color={colorSecondary[colorMode]} mb={6}>A simple dashboard containing various statistics. The data is fetched in realtime via Next.js api routes from various api's. Build your own by following along with this video.</Text>
                        <SimpleGrid minChildWidth="300px" spacing="20px">
                            <YouTubeData />
                            <GitHubData />
                            <StravaData />
                        </SimpleGrid>
                    </motion.div>
                </Flex>
            </Container>
        </>
    )
}
Example #22
Source File: Details.js    From web-client with Apache License 2.0 4 votes vote down vote up
ProjectDetails = () => {
    const navigate = useNavigate();
    const { projectId } = useParams();
    const { colorMode } = useColorMode()

    const [project, updateProject] = useFetch(`/projects/${projectId}`)
    const [users] = useFetch(`/projects/${projectId}/users`)
    const destroy = useDelete(`/projects/`, updateProject);

    const handleGenerateReport = () => {
        navigate(`/projects/${project.id}/report`)
    }

    const handleManageTeam = () => {
        navigate(`/projects/${project.id}/membership`)
    }

    const onArchiveButtonClick = (project) => {
        secureApiFetch(`/projects/${project.id}`, {
            method: 'PATCH',
            body: JSON.stringify({ archived: !project.archived })
        })
            .then(() => {
                updateProject();
                actionCompletedToast('The project has been updated.');
            })
            .catch(err => console.error(err))
    }

    if (project && project.is_template) {
        return <Navigate to={`/projects/templates/${project.id}`} />
    }

    return <>
        <div className='heading'>
            <Breadcrumb>
                <Link to="/projects">Projects</Link>
            </Breadcrumb>
            {project && <>
                <PageTitle value={`${project.name} project`} />
                <ProjectTeam project={project} users={users} />

                <ButtonGroup isAttached>
                    <RestrictedComponent roles={['administrator', 'superuser', 'user']}>
                        {!project.archived && <>
                            <LinkButton href={`/projects/${project.id}/edit`}>Edit</LinkButton>
                            <SecondaryButton onClick={handleGenerateReport} leftIcon={<IconClipboardCheck />}>Report</SecondaryButton>
                            <SecondaryButton onClick={handleManageTeam} leftIcon={<IconUserGroup />}>Membership</SecondaryButton>
                        </>}

                        <Menu>
                            <MenuButton as={IconButton} aria-label='Options' icon={<FontAwesomeIcon icon={faEllipsis} />} variant='outline' />
                            <MenuList>
                                <MenuItem onClick={() => onArchiveButtonClick(project)}>{project.archived ? 'Unarchive' : 'Archive'}</MenuItem>
                                <MenuItem icon={<FontAwesomeIcon icon={faTrash} />} color={colorMode === "light" ? "red.500" : "red.400"} onClick={() => destroy(project.id)}>Delete</MenuItem>
                            </MenuList>
                        </Menu>
                    </RestrictedComponent>
                </ButtonGroup>
            </>}
        </div>
        {!project ? <Loading /> :
            <>
                <Title title={project.name} type="Project" icon={<IconFolder />} />

                <Tabs>
                    <TabList>
                        <Tab>Details</Tab>
                        <Tab>Targets</Tab>
                        <Tab>Tasks</Tab>
                        <Tab>Vulnerabilities</Tab>
                        <Tab>Notes</Tab>
                        <Tab>Attachments</Tab>
                        <Tab>Vault</Tab>
                    </TabList>
                    <TabPanels>
                        <TabPanel><ProjectDetailsTab project={project} /></TabPanel>
                        <TabPanel><ProjectTargets project={project} /></TabPanel>
                        <TabPanel><ProjectTasks project={project} /></TabPanel>
                        <TabPanel><ProjectVulnerabilities project={project} /></TabPanel>
                        <TabPanel><ProjectNotesTab project={project} /></TabPanel>
                        <TabPanel><ProjectAttachmentsTab project={project} /></TabPanel>
                        <TabPanel><ProjectVaultTab project={project} /></TabPanel>
                    </TabPanels>
                </Tabs>
            </>
        }
    </>
}
Example #23
Source File: Todo.js    From benjamincarlson.io with MIT License 4 votes vote down vote up
Todo = () => {
    const toast = useToast()
    const { colorMode } = useColorMode()
    const { isOpen, onOpen, onClose } = useDisclosure()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            <Todo />
            <TechStack />

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

        </Flex>
      </Container>
    </>
  )
}
Example #25
Source File: blog.js    From benjamincarlson.io with MIT License 4 votes vote down vote up
export default function BlogLayout({ children, frontMatter }) {
    const { colorMode } = useColorMode()
    const textColor = {
        light: 'gray.700',
        dark: 'gray.400'
    }
    const iconColor = {
        light: 'gray.600',
        dark: 'gray.300'
    }
    const router = useRouter()
    const slug = router.asPath.replace('/blog', '')


    const [width, setWidth] = useState(1)
    const handleScroll = () => {
        let scrollTop = window.scrollY;
        let docHeight = document.body.offsetHeight;
        let winHeight = window.innerHeight;
        let scrollPercent = scrollTop / (docHeight - winHeight);
        let scrollPercentRounded = Math.round(scrollPercent * 100);
        setWidth(scrollPercentRounded)
    }

    useEffect(() => {
        window.addEventListener('scroll', handleScroll);
        return () => {
            window.removeEventListener('scroll', handleScroll)
        }
    })

    return (
        <>
            <Box h={1} as="div" bgGradient="linear(to-r, blue.200, gray.500)" position="sticky" top={0} zIndex={100} w={`${width}%`} transition="width .5s ease-in-out"></Box>
            <Container>
                <BlogSeo url={`https://benjamincarlson.io/blog${slug}`} {...frontMatter} />
                <Stack
                    as="article"
                    spacing={8}
                    justifyContent="center"
                    alignItems="flex-start"
                    m="0 auto 4rem auto"
                    maxWidth="700px"
                    w="100%"
                    px={2}
                >
                    <Flex
                        flexDirection="column"
                        justifyContent="flex-start"
                        alignItems="flex-start"
                        maxWidth="700px"
                        w="100%"
                    >
                        <Heading letterSpacing="tight" mb={2} mt={4} as="h1" size="2xl">
                            {frontMatter.title}
                        </Heading>
                        <Flex
                            justify="space-between"
                            align={['initial', 'center']}
                            direction={['column', 'row']}
                            mt={2}
                            w="100%"
                            mb={4}
                        >
                            <Flex align="center">
                                <Avatar
                                    size="sm"
                                    name="Benjamin Carlson"
                                    src="../images/portrait.jpeg"
                                    mr={2}
                                />
                                <Text fontSize="sm" color={textColor[colorMode]}>
                                    {frontMatter.by}
                                    {'Benjamin Carlson / '}
                                    {format(parseISO(frontMatter.publishedAt), 'MMMM dd, yyyy')}
                                </Text>
                            </Flex>
                            <Text fontSize="sm" color="gray.500" minWidth="100px" mt={[2, 0]}>
                            {frontMatter.readingTime.text}
                            {` • `}
                            <ViewCounter id={slug} />
                            {` • `}
                            <LikeCounter id={slug} />
                        </Text>
                        </Flex>
                        {frontMatter.Image != '' ? <Image src={frontMatter.image} alt={frontMatter.alt} borderRadius={3} /> : null}
                    </Flex>
                    {/* <BlogAd /> */}
                    {children}
                    <Box>
                        <Link href={tweetUrl(slug)} isExternal>
                            <Icon as={TwitterIcon} size="18px" mr={2} />
                            {'Share on Twitter'}
                        </Link>
                        {` • `}
                        <Link href={editUrl(slug)} isExternal>
                            <Icon as={GitHubIcon} size="18px" mr={2} />
                            {'Edit on GitHub'}
                        </Link>
                    </Box>
                    <GitHubSponsorCard />
                    <Comments />
                </Stack>
            </Container>
        </>
    )
}
Example #26
Source File: Container.jsx    From bottle-radio with MIT License 4 votes vote down vote up
Container = () => {
  const { colorMode, toggleColorMode } = useColorMode();
  const color = { light: "black", dark: "white" };
  const [logoSpinning, setLogoSpinning] = useState(false);
  const [modal, setModal] = useState();
  const [showVisualiser, setShowVisualiser] = useState(false);
  const [player, setPlayer] = useState();

  const EmbedCode = () => {
    const [show, setShow] = React.useState(false);
    const handleToggle = () => setShow(!show);

    return (
      <Box mt="auto" pt={2} mb={3} mx={2}>
        <Collapse in={show}>
          <Code my={2} p={2} overflow="auto">
            {`<iframe src = '${window.location.protocol}//${window.location.host}/embed' frameborder = '0' allowtransparency = 'true' style = 'width: 100%; min-height: 150px; border: 0;'></iframe>`}
          </Code>
        </Collapse>
        <Button colorScheme="blue" variant="link" onClick={handleToggle}>
          Embed player
        </Button>
      </Box>
    );
  };

  return (
    <Fragment>
      <VisualiserProvider value={{ player, setPlayer }}>
        <Box
          width="100%"
          minHeight="100vh"
          bg={colorMode === "light" ? "#99c0ff" : "#1a202c"}
          color={colorMode === "light" ? "black" : "white"}
        >
          {player && (
            <Box pos="absolute" bottom={0} left={0} pointerEvents="none">
              <Collapse in={showVisualiser}>
                <Visualisation audio={player.current} />
              </Collapse>
            </Box>
          )}
          <Flex
            direction="column"
            justify="flex-start"
            align="center"
            width="100%"
            maxWidth="960px"
            minHeight="100vh"
            mx="auto"
            pt={5}
            pos="relative"
            zindex={1}
          >
            <Box
              as={colorMode === "light" ? FaMoon : FaSun}
              w="30px"
              h="30px"
              onClick={toggleColorMode}
              color={color[colorMode]}
            />
            <Box px={5}>
              <Image
                src="/logo512.png"
                maxWidth="230px"
                mx="auto"
                mt={3}
                className={logoSpinning ? "icon-spin" : ""}
                onClick={() =>
                  logoSpinning ? setLogoSpinning(false) : setLogoSpinning(true)
                }
              />
              <ModalProvider value={{ modal, setModal }}>
                <Player />
              </ModalProvider>
              <Links />
              <Button
                mt={2}
                variant="link"
                onClick={() => setShowVisualiser(!showVisualiser)}
              >
                Visualiser
              </Button>
            </Box>
            <EmbedCode />
            <Text mb={3}>
              Powered by{" "}
              <Link
                href="https://github.com/MrLemur/bottle-radio"
                color="teal.500"
                isExternal
              >
                Bottle Radio
              </Link>
            </Text>
          </Flex>
        </Box>
      </VisualiserProvider>
    </Fragment>
  );
}
Example #27
Source File: Footer.js    From benjamincarlson.io with MIT License 4 votes vote down vote up
Footer = () => {

    const { colorMode } = useColorMode()
    const borderIcon = {
        light: 'gray.400',
        dark: 'gray.500'
    }
    const footerHoverBg = {
        light: 'gray.100',
        dark: 'gray.700',
    }
    return (
        <Box bgColor={useColorModeValue("rgb(248, 250, 252)", "gray.900")} mt={4}>
            <Flex
                align="center"
                my={4}
                direction="column"
            >
                <div>
                    <Link href="https://twitter.com/bjmncrlsn" title="Twitter" isExternal>
                        <IconButton
                            aria-label="Twitter"
                            icon={<FiTwitter />}
                            size="lg"
                            color={borderIcon[colorMode]}
                            variant="ghost"
                            _hover={{ backgroundColor: footerHoverBg[colorMode] }}
                        />
                    </Link>
                    <Link href="https://github.com/bjcarlson42" title="GitHub" isExternal>
                        <IconButton
                            aria-label="GitHub"
                            icon={<FiGithub />}
                            size="lg"
                            color={borderIcon[colorMode]}
                            variant="ghost"
                            _hover={{ backgroundColor: footerHoverBg[colorMode] }}
                        />
                    </Link>
                    <Link
                        href="https://www.linkedin.com/in/bjcarlson42"
                        title="LinkedIn"
                        isExternal
                    >
                        <IconButton
                            aria-label="LinkedIn"
                            icon={<FiLinkedin />}
                            size="lg"
                            color={borderIcon[colorMode]}
                            variant="ghost"
                            _hover={{ backgroundColor: footerHoverBg[colorMode] }}
                        />
                    </Link>
                    <Link
                        href="https://www.youtube.com/benjamincarlson"
                        title="YouTube"
                        isExternal
                    >
                        <IconButton
                            aria-label="YouTube"
                            icon={<FiYoutube />}
                            size="lg"
                            color={borderIcon[colorMode]}
                            variant="ghost"
                            _hover={{ backgroundColor: footerHoverBg[colorMode] }}
                        />
                    </Link>
                    <Link href="mailto:[email protected]" title="Email" isExternal>
                        <IconButton
                            aria-label="Email"
                            icon={<FiMail />}
                            size="lg"
                            color={borderIcon[colorMode]}
                            variant="ghost"
                            _hover={{ backgroundColor: footerHoverBg[colorMode] }}
                        />
                    </Link>
                </div>
            </Flex>
        </Box>
    )
}
Example #28
Source File: PlayerEmbed.jsx    From bottle-radio with MIT License 4 votes vote down vote up
PlayerEmbed = () => {
  const variables = window._env_ ? window._env_ : { REACT_ICECAST_URL: "" };
  const [playing, setPlaying] = useState(false);
  const [loading, setLoading] = useState(false);
  const [muted, setMuted] = useState(false);
  const [nowPlaying, setNowPlaying] = useState(["No data", "No data"]);
  const { colorMode } = useColorMode();
  const colorHover = { light: "white", dark: "black" };

  useEffect(() => {
    const updateStats = async () => {
      let url = variables.REACT_ICECAST_URL + "status-json.xsl";
      let response = await fetch(url);
      let json = await response.json();
      let track = json.icestats.source.title;
      if (track && track !== "") {
        let artist = track.split(" - ")[0];
        track = track.split(" - ").slice(1).join(" - ");
        setNowPlaying([track, artist]);
      }
    };
    updateStats();
    setInterval(() => {
      updateStats();
    }, 10000);
  }, [variables.REACT_ICECAST_URL]);

  const togglePlay = () => {
    let player = document.getElementById("player");
    if (player.paused) {
      setPlaying(true);
      player.load();
      player.play();
    } else {
      setPlaying(false);
      player.pause();
    }
  };

  const changeVolume = (value) => {
    let player = document.getElementById("player");
    value <= 0 ? setMuted(true) : setMuted(false);
    player.volume = value / 100;
  };

  return (
    <div>
      <Flex
        direction="column"
        justify="center"
        align="center"
        width="100%"
        height="100%"
        bg="transparent"
      >
        <Box>
          <Grid
            m={2}
            p={2}
            templateColumns="auto 1fr"
            alignItems="center"
            gap={1}
          >
            <Box
              gridRow="1/4"
              size="80px"
              aria-label="Play toggle"
              as={loading ? FaSpinner : playing ? FaPauseCircle : FaPlayCircle}
              onClick={togglePlay}
              _hover={{ color: colorHover[colorMode] }}
              mr={1}
              className={loading ? "icon-spin" : ""}
            />
            <Text m={0} align="right">
              <strong>{nowPlaying[0]}</strong>
            </Text>
            <Text m={0} align="right">
              {nowPlaying[1]}
            </Text>

            <Flex direction="row" justify="center" maxWidth={400} p={2}>
              <Slider
                defaultValue={100}
                min={0}
                max={100}
                step={10}
                onChange={changeVolume}
                width={80}
              >
                <SliderTrack style={{ height: "5px" }}>
                  <SliderFilledTrack bg="tomato" />
                </SliderTrack>
                <SliderThumb size={2} />
              </Slider>
              <Box
                w="20px"
                h="20px"
                as={muted ? FaVolumeMute : FaVolumeUp}
                ml={3}
              />
              <audio
                id="player"
                autoPlay
                onPlay={() => setPlaying(true)}
                onPause={() => setPlaying(false)}
                onLoadStart={() => setLoading(true)}
                onLoadedData={() => setLoading(false)}
              >
                <source
                  src={variables.REACT_ICECAST_URL + "radio.mp3"}
                  type="audio/mp3"
                />
                Your browser does not support the audio element.
              </audio>
            </Flex>
          </Grid>
        </Box>
      </Flex>
    </div>
  );
}
Example #29
Source File: Player.jsx    From bottle-radio with MIT License 4 votes vote down vote up
Player = () => {
  const variables = window._env_ ? window._env_ : { REACT_ICECAST_URL: "" };
  const [playing, setPlaying] = useState(false);
  const [loading, setLoading] = useState(false);
  const [muted, setMuted] = useState(false);
  const [firstLoad, setFirstLoad] = useState(true);
  const [nowPlaying, setNowPlaying] = useState(["No data", "No data"]);
  const [listeners, setListeners] = useState([0, 0]);
  const { colorMode } = useColorMode();
  const colorHover = { light: "white", dark: "black" };
  const { isOpen, onOpen, onClose } = useDisclosure();
  const trackLinks = useSaveTrack(
    nowPlaying[0],
    nowPlaying[1]
  );
  const audioRef = useRef(null);
  const { setPlayer } = useContext(VisualiserContext);

  useEffect(() => {
    const audio = document.getElementById("player");
    if (audio) {
      setPlayer(audioRef);
    }
  }, [setPlayer]);

  useEffect(() => {
    const updateStats = async () => {
      let url = variables.REACT_ICECAST_URL + "status-json.xsl";
      let response = await fetch(url);
      let json = await response.json();
      let track = json.icestats.source.title;
      if (track && track !== "") {
        let artist = track.split(" - ")[0];
        track = track.split(" - ").slice(1).join(" - ");
        setNowPlaying([track, artist]);
      }
      let listeners = json.icestats.source.listeners;
      let peakListeners = json.icestats.source.listener_peak;

      if (listeners && listeners) {
        setListeners([listeners, peakListeners]);
      }
    };
    updateStats();
    setInterval(() => {
      updateStats();
    }, 10000);
  }, [variables.REACT_ICECAST_URL]);

  const togglePlay = () => {
    let player = document.getElementById("player");
    if (firstLoad) {
      setFirstLoad(false);
    }
    if (player.paused) {
      setPlaying(true);
      player.load();
      player.play();
    } else {
      setPlaying(false);
      player.pause();
    }
  };

  const changeVolume = (value) => {
    let player = document.getElementById("player");
    value <= 0 ? setMuted(true) : setMuted(false);
    player.volume = value / 100;
  };

  const TrackModal = (props) => {
    const { modal, setModal } = useContext(ModalContext);

    useEffect(() => {
      if (!modal) {
        setModal(trackLinks);
      }
    }, [modal, setModal]);

    return (
      <div>
        <Modal
          isOpen={isOpen}
          onClose={() => {
            onClose();
            setModal();
          }}
          size="sm"
          isCentered
        >
          <ModalOverlay>
            <ModalContent>
              <ModalCloseButton />
              <ModalBody>
                <Grid templateColumns="1fr 1fr" justifyItems="center" gap={0}>
                  {modal && modal.length > 0 ? (
                    modal.map((link) => (
                      <Link key={link.url} href={link.url} isExternal>
                        <Button variant="ghost">{link.displayName}</Button>
                      </Link>
                    ))
                  ) : (
                    <div>
                      <Spinner size="sm" /> Loading...
                    </div>
                  )}
                </Grid>
              </ModalBody>
            </ModalContent>
          </ModalOverlay>
        </Modal>
      </div>
    );
  };

  return (
    <div>
      <Flex
        direction="column"
        justify="center"
        align="center"
        width="100%"
        height="100%"
      >
        <Box>
          <Grid
            m={2}
            p={2}
            templateColumns="auto 1fr auto"
            alignItems="center"
            gap={1}
          >
            <Box
              gridRow="1/4"
              w="80px"
              h="80px"
              aria-label="Play toggle"
              as={loading ? FaSpinner : playing ? FaPauseCircle : FaPlayCircle}
              onClick={togglePlay}
              _hover={{ color: colorHover[colorMode] }}
              mr={1}
              className={loading ? "icon-spin" : ""}
            />
            <Text m={0} align="center">
              <strong>{nowPlaying[0]}</strong>
            </Text>
            <Text m={0} align="center">
              {nowPlaying[1]}
            </Text>

            <Flex direction="row" justify="center" maxWidth={400} p={2}>
              <Slider
                defaultValue={100}
                min={0}
                max={100}
                step={10}
                onChange={changeVolume}
                width="80px"
              >
                <SliderTrack>
                  <SliderFilledTrack bg="tomato" />
                </SliderTrack>
                <SliderThumb size={2} />
              </Slider>
              <Box
                w="20px"
                h="20px"
                as={muted ? FaVolumeMute : FaVolumeUp}
                ml={3}
              />
              <audio
                id="player"
                crossOrigin="anonymous"
                autoPlay
                preload="none"
                ref={audioRef}
                onPlay={() => setPlaying(true)}
                onPause={() => setPlaying(false)}
                onLoadStart={() => {
                  if (!firstLoad) {
                    setLoading(true);
                  }
                }}
                onCanPlay={() => setLoading(false)}
              >
                <source
                  src={variables.REACT_ICECAST_URL + "radio.mp3"}
                  type="audio/mp3"
                />
                Your browser does not support the audio element.
              </audio>
            </Flex>
            <Text gridColumn="1/4">
              <strong>Listeners: </strong>
              {listeners[0]} <strong>Peak: </strong>
              {listeners[1]}
            </Text>
            <Box gridColumn="3" gridRow="1/4" alignItems="center">
              <Box
                w="25px"
                h="25px"
                as={FaHeart}
                mx={1}
                onClick={onOpen}
                _hover={{ color: "tomato" }}
              />
              {isOpen ? <TrackModal /> : null}
            </Box>
          </Grid>
        </Box>
      </Flex>
    </div>
  );
}