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