added presentation viewers #9

Merged
weinol_m merged 1 commits from add_renku_material into main 2026-03-04 11:24:38 +01:00
15 changed files with 404 additions and 132 deletions

View File

@@ -1,4 +1,159 @@
.md-nav__source{display: none;}
.md-nav--primary > .md-nav__list > .md-nav__item > .md-nav__link {
font-weight: bold;
}
/* PDF Viewer Styles */
.pdf-viewer-container {
border: 1px solid #ccc;
border-radius: 6px;
overflow: hidden;
font-family: sans-serif;
margin-bottom: 20px;
background-color: #f5f5f5;
}
.pdf-viewer-header {
background-color: #333;
color: white;
padding: 10px 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
.pdf-viewer-header .document-label {
font-weight: bold;
font-size: 0.9em;
}
.pdf-viewer-header .download-btn {
text-decoration: none;
background-color: #e74c3c;
color: white !important;
padding: 6px 12px;
border-radius: 4px;
font-size: 0.85em;
transition: background 0.2s;
}
.pdf-viewer-header .download-btn:hover {
background-color: #c0392b;
}
.pdf-viewer-content {
position: relative;
width: 100%;
min-height: 200px;
background-color: #525659;
}
.pdf-viewer-content canvas {
display: block;
width: 100%;
height: auto;
}
.pdf-viewer-loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
}
.pdf-viewer-controls {
background-color: #ddd;
padding: 10px;
display: flex;
justify-content: center;
align-items: center;
gap: 15px;
}
.pdf-viewer-controls button {
cursor: pointer;
padding: 5px 15px;
border: 1px solid #999;
background: #eee;
border-radius: 3px;
}
.pdf-viewer-controls button:hover {
background: #fff;
}
.pdf-viewer-controls .page-info {
font-size: 0.9em;
}
/* HTML Viewer Styles */
.html-viewer-container {
border: 1px solid #ccc;
border-radius: 6px;
overflow: hidden;
font-family: sans-serif;
margin-bottom: 20px;
background-color: #f5f5f5;
}
.html-viewer-header {
background-color: #333;
color: white;
padding: 10px 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
.html-viewer-header .document-label {
font-weight: bold;
font-size: 0.9em;
}
.html-viewer-header .open-btn {
text-decoration: none;
background-color: #3498db;
color: white !important;
padding: 6px 12px;
border-radius: 4px;
font-size: 0.85em;
transition: background 0.2s;
}
.html-viewer-header .open-btn:hover {
background-color: #2980b9;
}
.html-viewer-content {
position: relative;
width: 100%;
aspect-ratio: 16 / 9;
}
.html-viewer-content iframe {
width: 100%;
height: 100%;
border: none;
}
.html-viewer-controls {
background-color: #ddd;
padding: 10px;
display: flex;
justify-content: center;
align-items: center;
gap: 15px;
}
.html-viewer-controls button {
cursor: pointer;
padding: 5px 15px;
border: 1px solid #999;
background: #eee;
border-radius: 3px;
}
.html-viewer-controls button:hover {
background: #fff;
}

View File

@@ -0,0 +1,66 @@
/**
* Navigation controller for Remark.js presentations in iframes.
*
* Looks for elements with class 'html-viewer-container'.
*/
document$.subscribe(({ body }) => {
const containers = body.querySelectorAll('.html-viewer-container');
containers.forEach(container => {
const iframe = container.querySelector('iframe');
const prevBtn = container.querySelector('.prev-btn');
const nextBtn = container.querySelector('.next-btn');
const pageNumDisplay = container.querySelector('.page-num');
const pageCountDisplay = container.querySelector('.page-count');
if (!iframe || !prevBtn || !nextBtn) return;
function updatePageInfo() {
try {
if (iframe.contentWindow && iframe.contentWindow.slideshow) {
const slideshow = iframe.contentWindow.slideshow;
const currentIndex = slideshow.getCurrentSlideIndex() + 1;
const totalSlides = slideshow.getSlides().length;
if (pageNumDisplay) pageNumDisplay.textContent = currentIndex;
if (pageCountDisplay) pageCountDisplay.textContent = totalSlides;
}
} catch (e) {
// Silently fail if cross-origin or slideshow not yet loaded
}
}
prevBtn.addEventListener('click', () => {
try {
if (iframe.contentWindow && iframe.contentWindow.slideshow) {
iframe.contentWindow.slideshow.gotoPreviousSlide();
updatePageInfo();
} else {
iframe.contentWindow.dispatchEvent(new KeyboardEvent('keydown', { 'keyCode': 37 }));
}
} catch (e) {
console.error("Could not navigate slideshow:", e);
}
});
nextBtn.addEventListener('click', () => {
try {
if (iframe.contentWindow && iframe.contentWindow.slideshow) {
iframe.contentWindow.slideshow.gotoNextSlide();
updatePageInfo();
} else {
iframe.contentWindow.dispatchEvent(new KeyboardEvent('keydown', { 'keyCode': 39 }));
}
} catch (e) {
console.error("Could not navigate slideshow:", e);
}
});
// Update info when iframe loads
iframe.addEventListener('load', updatePageInfo);
// Periodically update in case the user navigates using the keyboard inside the iframe
setInterval(updatePageInfo, 500);
});
});

View File

@@ -0,0 +1,108 @@
/**
* Reusable PDF Viewer for MkDocs Material
*
* Uses PDF.js to render PDF files in a canvas.
* Looks for elements with class 'pdf-viewer-container' and a 'data-url' attribute.
*/
document$.subscribe(({ body }) => {
const containers = body.querySelectorAll('.pdf-viewer-container[data-url]');
if (containers.length === 0) return;
// Load PDF.js worker if not already loaded
if (window['pdfjs-dist/build/pdf'] && !window['pdfjs-dist/build/pdf'].GlobalWorkerOptions.workerSrc) {
window['pdfjs-dist/build/pdf'].GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js';
}
containers.forEach(container => {
initPDFViewer(container);
});
});
function initPDFViewer(container) {
const url = container.getAttribute('data-url');
const canvas = container.querySelector('canvas');
const pageNumDisplay = container.querySelector('.page-num');
const pageCountDisplay = container.querySelector('.page-count');
const prevBtn = container.querySelector('.prev-btn');
const nextBtn = container.querySelector('.next-btn');
const loadingMsg = container.querySelector('.pdf-viewer-loading');
if (!canvas || !url) return;
let pdfDoc = null;
let pageNum = 1;
let pageRendering = false;
let pageNumPending = null;
const scale = 2.0;
const ctx = canvas.getContext('2d');
function renderPage(num) {
pageRendering = true;
pdfDoc.getPage(num).then(page => {
if (loadingMsg) loadingMsg.style.display = 'none';
const viewport = page.getViewport({ scale: scale });
canvas.height = viewport.height;
canvas.width = viewport.width;
const renderContext = {
canvasContext: ctx,
viewport: viewport
};
const renderTask = page.render(renderContext);
renderTask.promise.then(() => {
pageRendering = false;
if (pageNumPending !== null) {
renderPage(pageNumPending);
pageNumPending = null;
}
});
});
if (pageNumDisplay) pageNumDisplay.textContent = num;
}
function queueRenderPage(num) {
if (pageRendering) {
pageNumPending = num;
} else {
renderPage(num);
}
}
if (prevBtn) {
prevBtn.addEventListener('click', () => {
if (pageNum <= 1) return;
pageNum--;
queueRenderPage(pageNum);
});
}
if (nextBtn) {
nextBtn.addEventListener('click', () => {
if (pageNum >= pdfDoc.numPages) return;
pageNum++;
queueRenderPage(pageNum);
});
}
// Load the document
const pdfjsLib = window['pdfjs-dist/build/pdf'];
if (!pdfjsLib) {
console.error('PDF.js library not found');
return;
}
pdfjsLib.getDocument(url).promise.then(pdfDoc_ => {
pdfDoc = pdfDoc_;
if (pageCountDisplay) pageCountDisplay.textContent = pdfDoc.numPages;
renderPage(pageNum);
}).catch(err => {
console.error('Error loading PDF:', err);
if (loadingMsg) loadingMsg.textContent = "Error loading PDF.";
});
}

View File

@@ -12,7 +12,7 @@
| Date | Time | Event | Location | Link | Calendar |
| ---- | ---- | ----- | -------- | ---- | -------- |
| 03. Mar 2026 | 11:00-11:45 | [Elisabet Capón:<br>An Introduction to Renku](events/2026-03-03_capon.md) | [OHSA/E13](https://pocket.psi.ch/psimap) | N/A |
<!--
<div class="grid cards" markdown>
@@ -28,7 +28,8 @@
| Date | Time | Event | Location | Link | Calendar |
| ---- | ---- | ----- | -------- | ---- | -------- |
| 03. Feb 2026 | 11:00-11:45 | [Achim Gsell:<br>Coding Styles](events/2026-02-03/Coding_Styles.md) | [OHSA/E13](https://pocket.psi.ch/psimap) | N/A |
| 03. Mar 2026 | 11:00-11:45 | [Elisabet Capón:<br>An Introduction to Renku](events/2026-03-03/2026-03-03_capon.md) | [OHSA/E13](https://pocket.psi.ch/psimap) | N/A |
| 03. Feb 2026 | 11:00-11:45 | [Achim Gsell:<br>Coding Styles](events/2026-02-03/2026-02-03_gsell.md) | [OHSA/E13](https://pocket.psi.ch/psimap) | N/A |
| 02. Dec 2025 | 11:00-11:45 | [Michael Weinold: Serverless and decentralised](events/2025-12-02_weinold.md) | [OHSA/E13](https://pocket.psi.ch/psimap) | N/A | N/A |
| 04. Nov 2025 | 11:00-11:45 | [Romain Sacchi: From scientific software to public tools](events/2025-11-04_sacchi.md) | [OHSA/E13](https://pocket.psi.ch/psimap) | N/A | N/A |
| 23. Oct 2025 | 10:00-11:00 | Technical Documentation with `mkdocs` and WASM | Zoom | [Recording of the Talk](https://rse.swiss/events/2025_10_23_technical_documentation_with_mkdocs_and_webassembly/) | N/A |

View File

@@ -1,4 +1,4 @@
# Romain Sacchi: From scientific software to public tools
# Romain Sacchi: From Scientific Software to Public Tools
**Presenter:** Romain Sacchi
**When:** 4. November 2025; 11:00-11:45am

View File

@@ -1,4 +1,4 @@
# Serverless and decentralized
# Serverless and Decentralized
**Presenter:** Michael Weinold
**When:** 2. December 2025; 11:00-11:45

View File

@@ -0,0 +1,29 @@
# Achim Gsell: Coding Styles
**Presenter:** Achim Gsell
**When:** 3. February 2026; 11:00-11:45am
**Where:** PSI OHSA/E13
Coding style matters in software development because most code is read far
more often than it is written—and usually by someone other than the original
author. A consistent style makes intent obvious and helps the developers in
writing better code.
<div class="html-viewer-container">
<div class="html-viewer-header">
<span class="document-label">Presentation Viewer</span>
<a href="../index.html" target="_blank" class="open-btn">
↗ Open in New Tab
</a>
</div>
<div class="html-viewer-content">
<iframe src="../index.html"></iframe>
</div>
<div class="html-viewer-controls">
<button class="prev-btn">Previous</button>
<span class="page-info">Slide <span class="page-num">--</span> of <span class="page-count">--</span></span>
<button class="next-btn">Next</button>
</div>
</div>

View File

@@ -1,12 +0,0 @@
# Achim Gsell: Coding Styles
**Presenter:** Achim Gsell
**When:** 3. February 2026; 11:00-11:45am
**Where:** PSI OHSA/E13
Coding style matters in software development because most code is read far
more often than it is written—and usually by someone other than the original
author. A consistent style makes intent obvious and helps the developers in
writing better code.
[Link to slides](index.html)

View File

@@ -1,9 +0,0 @@
# Elisabet Capón: Introduction to Renku
**Presenter:** Elisabet Capón
**When:** 3. March 2026; 11:00-11:45am
**Where:** PSI OHSA/E13
In this talk, Dr. Elisabet Capón will introduce Renku, a novel open-source platform designed to connect the ecosystem of data, code, and compute to empower researchers and collaborative communities. The platform mission is to enable the Swiss National Open Research Data (ORD) Strategy by supporting the accessibility and reuse of research data across Switzerland.
Renku connectes external Git repositories, data stores, and containerized compute environments to allow users to mix and match resources to suit their project setups. The talk outlines how Renku reduces technical friction for three key groups: researchers seeking unified workflows, educators managing computing courses, and organizers running seamless events.

View File

@@ -0,0 +1,27 @@
# An Introduction to Renko
**Presenter:** Elisabet Capón García
**When:** 3. March 2026; 11:00-11:45
**Where:** PSI OHSA/E13
[Elisabet Capón](https://www.datascience.ch/people/elisabet-capon-garcia) is a community manager at the Swiss Data Science Center (SDSC), where she focuses on fostering open research practices and supporting the [Renku open-source project](https://renkulab.io). Renku is a platform that enables researchers to create, share, and reproduce data science projects with ease, promoting collaboration and transparency in scientific research. She will provide an introduction to Renku, highlighting its features and benefits for research software engineering.
<div class="pdf-viewer-container" data-url="../2026-03-03_slides.pdf">
<div class="pdf-viewer-header">
<span class="document-label">Document Viewer</span>
<a href="../2026-03-03_slides.pdf" download target="_blank" class="download-btn">
⬇ Download PDF
</a>
</div>
<div class="pdf-viewer-content">
<canvas></canvas>
<div class="pdf-viewer-loading">Loading...</div>
</div>
<div class="pdf-viewer-controls">
<button class="prev-btn">Previous</button>
<span class="page-info">Page <span class="page-num">--</span> of <span class="page-count">--</span></span>
<button class="next-btn">Next</button>
</div>
</div>

Binary file not shown.

View File

@@ -1,7 +0,0 @@
# An Introduction to Renko
**Presenter:** Elisabet Capón García
**When:** 3. March 2026; 11:00-11:45
**Where:** PSI OHSA/E13
[Elisabet Capón](https://www.datascience.ch/people/elisabet-capon-garcia) is a community manager at the Swiss Data Science Center (SDSC), where she focuses on fostering open research practices and supporting the [Renku open-source project](https://renkulab.io). Renku is a platform that enables researchers to create, share, and reproduce data science projects with ease, promoting collaboration and transparency in scientific research. She will provide an introduction to Renku, highlighting its features and benefits for research software engineering.

View File

@@ -6,7 +6,6 @@ Software is ubiquitous in modern research and its quality has a direct impact on
| Date | Time | Event | Location | Link | Calendar |
| ---- | ---- | ----- | -------- | ---- | -------- |
| 03. Mar 2026 | 11:00-11:45 | [Elisabet Capón:<br>An Introduction to Renku](events/2026-03-03_capon.md) | OHSA/E13 | [Map](https://pocket.psi.ch/psimap) | N/A |
## Staying Informed

View File

@@ -4,110 +4,22 @@
In 2025, we conducted a staff survey on the state of research software engineering at Paul Scherrer Institut (PSI). The survey was open in September and October 2025, and we received responses from over 50 research software engineers (RSEs) across all centers at PSI. On average, every respondent spent over half an hour on the survey. The results [are available through the ETH Research Collection](https://doi.org/10.3929/ethz-c-000790389) and can be downloaded below:
<div class="pdf-component" style="border: 1px solid #ccc; border-radius: 6px; overflow: hidden; font-family: sans-serif; margin-bottom: 20px; background-color: #f5f5f5;">
<div style="background-color: #333; color: white; padding: 10px 15px; display: flex; justify-content: space-between; align-items: center;">
<span style="font-weight: bold; font-size: 0.9em;">Document Viewer</span>
<a href="../_static/media/survey2025.pdf" download target="_blank" style="text-decoration: none; background-color: #e74c3c; color: white; padding: 6px 12px; border-radius: 4px; font-size: 0.85em; transition: background 0.2s;">
<div class="pdf-viewer-container" data-url="../_static/media/survey2025.pdf">
<div class="pdf-viewer-header">
<span class="document-label">Document Viewer</span>
<a href="../_static/media/survey2025.pdf" download target="_blank" class="download-btn">
⬇ Download PDF
</a>
</div>
<div id="pdf-wrapper" style="position: relative; width: 100%; min-height: 200px; background-color: #525659;">
<canvas id="the-canvas" style="display: block; width: 100%; height: auto;"></canvas>
<div id="pdf-loading" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: white;">Loading...</div>
<div class="pdf-viewer-content">
<canvas></canvas>
<div class="pdf-viewer-loading">Loading...</div>
</div>
<div style="background-color: #ddd; padding: 10px; display: flex; justify-content: center; align-items: center; gap: 15px;">
<button id="prev" style="cursor: pointer; padding: 5px 15px;">Previous</button>
<span style="font-size: 0.9em;">Page <span id="page_num">--</span> of <span id="page_count">--</span></span>
<button id="next" style="cursor: pointer; padding: 5px 15px;">Next</button>
<div class="pdf-viewer-controls">
<button class="prev-btn">Previous</button>
<span class="page-info">Page <span class="page-num">--</span> of <span class="page-count">--</span></span>
<button class="next-btn">Next</button>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.min.js"></script>
<script>
(function() {
var url = '../_static/media/survey2025.pdf'; // <--- CHECK PATH
var pdfjsLib = window['pdfjs-dist/build/pdf'];
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js';
var pdfDoc = null,
pageNum = 1,
pageRendering = false,
pageNumPending = null,
scale = 2.0, // High res render, scaled down by CSS
canvas = document.getElementById('the-canvas'),
ctx = canvas.getContext('2d'),
loading = document.getElementById('pdf-loading');
function renderPage(num) {
pageRendering = true;
// Fetch page
pdfDoc.getPage(num).then(function(page) {
loading.style.display = 'none';
var viewport = page.getViewport({scale: scale});
canvas.height = viewport.height;
canvas.width = viewport.width;
// Render
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
var renderTask = page.render(renderContext);
// Wait for render to finish
renderTask.promise.then(function() {
pageRendering = false;
if (pageNumPending !== null) {
renderPage(pageNumPending);
pageNumPending = null;
}
});
});
// Update page counters
document.getElementById('page_num').textContent = num;
}
function queueRenderPage(num) {
if (pageRendering) {
pageNumPending = num;
} else {
renderPage(num);
}
}
function onPrevPage() {
if (pageNum <= 1) { return; }
pageNum--;
queueRenderPage(pageNum);
}
document.getElementById('prev').addEventListener('click', onPrevPage);
function onNextPage() {
if (pageNum >= pdfDoc.numPages) { return; }
pageNum++;
queueRenderPage(pageNum);
}
document.getElementById('next').addEventListener('click', onNextPage);
// Initial Load
pdfjsLib.getDocument(url).promise.then(function(pdfDoc_) {
pdfDoc = pdfDoc_;
document.getElementById('page_count').textContent = pdfDoc.numPages;
renderPage(pageNum);
}).catch(function(err) {
console.error(err);
loading.textContent = "Error loading PDF.";
});
})();
</script>

View File

@@ -71,6 +71,9 @@ extra_javascript:
# unpkg is incredibly slow (17s to load the css file)
- https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.js
- https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/contrib/auto-render.min.js
- https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.min.js
- _javascripts/pdf-viewer.js
- _javascripts/html-viewer.js
extra_css:
# https://cdnjs.com/libraries/KaTeX
# unpkg is incredibly slow (17s to load the css file)