├── 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 | 
30 | 
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 |

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 |
5 | )
6 |
7 | export const PasteIcon = () => (
8 |
11 | )
12 |
13 | export const LogoIcon = () => (
14 |
17 | )
18 |
19 | export const SunIcon = () => (
20 |
23 | )
24 |
25 | export const MoonIcon = () => (
26 |
29 | )
--------------------------------------------------------------------------------