Context:
I'm working through the Odin Project and trying to make an etch-a-sketch board.
The project asks for you to make a board that you can draw on when your mouse hovers over, but it has to be made out of a grid of small divs that you add to the DOM from your javascript.
Problem:
When the divs get generated to make the grid, they appear with a width of x (user generated) but a height of 0. So you can't hover over them. I expect to see a large blue square but instead it is blank unless I go out of my way to add in a height value in the css. The divs are created in the for-loop of line 14 of the javascript file here: https://jsfiddle.net/krmanski/ry12xumq/9/
function generateCanvas(gridSize){
//create the gridlines
//divide canvas into A x A where A = the number provided by user
let canvas = document.querySelector(".main-grid-container");
canvas.style.gridTemplateColumns = `repeat(${gridSize}, 1fr)`;
canvas.style.gridTemplateRows = `repeat(${gridSize}, 1fr)`;
alert("canvas should be generated");
let divsTotal = (gridSize * gridSize);
for(let i = 0; i < divsTotal; i++){
let div = document.createElement("div");
div.classList.add("grid-item");
div.style.backgroundColor="blue";
//this will allow our divs to change color when hovered over
div.addEventListener("mouseover", function(){
div.style.backgroundColor="black";
})
canvas.appendChild(div);
}
}
I have looked at other people's solutions on github and youtube and nearly all of them use the exact same code I do in my for-loop, and they apply no CSS at any point to tell their divs to have height. I am thinking of starting from a blank slate because I just can't figure out the problem but at this point I'm just idly curious what is the problem and why my divs are appearing with 0 height.
Setting align-items: center on .main-grid-container is what prevents your divs from being stretched vertically. I recommend simply removing that declaration, the initial value normal will achieve the desired effect.
Is this the sort of effect that you were after? The following uses css variables to determine width/height of the individual grid squares based upon simple arithmetic of the canvas with divided by the number of grid-items. The CSS variables are updated within the generateCanvas function and this can be extended to control the various colours presumably set by the buttons.
let active=true;
//wait until the HTML and CSS are loaded before you run the javascript
document.addEventListener("DOMContentLoaded", function() {
generateCanvas();
document.addEventListener('contextmenu',e=>{
e.preventDefault();
if( e.target.parentNode==document.querySelector(".main-grid-container") ){
active=false;
}
})
document.addEventListener('blur',()=>active=true);
document.addEventListener('click',()=>active=true);
});
function generateCanvas(size=16) {
// Find the doc root to access variables
let root = document.documentElement;
let canvas = document.querySelector(".main-grid-container");
canvas.style.gridTemplateColumns = `repeat(${size}, 1fr)`;
canvas.style.gridTemplateRows = `repeat(${size}, 1fr)`;
// important to clear the grid otherwise it will grow
// on each invocation of this function!
canvas.innerHTML = '';
// calculate the size of the containg canvas
let box = canvas.getBoundingClientRect();
let w = box.width / size;
let h = box.height / size;
// update the variables with new sizes
root.style.setProperty('--w', `${w}px`);
root.style.setProperty('--h', `${h}px`);
for( let i=0; i < Math.pow(size, 2); i++ ) {
let div = document.createElement("div");
div.classList.add("grid-item");
canvas.appendChild(div);
}
// Rather than assign the same event listener to every grid square, use a `delegated`
// event listener bound to the canvas.
canvas.addEventListener('mouseover',e=>{
let cn='grid-paint';
if( active && e.target.classList.contains('grid-item') && !e.target.classList.contains( cn ) )e.target.classList.add( cn )
})
}
function selectSize() {
//has the user type a number and returns that number, but only if it is between 0 and 100
let userInput = prompt("What should be the size of the board?")
let message = document.querySelector("#message")
if (isNaN( userInput ) ) {
message.innerText = "Please provide a number only";
} else if( Number(userInput) < 0 || Number(userInput) > 100) {
message.innerText = "Please only provide a number between 1 and 100"
} else {
message.innerText = `You selected a ${userInput} x ${userInput} sized grid for your canvas`
generateCanvas(userInput);
}
return true;
}
const setcolours=( fgcol='black', bgcol='blue' )=>{
let root = document.documentElement;
root.style.setProperty(`--fgcolour`,fgcol);
root.style.setProperty(`--bgcolour`,bgcol);
return true;
}
const reset=()=>{
generateCanvas();
return setcolours();
}
const buttonPress = e => {
let buttonID = e.target.id;
let alt=e.target.dataset.alt;
switch(buttonID) {
case "modify-grid":return selectSize();
case 'blue':return setcolours(alt,buttonID);
case "black":return setcolours(alt,buttonID);
case "red":return setcolours(alt,buttonID);
case "reset":return reset();
}
}
//get all buttons and make them listen for a click to run a function
let buttons = document.querySelectorAll(".button");
buttons.forEach(button => button.addEventListener("click", buttonPress));
#import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
#import url('https://fonts.googleapis.com/css2?family=Comforter+Brush&display=swap');
#import url('https://fonts.googleapis.com/css?family=Quicksand&display=swap');
/*
Two variables to dictate width and height of grid elements.
These values are updated by javascript.
*/
:root {
--w:1px;
--h:1px;
--bgcolour:blue;
--fgcolour:black;
}
h3 {
font-family: 'Quicksand', sans-serif;
font-weight: 700;
font-style: normal;
letter-spacing: -.02em;
color: rgb(15, 45, 0);
font-size: 18px;
line-height: 1.15;
}
.header {
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: black;
flex-direction: column;
}
.main-program-space {
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: black;
flex-direction: column;
}
.buttons-flexbox {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: 10px;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
list-style: none;
}
/* This will make our buttons look cool and change when hovered over */
.button {
align-items: center;
background-image: linear-gradient(144deg, #AF40FF, #5B42F3 50%, #00DDEB);
border: 0;
border-radius: 8px;
box-shadow: rgba(151, 65, 252, 0.2) 0 15px 30px -5px;
box-sizing: border-box;
color: #FFFFFF;
display: flex;
flex:1;
font-family: Phantomsans, sans-serif;
font-size: 1rem;
justify-content: center;
line-height: 1rem;
text-decoration: none;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
white-space: nowrap;
cursor: pointer;
min-width: 130px;
min-height: 50px;
}
.button:active,
.button:hover {
outline: 0;
}
.main-grid-container {
display: grid;
justify-content: center;
align-items: center;
margin: 20px;
border: none;
width: 500px;
height: 500px;
padding:10px;
border:1px solid black;
}
.bottom-text {
display: flexbox;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
}
.footer-flexbox {
display: flexbox;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: black;
}
.footer {
display: flexbox;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
}
.grid-item {
display: flex;
flex: 1;
margin: 0;
background: var(--bgcolour);
width: var(--w);
height: var(--h);
}
.grid-paint{
background:var(--fgcolour);
}
<div class="title header">
<h3>The html is working but what about CSS</h3>
<p id="message">(messages from main.js will print here)</p>
</div>
<div class="main-program-space">
<ul class="buttons-flexbox">
<li><button id="modify-grid" class="button modify-grid">Modify Grid</button></li>
<li><button id="blue" data-alt='black' class="button blue">Blue</button></li>
<li><button id="black" data-alt='blue' class="button black">Black</button></li>
<li><button id="red" data-alt='yellow' class="button red">Red</button></li>
<li><button id="reset" class="button reset">Reset</button></li>
</ul>
<div class="main-grid-container"></div>
<div class="bottom-text">
<h3>XXXXX bottom text XXXXX</h3>
</div>
</div>
<div class="footer-flexbox">
<div class="footer">
<h3>XXXXX footer XXXXX</h3>
</div>
</div>
For some reason, your line ( I tried to figure the reason out, but couldn't )
// style.insertRule(`.grid-item {height: ${gridSize}}`,0);
doesn't select grid-items. but I found that you selected them when you added grid-item class. so just add div.style.height = "100%"; after that.
//wait until the HTML and CSS are loaded before you run the javascript
document.addEventListener("DOMContentLoaded", function(){
generateCanvas(16);
console.log("dom content is loaded");
});
function generateCanvas(gridSize){
//create the gridlines
//divide canvas into A x A where A = the number provided by user
let canvas = document.querySelector(".main-grid-container");
canvas.style.gridTemplateColumns = `repeat(${gridSize}, 1fr)`;
canvas.style.gridTemplateRows = `repeat(${gridSize}, 1fr)`;
// alert("canvas should be generated");
// style.insertRule(`.grid-item {height: ${gridSize}}`,0);
let divsTotal = (gridSize * gridSize);
for(let i = 0; i < divsTotal; i++){
let div = document.createElement("div");
div.classList.add("grid-item");
div.style.backgroundColor="blue";
div.style.height = "100%";
//this will allow our divs to change color when hovered over
div.addEventListener("mouseover", function(){
div.style.backgroundColor="black";
})
canvas.appendChild(div);
}
}
function selectSize(){
//has the user type a number and returns that number, but only if it is between 0 and 100
let userInput = prompt("What should be the size of the board?")
let message = document.querySelector("#message")
if (userInput == ""){
message.innerText = "Please provide a number only";
} else if(userInput < 0 || userInput > 100){
message.innerText ="Please only provide a number between 1 and 100"
} else {
message.innerText =`You selected a ${userInput} x ${userInput} sized grid for your canvas`
generateCanvas(userInput);
}
}
const buttonPress = e =>{
//takes in the id of the button that was pressed.
let buttonID = e.target.id;
console.log(buttonID);
alert(`button ${buttonID} was pressed`);
switch(buttonID){
case "modify-grid":
selectSize();
break;
case "black":
alert('you pressed black');
break;
case "red":
alert('you pressed red');
break;
case "reset":
alert('you pressed reset');
break;
}
}
//get all buttons and make them listen for a click to run a function
let buttons = document.querySelectorAll(".button");
buttons.forEach(button => button.addEventListener("click", buttonPress));
#import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
#import url('https://fonts.googleapis.com/css2?family=Comforter+Brush&display=swap');
#import url('https://fonts.googleapis.com/css?family=Quicksand&display=swap');
h3 {
font-family: 'Quicksand', sans-serif;
font-weight: 700;
font-style: normal;
letter-spacing: -.02em;
color: rgb(15, 45, 0);
font-size: 18px;
line-height: 1.15;
}
.header{
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: black;
flex-direction: column;
}
.main-program-space{
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: black;
flex-direction: column;
}
.buttons-flexbox{
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
list-style: none;
flex-direction: row;
gap: 20px;
}
/* This will make our buttons look cool and change when hovered over */
.button {
align-items: center;
background-image: linear-gradient(144deg,#AF40FF, #5B42F3 50%,#00DDEB);
border: 0;
border-radius: 8px;
box-shadow: rgba(151, 65, 252, 0.2) 0 15px 30px -5px;
box-sizing: border-box;
color: #FFFFFF;
display: flex;
font-family: Phantomsans, sans-serif;
font-size: 20px;
justify-content: center;
line-height: 1em;
max-width: 100%;
min-width: 140px;
padding: 3px;
text-decoration: none;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
white-space: nowrap;
cursor: pointer;
min-width: 150px;
min-height: 50px;
}
.button:active,
.button:hover {
outline: 0;
}
.main-grid-container{
display: grid;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
width: 500px;
height: 500px;
}
/* .grid-item{
height: 12px;
} */
.bottom-text{
display: flexbox;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
}
.footer-flexbox{
display: flexbox;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: black;
}
.footer{
display: flexbox;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
}
<body>
<div class ="title header">
<h3>The html is working but what about CSS</h3>
<p id="message">(messages from main.js will print here)</p>
</div>
<div class="main-program-space">
<ul class="buttons-flexbox">
<li><button id="modify-grid" class="button modify-grid">Modify Grid</span></button></li>
<li><button id="black" class="button black">Black</button></li>
<li><button id="red" class="button red">Red</button></li>
<li><button id="reset" class="button reset">Reset</button></li>
</ul>
<div class="main-grid-container">
</div>
<div class="bottom-text">
<h3>XXXXX bottom text XXXXX</h3>
</div>
</div>
<div class="footer-flexbox">
<div class="footer">
<h3>XXXXX footer XXXXX</h3>
</div>
</div>
</body>
Related
How to start my progressbar counting when i will go to container section of my webpage.I think i have to change my javascript code a bit please help me.
HTML CODE
<div class="container">
<div class="circular-progress">
<span class="progress-value">100%</span>
</div>
<span class="text">HTML & CSS</span>
</div>
<!-- JavaScript -->
<script src="js/script.js"></script>
CSS CODE
/* Google Fonts - Poppins */
#import url('https://fonts.googleapis.com/css2?family=Poppins:wght#300;400;500;600;700&display=swap');
*{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
body{
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: #7d2ae8;
}
.container{
display: flex;
width: 420px;
padding: 50px 0;
border-radius: 8px;
background: #fff;
row-gap: 30px;
flex-direction: column;
align-items: center;
}
.circular-progress{
position: relative;
height: 250px;
width: 250px;
border-radius: 50%;
background: conic-gradient(#7d2ae8 3.6deg, #ededed 0deg);
display: flex;
align-items: center;
justify-content: center;
}
.circular-progress::before{
content: "";
position: absolute;
height: 210px;
width: 210px;
border-radius: 50%;
background-color: #fff;
}
.progress-value{
position: relative;
font-size: 40px;
font-weight: 600;
color: #7d2ae8;
}
.text{
font-size: 30px;
font-weight: 500;
color: #606060;
}
Javascriptcode
let circularProgress = document.querySelector(".circular-progress"),
progressValue = document.querySelector(".progress-value");
let progressStartValue = 0,
progressEndValue = 90,
speed = 100;
let progress = setInterval(() => {
progressStartValue++;
progressValue.textContent = `${progressStartValue}%`
circularProgress.style.background = `conic-gradient(#7d2ae8 ${progressStartValue * 3.6}deg, #ededed 0deg)`
if(progressStartValue == progressEndValue){
clearInterval(progress);
}
}, speed);
When i load my page at first then progressbar is count value But i want to start the counting after i go to that section of that webpage.
You could use Intersection Observer. You choose an HTML element to observe and once this element is in view, that will trigger the start of the progress bar.
I have been working on this for a little while, and I think I'm stuck at this point.
I made a div slider with arrows. Each div slide is set to a min-width of 80px.
The code works just fine, except, when I navigate either to the left or the right, it stops at the last item. I want this slider to loop (as in endlessly), instead of ending at the last item.
let buttonLeft = document.getElementById('slide_left')
let buttonRight = document.getElementById('slide_right')
buttonLeft.addEventListener('click', function() {
document.getElementById('slider').scrollLeft -= 90
})
buttonRight.addEventListener('click', function() {
document.getElementById('slider').scrollLeft += 90
})
body{
background-color: #555;
height: 100vh;
display: grid;
align-items: center;
justify-items: center;
font-family: 'Helvetica';
}
div#slide_wrapper{
width: 440px;
display: flex;
justify-content: space-between;
height: fit-content;
}
div#slider{
width: 350px;
display: flex;
height: fit-content;
flex-wrap: nowrap;
overflow: hidden;
}
div.thumbnail{
min-width: 80px;
min-height: 80px;
cursor: pointer;
display: grid;
place-items: center;
font-size: 30px;
}
div.thumbnail:not(:last-child){
margin-right: 10px;
}
div.thumbnail:nth-child(1){
background-color: darkturquoise;
}
div.thumbnail:nth-child(2){
background-color: goldenrod;
}
div.thumbnail:nth-child(3){
background-color: rebeccapurple;
}
div.thumbnail:nth-child(4){
background-color: powderblue;
}
div.thumbnail:nth-child(5){
background-color: firebrick;
}
div.thumbnail:nth-child(6){
background-color: sienna;
}
div.thumbnail:nth-child(7){
background-color: bisque;
}
div.thumbnail:nth-child(8){
background-color: navy;
}
div#slide_wrapper > button{
height: fit-content;
align-self: center;
font-size: 24px;
font-weight: 800;
border: none;
outline: none;
}
div#slide_wrapper > button:hover{
cursor: pointer;
background-color: dodgerblue;
color: #fff;
}
<div id="slide_wrapper">
<button id="slide_left" class="slide_arrow">❮</button>
<div id="slider">
<div class="thumbnail active">1</div>
<div class="thumbnail">2</div>
<div class="thumbnail">3</div>
<div class="thumbnail">4</div>
<div class="thumbnail">5</div>
<div class="thumbnail">6</div>
<div class="thumbnail">7</div>
<div class="thumbnail">8</div>
</div>
<button id="slide_right" class="slide_arrow">❯</button>
</div>
Nice slider! There are several ways to achieve what you want. In my opinion, the simplest solution would be to work with some if conditions and a counter variable. Once the number of thumbnails is reached, set the counter back to 0.
Update
Regarding to your comment. "How about doing the same for the left arrow.". In the if condition block: if (0 == slideCount) { i add these lines:
slideCount = thumbnail.length // set the slideCounter to maximum
document.getElementById('slider').scrollLeft = slideCount * 90 // calculate the scroll distance
slideCount--; // decrease slidecount
setActive(); // set the red border on the current slide
const buttonLeft = document.getElementById('slide_left')
const buttonRight = document.getElementById('slide_right')
const thumbnail = document.querySelectorAll(".thumbnail");
let slideCount = 0;
setActive();
buttonLeft.addEventListener('click', function() {
if (0 == slideCount) {
slideCount = thumbnail.length
document.getElementById('slider').scrollLeft = slideCount * 90
slideCount--;
setActive();
return;
}
slideCount--;
document.getElementById('slider').scrollLeft -= 90
setActive();
})
buttonRight.addEventListener('click', function() {
slideCount++;
if ( 8 == slideCount) {
document.getElementById('slider').scrollLeft = 0
slideCount = 0;
} else {
document.getElementById('slider').scrollLeft += 90
}
setActive();
})
function setActive() {
thumbnail.forEach(t => {
t.classList.remove("active");
})
thumbnail[slideCount].classList.add("active")
}
function count() {
console.log(slideCount);
}
body{
background-color: #555;
height: 100vh;
display: grid;
align-items: center;
justify-items: center;
font-family: 'Helvetica';
}
div#slide_wrapper{
width: 440px;
display: flex;
justify-content: space-between;
height: fit-content;
}
div#slider{
width: 350px;
display: flex;
height: fit-content;
flex-wrap: nowrap;
overflow: hidden;
}
div.thumbnail{
min-width: 80px;
min-height: 80px;
cursor: pointer;
display: grid;
place-items: center;
font-size: 30px;
}
div.thumbnail:not(:last-child){
margin-right: 10px;
}
div.thumbnail:nth-child(1){
background-color: darkturquoise;
}
div.thumbnail:nth-child(2){
background-color: goldenrod;
}
div.thumbnail:nth-child(3){
background-color: rebeccapurple;
}
div.thumbnail:nth-child(4){
background-color: powderblue;
}
div.thumbnail:nth-child(5){
background-color: firebrick;
}
div.thumbnail:nth-child(6){
background-color: sienna;
}
div.thumbnail:nth-child(7){
background-color: bisque;
}
div.thumbnail:nth-child(8){
background-color: navy;
}
div#slide_wrapper > button{
height: fit-content;
align-self: center;
font-size: 24px;
font-weight: 800;
border: none;
outline: none;
}
div#slide_wrapper > button:hover{
cursor: pointer;
background-color: dodgerblue;
color: #fff;
}
.active {
border: 2px solid red;
}
<div id="slide_wrapper">
<button id="slide_left" class="slide_arrow">❮</button>
<div id="slider">
<div class="thumbnail active">1</div>
<div class="thumbnail">2</div>
<div class="thumbnail">3</div>
<div class="thumbnail">4</div>
<div class="thumbnail">5</div>
<div class="thumbnail">6</div>
<div class="thumbnail">7</div>
<div class="thumbnail">8</div>
</div>
<button id="slide_right" class="slide_arrow">❯</button>
</div>
Just find the width of the slider and compare it with the scroll left like
let buttonLeft = document.getElementById('slide_left')
let buttonRight = document.getElementById('slide_right')
buttonLeft.addEventListener('click', function() {
document.getElementById('slider').scrollLeft -= 90
})
buttonRight.addEventListener('click', function() {
const elem = document.getElementById('slider');
const ElemWidth = elem.getClientRects()[0].width
if(document.getElementById('slider').scrollLeft > ElemWidth ){
document.getElementById('slider').scrollLeft = 0
}else{
document.getElementById('slider').scrollLeft += 90
}
console.log(ElemWidth, document.getElementById('slider').scrollLeft , document.getElementById('slider').scrollLeft > ElemWidth)
})
Just made a simple div slider with navigation arrows. The div slider works just fine, except, I want some sort of CSS styling to be applied to the arrows.
That is, when a user clicks the left or right arrow, up to the last item, apply CSS styling telling the user they've reached the end of the slider.
let buttonLeft = document.getElementById('slide_left')
let buttonRight = document.getElementById('slide_right')
let container = document.getElementById('slider')
buttonLeft.addEventListener('click', function() {
container.scrollLeft -= 90
})
buttonRight.addEventListener('click', function() {
container.scrollLeft += 90
})
body {
background-color: #555;
height: 100vh;
display: grid;
align-items: center;
justify-items: center;
font-family: 'Helvetica';
}
div#slide_wrapper {
width: 440px;
display: flex;
justify-content: space-between;
height: fit-content;
}
div#slider {
width: 350px;
display: flex;
height: fit-content;
flex-wrap: nowrap;
overflow: hidden;
}
div.thumbnail {
min-width: 80px;
min-height: 80px;
cursor: pointer;
display: grid;
place-items: center;
font-size: 30px;
}
div.thumbnail:not(:last-child) {
margin-right: 10px;
}
div.thumbnail:nth-child(1) {
background-color: darkturquoise;
}
div.thumbnail:nth-child(2) {
background-color: goldenrod;
}
div.thumbnail:nth-child(3) {
background-color: rebeccapurple;
}
div.thumbnail:nth-child(4) {
background-color: powderblue;
}
div.thumbnail:nth-child(5) {
background-color: firebrick;
}
div.thumbnail:nth-child(6) {
background-color: sienna;
}
div.thumbnail:nth-child(7) {
background-color: bisque;
}
div.thumbnail:nth-child(8) {
background-color: navy;
}
div#slide_wrapper>button {
height: fit-content;
align-self: center;
font-size: 24px;
font-weight: 800;
border: none;
outline: none;
}
div#slide_wrapper>button:hover {
cursor: pointer;
}
<div id="slide_wrapper">
<button id="slide_left" class="slide_arrow">❮</button>
<div id="slider">
<div class="thumbnail active">1</div>
<div class="thumbnail">2</div>
<div class="thumbnail">3</div>
<div class="thumbnail">4</div>
<div class="thumbnail">5</div>
<div class="thumbnail">6</div>
<div class="thumbnail">7</div>
<div class="thumbnail">8</div>
</div>
<button id="slide_right" class="slide_arrow">❯</button>
</div>
Simply check to see if you need to disable each button based on the position of the scroll. Then if there is a need to disable a button, add the disabled class to the button, otherwise remove it.
Future enhancements.
Remove the hardcoded 360 value for the scroll end. This should be calculated from the size of the carousel items and the width of the viewport.
Allow more than one carousel to work with the same code. This could be achieved by using a javascript class that would hold the elements inside an object, separate from other carousels.
See the demo:
let buttonLeft = document.getElementById('slide_left')
let buttonRight = document.getElementById('slide_right')
let container = document.getElementById('slider')
let checkScroll = function() {
if (container.scrollLeft <= 0)
buttonLeft.classList.add("disabled");
else
buttonLeft.classList.remove("disabled");
if (container.scrollLeft >= 360)
buttonRight.classList.add("disabled");
else
buttonRight.classList.remove("disabled");
}
checkScroll();
buttonLeft.addEventListener('click', function() {
container.scrollLeft -= 90;
checkScroll();
})
buttonRight.addEventListener('click', function() {
container.scrollLeft += 90;
checkScroll();
})
body {
background-color: #555;
height: 100vh;
display: grid;
align-items: center;
justify-items: center;
font-family: 'Helvetica';
}
div#slide_wrapper {
width: 440px;
display: flex;
justify-content: space-between;
height: fit-content;
}
div#slider {
width: 350px;
display: flex;
height: fit-content;
flex-wrap: nowrap;
overflow: hidden;
}
div.thumbnail {
min-width: 80px;
min-height: 80px;
cursor: pointer;
display: grid;
place-items: center;
font-size: 30px;
}
div.thumbnail:not(:last-child) {
margin-right: 10px;
}
div.thumbnail:nth-child(1) {
background-color: darkturquoise;
}
div.thumbnail:nth-child(2) {
background-color: goldenrod;
}
div.thumbnail:nth-child(3) {
background-color: rebeccapurple;
}
div.thumbnail:nth-child(4) {
background-color: powderblue;
}
div.thumbnail:nth-child(5) {
background-color: firebrick;
}
div.thumbnail:nth-child(6) {
background-color: sienna;
}
div.thumbnail:nth-child(7) {
background-color: bisque;
}
div.thumbnail:nth-child(8) {
background-color: navy;
}
div#slide_wrapper>button {
height: fit-content;
align-self: center;
font-size: 24px;
font-weight: 800;
border: none;
outline: none;
}
div#slide_wrapper>button:hover {
cursor: pointer;
}
.slide_arrow.disabled {
opacity: 0.2;
cursor: auto !important;
}
<div id="slide_wrapper">
<button id="slide_left" class="slide_arrow">❮</button>
<div id="slider">
<div class="thumbnail active">1</div>
<div class="thumbnail">2</div>
<div class="thumbnail">3</div>
<div class="thumbnail">4</div>
<div class="thumbnail">5</div>
<div class="thumbnail">6</div>
<div class="thumbnail">7</div>
<div class="thumbnail">8</div>
</div>
<button id="slide_right" class="slide_arrow">❯</button>
</div>
a simple solution to this is to actually create a css class that defines the style of arrows when there are no more items and then just add/remove class based on current index of items
"use strict";
const diaryInput = document.querySelector(".writing");
const titleInput = document.querySelector(".title");
const submitButton = document.querySelector(".dsubmit");
const indexList = document.querySelector(".womb");
const inputTime = document.querySelector(".clock");
const selectAll = document.querySelector(".select");
const unselectAll = document.querySelector(".unselect");
const deleteIndex = document.querySelector(".delete");
submitButton.addEventListener("click", transferDiary);
selectAll.addEventListener("click", selectAllindex);
unselectAll.addEventListener("click", unselectAllindex);
deleteIndex.addEventListener("click", deleteDiaryIndex);
let layout_no = 0;
function transferDiary(e) {
e.preventDefault();
const indexLayout = document.createElement("div");
indexLayout.classList.add("indexlayout");
indexLayout.id = "indexlayout-" + layout_no;
const diaryIndex = document.createElement("div");
diaryIndex.classList.add("invisible");
diaryIndex.innerText = diaryInput.value;
saveLocalDiary(diaryInput.value);
const diaryTitle = document.createElement("div");
diaryTitle.classList.add("index");
const m = new Array(
"JAN.",
"FEB.",
"MAR.",
"APR.",
"MAY",
"JUN.",
"JUL.",
"AUG",
"SEPT.",
"OCT.",
"NOV.",
"DEC."
);
const years = date.getFullYear();
const months = date.getMonth();
const d = new Array(
"Sun.",
"Mon.",
"Tues.",
"wed.",
"Thurs.",
"Fri.",
"Sat."
);
const days = date.getDay();
const today = date.getDate();
diaryTitle.innerHTML = `<input type='checkbox' name='indexchild' value='' class="indexchild" >${m[months]} ${today} ${years} ${d[days]} -${titleInput.value}</>`;
indexLayout.appendChild(diaryTitle);
diaryTitle.appendChild(diaryIndex);
indexList.appendChild(indexLayout);
const wayBackHome = document.getElementById("indexlayout-" + layout_no);
wayBackHome.addEventListener("click", bringBackIndex);
layout_no++;
}
function selectAllindex(e) {
e.preventDefault();
const checkboxes = document.querySelectorAll("input[type=checkbox]");
for (const cb of checkboxes) {
cb.checked = true;
}
}
function unselectAllindex(e) {
e.preventDefault();
const checkboxes = document.querySelectorAll("input[type=checkbox]");
for (const cb of checkboxes) {
cb.checked = false;
}
}
function deleteDiaryIndex(i) {
i.preventDefault();
const checkboxes = document.querySelectorAll("input[type=checkbox]");
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked) {
removeDiv(checkboxes[i]);
removeLocalDiary(checkboxes[i]);
}
}
}
function removeDiv(d) {
console.log(d.parentElement.parentElement);
console.log(d.parentElement.parentElement[1]);
d.parentElement.parentElement.remove();
}
function bringBackIndex(e) {
e.preventDefault();
const bringEssence = e.target.getElementsByClassName("invisible");
diaryInput.value = bringEssence[0].innerHTML.replace(
/\s?(<br\s?\/?>)\s?/g,
"\r\n"
);
}
function saveLocalDiary(todo) {
//check ---- HEy Do I already have thing in localstorage?
let diary;
if (localStorage.getItem("diary") === null) {
diary = [];
} else {
diary = JSON.parse(localStorage.getItem("diary"));
}
diary.push(todo);
localStorage.setItem("diary", JSON.stringify(diary));
}
function removeLocalDiary(todo) {
let diary;
if (localStorage.getItem("diary") === null) {
diary = [];
} else {
diary = JSON.parse(localStorage.getItem("diary"));
}
const todoIndex = todo.children.innerText;
diary.splice(diary.indexOf(todoIndex), 1);
localStorage.setItem("diary", JSON.stringify(diary));
}
:root {
--page1-color: #20bf6b;
--page2-color: #f7b731;
--page3-color: #4b7bec;
--text-color: white;
}
html {
font-size: 62.5%;
/* 10px=1rem */
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: sans-serif;
}
.page3 {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: var(--page3-color);
width: 70%;
min-width: 600px;
box-shadow: 9px 9px 9px rgb(126, 124, 124),9px 9px 9px rgb(126, 124, 124);
}
.dlayout {
min-height: 90vh;
max-height: 90vh;
border: 1px solid var(--text-color);
display: flex;
}
.dtitle {
min-height: 10%;
border-bottom: 1px solid var(--text-color);
}
.dindex {
min-width: 10vw;
max-width: 15vw;
border-right: 1px solid var(--text-color);
display: flex;
flex-direction: column;
justify-content: space-between;
}
.diary {
min-width: 50vw;
display: flex;
flex-direction: column;
}
.submit {
display: flex;
flex-direction: row;
height: 10%;
border-bottom: 1px solid var(--text-color);
}
.submitime {
padding: 25px 0 0 15px;
color: var(--text-color);
min-width: 50%;
font-size: 3rem;
font-weight: 300;
}
.submitarea {
padding: 20px 0 0 0;
min-width: 40%;
color: var(--text-color);
font-size: 3rem;
letter-spacing: 3px;
font-weight: 300;
}
.title {
background-color: var(--page3-color);
border: 1px dashed var(--text-color);
font-size: 3rem;
outline: none;
height: 40px;
width: 200px;
letter-spacing: 3px;
font-weight: 300;
}
.dsubmit {
margin-top: 10px;
height: 30px;
width: 30px;
background-color: var(--page3-color);
border: none;
border-radius:50%;
cursor: pointer;
}
.dtitle {
color: var(--text-color);
text-align: center;
display: table;
font-size: 3rem;
font-weight: 300;
letter-spacing: 20px;
/* 자간 */
}
p {
display: table-cell;
vertical-align: middle;
}
.writing {
background-color: var(--page3-color);
border: none;
height: 90%;
color: var(--text-color);
font-size: 2.5rem;
letter-spacing: 3px;
font-weight: 100;
}
textarea::placeholder {
color: var(--text-color);
opacity: 0.5;
}
textarea{
resize: none;
}
.indexlayout {
color: var(--text-color);
text-align: center;
font-size: 1.5rem;
border: 1px solid var(--text-color);
margin:5px;
}
.invisible {
display:none ;
}
.womb{
overflow: scroll;
}
.selector{
color: var(--text-color);
width: 100%;
border:none;
border-top: 1px solid var(--text-color);
min-height: 5%;
background-color: var(--page3-color);
outline: none;
font-size: 3rem;
letter-spacing: 8px;
font-weight: 300;
}
.index{
word-break: break-all;
}
.indexchild{
}
.selector:hover{
color:var(--page3-color);
background-color: var(--text-color);
}
.dsubmit:hover{
box-shadow: -3px -3px 3px rgb(172, 172, 172), 3px 3px 3px rgb(237, 237, 237),;
transition: 0.3s;
}
.indexlayout:hover{
color:var(--page3-color);
background-color: var(--text-color);
}
<section class="page3">
<div class="dlayout">
<form id="indexo" name="indexi" class="dindex">
<div class="dtitle"><p>Diary</p></div>
<div class="womb"></div>
<div class="buttons">
<button class="selector select" value="selectall">Select All</button>
<button class="selector unselect" value="unselectall">Unselect All</button>
<button class="selector delete" value="delete">Delete</button>
</div>
</form>
<div class="diary">
<div class="submit">
<div class="submitime clock"></div>
<form class="submitarea">
Title: <input type="text" class="title" />
<button class="dsubmit"><img src="./arrow-circle-right-solid.svg" alt=""></button>
</form>
</div>
<textarea class="writing" placeholder=" shit something..."></textarea>
</div>
</div>
</section>
Hello, I am struggling code above. It is a quite simple diary, the right side has a textarea
tag so you can write your diary and also has a transfer button so you push it, left side is gonna have an index of what you wrote. and I also added a checkbox on the index so you can select/unselect/delete them all at once. if perfectly works fine until I added another function. I added Eventlistener(handler is click) on the index(div .indexlayout), when you click the index it is gonna bring back what you wrote into the textarea tag.
const wayBackHome = document.getElementById("indexlayout-" + layout_no);
wayBackHome.addEventListener("click", bringBackIndex);
It works also okay. so I was quite satisfied. However, a little while later, I found that checkboxes don't work ever since added a new function!!
to be specific, select/unselect All buttons still work and I can check checkboxes with those, but I cannot select checkboxes individually :/
I think it is because I added an event on div which is a parent of a checkbox.
But, not gonna lie, I had no idea how to solve this. I tried "wayBackHome.innerText" or even added event to other div but it didn't work. Could you tell me what I missed and How do I fix it please?
thx!
Hey so right now I'm learning Mainly JS but that also comes with HTML and CSS so I guess that too. I followed a great tutorial from Web Dev Simplified on how to make a snake game (https://www.youtube.com/watch?v=QTcIXok9wNY&t=1781s). so now I wanted to expand my knowledge and start adding features to the game. So I wanted to add a Score feature. The only thing is that when I change the the text-align or the font-size bigger then it already is, nothing changes, is there anything externally locking this data?
Index.html:
<style>
body {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
background-color: black;
}
#game-board {
background-color: white;
width: 100vmin;
height: 100vmin;
display: grid;
grid-template-rows: repeat(21, 1fr);
grid-template-columns: repeat(21, 1fr);
}
.snake {
background-color: hsl(216, 100%, 50%);
border: .25vmin solid black;
}
.food {
background-color: hsl(0, 100%, 50%);
border: .25vmin solid black;
}
#score {
color: white;
font-family: 'Source Sans Pro', sans-serif;
font-size: 60;
text-align: center;
text-align: top;
}
Main JS File:
import { update as updateSnake, draw as drawSnake, SNAKE_SPEED, getSnakeHead, snakeIntersection, scorefunc} from './snake.js'
import { update as updateFood, draw as drawFood } from './food.js'
import { outsideGrid } from './grid.js'
let lastRenderTime = 0
let gameOver = false
const gameBoard = document.getElementById('game-board')
function main(currentTime) {
if (gameOver) {
if (confirm('You lost. Press ok to restart.')) {
window.location = '/'
}
return
}
window.requestAnimationFrame(main)
const secondsSinceLastRender = (currentTime - lastRenderTime) / 1000
if (secondsSinceLastRender < 1 / SNAKE_SPEED) return
lastRenderTime = currentTime
update()
draw()
}
window.requestAnimationFrame(main)
function update() {
updateSnake()
updateFood()
checkDeath()
scorefunc()
}
function draw() {
gameBoard.innerHTML = ''
drawSnake(gameBoard)
drawFood(gameBoard)
}
function checkDeath() {
gameOver = outsideGrid(getSnakeHead()) || snakeIntersection()
}
All other files will be on my GitHub: https://github.com/CarsCanadian/snake-tutorial/
You forgot to add your HTML. Your javascript is unnecessary to show. Anyway, by following your link, I could locate where things went wrong. You need to add a unit to your font-size.
Your code.
body {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
background-color: black;
}
#score {
color: white;
font-family: 'Source Sans Pro', sans-serif;
font-size: 60;
text-align: center;
text-align: top;
}
<body>
<div id="game-board"></div>
<em id="score">123123</em>
</body>
Corrected code, using font-size: 60px.
body {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
background-color: black;
}
#score {
color: white;
font-family: 'Source Sans Pro', sans-serif;
font-size: 60px;
text-align: center;
text-align: top;
}
<body>
<div id="game-board"></div>
<em id="score">123123</em>
</body>