Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions components/LanguageSwitch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Link from 'next/link'
import { useRouter } from 'next/router'

export default function LocaleSwitcher() {
const router = useRouter()
const { locales, locale: activeLocale } = router
const otherLocales = locales.filter((locale) => locale !== activeLocale)

return (
<div>
{/* <p>Locale switcher:</p> */}
<ul>
{otherLocales.map((locale) => {
const { pathname, query, asPath } = router
return (
<li key={locale}>
<Link href={{ pathname, query }} as={asPath} locale={locale}>
<a>
<span className={`flag-icon flag-icon-${locale}`}></span>
</a>
</Link>
</li>
)
})}
</ul>
</div>
)
}
1 change: 0 additions & 1 deletion components/MDXComponents.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/** @jsx jsx */
import {
Box,
Alert,
Expand Down
54 changes: 44 additions & 10 deletions components/Navigation.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import React from 'react'
import {
useColorMode,
Button,
Flex,
Box
} from '@chakra-ui/react'
import styled from '@emotion/styled'
import NextLink from 'next/link'
import { useRouter } from 'next/router'

import DarkModeSwitch from '../components/DarkModeSwitch'
import useTranslation from 'next-translate/useTranslation'

const StickyNav = styled(Flex)`
position: sticky;
z-index: 10;
top: 0;
backdrop-filter: saturate(180%) blur(20px);
transition: height .5s, line-height .5s;
`

const Navigation = () => {
const { colorMode } = useColorMode()
const { t } = useTranslation()
const router = useRouter()
const { locale, locales, defaultLocale } = router

const changeLanguage = (e) => {
const locale = e.target.value
router.push(router.asPath, router.asPath, { locale })
}

const bgColor = {
light: '#fff',
Expand All @@ -23,8 +41,10 @@ const Navigation = () => {
dark: 'gray.700',
}



return (
<Flex
<StickyNav
flexDirection="row"
justifyContent="space-between"
alignItems="center"
Expand All @@ -39,11 +59,20 @@ const Navigation = () => {
mb={[null, 0, 8]}
mx="auto"
display={['none', 'flex', 'flex']}
pos="sticky"
zIndex={10}
top={0}
>
<DarkModeSwitch />
<select
onChange={changeLanguage}
defaultValue={locale}
style={{ textAlignLast: 'center' }}
className="text-gray-900 dark:text-gray-100 text-shadow-sm text-sm bg-transparent tracking-wide"
>
{locales.map((e) => (
<option value={e} key={e}>
{e}
</option>
))}
</select>
<Box>
<NextLink href="/statistics" passHref>
<Button
Expand All @@ -54,7 +83,7 @@ const Navigation = () => {
backgroundColor={router.pathname === '/statistics' ? navHoverBg[colorMode] : null}
aria-label="Statistics"
>
Statistics
{t('common:statistics')}
</Button>
</NextLink>
<NextLink href="/blog" passHref>
Expand All @@ -65,7 +94,7 @@ const Navigation = () => {
_hover={{ backgroundColor: navHoverBg[colorMode] }} backgroundColor={router.pathname.includes('/blog') ? navHoverBg[colorMode] : null}
aria-label="Blog"
>
Blog
{t('common:blog')}
</Button>
</NextLink>
<NextLink href="/projects" passHref>
Expand All @@ -76,7 +105,7 @@ const Navigation = () => {
_hover={{ backgroundColor: navHoverBg[colorMode] }} backgroundColor={router.pathname === '/projects' ? navHoverBg[colorMode] : null}
aria-label="Projects"
>
Projects
{t('common:projects')}
</Button>
</NextLink>
<NextLink href="/gear" passHref>
Expand All @@ -86,7 +115,7 @@ const Navigation = () => {
p={[1, 2, 4]} _hover={{ backgroundColor: navHoverBg[colorMode] }} backgroundColor={router.pathname === '/gear' ? navHoverBg[colorMode] : null}
aria-label="Gear"
>
Gear
{t('common:gear')}
</Button>
</NextLink>
<NextLink href="/" passHref>
Expand All @@ -97,11 +126,16 @@ const Navigation = () => {
_hover={{ backgroundColor: navHoverBg[colorMode] }} backgroundColor={router.pathname === '/' ? navHoverBg[colorMode] : null}
aria-label="Home"
>
Home
{t('common:home')}
</Button>
</NextLink>
{/* <NextLink href="https://tutorials.benjamincarlson.io" passHref>
<Button as="a" variant="ghost" p={[1, 2, 4]} _hover={{ backgroundColor: navHoverBg[colorMode] }} target="_blank">
Tutorials
</Button>
</NextLink> */}
</Box>
</Flex >
</StickyNav >
)
}

Expand Down
87 changes: 42 additions & 45 deletions components/TechStack.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import {
Td,
Tbody,
Link,
useColorMode,
Flex
useColorMode
} from '@chakra-ui/react'

const TechStack = () => {
Expand All @@ -32,49 +31,47 @@ const TechStack = () => {
Tech Stack
</Heading>
<Text color={colorSecondary[colorMode]} mb={4}>This websites tech stack.</Text>
<Flex overflowX="auto" maxW={[320, '100%', '100%']}>
<Table variant="simple">
<Thead>
<Tr>
<Th>Name</Th>
<Th>Route</Th>
<Th>Description</Th>
</Tr>
</Thead>
<Tbody>
<Tr>
<Td><Link href="https://nextjs.org" color={linkColor[colorMode]} isExternal>Next JS</Link></Td>
<Td>n/a</Td>
<Td>My JS framework for this website.</Td>
</Tr>
<Tr>
<Td><Link href="https://chakra-ui.com" color={linkColor[colorMode]} isExternal>Chakra UI</Link></Td>
<Td>n/a</Td>
<Td>My CSS framework for this website.</Td>
</Tr>
<Tr>
<Td>Blog</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> pages for my blog posts.</Td>
</Tr>
<Tr>
<Td>Real-Time Statistics</Td>
<Td>/api/[].js</Td>
<Td>Multiple api routes that 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>/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>Vercel</Td>
<Td>n/a</Td>
<Td>I use <Link href="https://vercel.com" color={linkColor[colorMode]} isExternal>Vercel</Link> to deploy my app.</Td>
</Tr>
</Tbody>
</Table>
</Flex>
<Table variant="simple">
<Thead>
<Tr>
<Th>Name</Th>
<Th>Route</Th>
<Th>Description</Th>
</Tr>
</Thead>
<Tbody>
<Tr>
<Td><Link href="https://nextjs.org" color={linkColor[colorMode]} isExternal>Next JS</Link></Td>
<Td>n/a</Td>
<Td>My JS framework for this website.</Td>
</Tr>
<Tr>
<Td><Link href="https://chakra-ui.com" color={linkColor[colorMode]} isExternal>Chakra UI</Link></Td>
<Td>n/a</Td>
<Td>My CSS framework for this website.</Td>
</Tr>
<Tr>
<Td>Blog</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> pages for my blog posts.</Td>
</Tr>
<Tr>
<Td>Real-Time Statistics</Td>
<Td>/api/[].js</Td>
<Td>Multiple api routes that 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>/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>Vercel</Td>
<Td>n/a</Td>
<Td>I use <Link href="https://vercel.com" color={linkColor[colorMode]} isExternal>Vercel</Link> to deploy my app.</Td>
</Tr>
</Tbody>
</Table>
</>
)
}
Expand Down
51 changes: 51 additions & 0 deletions data/blog/using-react-useeffect.fr.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
title: 'UseEffect In Next.JS - React Hooks'
publishedAt: '2021-03-14'
summary: "Learn what useEffect is learn how to use useEffect in Next.JS."
---

## Introduction

React hooks allow you to perform side effects in function components. In this post, we will take a look at ```useEffect``` and give examples
of how to use in in [next.js](https://nextjs.org/).

## Using useEffect In Next.JS

Let's take a look at an example. We will use ```useEffect``` to add an event listener
to handle when a user scrolls. We will then log to the console the scrollY value. This is how this website dynamically adds
the css to the nav bar on scroll!

First, we will import ```useEffect``` from react.

```javascript
import React, { useState, useEffect } from 'react'
```

Next, call the method:

```javascript
useEffect(() => {

})
```

We can add anything we want in here. Let's add our event listeners:

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

Finally, create the handle scroll method and log the scrollY value to the console:

```javascript
const handleScroll = () => {
console.log(scrollY)
}
```

And that's it! Check out my [YouTube channel](https://youtube.com/benjamincarlson) for more coding tutorials!
7 changes: 7 additions & 0 deletions i18n.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"locales": ["en", "fr"],
"defaultLocale": "en",
"pages": {
"*": ["common"]
}
}
32 changes: 32 additions & 0 deletions lib/remark-code-title.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { visit } from 'unist-util-visit'

export default function remarkCodeTitles() {
return (tree) =>
visit(tree, 'code', (node, index) => {
const nodeLang = node.lang || ''
let language = ''
let title = ''

if (nodeLang.includes(':')) {
language = nodeLang.slice(0, nodeLang.search(':'))
title = nodeLang.slice(nodeLang.search(':') + 1, nodeLang.length)
}

if (!title) {
return
}

const className = 'remark-code-title'

const titleNode = {
type: 'mdxJsxFlowElement',
name: 'div',
attributes: [{ type: 'mdxJsxAttribute', name: 'className', value: className }],
children: [{ type: 'text', value: title }],
data: { _xdmExplicitJsx: true },
}

tree.children.splice(index, 0, titleNode)
node.lang = language
})
}
35 changes: 35 additions & 0 deletions lib/remark-img-to-jsx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { visit } from 'unist-util-visit'
import sizeOf from 'image-size'
import fs from 'fs'

export default function remarkImgToJsx() {
return (tree) => {
visit(
tree,
// only visit p tags that contain an img element
(node) => node.type === 'paragraph' && node.children.some((n) => n.type === 'image'),
(node) => {
const imageNode = node.children.find((n) => n.type === 'image')

// only local files
if (fs.existsSync(`${process.cwd()}/public${imageNode.url}`)) {
const dimensions = sizeOf(`${process.cwd()}/public${imageNode.url}`)

// Convert original node to next/image
;(imageNode.type = 'mdxJsxFlowElement'),
(imageNode.name = 'Image'),
(imageNode.attributes = [
{ type: 'mdxJsxAttribute', name: 'alt', value: imageNode.alt },
{ type: 'mdxJsxAttribute', name: 'src', value: imageNode.url },
{ type: 'mdxJsxAttribute', name: 'width', value: dimensions.width },
{ type: 'mdxJsxAttribute', name: 'height', value: dimensions.height },
])

// Change node type from p to div to avoid nesting error
node.type = 'div'
node.children = [imageNode]
}
}
)
}
}
Loading