Skip to content

Commit 0de2a03

Browse files
authored
Merge pull request #304 from kpfromer/refactor/svg-wave-github-projects
refactor: svg wave - GitHub projects
2 parents ad52c88 + 224976e commit 0de2a03

File tree

30 files changed

+770
-356
lines changed

30 files changed

+770
-356
lines changed

.github/renovate.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": ["config:base", "schedule:nonOfficeHours"]
3+
}

.github/workflows/test.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,3 @@ jobs:
4141
run: |
4242
pnpm lint
4343
pnpx prettier --check .
44-
45-
- name: build
46-
run: pnpm build

components/Blog/Preview/index.tsx

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { BlogPostFrontmatter } from '@lib/blog';
2+
import Card from '@components/Card';
23
import { DateTime } from 'luxon';
3-
import { HTMLProps } from 'react';
44
import Img from 'next/image';
55
import { ImgPlaceholder } from '@lib/placeholder';
6-
import classnames from 'clsx';
76

8-
export type PreviewProps = HTMLProps<HTMLDivElement> &
7+
export type PreviewProps = React.ComponentProps<typeof Card> &
98
BlogPostFrontmatter & {
109
coverImagePlaceholder: ImgPlaceholder;
1110
};
@@ -19,13 +18,7 @@ const Preview: React.FC<PreviewProps> = ({
1918
...props
2019
}) => {
2120
return (
22-
<div
23-
{...props}
24-
className={classnames(
25-
'flex flex-col bg-white dark:bg-gray-700 rounded-md p-4 h-full border border-gray-300',
26-
props.className,
27-
)}
28-
>
21+
<Card {...props}>
2922
<div className="overflow-hidden rounded-lg">
3023
<Img
3124
className="bg-white"
@@ -42,7 +35,7 @@ const Preview: React.FC<PreviewProps> = ({
4235
<h2 className="text-xl md:text-2xl font-bold">{title}</h2>
4336
<p className="text-md mt-2">{DateTime.fromISO(created).toFormat('DDD')}</p>
4437
</div>
45-
</div>
38+
</Card>
4639
);
4740
};
4841

components/Button.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import tw from 'tailwind-styled-components';
2+
3+
export interface ButtonProps {
4+
$disabled?: boolean;
5+
}
6+
7+
// @ts-ignore
8+
const Button = tw.button<ButtonProps>`
9+
${(p) => (p.$disabled ? 'btn-disabled cursor-default' : 'btn-primary')}
10+
transition-colors
11+
flex-grow
12+
md:flex-grow-0
13+
ml-0
14+
md:ml-auto
15+
`;
16+
17+
export default Button;

components/Card.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import tw from 'tailwind-styled-components';
2+
3+
const Card = tw.div`
4+
flex
5+
flex-col
6+
7+
border-gray-300
8+
dark:border-gray-700
9+
10+
text-gray-800
11+
dark:text-gray-200
12+
13+
rounded-md
14+
p-4
15+
h-full
16+
border
17+
`;
18+
19+
export default Card;

components/Code/Block/index.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import Highlight, { defaultProps, Language } from 'prism-react-renderer';
1+
import Highlight, { Language, defaultProps } from 'prism-react-renderer';
22
import React, { HTMLAttributes } from 'react';
3+
34
import classnames from 'clsx';
45

56
export interface CodeBlockProps {
@@ -40,7 +41,7 @@ const CodeBlock: React.FC<CodeBlockProps> = ({
4041
return (
4142
<div {...rest} className={classnames('transition-colors duration-500', showTopbar && 'my-3')}>
4243
{showTopbar && (
43-
<div className="text-gray-800 dark:text-gray-200 py-2 px-5 border-t border-l border-r border-gray-100 dark:border-gray-700 rounded-t bg-gray-200 dark:bg-gray-800 font-bold">
44+
<div className="text-gray-800 dark:text-gray-200 py-2 px-5 border-t border-l border-r border-gray-100 dark:border-gray-700 rounded-t bg-gray-200 dark:bg-naturalGray-400 font-bold">
4445
{filename}
4546
</div>
4647
)}
@@ -56,7 +57,7 @@ const CodeBlock: React.FC<CodeBlockProps> = ({
5657
<pre
5758
style={style}
5859
className={classnames(
59-
'text-gray-200 overflow-x-auto text-sm leading-relaxed py-3 px-5 border bg-gray-50 border-gray-200 dark:border-gray-700 dark:bg-gray-900',
60+
'text-gray-200 overflow-x-auto text-sm leading-relaxed py-3 px-5 border bg-gray-50 border-gray-200 dark:border-gray-700 dark:bg-naturalGray-600',
6061
showTopbar ? 'mt-0 rounded-b' : 'my-3 rounded',
6162
)}
6263
>

components/ContactForm/index.tsx

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,43 @@
1-
import Icon from '@components/Icon';
1+
import Button from '@components/Button';
22
import { FiMail } from 'react-icons/fi';
3-
import { useState } from 'react';
4-
import classnames from 'clsx';
3+
import Icon from '@components/Icon';
4+
import tw from 'tailwind-styled-components';
55
import { useForm } from 'react-hook-form';
6+
import { useState } from 'react';
7+
8+
const Input = tw.input`
9+
p-2
10+
border
11+
dark:bg-naturalGray-400
12+
border-gray-500
13+
border-opacity-20
14+
rounded-md
15+
focus:outline-none
16+
focus:ring-2
17+
focus:ring-primary-500
18+
focus:border-transparent
19+
shadow
20+
`;
21+
22+
const TextArea = tw.textarea`
23+
p-2
24+
border
25+
dark:bg-naturalGray-400
26+
border-gray-500
27+
border-opacity-20
28+
rounded-md
29+
focus:outline-none
30+
focus:ring-2
31+
focus:ring-primary-500
32+
focus:border-transparent
33+
shadow
34+
`;
35+
36+
const InputContainer = tw.div`
37+
flex
38+
flex-col
39+
space-y-3
40+
`;
641

742
type FormData = {
843
email: string;
@@ -37,47 +72,40 @@ const ContactForm: React.FC<ContactFormProps> = () => {
3772
</div>
3873
)}
3974

40-
<div className="flex flex-col space-y-3">
75+
<InputContainer>
4176
<label htmlFor="email" className="font-bold">
4277
Email address*
4378
</label>
44-
<input
79+
<Input
4580
id="email"
4681
type="email"
4782
name="email"
48-
className="p-2 border dark:bg-gray-800 border-gray-500 border-opacity-20 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent shadow"
4983
disabled={status === 'good'}
5084
required
5185
ref={register}
5286
/>
5387
<span className="block text-gray-600 dark:text-gray-200">
5488
I will never share your email. It's just used for me to reply.
5589
</span>
56-
</div>
90+
</InputContainer>
5791

58-
<div className="flex flex-col space-y-3">
92+
<InputContainer>
5993
<label htmlFor="message" className="font-bold">
6094
Message*
6195
</label>
62-
<textarea
96+
<TextArea
6397
id="message"
6498
name="message"
65-
className="p-2 border dark:bg-gray-800 border-gray-500 border-opacity-20 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent shadow"
6699
disabled={status === 'good'}
67100
required
68101
ref={register}
69102
/>
70-
</div>
103+
</InputContainer>
71104

72105
<input type="text" name="_gotcha" style={{ display: 'none' }} />
73106

74-
<button
75-
className={classnames(
76-
status === 'pending' || status === 'error'
77-
? 'btn-primary'
78-
: 'btn-disabled cursor-default',
79-
'transition-colors flex-grow md:flex-grow-0 ml-0 md:ml-auto',
80-
)}
107+
<Button
108+
$disabled={!(status === 'pending' || status === 'error')}
81109
disabled={status === 'good'}
82110
type="submit"
83111
>
@@ -88,7 +116,7 @@ const ContactForm: React.FC<ContactFormProps> = () => {
88116
) : (
89117
'Sent!'
90118
)}
91-
</button>
119+
</Button>
92120
</form>
93121
);
94122
};

components/Container/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const Container: React.FC<ContainerProps> = ({ children, ...props }) => {
99
<div
1010
{...props}
1111
style={{ ...props.style, maxWidth: 900 }}
12-
className={classnames('px-2 lg:px-0 mx-auto', props.className)}
12+
className={classnames('lg:px-0 mx-auto px-3 sm:px-4 md:px-0', props.className)}
1313
>
1414
{children}
1515
</div>

components/Github/Project.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import Card from '@components/Card';
12
import { DateTime } from 'luxon';
23

34
export interface ProjectProps {
5+
// TODO: typing
46
project: any;
57
}
68

@@ -27,10 +29,7 @@ const GithubFork = () => (
2729
const Project: React.FC<ProjectProps> = ({ project }) => {
2830
const updatedAt = DateTime.fromISO(project.updatedAt);
2931
return (
30-
<div
31-
className="rounded-md border border-gray-300 dark:border-gray-700 p-3 text-gray-600 dark:text-gray-100 dark:bg-gray-900 flex flex-col transition-colors"
32-
style={{ fontSize: '.8em' }}
33-
>
32+
<Card>
3433
<a
3534
href={project.url}
3635
target="_blank"
@@ -65,7 +64,7 @@ const Project: React.FC<ProjectProps> = ({ project }) => {
6564

6665
<div>Updated {updatedAt.toRelative()}</div>
6766
</div>
68-
</div>
67+
</Card>
6968
);
7069
};
7170

components/Header/index.tsx

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
import IconButton from '@components/IconButton';
1+
import { FiMenu, FiMoon, FiSun } from 'react-icons/fi';
2+
import { HTMLAttributes, useState } from 'react';
3+
24
import Container from '@components/Container';
3-
import { FiSun, FiMoon, FiMenu } from 'react-icons/fi';
5+
import IconButton from '@components/IconButton';
46
import NextLink from 'next/link';
5-
import { HTMLAttributes, useState } from 'react';
6-
import { useDarkMode } from '@utils/dark-mode-provider';
77
import classnames from 'clsx';
8+
import tw from 'tailwind-styled-components';
9+
import { useDarkMode } from '@utils/dark-mode-provider';
810

911
const NavLink: React.FC<
1012
Omit<HTMLAttributes<HTMLAnchorElement>, 'href'> & { href: string; mobile?: boolean }
@@ -16,14 +18,53 @@ const NavLink: React.FC<
1618
</NextLink>
1719
);
1820

19-
export interface HeaderProps {}
21+
const HeaderContainer = tw.div`
22+
py-4
23+
sticky
24+
top-0
25+
left-0
26+
right-0
27+
z-10
28+
bg-gray-50
29+
dark:bg-naturalGray-400
30+
transition-colors
31+
duration-500
32+
`;
2033

21-
const Header: React.FC<HeaderProps> = () => {
34+
export interface HeaderProps {
35+
bottomNav?: boolean;
36+
}
37+
38+
const Header: React.FC<HeaderProps> = ({ bottomNav = false }) => {
2239
const { mode, toggleMode } = useDarkMode();
2340
const [visible, setVisible] = useState(false);
2441

42+
const mobileNav = (
43+
<Container className={visible ? 'visible' : 'hidden'}>
44+
<div className={classnames('py-2 flex flex-col space-y-2', visible ? 'visible' : 'hidden')}>
45+
<NavLink href="/" mobile onClick={() => setVisible(false)}>
46+
Home
47+
</NavLink>
48+
<NavLink href="/blog" mobile onClick={() => setVisible(false)}>
49+
Blog
50+
</NavLink>
51+
<NavLink href="/resume" mobile onClick={() => setVisible(false)}>
52+
Experience
53+
</NavLink>
54+
<NavLink href="/projects" mobile onClick={() => setVisible(false)}>
55+
Projects
56+
</NavLink>
57+
<NavLink href="/contact" mobile onClick={() => setVisible(false)}>
58+
Contact
59+
</NavLink>
60+
</div>
61+
</Container>
62+
);
63+
2564
return (
26-
<div className="py-4 sticky top-0 left-0 right-0 z-10 bg-gray-50 dark:bg-gray-800 transition-colors duration-500">
65+
<HeaderContainer>
66+
{bottomNav && mobileNav}
67+
2768
<Container className="flex justify-center items-center">
2869
<IconButton
2970
className="sm:hidden"
@@ -33,11 +74,11 @@ const Header: React.FC<HeaderProps> = () => {
3374
/>
3475

3576
<div className="hidden sm:flex sm:flex-row sm:space-x-3">
36-
<NavLink href="/#top">Home</NavLink>
37-
<NavLink href="/#blog">Blog</NavLink>
38-
<NavLink href="/#experience">Experience</NavLink>
39-
<NavLink href="/#projects">Projects</NavLink>
40-
<NavLink href="/#contact">Contact</NavLink>
77+
<NavLink href="/">Home</NavLink>
78+
<NavLink href="/blog">Blog</NavLink>
79+
<NavLink href="/resume">Resume</NavLink>
80+
<NavLink href="/projects">Projects</NavLink>
81+
<NavLink href="/contact">Contact</NavLink>
4182
</div>
4283

4384
<div className="flex-grow" />
@@ -48,26 +89,9 @@ const Header: React.FC<HeaderProps> = () => {
4889
onClick={toggleMode}
4990
/>
5091
</Container>
51-
<Container className={visible ? 'visible' : 'hidden'}>
52-
<div className={classnames('py-2 flex flex-col space-y-2', visible ? 'visible' : 'hidden')}>
53-
<NavLink href="/" mobile onClick={() => setVisible(false)}>
54-
Home
55-
</NavLink>
56-
<NavLink href="/#blog" mobile onClick={() => setVisible(false)}>
57-
Blog
58-
</NavLink>
59-
<NavLink href="/#experience" mobile onClick={() => setVisible(false)}>
60-
Experience
61-
</NavLink>
62-
<NavLink href="/#projects" mobile onClick={() => setVisible(false)}>
63-
Projects
64-
</NavLink>
65-
<NavLink href="/#contact" mobile onClick={() => setVisible(false)}>
66-
Contact
67-
</NavLink>
68-
</div>
69-
</Container>
70-
</div>
92+
93+
{!bottomNav && mobileNav}
94+
</HeaderContainer>
7195
);
7296
};
7397

0 commit comments

Comments
 (0)