Mục tiêu

Trong bài này, chúng ta sẽ cùng học cách tạo giao diện cho một theme ezyplatform blog đơn giản.

Bài hướng dẫn sẽ giúp bạn:

  • Hiểu cấu trúc thư mục của một theme.
  • Tích hợp mã nguồn HTML, CSS, JS từ repo bên ngoài.
  • Chỉnh sửa và tổ chức lại các phần tử thành các fragment theo chuẩn của Thymeleaf.
  • Hoàn thiện giao diện và khởi chạy thử nghiệm theme.

1. Chuẩn bị môi trường và mã nguồn

Trước hết, bạn cần có:

  • Một dự án theme của EzyPlatform đã được khởi tạo sẵn (nếu chưa, hãy tham khảo hướng dẫn này).
  • Cài đặt Java, Maven, và Git.
  • Trình soạn thảo IntelliJ IDEA.

Repo mã nguồn giao diện

Trong hướng dẫn này, chúng ta sử dụng mã nguồn giao diện có sẵn tại: https://github.com/codingstella/personal-blog-website

Đây là một giao diện blog đơn giản, được cộng đồng chia sẻ.


2. Clone mã nguồn và cấu trúc thư mục

Mở terminal và clone dự án:

git clone https://github.com/codingstella/personal-blog-website

Sau khi clone xong, bạn sẽ thấy cấu trúc thư mục như:

personal-blog-website/
 ├── assets/
 ├── index.html
 ├── style.css
 ├── js/
 └── images/

Tuy nhiên, khi tích hợp vào EzyPlatform, ta sẽ phải điều chỉnh lại cấu trúc này cho phù hợp.


3. Xóa và thay thế thư mục tĩnh

Trong module theme của dự án theme EzyPlatform của bạn (ví dụ: personal/personal-theme), bạn sẽ thấy một thư mục có tên:

src/main/resources/static

Đây là nơi chứa các tài nguyên tĩnh như ảnh, CSS, JS.

Thực hiện:

  1. Xóa toàn bộ nội dung bên trong static/.
  2. Copy tất cả nội dung trong thư mục assets/ của repo personal-blog-website vào static/.

Kết quả:

src/main/resources/static/
 ├── css/
 ├── js/
 ├── images/
 └── fonts/

4. Chỉnh sửa liên kết CSS/JS trong template

Trong dự án personal-blog-website, file chính là index.html.

Ở đó, CSS được gọi như:

<link rel="stylesheet" href="./assets/css/style.css">

Trong EzyPlatform, đường dẫn static không dùng ./assets/ nữa, mà chỉ cần:

<link rel="stylesheet" href="/css/style.css">

Vì sao?

Vì khi EzyPlatform chạy, nó tự động ánh xạ đường dẫn tập tin từ /static ở cấp /.

Hãy tìm và thay thế toàn bộ ./assets//

Ví dụ:

  • ./assets/images/.../images/...
  • ./assets/js/.../js/...

5. Tạo cấu trúc Thymeleaf Template

Trong EzyPlatform, các file HTML được chia thành các fragment:

src/main/resources/templates/
 ├── fragments/
 │   ├── header.html
 │   ├── footer.html
 │   └── ...
 ├── home.html
 └── page.html

Chia nội dung

Từ index.html trong repo gốc:

  • Phần đầu trang (<header>...</header>)fragments/header.html
  • Phần chân trang (<footer>...</footer>)fragments/footer.html
  • Phần giữa (<main>...</main>)home.html

6. Kết hợp các fragment vào layout

Tạo file layout.html trong thư mục templates/ với nội dung như sau:

<!DOCTYPE html>
<html
	xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	xmlns:ezy="http://www.ezyplatform.com/thymeleaf/layout">

<head th:remove="tag">
	<link rel="stylesheet" type="text/css" ezy:vhref="/css/main.css" />
</head>
<body th:remove="tag">
<div class="wrapper light-theme" id="theme-wrapper">
	<header class="header">
		<div th:replace="~{fragments/header :: header}"></div>
	</header>
	<main>
		<div layout:fragment="content"></div>
	</main>
	<footer th:replace="~{fragments/footer :: footer}"></footer>
</div>

<div id="loadingScreen" class="screen-loading d-none">
	<i class="fas fa-3x fa-sync fa-spin text-secondary"></i>
</div>

<th:block layout:fragment="modals"></th:block>

<!-- REQUIRED SCRIPTS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="module" src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.js"></script>
<script ezy:vsrc="/js/main.js" type="text/javascript"></script>

<!-- OPTIONAL SCRIPTS -->
<script layout:fragment="import-scripts" th:remove="tag"></script>
<script layout:fragment="pre-main-scripts" type="text/javascript"></script>
<script layout:fragment="scripts" type="text/javascript"></script>
<script layout:fragment="post-scripts" type="text/javascript"></script>
<script>
$( document ).ready(function() {
	ezyweb.formatDateStringElements();
	ezyweb.formatDateTimeStringElements();
	ezyweb.formatDateTimeMinuteStringElements();
	ezyweb.formatStatusTextElements();
	ezyweb.formatNumberWithCommasElements();
	if (ezyweb.lang) {
		ezyweb.appendLangParameterToLinks(ezyweb.lang);
	}
});
</script>
<script th:replace="~{fragments/header :: scripts}" type="text/javascript"></script>
<script th:replace="~{fragments/footer :: scripts}" type="text/javascript"></script>
</body>
</html>

7. Hiểu qua về Thymeleaf Fragment

Thymeleaf là một thư viện template dạng like HTML tức là gần như HTML (98%) còn lại là bổ sung thêm một số cú pháp để sử dụng biến.

Một “fragment” giúp bạn tái sử dụng các phần giao diện (như header/footer) ở nhiều trang.

Ví dụ header.html có thể định nghĩa:

<div th:fragment="header">
  <header>
    <h1>Welcome to My Blog</h1>
  </header>
</div>

Sau đó trong layout, chỉ cần gọi:

<th:replace="fragments/header :: header"></th:replace>

8. Kiểm tra và khởi động theme

Sau khi hoàn tất:

  1. Mở IDE và chạy tập tin test startup ví dụ PersonalThemeStartupTest nếu bạn đã chạy rồi thì không cần chạy lại.
  2. Truy cập http://localhost:8080 để xem kết quả.

Nếu mọi thứ đúng, bạn sẽ thấy một giao diện blog đơn giản hiển thị trên trình duyệt — chính là theme mới mà bạn vừa tạo!

Screenshot 2025-10-11 at 11.20.54.png

9. Ghi nhận công lao tác giả giao diện

Dù repo không đính kèm license, bạn nên thêm lời cảm ơn trong file README.md hoặc theme.rb:

# Credit
Giao diện được tham khảo và chỉnh sửa từ dự án:
https://github.com/codingstella/personal-blog-website

10. Tổng kết

Vậy là bạn đã:

  • Clone và tích hợp giao diện HTML/CSS vào theme EzyPlatform.
  • Chuyển đổi sang cấu trúc fragment của Thymeleaf.
  • Hiểu cách hoạt động của đường dẫn static trong EzyPlatform.

bài tiếp theo, bạn sẽ học cách kết nối theme này với module EzyArticle,

để hiển thị nội dung động từ cơ sở dữ liệu (bài viết, danh mục...).


Tài liệu tham khảo