user8987378
user8987378

Reputation: 332

how to make dialog like google keep in pure js and css

how can i create dialog effect like google keep.i tried to debug the css but without any success. is there code example out there ?

i see that they using hidden position fixed modal that triggering on click but how they calculate the position.

modal open animation

modal open

modal close

Upvotes: 0

Views: 1656

Answers (4)

Samer
Samer

Reputation: 21

I did like the example above, wich worked perfectly. I added opacity to de card selected to remove erase the card from the screen when it is clicked

<style type="text/css">

    body {
        display: flex;
        flex-wrap: wrap;
        width: 100%;
        color: #333;
    }

    .note {
        flex: 0 0 200px;
        width: 200px;
        height: 200px;

        border: 1px solid #CCC;
        margin: 12px;
        border-radius: 10px;
    }

    .modal-container {
        display: none;

        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;

        background-color: rgba(33, 33, 33, 0.5);
    }

    .modal-container--open {
        display: block;
    }

    .modal {
        position: absolute;
        top: 150px;
        left: 50%;
        margin-left: -300px;
        width: 600px;
        height: 150px;

        transform-origin: top left;
        will-change: transform;
        /* makes the animation run smoother */

        background-color: #EEE;
        border-radius: 10px;
    }
</style>
<script type="text/javascript">
    function openModal(noteEl, modalEl, modalContainerEl) {
        // Compute and apply the transform to deform the modal to cover the note with a transition to make it animate
        const transform = computeTransform(noteEl);
        modalEl.style.transform = transform;
        modalEl.style.transition = 'transform 250ms';

        // Setup the modal background animate in too
        modalContainerEl.style.backgroundColor = 'transparent';
        modalContainerEl.style.transition = 'background-color 250ms';

        // Show the modal
        modalContainerEl.classList.add('modal-container--open');
        noteEl.style.opacity = 0;

        // Put the rest in a setTimeout to allow the styles applied above to take
        // affect and render before we overwrite them with new ones below
        setTimeout(function () {
            // Remove the transform to allow the modal to return to it's natural shape and position
            modalEl.style.transform = 'none';
            modalContainerEl.style.backgroundColor = 'rgba(33, 33, 33, 0.5)';
        }, 0)
    }

    function computeTransform(noteEl) {

        // Modal positions here are hardcoded to match styles set in CSS
        const modalTop = 150;
        const modalLeft = (document.body.offsetWidth / 2) - 300;
        const modalWidth = 600;
        const modalHeight = 150;

        // Get note div's position relative to the viewport
        const notePosition = noteEl.getBoundingClientRect();

        // Compute a CSS transform that moves the modal to match the note's position
        const translateX = notePosition.left - modalLeft;
        const translateY = notePosition.top - modalTop;
        const scaleX = notePosition.width / modalWidth;
        const scaleY = notePosition.height / modalHeight;

        return `translateX(${translateX}px) translateY(${translateY}px) scaleX(${scaleX}) scaleY(${scaleY})`;
    }

    // Handle click events using event delegation
    let cardSelected;
    document.addEventListener('click', function (event) {
        // Handle click events on note elements (open modal)
        if (event.target.className === 'note') {
            // Get a reference
            cardSelected = event.target
            const modalContainerEl = document.querySelector('.modal-container');
            const modalEl = document.querySelector('.modal');
            openModal(event.target, modalEl, modalContainerEl);
        }

        // Handle click event on modal background element (close modal)
        if (event.target.classList.contains('modal-container')) {
            event.target.classList.remove('modal-container--open');
            cardSelected.style.opacity = 1;
        }
    })


</script>
<div class="note">1</div>
<div class="note">2</div>
<div class="note">3</div>
<div class="note">4</div>
<div class="note">5</div>
<div class="note">6</div>
<div class="note">7</div>
<div class="note">8</div>
<div class="note">9</div>
<div class="note">10</div>
<div class="note">11</div>
<div class="note">12</div>
<div class="note">13</div>
<div class="note">14</div>
<div class="note">15</div>
<div class="note">16</div>
<div class="note">17</div>
<div class="note">18</div>
<div class="note">19</div>
<div class="note">20</div>

<div class="modal-container">
    <div class="modal">
        Modal
    </div>
</div>

Upvotes: 2

Aman Chadha
Aman Chadha

Reputation: 2496

This is what i could make out of your question(pure JS and CSS). enter image description here

Below is the code

var example_note = document.getElementsByClassName('example_note')[0];
var close_btn = document.getElementById('close_btn');
example_note.onclick = function() {
  document.getElementsByClassName('background_change')[0].style.display = "block";
  document.getElementsByClassName('display_block')[0].style.display = "block";
  example_note.style.display="none";
}

close_btn.onclick = function() {
  document.getElementsByClassName('background_change')[0].style.display = "none";
  document.getElementsByClassName('display_block')[0].style.display = "none";
  example_note.style.display="block";
}
* {
  margin: 0px;
  padding: 0px;
  font-family: 'arial';
}

.example_note {
  position: absolute;
  width: 250px;
  margin-top: 10%;
  margin-left: 15%;
  box-shadow: -1px 1px 10px 3px rgba(0, 0, 0, 0.2);
  -webkit-box-shadow: -1px 1px 10px 3px rgba(0, 0, 0, 0.2);
  -moz-box-shadow: -1px 1px 10px 3px rgba(0, 0, 0, 0.2);
  padding: 30px;
  border-radius: 15px;
  background-color: white;
}

.example_note h1 {
  font-size: 23px;
}

.display_block {
  display: none;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 450px;
  background-color: white;
  padding: 30px;
  border-radius: 15px;
  transform-origin: 0 25%;
  animation: show_block 0.2s 1;
}

@keyframes show_block {
  from {
    transform: translate(-50%, -50%)scale(0);
  }
  to {
    transform: translate(-50%, -50%)scale(1);
  }
}

input[type="text"] {
  width: 390px;
  padding: 10px;
  border: none;
}

input[type="text"]:focus {
  outline: none;
}

button {
  float: right;
  background-color: white;
  padding: 10px 20px 10px 20px;
  border-radius: 8px;
  border: none;
  font-size: 17px;
  transition: 0.4s;
  font-weight: bold;
  outline: none;
}

button:hover {
  background-color: #E3E3E3;
}

.background_change {
  display: none;
  height: 100%;
  width: 100%;
  position: absolute;
  background-color: black;
  opacity: 0.6;
  animation: show_back 0.5s 1;
}

@keyframes show_back {
  from {
    opacity: 0;
  }
  to {
    opacity: 0.6;
  }
}
<div class="example_note">
  <h1>Example Note</h1>
</div>
<div class="background_change"></div>
<div class="display_block">
  <input type="text" name="title" placeholder="Title" style="font-size: 25px;">
  <br>
  <input type="text" name="name" value="Example Note" style="font-size: 15px; font-weight: bold;">
  <br>
  <button id="close_btn">close</button>
</div>

Upvotes: 4

Nico Burns
Nico Burns

Reputation: 17099

This answer is plain JavaScript and CSS (no libraries), and produces the following effect:

enter image description here

A full working example is contained in the following snippet (best previewed full screen):

function openModal(noteEl, modalEl, modalContainerEl) {

        // Compute and apply the transform to deform the modal to cover the note with a transition to make it animate
        const transform = computeTransform(noteEl);
        modalEl.style.transform = transform;
        modalEl.style.transition = 'transform 250ms';

        // Setup the modal background animate in too
        modalContainerEl.style.backgroundColor = 'transparent';
        modalContainerEl.style.transition = 'background-color 250ms';

        // Show the modal
        modalContainerEl.classList.add('modal-container--open');

        // Put the rest in a setTimeout to allow the styles applied above to take
        // affect and render before we overwrite them with new ones below
        setTimeout(function () {
          // Remove the transform to allow the modal to return to it's natural shape and position
          modalEl.style.transform = 'none';
          modalContainerEl.style.backgroundColor = 'rgba(33, 33, 33, 0.5)';
        }, 0)
      }

      function computeTransform(noteEl) {

        // Modal positions here are hardcoded to match styles set in CSS
        const modalTop = 150;
        const modalLeft = (document.body.offsetWidth / 2) - 300;
        const modalWidth = 600;
        const modalHeight = 150;

        // Get note div's position relative to the viewport
        const notePosition = noteEl.getBoundingClientRect();
        
        // Compute a CSS transform that moves the modal to match the note's position
        const translateX = notePosition.left - modalLeft;
        const translateY = notePosition.top - modalTop;
        const scaleX = notePosition.width / modalWidth;
        const scaleY = notePosition.height / modalHeight;

        return `translateX(${translateX}px) translateY(${translateY}px) scaleX(${scaleX}) scaleY(${scaleY})`;
      }

      // Handle click events using event delegation
      document.addEventListener('click', function (event) {

        // Handle click events on note elements (open modal)
        if (event.target.className === 'note') {

          // Get a reference
          const modalContainerEl = document.querySelector('.modal-container');
          const modalEl = document.querySelector('.modal');
          openModal(event.target, modalEl, modalContainerEl);
        }

        // Handle click event on modal background element (close modal)
        if (event.target.classList.contains('modal-container')) {
          event.target.classList.remove('modal-container--open');
        }
      })
body {
        display: flex;
        flex-wrap: wrap;
        width: 100%;
        color: #333;
      }

      .note {
        flex: 0 0 200px;
        width: 200px;
        height: 200px;

        border: 1px solid #CCC;
        margin: 12px;
        border-radius: 10px;
      }

      .modal-container {
        display: none;

        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;

        background-color: rgba(33, 33, 33, 0.5);
      }

      .modal-container--open {
        display: block;
      }

      .modal {
        position: absolute;
        top: 150px;
        left: 50%;
        margin-left: -300px;
        width: 600px;
        height: 150px;
        
        transform-origin: top left;
        will-change: transform; /* makes the animation run smoother */

        background-color: #EEE;
        border-radius: 10px;
      }
<!DOCTYPE html>
<html>
  <head>
    <style type="text/css" />

      

    </style>
    <script type="text/javascript">
      
      

    </script>
  </head>
  <body>
    <div class="note">1</div>
    <div class="note">2</div>
    <div class="note">3</div>
    <div class="note">4</div>
    <div class="note">5</div>
    <div class="note">6</div>
    <div class="note">7</div>
    <div class="note">8</div>
    <div class="note">9</div>
    <div class="note">10</div>
    <div class="note">11</div>
    <div class="note">12</div>
    <div class="note">13</div>
    <div class="note">14</div>
    <div class="note">15</div>
    <div class="note">16</div>
    <div class="note">17</div>
    <div class="note">18</div>
    <div class="note">19</div>
    <div class="note">20</div>

    <div class="modal-container">
      <div class="modal">
        Modal
      </div>
    </div>
  </body>
</html>

The trick is to apply a CSS transform to the modal in order to deform into the shape/position of the clicked note before showing the modal. We can then remove the transform and use a CSS transition to get it to smoothly animate into it's natural shape/position.

We calculate the transform as follows:

function computeTransform(noteEl) {

  // Modal positions here are hardcoded to match styles set in CSS
  const modalTop = 150;
  const modalLeft = (document.body.offsetWidth / 2) - 300;
  const modalWidth = 600;
  const modalHeight = 150;

  // Get note div's position relative to the viewport
  const notePosition = noteEl.getBoundingClientRect();
  
  // Compute a CSS transform that moves the modal to match the note's position
  const translateX = notePosition.left - modalLeft;
  const translateY = notePosition.top - modalTop;
  const scaleX = notePosition.width / modalWidth;
  const scaleY = notePosition.height / modalHeight;

  return `translateX(${translateX}px) translateY(${translateY}px) scaleX(${scaleX}) scaleY(${scaleY})`;
}

And we apply it as follows:

function openModal(noteEl, modalEl, modalContainerEl) {

  // Compute and apply the transform to deform the modal to cover the note with a transition to make it animate
  const transform = computeTransform(noteEl);
  modalEl.style.transform = transform;
  modalEl.style.transition = 'transform 250ms';

  // Setup the modal background animate in too
  modalContainerEl.style.backgroundColor = 'transparent';
  modalContainerEl.style.transition = 'background-color 250ms';

  // Show the modal
  modalContainerEl.classList.add('modal-container--open');

  // Put the rest in a setTimeout to allow the styles applied above to take
  // affect and render before we overwrite them with new ones below
  setTimeout(function () {
    // Remove the transform to allow the modal to return to it's natural shape and position
    modalEl.style.transform = 'none';
    modalContainerEl.style.backgroundColor = 'rgba(33, 33, 33, 0.5)';
  }, 0)
}

Note the setTimeout between applying and removing the transform. This is important as otherwise the transform will never actually be applied.

See the snippet for the full details, but also of note: the transform-origin: top left; style on the modal is important to make the transform computation work.

Upvotes: 3

Krokodil
Krokodil

Reputation: 1480

To create a modal, you can use a library called Swal. Swal, however does not look like keep's popups, so I've restyled it below.

script links you must reference to:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@sweetalert2/theme-material-ui/material-ui.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>.
You may also wish to visit Google Fonts and pick a nice font-family. Test this pop-up by clicking run this snippet.

const MySwal = Swal.mixin({
    //background: "rgb(10,10,10)",
    background: "white",
    showCloseButton: true,
    backdrop: "rgba(0,0,0,0.7)",


    showClass: {
        popup: "animate__animated animate__fadeInDown med"
    },

    hideClass: {
        popup: "animate__animated animate__fadeOutUp fast"
    },

    width: "95vw"

});
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.js" integrity="sha512-HBD0cOZJYcymSn0H0CnN3VBhQLdiH8imucm16ZQ792TT2n48u6nmX+T7hZTCwmzIrgMt76x4rHhR7KkZqhIGxA==" crossorigin="anonymous"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

    <meta charset="UTF-8">
    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
    <script src="alpha.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
    <link rel="shortcut icon" href="favicon.png" id="iconshort">


    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@sweetalert2/theme-material-ui/material-ui.css">



    <script src='https://kit.fontawesome.com/a076d05399.js'></script>
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300&display=swap" rel="stylesheet">
</head>

<body>
<button onclick="MySwal.fire('Title','Content')">LAUNCH POP-UP</button>
</body>

const MySwal = Swal.mixin({
    //background: "rgb(10,10,10)",
    background: "white",
    showCloseButton: true,
    backdrop: "rgba(0,0,0,0.7)",


    showClass: {
        popup: "animate__animated animate__fadeInDown med"
    },

    hideClass: {
        popup: "animate__animated animate__fadeOutUp fast"
    },

    width: "95vw",

    willOpen: function() {
        open_audio.play();
    },

    willClose: function() {
        confirm_audio.play();
    }

});

Upvotes: 0

Related Questions