├── .gitignore ├── LICENSE ├── README.md ├── gatsby-browser.js ├── gatsby-config.js ├── gatsby-node.js ├── gatsby-ssr.js ├── package.json ├── src ├── components │ ├── common │ │ ├── ProgressBar.tsx │ │ └── index.tsx │ ├── layout.css │ ├── layout.tsx │ ├── sections │ │ ├── about.tsx │ │ ├── action.tsx │ │ ├── careers.tsx │ │ ├── index.tsx │ │ ├── profile.tsx │ │ └── skills.tsx │ └── seo.tsx ├── images │ └── gatsby-icon.png ├── models │ └── index.ts └── pages │ ├── 404.tsx │ └── index.tsx ├── static ├── profile-yaml.png ├── resumes │ ├── chick.png │ └── john-doe.yaml └── simple-resume.png ├── tsconfig.json ├── tslint.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 gatsbyjs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

🐤️ Simple-resume

6 |

7 | 8 | Simple-resume is released under the MIT license. 9 | 10 | 11 | 12 | 13 | 14 |

15 | 16 | ## Overview 17 | Simple-resume은 React+Gatsby와 yaml을 통해 편리하고 빠르게 이력서를 작성 할 수 있습니다. 18 |
19 | 20 |
21 | 22 | ## Installation 23 | 24 | ```shell 25 | $ git clone https://github.com/suites/simple-resume.git 26 | $ cd simple-resume 27 | $ yarn install 28 | ``` 29 | 30 | 1. 프로젝트를 clone합니다. 31 | ```shell 32 | $ git clone https://github.com/suites/simple-resume.git 33 | ``` 34 | 2. simple-resume 폴더로 이동합니다. `cd simple-resume` 35 | 3. yarn을 통해 package를 설치합니다. `yarn install` 36 | 37 | ## How to use 38 | ```shell 39 | $ npm run start 40 | ``` 41 | - run your program, go to http://localhost:8000 42 | 43 | 1. static/resumes/john-doe.yaml 파일을 복사하여 새로운 profile.yaml을 작성합니다. 44 | 45 | 2. gatsby-config.js 에서 해당 코드의 path부분을 본인의 yaml 파일로 지정합니다. 46 | 47 | 3. ```json 48 | `gatsby-transformer-yaml`, 49 | { 50 | resolve: `gatsby-source-filesystem`, 51 | options: { 52 | path: `./static/resumes/resume.yaml`, 53 | }, 54 | }, 55 | ``` 56 | 57 | 3. http://localhost:8000 에서 이력서를 확인할 수 있습니다. 58 | 59 | ## Demo 60 | * simple-resume 61 | 62 | 63 | 64 | ## Contributing 65 | 66 | This is an open source product, please feel free to fork and make pull requests! 67 | 68 | Any suggestions are welcomed! 69 | 70 | ## Authors 71 | 72 | [yoon.homme](https://github.com/suites) 73 | 74 | ## License 75 | 76 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details -------------------------------------------------------------------------------- /gatsby-browser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Browser APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/browser-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: `Resume - John Doe`, 4 | description: `This is a resume of software engineer John Doe.`, 5 | author: `John Doe`, 6 | }, 7 | plugins: [ 8 | `gatsby-plugin-react-helmet`, 9 | { 10 | resolve: `gatsby-source-filesystem`, 11 | options: { 12 | name: `images`, 13 | path: `${__dirname}/src/images`, 14 | }, 15 | }, 16 | `gatsby-transformer-sharp`, 17 | `gatsby-plugin-typescript`, 18 | `gatsby-plugin-sharp`, 19 | { 20 | resolve: `gatsby-plugin-manifest`, 21 | options: { 22 | name: `gatsby-starter-default`, 23 | short_name: `starter`, 24 | start_url: `/`, 25 | background_color: `#663399`, 26 | theme_color: `#663399`, 27 | display: `minimal-ui`, 28 | icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site. 29 | }, 30 | }, 31 | `gatsby-transformer-yaml`, 32 | { 33 | resolve: `gatsby-source-filesystem`, 34 | options: { 35 | path: `./static/resumes/john-doe.yaml`, 36 | }, 37 | }, 38 | // this (optional) plugin enables Progressive Web App + Offline functionality 39 | // To learn more, visit: https://gatsby.dev/offline 40 | // `gatsby-plugin-offline`, 41 | ], 42 | } 43 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Node APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/node-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's SSR (Server Side Rendering) APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/ssr-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-resume", 3 | "private": true, 4 | "description": "Simple resume", 5 | "version": "0.1.0", 6 | "author": "yoon.homme ", 7 | "dependencies": { 8 | "@types/react-helmet": "^5.0.9", 9 | "@types/react-linkify": "^0.2.0", 10 | "@types/styled-components": "^4.1.18", 11 | "babel-preset-gatsby": "^1.0.0", 12 | "gatsby": "^3.0.3", 13 | "gatsby-image": "^3.0.0", 14 | "gatsby-plugin-manifest": "^3.0.0", 15 | "gatsby-plugin-offline": "^3.0.0", 16 | "gatsby-plugin-react-helmet": "^4.0.0", 17 | "gatsby-plugin-sharp": "^3.0.0", 18 | "gatsby-plugin-typescript": "^3.0.0", 19 | "gatsby-source-filesystem": "^3.0.0", 20 | "gatsby-transformer-sharp": "^3.0.0", 21 | "gatsby-transformer-yaml": "^3.0.0", 22 | "prop-types": "^15.7.2", 23 | "react": "^17.0.0", 24 | "react-dom": "^16.9.0", 25 | "react-helmet": "^5.2.1", 26 | "react-icons": "^3.7.0", 27 | "react-linkify": "^1.0.0-alpha", 28 | "styled-components": "^4.3.2", 29 | "typescript": "^3.5.3" 30 | }, 31 | "devDependencies": { 32 | "prettier": "^1.18.2" 33 | }, 34 | "keywords": [ 35 | "gatsby" 36 | ], 37 | "license": "MIT", 38 | "scripts": { 39 | "build": "gatsby build", 40 | "develop": "gatsby develop", 41 | "format": "prettier --write \"**/*.{js,jsx,json,md}\"", 42 | "start": "npm run develop", 43 | "serve": "gatsby serve", 44 | "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\"" 45 | }, 46 | "repository": { 47 | "type": "git", 48 | "url": "https://github.com/gatsbyjs/simple-resume" 49 | }, 50 | "bugs": { 51 | "url": "https://github.com/gatsbyjs/gatsby/issues" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/components/common/ProgressBar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | const ProgressContainer = styled.div` 5 | width: 100%; 6 | height: 8px; 7 | background: #ccc; 8 | `; 9 | 10 | const Progress = styled.div` 11 | height: 8px; 12 | background: #3a7bd5; 13 | width: ${(props: { scrolled: string }) => props.scrolled}; 14 | `; 15 | 16 | export class ProgressBar extends React.Component<{}, { scrolled: string }> { 17 | constructor(props: {}) { 18 | super(props); 19 | this.state = { 20 | scrolled: '0%', 21 | }; 22 | } 23 | 24 | componentDidMount() { 25 | window.addEventListener('scroll', this.scrollProgress); 26 | } 27 | 28 | componentWillUnmount() { 29 | window.removeEventListener('scroll', this.scrollProgress); 30 | } 31 | 32 | scrollProgress = () => { 33 | const scrollPx = document.documentElement.scrollTop; 34 | const winHeightPx = 35 | document.documentElement.scrollHeight - 36 | document.documentElement.clientHeight; 37 | const scrolled = `${scrollPx / winHeightPx * 100}%`; 38 | 39 | this.setState({ 40 | scrolled, 41 | }); 42 | } 43 | render() { 44 | return ( 45 | 46 | 47 | 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/components/common/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import * as icons from 'react-icons/fa'; 3 | import styled from 'styled-components'; 4 | 5 | export * from './ProgressBar'; 6 | export const Section = styled.section` 7 | padding: 0 2rem; 8 | `; 9 | 10 | export const SectionTitle = styled.h2` 11 | `; 12 | 13 | const StyledHeadline = styled.div` 14 | display: -webkit-box; 15 | display: -ms-flexbox; 16 | display: flex; 17 | border-bottom: 2px solid #3a7bd5; 18 | `; 19 | 20 | export const HeadLine = ({ icon, title }: { icon: string, title: string }) => { 21 | return ( 22 | 23 | 24 | 30 | {title} 31 | 32 | 33 | ); 34 | }; 35 | 36 | export const Contents = styled.div` 37 | padding: 1rem 0rem 1rem; 38 | border-bottom: 1px solid #eeeeee; 39 | `; 40 | 41 | export const Row = styled(Contents)` 42 | display: flex; 43 | `; 44 | 45 | export const RowLeft = styled.div` 46 | flex-basis: 18rem; 47 | padding-right: 1rem; 48 | flex-shrink: 0; 49 | `; 50 | 51 | export const RowRight = styled.div` 52 | flex-grow: 1; 53 | `; 54 | 55 | export const StyledUl = styled.ul` 56 | list-style:none; 57 | padding:0; 58 | margin:0 0 1rem; 59 | font-size:1.1rem; 60 | `; 61 | 62 | export const ALink = styled.a` 63 | color: #3a7bd5; 64 | transition: color 0.3s ease; 65 | &:hover { 66 | color: #00d2ff; 67 | } 68 | `; 69 | 70 | export const StyledLi = styled.li` 71 | ${StyledUl} > & { 72 | position:relative; 73 | padding:.2rem 0 0rem 1rem; 74 | } 75 | &:before { 76 | position:absolute; 77 | left:0; 78 | display:inline-block; 79 | content:"•"; 80 | color:#3a7bd5; 81 | } 82 | `; 83 | 84 | export const StyledH2 = styled.h2` 85 | font-size:2.5rem; 86 | margin:3rem 0 2rem; 87 | `; 88 | 89 | export const StyledH3 = styled.h3` 90 | font-size: 2rem; 91 | margin: 0 0 1rem 0; 92 | `; 93 | 94 | export const StyledH4 = styled.h4` 95 | font-size: 1.5rem; 96 | margin: 1rem 0 1rem 0; 97 | `; 98 | 99 | export const StyledH5 = styled.h5` 100 | font-size: 1.3rem; 101 | margin: 0.5rem 0 0.5rem 0; 102 | color: #333333; 103 | `; 104 | 105 | interface FaIconProps { 106 | icon: string; 107 | verticalAlign?: string; 108 | marginLeft?: string; 109 | marginRight?: string; 110 | size?: string; 111 | } 112 | 113 | export const FaIcon = ({ icon, verticalAlign, marginRight, marginLeft, size }: FaIconProps) => { 114 | try { 115 | const Result = (icons as any)[icon]; 116 | return ( 117 | 118 | ); 119 | } catch { 120 | return <>; 121 | } 122 | 123 | }; 124 | 125 | interface DateProps { 126 | start: string; 127 | end?: string; 128 | } 129 | 130 | export const Date = ({ start, end }: DateProps) => { 131 | return ( 132 | 133 | 136 | { 137 | end && 138 | <> 139 | - 140 | 143 | 144 | } 145 | 146 | ); 147 | }; 148 | 149 | export const StyledTime = styled.span` 150 | display: block; 151 | margin-bottom: 1.5rem; 152 | `; 153 | 154 | export const StyledP = styled.p` 155 | margin: 0 0 1rem 0; 156 | font-size: 1.1rem; 157 | line-height: 1.4; 158 | `; 159 | -------------------------------------------------------------------------------- /src/components/layout.css: -------------------------------------------------------------------------------- 1 | @import url(//spoqa.github.io/spoqa-han-sans/css/SpoqaHanSans-kr.css); 2 | @import url(//spoqa.github.io/spoqa-han-sans/css/SpoqaHanSans-jp.css); 3 | 4 | ::selection { 5 | background: #00d2ff; 6 | } 7 | 8 | html, body, div, span, applet, object, iframe, 9 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 10 | a, abbr, acronym, address, big, cite, code, 11 | del, dfn, em, img, ins, kbd, q, s, samp, 12 | small, strike, strong, sub, sup, tt, var, 13 | b, u, i, center, 14 | dl, dt, dd, ol, ul, li, 15 | fieldset, form, label, legend, 16 | table, caption, tbody, tfoot, thead, tr, th, td, 17 | article, aside, canvas, details, embed, 18 | figure, figcaption, footer, header, hgroup, 19 | menu, nav, output, ruby, section, summary, 20 | time, mark, audio, video { 21 | margin: 0; 22 | padding: 0; 23 | border: 0; 24 | font-size: 100%; 25 | vertical-align: baseline; 26 | } 27 | /* HTML5 display-role reset for older browsers */ 28 | article, aside, details, figcaption, figure, 29 | footer, header, hgroup, menu, nav, section { 30 | display: block; 31 | } 32 | body { 33 | font-size: 16px; 34 | word-break: keep-all; 35 | font-family: Spoqa Han Sans, sans-serif; 36 | letter-spacing: -0.3px; 37 | color: #222222; 38 | padding-bottom: 2rem; 39 | overflow-x: hidden; 40 | -webkit-font-smoothing: antialiased; 41 | -moz-osx-font-smoothing: grayscale; 42 | } 43 | ol, ul { 44 | list-style: none; 45 | } 46 | blockquote, q { 47 | quotes: none; 48 | } 49 | blockquote:before, blockquote:after, 50 | q:before, q:after { 51 | content: ''; 52 | content: none; 53 | } 54 | table { 55 | border-collapse: collapse; 56 | border-spacing: 0; 57 | } 58 | a { 59 | color: #3a7bd5; 60 | transition: color 0.3s ease; 61 | } 62 | a:hover { 63 | color: #00d2ff; 64 | } 65 | 66 | * { 67 | box-sizing: border-box; 68 | } -------------------------------------------------------------------------------- /src/components/layout.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { graphql, useStaticQuery } from 'gatsby'; 4 | import styled from 'styled-components'; 5 | import Resume from '../models'; 6 | import { ProgressBar } from './common'; 7 | import './layout.css'; 8 | import { ActionComponent, Careers, Profile, Skills } from './sections'; 9 | import { About } from './sections/about'; 10 | 11 | const Header = styled.div` 12 | position: fixed; 13 | top: 0; 14 | z-index: 1; 15 | width: 100%; 16 | background-color: #f1f1f1; 17 | `; 18 | 19 | const Container = styled.div` 20 | width: 100%; 21 | max-width: 50rem; 22 | margin: auto; 23 | `; 24 | 25 | const Layout = () => { 26 | const data = useStaticQuery(graphql` 27 | query { 28 | allResumesYaml { 29 | edges { 30 | node { 31 | experiences { 32 | name 33 | information 34 | date { 35 | start 36 | end 37 | } 38 | description 39 | } 40 | educations { 41 | name 42 | date { 43 | start 44 | end 45 | } 46 | description 47 | } 48 | licenses { 49 | name 50 | information 51 | date { 52 | start 53 | end 54 | } 55 | description 56 | } 57 | } 58 | } 59 | } 60 | } 61 | `); 62 | const resume: Resume = data.allResumesYaml.edges[0].node; 63 | 64 | return ( 65 | <> 66 |
67 | 68 |
69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | ); 80 | }; 81 | 82 | export default Layout; 83 | -------------------------------------------------------------------------------- /src/components/sections/about.tsx: -------------------------------------------------------------------------------- 1 | import { graphql, useStaticQuery } from 'gatsby'; 2 | import React from 'react'; 3 | import Linkify from 'react-linkify'; 4 | import Resume from '../../models'; 5 | import { Contents, HeadLine, Section, StyledH4, StyledH5 } from '../common'; 6 | export const About = () => { 7 | const data = useStaticQuery(graphql` 8 | query { 9 | allResumesYaml { 10 | edges { 11 | node { 12 | aboutme 13 | } 14 | } 15 | } 16 | } 17 | `); 18 | const resume: Resume = data.allResumesYaml.edges[0].node; 19 | 20 | return ( 21 |
22 | 23 | 24 | 25 | { 26 | resume.aboutme.map((value, i) => { 27 | const Sentence = 28 | value.includes('##') && {value.replace('##', '')} 29 | || value.includes('#') && {value.replace('#', '')} 30 | ||

{value}

; 31 | return ( 32 | Sentence 33 | ); 34 | }) 35 | } 36 |
37 |
38 |
39 | ); 40 | }; 41 | -------------------------------------------------------------------------------- /src/components/sections/action.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Linkify from 'react-linkify'; 3 | import styled from 'styled-components'; 4 | import { Action } from '../../models'; 5 | import { Contents, Date, HeadLine, Section, StyledH3 } from '../common'; 6 | 7 | interface Props { 8 | title: string; 9 | icon: string; 10 | actions: Action[]; 11 | } 12 | 13 | const Information = styled.span` 14 | `; 15 | 16 | const Text = styled.p` 17 | `; 18 | 19 | export const ActionComponent = ({ title, icon, actions }: Props) => { 20 | return ( 21 |
22 | 23 | {actions && actions.map((action, i) => { 24 | return ( 25 | 26 | {action.name} 27 | {action.information} 28 | { 29 | action.date && 30 | 31 | } 32 | 33 | { 34 | action.description && 35 | action.description.map((value, j) => { 36 | return ( 37 | {value} 38 | ); 39 | }) 40 | } 41 | 42 | 43 | ); 44 | })} 45 |
46 | ); 47 | }; 48 | -------------------------------------------------------------------------------- /src/components/sections/careers.tsx: -------------------------------------------------------------------------------- 1 | import { graphql, useStaticQuery } from 'gatsby'; 2 | import React from 'react'; 3 | import Resume, { Career, Project } from '../../models'; 4 | import { Date, FaIcon, HeadLine, Row, RowLeft, RowRight, Section, StyledH3, StyledH4, StyledH5, StyledLi, StyledP, StyledUl } from '../common'; 5 | 6 | const TechStack = ({ career }: { career: Career }) => { 7 | return ( 8 | <> 9 | {'Tech Stacks'} 10 | 11 | {career.techStacks.map((techStack, i) => { 12 | return ( 13 | 14 | {`${techStack.name} : ${techStack.items.join(', ')}`} 15 | 16 | ); 17 | }) 18 | } 19 | 20 | 21 | ); 22 | }; 23 | 24 | const ProjectComponent = ({ projects }: { projects: Project[] }) => { 25 | return ( 26 | <> 27 | { 28 | projects.map((project, i) => { 29 | return ( 30 |
31 | 32 | 39 | {project.name} 40 | 41 | { 42 | project.date && 43 | 44 | } 45 | Descrition 46 | {project.description} 47 | What did I do 48 | 49 | {project.parts.map((part, j) => { 50 | return ( 51 | 52 | {part} 53 | 54 | ); 55 | })} 56 | 57 |
58 | ); 59 | }) 60 | } 61 | 62 | ); 63 | }; 64 | 65 | export const Careers = () => { 66 | const data = useStaticQuery(graphql` 67 | query { 68 | allResumesYaml { 69 | edges { 70 | node { 71 | careers { 72 | name 73 | information 74 | date { 75 | start 76 | end 77 | } 78 | techStacks { 79 | name 80 | items 81 | } 82 | projects { 83 | name 84 | date { 85 | start 86 | end 87 | } 88 | description 89 | parts 90 | } 91 | } 92 | } 93 | } 94 | } 95 | } 96 | `); 97 | const resume: Resume = data.allResumesYaml.edges[0].node; 98 | 99 | return ( 100 |
101 | 102 | { 103 | resume.careers.map((career, i) => { 104 | return ( 105 | 106 | 107 | {career.name} 108 | {career.information} 109 | { 110 | career.date && 111 | 112 | } 113 | 114 | 115 | 116 | 117 | 118 | 119 | ); 120 | }) 121 | } 122 |
123 | ); 124 | }; 125 | -------------------------------------------------------------------------------- /src/components/sections/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './profile'; 2 | export * from './skills'; 3 | export * from './careers'; 4 | export * from './action'; 5 | export * from './about'; 6 | -------------------------------------------------------------------------------- /src/components/sections/profile.tsx: -------------------------------------------------------------------------------- 1 | import { graphql, useStaticQuery } from 'gatsby'; 2 | import React from 'react'; 3 | import styled from 'styled-components'; 4 | import Resume from '../../models'; 5 | import { ALink, FaIcon, Row, RowLeft, RowRight, Section, StyledH2, StyledLi, StyledUl } from '../common'; 6 | 7 | const Sentence = styled.div` 8 | `; 9 | 10 | const Introduction = styled.div` 11 | padding: 2rem 0 0rem; 12 | border-bottom: 0px; 13 | & > ${Sentence} { 14 | margin: 0 0 1rem 0; 15 | font-size: 2rem; 16 | line-height: 1.4; 17 | font-weight: 500; 18 | } 19 | `; 20 | 21 | const ProfileRow = styled(Row)` 22 | padding: 2rem 0 0rem; 23 | border-bottom: 0px; 24 | `; 25 | 26 | const Name = styled(StyledH2)` 27 | margin-top: 0px; 28 | `; 29 | 30 | const Address = styled(StyledUl)` 31 | list-style-type: none; 32 | `; 33 | 34 | const AddressItem = styled(StyledLi)` 35 | ${Address} > & { 36 | padding: .6rem 0 .2rem 0; 37 | } 38 | &::before{ 39 | content:none; 40 | } 41 | `; 42 | 43 | export const Profile = () => { 44 | const data = useStaticQuery(graphql` 45 | query { 46 | allResumesYaml { 47 | edges { 48 | node { 49 | photo 50 | name 51 | links { 52 | type 53 | name 54 | symbol 55 | } 56 | introduction 57 | } 58 | } 59 | } 60 | } 61 | `); 62 | const resume: Resume = data.allResumesYaml.edges[0].node; 63 | 64 | return ( 65 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | {resume.name} 73 | 74 |
75 | { 76 | resume.links.map((value, i) => { 77 | return ( 78 | 79 | 84 | {value.name} 85 | 86 | ); 87 | }) 88 | } 89 |
90 |
91 |
92 | 93 | { 94 | resume.introduction.map((value, i) => { 95 | return {value}; 96 | }) 97 | } 98 | 99 |
100 | ); 101 | }; 102 | -------------------------------------------------------------------------------- /src/components/sections/skills.tsx: -------------------------------------------------------------------------------- 1 | import { graphql, useStaticQuery } from 'gatsby'; 2 | import React from 'react'; 3 | import Resume from '../../models'; 4 | import { HeadLine, Row, RowLeft, RowRight, Section, StyledH3, StyledLi, StyledUl } from '../common'; 5 | 6 | export const Skills = () => { 7 | const data = useStaticQuery(graphql` 8 | query { 9 | allResumesYaml { 10 | edges { 11 | node { 12 | skills { 13 | name 14 | items 15 | } 16 | } 17 | } 18 | } 19 | } 20 | `); 21 | const resume: Resume = data.allResumesYaml.edges[0].node; 22 | 23 | return ( 24 |
25 | 26 | { 27 | resume.skills.map((value, i) => { 28 | return ( 29 | 30 | 31 | {value.name} 32 | 33 | 34 | 35 | { 36 | value.items.map((item, j) => { 37 | return {item}; 38 | }) 39 | } 40 | 41 | 42 | 43 | ); 44 | }) 45 | } 46 | 47 |
48 | ); 49 | }; 50 | -------------------------------------------------------------------------------- /src/components/seo.tsx: -------------------------------------------------------------------------------- 1 | import { graphql, useStaticQuery } from 'gatsby'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | import Helmet from 'react-helmet'; 5 | 6 | function SEO({ description, lang, meta, title }: { description: string, lang: string, meta: any, title: string }) { 7 | const { site } = useStaticQuery( 8 | graphql` 9 | query { 10 | site { 11 | siteMetadata { 12 | title 13 | description 14 | author 15 | } 16 | } 17 | } 18 | `, 19 | ); 20 | 21 | const metaDescription = description || site.siteMetadata.description; 22 | 23 | return ( 24 | 65 | ); 66 | } 67 | 68 | SEO.defaultProps = { 69 | lang: `en`, 70 | meta: [], 71 | description: ``, 72 | }; 73 | 74 | SEO.propTypes = { 75 | description: PropTypes.string, 76 | lang: PropTypes.string, 77 | meta: PropTypes.arrayOf(PropTypes.object), 78 | title: PropTypes.string.isRequired, 79 | }; 80 | 81 | export default SEO; 82 | -------------------------------------------------------------------------------- /src/images/gatsby-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suites/simple-resume/6415ed4e6fe644aee26feccc94e7cc27681e3c7d/src/images/gatsby-icon.png -------------------------------------------------------------------------------- /src/models/index.ts: -------------------------------------------------------------------------------- 1 | export default interface Resume { 2 | blogUrl: string; 3 | description: string; 4 | cover: string; 5 | name: string; 6 | photo: string; 7 | introduction: string[]; 8 | skills: Skill[]; 9 | careers: Career[]; 10 | links: Link[]; 11 | experiences: Action[]; 12 | educations: Action[]; 13 | licenses: Action[]; 14 | aboutme: string[]; 15 | } 16 | 17 | export interface Skill { 18 | name: string; 19 | items: string[]; 20 | } 21 | 22 | export interface Action { 23 | name: string; 24 | information?: string; 25 | date?: ActionDate; 26 | description?: string[]; 27 | } 28 | 29 | export interface ActionDate { 30 | start: string; 31 | end?: string; 32 | } 33 | 34 | export interface Career extends Action { 35 | techStacks: Skill[]; 36 | projects: Project[]; 37 | } 38 | 39 | export interface Project extends Action { 40 | parts: string[]; 41 | } 42 | 43 | export interface Link { 44 | name: string; 45 | symbol: string; 46 | type: string; 47 | } 48 | -------------------------------------------------------------------------------- /src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import SEO from '../components/seo'; 4 | 5 | const NotFoundPage = () => ( 6 | <> 7 | 8 |

NOT FOUND

9 |

You just hit a route that doesn't exist... the sadness.

10 | 11 | ); 12 | 13 | export default NotFoundPage; 14 | -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Layout from '../components/layout'; 4 | import SEO from '../components/seo'; 5 | 6 | const IndexPage = () => { 7 | return ( 8 | <> 9 | 10 | 11 | 12 | ); 13 | }; 14 | 15 | export default IndexPage; 16 | -------------------------------------------------------------------------------- /static/profile-yaml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suites/simple-resume/6415ed4e6fe644aee26feccc94e7cc27681e3c7d/static/profile-yaml.png -------------------------------------------------------------------------------- /static/resumes/chick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suites/simple-resume/6415ed4e6fe644aee26feccc94e7cc27681e3c7d/static/resumes/chick.png -------------------------------------------------------------------------------- /static/resumes/john-doe.yaml: -------------------------------------------------------------------------------- 1 | # Head config [views/partials/head.ejs] 2 | # Meta tag 관련 설정입니다. 3 | # Meta tag-related settings. 4 | blogUrl: http://example.com/resume 5 | description: This is a resume of software engineer John Doe. 6 | cover: "/" 7 | # Resume config [views/partials/profile.ejs] 8 | # 이력서 상단에 들어갈 사진과 이름, 간단 소개입니다. 9 | # A picture, name and brief introduction to the top of your resume. 10 | name: John Doe 11 | photo: "resumes/chick.png" 12 | introduction: 13 | - Hello! I'm John Doe. I'm Software Engineer. 14 | - I enjoy playing games and eating. I'm happiest when I eat. I like pork. 15 | 16 | # Profile link config [views/sections/profile.ejs] 17 | # email, github, linkedin, blog의 주소와 아이콘 설정입니다. 18 | # The address and icon settings for email, github, linkedin, and blog. 19 | 20 | # name: 연결할 서비스의 주소입니다. 21 | # symbol: 링크 앞의 awesome font 심볼입니다. [https://fontawesome.com/icons/](ex : fab fa-apple) 22 | # type: 링크의 서비스명 입니다. 23 | 24 | # name: The address of the service to which you want to connect. 25 | # symbol: Awesome font symbol in front of the link. [https://fontawesome.com/icons/](ex : fab fa-apple) 26 | # type: This is the service name of the link. 27 | 28 | links: 29 | - name: "john.doe@example.com" 30 | symbol: FaEnvelope 31 | type: email 32 | - name: "https://github.com/johndoe" 33 | symbol: FaGithub 34 | type: github 35 | - name: https://www.linkedin.com/in/johndoe 36 | symbol: FaLinkedin 37 | type: linkedin 38 | - name: http://example.com 39 | symbol: FaHome 40 | type: blog 41 | 42 | # Skills config [views/sections/skills.ejs] 43 | # 보유기술 설정입니다. 항목을 자유롭게 추가할 수 있습니다. 44 | 45 | # This is a technology setting. You can add items freely. 46 | skills: 47 | - name: Languages 48 | items: 49 | - Node.js 50 | - python 51 | - mysql 52 | - name: Libraries 53 | items: 54 | - Express 55 | - name: Tools 56 | items: 57 | - vscode 58 | - name: VCS 59 | items: 60 | - Git 61 | 62 | # Careers config [views/sections/careers.ejs] 63 | # 경력사항 설정입니다. 회사와 프로젝트를 추가할 수 있습니다. 64 | # 회사 추가시 careers 밑의 -company 부터 복사하여 사용하고, 65 | # 프로젝트 추가시 projects 밑의 -name 부터 복사하여 사용합니다. 66 | # Date type : yyyy.mm 67 | 68 | # Experience settings. You can add companies and projects. 69 | # When adding a company, copy and use it from "-company" under careers. 70 | # When adding a project, copy and use "-name" under projects. 71 | careers: 72 | - name: John Company 73 | information: Junior Software Engineer 74 | date: 75 | start: '2018.03' 76 | end: 'now' 77 | techStacks: 78 | - name: Language 79 | items: 80 | - HTML 81 | - CSS3 82 | - JavaScript 83 | - Node.js 84 | - name: System 85 | items: 86 | - Ubuntu 16.04 87 | - name: Tool 88 | items: 89 | - Git 90 | projects: 91 | - name: Member management service operations 92 | date: 93 | start: '2018.03' 94 | end: '2018.06' 95 | description: The member management functions were developed and maintained for the smooth service use of users. 96 | parts: 97 | - Development of member management 98 | - Implement SNS login 99 | 100 | # Other Experiences config [views/sections/experiences.ejs] 101 | # 기타 경험 설정입니다. 이름, 역할, 기간, 요약등을 추가할 수 있습니다. 102 | # 항목 추가시 -experience 부터 description까지 복사하여 사용합니다. 103 | 104 | # Other experience settings. You can add names, informations, date, and summaries. 105 | # When adding an item, copy and use -experience to description under otherExperience. 106 | experiences: 107 | - name: Delicious Cookie Hackathon 108 | information: Development 109 | date: 110 | start: '2018.08' 111 | end: '2018.08' 112 | description: 113 | - Delicious Cookie Hackathon has developed Cookie Food Service and won it. 114 | - name: Nursing home volunteer activities 115 | information: Volunteer 116 | date: 117 | start: '2018.06' 118 | end: '2018.07' 119 | description: 120 | - https://example.com/example/ 121 | - I went to the nursing home and did volunteer work. It was rewarding. 122 | 123 | # Educations config [views/sections/educations.ejs] 124 | # 학력, 교육 항목 설정입니다. 이름과 기간 요약을 추가할 수 있습니다. 125 | # 항목 추가시 -education 부터 description까지 복사하여 사용합니다. 126 | 127 | # Education, education item settings. Lets you add a name and a summary of the date summary. 128 | # When adding an item, copy and use the item from -education to description. 129 | educations: 130 | - name: Korea Cookie University 131 | date: 132 | start: '2011.03' 133 | end: '2015.03' 134 | description: 135 | - I graduated from school. 136 | 137 | # Licenses config [views/sections/licenses.ejs] 138 | # 자격증 항목 설정입니다. 이름과 기간 요약을 추가할 수 있습니다. 139 | # 항목 추가시 licenses 밑의 -license 부터 description까지 복사하여 사용합니다. 140 | 141 | # Certificate entry settings. Lets you add a name and a summary of the date summary. 142 | # When adding items, copy and use the -license to description under Licenses. 143 | 144 | licenses: 145 | - name: Confectionary function qualification 146 | information: Cookie Land 147 | date: 148 | start: '2008.03' 149 | end: '' 150 | description: 151 | - I got a license. 152 | 153 | # aboutme config [views/sections/about.ejs] 154 | # 자기소개서 설정입니다. 자유롭게 작성할 수 있습니다. 155 | # - 로 항목을 추가하면 문단이 추가되는 효과가 있습니다. 156 | aboutme: 157 | - Elit minim consectetur adipisicing nisi et laborum occaecat esse 158 | - dolor cupidatat exercitation consequat pariatur sunt. Esse est ipsum nostrud consectetur tempor ad. Anim laboris Lorem deserunt ad eu deserunt est aute. 159 | - '# Sit elit veniam' 160 | - Irure velit sit eiusmod cupidatat minim irure cupidatat velit magna mollit in cupidatat cillum. Amet aliqua dolor elit enim. 161 | - '## Sit elit veniam' 162 | - Minim esse consectetur velit sunt nostrud nulla id aliqua. 163 | - '## incididunt exercitation' 164 | - 'https://example.com' 165 | - veniam deserunt proident voluptate occaecat dolor incididunt exercitation irure sit ex. Veniam cupidatat excepteur nulla laboris non sunt Lorem irure Lorem eu non enim dolor. Culpa enim nulla quis ex cupidatat anim ad occaecat anim ea nostrud. 166 | -------------------------------------------------------------------------------- /static/simple-resume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suites/simple-resume/6415ed4e6fe644aee26feccc94e7cc27681e3c7d/static/simple-resume.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "jsx": "react", 6 | "strict": true, 7 | "esModuleInterop": true, 8 | "typeRoots": [ 9 | "./node_modules/@types", 10 | "./@types", 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "indent": { 9 | "options": [ 10 | "spaces", 11 | 2 12 | ] 13 | }, 14 | "interface-name": { 15 | "options": [ 16 | "never-prefix" 17 | ] 18 | }, 19 | "max-classes-per-file": { 20 | "options": [ 21 | 10 22 | ] 23 | }, 24 | "max-line-length": { 25 | "options": [ 26 | 150 27 | ], 28 | "severity": "warning" 29 | }, 30 | "member-access": false, 31 | "member-ordering": false, 32 | "no-console": false, 33 | "no-empty-interface": false, 34 | "no-reference": false, 35 | "no-var-requires": false, 36 | "object-literal-sort-keys": false, 37 | "quotemark": { 38 | "options": [ 39 | "single", 40 | "jsx-single", 41 | "avoid-escape" 42 | ] 43 | }, 44 | "trailing-comma": { 45 | "options": { 46 | "esSpecCompliant": true, 47 | "multiline": "always", 48 | "singleline": "never" 49 | } 50 | }, 51 | "variable-name": { 52 | "options": [ 53 | "ban-keywords", 54 | "check-format", 55 | "allow-pascal-case", 56 | "allow-snake-case" 57 | ] 58 | } 59 | }, 60 | "rulesDirectory": [] 61 | } --------------------------------------------------------------------------------