base2database.js2 matches
2import { sqlite } from "https://esm.town/v/std/sqlite";
34// This function runs only once to set up the tables if they don't exist.
5async function initialize() {
6await sqlite.execute(`
7CREATE TABLE IF NOT EXISTS news (
base2index.html37 matches
211const API_NEWS_BY_BATCH = '/api/news/batch/';
212213async function init() {
214await lucide.createIcons();
215
251}
252253function setupEventListeners() {
254prevBtn.addEventListener('click', goToPrevious);
255nextBtn.addEventListener('click', goToNext);
282}
283
284function handleAudioEnded() {
285audioEnded = true;
286console.log("Audio ended");
297
298
299function speakNewsItem() {
300audioEnded = false;
301ttsAbortController.abort();
424425
426function stopSpeaking() {
427ttsAbortController.abort();
428ttsAudio.pause();
437
438
439function userActive() {
440carouselContainer.classList.remove('user-inactive');
441carouselContainer.classList.add('user-active');
450}
451
452function startUserActivityMonitor() {
453userActive();
454}
455456function updateHeadline() {
457if (newsItems.length === 0) {
458headline.textContent = 'No news available.';
463}
464
465function updateFullContent() {
466if (newsItems.length === 0) return;
467
489}
490491async function goToNext() {
492if (isTransitioning) return;
493isTransitioning = true;
497}
498
499async function goToPrevious() {
500if (isTransitioning) return;
501isTransitioning = true;
505}
506507function updateCarousel() {
508updateHeadline();
509updateFullContent();
515516
517async function restartVideo() {
518stopSpeaking();
519audioEnded = false;
535}
536537function togglePlayPause() {
538isPlaying = !isPlaying;
539
559560
561function updatePlayPauseIcon() {
562const btn = document.getElementById('play-pause-btn');
563btn.innerHTML = `<i data-lucide="${isPlaying ? 'pause' : 'play'}"></i>`;
565}
566
567function startAutoAdvance() {
568stopAutoAdvance();
569if (isPlaying) {
576}
577578function stopAutoAdvance() {
579if (autoAdvanceInterval) {
580clearInterval(autoAdvanceInterval);
583}
584585function toggleMute() {
586if (video.volume > 0) {
587lastVolume = video.volume;
597userActive();
598}
599function updateVolume() {
600const volume = parseFloat(volumeSlider.value);
601video.volume = volume;
610}
611}
612function updateVolumeIcon(volume) {
613const btn = document.getElementById('mute-btn');
614let iconName = 'volume-x';
620}
621622function updateProgressBar() {
623if (video.duration) {
624const progress = (video.currentTime / video.duration) * 100;
628}
629630function seekVideo(e) {
631const rect = progressContainer.getBoundingClientRect();
632const percent = (e.clientX - rect.left) / rect.width;
637}
638639function updateTimeDisplay() {
640if (video.duration) {
641const currentTime = formatTime(video.currentTime);
645}
646647function updateVideoDurationDisplay() {
648if (video.duration) {
649timeDisplay.textContent = `0:00 / ${formatTime(video.duration)}`;
653}
654655function formatTime(seconds) {
656if (!seconds || isNaN(seconds)) return '0:00';
657
661}
662663function handleVideoEnded() {
664// Let the audio ended event handle navigation
665}
666667function showContentPanel() {
668contentVisible = true;
669newsContent.classList.add('active');
676}
677
678function hideContentPanel() {
679contentVisible = false;
680newsContent.classList.remove('active');
682}
683684async function openHistoryPanel() {
685loadingOverlay.style.display = 'flex';
686loadingOverlay.querySelector('.loading-text').textContent = 'Loading news history...';
707}
708
709function populateHistoryPanel() {
710historyList.innerHTML = '';
711
741}
742743async function loadNewsBatch(batchId) {
744loadingOverlay.style.display = 'flex';
745loadingOverlay.querySelector('.loading-text').textContent = 'Loading news batch...';
777}
778779function closeHistoryPanel() {
780historyPanel.classList.remove('active');
781userActive();
782}
783784function toggleFullscreen() {
785if (!document.fullscreenElement) {
786document.querySelector('.carousel-container').requestFullscreen().catch(err => {
793}
794795function updateFullscreenIcon() {
796const icon = document.fullscreenElement ? 'minimize' : 'maximize';
797fullscreenBtn.innerHTML = `<i data-lucide="${icon}"></i>`;
799}
800801function handleMediaError(e) {
802console.error('Media error:', e);
803const mediaElement = e.target;
813}
814815function showError(message) {
816errorMessage.textContent = message;
817errorMessage.classList.add('active');
822}
823824function handleKeyboardShortcuts(e) {
825if (e.code === 'Space') {
826e.preventDefault();
1export default async function (req: Request): Promise<Response> {
2return Response.json({ ok: true })
3}
32break;
33case 2:
34function c(e) {
35var a;
36for (var r = 2; r !== 11;) {
41case 6:
42a = Y7j7u.M2F(
43Y7j7u.N_m(B, function() {
44for (var e = 2; e !== 1;) {
45switch (e) {
95var $ = Y7j7u.s$f($, "{");
96var k = 0;
97function J(e) {
98for (var a = 2; a !== 23;) {
99switch (a) {
188}
189}
190function n(e) {
191for (var a = 2; a !== 1;) {
192switch (a) {
2021// Initialize database
22async function initDatabase() {
23// Create gardens table
24await sqlite.execute(`CREATE TABLE IF NOT EXISTS ${GARDENS_TABLE_NAME} (
Gardenonindex.html24 matches
488
489// Load all gardens
490async function loadGardens() {
491try {
492const response = await fetch('/api/gardens');
520
521// Load current garden and its plants
522async function loadCurrentGarden() {
523if (!currentGarden) return;
524
532
533// Fetch plants for current garden
534async function fetchPlants() {
535if (!currentGarden) {
536plants = [];
551
552// Render plants on the map and in the list
553function renderPlants() {
554// Clear existing plants (but preserve placeholder)
555gardenMap.querySelectorAll('.plant:not(.placeholder)').forEach(el => el.remove());
628
629// Create a new garden
630async function createGarden() {
631const name = newGardenNameInput.value.trim();
632const width = parseInt(newGardenWidthInput.value);
674
675// Update current garden settings
676async function updateGardenSettings() {
677if (!currentGarden) return;
678
722
723// Delete current garden
724async function deleteGarden() {
725if (!currentGarden) return;
726
759
760// Create a placeholder plant on the map
761function createPlaceholderPlant(x, y) {
762// Remove existing placeholder if any
763removePlaceholderPlant();
792
793// Remove placeholder plant from the map
794function removePlaceholderPlant() {
795if (placeholderPlant && placeholderPlant.element) {
796placeholderPlant.element.remove();
800
801// Select a plant to edit
802function selectPlant(plant) {
803// Cancel move mode if active
804if (isMovingPlant) {
833
834// Clear the form
835function clearForm() {
836// Remove placeholder plant if it exists
837removePlaceholderPlant();
859
860// Start move mode
861function startMoveMode() {
862if (!selectedPlant) {
863alert('Please select a plant to move.');
873
874// Cancel move mode
875function cancelMoveMode() {
876isMovingPlant = false;
877mapInstructions.textContent = 'Tap anywhere on the map to add a plant';
882
883// Move plant to new position
884function movePlantTo(x, y) {
885if (!selectedPlant) return;
886
906
907// Add a new plant at the clicked position
908function addPlantAt(x, y) {
909if (!currentGarden) {
910alert('Please select a garden first.');
937
938// Save plant data
939async function savePlant(plantData) {
940if (!currentGarden) {
941alert('Please select a garden first.');
984
985// Update placeholder plant when diameter changes
986function updatePlaceholderPlant() {
987if (placeholderPlant && placeholderPlant.element) {
988const newDiameter = parseFloat(plantDiameterInput.value) || 50;
994
995// Delete a plant
996async function deletePlant(id) {
997if (!confirm('Are you sure you want to delete this plant?')) {
998return;
1020}
1021
1022// Modal functions
1023function openGardenSettingsModal() {
1024if (!currentGarden) {
1025alert('Please select a garden first.');
1033}
1034
1035function closeGardenSettingsModal() {
1036gardenSettingsModal.style.display = 'none';
1037}
1038
1039function openNewGardenModal() {
1040newGardenNameInput.value = '';
1041newGardenWidthInput.value = 700;
1044}
1045
1046function closeNewGardenModal() {
1047newGardenModal.style.display = 'none';
1048}
1176
1177// Initialize
1178async function initialize() {
1179await loadGardens();
1180}
Gardenonadmin.html4 matches
241
242// Fetch database info
243async function fetchDatabaseInfo() {
244try {
245const response = await fetch('/api/admin/db');
257
258// Render database info
259function renderDatabaseInfo() {
260if (!dbData) return;
261
299
300// Render a single table
301function renderTable(tableData, elements) {
302if (!tableData) return;
303
368
369// Toggle between table and JSON view
370function toggleView() {
371isJsonView = !isJsonView;
372
thirdTimerutils.ts2 matches
4* @returns {string} Formatted time string
5*/
6export function formatTime(seconds: number): string {
7const hours = Math.floor(seconds / 3600);
8const minutes = Math.floor((seconds % 3600) / 60);
24* @returns {string} Formatted duration string (e.g., "30s", "5m", "2h 30m")
25*/
26export function formatMinutes(minutes: number): string {
27if (minutes < 1) return `${Math.round(minutes * 60)}s`;
28if (minutes < 60) return `${Math.round(minutes)}m`;
thirdTimerTimerDisplay.tsx1 match
16}
1718export function TimerDisplay({
19state,
20currentSessionTime,
openHeartProtocolmain.tsx6 matches
57};
5859export default async function fetch(request: Request) {
60console.log(`Received ${request.method} request to ${request.url}`);
61if (request.method === "GET") {
70}
7172function error(text: string, code = 400) {
73console.log(`Error response: ${text} (${code})`);
74return new Response(text, { status: code });
75}
7677async function handleGet(request: Request) {
78console.log("Handling GET request");
79const [domain, ...uidParts] = url(request).pathname.slice(1).split("/");
105}
106107function url(request: Request) {
108return new URL(request.url);
109}
110111async function handlePost(request: Request) {
112console.log("Handling POST request");
113const urlObject = url(request);
146}
147148function ensureEmoji(emoji: string) {
149const segments = Array.from(new Intl.Segmenter("en", { granularity: "grapheme" }).segment(emoji.trim()));
150const parsedEmoji: string | null = segments.length > 0 ? segments[0].segment : null;