Here’s my stuff
Here is: Inline timer in note via DataviewJS + metadata. It’s working very janky, but I really like the idea of inline timers. I didn’t find the implementation of this idea, so i did it myself…
I don’t have enough time to continue this prj for now
I would be glad if someone nice would fix this stuff, thx
Here is code:
[[timer::00:00]]
```dataviewjs
// U HAVE TO ADD the path to the SAX GANDALF MP3(or any other mp3) FIRST.. U HAVE TO !!!!
const soundPath = "---/MP3/HD Epic Sax Gandalf.mp3";
const file=dv.current();
const time = file.timer;
const afile = app.workspace.getActiveFile();
const content = await app.vault.read(afile);
const txt = content
const txtNum = [];
for (let i = 0; i < txt.length; i++) {
txtNum.push(String(i));
}
let awaiting = false;
let isInl = false;
const markdown = [];
const InlMarkdown = [];
let newMark = [];
for (let index = 0; index < txt.length - 2; index++) {
const i = txt[index];
const j = txt[index + 1];
const i1 = txtNum[index];
const j1 = txtNum[index + 1];
if (i === "[" && j === "[") {
awaiting = true;
newMark.push(i1);
}
if (awaiting && i === ":" && j === ":") {
isInl = true;
}
if (awaiting && i === "]" && j === "]") {
newMark.push(j1);
if (isInl) {
InlMarkdown.push(newMark);
} else {
markdown.push(newMark);
}
newMark = [];
awaiting = false;
isInl = false;
}
}
for (const i of InlMarkdown) {
console.log(txt.slice(parseInt(i[0]), parseInt(i[1])));
}
console.log(InlMarkdown);
// найти все входы старого таймера и поменять их на новый
// Create and style timer container
const timerContainer = dv.el('div');
timerContainer.style.cssText = "top: 50%;left: 50%;font-family: 'Arial', sans-serif;text-align: center;user-select: none;color: #2D353B;";
const display = dv.el('div','111111');
display.id = 'timer-display';
display.style.cssText = "font-size: 5rem;font-weight: 300;letter-spacing: -3px;margin-bottom: 1rem;color: #2B59C3";
const btnContainer = dv.el('div');
btnContainer.style.display = 'flex';
btnContainer.style.gap = '0.5rem';
btnContainer.style.justifyContent = 'center';
const startBtn = dv.el('button');
startBtn.textContent = 'Start';
startBtn.style.cssText = `
background: #f0f0f0;
border: 1px solid #ddd;
padding: 0.5rem 1rem;
cursor: pointer;
font-size: 1rem;
border-radius: 4px;
transition: all 0.2s;
`;
startBtn.onmouseover = () => startBtn.style.background = '#3A4349';
startBtn.onmouseout = () => startBtn.style.background = '#3A4349';
const resetBtn = dv.el('button');
resetBtn.textContent = 'Reset';
resetBtn.style.cssText = startBtn.style.cssText;
resetBtn.onmouseover = () => resetBtn.style.background = '#3A4349';
resetBtn.onmouseout = () => resetBtn.style.background = '#3A4349';
btnContainer.appendChild(startBtn);
btnContainer.appendChild(resetBtn);
timerContainer.appendChild(display);
timerContainer.appendChild(btnContainer);
dv.el= timerContainer;
//ВОТ НАЧАЛЬНОЕ ВРЕМЯ!!!!!!
//!!!
const mins =parseInt(time.toString().slice(0,2))
const secs=parseInt(time.toString().slice(3,5))
//let initTime =(time.toString().slice(0,2).toInt()
let initTime = mins*60+secs
//!!!
//ВОТ НАЧАЛЬНОЕ ВРЕМЯ!!!!!!
let countdown;
let remainingTime = initTime; // 25 minutes (25 * 60)
function formatTime(seconds) {
const mins = Math.floor(seconds / 60).toString().padStart(2, '0');
const secs = (seconds % 60).toString().padStart(2, '0');
return `${mins}:${secs}`;
}
async function updateDisplay() {
let newTime =formatTime(remainingTime);
display.textContent = newTime;
//time = Math.floor(initTime / 60)
const updInline = "timer::"+newTime.toString();
let copiedtxt = "";
for (let i of InlMarkdown) {
const meta = txt.slice(parseInt(i[0]) + 2, parseInt(i[1]) - 1);
if (meta.slice(0, meta.indexOf("::")) === "timer") {
copiedtxt = txt.slice(0, parseInt(i[0]) + 2) + updInline + txt.slice(parseInt(i[1]) - 1);
}
}
// Write changes back to file
await app.vault.modify(afile, copiedtxt);
}
function startTimer() {
if (countdown) return;
startBtn.textContent = 'Pause';
countdown = setInterval(() => {
remainingTime--;
updateDisplay();
if (remainingTime <= 0) {
const audio = new Audio(app.vault.adapter.getResourcePath(soundPath));
audio.play().catch(e => console.error("Playback failed:", e));
clearInterval(countdown);
countdown = null;
startBtn.textContent = 'Start';
display.style.color = '#e74c3c';
setTimeout(() => display.style.color = '#333', 1000);
}
}, 1000);
}
function pauseTimer() {
clearInterval(countdown);
countdown = null;
startBtn.textContent = 'Start';
}
function resetTimer() {
clearInterval(countdown);
countdown = null;
remainingTime = initTime;
updateDisplay();
startBtn.textContent = 'Start';
display.style.color = '#443FAE';
}
startBtn.addEventListener('click', () => {
countdown ? pauseTimer() : startTimer();
});
resetBtn.addEventListener('click', resetTimer);
// Initialize display
updateDisplay();
Here is md page:
Timer MY TIMER (magic timer with a Gandalf blessing).md (5.3 KB)
U have to add up a path to the mp3 file first btw
pls don’t get destructed by strange notes in my note
Known problems:
- It can randomly stop when you change the note, but js code is still gonna run. So you can run like 5 countdowns in the 1 moment(it was a huuuuge surprise when they came off in 1 moment lol)
- The page is shaking all the time
- It doesn’t allow to edit page when countdown is active(so the only solution for this countdown to stop is actually alt+f4)
- When in preview mode from other page it will destroy the whole page for some reason. I.g. the code will run but not fully ruining the whole other page to the ground…