This commit is contained in:
oliver
2026-04-25 05:44:03 -03:00
parent 5bbba4ba69
commit 61ca437c83
2 changed files with 324 additions and 34 deletions
+242 -34
View File
@@ -1065,9 +1065,96 @@
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.news-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
flex-wrap: wrap;
margin-bottom: 24px;
}
.news-search {
width: min(420px, 100%);
padding: 14px 18px;
border-radius: 999px;
border: 1px solid rgba(230, 81, 0, 0.18);
background: rgba(255, 243, 224, 0.8);
color: var(--white);
font: inherit;
}
.news-search:focus {
outline: none;
border-color: var(--gold);
box-shadow: 0 0 0 3px var(--gold-glow);
}
.news-meta {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
justify-content: flex-end;
}
.news-count {
font-size: 0.72rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--grey);
}
.news-pager {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.news-page-btn {
padding: 12px 16px;
border-radius: 999px;
border: 1px solid rgba(93, 64, 55, 0.16);
background: rgba(255, 243, 224, 0.82);
color: var(--white);
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
cursor: pointer;
transition: border-color 0.2s, color 0.2s, background 0.2s;
}
.news-page-btn:hover:not(:disabled) {
border-color: var(--gold);
color: var(--gold);
}
.news-page-btn:disabled {
opacity: 0.45;
cursor: not-allowed;
}
.news-card {
padding: 22px;
padding: 0;
border-radius: 24px;
overflow: hidden;
background: var(--card);
}
.news-card-image {
width: 100%;
height: 190px;
object-fit: cover;
}
.news-card-body {
display: flex;
flex-direction: column;
justify-content: space-between;
min-height: 210px;
padding: 20px;
background: var(--lift);
}
.news-area,
@@ -1108,6 +1195,29 @@
color: var(--grey);
}
.news-link {
display: inline-flex;
align-items: center;
gap: 8px;
align-self: flex-start;
margin-top: 18px;
font-size: 0.72rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--gold);
}
.news-empty {
grid-column: 1 / -1;
padding: 24px;
border-radius: 24px;
background: rgba(255, 243, 224, 0.82);
border: 1px solid rgba(93, 64, 55, 0.12);
color: var(--silver);
text-align: center;
}
.pricing-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
align-items: stretch;
@@ -1980,47 +2090,32 @@
</p>
</div>
</div>
<div class="news-toolbar">
<input
type="search"
id="news-search"
class="news-search"
placeholder="Search headlines, verticals, and summaries"
aria-label="Search blog posts"
/>
<div class="news-meta">
<span class="news-count" id="news-count">Loading posts...</span>
<div class="news-pager">
<button type="button" class="news-page-btn" id="news-prev">Last Posts</button>
<button type="button" class="news-page-btn" id="news-next">Next Posts</button>
</div>
</div>
</div>
<div
class="news-grid"
id="news-grid"
data-mf-stagger-animation="fade-up"
data-mf-stagger-gap="100"
data-mf-stagger-duration="650"
data-mf-stagger-distance="28"
data-mf-stagger-once="true"
>
<article class="news-card">
<div class="news-area">NGO</div>
<h3 class="news-title">How a regional NGO cut grant reporting time by 70%</h3>
<p class="news-teaser">
Donor reconciliation and project cost allocation moved into one
workflow, returning 15 hours a week to mission work instead of admin.
</p>
<span class="news-date">June 2025</span>
</article>
<article class="news-card">
<div class="news-area">Startups</div>
<h3 class="news-title">Why investors love clean Odoo data rooms</h3>
<p class="news-teaser">
Founders shared how structured finance and CRM data reduced scramble during due diligence.
</p>
<span class="news-date">May 2025</span>
</article>
<article class="news-card">
<div class="news-area">Manufacturing</div>
<h3 class="news-title">Real-time BoM costing saved a factory $40k</h3>
<p class="news-teaser">
Live material cost tracking helped the team reprice before margin loss became irreversible.
</p>
<span class="news-date">April 2025</span>
</article>
<article class="news-card">
<div class="news-area">Restaurants</div>
<h3 class="news-title">Food cost under control before it hit the P&amp;L</h3>
<p class="news-teaser">
Linking POS data to supplier invoices exposed a 12% creep in week one instead of month three.
</p>
<span class="news-date">March 2025</span>
</article>
<div class="news-empty">Loading posts...</div>
</div>
</section>
@@ -2356,6 +2451,119 @@
</div>
</div>
<script>
(function () {
var POSTS_URL = "posts.json";
var PAGE_SIZE = 8;
var grid = document.getElementById("news-grid");
var search = document.getElementById("news-search");
var prevBtn = document.getElementById("news-prev");
var nextBtn = document.getElementById("news-next");
var count = document.getElementById("news-count");
var allPosts = [];
var filteredPosts = [];
var currentPage = 0;
function formatDate(value) {
var date = new Date(value);
if (isNaN(date.getTime())) return value;
return date.toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
});
}
function postMarkup(post) {
return [
'<a class="news-card" href="' + post.link + '">',
'<img class="news-card-image" src="' + post.image + '" alt="' + post.headline.replace(/"/g, "&quot;") + '">',
'<div class="news-card-body">',
'<div>',
'<div class="news-area">' + post.vertical + '</div>',
'<h3 class="news-title">' + post.headline + '</h3>',
'<p class="news-teaser">' + post.shortText + '</p>',
'<span class="news-date">' + formatDate(post.date) + '</span>',
'</div>',
'<span class="news-link">Read article &#8594;</span>',
'</div>',
'</a>',
].join("");
}
function emptyMarkup(text) {
return '<div class="news-empty">' + text + '</div>';
}
function updateCount() {
var total = filteredPosts.length;
if (!total) {
count.textContent = "0 posts";
return;
}
var start = currentPage * PAGE_SIZE + 1;
var end = Math.min(start + PAGE_SIZE - 1, total);
count.textContent = start + "-" + end + " of " + total + " posts";
}
function render() {
var start = currentPage * PAGE_SIZE;
var pagePosts = filteredPosts.slice(start, start + PAGE_SIZE);
if (!pagePosts.length) {
grid.innerHTML = emptyMarkup("No posts match your search.");
} else {
grid.innerHTML = pagePosts.map(postMarkup).join("");
}
prevBtn.disabled = currentPage === 0;
nextBtn.disabled = start + PAGE_SIZE >= filteredPosts.length;
updateCount();
}
function applyFilter() {
var term = (search.value || "").trim().toLowerCase();
filteredPosts = allPosts.filter(function (post) {
if (!term) return true;
var haystack = [post.headline, post.vertical, post.shortText]
.join(" ")
.toLowerCase();
return haystack.indexOf(term) !== -1;
});
currentPage = 0;
render();
}
prevBtn.addEventListener("click", function () {
if (currentPage === 0) return;
currentPage -= 1;
render();
});
nextBtn.addEventListener("click", function () {
if ((currentPage + 1) * PAGE_SIZE >= filteredPosts.length) return;
currentPage += 1;
render();
});
search.addEventListener("input", applyFilter);
fetch(POSTS_URL)
.then(function (response) {
return response.json();
})
.then(function (posts) {
allPosts = Array.isArray(posts) ? posts : [];
filteredPosts = allPosts.slice();
render();
})
.catch(function () {
grid.innerHTML = emptyMarkup("Posts could not be loaded right now.");
count.textContent = "Posts unavailable";
prevBtn.disabled = true;
nextBtn.disabled = true;
});
})();
</script>
<script>
(function () {
"use strict";