Skip to content

Commit 2277b66

Browse files
committed
Refactors HTML layout and enables HTMX morph swap
Introduces HTMX `morph` swapping to allow for smoother partial page updates. Integrates Alpine.js and Alpine Morph CDN scripts to support this functionality. Restructures HTML templates by introducing semantic ``, ``, and `` tags and consolidating layout-specific classes and HTMX extensions into `layout.html`. This standardizes the page structure across all content pages and fragments, improving maintainability.
1 parent 36224c9 commit 2277b66

File tree

10 files changed

+189
-175
lines changed

10 files changed

+189
-175
lines changed

src/main/java/dev/ikm/server/cosmos/config/SecurityConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package dev.ikm.server.cosmos.config;
22

33
import org.springframework.context.annotation.Bean;
4-
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
54
import org.springframework.context.annotation.Configuration;
65
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
76
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
7+
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
88
import org.springframework.security.web.SecurityFilterChain;
99

1010
@Configuration

src/main/resources/templates/data.html

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@
55
<head>
66
<title>Data</title>
77
</head>
8-
98
<body>
10-
11-
<header id="header-content" layout:fragment="header-content" th:replace="~{fragments/navigation :: navigation-content}"></header>
12-
13-
<main id="main-content" class="container flex-shrink-0" th:fragment="main-content" layout:fragment="main-content">
14-
<h1>Data View</h1>
15-
<p>This is the content for the Data page.</p>
9+
<header>
10+
<div id="header-content" layout:fragment="header-content"
11+
th:replace="~{fragments/navigation :: navigation-content}"></div>
12+
</header>
13+
<main>
14+
<div id="main-content" th:fragment="main-content" layout:fragment="main-content">
15+
<h1>Data View</h1>
16+
<p>This is the content for the Data page.</p>
17+
</div>
1618
</main>
17-
18-
<footer id="footer-content" class="footer mt-auto py-3 bg-light" layout:fragment="footer-content" th:replace="~{fragments/footer :: #footer-content}"></footer>
19-
19+
<footer>
20+
<div id="footer-content" layout:fragment="footer-content" th:replace="~{fragments/footer :: #footer-content}"></div>
21+
</footer>
2022
</body>
2123
</html>

src/main/resources/templates/fragments/footer.html

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@
55
<head>
66
<title>Footer</title>
77
</head>
8-
98
<body>
10-
11-
<footer id="footer-content" class="footer mt-auto py-3 bg-light" th:fragment="footer-content" hx-swap-oob="true">
12-
<div class="container">
9+
<footer>
10+
<div id="footer-content" th:fragment="footer-content" hx-swap-oob="true" class="container">
1311
<span class="text-muted" th:text="${footerText}"></span>
1412
</div>
1513
</footer>
16-
1714
</body>
1815
</html>

src/main/resources/templates/fragments/navigation.html

Lines changed: 69 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -5,78 +5,77 @@
55
<head>
66
<title>Navigation</title>
77
</head>
8-
98
<body>
10-
11-
<header id="header-content" th:fragment="navigation-content" hx-swap-oob="true">
12-
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
13-
<div class="container-fluid">
14-
<a class="navbar-brand" href="#">Cosmos</a>
15-
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse"
16-
aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
17-
<span class="navbar-toggler-icon"></span>
18-
</button>
19-
<div class="collapse navbar-collapse" id="navbarCollapse">
20-
<ul class="navbar-nav me-auto mb-2 mb-md-0">
21-
<li class="nav-item">
22-
<a class="nav-link"
23-
th:classappend="${activePage == 'home' ? 'active' : ''}"
24-
href="/home"
25-
hx-get="/home"
26-
hx-target="#main-content"
27-
hx-swap="outerHTML"
28-
hx-push-url="true">Home</a>
29-
</li>
30-
<li class="nav-item">
31-
<a class="nav-link"
32-
th:classappend="${activePage == 'perspective' ? 'active' : ''}"
33-
href="/perspective"
34-
hx-get="/perspective"
35-
hx-target="#main-content"
36-
hx-swap="outerHTML"
37-
hx-push-url="true">Perspective</a>
38-
</li>
39-
<li class="nav-item">
40-
<a class="nav-link"
41-
th:classappend="${activePage == 'data' ? 'active' : ''}"
42-
href="/data"
43-
hx-get="/data"
44-
hx-target="#main-content"
45-
hx-swap="outerHTML"
46-
hx-push-url="true">Data</a>
47-
</li>
48-
<li class="nav-item">
49-
<a class="nav-link"
50-
th:classappend="${activePage == 'knowledge' ? 'active' : ''}"
51-
href="/knowledge"
52-
hx-get="/knowledge"
53-
hx-target="#main-content"
54-
hx-swap="outerHTML"
55-
hx-push-url="true">Knowledge</a>
56-
</li>
57-
<li class="nav-item">
58-
<a class="nav-link"
59-
th:classappend="${activePage == 'quality' ? 'active' : ''}"
60-
href="/quality"
61-
hx-get="/quality"
62-
hx-target="#main-content"
63-
hx-swap="outerHTML"
64-
hx-push-url="true">Quality</a>
65-
</li>
66-
<li class="nav-item">
67-
<a class="nav-link"
68-
th:classappend="${activePage == 'query' ? 'active' : ''}"
69-
href="/query"
70-
hx-get="/query"
71-
hx-target="#main-content"
72-
hx-swap="outerHTML"
73-
hx-push-url="true">Query</a>
74-
</li>
75-
</ul>
9+
<header>
10+
<div id="header-content" th:fragment="navigation-content" hx-swap-oob="true">
11+
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
12+
<div class="container-fluid">
13+
<a class="navbar-brand" href="#">Cosmos</a>
14+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse"
15+
aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
16+
<span class="navbar-toggler-icon"></span>
17+
</button>
18+
<div class="collapse navbar-collapse" id="navbarCollapse">
19+
<ul class="navbar-nav me-auto mb-2 mb-md-0">
20+
<li class="nav-item">
21+
<a class="nav-link"
22+
th:classappend="${activePage == 'home' ? 'active' : ''}"
23+
href="/home"
24+
hx-get="/home"
25+
hx-target="#main-content"
26+
hx-swap="morph"
27+
hx-push-url="true">Home</a>
28+
</li>
29+
<li class="nav-item">
30+
<a class="nav-link"
31+
th:classappend="${activePage == 'perspective' ? 'active' : ''}"
32+
href="/perspective"
33+
hx-get="/perspective"
34+
hx-target="#main-content"
35+
hx-swap="morph"
36+
hx-push-url="true">Perspective</a>
37+
</li>
38+
<li class="nav-item">
39+
<a class="nav-link"
40+
th:classappend="${activePage == 'data' ? 'active' : ''}"
41+
href="/data"
42+
hx-get="/data"
43+
hx-target="#main-content"
44+
hx-swap="morph"
45+
hx-push-url="true">Data</a>
46+
</li>
47+
<li class="nav-item">
48+
<a class="nav-link"
49+
th:classappend="${activePage == 'knowledge' ? 'active' : ''}"
50+
href="/knowledge"
51+
hx-get="/knowledge"
52+
hx-target="#main-content"
53+
hx-swap="morph"
54+
hx-push-url="true">Knowledge</a>
55+
</li>
56+
<li class="nav-item">
57+
<a class="nav-link"
58+
th:classappend="${activePage == 'quality' ? 'active' : ''}"
59+
href="/quality"
60+
hx-get="/quality"
61+
hx-target="#main-content"
62+
hx-swap="morph"
63+
hx-push-url="true">Quality</a>
64+
</li>
65+
<li class="nav-item">
66+
<a class="nav-link"
67+
th:classappend="${activePage == 'query' ? 'active' : ''}"
68+
href="/query"
69+
hx-get="/query"
70+
hx-target="#main-content"
71+
hx-swap="morph"
72+
hx-push-url="true">Query</a>
73+
</li>
74+
</ul>
75+
</div>
7676
</div>
77-
</div>
78-
</nav>
77+
</nav>
78+
</div>
7979
</header>
80-
8180
</body>
8281
</html>

src/main/resources/templates/home.html

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,44 +7,47 @@
77
<title>Home</title>
88
</head>
99
<body>
10-
11-
<header id="header-content" layout:fragment="header-content" th:replace="~{fragments/navigation :: navigation-content}"></header>
12-
13-
<main id="main-content" class="container flex-shrink-0" th:fragment="main-content" layout:fragment="main-content">
14-
<h1>Welcome Home!</h1>
15-
<table class="table table-striped table-hover">
16-
<thead>
17-
<tr>
18-
<th scope="col">#</th>
19-
<th scope="col">First</th>
20-
<th scope="col">Last</th>
21-
<th scope="col">Handle</th>
22-
</tr>
23-
</thead>
24-
<tbody>
25-
<tr>
26-
<th scope="row">1</th>
27-
<td>Mark</td>
28-
<td>Otto</td>
29-
<td>@mdo</td>
30-
</tr>
31-
<tr>
32-
<th scope="row">2</th>
33-
<td>Jacob</td>
34-
<td>Thornton</td>
35-
<td>@fat</td>
36-
</tr>
37-
<tr>
38-
<th scope="row">3</th>
39-
<td>John</td>
40-
<td>Doe</td>
41-
<td>@social</td>
42-
</tr>
43-
</tbody>
44-
</table>
10+
<header>
11+
<div id="header-content" layout:fragment="header-content"
12+
th:replace="~{fragments/navigation :: navigation-content}"></div>
13+
</header>
14+
<main>
15+
<div id="main-content" th:fragment="main-content" layout:fragment="main-content">
16+
<h1>Welcome Home!</h1>
17+
<table class="table table-striped table-hover">
18+
<thead>
19+
<tr>
20+
<th scope="col">#</th>
21+
<th scope="col">First</th>
22+
<th scope="col">Last</th>
23+
<th scope="col">Handle</th>
24+
</tr>
25+
</thead>
26+
<tbody>
27+
<tr>
28+
<th scope="row">1</th>
29+
<td>Mark</td>
30+
<td>Otto</td>
31+
<td>@mdo</td>
32+
</tr>
33+
<tr>
34+
<th scope="row">2</th>
35+
<td>Jacob</td>
36+
<td>Thornton</td>
37+
<td>@fat</td>
38+
</tr>
39+
<tr>
40+
<th scope="row">3</th>
41+
<td>John</td>
42+
<td>Doe</td>
43+
<td>@social</td>
44+
</tr>
45+
</tbody>
46+
</table>
47+
</div>
4548
</main>
46-
47-
<footer id="footer-content" class="footer mt-auto py-3 bg-light" layout:fragment="footer-content" th:replace="~{fragments/footer :: #footer-content}"></footer>
48-
49+
<footer>
50+
<div id="footer-content" layout:fragment="footer-content" th:replace="~{fragments/footer :: #footer-content}"></div>
51+
</footer>
4952
</body>
5053
</html>

src/main/resources/templates/knowledge.html

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
<title>Knowledge</title>
66
</head>
77
<body>
8-
9-
<header id="header-content" layout:fragment="header-content" th:replace="~{fragments/navigation :: navigation-content}"></header>
10-
11-
<main id="main-content" class="container flex-shrink-0" th:fragment="main-content" layout:fragment="main-content">
12-
<h1>Knowledge View</h1>
13-
<p>This is the content for the Knowledge page.</p>
8+
<header>
9+
<div id="header-content" layout:fragment="header-content"
10+
th:replace="~{fragments/navigation :: navigation-content}"></div>
11+
</header>
12+
<main>
13+
<div id="main-content" th:fragment="main-content" layout:fragment="main-content">
14+
<h1>Knowledge View</h1>
15+
<p>This is the content for the Knowledge page.</p>
16+
</div>
1417
</main>
15-
16-
<footer id="footer-content" class="footer mt-auto py-3 bg-light" layout:fragment="footer-content" th:replace="~{fragments/footer :: #footer-content}"></footer>
17-
18+
<footer>
19+
<div id="footer-content" layout:fragment="footer-content" th:replace="~{fragments/footer :: #footer-content}"></div>
20+
</footer>
1821
</body>
1922
</html>
Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<!doctype html>
22
<html lang="en" class="h-100" xmlns:th="http://www.thymeleaf.org"
3-
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
3+
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://www.ultraq.net.nz/thymeleaf/layout ">
45
<head>
56
<meta charset="utf-8">
67
<meta name="viewport" content="width=device-width, initial-scale=1">
@@ -13,24 +14,27 @@
1314
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js"
1415
integrity="sha384-/TgkGk7p307TH7EXJDuUlgG3Ce1UVolAOFopFekQkkXihi5u/6OCvVKyz1W+idaz"
1516
crossorigin="anonymous"></script>
17+
<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/morph@3.14.7/dist/cdn.min.js"></script>
18+
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.15.1/dist/cdn.min.js"></script>
1619

1720
<style>
1821
body {
1922
padding-top: 56px;
2023
}
2124

22-
.footer {
23-
background-color: #f5f5f5;
24-
}
2525
</style>
2626
</head>
27-
<body class="d-flex flex-column h-100">
28-
29-
<header id="header-content" layout:fragment="header-content"></header>
30-
31-
<main id="main-content" layout:fragment="main-content"></main>
32-
33-
<footer id="footer-content" layout:fragment="footer-content"></footer>
34-
27+
<body class="d-flex flex-column h-100" hx-ext="alpine-morph">
28+
<header>
29+
<div id="header-content" layout:fragment="header-content"></div>
30+
</header>
31+
<main>
32+
<div class="container flex-shrink-0">
33+
<div id="main-content" layout:fragment="main-content"></div>
34+
</div>
35+
</main>
36+
<footer class="footer mt-auto py-3 bg-light">
37+
<div id="footer-content" layout:fragment="footer-content"></div>
38+
</footer>
3539
</body>
3640
</html>

0 commit comments

Comments
 (0)