<!DOCTYPE html>
<html lang="ru">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Плавное расширение карточки через Grid</title>
    <style>
        * {
            box-sizing: border-box;
        }

        body {
            font-family: Arial, sans-serif;
            padding: 20px;
            margin: 0;
        }

        .grid-container {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
            gap: 16px;
            position: relative;
        }

        .card {
            background-color: #f0f0f0;
            padding: 20px;
            position: relative;
            cursor: pointer;
            z-index: 1;
            border-radius: 8px;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
            overflow: hidden;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            transition: height 500ms ease, background-color 500ms ease, transform 500ms ease;
            /* height: 160px; */
        }

        .card .expand-btn {
            margin-top: 10px;
            padding: 8px 12px;
            background-color: #007bff;
            color: white;
            border: none;
            cursor: pointer;
            transition: background-color 300ms ease;
            border-radius: 4px;
        }

        .card .expand-btn:hover {
            background-color: #0056b3;
        }

        /* Добавим стили для модального расширения */
        .card-clone {
            position: absolute;
            background-color: #d0eaff;
            border-radius: 8px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
            padding: 20px;
            transition: all 500ms ease;
            z-index: 1000;
            overflow: hidden;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            opacity: 1;
        }

        .card-clone .details {
            max-height: 500px; /* Достаточно большое значение */
            opacity: 1;
            margin-top: 10px;
            transition: height 500ms ease, background-color 500ms ease, transform 500ms ease, opacity 500ms ease;
        }

        .card-clone .collapse-btn {
            margin-top: 10px;
            padding: 8px 12px;
            background-color: #dc3545;
            color: white;
            border: none;
            cursor: pointer;
            transition: background-color 300ms ease;
            border-radius: 4px;
        }

        .card-clone .collapse-btn:hover {
            background-color: #c82333;
        }

        .card-clone.fade-out {
            opacity: 0;
            transform: scale(0.95);
        }
    </style>
</head>

<body>
    <div class="grid-container">
        <div class="card">
            <div class="content">Карточка 1</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 1...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 2</div>
            <div class="details" style="display:none;">
                <card data-open="true">
                    <card-data>
                        <div class="open_flag_header">
                        <span class="open_flag_index">AL</span>
                        <div class="open_flag_shortname">Албания</div>
                            <card-close></card-close>
                        </div>
                        <div class="open_flag_img">
                        <img class="lazy entered loaded" src="flags/PNG-1200/PNG-O/AL-O-1200.png" data-src="flags/PNG-1200/PNG-O/AL-O-1200.png" data-ll-status="loaded">
                        </div>
                        <div class="open_flag_longname">Республика Албания</div>
                        <div class="open_flag_names_container">
                        <span class="open_flag_original_lang">албанский</span>
                        <span>Republika e Shqipërisë</span>
                        </div>
                        <div class="open_flag_controls">
                        <div class="open_flag_proportions_container">
                        <span>Пропорции флага:&nbsp;</span>
                        <input type="radio" name="proportions_button" value="500m" onchange="makeCardImage(`AL`);" id="proportion_500m">
                        <label for="proportion_500m">1:2</label>
                        <input type="radio" name="proportions_button" value="0.67" onchange="makeCardImage(`AL`);" id="proportion_0.67">
                        <label for="proportion_0.67">2:3</label>
                        <input type="radio" name="proportions_button" value="750m" onchange="makeCardImage(`AL`);" id="proportion_750m">
                        <label for="proportion_750m">3:4</label>
                        <input type="radio" name="proportions_button" value="1.0" onchange="makeCardImage(`AL`);" id="proportion_1.0">
                        <label for="proportion_1.0">Квадрат</label>
                        <input type="radio" name="proportions_button" value="R" onchange="makeCardImage(`AL`);" id="proportion_R">
                        <label for="proportion_R">Круг</label>
                        <input type="radio" checked="" name="proportions_button" value="O" onchange="makeCardImage(`AL`);" id="proportion_O">
                        <label for="proportion_O">Оригинальные&nbsp;(5:7)</label>
                        </div>
                        <div class="open_flag_formats_container">
                        <span>Формат изображения:&nbsp;</span>
                        <input type="radio" name="formats_button" value="SVG" onchange="makeCardImage(`AL`);" id="format_SVG">
                        <label for="format_SVG">SVG</label>
                        <input type="radio" name="formats_button" value="PNG-30" onchange="makeCardImage(`AL`);" id="format_PNG-30">
                        <label for="format_PNG-30">PNG шириной 30&nbsp;пикселей</label>
                        <input type="radio" name="formats_button" value="PNG-120" onchange="makeCardImage(`AL`);" id="format_PNG-120">
                        <label for="format_PNG-120">PNG шириной 120&nbsp;пикселей</label>
                        <input type="radio" name="formats_button" value="PNG-360" onchange="makeCardImage(`AL`);" id="format_PNG-360">
                        <label for="format_PNG-360">PNG шириной 360&nbsp;пикселей</label>
                        <input type="radio" name="formats_button" checked="" value="PNG-1200" onchange="makeCardImage(`AL`);" id="format_PNG-1200">
                        <label for="format_PNG-1200">PNG шириной 1200&nbsp;пикселей</label>
                        <input type="radio" name="formats_button" value="PNG-2400" onchange="makeCardImage(`AL`);" id="format_PNG-2400">
                        <label for="format_PNG-2400">PNG шириной 2400&nbsp;пикселей</label>
                        </div>
                        </div>
                        <a class="open_flag_download" target="_blank" download="" href="flags/PNG-1200/PNG-O/AL-O-1200.png">Скачать&nbsp;флаг</a>
                        <div class="open_flag_colors_container">
                        <div class="open_flag_color" title="красный" style="background-color: #D91C16;">
                        </div>
                        <div class="open_flag_color" title="чёрный" style="background-color: #000000;">
                        </div>
                        </div>
                    </card-data>
                    <card-overlay></card-overlay>
                </card>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 3</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 3...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 4</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 4...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 5</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 1...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 6</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 2...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 7</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 3...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 8</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 4...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 9</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 1...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 10</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 2...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 11</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 3...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 12</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 4...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 13</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 1...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 14</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 2...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 15</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 3...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 16</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 4...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 17</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 1...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 18</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 2...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 19</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 3...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
        <div class="card">
            <div class="content">Карточка 20</div>
            <div class="details" style="display:none;">
                <p>Дополнительная информация для карточки 4...</p>
            </div>
            <button class="expand-btn">Развернуть</button>
        </div>
    </div>

<script>
    const gridContainer = document.querySelector('.grid-container');
    let expandedCard, currentClone, startRowWidth = null;
    let transitionDuration = 500; // соответствует длительности CSS (500ms)

    // Функция для получения верхней позиции элемента относительно документа
    function getTop(elem) {
        let box = elem.getBoundingClientRect();
        return (box.top + pageYOffset);
    }

    // Функция для получения карточек в той же строке
    function getCardsInSameRow(card) {
        const rect = card.getBoundingClientRect();
        const top = rect.top;
        const tolerance = 5; // пикселей допуска
        return Array.from(document.querySelectorAll('.card')).filter(c => {
            const cTop = c.getBoundingClientRect().top;
            return Math.abs(cTop - top) < tolerance && c !== card;
        });
        // я в шоке с того, какой это тупой метод, но работает
    }

    // Обработчик клика на кнопки развёртывания
    document.querySelectorAll('.expand-btn').forEach(button => {
        button.addEventListener('click', (e) => {
            e.stopPropagation();

            // Если уже есть развёрнутая карточка, сворачиваем её
            if (currentClone) {
                collapseCard(currentClone, expandedCard);
            }
            
            // Разворачиваем текущую карточку
            expandCard(e, button);
        });
    });

    // Функция для развёртывания карточки
    function expandCard(e, button){
        const card = button.closest('.card');

        // Находим карточки в том же ряду
        const sameRowCards = getCardsInSameRow(card);

        // Создаем клон карточки
        const cardClone = card.cloneNode(true);
        cardClone.classList.add('card-clone');

        // Изменяем кнопку на "Свернуть"
        const expandButton = cardClone.querySelector('.expand-btn');
        expandButton.textContent = 'Свернуть';
        expandButton.classList.remove('expand-btn');
        expandButton.classList.add('collapse-btn');

        // Добавляем обработчик для сворачивания
        const collapseButton = cardClone.querySelector('.collapse-btn');
        collapseButton.addEventListener('click', (e) => {
            e.stopPropagation();
            collapseCard(cardClone, card);
        });

        // Добавляем клон в body
        document.body.appendChild(cardClone);

        // Получаем позиции оригинальной карточки
        const rect = card.getBoundingClientRect();
        
        // Устанавливаем начальные стили клона
        cardClone.style.top = `${getTop(card)}px`;
        cardClone.style.left = `${rect.left + window.pageXOffset}px`;
        cardClone.style.width = `${rect.width}px`;
        cardClone.style.height = `${rect.height}px`;

        // Форсируем перерисовку
        cardClone.getBoundingClientRect();

        // Вычисляем целевую ширину и позицию
        const targetLeft = 20; // Поскольку у body padding-left: 20px
        const targetWidth = document.body.clientWidth - 40; // Учитываем padding

        // Устанавливаем конечные стили для анимации
        cardClone.style.top = `${getTop(card)}px`;
        cardClone.style.left = `${targetLeft}px`;
        cardClone.style.width = `${targetWidth}px`;

        cardClone.style.pointerEvents = 'none';
        // Убираем детали и показываем их через CSS
        const details = cardClone.querySelector('.details');
        // Удаляем inline-стили, чтобы плавно раскрыть детали
        details.style.display = '';

        // устанавливаем карточкам того же ряда высоту, которая у них и так есть, но в пикселях — нужно для анимации
        sameRowCards.forEach(card => {
            card.style.height = `${card.scrollHeight}px`;
            // запоминаем эту высоту, чтобы было куда вернуться
            startRowWidth = card.style.height;
        });

        setTimeout(() => {
            // Получаем размеры клона с контентом
            cardClone.style.maxHeight = '60vh'; // Убираем ограничение, чтобы измерить реальную высоту
            let targetHeight = cardClone.scrollHeight + 'px';

            // Устанавливаем конечную height для анимации
            cardClone.style.height = targetHeight;
            cardClone.style.overflowY = 'auto';

            // переопределяем по новой высоте открытой карточки, чтобы сделать закрытые под ней той же высоты
            targetHeight = cardClone.style.height + 'px';

            // Для плавного перехода сначала устанавливаем текущие высоты
            sameRowCards.forEach(card => {
                card.style.height = `${cardClone.scrollHeight}px`;
                console.log(card.scrollHeight);
            });

            // Форсируем перерисовку
            sameRowCards[0].offsetHeight;

            // Устанавливаем новые высоты
            sameRowCards.forEach(card => {
                card.style.height = `${targetHeight}px`;
            });
        }, transitionDuration);
        
        cardClone.addEventListener('transitionend', () => {
            // закончили анимацию — можно и на кнопки жать, не раньше
            cardClone.style.pointerEvents = '';
        }, { once: true });

        expandedCard = card;
        currentClone = cardClone;
    }

    function collapseCard(clone, originalCard) {
        // Получаем позиции оригинальной карточки
        const rect = originalCard.getBoundingClientRect();

        // Устанавливаем конечные стили клона для анимации сворачивания
        clone.style.top = `${getTop(originalCard)}px`;
        clone.style.left = `${rect.left}px`;
        clone.style.width = `${rect.width}px`;
        clone.style.height = `${rect.height}px`;

        // Сбрасываем высоты карточек в ряду
        const sameRowCards = getCardsInSameRow(originalCard);
        sameRowCards.forEach(card => {
            card.style.height = startRowWidth;
        });

        // Удаляем клон после завершения анимации
        clone.addEventListener('transitionend', () => {
            if (clone && clone.parentNode) {
                clone.parentNode.removeChild(clone);
            }
            sameRowCards.forEach(card => {
                card.style.height = '';
            });
        }, { once: true });

        expandedCard = null;
        currentClone = null;
    }

    // Обработка изменения размера окна
    window.addEventListener('resize', () => {
        const cloneToClose = document.querySelector('.card-clone');
        if (cloneToClose) {
            // Добавляем класс для начала анимации исчезновения
            cloneToClose.classList.add('fade-out');

            // После завершения анимации удаляем элемент
            cloneToClose.addEventListener('transitionend', () => {
                if (cloneToClose && cloneToClose.parentNode) {
                    cloneToClose.parentNode.removeChild(cloneToClose);
                }
            }, { once: true }); // Обработчик срабатывает только один раз
            
            expandedCard = null;
            currentClone = null;
        }
    });
</script>
</body>

</html>

в чём слабые места этого кода?