Initial commit
This commit is contained in:
+146
@@ -0,0 +1,146 @@
|
||||
const btnHeroOpen = document.getElementById('btn-hero-open');
|
||||
const btnOpen = document.getElementById('btn-open');
|
||||
const btnPlay = document.getElementById('btn-play');
|
||||
const btnReset = document.getElementById('btn-reset');
|
||||
const inputSpeed = document.getElementById('input-speed');
|
||||
const inputSize = document.getElementById('input-size');
|
||||
const markdownOutput = document.getElementById('markdown-output');
|
||||
const placeholder = document.getElementById('placeholder');
|
||||
const scrollContainer = document.getElementById('scroll-container');
|
||||
const iconPlay = document.getElementById('icon-play');
|
||||
const iconPause = document.getElementById('icon-pause');
|
||||
|
||||
let isScrolling = false;
|
||||
let scrollAccumulator = 0;
|
||||
let animationId;
|
||||
let scrollSpeed = parseInt(inputSpeed.value, 10);
|
||||
|
||||
// Initialize
|
||||
function init() {
|
||||
setupEventListeners();
|
||||
updateFontSize(inputSize.value);
|
||||
}
|
||||
|
||||
function setupEventListeners() {
|
||||
btnHeroOpen.addEventListener('click', openFile);
|
||||
btnOpen.addEventListener('click', openFile);
|
||||
|
||||
btnPlay.addEventListener('click', toggleScrolling);
|
||||
|
||||
// Spacebar to toggle
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.code === 'Space') {
|
||||
e.preventDefault(); // Prevent page down scroll
|
||||
toggleScrolling();
|
||||
}
|
||||
});
|
||||
|
||||
btnReset.addEventListener('click', () => {
|
||||
stopScrolling();
|
||||
scrollContainer.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
});
|
||||
|
||||
inputSpeed.addEventListener('input', (e) => {
|
||||
scrollSpeed = parseInt(e.target.value, 10);
|
||||
});
|
||||
|
||||
inputSize.addEventListener('input', (e) => {
|
||||
updateFontSize(e.target.value);
|
||||
});
|
||||
}
|
||||
|
||||
async function openFile() {
|
||||
const filePath = await window.electronAPI.openFileDialog();
|
||||
if (filePath) {
|
||||
const content = await window.electronAPI.readFile(filePath);
|
||||
renderMarkdown(content);
|
||||
}
|
||||
}
|
||||
|
||||
function renderMarkdown(content) {
|
||||
if (!content) return;
|
||||
|
||||
// Using marked from global scope (loaded via script tag)
|
||||
const html = marked.parse(content);
|
||||
markdownOutput.innerHTML = html;
|
||||
|
||||
// Switch view
|
||||
placeholder.style.display = 'none';
|
||||
markdownOutput.style.display = 'block';
|
||||
|
||||
// Reset scroll
|
||||
scrollContainer.scrollTop = 0;
|
||||
}
|
||||
|
||||
function updateFontSize(size) {
|
||||
markdownOutput.style.fontSize = `${size}px`;
|
||||
}
|
||||
|
||||
function toggleScrolling() {
|
||||
if (isScrolling) {
|
||||
stopScrolling();
|
||||
} else {
|
||||
startScrolling();
|
||||
}
|
||||
}
|
||||
|
||||
function startScrolling() {
|
||||
if (!markdownOutput.innerHTML) return; // Don't scroll if empty
|
||||
|
||||
isScrolling = true;
|
||||
btnPlay.classList.add('active');
|
||||
iconPlay.style.display = 'none';
|
||||
iconPause.style.display = 'block';
|
||||
|
||||
animationId = requestAnimationFrame(step);
|
||||
}
|
||||
|
||||
function stopScrolling() {
|
||||
isScrolling = false;
|
||||
btnPlay.classList.remove('active');
|
||||
iconPlay.style.display = 'block';
|
||||
iconPause.style.display = 'none';
|
||||
cancelAnimationFrame(animationId);
|
||||
}
|
||||
|
||||
function step() {
|
||||
if (!isScrolling) return;
|
||||
|
||||
// Calculate scroll amount based on speed
|
||||
// Map 1-100 to sensible range.
|
||||
// Let's say max speed (100) is ~300 pixels per second? ~5px/frame at 60fps
|
||||
// Min speed (1) is ~10 pixels per second? ~0.16px/frame
|
||||
|
||||
// Formula: (speed / 100) * maxPixelsPerFrame
|
||||
// Adding a base speed so 1 isn't 0.
|
||||
|
||||
const maxSpeedValues = 5.0;
|
||||
const minSpeedValues = 0.2;
|
||||
|
||||
// Exponential curve for better control at lower speeds
|
||||
// Normalized speed 0-1
|
||||
const normalizedSpeed = (scrollSpeed - 1) / 99;
|
||||
|
||||
// Linear interpolation? Or quadratic? Quadratic feels "acceleration"
|
||||
// Let's stick to linear for predictability first, user says "simple"
|
||||
const pixelsPerFrame = minSpeedValues + (normalizedSpeed * (maxSpeedValues - minSpeedValues));
|
||||
|
||||
scrollAccumulator += pixelsPerFrame;
|
||||
const pixelsToScroll = Math.floor(scrollAccumulator);
|
||||
|
||||
if (pixelsToScroll >= 1) {
|
||||
// Stop if at bottom
|
||||
// Use a small buffer (1px) for float inconsistencies
|
||||
if (Math.ceil(scrollContainer.scrollTop + scrollContainer.clientHeight) >= scrollContainer.scrollHeight) {
|
||||
stopScrolling();
|
||||
return;
|
||||
}
|
||||
|
||||
scrollContainer.scrollTop += pixelsToScroll;
|
||||
scrollAccumulator -= pixelsToScroll;
|
||||
}
|
||||
|
||||
animationId = requestAnimationFrame(step);
|
||||
}
|
||||
|
||||
init();
|
||||
Reference in New Issue
Block a user