├── .gitignore
├── README.md
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── src
├── App.js
├── components
│ ├── Code.js
│ ├── Header.js
│ ├── Post.js
│ └── assets
│ │ └── icons.js
├── index.css
├── index.js
├── markdown-ss.png
└── markdown
│ └── article.md
└── yarn.lock
/.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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | 
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `yarn install`
10 |
11 | Instal All dependencies in this project
12 |
13 | ### `yarn dev`
14 |
15 | Runs the app in the development mode.
16 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
17 |
18 | ### Link
19 |
20 | - React Syntax Highlighter: https://www.npmjs.com/package/react-syntax-highlighter
21 | - React Copy To Clipboard: https://github.com/nkbt/react-copy-to-clipboard
22 | - Markdown To Jsx: https://www.npmjs.com/package/markdown-to-jsx
23 | - Heroicons: https://heroicons.com/
24 | - article markdown: https://gist.github.com/candraKriswinarto/38e52a600edf73f3b5626acc5c07403e
25 |
26 | ### Video Tutorial
27 |
28 | You can see my youtube video for this project in [here](https://youtu.be/Od-Uj5RSsuM)
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "markdown-blog",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.14.1",
7 | "@testing-library/react": "^13.0.0",
8 | "@testing-library/user-event": "^13.2.1",
9 | "markdown-to-jsx": "^7.1.7",
10 | "react": "^18.2.0",
11 | "react-copy-to-clipboard": "^5.1.0",
12 | "react-dom": "^18.2.0",
13 | "react-scripts": "5.0.1",
14 | "react-syntax-highlighter": "^15.5.0",
15 | "web-vitals": "^2.1.0"
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 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candraKriswinarto/react-markdown-blog/b257ceaade87f826df9d1bc71a91f06e8fafb579/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 | JS Snipets
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candraKriswinarto/react-markdown-blog/b257ceaade87f826df9d1bc71a91f06e8fafb579/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candraKriswinarto/react-markdown-blog/b257ceaade87f826df9d1bc71a91f06e8fafb579/public/logo512.png
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import { createContext, useState } from "react";
2 | import Header from "./components/Header";
3 | import Post from "./components/Post";
4 |
5 | // Create Context
6 | export const ThemeContext = createContext();
7 |
8 | function App() {
9 | const [isDark, setIsDark] = useState(true);
10 |
11 | const value = {
12 | isDark, setIsDark
13 | }
14 |
15 | return (
16 |
17 |
18 |
19 |
20 | );
21 | }
22 |
23 | export default App;
24 |
--------------------------------------------------------------------------------
/src/components/Code.js:
--------------------------------------------------------------------------------
1 | import { useContext, useEffect, useState } from 'react';
2 | import CopyToClipboard from 'react-copy-to-clipboard';
3 | import { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';
4 | import { materialDark, materialLight } from 'react-syntax-highlighter/dist/esm/styles/prism';
5 | import { ThemeContext } from '../App';
6 | import { CopyIcon, PasteIcon } from './assets/icons';
7 |
8 | const Code = ({ children, language }) => {
9 | const [copied, setCopied] = useState(false);
10 | const { isDark } = useContext(ThemeContext);
11 |
12 | useEffect(() => {
13 | const timer = setTimeout(() => {
14 | setCopied(false)
15 | }, 1000)
16 | return () => clearTimeout(timer)
17 | }, [copied])
18 |
19 | return (
20 |
21 |
setCopied(true)}>
22 |
25 |
26 |
30 | {children}
31 |
32 |
33 | )
34 | }
35 |
36 | export default Code
--------------------------------------------------------------------------------
/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import { useContext } from "react";
2 | import { ThemeContext } from "../App";
3 | import { LogoIcon, MoonIcon, SunIcon } from "./assets/icons";
4 |
5 | const Header = () => {
6 | const { isDark, setIsDark } = useContext(ThemeContext);
7 |
8 | return (
9 |
10 |
11 |
12 |
13 |
14 | JS Snipets
15 |
16 |
17 |
18 |
19 |
20 | );
21 | };
22 |
23 | export default Header;
24 |
--------------------------------------------------------------------------------
/src/components/Post.js:
--------------------------------------------------------------------------------
1 | import Markdown from "markdown-to-jsx"
2 | import { useEffect, useState } from "react"
3 | import Code from "./Code";
4 |
5 | const Post = () => {
6 | const [postContent, setPostContent] = useState("");
7 |
8 | useEffect(() => {
9 | import("../markdown/article.md")
10 | .then(res => {
11 | fetch(res.default)
12 | .then(response => response.text())
13 | .then(response => setPostContent(response))
14 | .catch(err => console.log(err))
15 | })
16 | }, []);
17 |
18 | return (
19 |
20 |
21 |
22 |
29 | {postContent}
30 |
31 |
32 |
33 |
34 | )
35 | }
36 |
37 | export default Post
--------------------------------------------------------------------------------
/src/components/assets/icons.js:
--------------------------------------------------------------------------------
1 | export const LogoIcon = () => (
2 |
5 | )
6 |
7 | export const MoonIcon = () => (
8 |
11 | )
12 |
13 | export const CopyIcon = () => (
14 |
18 | )
19 |
20 | export const PasteIcon = () => (
21 |
25 | )
26 |
27 | export const SunIcon = () => (
28 |
31 | )
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
2 | :root {
3 | --background-body: #292929;
4 | --background-content: #1d1d1d;
5 | --text-color: #e5e5e5;
6 | }
7 |
8 | body {
9 | margin: 0;
10 | font-size: 1rem;
11 | font-family: 'Roboto', sans-serif;
12 | background: var(--background-body);
13 | color: var(--text-color);
14 | }
15 |
16 | /* Global */
17 | svg {
18 | width: 1.5rem;
19 | }
20 | button.icon {
21 | background: none;
22 | outline: none;
23 | border: none;
24 | cursor: pointer;
25 | }
26 | .container {
27 | max-width: 50rem;
28 | margin: 0 auto;
29 | padding: 0 0.5rem 0 0.5rem;
30 | display: flex;
31 | align-items: center;
32 | height: 100%;
33 | }
34 |
35 | /* header */
36 | header.header {
37 | position: fixed;
38 | top: 0;
39 | left: 0;
40 | width: 100%;
41 | height: 4.5rem;
42 | background: var(--background-content);
43 | box-shadow: 0 1px 1px rgba(0,0,0, 0.3);
44 | z-index: 10;
45 | }
46 | header .logo-wrapper {
47 | display: flex;
48 | align-items: center;
49 | justify-content: space-between;
50 | width: 100%;
51 | }
52 | header .logo {
53 | display: flex;
54 | align-items: center;
55 | cursor: default;
56 | }
57 | header .logo span {
58 | margin-left: 0.5rem;
59 | }
60 |
61 | /* Post */
62 | .article {
63 | margin: 4rem 0;
64 | }
65 | .post-wrapper {
66 | width: 100%;
67 | }
68 |
69 | /* Code */
70 | .code {
71 | position: relative;
72 | }
73 | .code .copy-icon {
74 | position: absolute;
75 | top: 1rem;
76 | right: 1rem;
77 | z-index: 5;
78 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 |
6 | const root = ReactDOM.createRoot(document.getElementById('root'));
7 | root.render(
8 |
9 |
10 |
11 | );
12 |
13 |
--------------------------------------------------------------------------------
/src/markdown-ss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candraKriswinarto/react-markdown-blog/b257ceaade87f826df9d1bc71a91f06e8fafb579/src/markdown-ss.png
--------------------------------------------------------------------------------
/src/markdown/article.md:
--------------------------------------------------------------------------------
1 | # Useful JavaScript Code Snippets
2 |
3 | 1. Sort an Array
4 |
5 |
6 | //strings
7 | const names = ["Seema", "Rekha", "Jaya"];
8 | names.sort();
9 | //['Jaya', 'Rekha', 'Seema' ]
10 |
11 | //Numbers
12 | const numbers = [101, 8, 87];
13 | numbers.sort((a, b) => {
14 | return a - b;
15 | });
16 | //[ 8, 87, 101 ]
17 |
18 |
19 | 2. Select a random element
20 |
21 |
22 | const items = ["Ball", "Bat", "Cup"]
23 | const randomIndex = Math.floor(Math.random()*items.length)
24 | items[randomIndex]
25 |
26 |
27 | 3. Reverse a string
28 |
29 |
30 | function reverseString(string) {
31 | return string.split(" ").reverse().join(" ")
32 | }
33 |
34 | revereseString("Random String")
35 |
36 |
37 | 4. Check if element has a class
38 |
39 |
40 | const element = document.querySelector("#element")
41 | element.classList.contains("active")
42 |
43 |
44 | 5. String interpolation
45 |
46 |
47 | const name = "Jaya"
48 | console.log(`Hi, ${name}. You have ${2 ** 3} new notifications.`}
49 | //Hi, Jaya. You have 8 new notifications.
50 |
51 |
52 | 6. Loop through an array
53 |
54 |
55 | const cars = ["Ford", "BMW", "Audi" ]
56 | for (let car of cars) {
57 | console.log(car)
58 | }
59 |
60 | /*
61 | Ford
62 | BMW
63 | Audi
64 | */
65 |
66 |
67 | 7. Get current time
68 |
69 |
70 | const date = new Date()
71 | const currentTime =
72 | `${date.getHours()}:${date.getMintues()}:${date.getSeconds()}`
73 |
74 | console.log(currentTimes)
75 | //example output: "22:16:41"
76 |
77 |
78 | 8. Replace part of a string
79 |
80 |
81 | const string = "You are awesome."
82 | const replacedString = string.replace("You", "We")
83 |
84 | console.log(replacedString) //Output: "We are awesome"
85 |
86 |
87 | 9. Destructing variable assignment
88 |
89 |
90 | let profile = ['bob', 34, 'carpenter'];
91 | let [name, age, job] = profile;
92 | console.log(name);
93 | // bob
94 |
95 |
96 | 10. Using the spread operator
97 |
98 |
99 | let data = [1,2,3,4,5];
100 | console.log(...data);
101 | // 1 2 3 4 5
102 | let data2 = [6,7,8,9,10];
103 | let combined = [...data, ...data2];
104 | console.log(...combined);
105 | // 1 2 3 4 5 6 7 8 9 10
106 | console.log(Math.max(...combined));
107 | // 10
108 |
--------------------------------------------------------------------------------