Hoan thanh chuc nang Page

This commit is contained in:
2026-06-25 21:34:36 +07:00
parent 6fe098bc5b
commit 38d6b8234a
16 changed files with 204 additions and 111 deletions
@@ -8,102 +8,79 @@
</head>
<body>
<!--
Because the user wants absolute freedom to design the page using snippets,
we will render the blocks directly into the content fragment with NO constraining containers.
If they want a container, they can use a standard snippet.
-->
<!-- Render Editor.js Blocks -->
<div layout:fragment="content">
<!-- Render Editor.js Blocks -->
<th:block th:each="block : ${blocks}">
<!-- 1. HTML Snippet Block (Custom) -->
<th:block th:if="${block.type == 'snippet'}">
<div th:insert="~{'snippets/' + ${block.data.id}}"></div>
<!-- 1. HTML Snippet Block (Custom) -->
<th:block th:if="${block.type == 'snippet'}">
<div th:insert="~{'snippets/' + ${block.data.id}}" th:remove="tag"></div>
</th:block>
<!-- 2. Header Block -->
<th:block th:if="${block.type == 'header'}">
<th:block th:switch="${block.data.level}">
<h1 th:case="1" th:utext="${block.data.text}"></h1>
<h2 th:case="2" th:utext="${block.data.text}"></h2>
<h3 th:case="3" th:utext="${block.data.text}"></h3>
<h4 th:case="4" th:utext="${block.data.text}"></h4>
<h5 th:case="5" th:utext="${block.data.text}"></h5>
<h6 th:case="6" th:utext="${block.data.text}"></h6>
<h2 th:case="*" th:utext="${block.data.text}"></h2>
</th:block>
<!-- 2. Header Block -->
<th:block th:if="${block.type == 'header'}">
<!-- Editor.js header block has level (1-6) and text -->
<div class="container my-3">
<th:block th:switch="${block.data.level}">
<h1 th:case="1" th:utext="${block.data.text}"></h1>
<h2 th:case="2" th:utext="${block.data.text}"></h2>
<h3 th:case="3" th:utext="${block.data.text}"></h3>
<h4 th:case="4" th:utext="${block.data.text}"></h4>
<h5 th:case="5" th:utext="${block.data.text}"></h5>
<h6 th:case="6" th:utext="${block.data.text}"></h6>
<h2 th:case="*" th:utext="${block.data.text}"></h2>
</th:block>
</div>
</th:block>
<!-- 3. Paragraph Block -->
<th:block th:if="${block.type == 'paragraph'}">
<div class="container">
<p th:utext="${block.data.text}"></p>
</div>
</th:block>
<!-- 4. List Block -->
<th:block th:if="${block.type == 'list'}">
<div class="container">
<ul th:if="${block.data.style == 'unordered'}">
<li th:each="item : ${block.data.items}" th:utext="${item}"></li>
</ul>
<ol th:if="${block.data.style == 'ordered'}">
<li th:each="item : ${block.data.items}" th:utext="${item}"></li>
</ol>
</div>
</th:block>
<!-- 5. Image Block -->
<th:block th:if="${block.type == 'image'}">
<div class="container text-center my-4">
<img th:src="${block.data.file.url}" class="img-fluid" th:alt="${block.data.caption}" />
<p class="text-muted small mt-1" th:if="${block.data.caption}" th:utext="${block.data.caption}"></p>
</div>
</th:block>
<!-- 6. Quote Block -->
<th:block th:if="${block.type == 'quote'}">
<div class="container my-4">
<blockquote class="blockquote">
<p class="mb-0" th:utext="${block.data.text}"></p>
<footer class="blockquote-footer" th:if="${block.data.caption}" th:utext="${block.data.caption}"></footer>
</blockquote>
</div>
</th:block>
<!-- 7. Delimiter Block -->
<th:block th:if="${block.type == 'delimiter'}">
<div class="container text-center my-4">
<span style="font-size: 24px; letter-spacing: 10px; color: #ccc;">***</span>
</div>
</th:block>
<!-- 8. Table Block -->
<th:block th:if="${block.type == 'table'}">
<div class="container my-4">
<table class="table table-bordered">
<tbody>
<tr th:each="row, rowStat : ${block.data.content}">
<!-- If withHeadings is true, make first row <th> -->
<th:block th:if="${block.data.withHeadings == true and rowStat.index == 0}">
<th th:each="cell : ${row}" th:utext="${cell}"></th>
</th:block>
<th:block th:unless="${block.data.withHeadings == true and rowStat.index == 0}">
<td th:each="cell : ${row}" th:utext="${cell}"></td>
</th:block>
</tr>
</tbody>
</table>
</div>
</th:block>
</th:block>
<!-- 3. Paragraph Block -->
<th:block th:if="${block.type == 'paragraph'}">
<p th:utext="${block.data.text}"></p>
</th:block>
<!-- 4. List Block -->
<th:block th:if="${block.type == 'list'}">
<ul th:if="${block.data.style == 'unordered'}">
<li th:each="item : ${block.data.items}" th:utext="${item}"></li>
</ul>
<ol th:if="${block.data.style == 'ordered'}">
<li th:each="item : ${block.data.items}" th:utext="${item}"></li>
</ol>
</th:block>
<!-- 5. Image Block -->
<th:block th:if="${block.type == 'image'}">
<img th:src="${block.data.file.url}" th:alt="${block.data.caption}" />
<p th:if="${block.data.caption}" th:utext="${block.data.caption}"></p>
</th:block>
<!-- 6. Quote Block -->
<th:block th:if="${block.type == 'quote'}">
<blockquote>
<p th:utext="${block.data.text}"></p>
<footer th:if="${block.data.caption}" th:utext="${block.data.caption}"></footer>
</blockquote>
</th:block>
<!-- 7. Delimiter Block -->
<th:block th:if="${block.type == 'delimiter'}">
<hr />
</th:block>
<!-- 8. Table Block -->
<th:block th:if="${block.type == 'table'}">
<table>
<tbody>
<tr th:each="row, rowStat : ${block.data.content}">
<th:block th:if="${block.data.withHeadings == true and rowStat.index == 0}">
<th th:each="cell : ${row}" th:utext="${cell}"></th>
</th:block>
<th:block th:unless="${block.data.withHeadings == true and rowStat.index == 0}">
<td th:each="cell : ${row}" th:utext="${cell}"></td>
</th:block>
</tr>
</tbody>
</table>
</th:block>
</th:block>
</div>
</body>