Hello,
I want to make images grid layout in my Laravel 8 / alpinejs 3.8.1 / tailwindcss 2.2.2 app and
searching in net I found several possible decisions :
-
With css styling
Which is based on 3 custom classes masonry-3-col, masonry-2-col , break-inside and it works ok for my page including different devices :
http://hostels4j.my-demo-apps.tk/hostels-gallery -
I found this masonry.desandro library, but trying to implmenent it on the same page
I have very wierd results : Any image item is show with desined borders and shadows when mouse is over as expected, but
grids layout
is rather strange. I see that masonry library is applied. Please look the same url with debug key added “/1”
http://hostels4j.my-demo-apps.tk/hostels-gallery/1 debug key added/missing “/1”
In Blade file below I switch these 2 modes depending on :
<div class="frontend_page_container" x-data="hostelsGalleyViewPageComponent()"
x-init="[onHostelsGalleyViewPageComponentInit() ]" id="hostels_gallery_page_container" x-cloak>
{{-- SOURCE : https://stackoverflow.com/questions/66914169/can-i-create-a-masonry-layout-using-tailwind-css-utility-classes--}}
<div
class="relative pt-16 pb-32 flex content-center items-center justify-center"
style="min-height: 45vh;" x-cloak
>
<div
class="absolute top-0 w-full h-full bg-center bg-cover"
style='background-image: url("{{ \App\Library\Services\AppContent::BG_IMAGE_HEADER_HOSTEL }}");'
>
<span
id="blackOverlay"
class="w-full h-full absolute opacity-50 bg-black"
></span>
</div>
<div class="container relative mx-auto">
<div class="items-center flex flex-wrap">
<div class="w-full lg:w-6/12 px-4 ml-auto mr-auto text-center">
<div class="pr-12">
<h1 class="frontend_main_inverted_color font-semibold text-4xl">
{{ $site_name }}
</h1>
@if(!empty($appHeaderBlockHeader['text']))
<p class="mt-4 text-lg frontend_main_inverted_color">
{!! $appHeaderBlockHeader['text'] !!}
</p>
@endif
<a href="{{ route('personal.new-hostel') }}" class="btn_frontend_action_big">
Publish Hostel
</a>
</div>
</div>
</div>
</div>
<div
class="top-auto bottom-0 left-0 right-0 w-full absolute pointer-events-none overflow-hidden"
style="height: 70px;"
>
<svg
class="absolute bottom-0 overflow-hidden"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="none"
version="1.1"
viewBox="0 0 2560 100"
x="0"
y="0"
>
<polygon
class="text-gray-700"
points="2560 0 2560 100 0 100"
></polygon>
</svg>
</div>
</div>
<section class="pb-20 bg-gray-300 -mt-24">
<div class="container mx-auto px-4">
<div class="flex flex-wrap items-center mt-16">
@if(!empty($ourCompanyInfoBlock['name']) and !empty($ourCompanyInfoBlock['text']))
<div class="w-full md:w-6/12 px-2 mr-auto ml-auto">
<h3 class="text-3xl mb-2 frontend_content_text leading-normal">
{!! showAppIcon('our_company', 'frontend') !!}
{!! $ourCompanyInfoBlock['name'] !!}
</h3>
<p
class="text-lg font-light leading-relaxed mt-4 mb-4 frontend_content_text"
>
{!! $ourCompanyInfoBlock['text'] !!}
</p>
</div>
@endif
<div class="w-full md:w-5/12 px-2 mr-auto ml-auto">
<div
class="relative flex flex-col min-w-0 break-words bg-white w-full mb-6 shadow-lg rounded-lg bg-green-600"
>
<img
alt="..."
src="{{ \App\Library\Services\AppContent::BG_IMAGE_HOSTELS_GALLERY }}"
class="w-full align-middle rounded-t-lg"
/>
<blockquote class="relative p-2 lg:p-6 mb-4">
<svg
preserveAspectRatio="none"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 583 95"
class="absolute left-0 w-full block"
style="height: 95px; top: -94px;"
>
<polygon
points="-30,95 583,95 583,65"
class="text-green-600 fill-current"
></polygon>
</svg>
<h4 class="text-xl font-bold frontend_main_inverted_color">
{!! $hostelsGalleryInfoBlock['name'] !!}
</h4>
@if(!empty($hostelsGalleryInfoBlock['text']))
<p class="text-md font-light mt-2 frontend_main_inverted_color">
{!! $hostelsGalleryInfoBlock['text'] !!}
</p>
@endif
</blockquote>
</div>
</div>
</div>
</div>
</section>
<section class="relative py-10">
<div
class="bottom-auto top-0 left-0 right-0 w-full absolute pointer-events-none overflow-hidden -mt-20"
style="height: 80px;"
>
<svg
class="absolute bottom-0 overflow-hidden"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="none"
version="1.1"
viewBox="0 0 2560 100"
x="0"
y="0"
>
<polygon
class="bg-gray-300"
points="2560 0 2560 100 0 100"
></polygon>
</svg>
</div>
<div class="container mx-auto p-0 frontend_block_border rounded-lg">
@if(count($hostelsDataRows) == 0)
<div class="m-2 p-2 warning_text">
{!! showAppIcon('warning', 'frontend') !!}
No hostels found !
</div>
@endif
@if(count($hostelsDataRows) > 0)
<x-h2 class="frontend_subtitle">
{!! showAppIcon('image') !!}
{{ count($hostelsDataRows) }} {{ pluralize3( count($hostelsDataRows), 'no images', 'image', 'images' ) }}
</x-h2>
<div id="div_photos_container_id" class="block">
@if($debug)
<div class="main_gallery__blocks">
<!-- HOSTELS FOREACH START -->
@foreach($hostelsDataRows as $nextHostel)
@livewire('hostel.hostel-gallery-item', ['nextHostel' => $nextHostel, 'loop_index'=>
$loop->index])
@endforeach
<!-- HOSTELS FOREACH END -->
</div>
@else
<div
class="md:masonry-2-col lg:masonry-3-col box-border mx-auto before:box-inherit after:box-inherit">
<!-- HOSTELS FOREACH START -->
@foreach($hostelsDataRows as $nextHostel)
<div class="break-inside p-4 m-0 bg-gray-100 rounded-lg">
@livewire('hostel.hostel-gallery-item', ['nextHostel' => $nextHostel, 'loop_index'=>
$loop->index])
</div>
@endforeach
<!-- HOSTELS FOREACH END -->
</div>
@endif
</div>
@endif
</div>
</section>
@if($debug)
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
@endif
<script>
function hostelsGalleyViewPageComponent() {
return {
onHostelsGalleyViewPageComponentInit: function () {
console.log('onHostelsGalleyViewPageComponentInit $debug::')
console.log('{{ $debug }}')
if ('{{ $debug }}' == '1') {
var container = document.querySelector('.main_gallery__blocks');
var msnry = new Masonry(container, {
columnWidth: 240,
// isFitWidth: true,
itemSelector: '.main_gallery__block',
});
setTimeout(setPhotosContainerHeight, 1000); // But this method really helped
}
},
}
} // function hostelsGalleyViewPageComponent() {
function setPhotosContainerHeight() {
console.log('setPhotosContainerHeight::')
document.getElementById('div_photos_container_id').setAttribute("style", "height:100% !important");
console.log('document.getElementById(div_photos_container_id).setAttribute("style"::')
console.log(document.getElementById('div_photos_container_id').getAttribute("style"))
// this.is_photos_container_loaded = true;
}
</script>
<style>
.main_gallery__blocks {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
width: calc(100% + 14px);
margin: -7px;
}
.main_gallery__block {
width: 100%;
padding: 4px;
}
.main_gallery__link {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
opacity: 0;
z-index: 2;
}
.main_gallery__content {
width: 100%;
height: 100%;
position: relative;
}
.main_gallery__content img {
width: 100%;
height: 100%;
-o-object-fit: cover;
object-fit: cover;
}
.main_gallery__content:before {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.4);
opacity: 0;
-webkit-transition: 0.3s opacity;
-o-transition: 0.3s opacity;
transition: 0.3s opacity;
}
.main_gallery__content:hover:before {
opacity: 1;
}
.main_gallery__content:hover .main_gallery__info,
.main_gallery__content:hover .main_gallery__comments,
.main_gallery__content:hover .main_gallery__description,
.main_gallery__content:hover .main_gallery__sticker_mark {
opacity: 1;
}
.main_gallery__content:hover .main_gallery__description {
color: #FFD846;
}
.main_gallery__description {
display: block;
width: 100%;
font-weight: 500;
font-size: 18px;
letter-spacing: 0.03em;
color: #fff;
padding: 0 0 11px 23px;
position: absolute;
left: 0;
bottom: 0;
-webkit-transition: 0.3s color;
-o-transition: 0.3s color;
transition: 0.3s color;
}
.main_gallery__content:hover .main_gallery__description,
.main_gallery__content:hover .main_gallery__sticker_mark {
opacity: 1;
}
.main_gallery__content:hover .main_gallery__description {
color: #FFD846;
}
@media screen and (max-width: 767px) {
.main_gallery__description {
font-size: 14px;
padding: 0 0 15px 15px;
}
}
@media screen and (max-width: 480px) {
.main_gallery__description {
font-size: 12px;
padding: 0 0 10px 10px;
}
}
</style>
</div>
and resources/views/livewire/hostel/hostel-gallery-item.blade.php with template for any image :
<div>
<div class="main_gallery__block" >
<div class="main_gallery__content">
<a href="{{ route('hostel-view-page', $nextHostel->slug ) }}" class="main_gallery__link"></a>
@if(!empty($nextHostel['filenameData']))
<img src="{{$nextHostel['filenameData']['image_url']}}" alt="">
@else
<img src="/img/hostels-gallery.jpg" alt="{{ $nextHostel['name'] }}">
@endif
<p class="main_gallery__description">{{$nextHostel['id']}}::{{$nextHostel['name']}}</p>
</div>
</div>
</div>
Actually I would prefer to use the second way, as I want to master this library, but why results are some ugly and how it can be fixed?
Thanks!