-
-
Notifications
You must be signed in to change notification settings - Fork 183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document Object Model - practice #159
Conversation
Removed DOM calls from loop in renderButtons function |
Could you give some advice how to load image faster? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
box-sizing: border-box; | ||
} | ||
|
||
ul, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this style applies just for li
tags, so you can leave just one tag here
https://developer.mozilla.org/en-US/docs/Web/CSS/list-style
background: none; | ||
color: inherit; | ||
border: none; | ||
padding: 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you specified this property for all elements in the first lines
@@ -0,0 +1,47 @@ | |||
<!DOCTYPE html> | |||
<html lang="en" id="root"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a common practice to divide responsibility - ids for JS, classes for styling. Better to use the wrapper in this case and set styles for wrapper
, not for html
tag. Using html styling is even bad for performance reasons
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can I use :root pseudo-class in CSS instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the common use of :root is for variables declaration. For such files root will be always html
https://developer.mozilla.org/en-US/docs/Web/CSS/:root
.nav-item { | ||
border-bottom: 1px solid #f5f5dc; | ||
width: 20rem; | ||
margin: 10; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what are the units?
<header class="header"> | ||
<span class="dropdown-wrap"> | ||
<button class="dropdown"> | ||
<i class="fa-solid fa-bars fa-lg"></i> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fa-solid fa-bars fa-lg. What are these classes for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's Font Awesome prebuilt classes, I thought it is not needed to change them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are right. my bad
} | ||
|
||
function renderArticle(museumObj, content) { | ||
const contentHTML = ` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use object destructuring
https://javascript.info/destructuring-assignment#object-destructuring
} | ||
|
||
function toggleSelectedButton(museums, content) { | ||
let selectedButton = document.getElementsByClassName("nav-item")[1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logically, default value is the first element of the array, not second
function changeTheme() { | ||
|
||
const checkbox = document.getElementById("switcher"); | ||
checkbox.addEventListener("change", () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
better to separate the handler function from a listener.
el.addEventListener("change", handler);
function handler {}
|
||
document.addEventListener("DOMContentLoaded", main); | ||
|
||
function renderButtons(arr, menu) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arr sounds too generic. We can name it listOfCards
for example or what you prefer more
function renderButtons(arr, menu) { | ||
let buttonsHTML = ``; | ||
|
||
arr.forEach(({ btnName }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
map
looks like the optimal choice
About images - the simplest way is to compress images or use a lightweight format such as webp. One more option - while an image is loading you can set some default placeholder instead. Also, HTML has a cool tag |
Tried to make all fixes accordingly to remarks. |
I have questions about some remarks, see in comments above. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great progress, but let's improve JS part 🚀
</main> | ||
<footer class="footer"> | ||
<a class="footer-link" href="https://github.com/zhenyakornilov" target="_blank"> | ||
<span><i class="fa-brands fa-github"></i> Yevhen Kornilov</span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is a good practice to place one tag in a line
grid-template-areas: "header-top header-top" "content-main content-main" "footer-bottom footer-bottom"; | ||
} | ||
|
||
.dropdown { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I don't understand this remark here.
Do You mean something wrong with grid-template-areas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have two similar classes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yet I don't get what I have to change here(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
look at line 132
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what's wrong here. I defined .dropdown in CSS with display none to hide and then changed this in media query to make it visible.
} | ||
|
||
.dropdown-wrap { | ||
display: inline; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't it the default display value?
outline: inherit; | ||
} | ||
|
||
:root { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use html if you want
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I change html font-size since I use rem and when html font-size is equal to 62.5% then 1 rem is like 10 pixels, 2.1rem is 21 pixels etc. It makes more clear to me rem values to interpret them as pixels.
} | ||
|
||
.header .check-switch:checked + .theme-switcher .circle { | ||
transform: translatex(2.4rem); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
X from capital :))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
too specific selector, WDYT?
@@ -0,0 +1,89 @@ | |||
"use strict"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make JS more readable let's try to do some improvements:
we can declare all elements which we found by getElement at the top of the file;
then we can declare all functions. Functions should be pure, which means do one thing;
at the bottom, we can add listeners;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed index.js. Did You mean something like it looks now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet. Divide listeners and functions
element.addEventListener(event, listener);
Look below, the listener is bold
function showMuseumInfoByClick(museums, content, menu) { menu.addEventListener("click",function ({ target }) { if (target.tagName.toLowerCase() === "button") { const currentContentObject = museums.filter( ({ btnName }) => btnName === target.textContent ); renderArticle(currentContentObject[0], content); } }); }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
separated listeners and functions
@@ -0,0 +1,15 @@ | |||
function toggleDarkClass() { | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to add spaces inside a function. It should looks like a block of code
|
||
const buttons = document.getElementsByClassName("nav-item"); | ||
|
||
function getContextObj() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please explain what function name getContextObj
mean. I really want to understand :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function returns object from museums array to render as content.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean name. getConteNtObject?
renderArticle(getContextObj(), content); | ||
|
||
for (let button of buttons) { | ||
button.addEventListener("click", function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here you added a listener to every button. why not add a listener to the navigation menu?
|
||
renderArticle(getContextObj(), content); | ||
|
||
for (let button of buttons) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try to use a different approach. for...of
is not needed here. now it seems that you take different parts of code from different sources
Tried to make changes accordingly to recommendations, but still have some questions above. |
Please do not resolve comments, I need to see them |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job! Please take a look at the comments and make corresponding changes. Also add hover effect to theme-switcher
grid-template-areas: "header-top header-top" "content-main content-main" "footer-bottom footer-bottom"; | ||
} | ||
|
||
.dropdown { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
look at line 132
<body class="body"> | ||
<div class="wrapper"> | ||
<header class="header"> | ||
<span class="dropdown-wrap"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You deleted this class in the CSS file
<p class="museum-desc">${description}</p> | ||
</div> | ||
<div class="additional-wrapper"> | ||
<p class="museum-link"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please take a look at when you can use p
tag and find appropriate tag
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/p
<ul class="menu-items" id="menu"></ul> | ||
</nav> | ||
<main class="content"> | ||
<article class="content-body" id="content"></article> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
article
should have a header
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/article
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have misunderstanding here. I have h2 tag added with JS inside article tag, isn't it can be counted as header? Or shall I set h2 tag inside index.html? May I just change article tag to div then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are right, I missed h2
. All is fine here
import switchTheme from "./utils.js"; | ||
|
||
function main() { | ||
const dropdownBtn = document.getElementById("dropdown"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you get element by id dropdown
and name it dropdownBtn, which means button. seems inconsistent naming here
@@ -0,0 +1,89 @@ | |||
"use strict"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet. Divide listeners and functions
element.addEventListener(event, listener);
Look below, the listener is bold
function showMuseumInfoByClick(museums, content, menu) { menu.addEventListener("click",function ({ target }) { if (target.tagName.toLowerCase() === "button") { const currentContentObject = museums.filter( ({ btnName }) => btnName === target.textContent ); renderArticle(currentContentObject[0], content); } }); }
</div> | ||
<div class="additional-wrapper"> | ||
<p class="museum-link"> | ||
<span>Visit </span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why span? you can leave this text without wrapping in a tag
const contentHTML = ` | ||
<h2 class="museum-title">${name}</h2> | ||
<div class="desc-wrapper"> | ||
<img class="museum-image" src="${imageSrc}" alt="photo of museum"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alt
should be moved to data.js
as one of the paramters, because it can't be the same for different images
New chnages added, but some questions left. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much better now, great job!
Some small changes left. And about the hover effect on switchTheme button. All interactive elements should have pointer
cursor on hover
|
||
function showMuseumInfo({ target }) { | ||
if (target.tagName.toLowerCase() === "button") { | ||
const currentContentObject = museums.filter( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can try to use spread here
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
} | ||
|
||
function showMuseumInfo({ target }) { | ||
if (target.tagName.toLowerCase() === "button") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do not use .closest
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also better to prevent rendering when you click on the same button which already selected
|
||
themeSwitcher.addEventListener("change", toggleDarkClass); | ||
dropdownBtn.addEventListener("click", openDropdownMenu); | ||
listMenu.addEventListener("click", showMuseumInfo); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good article to understand the events bubbling process
https://javascript.info/bubbling-and-capturing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks
Added latest changes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make last small improvements ;)
const contentBody = document.getElementById("content"); | ||
|
||
function renderButtons(museumsObj, menu) { | ||
let buttonsHTML = museumsObj |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you have plural, better name it like buttonsListHtml
|
||
function showMuseumInfo({ target }) { | ||
if (target.closest(".btn-text")) { | ||
let currentSelectedBtn = target.closest(".nav-item"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can move it higher and then make instead of two one if
statement
let currentSelectedBtn = target.closest(".nav-item"); | ||
if (!currentSelectedBtn.classList.contains("active")) { | ||
const [currentContentObject] = museums.filter( | ||
({ btnName }) => btnName === target.textContent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better use id
to identify the target item, not the text. For example, we can have two items with the same button name. So, in such cases we should always use id for DOM manipulation
Added new changes accordingly to remarks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, I guess :) Good job 👍
Document Object Model - practice
Demo |
Code base
The code is submitted in a dedicated feature branch.
Only code files are submitted.
Please, review.