Skip to content
  • Unlock Pro
  • Log in with GitHub
Profile
OverviewSolutions
3
Comments
9

ricardoychino

@ricardoychinoBrazil190 points

I’m a mysterious individual who has yet to fill out my bio. One thing’s for certain: I love writing front-end code!

Latest solutions

  • Comments Section w/ Vue 3 + Pinia + TS + SCSS + Toasts

    #pinia#sass/scss#typescript#vue#vite

    ricardoychino•190
    Submitted 10 months ago

    First of all, please have fun playing with the layout. It was pretty fun to code and I am quite satisfied with the outcome. Then as always, any feedback is welcome.

    But the most important thing(s) that I want help:

    [TypeScript] Do you recommend some good resources or do you have some tips for typing error handling in catch block? And what about API responses? This would help me a lot

    [Tests] I started some testing in project with vitest + vue-test-utils, but I didn't have the patience to write every test case I was thinking of, and one of the main reasons that I stopped trying is that I was spending too much time looking for references and usage examples in their documentation (I'm kind of new to automated tests).So if you may recommend any resources, cheatsheet, alternative documentation or something like that, I would greatly appreciate it


    0 comments
  • IP Tracker with Vue 3 (Composables, Pinia, Axios, Leaflet.js, TS)

    #pinia#sass/scss#typescript#vue#axios

    ricardoychino•190
    Submitted 10 months ago

    There are some points:

    • [TypeScript] The declaration of types at src/types/GeolocationAPI.d.ts and their usage at src/stores/ip-tracking.ts and src/composables/useGeolocationAPI.ts. Are they ok or it could be better in some another way?
    • [TypeScript] I'd love some feedback about the use of generics at src/composables/useCachedResponses.ts
    • [Pinia] This is the first time I use Pinia for anything, so I'm not sure if it is organized enough since it is kind different with the Vuex
    • [SCSS] If there are some alternative ways to apply the styles inside the components, I'd like to hear
    • [Logic] The overall feedback of the logic, if possible. What you'd do different, what could be better, I'd like to know

    0 comments
  • Job Listing with Vue 3 using composables

    #sass/scss#typescript#vue#vite

    ricardoychino•190
    Submitted 10 months ago

    The logic in the useTagFilter. I created an internal Set where each filter applied is added as a string containing the property name and value (for example, 'tools-Vue'), because if the entries are created by the user typing the values, it is possible that 'Vue' could be added as a language instead of tool or something like that. That said, I return a mapped array removing the key from the string.

    I see some problems with that approach:

    • I maintained the list filtering logic (the function isResult()) inside the composable
    • Too many items on the object returned by the composable
    • In the CurrentFilters.vue component, there's no way to know from which property that value is, and that's why I created a keysByValue map. But I feel that it was pretty much unnecessary and waste of memory
    • In localStorage, the full joined string is saved, ie. tools-React,tools-Vue,contract-Full Time for example. Saving only the values would be much more functional, but if I do so, the problem is to know from which property that value is

    I wanted some feedbacks or insights about that logic, because while I am happy that I finished it and it is functional, I can see that there are bunch of flaws and I feel this is not a optimal approach


    0 comments

Latest comments

  • Marcone Silva de Brito•80
    @marconesdb
    Submitted 9 months ago
    What are you most proud of, and what would you do differently next time?

    Estou mais orgulhoso da forma como o Tailwind CSS foi utilizado para acelerar o desenvolvimento e estilização do projeto. Utilizando um framework CSS utilitário como o Tailwind, pude aplicar classes diretamente no HTML, o que tornou o processo mais ágil e modular. Outro ponto de destaque foi a personalização do arquivo CSS externo, onde defini cores personalizadas usando HSL e configurei fontes específicas. Essa customização permitiu manter consistência no design e fácil manutenção do código.

    What challenges did you encounter, and how did you overcome them?

    Na próxima vez, investiria mais tempo na acessibilidade do projeto, como a implementação de descrições mais detalhadas para leitores de tela e testes com ferramentas de acessibilidade. Também gostaria de explorar temas escuros e claros configuráveis no Tailwind, permitindo uma experiência mais adaptativa ao usuário. Usaria também componentização com frameworks como React ou Vue para criar componentes reutilizáveis em vez de depender de uma única página HTML estática.

    What specific areas of your project would you like help with?

    Um dos principais desafios foi compilar e configurar o Tailwind CSS corretamente. O problema estava relacionado ao escopo dos caminhos definidos na propriedade content do arquivo de configuração, que não apontava corretamente para os arquivos HTML. Outro desafio menor foi garantir que o JavaScript fosse simples e funcional. Eu queria adicionar uma funcionalidade de redirecionamento ao clicar na imagem do QR code. A solução foi usar JavaScript puro (Vanilla JS) com um simples evento addEventListener, resolvendo o problema sem a necessidade de frameworks adicionais.

    Tailwind CSS Framework, HTML Semântico, Utilizei classes utilitárias.

    #accessibility
    2
    ricardoychino•190
    @ricardoychino
    Posted 9 months ago

    Marcones,

    Primeiramente, parabéns pela solução. Sobre o que você citou de redirecionamento ao clicar na imagem, seria melhor você só ter adicionado um <a> envolvendo a imagem. Por alguns motivos:

    1. Mais simples, sem "trabalho" adicional
    2. Semântica
    3. Até uma questão de segurança e confiabilidade/usabildiade. Ao passar o cursor na imagem, o <a> vai permitir que o navegador mostre pra onde o usuário vai ser redirecionado ao clicar na imagem. Se um usuário clica sem querer e é levado a um site externo, é uma ação inesperada. O destino neste caso é um site confiável, ok. Mas poderia muito bem ser um spam, então o ideal é, se possível, usar o <a> para que o navegador possa informar qual o destino
    4. Manutenção. Digamos que algum outro dev vai trabalhar no mesmo projeto e recebeu a task de fazer a alteração do link, a primeira coisa que ele vai procurar é o <a>. Não encontra. Vai levar um tempo extra pra encontrar onde está sendo feito esse redirecionamento. Neste caso o projeto é pequeno, mas imagine em um projeto grande, num arquivo JS com 15000 linhas. É um pouco mais trabalhoso.

    No mais, bem-vindo e tenha uma boa experiência com os projetos

  • 1deadjoe•370
    @1deadjoe
    Submitted 9 months ago
    What are you most proud of, and what would you do differently next time?

    I am proud that I am getting better at SCSS. It is easier to avoid repitition using mixins, extend, etc.

    What challenges did you encounter, and how did you overcome them?

    I got too focused on the styling that I somehow got lost with the JS. Not being able to follow what class to call was wracking.

    What specific areas of your project would you like help with?

    I would greatly appreciate if someone could help me identiy where to use JS to add the interactivity. I did not know how to place the items in the header in order to get the desired effect.

    LOOPSTUDIOS LANDING PAGE USING HTML AND SCSS

    #sass/scss#accessibility
    3
    ricardoychino•190
    @ricardoychino
    Posted 9 months ago

    Hi,

    Congratulations! That's a great looking solution. Very readable and good semantics, too!

    There are two things that caught my attention that I'd like to point out:

    1. At hero section, I think it would be better if you just use background property to apply the image instead of using a <picture> with position: absolute;. It is easier to handle an image change or if the image doesn't have the dimensions that fits the section. As for the responsive source of the images, you can always use a media query.

    2. Initially I was intending to recommend the selector :nth-child() for the section where you have the products, instead of using selectors .product-{n}, but actually I don't think you need to set the grid properties from lines 374 to 391 and 425 to 440 in your main.scss. I disabled those properties on devtools and your design is still looking great! The only one that I kept is the grid-template-columns: repeat(4, 1fr); for desktop viewing. Why did I point this out? Because, let's assume you need to add another product eventually. You will then probably need to add a .product-9 rule to your CSS, or use one of the currently created .product-{n} on it. Either way, there are disadvantages: maintainability or consistency, respectively. If you remove those styling, the style will still be as you intended and there's no need to worry in case you need to add or remove new items

    About the JS interactivity:

    It seems like it's pretty much halfway done and that only needs to add a JS interaction. With your current code, I'd start adding a event listener to the button which adds (or in your current code's case, remove) a class to handle visibility of the menu, such as:

    /*
      This adds a reference to the target elements
      (This is optional, but I personally believe that this 
      makes the code a bit cleaner)
    */
    const buttonElement = document.getElementById('menu')
    const navElement = document.querySelector('.header-nav')
    
    /* Adds the event listener for clicks to the <button> */
    buttonElement.addEventListener('click', () => {
      // Check if nav is hidden
      if (navElement.classList.contains('hidden')) {
        navElement.classList.remove('hidden') // Shows nav
        buttonElement.querySelector(':scope .open').classList.add('hidden')  // Hide the hamburger icon
        buttonElement.querySelector(':scope .close').classList.remove('hidden') // Shows the close icon
      } else {
        navElement.classList.add('hidden')  // Hides nav
        buttonElement.querySelector(':scope .open').classList.remove('hidden')  // Shows the hamburger icon
        buttonElement.querySelector(':scope .close').classList.add('hidden') // Hide the close icon
      }
    })
    

    This is enough to toggle the show/hide in your current code and continue to style further or change the structure if you want to. You will see that the styling will need some adjusts after applying that toggling. I'd change a little this approach, but the way you did works fine as well.

    I hope this is what you needed and that it helps. I apologize if it didn't. Again, great job and keep it up!

    Marked as helpful
  • GiorgiOsha95•100
    @GiorgiOsha95
    Submitted 9 months ago
    What are you most proud of, and what would you do differently next time?

    i had tried to use SASS/SCSS for this project instead of simple CSS and tried writing semantic HTML.

    What specific areas of your project would you like help with?

    Should I use less class names for elements when writing in sass or it's still easier to read with many class names specifically when writing in sass?

    Social links profile main

    #sass/scss
    1
    ricardoychino•190
    @ricardoychino
    Posted 9 months ago

    Hey, great solution!

    As for your question, in my experience and it is kind of a consensus as far as I know that usually it is a good idea to use classes for styling. Classes makes the selection more specific, and also you can get a general idea of what the purpose of the rule you wrote. Think this way:

    .profile-avatar {  /* "Oh okay, this is CSS for profile avatar" */
      ...
    }
    img {    /* "What, which image?" (Imagine that in a real project you WILL have more than one eventually) */
    }
    

    In your solution, for example, there are some element selectors, but it is not that abstract, since they are nested in more specific selectors. So in my humble opinion you just did great.

    The only thing that I would change is the rule for *. Separate them like this:

    * {
      box-sizing: border-box;
    }
    body {
      margin: 0;
      padding: 0;
      font-size: 14px;
      font-family: "Inter", sans-serif;
    }
    /* This one depends on the project: */
    ul {
      list-style-type: none;
    }
    

    The * will apply the properties on every single element unnecessarily. The box-sizing is a good idea to apply, but the others like font properties will be inherited anyway; and if you decide to use a <small> for example, the font-size: 14px; will be applied to it, which is not a good idea. About the box model properties, I actually am not sure if there's any problem applying the reset on *, but usually they are already 0s, so if you want to reset them, reset only where it is needed.

    Anyway, just my thoughts. Good job and keep it up

  • Salim•360
    @limsael
    Submitted 9 months ago
    What specific areas of your project would you like help with?
    • The share message display and position

    article preview component, html sass

    #sass/scss
    1
    ricardoychino•190
    @ricardoychino
    Posted 9 months ago

    Hi, good job finishing the challenge!

    About displaying and positioning, I am looking at the styling and I think the approach is a little bit overcomplicated. It could be simpler. It is awesome that you learned and applied clip-path property (I myself don't really know how to use it, to be honest), but I think you could get the desired result without it.

    But first, I think it is better to wrap the whole button .card__profile--share inside the <a> tag, because currently the "tooltip" opens only when the icon per se is clicked, not the "button" (.card__profile--share) - if the user clicks on the padding, for example, nothing really happens. That requires certain precision from the user, and that could led to some bad experience. So I recommend wrapping the whole button with the anchor tag. Also, as a bonus I'd define a height and width to make it a perfect circle. It is a bit elliptical currently.

    Now about the approach, I think you could:

    (1) Remove the margins from .card__action ("SHARE" text) and .card__socials--links (the social icons wrapper)

    (2) Reduce the vertical padding from .card__profile--social, perhaps to:

    padding: 0.75rem 2.25rem;
    

    This makes the tooltip visual fine, and with simple styling

    (3) Now let's add the "tail" of the tooltip. You can do this by adding a pseudo-element ::after to the "tooltip" component, just like:

    .card__profile--social::after{
      /* Part 1 */
      content: "";
    
      /* Part 2 */
      position: absolute;
      top: 100%;
      left: calc(50% - 10px);
    
      /* Part 3 */
      border-top: 15px solid hsl(217, 19%, 35%);
      border-left: 10px solid transparent;
      border-right: 10px solid transparent;
    }
    

    Let me explain the rule above in parts:

    Part 1: Pseudo-elements always needs a content property, even if it is empty. If you don't add it to the rule, the browser will just ignore it

    Part 2: We need to position it relative to the content. As a pseudo-element is a child of the content and that content has the position defined, we just add position: absolute on it to position it as we wish. top: 100% will position it right after the parent, as it jumps the full size of the parent. left: calc(50% - 10px) will position it centered horizontally (50% of the parent width minus the half of its own size). This positioning makes it dynamic, so even if you need to change the content of the tooltip that will change its size later on the future, you won't need to redefine all these properties

    Part 3 This will define the shape of the "tail" per se. The border-top will be the "tail", with the same color as the content, and the border-width (15px) is what will define how long the tail will be. The border-left and border-right are needed to give it a triangular shape. Changing their width (10px) will make the tail wider or thinner. Change them as you wish

    (4) Now for the final touch, it would be really helpful if we could split the .card__profile--social into two elements, such as:

    <div class="card__profile--social" id="card-social">
      <div class="card__profile--social-wrapper">
        <!-- p.card__action and div.card__socials -->
      </div>
    </div>
    

    This way we can split the responsibilities, .card__profile--social for the visibility and positioning relative to father "button", and .card__profile--social-wrapper for the styling and positioning. The result will be something like:

    .card__profile--social {
      position: absolute;
      bottom: calc(100% + 10px); /* Position of the whole component */
      left: 50%; /* Right to the middle of the "button" */
      visibility: hidden;
    }
    .card__profile--social-wrapper {
      padding: 0.75rem 2.25rem; /* The padding I mentioned before on (2) - we move to this rule */
      margin-left: -50%; /* This will help position the tooltip right to the middle of "button" */
      width: 100%;
      position: relative; /* We need this to position the "tail" */
    
      /* The others are properties that already existed in .card__profile--social and I moved to this wrapper/styling class */
      background-color: hsl(217, 19%, 35%);
      display: flex;
      align-items: center;
      gap: 1.5rem;
      border-radius: 0.5rem;
    }
    
    /* Let's move the "tail" ::after pseudo-element to the new element too */
    .card__profile--social-wrapper::after {
      content: "";
      position: absolute;
      top: 100%;
      left: calc(50% - 10px);
      border-top: 15px solid hsl(217, 19%, 35%);
      border-left: 10px solid transparent;
      border-right: 10px solid transparent;
    }
    
    /* Remove the margins as I mentioned on (1) */
    .card__action {
      color: hsl(0, 0%, 100%);
      opacity: 0.7;
      text-transform: uppercase;
      letter-spacing: 3px;
    }
    .card__socials--links {
      display: flex;
      align-items: center;
      gap: 0.75rem;
    }
    

    The point of adding a new element is that the parent .card__profile--social will have the size of its content, and we can use it to apply the margin-left: -50% on .card__profile--social-wrapper to center it inside the parent. If we don't add the new element, the parent will be the "button" element (.card__profile--share), which has a smaller size. Since the % always are proportional to the element's parent, the margin-left won't have the desired result.

    I'm sorry for the lengthy comment, but I think this is the most common and a more dynamic approach. I hope this helps! Good job and keep it up!

  • John Tan•140
    @JohnEdgiTan
    Submitted 10 months ago
    What are you most proud of, and what would you do differently next time?

    Use frameworks like React or Angular

    What challenges did you encounter, and how did you overcome them?

    So far, the greatest challenged I faced was doing the buttons that changes when hovered.

    What specific areas of your project would you like help with?

    Although I have completed the challenge, I would very much appreciate any comments that can help me learn more. Specially for the part of adding contents to the order where the total quantity stays as it is instead of fading when mouse is not hovered any more on the button. Thank you.

    Product List with Cart using HTML CSS Javascript and SCSS

    #sass/scss
    1
    ricardoychino•190
    @ricardoychino
    Posted 10 months ago

    Hello,

    Congratulations with your solution, it looks very nice. Just want to point out some things that I found:

    1 - As the quantity of the products are already initiated with 1, it is a little bit confusing in terms of usability when you click and you don't have a visual feedback on the button (we can see it showing up at the cart, sure, but it forces us to spread our range of vision where we need to focus, causing certain negative experience). I suggest:

    • starting the initial quantity with 0

    • instead of controlling which component to appear (button or quantifier) by hover, control them by classes or another atribute, only changing them if the quantity of that product is zero (shows the button 'Add to cart') or has one or more items (quantifier). When we have at least one item of that product in the cart, it is already there, so personally I think showing 'Add to cart' makes less sense than showing the quantifier. And also, I think it gives you a better visual feedback that indicates that the product is already in the cart (currently we need to hover the button to see if the quantity is greater than 1 - one more reason why it could be better to start the counter with 0 - or compare the name of the product with the name of the items in the cart)

    2 - When you remove a product directly from your cart, the quantifier of the product didn't reset. You did the splice in removeItemFromCart, but didn't alter the quantity on the product list

    3 - For the cart's data structure, personally I'd go with a Map instead of an array, here's why:

    • You wouldn't need anymore to check positionThisProductInCart in your methods. Use the ID of the product as key and the quantity as its value. For example:
    // Declare the cart
    const cart = new Map() // or Map<number, number>() if you're using TS
    
    // Add or sum up quantity
    cart.set(+productId, (cart.get(+productId) || 0) + 1)
    // - `+productId` to convert to a number in case the variable is a string
    // - The cart.get there is to get the current quantity. If it is not included, is 0
    
    // Subtract from cart
    if (cart.has(+productId)) {
      cart.set(+productId, cart.get(+productId) - 1)
    }
    
    // Remove from cart
    cart.delete(+productId)
    
    // Iterate over it
    [...cart.entries()].forEach(item => {
      // entries() gives you an iterable with the pair [key, value], so:
      // item[0] == product ID
      // item[1] == quantity
      totalQuantity = totalQuantity +  item[1]
      ...
      newItem.dataset.id = item[0];
    })
    
    • The entries are also already sorted by the order you added the item, so it is timeline-faithful (? sorry, I'm not sure if I expressed well)

    • Maps are more performant

    • for sure will save you from writing some additional code there.

    You could use a Map to store your products, too, using the product ID as a key and the object of the product as value:

    // At initApp():
    data.forEach(item => {
      product.set(item.id, item)
    })
    
    // At addDataToHTML():
    [...products.values()].forEach(product => ....)
    

    An example of performance improvement within the function addCartToHTML:

    let info = products.get(item.product_id)
    

    That single line could substitute the block:

    let positionProduct = products.findIndex((value) => value.id == item.product_id);
    let info = products[positionProduct];
    

    You don't need anymore to travel the array of products to find its info! If we have thousands of products, it could take some time to find each product in cart

    What do you think? I hope it helps. Cheers

    P.S.: The link to your repository ends up in a 404 page. Maybe it is not set as public? If we could read the code on GitHub, that certainly helps - I did this in the browser's inspector

  • Dei•60
    @deidalopez
    Submitted 10 months ago
    What are you most proud of, and what would you do differently next time?

    I like the structure of the project since I think its readable, and easy to follow. I am also glad to have found the CSS Reset from Josh Comeau https://www.joshwcomeau.com/css/custom-css-reset/.

    However, I didnt spend too much time with the font scaling since it was readable regardless, so maybe in a future project I'll implement it.

    I also struggled because I didnt have the Figma files, but I'm still proud about how close it got.

    What challenges did you encounter, and how did you overcome them?

    Working with images has been a challenge for me, so it was a lot of troubleshooting to get the image to fit correctly... I dont know how close I got, but it got to a better place than it was haha.

    What specific areas of your project would you like help with?

    I guess if anyone has any resources for image styling?

    For example, I wanted the image to fit within the container, hoping that I wouldnt need to manually set the border radius for the corners of the image since I set the border radius on the parent div.

    Preview card

    2
    ricardoychino•190
    @ricardoychino
    Posted 10 months ago

    Hi,

    Nice job with the solution

    Regarding the image, let me explain: you added the object-fit: cover correctly. It indeed makes the image fit within the container. But it is not being applied. This is because when using object-fit, the dimensions available must be clear and the overflow: hidden in the image is messing a little with the sizing of it. Also, the width should be 50% since it is supposed to have the half of the parent .container:

    .perfumeImg {
      width: 50%;
      object-fit: cover
    }
    

    That's enough to define the sizing of the image as half of the card, fitting inside that space.

    Now, as for having the same corners, the thing is that there's nothing wrong. It is fitting the space available, which is a rectangle without rounded corners! The rounded corner exists only on the parent, which is a completely different and independent element. The corner is visually altered, but it is there and the img element corner is matching the same position. So technically, it is correctly fitting the space available.

    So there are 2 options:

    1. Set the border on the image (as you did)
    2. Apply overflow: hidden on parent element, since they are the ones that have the rounded corner
    .container {
      border-radius: 1rem;
      overflow: hidden;  <-- add this
      ...
    }
    

    But keep in mind that sometimes the approach 1 will be better (if for some kind of design choice you NEED elements that get out and be visible outside parent div), and in others the 2 will have a best fit. In case of this solution, I'd go with the approach 2 so that we don't have to repeat code.

    Hope this helps.

    Marked as helpful
View more comments
Frontend Mentor logo

Stay up to datewith new challenges, featured solutions, selected articles, and our latest news

Frontend Mentor

  • Unlock Pro
  • Contact us
  • FAQs
  • Become a partner

Explore

  • Learning paths
  • Challenges
  • Solutions
  • Articles

Community

  • Discord
  • Guidelines

For companies

  • Hire developers
  • Train developers
© Frontend Mentor 2019 - 2025
  • Terms
  • Cookie Policy
  • Privacy Policy
  • License

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub