forked from UKSOURCE/cms.hailearning.edu.vn
feat: Add initial CMS for home page content management, including sections for hero, testimonials, partners, and more.
This commit is contained in:
175
views/admin/home/sections/blogPreview.ejs
Normal file
175
views/admin/home/sections/blogPreview.ejs
Normal file
@@ -0,0 +1,175 @@
|
||||
<!-- Blog Preview Tab -->
|
||||
<div class="tab-pane fade" id="blogpreview" role="tabpanel">
|
||||
<div class="row g-4">
|
||||
<!-- Basic Info -->
|
||||
<div class="col-md-12">
|
||||
<div class="card border shadow-sm">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0">
|
||||
<i class="fas fa-info-circle me-2"></i>Basic Information & Blog Selection
|
||||
</h6>
|
||||
<span class="badge bg-info text-dark">CMS will automatically fetch the 3 latest posts if no specific blog is
|
||||
selected.</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-medium">Heading</label>
|
||||
<input type="text" class="form-control" id="blogPreviewHeading"
|
||||
value="<%= data.blogPreview?.heading || '' %>" placeholder="e.g., Latest Insights & Updates" />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-medium">Subheading</label>
|
||||
<input type="text" class="form-control" id="blogPreviewSubheading"
|
||||
value="<%= data.blogPreview?.subheading || '' %>" placeholder="e.g., Visa Tips & Guides" />
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 mt-4">
|
||||
<label class="form-label fw-bold"><i class="fas fa-check-square me-2"></i>Select Featured Blogs (Direct
|
||||
from Blog Module)</label>
|
||||
<p class="text-muted small mb-3">Select blog posts to prioritize on the home page. If none are selected,
|
||||
the system will use the 3 latest posts.</p>
|
||||
<div class="row g-3 blog-selector-container"
|
||||
style="max-height: 400px; overflow-y: auto; border: 1px solid #eee; padding: 15px; border-radius: 8px;">
|
||||
<% if (allBlogs && allBlogs.length> 0) { %>
|
||||
<% allBlogs.forEach(blog=> {
|
||||
const isSelected = data.blogPreview?.selectedBlogIds && data.blogPreview.selectedBlogIds.some(id =>
|
||||
id.toString() === blog._id.toString());
|
||||
%>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 blog-select-card <%= isSelected ? 'border-primary bg-light' : '' %>"
|
||||
onclick="toggleBlogSelection(this, '<%= blog._id %>')"
|
||||
style="cursor: pointer; transition: all 0.2s;">
|
||||
<div class="position-absolute top-0 end-0 m-2">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input blog-checkbox" type="checkbox" value="<%= blog._id %>"
|
||||
<%=isSelected ? 'checked' : '' %> onclick="event.stopPropagation();
|
||||
handleCheckboxChange(this)">
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
src="<%= blog.featuredImage ? getFullImageUrl(blog.featuredImage, backendUrl) : '/assets/img/placeholder.jpg' %>"
|
||||
class="card-img-top" style="height: 210px; object-fit: cover;">
|
||||
<div class="card-body p-2">
|
||||
<h6 class="card-title small fw-bold mb-1" title="<%= blog.title %>"
|
||||
style="display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; height: 2.6em; line-height: 1.3em;">
|
||||
<%= blog.title %>
|
||||
</h6>
|
||||
<p class="card-text tiny text-muted mb-0">
|
||||
<%= blog.publishedAt ? new Date(blog.publishedAt).toLocaleDateString('vi-VN') : '' %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% }) %>
|
||||
<% } else { %>
|
||||
<div class="col-12 text-center py-4">
|
||||
<p class="text-muted">No published blogs found. Please create some blogs first.</p>
|
||||
<a href="/admin/blog/create" class="btn btn-sm btn-outline-primary">Create Blog</a>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CTA Button -->
|
||||
<div class="col-md-12">
|
||||
<div class="card border shadow-sm">
|
||||
<div class="card-header bg-white">
|
||||
<h6 class="mb-0">
|
||||
<i class="fas fa-mouse-pointer me-2"></i>CTA Button
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-medium">Label</label>
|
||||
<input type="text" class="form-control" id="blogPreviewCtaLabel"
|
||||
value="<%= data.blogPreview?.ctaButton?.label || '' %>" placeholder="e.g., View All Articles" />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-medium">Link</label>
|
||||
<input type="text" class="form-control" id="blogPreviewCtaHref"
|
||||
value="<%= data.blogPreview?.ctaButton?.href || '' %>" placeholder="/blog" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleBlogSelection(card, blogId) {
|
||||
const checkbox = card.querySelector('.blog-checkbox');
|
||||
const isChecking = !checkbox.checked;
|
||||
|
||||
if (isChecking) {
|
||||
const checkedCount = document.querySelectorAll('.blog-checkbox:checked').length;
|
||||
if (checkedCount >= 3) {
|
||||
alert('You can only select up to 3 blogs.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
checkbox.checked = isChecking;
|
||||
handleCheckboxUpdate(card, checkbox.checked);
|
||||
}
|
||||
|
||||
function handleCheckboxChange(checkbox) {
|
||||
if (checkbox.checked) {
|
||||
const checkedCount = document.querySelectorAll('.blog-checkbox:checked').length;
|
||||
if (checkedCount > 3) {
|
||||
checkbox.checked = false;
|
||||
alert('You can only select up to 3 blogs.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
const card = checkbox.closest('.blog-select-card');
|
||||
handleCheckboxUpdate(card, checkbox.checked);
|
||||
}
|
||||
|
||||
function handleCheckboxUpdate(card, isChecked) {
|
||||
if (isChecked) {
|
||||
card.classList.add('border-primary', 'bg-light');
|
||||
} else {
|
||||
card.classList.remove('border-primary', 'bg-light');
|
||||
}
|
||||
}
|
||||
|
||||
// Đăng ký scraper cho Blog Preview
|
||||
window.homeScrapers = window.homeScrapers || {};
|
||||
window.homeScrapers.blogPreview = () => {
|
||||
const selectedIds = [];
|
||||
document.querySelectorAll('.blog-checkbox:checked').forEach(cb => {
|
||||
selectedIds.push(cb.value);
|
||||
});
|
||||
|
||||
// Chúng ta vẫn giữ cấu trúc cũ cho items nếu muốn preview offline,
|
||||
// nhưng server sẽ ưu tiên dùng selectedBlogIds để populate dữ liệu mới nhất.
|
||||
return {
|
||||
heading: document.getElementById('blogPreviewHeading').value,
|
||||
subheading: document.getElementById('blogPreviewSubheading').value,
|
||||
ctaButton: {
|
||||
label: document.getElementById('blogPreviewCtaLabel').value,
|
||||
href: document.getElementById('blogPreviewCtaHref').value
|
||||
},
|
||||
selectedBlogIds: selectedIds,
|
||||
items: [] // Server side will handle full items content
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.tiny {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.blog-select-card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user