├── src
├── components
│ ├── Container
│ │ ├── Container.css
│ │ └── Container.jsx
│ ├── HeaderTitle
│ │ ├── HeaderTitle.css
│ │ └── HeaderTitle.jsx
│ ├── ModeCTA
│ │ ├── ModeCTA.css
│ │ └── ModeCTA.jsx
│ └── Header
│ │ ├── Header.css
│ │ └── Header.jsx
├── index.js
├── App
│ ├── App.css
│ └── App.js
└── index.css
├── public
├── favicon.ico
├── logo192.png
├── logo512.png
├── robots.txt
├── manifest.json
└── index.html
├── readme_images
├── HeaderTitle.png
├── GlobalStyles.png
├── FolderStructure.png
└── HeaderTitleStyle.png
├── .gitignore
├── package.json
└── README.md
/src/components/Container/Container.css:
--------------------------------------------------------------------------------
1 | .Container {
2 | width: 375px;
3 | }
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pipe12/dark-mode-example/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pipe12/dark-mode-example/HEAD/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pipe12/dark-mode-example/HEAD/public/logo512.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/readme_images/HeaderTitle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pipe12/dark-mode-example/HEAD/readme_images/HeaderTitle.png
--------------------------------------------------------------------------------
/readme_images/GlobalStyles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pipe12/dark-mode-example/HEAD/readme_images/GlobalStyles.png
--------------------------------------------------------------------------------
/readme_images/FolderStructure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pipe12/dark-mode-example/HEAD/readme_images/FolderStructure.png
--------------------------------------------------------------------------------
/readme_images/HeaderTitleStyle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pipe12/dark-mode-example/HEAD/readme_images/HeaderTitleStyle.png
--------------------------------------------------------------------------------
/src/components/HeaderTitle/HeaderTitle.css:
--------------------------------------------------------------------------------
1 | .HeaderTitle {
2 | margin: 0;
3 | font-size: 14px;
4 | font-weight: 800;
5 | }
--------------------------------------------------------------------------------
/src/components/HeaderTitle/HeaderTitle.jsx:
--------------------------------------------------------------------------------
1 | import './HeaderTitle.css';
2 |
3 | const HeaderTitle = () =>
Dark Mode Example
4 |
5 | export default HeaderTitle;
--------------------------------------------------------------------------------
/src/components/Container/Container.jsx:
--------------------------------------------------------------------------------
1 | import './Container.css'
2 |
3 | const Container = ({ children }) => {
4 | return (
5 |
6 | { children }
7 |
8 | )
9 | }
10 |
11 | export default Container;
12 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App/App';
5 |
6 | ReactDOM.render(
7 |
8 |
9 | ,
10 | document.getElementById('root')
11 | );
12 |
--------------------------------------------------------------------------------
/src/App/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | border: 1px solid purple;
3 |
4 | height: 100vh;
5 | width: 100vw;
6 | box-sizing: border-box;
7 |
8 | display: grid;
9 | justify-content: center;
10 | align-content: center;
11 |
12 | background-color: var(--dark-mode-background);
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/ModeCTA/ModeCTA.css:
--------------------------------------------------------------------------------
1 | .ModeCTA {
2 | background-color: transparent;
3 | border: none;
4 | color: var(--dark-mode-text);
5 | font-size: 12px;
6 | display: flex;
7 | align-items: center;
8 | cursor: pointer;
9 | padding: 0;
10 | }
11 |
12 | .ModeCTA .MoonIcon {
13 | margin-right: 8px;
14 | }
--------------------------------------------------------------------------------
/src/components/ModeCTA/ModeCTA.jsx:
--------------------------------------------------------------------------------
1 | import { BsMoon } from 'react-icons/bs';
2 | import "./ModeCTA.css"
3 |
4 | const ModeCTA = () => {
5 | return (
6 |
10 | )
11 | }
12 |
13 | export default ModeCTA;
14 |
--------------------------------------------------------------------------------
/src/components/Header/Header.css:
--------------------------------------------------------------------------------
1 | .Header {
2 | background-color: var(--dark-mode-element);
3 | color: var(--dark-mode-text);
4 | height: 80px;
5 | display: flex;
6 | align-items: center;
7 | justify-content: space-between;
8 | padding: 0 24px;
9 | box-shadow: 0px 2px 10px 0px var(--dark-mode-shadow);
10 | }
11 |
--------------------------------------------------------------------------------
/src/App/App.js:
--------------------------------------------------------------------------------
1 | import Container from '../components/Container/Container';
2 | import Header from '../components/Header/Header';
3 | import './App.css';
4 |
5 | function App() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | export default App;
16 |
--------------------------------------------------------------------------------
/src/components/Header/Header.jsx:
--------------------------------------------------------------------------------
1 | import HeaderTitle from '../HeaderTitle/HeaderTitle';
2 | import ModeCTA from '../ModeCTA/ModeCTA';
3 | import './Header.css';
4 |
5 | const Header = ({ children }) => {
6 | return (
7 |
11 | )
12 | }
13 |
14 | export default Header;
15 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 | React App
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --dark-blue: hsl(209, 23%, 22%);
3 | --darker-blue: hsl(207, 26%, 17%);
4 | --darkest-blue: hsl(200, 15%, 8%);
5 | --thirty-darkest-blue: hsla(200, 15%, 8%, .3);
6 | --thirty-dark-gray: hsla(0, 0%, 52%, .3);
7 | --dark-gray: hsl(0, 0%, 52%);
8 | --very-light-gray: hsl(0, 0%, 98%);
9 |
10 | --dark-mode-background: var(--darker-blue);
11 | --dark-mode-element: var(--dark-blue);
12 | --dark-mode-text: white;
13 | --dark-mode-input: var(--dark-blue);
14 | --dark-mode-shadow: var(--thirty-darkest-blue);
15 |
16 | --light-mode-background: var(--very-light-gray);
17 | --light-mode-element: white;
18 | --light-mode-text: var(--darkest-blue);
19 | --light-mode-input: var(--dark-gray);
20 | --light-mode-shadow: var(--thirty-dark-gray);
21 | }
22 |
23 | body {
24 | margin: 0;
25 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
26 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
27 | sans-serif;
28 | }
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dark-mode-example",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.11.4",
7 | "@testing-library/react": "^11.1.0",
8 | "@testing-library/user-event": "^12.1.10",
9 | "react": "^17.0.2",
10 | "react-dom": "^17.0.2",
11 | "react-icons": "^4.2.0",
12 | "react-scripts": "4.0.3",
13 | "web-vitals": "^1.0.1"
14 | },
15 | "scripts": {
16 | "start": "react-scripts start",
17 | "build": "react-scripts build",
18 | "test": "react-scripts test",
19 | "eject": "react-scripts eject"
20 | },
21 | "eslintConfig": {
22 | "extends": [
23 | "react-app",
24 | "react-app/jest"
25 | ]
26 | },
27 | "browserslist": {
28 | "production": [
29 | ">0.2%",
30 | "not dead",
31 | "not op_mini all"
32 | ],
33 | "development": [
34 | "last 1 chrome version",
35 | "last 1 firefox version",
36 | "last 1 safari version"
37 | ]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dark mode usando Styled-components
2 |
3 | ## Table of contents
4 |
5 | - [Objetivo general](#objetivo-general)
6 | - [Introducción a Styled-components](#introducción-a-styled-components)
7 | - [Ventajas de usar Styled-components](ventajas-de-usar-styled-components)
8 | - [Desventajas de usar Styled-components](#desventajas-de-usar-styled-components)
9 | - [Instalación y algunos ejemplos](#instalación-y-algunos-ejemplos)
10 | - [Instalación](#instalación)
11 | - [Crear un componente](#crear-un-componente)
12 | - [Crear estilos globales](#crear-estilos-globales)
13 | - [Proveer los themes a toda la App](#proveer-los-themes-a-toda-la-App)
14 | - [Como usar este repositorio](#como-usar-este-repositorio)
15 |
16 | ## Objetivo general
17 |
18 | Implementar la funcionalidad de Dark Mode usando Styled-components en React.
19 |
20 | ## Introducción a Styled-components
21 |
22 | Styled-components es la repuesta a la búsqueda de como podemos ensanchar CSS para darle estilos a el sistema de componentes de React.
23 |
24 | ### Ventajas de usar Styled-components
25 |
26 | * Automatic critical CSS: Styled-components mantiene un rastreo de cuales componentes son renderezados en la pagina y le inyecta sus estilos y nada mas de manera autmatica.
27 |
28 | * No mas Bugs por nombres de class: Styled-components genera nombres de clase únicos para los estilos. Nunca mas te preocuparas por duplicación, superposición o errores de escritura.
29 |
30 | * Facil de remover del CSS: es difícil saber donde se uso un nombre de clase fue usado dentro del código. Styled-components makes esto obvio, como cada pedazo de CSS es atado a un componente especifico.
31 |
32 | * Simple dynamic styling: Adaptar los estilos del componente basado en las props o el thema global es simple e intuitivo sin la necesidad de manejar muchas clases.
33 |
34 | * Mantenimiento menos doloroso: No tendrás que buscar a través que line a código esta afectando el component.
35 |
36 | * Automatic vendor prefixing: Escribe tu CSS normal y permite que Styled-components haga el resto.
37 |
38 | Tienes todos estos beneficios mientras escribes CSS de toda la vida, solo separado en piezas individuales.
39 |
40 | ### Desventajas de usar Styled-components
41 |
42 | En mi concepto. Si tienes muchos componentes similares como muchos componentes botón cuando estas en el navegador buscando cual es. Los hash generados en las clases no generan ninguna información extra para saber cual es el componente especifico.
43 |
44 | ## Instalación y algunos ejemplos
45 |
46 | ### Instalación
47 |
48 | Instalar styled-components solo toma una linea de código :
49 |
50 | ```bash
51 | # with npm
52 | npm install --save styled-components
53 |
54 | # with yarn
55 | yarn add styled-components
56 | ```
57 |
58 | ### Crear un componente
59 |
60 | Estructura de carpetas
61 |
62 | 
63 |
64 | Crear estilos StyledHeaderTitle.js
65 |
66 | ```javaScript
67 | import styled from 'styled-components';
68 |
69 | const StyledHeaderTitle = styled.h2`
70 | margin: 0;
71 | font-size: 14px;
72 | font-weight: 800;
73 | `
74 | export default StyledHeaderTitle;
75 | ```
76 |
77 | Crear el componente de React HeaderTitle.jsx
78 |
79 | ```javaScript
80 | import StyledHeaderTitle from './StyledHeaderTitle';
81 |
82 | const HeaderTitle = () => {
83 | return (
84 |
85 | Dark Mode Example
86 |
87 | )
88 | }
89 |
90 | export default HeaderTitle;
91 | ```
92 | Como se ve en el navegador
93 |
94 | 
95 |
96 | 
97 |
98 | ### Crear estilos globales
99 |
100 | Crear los estilos globales en GlobalStyles.js
101 |
102 | ```javaScript
103 | import { createGlobalStyle } from "styled-components";
104 |
105 | const GlobalStyles = createGlobalStyle`
106 | :root {
107 | --dark-blue: hsl(209, 23%, 22%);
108 | --darker-blue: hsl(207, 26%, 17%);
109 | --darkest-blue: hsl(200, 15%, 8%);
110 | --thirty-darkest-blue: hsla(200, 15%, 8%, .3);
111 | --thirty-dark-gray: hsla(0, 0%, 52%, .3);
112 | --dark-gray: hsl(0, 0%, 52%);
113 | --very-light-gray: hsl(0, 0%, 98%);
114 |
115 | --dark-mode-background: var(--darker-blue);
116 | --dark-mode-element: var(--dark-blue);
117 | --dark-mode-text: white;
118 | --dark-mode-input: var(--dark-blue);
119 | --dark-mode-shadow: var(--thirty-darkest-blue);
120 |
121 | --light-mode-background: var(--very-light-gray);
122 | --light-mode-element: white;
123 | --light-mode-text: var(--darkest-blue);
124 | --light-mode-input: var(--dark-gray);
125 | --light-mode-shadow: var(--thirty-dark-gray);
126 | }
127 |
128 | body {
129 | margin: 0;
130 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
131 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
132 | sans-serif;
133 | }
134 | `
135 |
136 | export default GlobalStyles;
137 | ```
138 |
139 | Como se ve en el navegador.
140 |
141 | 
142 |
143 | ### Proveer los themes a toda la App
144 |
145 | Crear los themes en la App ./src/utils/themes.js
146 |
147 | ```javaScript
148 | export const lightTheme = {
149 | backgroundBody: '--light-mode-background',
150 | text: '--light-mode-text',
151 | backgroundElement: '--light-mode-element',
152 | input: '--light-mode-input',
153 | shadow: '--light-mode-shadow'
154 | }
155 |
156 | export const darkTheme = {
157 | backgroundBody: '--dark-mode-background',
158 | text: '--dark-mode-text',
159 | backgroundElement: '--dark-mode-element',
160 | input: '--dark-mode-input',
161 | shadow: '--dark-mode-shadow'
162 | }
163 | ```
164 | Proveer themes a la App
165 |
166 | ```javaScript
167 | import { useState } from 'react';
168 | import StyledApp from './StyledApp';
169 | import Container from '../components/Container/Container';
170 | import Header from '../components/Header/Header';
171 | import { ThemeProvider } from 'styled-components';
172 | import { darkTheme, lightTheme } from '../utils/themes';
173 |
174 | function App() {
175 |
176 | const [theme, setTheme] = useState('dark');
177 |
178 | const toggleTheme = () => {
179 | if (theme === 'dark') {
180 | setTheme('light');
181 | } else {
182 | setTheme('dark');
183 | }
184 | }
185 |
186 | return (
187 |
188 |
189 |
190 |
192 |
193 |
194 | );
195 | }
196 |
197 | export default App;
198 | ```
199 | Aplicandolo en el componente
200 |
201 | ```javaScript
202 | .App {
203 | border: 1px solid purple;
204 |
205 | height: 100vh;
206 | width: 100vw;
207 | box-sizing: border-box;
208 |
209 | display: grid;
210 | justify-content: center;
211 | align-content: center;
212 |
213 | background-color: var(--dark-mode-background);
214 | }
215 | ```
216 |
217 | ## Como usar este repositorio
218 |
219 | Este repo tiene 6 ramas y en cada se realiza un paso para lograr implementar la funcionalidad de Dark Mode.
220 |
221 | * master
222 | * 01-install-styled-components
223 | * 02-convert-all-components-to-styled-components
224 | * 03-create-global-styles
225 | * 04-create-and-provide-themes
226 | * 05-apply-themes-to-components
227 | * 06-manage-mode-with-button
228 |
229 | Master es la rama inicial y puedes pasar de rama a rama y ver cada paso en la implementación. en la rama 06-manage-mode-with-button puedes ver la implementación terminada.
230 |
--------------------------------------------------------------------------------