Структура построения отображения картинок

Имеется код страницы
В нем в процессе загрузки создаются блоки с картинками, мне надо что-бы они были условно построечно, но не создавали пропусков, ни где не смог найти ответов, в том числе у ии, просьба помочь с реализацией задуманного.

Первый блок кода - код блока с картинкой
Второй блок кода - вся страница
1 картинка показывает что по факту имеется
2 картинка показывает что должно получится (сделал в photoshop)

<?php foreach ($photos as $photo) { ?>
  <div class="col draggable" data-id="<?=$photo['id']?>">
    <div class="card">
      <div class="card-body p-0 position-relative">
        <img src="uploads/<?=$photo['file_name']?>" class="card-img-top img-fluid" alt="Фото <?=$photo['id']?>" onclick="openModal(this.src)">
        <div class="photo-actions position-absolute w-100 d-flex justify-content-center">
          <div class="opacity-75 p-2 rounded">
            <a href="uploads/<?=$photo['file_name']?>" download class="btn btn-secondary">Скачать</a>
            <button class="btn btn-primary print-request" data-id="<?=$photo['id']?>">Запрос на печать</button>
            <button class="btn btn-danger delete-photo" data-id="<?=$photo['id']?>">Удалить</button>
          </div>
        </div>
      </div>
    </div>
  </div>
<?php } ?>

<?php
require("includes/header.php");
require("../src/db.php");

$stmt = $conn->prepare("SELECT * FROM bids WHERE user_id=?");
$stmt->execute([$_SESSION['user_id']]);
$bids = $stmt->fetchAll();

$photosStmt = $conn->prepare("SELECT * FROM photos WHERE user_id=?");
$photosStmt->execute([$_SESSION['user_id']]);
$photos = $photosStmt->fetchAll();
?>

<div class="container-fluid w-75 mb-3 mx-auto">
    <h2 class="text-center p-3">Личный кабинет</h2>
    <div class="container border mb-5">
        <a href="bid_form.php" class="btn btn-success mb-2 mt-3">Новая заявка</a>
        <h3>Ваши заявки:</h3>
        <button class="btn btn-primary mb-3 mt-2" type="button" data-bs-toggle="collapse" data-bs-target="#bidsTable" aria-expanded="false" aria-controls="bidsTable">
            Показать/Скрыть заявки
        </button>
        <div class="collapse" id="bidsTable">
            <div class="row row-cols-1 row-cols-md-2 g-4">
                <?php foreach ($bids as $bid) { ?>
                    <div class="col">
                        <div class="card">
                            <div class="card-body">
                                <h5 class="card-title">Заявка № <?=$bid["id"]?></h5>
                                <h5 class="card-title"><?=$bid["title"]?></h5>
                                <p class="card-text"><?=$bid["description"]?></p>
                                <p class="card-text"><?=$bid["status"]?></p>
                            </div>
                        </div>
                    </div>
                <?php } ?>
            </div>
        </div>
    </div>

    <div class="container border">
        <h3>Ваши фото:</h3>
        <form action="api/upload_photo.php" method="post" enctype="multipart/form-data">
            <input type="file" name="photo" id="photoInput" class="form-control mb-3" onchange="toggleUploadButton()">
            <button type="submit" id="uploadButton" class="btn btn-primary" disabled>Загрузить фото</button>
        </form>
        <div id="photoGallery" class="row row-cols-1 row-cols-md-2 g-4 mt-3 mb-3">
            <?php foreach ($photos as $photo) { ?>
                <div class="col draggable" data-id="<?=$photo['id']?>">
                    <div class="card">
                        <div class="card-body p-0 position-relative">
                            <img src="uploads/<?=$photo['file_name']?>" class="card-img-top img-fluid" alt="Фото <?=$photo['id']?>" onclick="openModal(this.src)">
                            <div class="photo-actions position-absolute w-100 d-flex justify-content-center">
                                <div class="opacity-75 p-2 rounded">
                                    <a href="uploads/<?=$photo['file_name']?>" download class="btn btn-secondary">Скачать</a>
                                    <button class="btn btn-primary print-request" data-id="<?=$photo['id']?>">Запрос на печать</button>
                                    <button class="btn btn-danger delete-photo" data-id="<?=$photo['id']?>">Удалить</button>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            <?php } ?>
        </div>
    </div>            
</div>

<!-- Modal for full-size image -->
<div id="imageModal" class="modal" tabindex="-1">
    <span class="close" onclick="closeModal()">&times;</span>
    <img class="modal-content" id="modalImage">
</div>

<script>
function toggleUploadButton() {
    const photoInput = document.getElementById('photoInput');
    const uploadButton = document.getElementById('uploadButton');
    uploadButton.disabled = !photoInput.files.length;
}

document.addEventListener('DOMContentLoaded', function() {
    const deleteButtons = document.querySelectorAll('.delete-photo');
    deleteButtons.forEach(button => {
        button.addEventListener('click', function() {
            const photoId = this.getAttribute('data-id');
            if (confirm('Вы уверены, что хотите удалить это фото?')) {
                fetch('api/delete_photo.php', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded'
                    },
                    body: new URLSearchParams({
                        'photo_id': photoId
                    })
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        this.closest('.col').remove();
                    } else {
                        alert('Ошибка при удалении фото: ' + data.message);
                    }
                })
                .catch(error => {
                    console.error('Ошибка:', error);
                    alert('Произошла ошибка при удалении фото');
                });
            }
        });
    });
});

function openModal(src) {
    const modal = document.getElementById("imageModal");
    const modalImg = document.getElementById("modalImage");
    modal.style.display = "block";
    modalImg.src = src;
}

function closeModal() {
    const modal = document.getElementById("imageModal");
    modal.style.display = "none";
}
</script>

<style>
.card-body {
    position: relative;
    overflow: hidden;
}

.card-body .photo-actions {
    display: flex;
    align-items: center;
    justify-content: center;
    bottom: -100%;
    left: 0;
    right: 0;
    background: linear-gradient(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.45));
    transition: bottom 0.3s ease;
    padding: 10px;
}

.card:hover .photo-actions {
    bottom: 0;
}

/* Стили для предотвращения растягивания изображения */
.card-img-top {
    object-fit: cover;
    width: 100%;
    height: auto;
}

/* Modal styles */
.modal {
    display: none;
    position: fixed;
    z-index: 1000;
    padding-top: 60px;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    overflow: auto;
    background-color: rgba(0, 0, 0, 0.8);
}

.modal-content {
    margin: auto;
    display: block;
    max-width: 90%;
    max-height: 90%;
    width: auto;
    height: auto;
}

.close {
    position: absolute;
    top: 15px;
    right: 35px;
    color: #fff;
    font-size: 40px;
    font-weight: bold;
    transition: 0.3s;
}

.close:hover,
.close:focus {
    color: #bbb;
    text-decoration: none;
    cursor: pointer;
}
</style>
<?php require("includes/footer.php"); ?>

Как есть. Как должно получиться.


Ответы (0 шт):