I am trying to make a button that allows the user to switch between light and dark theme. The method I am using is to change the className of my App div. All of the other components in my project are inside of the App component. Then in the individual CSS files for the components I first select the className of the App div which is either .light or .dark. Then I write the name of the component that I want to set a theme color to. For example:
.light p {
background-color: white;
}
However, this doesn't work.
Here are some of the files:
/*App.js*/
import { useState } from "react";
import TaskPage from "./pages/taskPage";
import { fas } from "#fortawesome/free-solid-svg-icons";
import { library } from "#fortawesome/fontawesome-svg-core";
import { MainContextProvider } from "./store/MainContext";
library.add(fas);
function App() {
const [theme, setTheme] = useState("light");
const switchTheme = () => {
setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
};
return (
<MainContextProvider>
<div className={`App ${theme}`}>
<div className="pageTop">
<h1 className="title">Task Board</h1>
</div>
<button className="button" onClick={switchTheme}>
Change theme
</button>
<TaskPage />
</div>
</MainContextProvider>
);
}
export default App;
/*index.css*/
#import url("https://fonts.googleapis.com/css2?family=Roboto:wght#400;500;700&display=swap");
.App {
overflow-x: hidden;
padding-bottom: 40px;
height: 100%;
width: 100%;
}
.light {
background-color: #fcfcfc;
}
.dark {
background-color: #181A1B;
}
.title {
font-family: "Roboto", sans-serif;
font-size: 50px;
font-weight: 700;
text-align: center;
margin-top: 40px;
text-shadow: 0px 3px 4px rgba(0, 0, 0, 0.2);
}
.light .title {
color: black;
}
.dark .title {
color: white;
}
.pageTop {
margin-bottom: 50px;
}
/*todo.module.css*/
.taskCard {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
transition: 0.3s;
width: 340px;
height: 260px;
min-width: 340px;
min-height: 260px;
display: flex;
flex-wrap: wrap;
flex-direction: column;
border-radius: 12px;
padding: 14px;
box-sizing: border-box;
}
.light .taskCard {
background-color: white;
}
.dark .taskCard {
background-color: #2B2E30;
}
I used this sandbox as an example: https://codesandbox.io/s/stupefied-jackson-0ynz6?file=/src/App.js
I am a beginner with React.js
Related
I'm creating a React Notes App with the feature to switch between Dark/Light Mode.
So basically I've written a React Toggle to switch between Dark and Light Mode.
But apparently the code is only switching the background and h1 color and not switching the notes color as I want .
Apparently the component color doesn't seem to change.
Toggle.js toggles the classname between 'theme-dark' and 'theme-light' and in turn toggles the CSS too. But it doesn't seem to change the CSS of notes component.
Toggle.js:
import React, { useEffect, useState } from 'react';
import '../index.css';
import { setTheme } from '../theme';
import { MdDarkMode, MdOutlineDarkMode } from 'react-icons/md'
function Toggle() {
const [ togClass, setTogClass ] = useState('dark');
let theme = localStorage.getItem('theme');
const handleOnClick = () => {
if (localStorage.getItem('theme') === 'theme-dark') {
setTheme('theme-light');
setTogClass('light')
} else {
setTheme('theme-dark');
setTogClass('dark')
}
}
useEffect(() => {
if (localStorage.getItem('theme') === 'theme-dark') {
setTogClass('dark')
} else if (localStorage.getItem('theme') === 'theme-light') {
setTogClass('light')
}
}, [theme])
return (
<div className="container--toggle"> {
<button
id="toggle"
className={"toggle--button "+togClass}
onClick={handleOnClick}
>
{togClass === 'light' ? <MdOutlineDarkMode size='1.5rem' /> :
<MdDarkMode size='1.5rem'/>}
</button>
}
<label htmlFor="toggle" className="toggle--label">
<span className="toggle--label-background"></span>
</label>
</div>
)
}
export default Toggle
theme.js
function setTheme(themeName) {
localStorage.setItem('theme', themeName);
document.documentElement.className = themeName;
}
function keepTheme() {
if (localStorage.getItem('theme')) {
if (localStorage.getItem('theme') === 'theme-dark') {
setTheme('theme-dark');
} else if (localStorage.getItem('theme') === 'theme-light') {
setTheme('theme-light')
}
} else {
setTheme('theme-dark')
}
}
export {
setTheme,
keepTheme
}
I'm certain the React Toggle.js works fine. Do note that I'm a newbie in CSS Variables ( you can probably tell ) and I think that's where the code messes up.
index.css
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans',
'Droid Sans', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.theme-light {
--dark-text: black;
--light-text: #5E4B56;
--dark-background: #FFCFDF;
--light-background: #FFCFDF;
--accent: #DBE7E4;
--button-border: #5E4B56;
--note: #E0F9B5;
--note-new: #A5DEE5;
}
.theme-dark {
--dark-text: #EEEEEE;
--light-text: #F9F8F8;
--dark-background: #222831;
--light-background: #586F7C;
--accent: #B8DBD9;
--button-border: #B8DBD9;
--note: #EEEEEE;
--note-new: #00ADB5;
}
#root {
background-color: var(--dark-background);
color: var(--dark-text);
}
.toggle--button {
cursor: pointer;
}
.toggle--button.dark {
border: none;
--dark-background: #222831;
background-color: var(--dark-background);
}
.toggle--button.light {
border: none;
background-color: var(--dark-background);
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas,
'Courier New', monospace;
}
.header {
display: flex;
align-items: center;
justify-content: space-between;
}
.container {
max-width: 960px;
margin-right: auto;
margin-left: auto;
padding-right: 15px;
padding-left: 15px;
min-height: 100vh;
}
textarea {
color: var(--dark-text);
border: none;
resize: none;
background-color: var(--note-new);
}
textarea:focus {
outline: none;
}
.save {
size: 10rem;
background-color: #e1e1e1;
border: none;
border-radius: 15px;
padding: 5px 10px 5px 10px;
}
.save:hover {
background-color: #ededed;
cursor: pointer;
}
.note {
color: var(--dark-text);
background-color: var(--note);
border-radius: 10px;
padding: 1rem;
min-height: 170px;
display: flex;
flex-direction: column;
justify-content: space-between;
white-space: pre-wrap;
}
.note-footer {
display: flex;
align-items: center;
justify-content: space-between;
}
.notes-list {
display: grid;
grid-gap: 1rem;
grid-template-columns: repeat(
auto-fill,
minmax(250px, 1fr)
);
}
.note.new {
background-color: var(--note-new);
}
.delete-icon {
cursor: pointer;
}
.search {
display: flex;
align-items: center;
background-color: rgb(233, 233, 233);
border-radius: 10px;
padding: 5px;
margin-bottom: 1.5em;
}
.search input {
border: none;
background-color: rgb(233, 233, 233);
width: 100%;
}
.search-icons {
color: black;
}
.search input:focus {
outline: none;
}
Light Mode:
Dark Mode:
I want the dark mode to switch colors of notes from light mode ones.
This is how I want it to look:
Error on my side, my App.js file had classname set to theme-light which prevented overriding.
When I shrink the page vertically, the flex container become outside the flexbox.
All of my content is supposed to be in the grey area.
I tried to change the height property on css class .App and .App__main, but it doesn't works.
App.js
import "./styles.css";
import Content from "./Content";
export default function App() {
return (
<div className="App">
<div className="App__main">
<Content />
</div>
</div>
);
}
Content.js
import React from "react";
import List from "./List";
import "./styles.css";
export default function Content() {
return (
<>
<div className="layout__container">
<h1 className="layout__container__title">Media</h1>
<List />
</div>
</>
);
}
List.js
import "./styles.css";
import React, { useState } from "react";
export default function List() {
const [list, setList] = useState([
{ id: 1, fileName: "file 1" },
{ id: 2, fileName: "file 2" },
{ id: 3, fileName: "file 3" },
{ id: 4, fileName: "file 4" },
{ id: 5, fileName: "file 5" },
{ id: 6, fileName: "file 6" }
]);
return (
<div className="list">
{list.map((li) => {
return (
<figure title={li.fileName} key={li.id} className={"list__item"}>
<div className="list__item__file">
<div className="list__item__file__name">{li.fileName}</div>
</div>
</figure>
);
})}
</div>
);
}
styles.css
body {
margin: 0;
height: 100%;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.App {
text-align: center;
background-color: #f6f7f7;
border: 1px solid grey;
height: 100vh;
}
.App__main {
display: flex;
height: 100%;
}
/* it's used to save some area for navigation bar */
.App__spacing {
margin-top: 32px;
}
/* list */
.list {
margin-top: 1rem;
display: flex;
flex-direction: row;
justify-content: left;
flex-wrap: wrap;
flex-grow: 1;
}
.list .list__item {
position: relative;
width: 100px;
height: 100px;
margin-right: 1rem;
margin-bottom: 1rem;
background-color: white;
border: 1px solid white;
overflow: hidden;
flex: 0 0 auto;
}
.list .list__item img {
max-height: 100%;
max-width: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.list .list__item .list__item__file {
background-color: #c3c4c7;
display: flex;
flex-direction: column;
justify-content: center;
padding: 1rem;
overflow: hidden;
width: 100%;
height: 100%;
}
.list .list__item .list__item__file .list__item__file__name {
overflow: hidden;
font-size: 0.9rem;
}
.list .list__item .ist__item__file .list__item__file__type {
color: #8c8f94;
font-size: 0.625rem;
text-transform: uppercase;
margin: 0 auto;
}
CodeSandbox:
https://codesandbox.io/s/agitated-dew-rlnw3?file=/src/App.js
The App container with 100vh has a static height and doesn't grow to fit it's content.
.App {
text-align: center;
background-color: #f6f7f7;
border: 1px solid grey;
height: 100vh;
}
Use 100% of parent container instead.
.App {
text-align: center;
background-color: #f6f7f7;
border: 1px solid grey;
height: 100%;
}
I have this part of component:
<div id="container">
<span id="magnify">🔍</span>
<input id="search" />
<span id="user">👤</span>
<span
#click="dialog = true"
id="buttonMenuHamburger">Ⓜ️</span>
</div>
<transition name="fade">
<div
id="menuOverlay"
v-if="dialog"
>
<div
class="fondOverlay"
#click="dialog = false">
</div>
<ul class="contenuMenuOverlay">
<li>
<router-link to="/home">
➕ Home
</router-link>
</li>
</ul>
</div>
</transition>
<script>
import {
ref,
} from 'vue';
import { useRouter } from 'vue-router';
export default {
name: 'SearchBar',
setup() {
const router = useRouter();
const dialog = ref(false);
router.beforeEach((to, from, next) => {
dialog.value = false;
next();
});
return {
dialog,
};
},
};
</script>
<style scoped>
a {
color: black;
}
#menuOverlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
#menuOverlay .fondOverlay {
background-color: rgba(10, 10, 10, 0.5);
height: 100%;
width: 100%;
position: absolute;
z-index: 99;
}
#menuOverlay .contenuMenuOverlay {
padding: 20px;
margin: 20px;
border: 2px solid white;
text-align: left;
font-size: 2em;
font-variant: small-caps;
border: 2px solid white;
border-radius: 30px;
background-color: rgba(255, 255, 255, 0.5);
z-index: 100;
}
ul {
list-style-type: none;
font-family: "Champagne & Limousines";
font-variant: small-caps;
}
#container {
margin-bottom: 10px;
}
#container span {
padding-top: 7px;
cursor: pointer;
position: absolute;
}
#magnify {
padding-left: 5px;
min-width: 30px;
}
#user {
margin-left: -60px;
}
#buttonMenuHamburger {
margin-left: -30px;
}
#search {
background: transparent;
text-align: center;
color: white;
font-weight: bold;
font-size: 24px;
padding: 0 80px;
height: 30px;
width: 25%;
border: 2px solid white;
border-radius: 30px;
font-family: 'Caviar Dream';
transition: width 0.2s;
outline: none;
}
#search:focus {
width: 50%;
}
#search:before { content: 'Some'; }
</style>
When I click on the Ⓜ️, the dialog value changes correctly. But if I have the focus on the input, when I click on Ⓜ️ it just loses the focus on the input. I have to click again on the Ⓜ️ to get the dialog value set to true.
Is there something I'm missing?
Thanks in advance.
EDIT: it seems to come from the width change...
I might be misunderstanding your problem but I can't replicate the issue.
const { watchEffect, ref, onMounted, nextTick } = Vue;
Vue.createApp({
setup() {
const dialog = ref(false);
const input = ref(null);
// log when `dialog` is changed
watchEffect(() => console.log(dialog.value));
// focus on `input` from the beginning
onMounted(() => nextTick(() => input.value.focus()));
return { dialog, input };
},
}).mount('#app');
<script src="https://unpkg.com/vue#3.0.7/dist/vue.global.js"></script>
<div id="app">
<span id="magnify">🔍</span>
<input id="search" ref="input" />
<span id="user">👤</span>
<transition name="fade">
<span
#click="dialog = true"
id="buttonMenuHamburger">Ⓜ️</span>
</transition>
</div>
I'm trying to create overlapping avatars in HTML and CSS. It is based on this code snippet. Only that this snippet is created in SCSS and PUG. How can I convert PUG to HTML and SCSS to CSS? I have a problem that the avatars are distant from each other and the name does not appear when you hover over the avatar.
Check code here.
import React from 'react';
import { render } from 'react-dom';
import './style.css';
class App extends React.Component {
constructor() {
super();
this.state = {
todos:
[
{name:'Tobias', avatar: 'https://vignette.wikia.nocookie.net/arresteddevelopment/images/7/77/2x01_The_One_Where_Michael_Leaves_%28098%29.png/revision/latest?cb=20121126025806'},
{name:'Lindsey', avatar: 'https://vignette.wikia.nocookie.net/arresteddevelopment/images/1/16/Season_3_Character_Promos_-_Lindsay_Bluth_F%C3%BCnke_01.jpg/revision/latest?cb=20111027201233'},
{name:'Buster', avatar: 'https://vignette.wikia.nocookie.net/arresteddevelopment/images/b/be/Season_3_Character_Promos_-_Buster_Bluth_01.jpg/revision/latest?cb=20111027201440'},
{name:'George Michael', avatar: 'https://vignette.wikia.nocookie.net/arresteddevelopment/images/c/c3/Season_1_Character_Promos_-_George_Michael_Bluth_02.jpeg/revision/latest?cb=20120429230332'},
{name:'Gob', avatar: 'https://vignette.wikia.nocookie.net/arresteddevelopment/images/0/02/Season_1_Character_Promos_-_G.O.B.jpeg/revision/latest?cb=20120429230530'},
{name:'Michael', avatar: 'https://vignette.wikia.nocookie.net/arresteddevelopment/images/1/10/1x01_Pilot_%2839%29.png/revision/latest?cb=20120301050056'}
],
};
}
render() {
let todos = this.state.todos.map((todo, index) =>
<Todo
key={index}
index={index}
todo={todo}
/>
)
return (
<div>
<ul>{todos}</ul>
</div>
);
}
}
class Todo extends React.Component {
render() {
const Background = this.props.todo.avatar;
const name = this.props.todo.name;
const profile = {
"&:hover&:after": {
position: "absolute",
content: `attr(${name})`,
background: "rgba(255, 255, 255, .95)",
color: "inherit",
fontSize: "10px",
padding: "4px",
width: "auto",
bottom: "-0.5rem",
right: "-0.5rem",
boxShadow: "0px 5px 12px rgba(0, 0, 0, .12)",
opacity: "0",
borderRadius: "0.15rem",
animation: "fade 100ms ease 750ms forwards"
}
}
return (
<ul className="c-profile__list">
<li style={profile} className="c-profile" style={{backgroundImage: `url(${Background})`}}></li>
</ul>
);
}
}
render(<App />, document.getElementById('root'));
CSS
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
html, body {
width: 100%;
height: 100%;
}
body {
display: flex;
align-items: center;
justify-content: center;
font-family: system-ui;
flex-direction: column;
color: #2c2c54;
font-size: 1.6rem;
}
.c-profile {
width: 70px;
height: 70px;
border: 4px solid white;
border-radius: 50%;
box-shadow: 0px 3px 8px rgba(44, 44, 84, .2);
display: inline-block;
background: white;
cursor: pointer;
background-size: cover;
background-position: center center;
transition: all 200ms ease;
}
.c-profile:nth-of-type(n+2) {
margin-left: -42px;
}
.c-profile:hover {
transform: scale(1.2);
box-shadow: 0px 8px 20px rgba(44, 44, 84, .2);
}
.c-profile:hover:after {
position: absolute;
content: attr(username);
background: rgba(255, 255, 255, .95);
color: inherit;
font-size: 10px;
padding: 4px;
width: auto;
bottom: -0.5rem;
right: -0.5rem;
box-shadow: 0px 5px 12px rgba(0, 0, 0, .12);
opacity: 0;
border-radius: 0.15rem;
animation: fade 100ms ease 750ms forwards;
}
.c-profile__list {
display: flex;
position: relative;
width: auto;
padding-top: 1rem;
padding-bottom: 1rem;
}
.c-profile__list:hover .c-profile:nth-of-type(n+2) {
margin-left: 7px;
}
article {
width: 100%;
max-width: 600px;
}
#keyframes fade {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
ul {
list-style: none;
display: inline;
}
From a short look...
You are wrapping ul tags in a parent ul. Quick fix:
https://stackblitz.com/edit/react-ctuy4n?file=index.js
In your Todo, you need to remove the additional <ul> tag around each item and add your name as a title prop:
return (
<li style={profile} className="c-profile" title={name} style={{backgroundImage: `url(${Background})`}}></li>
);
I've just installed the react-calendar package using
npm install react-calendar
but I have no idea how to style it, or to give it some color. The instructions in react-calendar - npm do not provide any information about that. I was wondering if anyone that has used this package could help me here.
This is the code I have:
import React, {Component} from 'react'
import Calendar from 'react-calendar'
export default class EventModifier extends Component {
state = {
date: new Date(2018, 6, 1)
}
render(){
let calendar = <Calendar onChange={this.onChange} value={this.state.date} onClickDay={(value) => alert("day" + value + "clicked")}/>
return(
<div>
{calendar}
</div>
)
}
}
Go to node_modules / react-calender / dist / Calender.css, copy all the content in your own css or scss file and there you will have all the default styles and you can change only the ones you want.
To this date the file looks something like this:
.react-calendar {
width: 350px;
max-width: 100%;
background: white;
border: 1px solid #a0a096;
font-family: Arial, Helvetica, sans-serif;
line-height: 1.125em;
}
.react-calendar--doubleView {
width: 700px;
}
.react-calendar--doubleView .react-calendar__viewContainer {
display: flex;
margin: -0.5em;
}
.react-calendar--doubleView .react-calendar__viewContainer > * {
width: 50%;
margin: 0.5em;
}
.react-calendar,
.react-calendar *,
.react-calendar *:before,
.react-calendar *:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.react-calendar button {
margin: 0;
border: 0;
outline: none;
}
.react-calendar button:enabled:hover {
cursor: pointer;
}
.react-calendar__navigation {
height: 44px;
margin-bottom: 1em;
}
.react-calendar__navigation button {
min-width: 44px;
background: none;
}
.react-calendar__navigation button:enabled:hover,
.react-calendar__navigation button:enabled:focus {
background-color: #e6e6e6;
}
.react-calendar__navigation button[disabled] {
background-color: #f0f0f0;
}
.react-calendar__month-view__weekdays {
text-align: center;
text-transform: uppercase;
font-weight: bold;
font-size: 0.75em;
}
.react-calendar__month-view__weekdays__weekday {
padding: 0.5em;
}
.react-calendar__month-view__weekNumbers {
font-weight: bold;
}
.react-calendar__month-view__weekNumbers .react-calendar__tile {
display: flex;
align-items: center;
justify-content: center;
font-size: 0.75em;
padding: calc(0.75em / 0.75) calc(0.5em / 0.75);
}
.react-calendar__month-view__days__day--weekend {
color: #d10000;
}
.react-calendar__month-view__days__day--neighboringMonth {
color: #757575;
}
.react-calendar__year-view .react-calendar__tile,
.react-calendar__decade-view .react-calendar__tile,
.react-calendar__century-view .react-calendar__tile {
padding: 2em 0.5em;
}
.react-calendar__tile {
max-width: 100%;
text-align: center;
padding: 0.75em 0.5em;
background: none;
}
.react-calendar__tile:disabled {
background-color: #f0f0f0;
}
.react-calendar__tile:enabled:hover,
.react-calendar__tile:enabled:focus {
background-color: #e6e6e6;
}
.react-calendar__tile--now {
background: #ffff76;
}
.react-calendar__tile--now:enabled:hover,
.react-calendar__tile--now:enabled:focus {
background: #ffffa9;
}
.react-calendar__tile--hasActive {
background: #76baff;
}
.react-calendar__tile--hasActive:enabled:hover,
.react-calendar__tile--hasActive:enabled:focus {
background: #a9d4ff;
}
.react-calendar__tile--active {
background: #006edc;
color: white;
}
.react-calendar__tile--active:enabled:hover,
.react-calendar__tile--active:enabled:focus {
background: #1087ff;
}
.react-calendar--selectRange .react-calendar__tile--hover {
background-color: #e6e6e6;
}
Use className prop that will be added along with "react-calendar" to the main React-Calendar element. and it can be used to style the calendar as you want
<Calendar className={['c1','c2']}/>
import './Calender.scss';
<Calendar onChange={onChange} value={state.date} className="react-calendar" />
Calender.scss
.react-calendar {
width: 600px;
.react-calendar__navigation {
.react-calendar__navigation__arrow {
display: none;
}
.react-calendar__navigation__label {
font-size: 32px;
}
}
.react-calendar__tile {
height: 70px;
}
.react-calendar__month-view__weekdays__weekday {
font-size: 16px;
color: rgb(15, 70, 15);
}
.react-calendar__tile--active {
background: #e70220;
color: white;
}
.react-calendar__tile--active:enabled:hover,
.react-calendar__tile--active:enabled:focus {
background: #e70220;
}
.react-calendar__tile,
.react-calendar__month-view__days__day {
font-size: 18px;
}
}