Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f3dc688
News Cards Adding in the Landing Page
BytePaul Oct 9, 2025
a774f7a
Improve Latest News section with production support and content enhan…
BytePaul Oct 15, 2025
c9e637e
Fixed the Category Issue. Now it points to the Latest News Published …
BytePaul Oct 16, 2025
950cc18
Added Link to the Discourse News Feed for more news
BytePaul Oct 16, 2025
0a6c208
Added Link to the Discourse News Feed for more news
BytePaul Oct 16, 2025
897343b
style(news-section): match 'More news' button with FAQ style by using…
BytePaul Oct 16, 2025
975aa93
Merge branch 'master' into feature/landing-page-news-section
BytePaul Oct 18, 2025
77d0fb1
fix: address review feedback for news section implementation
BytePaul Oct 18, 2025
83b97e6
ci(news): add GitHub Actions workflow for scheduled data fetching
BytePaul Oct 23, 2025
27b18ea
Cleaned Up the CSS files
BytePaul Oct 27, 2025
0d51540
Replaced JS file with PY file for static json and improved news-colle…
BytePaul Oct 27, 2025
6c706a2
Updated workflow for fetching news
BytePaul Oct 27, 2025
68364e4
Improved comments
BytePaul Oct 27, 2025
7587d4a
Aligned the HTML file according to the new improvements
BytePaul Oct 27, 2025
8f407d4
Made Python version explicit and updated the action to v6
BytePaul Oct 27, 2025
ba69529
Removed unused fetch-news.js news-proxy.js and package.json as this i…
BytePaul Oct 27, 2025
fedb537
Irrelevant Due to the Addition of update-discourse-data.yml
BytePaul Oct 27, 2025
4f9dcf7
Merge branch 'master' into feature/landing-page-news-section
MakisH Oct 27, 2025
0d76a2e
Update _layouts/landing_page.html
MakisH Oct 27, 2025
025289c
Formatting
MakisH Oct 27, 2025
b5825b7
Allows news cards to wrap on Mobile
BytePaul Oct 28, 2025
722cdc4
Merge branch 'feature/landing-page-news-section' of https://github.co…
BytePaul Oct 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/update-discourse-data.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Update Discourse data

on:
workflow_dispatch:
schedule:
- cron: "0 6 * * *"

jobs:
update-discourse-data:
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.WEBSITE_UPDATER_APPID }}
private-key: ${{ secrets.WEBSITE_UPDATER_KEY }}

- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.14"

- name: Fetch latest news from Discourse
run: python tools/fetch-news.py

- name: Configure Git author
run: |
git config --local user.name "precice-bot"
git config --local user.email "info@precice.org"

- name: Commit changes (if any)
run: |
git add assets/data/news.json
git commit -m "Update Discourse news data [skip ci]" || echo "No changes to commit"

- name: Push commit
uses: ad-m/github-push-action@master
with:
github_token: ${{ steps.app-token.outputs.token }}
branch: ${{ github.ref }}
7 changes: 3 additions & 4 deletions _layouts/landing_page.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

{% include footer.html %}

<script src="{{ "js/github-queries.js" }}"></script>
<script src="{{ '/js/github-queries.js' | relative_url }}"></script>

<script src="{{ '/js/news-collect.js' | relative_url }}"></script>

</body>

Expand All @@ -25,6 +27,3 @@
{% endif %}

</html>



26 changes: 26 additions & 0 deletions content/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,32 @@ <h2 class="section-header">Ready-to-use with your favourite open-source solver</
</div> <!-- section -->
</div> <!-- container -->

<!-- Latest News Section -->
<section id="latest-news" class="section">
<div class="container">
<h2 class="section-header text-center">Latest News</h2>

<div id="news-container" class="row equal">
<!-- News cards will be inserted dynamically -->
<p id="loading-news">Loading latest news...</p>
</div>


<div class="row" style="margin-top: 25px;">
<div class="col-lg-12 text-center">
<a href="https://precice.discourse.group/c/news/5"
class="btn btn-primary no-icon"
role="button"
target="_blank"
rel="noopener noreferrer">
More news &nbsp;<i class="fas fa-chevron-right"></i>
</a>
</div>
</div>

</div>
</section>

<!-- Testimonials, full bleed layout -->

<div class="background-dark">
Expand Down
28 changes: 12 additions & 16 deletions css/customstyles-precice.css
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@

/* (Material) changes to the customstyles.css start here */

body {
font-size: 16px;
font-family: Roboto,"Helvetica Neue",Helvetica,Arial,sans-serif;
padding-top: 70px; /* https://getbootstrap.com/docs/3.4/components/#navbar-fixed-top */
}
main {
/*margin-top:-20px;*/
}

.banner-container {
margin-top:-20px;
}
Expand Down Expand Up @@ -69,7 +66,6 @@ details > summary {

/* General layout classes */


h2.page-header {
/*border-bottom: 1px solid #0A76BB;*/
border-bottom: 1px solid rgba(10,118,187, 0);
Expand Down Expand Up @@ -230,7 +226,7 @@ ul.devlist>li {
display: flex;
flex-flow: row wrap;
border-top: 1px solid #0a76bb;
border-top-radius: 5px;
border-radius: 5px;
padding: 8px 16px;
margin: 0;
}
Expand Down Expand Up @@ -340,17 +336,17 @@ div#tg-sb-sidebar {
div#tg-sb-sidebar {
position: static;
}
/* style navtabs */
.post-content ol li, .post-content ul li {
margin: 0px;
}
div.tab-content {
padding: 0px;
background-color: white;
/* style navtabs */
.post-content ol li, .post-content ul li {
margin: 0px;
}
div.tab-content {
padding: 0px;
background-color: white;
}
div.tab-content div.tab-pane pre {
margin-top: 0px;
}
div.tab-content div.tab-pane pre {
margin-top: 0px;
}
}

/* Hide default marker Chromium/WebKit */
Expand Down
67 changes: 64 additions & 3 deletions css/landing-page.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
/* clear fixes */
/* idea is to not touch the docs part of the website, but start from a clear state */

main { /* fixed topnav takes up 50 + 20 px */
/* margin-top: -20px; */
}
h1[id], h2[id], h3[id], h4[id], h5[id], h6[id],
dt[id] {
padding-top: 0px;
Expand Down Expand Up @@ -237,3 +234,67 @@ div.logo-holder > img {
.no-padding {
padding: 0;
}

/* Latest News Section */

#latest-news {
background-color: #e6f2ff;
padding: 70px 0;
}

#latest-news .section-header {
margin-bottom: 40px;
text-align: center;
}

#latest-news a.no-external-marker::after {
content: none !important;
}

.news-card {
background: white;
border: 1px solid #ddd;
border-radius: 6px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}

.news-card h4 {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
height: 2.8em;
}

.news-card p:first-of-type {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 4;
line-clamp: 4;
-webkit-box-orient: vertical;
}


#news-container {
display: flex;
gap: 25px;
}

#news-container .col-md-4 {
flex: 1;
}


@media (max-width: 768px) {
#news-container {
flex-wrap: wrap;
}
#news-container .col-md-4 {
flex: 1 1 100%;
}
}
46 changes: 46 additions & 0 deletions js/news-collect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
console.log(">>> USING JS FILE: news-collect.js LOADED <<<");

document.addEventListener("DOMContentLoaded", async function () {
const newsContainer = document.getElementById("news-container");
const loadingText = document.getElementById("loading-news");

try {
const response = await fetch("/assets/data/news.json");
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
let topics = data.topics || [];

if (!topics.length) throw new Error("No topics found");

topics.sort((a, b) => new Date(b.last_posted_at) - new Date(a.last_posted_at));
loadingText.style.display = "none";

for (const topic of topics.slice(0, 3)) {
const col = document.createElement("div");
col.className = "col-md-4 col-sm-6 col-xs-12";

const card = document.createElement("div");
card.className = "news-card";

card.innerHTML = `
<h4><strong>${topic.title}</strong></h4>
<p>${topic.description}</p>
<p>
<a href="${topic.url}" target="_blank" rel="noopener noreferrer" class="no-external-marker">
Read more about this update
</a>
</p>
<p class="text-muted"><small>
Last activity: ${new Date(topic.last_posted_at).toLocaleDateString()}
</small></p>
`;

col.appendChild(card);
newsContainer.appendChild(col);
}

} catch (err) {
console.error(err);
loadingText.textContent = "Failed to load latest news.";
}
});
55 changes: 55 additions & 0 deletions tools/fetch-news.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import json
import os
import re
from urllib.request import urlopen

DISCOURSE_URL = "https://precice.discourse.group/c/news/5.json"
OUTPUT_FILE = "./assets/data/news.json"


def fetch_json(url: str):
with urlopen(url) as res:
return json.loads(res.read().decode("utf-8"))


def strip_html(html: str) -> str:
return re.sub(r"<[^>]*>", "", html)


def main():
try:
data = fetch_json(DISCOURSE_URL)
topics = data.get("topic_list", {}).get("topics", [])

news = []
for topic in topics:
detail = fetch_json(f"https://precice.discourse.group/t/{topic['id']}.json")
cooked = detail.get("post_stream", {}).get("posts", [{}])[0].get("cooked", "")
text = strip_html(cooked).strip()

excerpt = " ".join(text.split()[:30]) + "..."

news.append({
"id": topic["id"],
"title": topic["title"],
"slug": topic["slug"],
"url": f"https://precice.discourse.group/t/{topic['slug']}/{topic['id']}",
"last_posted_at": topic.get("last_posted_at"),
"like_count": topic.get("like_count"),
"posts_count": topic.get("posts_count"),
"views": topic.get("views"),
"description": excerpt,
})

os.makedirs(os.path.dirname(OUTPUT_FILE), exist_ok=True)
with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
json.dump({"generated_at": __import__("datetime").datetime.utcnow().isoformat(), "topics": news}, f, indent=2)

print(f"News data saved to {OUTPUT_FILE}")

except Exception as e:
print("Error fetching news:", e)


if __name__ == "__main__":
main()