Структура построения отображения картинок
Имеется код страницы
В нем в процессе загрузки создаются блоки с картинками, мне надо что-бы они были условно построечно, но не создавали пропусков, ни где не смог найти ответов, в том числе у ии, просьба помочь с реализацией задуманного.
Первый блок кода - код блока с картинкой
Второй блок кода - вся страница
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()">×</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"); ?>