blog
This commit is contained in:
+283
@@ -638,6 +638,186 @@
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Blog Section ---- */
|
||||
.blog-section {
|
||||
padding: 3rem 0;
|
||||
background: #08080c;
|
||||
color: #e8e8f0;
|
||||
}
|
||||
.blog-section h2 {
|
||||
color: #e8e8f0;
|
||||
}
|
||||
.blog-search-wrap {
|
||||
max-width: 500px;
|
||||
margin: 0 auto 2rem;
|
||||
}
|
||||
.blog-search {
|
||||
width: 100%;
|
||||
padding: 0.75rem 1rem;
|
||||
font-size: 0.85rem;
|
||||
background: #12121c;
|
||||
border: 1px solid #1a1a2e;
|
||||
border-radius: 0.5rem;
|
||||
color: #e8e8f0;
|
||||
font-family: Inter, sans-serif;
|
||||
transition: border-color 0.2s;
|
||||
outline: none;
|
||||
}
|
||||
.blog-search:focus {
|
||||
border-color: #00f5ff;
|
||||
box-shadow: 0 0 0 2px rgba(0,245,255,0.15);
|
||||
}
|
||||
.blog-search::placeholder {
|
||||
color: rgba(232,232,240,0.35);
|
||||
}
|
||||
.blog-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 1.25rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.blog-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
@media (max-width: 576px) {
|
||||
.blog-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
.blog-card {
|
||||
background: #12121c;
|
||||
border: 1px solid #1a1a2e;
|
||||
border-radius: 0.6rem;
|
||||
padding: 1.25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: transform 0.2s, border-color 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
.blog-card:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: #00f5ff;
|
||||
box-shadow: 0 4px 20px rgba(0,245,255,0.08);
|
||||
}
|
||||
.blog-card-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.blog-badge {
|
||||
display: inline-block;
|
||||
padding: 0.15rem 0.5rem;
|
||||
border-radius: 3rem;
|
||||
font-size: 0.6rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: #08080c;
|
||||
}
|
||||
.blog-badge-speed-run {
|
||||
background: #f472b6;
|
||||
}
|
||||
.blog-badge-guide {
|
||||
background: #a78bfa;
|
||||
}
|
||||
.blog-badge-howto {
|
||||
background: #00f5ff;
|
||||
}
|
||||
.blog-badge-news {
|
||||
background: #ffaa00;
|
||||
}
|
||||
.blog-badge-default {
|
||||
background: #a78bfa;
|
||||
}
|
||||
.blog-agent {
|
||||
display: inline-block;
|
||||
padding: 0.15rem 0.45rem;
|
||||
border-radius: 3rem;
|
||||
font-size: 0.56rem;
|
||||
font-weight: 600;
|
||||
background: rgba(0,245,255,0.15);
|
||||
color: #00f5ff;
|
||||
border: 1px solid rgba(0,245,255,0.25);
|
||||
}
|
||||
.blog-date {
|
||||
font-size: 0.7rem;
|
||||
color: rgba(232,232,240,0.45);
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
.blog-card h3 {
|
||||
font-family: 'Inter Tight', sans-serif;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
margin: 0 0 0.5rem;
|
||||
line-height: 1.35;
|
||||
}
|
||||
.blog-card h3 a {
|
||||
color: #e8e8f0;
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.blog-card h3 a:hover {
|
||||
color: #00f5ff;
|
||||
}
|
||||
.blog-teaser {
|
||||
font-size: 0.78rem;
|
||||
color: rgba(232,232,240,0.65);
|
||||
line-height: 1.55;
|
||||
margin-bottom: 1rem;
|
||||
flex: 1;
|
||||
}
|
||||
.blog-readmore {
|
||||
font-size: 0.75rem;
|
||||
color: #00f5ff;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: opacity 0.2s;
|
||||
margin-top: auto;
|
||||
}
|
||||
.blog-readmore:hover {
|
||||
opacity: 0.75;
|
||||
}
|
||||
.blog-empty {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
color: rgba(232,232,240,0.5);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.blog-pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem 0;
|
||||
}
|
||||
.blog-page-btn {
|
||||
padding: 0.4rem 1rem;
|
||||
font-size: 0.78rem;
|
||||
background: #12121c;
|
||||
border: 1px solid #1a1a2e;
|
||||
border-radius: 0.4rem;
|
||||
color: #e8e8f0;
|
||||
cursor: pointer;
|
||||
font-family: Inter, sans-serif;
|
||||
transition: border-color 0.2s, background 0.2s;
|
||||
}
|
||||
.blog-page-btn:hover:not(:disabled) {
|
||||
border-color: #00f5ff;
|
||||
background: rgba(0,245,255,0.08);
|
||||
}
|
||||
.blog-page-btn:disabled {
|
||||
opacity: 0.3;
|
||||
cursor: default;
|
||||
}
|
||||
.blog-page-info {
|
||||
font-size: 0.78rem;
|
||||
color: rgba(232,232,240,0.55);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -1224,6 +1404,20 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="blog-section" id="blog">
|
||||
<div class="container">
|
||||
<div class="text-center mb-4">
|
||||
<div class="hr"></div>
|
||||
<h2>Latest from the Blog</h2>
|
||||
</div>
|
||||
<div class="blog-search-wrap">
|
||||
<input type="text" class="blog-search" id="blogSearch" placeholder="Search posts..." />
|
||||
</div>
|
||||
<div class="blog-grid" id="blogGrid"></div>
|
||||
<div class="blog-pagination" id="blogPagination"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
@@ -1463,6 +1657,95 @@
|
||||
.classList.add("active");
|
||||
});
|
||||
});
|
||||
|
||||
/* ---- Blog Module ---- */
|
||||
var blogState = {
|
||||
allPosts: [],
|
||||
filteredPosts: [],
|
||||
currentPage: 1,
|
||||
perPage: 6,
|
||||
searchTerm: ""
|
||||
};
|
||||
|
||||
function formatDate(dateStr) {
|
||||
var d = new Date(dateStr + "T00:00:00Z");
|
||||
var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
||||
return months[d.getUTCMonth()] + " " + d.getUTCDate() + ", " + d.getUTCFullYear();
|
||||
}
|
||||
|
||||
function badgeClass(area) {
|
||||
var m = {"speed-run":"speed-run","guide":"guide","howto":"howto","news":"news"};
|
||||
return m[area] || "default";
|
||||
}
|
||||
|
||||
function renderBlog() {
|
||||
var grid = document.getElementById("blogGrid");
|
||||
var search = (blogState.searchTerm || "").toLowerCase();
|
||||
blogState.filteredPosts = blogState.allPosts.filter(function(p) {
|
||||
if (!search) return true;
|
||||
return (p.headline + " " + p.teaser).toLowerCase().indexOf(search) !== -1;
|
||||
});
|
||||
var total = blogState.filteredPosts.length;
|
||||
var totalPages = Math.max(1, Math.ceil(total / blogState.perPage));
|
||||
if (blogState.currentPage > totalPages) blogState.currentPage = totalPages;
|
||||
var start = (blogState.currentPage - 1) * blogState.perPage;
|
||||
var pagePosts = blogState.filteredPosts.slice(start, start + blogState.perPage);
|
||||
|
||||
var html = "";
|
||||
if (pagePosts.length === 0) {
|
||||
html = "<div class=\"blog-empty\">No posts match your search.</div>";
|
||||
} else {
|
||||
for (var i = 0; i < pagePosts.length; i++) {
|
||||
var p = pagePosts[i];
|
||||
var bc = badgeClass(p.area);
|
||||
var agentHtml = "";
|
||||
if (p.agent) agentHtml = "<span class=\"blog-agent\">" + p.agent + "</span>";
|
||||
html += "<div class=\"blog-card\">" +
|
||||
"<div class=\"blog-card-top\">" +
|
||||
"<span class=\"blog-badge blog-badge-" + bc + "\">" + p.area + "</span>" +
|
||||
agentHtml +
|
||||
"</div>" +
|
||||
"<div class=\"blog-date\">" + formatDate(p.date) + "</div>" +
|
||||
"<h3><a href=\"" + p.link + "\">" + p.headline + "</a></h3>" +
|
||||
"<p class=\"blog-teaser\">" + p.teaser + "</p>" +
|
||||
"<a href=\"" + p.link + "\" class=\"blog-readmore\">Read more →</a>" +
|
||||
"</div>";
|
||||
}
|
||||
}
|
||||
grid.innerHTML = html;
|
||||
|
||||
var pag = document.getElementById("blogPagination");
|
||||
var pagHtml = "";
|
||||
if (totalPages > 1) {
|
||||
pagHtml += "<button class=\"blog-page-btn\" onclick=\"blogGo(1)\"" + (blogState.currentPage <= 1 ? " disabled\"" : "\"") + ">«</button>";
|
||||
pagHtml += "<button class=\"blog-page-btn\" onclick=\"blogGo(" + (blogState.currentPage - 1) + ")\"" + (blogState.currentPage <= 1 ? " disabled\"" : "\"") + ">‹ Prev</button>";
|
||||
pagHtml += "<span class=\"blog-page-info\">Page " + blogState.currentPage + " of " + totalPages + "</span>";
|
||||
pagHtml += "<button class=\"blog-page-btn\" onclick=\"blogGo(" + (blogState.currentPage + 1) + ")\"" + (blogState.currentPage >= totalPages ? " disabled\"" : "\"") + ">Next ›</button>";
|
||||
pagHtml += "<button class=\"blog-page-btn\" onclick=\"blogGo(" + totalPages + ")\"" + (blogState.currentPage >= totalPages ? " disabled\"" : "\"") + ">»</button>";
|
||||
}
|
||||
pag.innerHTML = pagHtml;
|
||||
}
|
||||
|
||||
function blogGo(page) {
|
||||
blogState.currentPage = page;
|
||||
renderBlog();
|
||||
}
|
||||
|
||||
fetch("blog/index.json?_=" + Date.now())
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) {
|
||||
blogState.allPosts = data.posts;
|
||||
renderBlog();
|
||||
})
|
||||
.catch(function() {
|
||||
document.getElementById("blogGrid").innerHTML = "<div class=\"blog-empty\">Could not load blog posts.</div>";
|
||||
});
|
||||
|
||||
document.getElementById("blogSearch").addEventListener("input", function() {
|
||||
blogState.searchTerm = this.value;
|
||||
blogState.currentPage = 1;
|
||||
renderBlog();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user