├── public ├── favicon.ico ├── logo192.png ├── logo512.png ├── robots.txt ├── manifest.json └── index.html ├── src ├── assets │ ├── img │ │ └── cover.jpeg │ └── icons │ │ └── index.js ├── styles │ ├── Post.css │ ├── Code.css │ └── App.css ├── App.js ├── index.js ├── components │ ├── Post.js │ └── Code.js └── tutorials │ └── tutorial1.md ├── .gitignore ├── README.md └── package.json /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljaviertovar/blog-markdown/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljaviertovar/blog-markdown/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljaviertovar/blog-markdown/HEAD/public/logo512.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/assets/img/cover.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljaviertovar/blog-markdown/HEAD/src/assets/img/cover.jpeg -------------------------------------------------------------------------------- /src/styles/Post.css: -------------------------------------------------------------------------------- 1 | .article-wrapper { 2 | padding: 2rem; 3 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3); 4 | } 5 | 6 | .article__cover img { 7 | width: 100%; 8 | } -------------------------------------------------------------------------------- /src/styles/Code.css: -------------------------------------------------------------------------------- 1 | .code { 2 | position: relative; 3 | } 4 | 5 | .code pre { 6 | padding-top: 2rem !important; 7 | transition: .3s ease all; 8 | } 9 | 10 | .code__icons { 11 | position: absolute; 12 | top: 0; 13 | right: 0; 14 | z-index: 1; 15 | } 16 | 17 | .code__icons button { 18 | background-color: transparent; 19 | border: none; 20 | padding: 10px; 21 | cursor: pointer; 22 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import Post from './components/Post' 2 | 3 | import { LogoIcon } from './assets/icons' 4 | import './styles/App.css' 5 | 6 | const App = () => { 7 | return ( 8 | <> 9 |
10 |
11 |
My Blog Tutorials
12 |
13 |
14 |
15 | 16 |
17 | 18 | ) 19 | } 20 | 21 | export default App 22 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | // import reportWebVitals from './reportWebVitals'; 5 | 6 | ReactDOM.render( 7 | 8 | 9 | , 10 | document.getElementById('root') 11 | ); 12 | 13 | // If you want to start measuring performance in your app, pass a function 14 | // to log results (for example: reportWebVitals(console.log)) 15 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 16 | // reportWebVitals(); 17 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 📑 My Blog Tutorials 2 | 3 | Tutorials blog made white React and Markdown, darkmode and copy to clipboard. 4 | 5 | ### Front-end 6 | * React js 7 | * markdown-to-jsx 8 | * react-syntax-highlighter 9 | * react-copy-to-clipboard 10 | 11 | ### Installig 12 | 13 | ``` 14 | npm run install 15 | ``` 16 | 17 | ### Running app 18 | 19 | ``` 20 | npm run start 21 | ``` 22 | 23 |
24 | 25 | [🚀 See the demo here.](https://my-blog-tutorials.netlify.app/) 26 | 27 | This app is explained in the following [📰 post](https://medium.com/bitsrc/build-a-blog-with-react-and-markdown-files-30d969ce62d5). 28 | 29 | ![image](https://user-images.githubusercontent.com/34925280/189154683-86d6ad0c-f405-42b1-962b-7d58e03b50cb.png) 30 | ![image](https://user-images.githubusercontent.com/34925280/189154774-0c5c5c57-73ec-4c97-a4f8-9bac99b051da.png) 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog-markdown", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.2", 7 | "@testing-library/react": "^12.1.3", 8 | "@testing-library/user-event": "^13.5.0", 9 | "markdown-to-jsx": "^7.1.6", 10 | "react": "^17.0.2", 11 | "react-copy-to-clipboard": "^5.0.4", 12 | "react-dom": "^17.0.2", 13 | "react-scripts": "5.0.0", 14 | "react-syntax-highlighter": "^15.4.5", 15 | "web-vitals": "^2.1.4" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": [ 25 | "react-app", 26 | "react-app/jest" 27 | ] 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/components/Post.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react" 2 | import Markdown from "markdown-to-jsx" 3 | import Code from "./Code" 4 | 5 | import cover from '../assets/img/cover.jpeg' 6 | import '../styles/Post.css' 7 | 8 | const Post = () => { 9 | const [postContent, setPostcontent] = useState('') 10 | const [isDark, setIsDark] = useState(true) 11 | 12 | useEffect(() => { 13 | import('../tutorials/tutorial1.md') 14 | .then(res => 15 | fetch(res.default) 16 | .then(response => response.text()) 17 | .then(response => setPostcontent(response)) 18 | .catch(err => console.log(err)) 19 | ) 20 | }, []) 21 | 22 | return ( 23 |
24 |
25 |
26 |
27 | my-cover 31 |
32 |
33 |
34 | 47 | {postContent} 48 | 49 |
50 |
51 |
52 | ) 53 | } 54 | 55 | export default Post -------------------------------------------------------------------------------- /src/components/Code.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | import { CopyToClipboard } from "react-copy-to-clipboard" 3 | import { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter' 4 | import jsx from 'react-syntax-highlighter/dist/esm/languages/prism/jsx' 5 | import { materialDark, materialLight } from 'react-syntax-highlighter/dist/esm/styles/prism' 6 | 7 | import { CopyIcon, PasteIcon, SunIcon, MoonIcon } from "../assets/icons" 8 | import '../styles/Code.css' 9 | 10 | const Code = ({ children, language, isDark, setIsDark }) => { 11 | const [isCopied, setIsCopied] = useState(false) 12 | 13 | SyntaxHighlighter.registerLanguage('jsx', jsx); 14 | 15 | const setCopied = () => { 16 | setIsCopied(true) 17 | setTimeout(() => { setIsCopied(false) }, 1000); 18 | } 19 | 20 | return ( 21 |
22 |
23 | 26 | 27 | 28 | 34 | 35 |
36 | 37 | 38 | {children} 39 | 40 |
41 | ) 42 | } 43 | 44 | export default Code -------------------------------------------------------------------------------- /src/tutorials/tutorial1.md: -------------------------------------------------------------------------------- 1 | # Using the State Hook 2 | 3 | The [introduction page](https://reactjs.org/docs/hooks-intro.html) used this example to get familiar with Hooks: 4 | 5 | 6 | import React, { useState } from 'react'; 7 | function Example() { 8 | // Declare a new state variable, which we'll call "count" 9 | const [count, setCount] = useState(0); 10 | return ( 11 | <div> 12 | <p>You clicked {count} times

13 | <button onClick={() => setCount(count + 1)}> 14 | Click me 15 | 16 | 17 | ); 18 | } 19 | export default Example; 20 |
21 | 22 | We’ll start learning about Hooks by comparing this code to an equivalent class example. 23 | 24 | # Equivalent Class Example 25 | 26 | If you used classes in React before, this code should look familiar: 27 | 28 | 29 | class Example extends React.Component { 30 | constructor(props) { 31 | super(props); 32 | this.state = { 33 | count: 0 34 | }; 35 | } 36 | 37 | render() { 38 | return ( 39 | <div> 40 | <p>You clicked {this.state.count} times

41 | <button 42 | onClick={() => this.setState({ count: this.state.count + 1 })}> 43 | Click me 44 | 45 | 46 | ); 47 | } 48 | } 49 |
50 | 51 | The state starts as `{ count: 0 }`, and we increment state.count when the user clicks a button by calling `this.setState()`. We’ll use snippets from this class throughout the page. 52 | 53 | > ***Note*** 54 | > 55 | > You might be wondering why we’re using a counter here instead of a more realistic example. This is to help us focus on the API while we’re still making our first steps with Hooks. -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | My blog of tutorials 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/styles/App.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --background-body: #292929; 3 | --background-content: #1D1D1D; 4 | --text-color: #E5E5E5; 5 | --primary-color: #4DFF7C; 6 | --second-color: #89DDFF; 7 | } 8 | 9 | body { 10 | margin: 0; 11 | font-size: 1rem; 12 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 13 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 14 | sans-serif; 15 | -webkit-font-smoothing: antialiased; 16 | -moz-osx-font-smoothing: grayscale; 17 | background-color: var(--background-body); 18 | color: var(--text-color); 19 | } 20 | 21 | header.header { 22 | position: fixed; 23 | width: 100%; 24 | height: 3.5rem; 25 | top: 0px; 26 | left: 0px; 27 | background-color: var(--background-content); 28 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3); 29 | z-index: 10; 30 | } 31 | 32 | .header__content { 33 | max-width: 1280px; 34 | padding: 0 1rem; 35 | margin: auto; 36 | display: flex; 37 | justify-content: space-between; 38 | align-items: center; 39 | position: relative; 40 | height: 3.5rem; 41 | background-color: var(--background-content); 42 | } 43 | 44 | .logo { 45 | font-size: 20px; 46 | display: flex; 47 | gap: 0.5rem; 48 | align-items: center; 49 | color: var(--text-color); 50 | } 51 | 52 | main.main { 53 | width: 50%; 54 | margin: auto; 55 | margin-bottom: 3rem; 56 | margin-top: 4.5rem; 57 | background-color: var(--background-content); 58 | box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px, rgba(0, 0, 0, 0.08) 0px 0px 0px 1px; 59 | border-radius: 3px; 60 | } 61 | 62 | blockquote { 63 | background: rgba(77, 255, 124, 0.2); 64 | border-left: 10px solid var(--primary-color); 65 | margin: 1.5em 10px; 66 | padding: 1em 10px .1em 10px; 67 | quotes: "\201C""\201D""\2018""\2019"; 68 | } 69 | 70 | a { 71 | color: var(--primary-color); 72 | font-weight: 500; 73 | } 74 | 75 | code { 76 | color: var(--second-color); 77 | background-color: rgba(137, 221, 255, 0.3); 78 | } 79 | 80 | .dark-mode-icon { 81 | cursor: pointer; 82 | } 83 | 84 | @media screen and (max-width: 1024px) { 85 | main.main { 86 | width: 70%; 87 | } 88 | } 89 | 90 | @media screen and (max-width: 920px) { 91 | main.main { 92 | width: 80%; 93 | } 94 | } 95 | 96 | @media screen and (max-width: 520px) { 97 | main.main { 98 | width: 90%; 99 | } 100 | } -------------------------------------------------------------------------------- /src/assets/icons/index.js: -------------------------------------------------------------------------------- 1 | export const CopyIcon = () => ( 2 | 3 | 4 | 5 | ) 6 | 7 | export const PasteIcon = () => ( 8 | 9 | 10 | 11 | ) 12 | 13 | export const LogoIcon = () => ( 14 | 15 | 16 | 17 | ) 18 | 19 | export const SunIcon = () => ( 20 | 21 | 22 | 23 | ) 24 | 25 | export const MoonIcon = () => ( 26 | 27 | 28 | 29 | ) --------------------------------------------------------------------------------