├── .gitignore
├── README.md
├── components
├── index.js
└── render
│ ├── Button.js
│ ├── Div.js
│ ├── Li.js
│ ├── P.js
│ ├── VerticalDots.js
│ ├── index.js
│ └── renderComponent.js
├── config.js
├── package-lock.json
├── package.json
├── pages
├── _app.js
└── index.js
├── postcss.config.js
├── public
├── favicon.ico
└── vercel.svg
└── tailwind.config.js
/.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 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env.local
29 | .env.development.local
30 | .env.test.local
31 | .env.production.local
32 |
33 | # vercel
34 | .vercel
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Create React Components from JSON
2 |
3 | This repo is from a complete step-by-step tutorial by [Skillthrive](https://youtu.be/NMxMWOZC-Ec).
4 |
--------------------------------------------------------------------------------
/components/index.js:
--------------------------------------------------------------------------------
1 | export * from './render';
2 |
--------------------------------------------------------------------------------
/components/render/Button.js:
--------------------------------------------------------------------------------
1 | export const Button = ({ className, style, id, children }) => {
2 | return (
3 |
6 | );
7 | };
8 |
--------------------------------------------------------------------------------
/components/render/Div.js:
--------------------------------------------------------------------------------
1 | export const Div = ({ className, style, id, children }) => {
2 | return (
3 |
4 | {children}
5 |
6 | );
7 | };
8 |
--------------------------------------------------------------------------------
/components/render/Li.js:
--------------------------------------------------------------------------------
1 | export const Li = ({ className, style, id, children }) => {
2 | return (
3 |
4 | {children}
5 |
6 | );
7 | };
8 |
--------------------------------------------------------------------------------
/components/render/P.js:
--------------------------------------------------------------------------------
1 | export const P = ({ className, style, id, children }) => {
2 | return (
3 |
4 | {children}
5 |
6 | );
7 | };
8 |
--------------------------------------------------------------------------------
/components/render/VerticalDots.js:
--------------------------------------------------------------------------------
1 | import { BiDotsVerticalRounded } from 'react-icons/bi';
2 |
3 | export const VerticalDots = ({ className, style, id }) => {
4 | return ;
5 | };
6 |
--------------------------------------------------------------------------------
/components/render/index.js:
--------------------------------------------------------------------------------
1 | export * from './renderComponent';
2 |
--------------------------------------------------------------------------------
/components/render/renderComponent.js:
--------------------------------------------------------------------------------
1 | import { createElement } from 'react';
2 | import { Div } from './Div';
3 | import { Li } from './Li';
4 | import { P } from './P';
5 | import { Button } from './Button';
6 | import { VerticalDots } from './VerticalDots';
7 |
8 | const keysToComponentMap = {
9 | div: Div,
10 | li: Li,
11 | p: P,
12 | button: Button,
13 | verticalDots: VerticalDots,
14 | };
15 |
16 | const stylesMap = (styles) => {
17 | let mappedStyles = {};
18 | styles.forEach((style) => {
19 | mappedStyles[style.name] = style.value;
20 | });
21 | return mappedStyles;
22 | };
23 |
24 | export const renderComponent = (config) => {
25 | if (typeof keysToComponentMap[config.component] !== 'undefined') {
26 | return createElement(
27 | keysToComponentMap[config.component],
28 | {
29 | id: config.id,
30 | key: config.id,
31 | className: config.className ? config.className : null,
32 | ariaHidden: config.ariaHidden ? config.ariaHidden : null,
33 | style: config.styles ? stylesMap(config.styles) : null,
34 | },
35 | config.children &&
36 | (typeof config.children === 'string'
37 | ? config.children
38 | : config.children.map((c) => renderComponent(c)))
39 | );
40 | }
41 | };
42 |
--------------------------------------------------------------------------------
/config.js:
--------------------------------------------------------------------------------
1 | export const config = {
2 | component: 'li',
3 | id: 'cardWrapper',
4 | className: 'col-span-1 flex shadow-sm rounded-md',
5 | children: [
6 | {
7 | component: 'div',
8 | id: 'initialWrapper',
9 | className:
10 | 'flex-shrink-0 flex items-center justify-center w-16 text-white text-sm font-medium rounded-l-md',
11 | styles: [
12 | {
13 | name: 'backgroundColor',
14 | value: '#6366F1',
15 | },
16 | ],
17 | children: 'HB',
18 | },
19 | {
20 | component: 'div',
21 | id: 'infoWrapper',
22 | className:
23 | 'flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-md truncate',
24 | children: [
25 | {
26 | component: 'div',
27 | id: 'info',
28 | className: 'flex-1 px-4 py-2 text-sm truncate',
29 | children: [
30 | {
31 | component: 'p',
32 | id: 'title',
33 | className: 'text-gray-900 font-medium hover:text-gray-600',
34 | children: 'GraphQL',
35 | },
36 | {
37 | component: 'p',
38 | id: 'readTime',
39 | className: 'text-gray-500',
40 | children: '10 min read',
41 | },
42 | ],
43 | },
44 | {
45 | component: 'div',
46 | id: 'buttonWrapper',
47 | className: 'flex-shrink-0 pr-2',
48 | children: [
49 | {
50 | component: 'button',
51 | id: 'optionButton',
52 | className:
53 | 'w-8 h-8 bg-white inline-flex items-center justify-center text-gray-400 rounded-full bg-transparent hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500',
54 | children: [
55 | {
56 | component: 'span',
57 | id: 'optionButtonSr',
58 | className: 'sr-only',
59 | children: 'Open Options',
60 | },
61 | {
62 | component: 'verticalDots',
63 | id: 'verticalDots',
64 | className: 'w-5 h-5',
65 | ariaHidden: 'true',
66 | },
67 | ],
68 | },
69 | ],
70 | },
71 | ],
72 | },
73 | ],
74 | };
75 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "with-tailwindcss",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start"
9 | },
10 | "dependencies": {
11 | "next": "latest",
12 | "react": "^17.0.2",
13 | "react-dom": "^17.0.2",
14 | "react-icons": "^4.2.0"
15 | },
16 | "devDependencies": {
17 | "autoprefixer": "^10.2.6",
18 | "postcss": "^8.3.5",
19 | "tailwindcss": "^2.2.2"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 | import 'tailwindcss/tailwind.css'
2 |
3 | function MyApp({ Component, pageProps }) {
4 | return
5 | }
6 |
7 | export default MyApp
8 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import { BiDotsVerticalRounded } from 'react-icons/bi';
2 |
3 | import { config } from '../config';
4 | import { renderComponent } from '../components';
5 |
6 | export default function Home() {
7 | const project = {
8 | name: 'Graph API',
9 | initials: 'GA',
10 | href: '#',
11 | members: 16,
12 | bgColor: 'bg-pink-600',
13 | };
14 |
15 | const classNames = (...classes) => {
16 | return classes.filter(Boolean).join(' ');
17 | };
18 |
19 | return (
20 |
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | // If you want to use other PostCSS plugins, see the following:
2 | // https://tailwindcss.com/docs/using-with-preprocessors
3 | module.exports = {
4 | plugins: {
5 | tailwindcss: {},
6 | autoprefixer: {},
7 | },
8 | }
9 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hunterbecton/react-from-json/27f218dd4805e1e80166c0f902de052ee4d13285/public/favicon.ico
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | mode: 'jit',
3 | purge: {
4 | content: [
5 | './pages/**/*.{js,ts,jsx,tsx}',
6 | './components/**/*.{js,ts,jsx,tsx}',
7 | ],
8 | safelist: [
9 | 'col-span-1',
10 | 'flex',
11 | 'shadow-sm',
12 | 'rounded-md',
13 | 'flex-shrink-0',
14 | 'items-center',
15 | 'justify-center',
16 | 'w-16',
17 | 'text-white',
18 | 'text-sm',
19 | 'font-medium',
20 | 'rounded-l-md',
21 | 'flex-1',
22 | 'px-4',
23 | 'py-2',
24 | 'pr-2',
25 | 'w-8',
26 | 'h-8',
27 | 'inline-flex',
28 | 'text-gray-400',
29 | 'rounded-full',
30 | 'bg-transparent',
31 | 'hover:text-gray-500',
32 | 'focus:outline-none',
33 | 'focus:ring-2',
34 | 'focus:ring-offset-2',
35 | 'focus:ring-indigo-500',
36 | ],
37 | },
38 | darkMode: false, // or 'media' or 'class'
39 | theme: {
40 | extend: {},
41 | },
42 | variants: {
43 | extend: {},
44 | },
45 | plugins: [],
46 | };
47 |
--------------------------------------------------------------------------------