Refactor home.html: Update navbar structure, enhance styling, and implement search functionality

- Working infinite scroll effect
- Removed unused CSS and JS files to streamline the template.
This commit is contained in:
Kiyan 2025-12-16 23:02:42 +02:00
parent 8320954344
commit b587244dae
20 changed files with 61 additions and 350 deletions

View File

@ -4,7 +4,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import com.example.PhotoGallery.Services.PhotoService;
@Controller
@ -15,23 +14,36 @@ public class PhotosController {
private final int RANDOM_NUMBER_IMAGES = 5;
private final int FIRST_PAGE = 0;
private final int INITIAL_PAGE_SIZE = 30;
private final int PAGE_SIZE = 10;
private int pageCounter = 0;
@GetMapping("/home")
private String home(Model model) {
photoService.WriteImagesFromDirToDB();
//reset the page counter when the page home page is reloaded
pageCounter = 0;
model.addAttribute("images", photoService.getPagedPhotos(FIRST_PAGE, INITIAL_PAGE_SIZE));
//upon a page refresh we will scan the db and add any new images that are in the directory
photoService.WriteImagesFromDirToDB(); //TODO: run this method asynchronously
model.addAttribute("images", photoService.getPagedPhotos(FIRST_PAGE, PAGE_SIZE));
model.addAttribute("carouselImages", photoService.getRandomPhotos(RANDOM_NUMBER_IMAGES));
return "home";
}
@GetMapping("/images")
public String test(Model model) {
model.addAttribute("images", photoService.getPagedPhotos(0, 10));
@GetMapping("/loadMoreImages")
public String loadMoreImages(Model model) {
int totalPages = photoService.getPagedPhotos(FIRST_PAGE, PAGE_SIZE).getTotalPages();
//dont load any more images if we have reached the last images
if (pageCounter == totalPages){
return "home :: images";
}
pageCounter++;
model.addAttribute("images", photoService.getPagedPhotos(pageCounter, 10));
return "home :: images";
}

View File

@ -1,208 +0,0 @@
/* !
* baguetteBox.js
* @author feimosi
* @version 1.11.1
* @url https://github.com/feimosi/baguetteBox.js */
#baguetteBox-overlay {
display: none;
opacity: 0;
position: fixed;
overflow: hidden;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000000;
background-color: #222;
background-color: rgba(0,0,0,.8);
-webkit-transition: opacity .5s ease;
transition: opacity .5s ease;
}
#baguetteBox-overlay.visible {
opacity: 1;
}
#baguetteBox-overlay .full-image {
display: inline-block;
position: relative;
width: 100%;
height: 100%;
text-align: center;
}
#baguetteBox-overlay .full-image figure {
display: inline;
margin: 0;
height: 100%;
}
#baguetteBox-overlay .full-image img {
display: inline-block;
width: auto;
height: auto;
max-height: 100%;
max-width: 100%;
vertical-align: middle;
-webkit-box-shadow: 0 0 8px rgba(0,0,0,.6);
-moz-box-shadow: 0 0 8px rgba(0,0,0,.6);
box-shadow: 0 0 8px rgba(0,0,0,.6);
}
#baguetteBox-overlay .full-image figcaption {
display: block;
position: absolute;
bottom: 0;
width: 100%;
text-align: center;
line-height: 1.8;
white-space: normal;
color: #ccc;
background-color: #000;
background-color: rgba(0,0,0,.6);
font-family: sans-serif;
}
#baguetteBox-overlay .full-image:before {
content: "";
display: inline-block;
height: 50%;
width: 1px;
margin-right: -1px;
}
#baguetteBox-slider {
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
white-space: nowrap;
-webkit-transition: left .4s ease,-webkit-transform .4s ease;
transition: left .4s ease,-webkit-transform .4s ease;
transition: left .4s ease,transform .4s ease;
transition: left .4s ease,transform .4s ease,-webkit-transform .4s ease,-moz-transform .4s ease;
}
#baguetteBox-slider.bounce-from-right {
-webkit-animation: bounceFromRight .4s ease-out;
animation: bounceFromRight .4s ease-out;
}
#baguetteBox-slider.bounce-from-left {
-webkit-animation: bounceFromLeft .4s ease-out;
animation: bounceFromLeft .4s ease-out;
}
@keyframes bounceFromRight {
0%, 100% {
margin-left: 0;
}
50% {
margin-left: -30px;
}
}
@keyframes bounceFromLeft {
0%, 100% {
margin-left: 0;
}
50% {
margin-left: 30px;
}
}
.baguetteBox-button#next-button, .baguetteBox-button#previous-button {
top: 50%;
top: calc(50% - 30px);
width: 44px;
height: 60px;
}
.baguetteBox-button {
position: absolute;
cursor: pointer;
outline: 0;
padding: 0;
margin: 0;
border: 0;
-moz-border-radius: 15%;
border-radius: 15%;
background-color: #323232;
background-color: rgba(50,50,50,.5);
color: #ddd;
font: 1.6em sans-serif;
-webkit-transition: background-color .4s ease;
transition: background-color .4s ease;
}
.baguetteBox-button:focus, .baguetteBox-button:hover {
background-color: rgba(50,50,50,.9);
}
.baguetteBox-button#next-button {
right: 2%;
}
.baguetteBox-button#previous-button {
left: 2%;
}
.baguetteBox-button#close-button {
top: 20px;
right: 2%;
right: calc(2% + 6px);
width: 30px;
height: 30px;
}
.baguetteBox-button svg {
position: absolute;
left: 0;
top: 0;
}
.baguetteBox-spinner {
width: 40px;
height: 40px;
display: inline-block;
position: absolute;
top: 50%;
left: 50%;
margin-top: -20px;
margin-left: -20px;
}
.baguetteBox-double-bounce1, .baguetteBox-double-bounce2 {
width: 100%;
height: 100%;
-moz-border-radius: 50%;
border-radius: 50%;
background-color: #fff;
opacity: .6;
position: absolute;
top: 0;
left: 0;
-webkit-animation: bounce 2s infinite ease-in-out;
animation: bounce 2s infinite ease-in-out;
}
.baguetteBox-double-bounce2 {
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
@keyframes bounce {
0%, 100% {
-webkit-transform: scale(0);
-moz-transform: scale(0);
transform: scale(0);
}
50% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
transform: scale(1);
}
}

View File

@ -1,57 +0,0 @@
.bs-icon {
--bs-icon-size: .75rem;
display: flex;
flex-shrink: 0;
justify-content: center;
align-items: center;
font-size: var(--bs-icon-size);
width: calc(var(--bs-icon-size) * 2);
height: calc(var(--bs-icon-size) * 2);
color: var(--bs-primary);
}
.bs-icon-xs {
--bs-icon-size: 1rem;
width: calc(var(--bs-icon-size) * 1.5);
height: calc(var(--bs-icon-size) * 1.5);
}
.bs-icon-sm {
--bs-icon-size: 1rem;
}
.bs-icon-md {
--bs-icon-size: 1.5rem;
}
.bs-icon-lg {
--bs-icon-size: 2rem;
}
.bs-icon-xl {
--bs-icon-size: 2.5rem;
}
.bs-icon.bs-icon-primary {
color: var(--bs-white);
background: var(--bs-primary);
}
.bs-icon.bs-icon-primary-light {
color: var(--bs-primary);
background: rgba(var(--bs-primary-rgb), .2);
}
.bs-icon.bs-icon-semi-white {
color: var(--bs-primary);
background: rgba(255, 255, 255, .5);
}
.bs-icon.bs-icon-rounded {
border-radius: .5rem;
}
.bs-icon.bs-icon-circle {
border-radius: 50%;
}

View File

@ -1,4 +0,0 @@
.aspect-ratio-4x3 {
aspect-ratio: 4/3;
}

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

File diff suppressed because one or more lines are too long

View File

@ -1,3 +0,0 @@
if (document.querySelectorAll('[data-bss-baguettebox]').length > 0) {
baguetteBox.run('[data-bss-baguettebox]', { animation: 'slideIn' });
}

File diff suppressed because one or more lines are too long

View File

@ -6,44 +6,46 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>Untitled</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/bss-overrides.css">
<link rel="stylesheet" href="/css/Lightbox-Gallery-baguetteBox.min.css">
<link rel="stylesheet" href="/css/Navbar-Centered-Links-icons.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css">
<style>
body {
background-color: #222831;
}
#search:active{
border: none;
}
</style>
</head>
<body style="height: 100%;width: 100%;">
<nav class="navbar navbar-expand-md bg-body mb-3 py-3">
<nav class="navbar navbar-expand-md sticky-top bg-body border-bottom">
<div class="container">
<a class="navbar-brand d-flex align-items-center" href="#">
<span
class="bs-icon-sm bs-icon-rounded bs-icon-primary d-flex justify-content-center align-items-center me-2 bs-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor"
viewBox="0 0 16 16" class="bi bi-camera">
<path
d="M15 12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h1.172a3 3 0 0 0 2.12-.879l.83-.828A1 1 0 0 1 6.827 3h2.344a1 1 0 0 1 .707.293l.828.828A3 3 0 0 0 12.828 5H14a1 1 0 0 1 1 1zM2 4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-1.172a2 2 0 0 1-1.414-.586l-.828-.828A2 2 0 0 0 9.172 2H6.828a2 2 0 0 0-1.414.586l-.828.828A2 2 0 0 1 3.172 4z">
</path>
<path
d="M8 11a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5m0 1a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7M3 6.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0">
</path>
</svg>
</span>
<span>Photo Gallery</span>
</a>
<button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-3">
<span class="visually-hidden">Toggle navigation</span>
<a class="navbar-brand fw-bold" href="#">Photo Gallery</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navMain">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navcol-3">
<ul class="navbar-nav align-items-center mx-auto">
<div class="collapse navbar-collapse" id="navMain">
<ul class="navbar-nav ms-auto align-items-md-center gap-md-2">
<li class="nav-item">
<a class="nav-link active my-0 py-2" th:href="@{/uploadPhoto}">First Item</a>
<div>
<i class="bi bi-search"></i>
<input style="border: none;" type="search" name="search" id="search" placeholder="Search Photos...">
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Second Item</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Third Item</a>
<button class="btn btn-outline-dark dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</button>
<ul class="dropdown-menu dropdown-menu-dark">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</li>
</ul>
</div>
@ -77,39 +79,28 @@
</div>
<div>
<section class="pt-5 pb-0 my-0 py-xl-5" style="padding: 0;">
<div class="d-flex">
<div class="w-100">
<input class="mx-2 px-2 my-3 py-1" type="search" placeholder="Search Photos...">
</div>
<div class="d-flex w-100 align-items-center justify-content-end ">
<select class="p-2 me-3" name="" id="">
<option value="">People</option>
<option value="">Landscapes</option>
<option value="">Animals</option>
<option value="">Black & White</option>
</select>
</div>
</div>
<div class="container">
<div th:fragment="images" class="row gx-2 gy-2 row-cols-1 row-cols-md-2 row-cols-xl-3 mt-0"
<div id="image-row" class="row gx-1 gy-1 row-cols-1 row-cols-md-2 row-cols-xl-5 mt-0"
data-bss-baguettebox="">
<div class="col" th:each="image : ${images}">
<div th:fragment="images" class="col" th:each="image : ${images}">
<span th:text="${images.number}"></span>
<a th:href="@{${image.filePath}}">
<img class="img-fluid aspect-ratio-4x3 object-fit-cover w-100 h-100"
<img class="bg-black img-fluid aspect-ratio-4x3 object-fit-cover w-100 h-100"
style="padding: 1px;"
alt="Replace with image description" th:src="@{${image.thumbnailPath}}"
loading="lazy">
</a>
</div>
</div>
<!-- HTMX infinite-scroll sentinel -->
<div th:if="${images}" hx-get="/images" hx-trigger="revealed"
hx-swap="afterend" style="height: 1px">
</div>
<div
style="height: 1px;"
hx-get="/loadMoreImages"
hx-trigger="intersect"
hx-target="#image-row"
hx-swap="beforeend">
</div>
</div>
@ -117,8 +108,6 @@
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/js/bootstrap.bundle.min.js"></script>
<script src="/js/Lightbox-Gallery-baguetteBox.min.js"></script>
<script src="/js/Lightbox-Gallery.js"></script>
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
</body>