Juris allows you to express all you creativity.
Here is an idea I had in ming a long time ago.
I finally realised it with Juris:
You can play with it here: NSTicker
Here is all the code :
// Enhanced News Ticker with Professional Features
// Configuration constants
const CONFIG = {
API: {
POLLINATIONS_BASE_URL: 'https://image.pollinations.ai/prompt',
IMAGE_PARAMS: {
nologo: true,
enhance: true,
width: 800,
height: 400,
model: 'flux'
},
RETRY_ATTEMPTS: 3,
RETRY_DELAY: 1000,
REQUEST_TIMEOUT: 10000
},
UI: {
MIN_DISPLAY_TIME: 5000,
DEFAULT_INTERVAL: 3000,
FAST_INTERVAL: 1000,
SLOW_INTERVAL: 5000,
IMAGE_LOAD_TIMEOUT: 8000,
ANIMATION_DURATION: 300
},
STORAGE_KEY: 'newsTickerPreferences'
};
// Enhanced error handling
class NewsTickerError extends Error {
constructor(message, code, context = {}) {
super(message);
this.name = 'NewsTickerError';
this.code = code;
this.context = context;
this.timestamp = new Date().toISOString();
}
}
// Logger utility
const Logger = {
levels: { ERROR: 0, WARN: 1, INFO: 2, DEBUG: 3 },
currentLevel: 2, // INFO level by default
log(level, message, data = null) {
if (this.levels[level] <= this.currentLevel) {
const timestamp = new Date().toISOString();
const logEntry = { timestamp, level, message, data };
console[level.toLowerCase()](
`[${timestamp}] ${level}: ${message}`,
data || ''
);
this.storeLog(logEntry);
}
},
error(message, data) { this.log('ERROR', message, data); },
warn(message, data) { this.log('WARN', message, data); },
info(message, data) { this.log('INFO', message, data); },
debug(message, data) { this.log('DEBUG', message, data); },
storeLog(entry) {
// Store last 100 log entries for debugging
const logs = JSON.parse(localStorage.getItem('newsTickerLogs') || '[]');
logs.push(entry);
if (logs.length > 100) logs.shift();
localStorage.setItem('newsTickerLogs', JSON.stringify(logs));
},
exportLogs() {
return JSON.parse(localStorage.getItem('newsTickerLogs') || '[]');
}
};
// Utility functions
const Utils = {
delay: (ms) => new Promise(resolve => setTimeout(resolve, ms)),
async withTimeout(promise, timeoutMs, errorMessage = 'Operation timed out') {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new NewsTickerError(errorMessage, 'TIMEOUT')), timeoutMs)
);
return Promise.race([promise, timeout]);
},
async retry(fn, attempts = 3, delay = 1000) {
for (let i = 0; i < attempts; i++) {
try {
return await fn();
} catch (error) {
Logger.warn(`Attempt ${i + 1} failed`, { error: error.message });
if (i === attempts - 1) throw error;
await this.delay(delay * Math.pow(2, i)); // Exponential backoff
}
}
},
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
},
sanitizeHtml(str) {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
},
formatDate(dateString) {
try {
return new Date(dateString).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
} catch {
return dateString; // Fallback to original string
}
}
};
// Enhanced news data with validation
const NewsData = {
categories: {
PHYSICS: 'Physics & Astronomy',
BIOLOGY: 'Biology & Medicine',
CHEMISTRY: 'Chemistry',
TECHNOLOGY: 'Computing & Technology',
ENGINEERING: 'Engineering & Energy'
},
items: [
// Physics & Astronomy
{
id: 'moon-landing-1969',
title: "The man walks on the moon",
author: "Neil Armstrong",
date: "1969-07-20",
category: 'PHYSICS',
description: "First human lunar landing mission",
tags: ['space', 'exploration', 'NASA'],
importance: 10
},
{
id: 'einstein-nobel-1921',
title: "Albert won Nobel Prize",
author: "Albert Einstein",
date: "1921-11-09",
category: 'PHYSICS',
description: "Awarded for photoelectric effect discovery",
tags: ['physics', 'quantum', 'nobel'],
importance: 9
},
{
id: 'planck-radiation-1900',
title: "Black body radiation explained",
author: "Max Planck",
date: "1900-12-14",
category: 'PHYSICS',
description: "Birth of quantum theory",
tags: ['quantum', 'theory', 'physics'],
importance: 9
},
{
id: 'einstein-relativity-1905',
title: "Relativity changes our view of space-time",
author: "Albert Einstein",
date: "1905-09-26",
category: 'PHYSICS',
description: "Revolutionary theory of space and time",
tags: ['relativity', 'physics', 'spacetime'],
importance: 10
},
{
id: 'quantum-entanglement-1981',
title: "Quantum entanglement proves Einstein wrong",
author: "Alain Aspect",
date: "1981-12-01",
category: 'PHYSICS',
description: "Experimental proof of quantum entanglement",
tags: ['quantum', 'entanglement', 'experiment'],
importance: 9
},
{
id: 'higgs-boson-2012',
title: "Higgs boson particle finally detected",
author: "CERN",
date: "2012-07-04",
category: 'PHYSICS',
description: "Discovery of the Higgs boson at the Large Hadron Collider",
tags: ['particle', 'physics', 'CERN', 'higgs'],
importance: 10
},
{
id: 'gravitational-waves-2015',
title: "Gravitational waves confirmed Einstein's theory",
author: "LIGO Team",
date: "2015-09-14",
category: 'PHYSICS',
description: "First direct detection of gravitational waves",
tags: ['gravity', 'waves', 'LIGO', 'Einstein'],
importance: 10
},
{
id: 'sputnik-1957',
title: "First artificial satellite launched",
author: "Sputnik 1",
date: "1957-10-04",
category: 'PHYSICS',
description: "Soviet Union launches first artificial satellite",
tags: ['satellite', 'space', 'soviet', 'sputnik'],
importance: 9
},
{
id: 'gagarin-space-1961',
title: "First human in space",
author: "Yuri Gagarin",
date: "1961-04-12",
category: 'PHYSICS',
description: "First human orbital spaceflight",
tags: ['space', 'human', 'orbit', 'soviet'],
importance: 10
},
{
id: 'black-hole-photo-2019',
title: "First photograph of a black hole",
author: "Event Horizon Telescope",
date: "2019-04-10",
category: 'PHYSICS',
description: "First direct image of a black hole's event horizon",
tags: ['black hole', 'telescope', 'astronomy'],
importance: 9
},
{
id: 'mars-curiosity-2012',
title: "Mars rover Curiosity lands successfully",
author: "NASA JPL",
date: "2012-08-05",
category: 'PHYSICS',
description: "Successful landing of Curiosity rover on Mars",
tags: ['mars', 'rover', 'NASA', 'exploration'],
importance: 8
},
{
id: 'james-webb-2021',
title: "James Webb Space Telescope launched",
author: "NASA & ESA",
date: "2021-12-25",
category: 'PHYSICS',
description: "Launch of the most powerful space telescope",
tags: ['telescope', 'space', 'infrared', 'astronomy'],
importance: 9
},
{
id: 'exoplanet-1995',
title: "First exoplanet discovered",
author: "Michel Mayor & Didier Queloz",
date: "1995-10-06",
category: 'PHYSICS',
description: "Discovery of 51 Eridani b, first exoplanet around sun-like star",
tags: ['exoplanet', 'discovery', 'astronomy'],
importance: 9
},
{
id: 'plate-tectonics-1912',
title: "Plate tectonics explains continental drift",
author: "Alfred Wegener",
date: "1912-01-06",
category: 'PHYSICS',
description: "Theory explaining continental drift through plate movement",
tags: ['geology', 'tectonics', 'earth', 'continental drift'],
importance: 8
},
{
id: 'big-bang-theory-1927',
title: "Big Bang theory proposed",
author: "Georges Lemaître",
date: "1927-05-01",
category: 'PHYSICS',
description: "Theoretical foundation for the expansion of the universe",
tags: ['cosmology', 'universe', 'big bang', 'theory'],
importance: 10
},
{
id: 'pulsars-discovery-1967',
title: "Discovery of pulsars",
author: "Jocelyn Bell Burnell",
date: "1967-11-28",
category: 'PHYSICS',
description: "Discovery of rapidly rotating neutron stars",
tags: ['pulsar', 'neutron star', 'astronomy', 'radio'],
importance: 8
},
{
id: 'cosmic-microwave-background-1964',
title: "Discovery of cosmic microwave background radiation",
author: "Penzias & Wilson",
date: "1964-05-01",
category: 'PHYSICS',
description: "Discovery of relic radiation from the Big Bang",
tags: ['CMB', 'radiation', 'big bang', 'cosmology'],
importance: 9
},
{
id: 'space-shuttle-1981',
title: "First reusable spacecraft launched",
author: "Space Shuttle Columbia",
date: "1981-04-12",
category: 'PHYSICS',
description: "First launch of NASA's Space Shuttle program",
tags: ['shuttle', 'reusable', 'NASA', 'Columbia'],
importance: 8
},
{
id: 'voyager-interstellar-2012',
title: "Voyager probe enters interstellar space",
author: "NASA",
date: "2012-08-25",
category: 'PHYSICS',
description: "Voyager 1 becomes first human-made object to leave solar system",
tags: ['voyager', 'interstellar', 'NASA', 'exploration'],
importance: 8
},
// Biology & Medicine
{
id: 'dna-double-helix-1953',
title: "DNA double helix structure discovered",
author: "Watson & Crick",
date: "1953-04-25",
category: 'BIOLOGY',
description: "Discovery of the double helix structure of DNA",
tags: ['DNA', 'genetics', 'structure', 'molecular biology'],
importance: 10
},
{
id: 'dna-photo-1952',
title: "First picture of DNA captured",
author: "Rosalind Franklin",
date: "1952-05-01",
category: 'BIOLOGY',
description: "X-ray crystallography image of DNA structure (Photo 51)",
tags: ['DNA', 'crystallography', 'structure', 'photography'],
importance: 9
},
{
id: 'penicillin-1928',
title: "Penicillin saves millions of lives",
author: "Alexander Fleming",
date: "1928-09-28",
category: 'BIOLOGY',
description: "Discovery of the first widely used antibiotic",
tags: ['antibiotic', 'medicine', 'bacteria', 'treatment'],
importance: 10
},
{
id: 'vaccines-1885',
title: "Vaccines eliminate deadly diseases",
author: "Louis Pasteur",
date: "1885-07-06",
category: 'BIOLOGY',
description: "Development of rabies vaccine and vaccination principles",
tags: ['vaccine', 'immunization', 'disease', 'prevention'],
importance: 10
},
{
id: 'evolution-1859',
title: "Evolution explains diversity of life",
author: "Charles Darwin",
date: "1859-11-24",
category: 'BIOLOGY',
description: "Publication of 'On the Origin of Species'",
tags: ['evolution', 'natural selection', 'biology', 'species'],
importance: 10
},
{
id: 'human-genome-2003',
title: "Human genome completely sequenced",
author: "Human Genome Project",
date: "2003-04-14",
category: 'BIOLOGY',
description: "Complete sequencing of human DNA",
tags: ['genome', 'sequencing', 'genetics', 'DNA'],
importance: 10
},
{
id: 'crispr-2012',
title: "CRISPR gene editing revolutionizes medicine",
author: "Jennifer Doudna",
date: "2012-06-28",
category: 'BIOLOGY',
description: "Development of precise gene editing technology",
tags: ['CRISPR', 'gene editing', 'biotechnology', 'medicine'],
importance: 10
},
{
id: 'heart-transplant-1967',
title: "First heart transplant performed",
author: "Christiaan Barnard",
date: "1967-12-03",
category: 'BIOLOGY',
description: "First successful human heart transplantation",
tags: ['transplant', 'surgery', 'heart', 'medicine'],
importance: 9
},
{
id: 'kidney-transplant-1954',
title: "First successful kidney transplant",
author: "Joseph Murray",
date: "1954-12-23",
category: 'BIOLOGY',
description: "First successful organ transplant between identical twins",
tags: ['transplant', 'kidney', 'surgery', 'organ'],
importance: 8
},
{
id: 'insulin-discovery-1921',
title: "Insulin discovered for diabetes treatment",
author: "Frederick Banting",
date: "1921-07-30",
category: 'BIOLOGY',
description: "Discovery of insulin as treatment for diabetes",
tags: ['insulin', 'diabetes', 'hormone', 'treatment'],
importance: 9
},
{
id: 'dolly-cloning-1996',
title: "First cloning of a mammal (Dolly the sheep)",
author: "Ian Wilmut",
date: "1996-07-05",
category: 'BIOLOGY',
description: "First successful cloning of a mammal from adult cell",
tags: ['cloning', 'genetics', 'biotechnology', 'sheep'],
importance: 9
},
{
id: 'stem-cells-1961',
title: "Stem cells discovered",
author: "James Till & Ernest McCulloch",
date: "1961-02-01",
category: 'BIOLOGY',
description: "Discovery of hematopoietic stem cells",
tags: ['stem cells', 'regenerative medicine', 'biology', 'cells'],
importance: 9
},
{
id: 'ivf-baby-1978',
title: "First IVF baby born",
author: "Louise Brown",
date: "1978-07-25",
category: 'BIOLOGY',
description: "Birth of first baby conceived through in vitro fertilization",
tags: ['IVF', 'fertility', 'reproduction', 'medicine'],
importance: 8
},
{
id: 'face-transplant-2010',
title: "First complete face transplant performed",
author: "Spanish surgeons",
date: "2010-03-20",
category: 'BIOLOGY',
description: "Full facial transplantation surgery breakthrough",
tags: ['transplant', 'surgery', 'face', 'reconstructive'],
importance: 7
},
{
id: 'mrna-vaccines-2005',
title: "Messenger RNA vaccines pioneered",
author: "Katalin Karikó",
date: "2005-08-01",
category: 'BIOLOGY',
description: "Development of mRNA vaccine technology",
tags: ['mRNA', 'vaccine', 'biotechnology', 'immunology'],
importance: 9
},
{
id: 'covid-vaccine-2020',
title: "First COVID-19 vaccine developed",
author: "Pfizer-BioNTech",
date: "2020-12-11",
category: 'BIOLOGY',
description: "First authorized COVID-19 vaccine using mRNA technology",
tags: ['COVID-19', 'vaccine', 'pandemic', 'mRNA'],
importance: 9
},
{
id: 'cancer-immunotherapy-2018',
title: "Cancer immunotherapy breakthrough",
author: "James Allison",
date: "2018-10-01",
category: 'BIOLOGY',
description: "Nobel Prize for cancer immunotherapy research",
tags: ['cancer', 'immunotherapy', 'treatment', 'oncology'],
importance: 9
},
{
id: 'gene-therapy-2017',
title: "First gene therapy approved",
author: "FDA",
date: "2017-08-30",
category: 'BIOLOGY',
description: "FDA approval of first gene therapy treatment",
tags: ['gene therapy', 'treatment', 'genetics', 'medicine'],
importance: 8
},
// Chemistry
{
id: 'periodic-table-1869',
title: "Periodic table created",
author: "Dmitri Mendeleev",
date: "1869-03-06",
category: 'CHEMISTRY',
description: "Organization of chemical elements by atomic properties",
tags: ['periodic table', 'elements', 'chemistry', 'atomic'],
importance: 10
},
{
id: 'radioactivity-becquerel-1896',
title: "Radioactivity discovered",
author: "Henri Becquerel",
date: "1896-03-01",
category: 'CHEMISTRY',
description: "Discovery of natural radioactivity in uranium",
tags: ['radioactivity', 'uranium', 'physics', 'nuclear'],
importance: 9
},
{
id: 'radioactivity-curie-1898',
title: "Radioactivity studied by Marie Curie",
author: "Marie Curie",
date: "1898-07-01",
category: 'CHEMISTRY',
description: "Isolation and study of radium and polonium",
tags: ['radioactivity', 'radium', 'polonium', 'nuclear'],
importance: 9
},
{
id: 'benzene-structure-1865',
title: "Structure of benzene discovered",
author: "Kekulé",
date: "1865-01-01",
category: 'CHEMISTRY',
description: "Discovery of the ring structure of benzene",
tags: ['benzene', 'organic chemistry', 'molecular structure'],
importance: 8
},
{
id: 'teflon-discovery-1938',
title: "Discovery of Teflon",
author: "Roy Plunkett",
date: "1938-04-06",
category: 'CHEMISTRY',
description: "Accidental discovery of polytetrafluoroethylene",
tags: ['teflon', 'polymer', 'materials', 'chemistry'],
importance: 7
},
{
id: 'plastic-invention-1907',
title: "Plastic invented",
author: "Leo Baekeland",
date: "1907-01-01",
category: 'CHEMISTRY',
description: "Invention of Bakelite, the first synthetic plastic",
tags: ['plastic', 'polymer', 'synthetic', 'materials'],
importance: 8
},
{
id: 'superconductivity-1911',
title: "Discovery of superconductivity",
author: "Heike Kamerlingh Onnes",
date: "1911-04-08",
category: 'CHEMISTRY',
description: "Discovery of zero electrical resistance in mercury",
tags: ['superconductivity', 'physics', 'electrical', 'materials'],
importance: 9
},
// Computing & Technology
{
id: 'transistor-1947',
title: "Transistor invention launches digital age",
author: "Bell Labs",
date: "1947-12-23",
category: 'TECHNOLOGY',
description: "Invention of the point-contact transistor",
tags: ['transistor', 'electronics', 'computing', 'semiconductor'],
importance: 10
},
{
id: 'first-computer-1941',
title: "First programmable computer unveiled",
author: "Konrad Zuse",
date: "1941-05-12",
category: 'TECHNOLOGY',
description: "Z3 computer, first programmable digital computer",
tags: ['computer', 'programming', 'digital', 'computing'],
importance: 9
},
{
id: 'tcp-ip-1974',
title: "Internet protocol TCP/IP standardized",
author: "Vint Cerf & Bob Kahn",
date: "1974-12-01",
category: 'TECHNOLOGY',
description: "Development of fundamental internet protocols",
tags: ['internet', 'protocol', 'networking', 'TCP/IP'],
importance: 10
},
{
id: 'world-wide-web-1989',
title: "World Wide Web invented",
author: "Tim Berners-Lee",
date: "1989-03-12",
category: 'TECHNOLOGY',
description: "Creation of the World Wide Web at CERN",
tags: ['web', 'internet', 'hypertext', 'browser'],
importance: 10
},
{
id: 'first-email-1971',
title: "First email sent",
author: "Ray Tomlinson",
date: "1971-10-01",
category: 'TECHNOLOGY',
description: "First network email using @ symbol",
tags: ['email', 'communication', 'networking', 'ARPANET'],
importance: 8
},
{
id: 'microprocessor-1971',
title: "First microprocessor released",
author: "Intel 4004",
date: "1971-11-15",
category: 'TECHNOLOGY',
description: "Intel 4004, first commercial microprocessor",
tags: ['microprocessor', 'Intel', 'computing', 'chip'],
importance: 9
},
{
id: 'web-browser-1993',
title: "First graphical web browser released",
author: "Mosaic",
date: "1993-04-22",
category: 'TECHNOLOGY',
description: "Mosaic browser popularizes the World Wide Web",
tags: ['browser', 'web', 'graphical', 'internet'],
importance: 8
},
{
id: 'smartphone-1992',
title: "First smartphone introduced",
author: "IBM Simon",
date: "1992-08-16",
category: 'TECHNOLOGY',
description: "IBM Simon Personal Communicator, first smartphone",
tags: ['smartphone', 'mobile', 'communication', 'PDA'],
importance: 8
},
{
id: 'google-founded-1998',
title: "Google founded",
author: "Larry Page & Sergey Brin",
date: "1998-09-04",
category: 'TECHNOLOGY',
description: "Founding of Google search engine company",
tags: ['Google', 'search', 'internet', 'algorithm'],
importance: 9
},
{
id: 'iphone-2007',
title: "Apple introduces iPhone",
author: "Steve Jobs",
date: "2007-01-09",
category: 'TECHNOLOGY',
description: "Launch of revolutionary touchscreen smartphone",
tags: ['iPhone', 'Apple', 'smartphone', 'touchscreen'],
importance: 9
},
{
id: 'deep-blue-chess-1997',
title: "First AI beats chess world champion",
author: "IBM Deep Blue",
date: "1997-05-11",
category: 'TECHNOLOGY',
description: "Deep Blue defeats Garry Kasparov in chess match",
tags: ['AI', 'chess', 'IBM', 'artificial intelligence'],
importance: 8
},
{
id: 'alphago-2016',
title: "First AI beats Go world champion",
author: "DeepMind AlphaGo",
date: "2016-03-15",
category: 'TECHNOLOGY',
description: "AlphaGo defeats Lee Sedol in Go tournament",
tags: ['AI', 'Go', 'DeepMind', 'machine learning'],
importance: 9
},
{
id: 'chatgpt-2022',
title: "ChatGPT released to public",
author: "OpenAI",
date: "2022-11-30",
category: 'TECHNOLOGY',
description: "Public release of conversational AI chatbot",
tags: ['AI', 'chatbot', 'GPT', 'natural language'],
importance: 9
},
{
id: 'bitcoin-2009',
title: "Bitcoin blockchain launched",
author: "Satoshi Nakamoto",
date: "2009-01-03",
category: 'TECHNOLOGY',
description: "Launch of first decentralized cryptocurrency",
tags: ['Bitcoin', 'blockchain', 'cryptocurrency', 'digital currency'],
importance: 8
},
{
id: '3d-printer-1984',
title: "First 3D printer invented",
author: "Chuck Hull",
date: "1984-03-09",
category: 'TECHNOLOGY',
description: "Invention of stereolithography 3D printing",
tags: ['3D printing', 'manufacturing', 'prototyping', 'technology'],
importance: 8
},
{
id: 'robot-surgery-2000',
title: "First robot-assisted surgery performed",
author: "da Vinci System",
date: "2000-07-11",
category: 'TECHNOLOGY',
description: "First surgery using da Vinci robotic system",
tags: ['robotics', 'surgery', 'medical technology', 'automation'],
importance: 7
},
{
id: 'self-driving-car-2005',
title: "First self-driving car tested",
author: "DARPA",
date: "2005-10-08",
category: 'TECHNOLOGY',
description: "DARPA Grand Challenge autonomous vehicle competition",
tags: ['autonomous', 'self-driving', 'automotive', 'AI'],
importance: 8
},
{
id: 'quantum-supremacy-2019',
title: "Quantum computer reaches supremacy",
author: "Google",
date: "2019-10-23",
category: 'TECHNOLOGY',
description: "Google's quantum computer outperforms classical computers",
tags: ['quantum computing', 'supremacy', 'computing', 'quantum'],
importance: 9
},
// Engineering & Energy
{
id: 'nuclear-power-1954',
title: "First nuclear power plant opens",
author: "Obninsk, USSR",
date: "1954-06-27",
category: 'ENGINEERING',
description: "First commercial nuclear power plant begins operation",
tags: ['nuclear', 'power', 'energy', 'electricity'],
importance: 9
},
{
id: 'wright-brothers-1903',
title: "First flight of the Wright brothers",
author: "Wright Brothers",
date: "1903-12-17",
category: 'ENGINEERING',
description: "First powered, controlled, sustained heavier-than-air flight",
tags: ['flight', 'aviation', 'airplane', 'Wright brothers'],
importance: 10
},
{
id: 'jet-airliner-1952',
title: "First commercial jet airliner",
author: "de Havilland Comet",
date: "1952-05-02",
category: 'ENGINEERING',
description: "First commercial jet passenger service begins",
tags: ['jet', 'aviation', 'commercial', 'passenger'],
importance: 8
},
{
id: 'supersonic-flight-1969',
title: "First supersonic passenger flight",
author: "Concorde",
date: "1969-03-02",
category: 'ENGINEERING',
description: "Concorde's first test flight breaks sound barrier",
tags: ['supersonic', 'Concorde', 'aviation', 'passenger'],
importance: 7
},
{
id: 'panama-canal-1914',
title: "Panama Canal completed",
author: "US Engineers",
date: "1914-08-15",
category: 'ENGINEERING',
description: "Completion of Panama Canal connecting Atlantic and Pacific",
tags: ['canal', 'engineering', 'transportation', 'shipping'],
importance: 8
},
{
id: 'first-skyscraper-1885',
title: "First skyscraper built",
author: "Chicago Home Insurance Building",
date: "1885-01-01",
category: 'ENGINEERING',
description: "First steel-frame skyscraper construction",
tags: ['skyscraper', 'construction', 'architecture', 'steel'],
importance: 7
},
{
id: 'photovoltaic-cell-1954',
title: "First photovoltaic cell invented",
author: "Bell Labs",
date: "1954-04-25",
category: 'ENGINEERING',
description: "First practical silicon solar cell developed",
tags: ['solar', 'photovoltaic', 'renewable energy', 'silicon'],
importance: 8
},
{
id: 'electric-battery-1800',
title: "First electric battery invented",
author: "Alessandro Volta",
date: "1800-03-20",
category: 'ENGINEERING',
description: "Invention of the voltaic pile, first electric battery",
tags: ['battery', 'electricity', 'energy storage', 'volta'],
importance: 9
},
{
id: 'electromagnetic-induction-1831',
title: "Electricity powers the modern world",
author: "Michael Faraday",
date: "1831-08-29",
category: 'ENGINEERING',
description: "Discovery of electromagnetic induction principles",
tags: ['electricity', 'electromagnetic', 'induction', 'power'],
importance: 10
}
],
validate(item) {
const required = ['id', 'title', 'author', 'date', 'category'];
const missing = required.filter(field => !item[field]);
if (missing.length > 0) {
throw new NewsTickerError(`Missing required fields: ${missing.join(', ')}`, 'VALIDATION_ERROR');
}
return true;
},
getByCategory(category) {
return this.items.filter(item => item.category === category);
},
getByImportance(minImportance = 5) {
return this.items.filter(item => item.importance >= minImportance);
},
search(query) {
const lowerQuery = query.toLowerCase();
return this.items.filter(item =>
item.title.toLowerCase().includes(lowerQuery) ||
item.author.toLowerCase().includes(lowerQuery) ||
item.tags.some(tag => tag.toLowerCase().includes(lowerQuery))
);
}
};
// Enhanced image service with caching and error handling
const ImageService = {
cache: new Map(),
loadingPromises: new Map(),
async fetchImage(prompt, options = {}) {
const cacheKey = `${prompt}_${JSON.stringify(options)}`;
// Return cached image if available
if (this.cache.has(cacheKey)) {
Logger.debug('Image cache hit', { prompt });
return this.cache.get(cacheKey);
}
// Return existing promise if already loading
if (this.loadingPromises.has(cacheKey)) {
Logger.debug('Image already loading', { prompt });
return this.loadingPromises.get(cacheKey);
}
const loadingPromise = this._loadImage(prompt, options, cacheKey);
this.loadingPromises.set(cacheKey, loadingPromise);
try {
const result = await loadingPromise;
this.cache.set(cacheKey, result);
return result;
} finally {
this.loadingPromises.delete(cacheKey);
}
},
async _loadImage(prompt, options, cacheKey) {
const params = { ...CONFIG.API.IMAGE_PARAMS, ...options };
const queryString = new URLSearchParams(params).toString();
const imageUrl = `${CONFIG.API.POLLINATIONS_BASE_URL}/${encodeURIComponent(prompt)}?${queryString}`;
return Utils.withTimeout(
this._preloadImage(imageUrl),
CONFIG.UI.IMAGE_LOAD_TIMEOUT,
'Image loading timeout'
);
},
_preloadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => {
Logger.debug('Image loaded successfully', { url });
resolve({
url,
width: img.naturalWidth,
height: img.naturalHeight,
loaded: true
});
};
img.onerror = (error) => {
Logger.error('Image failed to load', { url, error });
reject(new NewsTickerError('Failed to load image', 'IMAGE_LOAD_ERROR', { url }));
};
img.src = url;
});
},
clearCache() {
this.cache.clear();
this.loadingPromises.clear();
Logger.info('Image cache cleared');
},
getCacheStats() {
return {
cacheSize: this.cache.size,
loadingCount: this.loadingPromises.size,
cacheEntries: Array.from(this.cache.keys())
};
}
};
// User preferences management
const PreferencesManager = {
defaults: {
updateInterval: CONFIG.UI.DEFAULT_INTERVAL,
autoStart: true,
categories: Object.keys(NewsData.categories),
theme: 'auto',
soundEnabled: false,
minImportance: 5
},
load() {
try {
const stored = localStorage.getItem(CONFIG.STORAGE_KEY);
return stored ? { ...this.defaults, ...JSON.parse(stored) } : this.defaults;
} catch (error) {
Logger.error('Failed to load preferences', error);
return this.defaults;
}
},
save(preferences) {
try {
localStorage.setItem(CONFIG.STORAGE_KEY, JSON.stringify(preferences));
Logger.info('Preferences saved', preferences);
} catch (error) {
Logger.error('Failed to save preferences', error);
}
},
update(updates) {
const current = this.load();
const updated = { ...current, ...updates };
this.save(updated);
return updated;
}
};
// Enhanced NewsManager with better architecture
const NewsManager = (props, ctx) => {
let intervalId = null;
let currentNewsIndex = 0;
let filteredNews = [];
let isDestroyed = false;
const preferences = PreferencesManager.load();
// Initialize filtered news based on preferences
const updateFilteredNews = () => {
filteredNews = NewsData.items.filter(item =>
preferences.categories.includes(item.category) &&
item.importance >= preferences.minImportance
);
if (filteredNews.length === 0) {
Logger.warn('No news items match current filters');
filteredNews = NewsData.items; // Fallback to all news
}
Logger.info(`Filtered news updated: ${filteredNews.length} items`);
};
const fetchRandomNews = async () => {
if (filteredNews.length === 0) updateFilteredNews();
const randomIndex = Math.floor(Math.random() * filteredNews.length);
const newsItem = filteredNews[randomIndex];
try {
NewsData.validate(newsItem);
return newsItem;
} catch (error) {
Logger.error('Invalid news item', { newsItem, error });
throw error;
}
};
const updateNews = async () => {
if (isDestroyed) return;
const startTime = Date.now();
ctx.setState('loading', true);
try {
const news = await Utils.retry(fetchRandomNews, 3);
Logger.info('Fetched news item', { title: news.title, id: news.id });
// Generate image prompt based on news content
const imagePrompt = `${news.title} ${news.description || ''} scientific illustration`;
const imageResult = await Utils.retry(
() => ImageService.fetchImage(imagePrompt),
CONFIG.API.RETRY_ATTEMPTS
);
// Enforce minimum display time
const elapsed = Date.now() - startTime;
const remaining = CONFIG.UI.MIN_DISPLAY_TIME - elapsed;
if (remaining > 0) {
await Utils.delay(remaining);
}
if (!isDestroyed) {
ctx.setState('currentNews', {
...news,
imageUrl: imageResult.url,
imageMetadata: {
width: imageResult.width,
height: imageResult.height,
loadTime: Date.now() - startTime
}
});
ctx.setState('lastUpdated', new Date().toLocaleTimeString());
ctx.setState('error', null);
Logger.info('News updated successfully', { newsId: news.id });
}
} catch (error) {
Logger.error('Failed to update news', error);
ctx.setState('error', {
message: error.message,
code: error.code,
timestamp: new Date().toISOString()
});
} finally {
if (!isDestroyed) {
ctx.setState('loading', false);
}
}
};
// Cleanup function
const cleanup = () => {
if (intervalId) {
clearInterval(intervalId);
intervalId = null;
}
isDestroyed = true;
Logger.info('NewsManager cleaned up');
};
// Initialize
updateFilteredNews();
return {
api: {
async startPeriodicUpdates(intervalMs = preferences.updateInterval) {
if (intervalId) this.stopPeriodicUpdates();
ctx.setState('isUpdating', true);
ctx.setState('updateInterval', intervalMs);
Logger.info('Starting periodic updates', { intervalMs });
// Initial update
await updateNews();
if (!isDestroyed) {
intervalId = setInterval(async () => {
if (!ctx.getState('isUpdating') || isDestroyed) {
this.stopPeriodicUpdates();
return;
}
await updateNews();
}, intervalMs);
}
},
stopPeriodicUpdates() {
if (intervalId) {
clearInterval(intervalId);
intervalId = null;
Logger.info('Stopped periodic updates');
}
ctx.setState('isUpdating', false);
},
async fetchRandomNews() {
Logger.info('Manual news fetch requested');
await updateNews();
},
updatePreferences(newPrefs) {
Object.assign(preferences, newPrefs);
PreferencesManager.save(preferences);
updateFilteredNews();
Logger.info('Preferences updated', newPrefs);
},
getStats() {
return {
totalNews: NewsData.items.length,
filteredNews: filteredNews.length,
imageCache: ImageService.getCacheStats(),
preferences,
isRunning: !!intervalId
};
},
exportData() {
return {
currentNews: ctx.getState('currentNews'),
preferences,
stats: this.getStats(),
logs: Logger.exportLogs().slice(-20) // Last 20 logs
};
},
cleanup
}
};
};
// Enhanced Banner component with error handling
const Banner = (props, ctx) => ({
div: {
className: 'news-banner gradient-border',
children: [
// Error display
...(ctx.getState('error') ? [{
div: {
className: 'error-banner bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4',
children: [
{
span: {
className: 'font-bold',
text: 'Error: '
}
},
{
span: {
text: () => ctx.getState('error')?.message || 'Unknown error occurred'
}
}
]
}
}] : []),
// Loading indicator
...(ctx.getState('loading') ? [{
div: {
className: 'loading-indicator flex items-center justify-center py-4',
children: [
{
div: {
className: 'animate-spin rounded-full h-8 w-8 border-b-2 border-indigo-600 mr-3'
}
},
{ span: { text: 'Loading news...', className: 'text-gray-600' } }
]
}
}] : []),
// Main content
{
h1: {
className: 'news-title',
children: [
{
span: {
text: () => {
const news = ctx.getState('currentNews');
return news ? Utils.sanitizeHtml(news.title) : 'Loading news...';
}
}
}
]
}
},
{
img: {
src: () => ctx.getState('currentNews')?.imageUrl || '',
className: 'news-image',
alt: () => ctx.getState('currentNews')?.title || 'News image',
loading: 'lazy',
onError: () => {
Logger.error('Image failed to display');
ctx.setState('imageError', true);
}
}
},
{
div: {
className: 'news-meta text-sm text-gray-600 mb-4',
children: [
{
span: {
className: 'author font-medium',
text: () => {
const news = ctx.getState('currentNews');
return news ? `By ${news.author}` : '';
}
}
},
{
span: {
className: 'date ml-2',
text: () => {
const news = ctx.getState('currentNews');
return news ? `• ${Utils.formatDate(news.date)}` : '';
}
}
},
{
span: {
className: 'category ml-2 inline-block bg-gray-200 rounded-full px-2 py-1 text-xs',
text: () => {
const news = ctx.getState('currentNews');
return news ? NewsData.categories[news.category] : '';
}
}
}
]
}
},
{
div: {
className: 'info-bar',
children: [
{
div: {
className: () => `status-indicator ${ctx.getState('isUpdating') ? 'status-live' : 'status-paused'}`
}
},
{
span: {
text: () => ctx.getState('isUpdating') ? 'LIVE' : 'PAUSED',
className: 'font-semibold'
}
},
{
span: {
text: () => {
const lastUpdated = ctx.getState('lastUpdated');
const interval = ctx.getState('updateInterval');
return lastUpdated ? `• ${lastUpdated}${interval ? ` (${interval/1000}s)` : ''}` : '';
}
}
}
]
}
}
]
}
});
// Enhanced Controls with more options
const Controls = (props, ctx) => {
const { NewsManager } = ctx;
return {
div: {
className: 'controls-container',
children: [
// Primary controls
{
div: {
className: 'primary-controls flex gap-3 mb-4',
children: [
{
button: {
className: 'btn-primary',
text: () => ctx.getState('isUpdating') ? 'Stop Updates' : 'Start Updates',
onclick: () => {
if (ctx.getState('isUpdating')) {
NewsManager.stopPeriodicUpdates();
} else {
const preferences = PreferencesManager.load();
NewsManager.startPeriodicUpdates(preferences.updateInterval);
}
},
disabled: () => ctx.getState('loading')
}
},
{
button: {
className: 'btn-secondary',
text: 'Random News',
onclick: () => NewsManager.fetchRandomNews(),
disabled: () => ctx.getState('loading')
}
}
]
}
},
// Speed controls
{
div: {
className: 'speed-controls flex gap-2 mb-4',
children: [
{
button: {
className: 'btn-tertiary text-xs',
text: 'Fast (1s)',
onclick: () => {
if (ctx.getState('isUpdating')) {
NewsManager.stopPeriodicUpdates();
NewsManager.startPeriodicUpdates(CONFIG.UI.FAST_INTERVAL);
}
}
}
},
{
button: {
className: 'btn-tertiary text-xs',
text: 'Normal (3s)',
onclick: () => {
if (ctx.getState('isUpdating')) {
NewsManager.stopPeriodicUpdates();
NewsManager.startPeriodicUpdates(CONFIG.UI.DEFAULT_INTERVAL);
}
}
}
},
{
button: {
className: 'btn-tertiary text-xs',
text: 'Slow (5s)',
onclick: () => {
if (ctx.getState('isUpdating')) {
NewsManager.stopPeriodicUpdates();
NewsManager.startPeriodicUpdates(CONFIG.UI.SLOW_INTERVAL);
}
}
}
}
]
}
},
// Utility controls
{
div: {
className: 'utility-controls flex gap-2 text-xs',
children: [
{
button: {
className: 'btn-tertiary',
text: 'Clear Cache',
onclick: () => {
ImageService.clearCache();
Logger.info('Cache cleared by user');
}
}
},
{
button: {
className: 'btn-tertiary',
text: 'Export Data',
onclick: () => {
const data = NewsManager.exportData();
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `news-ticker-export-${Date.now()}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
}
}
]
}
}
]
}
};
};
// Enhanced App component
const App = (props, ctx) => ({
div: {
className: 'news-container',
children: [
{
div: {
className: 'news-wrapper',
children: [
{
h2: {
className: 'news-header',
text: 'Scientific Discovery Timeline'
}
},
{ Banner: {} },
{ Controls: {} },
// Stats panel (development mode)
...(window.location.search.includes('debug=true') ? [{
div: {
className: 'debug-panel mt-8 p-4 bg-gray-100 rounded-lg text-sm',
children: [
{ h3: { text: 'Debug Information', className: 'font-bold mb-2' } },
{
pre: {
text: () => JSON.stringify(ctx.NewsManager?.getStats?.() || {}, null, 2),
className: 'text-xs overflow-auto max-h-40'
}
}
]
}
}] : [])
]
}
}
]
}
});
// Initialize application with enhanced error handling
try {
const juris = new Juris({
states: {
currentNews: null,
isUpdating: false,
loading: false,
lastUpdated: null,
updateInterval: CONFIG.UI.DEFAULT_INTERVAL,
error: null,
imageError: false
},
components: { Banner, Controls, App },
headlessComponents: {
NewsManager: {
fn: NewsManager,
options: { autoInit: true }
}
},
layout: [{ App: {} }]
});
// Global error handler
window.addEventListener('error', (event) => {
Logger.error('Global error caught', {
message: event.error?.message,
stack: event.error?.stack,
filename: event.filename,
lineno: event.lineno
});
});
window.addEventListener('unhandledrejection', (event) => {
Logger.error('Unhandled promise rejection', {
reason: event.reason?.message || event.reason
});
});
// Cleanup on page unload
window.addEventListener('beforeunload', () => {
if (juris.headlessAPIs?.NewsManager?.cleanup) {
juris.headlessAPIs.NewsManager.cleanup();
}
});
juris.render();
// Auto-start if enabled in preferences
const preferences = PreferencesManager.load();
if (preferences.autoStart) {
setTimeout(() => {
juris.headlessAPIs.NewsManager?.startPeriodicUpdates?.(preferences.updateInterval);
}, 100);
}
Logger.info('News Ticker initialized successfully');
} catch (error) {
Logger.error('Failed to initialize News Ticker', error);
document.body.innerHTML = `
<div class="error-container">
<h1>Failed to Initialize News Ticker</h1>
<p>Error: ${error.message}</p>
<button onclick="location.reload()">Reload Page</button>
</div>
`;
}
Top comments (0)