Initial release v1.2.0 — Hellion NewTab Browser Extension

Persoenlicher Bookmark-Dashboard als Browser-Extension.
8 Themes, Drag & Drop, Sticky Notes, JSON Export/Import.
Chrome, Edge, Brave, Opera, Vivaldi (MV3) + Firefox (MV2).

Includes GitHub Actions for security scanning, code quality
validation, and automated release packaging.
This commit is contained in:
2026-03-20 22:48:21 +01:00
commit 87c30b24d0
30 changed files with 2835 additions and 0 deletions
+119
View File
@@ -0,0 +1,119 @@
/* =============================================
HELLION NEWTAB — app.js
Einstiegspunkt: Init, Clock, globale Events
============================================= */
async function init() {
const savedBoards = await Store.get('boards');
const savedSettings = await Store.get('settings');
boards = savedBoards ?? getDefaultBoards();
if (savedSettings) Object.assign(settings, savedSettings);
applySettings();
renderBoards();
startClock();
bindGlobalEvents();
bindSettingsEvents();
initSearch();
initStickyNote();
initDataButtons();
Store.checkQuota();
}
// ---- CLOCK & DATE ----
function startClock() {
const DAYS = ['So','Mo','Di','Mi','Do','Fr','Sa'];
const MONTHS = ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'];
function tick() {
const now = new Date();
document.getElementById('clock').textContent =
`${String(now.getHours()).padStart(2,'0')}:${String(now.getMinutes()).padStart(2,'0')}`;
document.getElementById('date').textContent =
`${DAYS[now.getDay()]}, ${String(now.getDate()).padStart(2,'0')}. ${MONTHS[now.getMonth()]}`;
}
tick();
setInterval(tick, 1000);
}
// ---- GLOBALE EVENTS (Header-Buttons, Modals, Import) ----
function bindGlobalEvents() {
// Header
document.getElementById('btnAddBoard').addEventListener('click', openAddBoardModal);
document.getElementById('btnImport').addEventListener('click', () => {
document.getElementById('importInput').click();
});
// HTML Bookmark Import
document.getElementById('importInput').addEventListener('change', async e => {
const file = e.target.files[0];
if (!file) return;
const imported = parseBookmarkHtml(await file.text());
if (imported.length === 0) { alert('Keine Bookmarks gefunden.'); return; }
boards = [...boards, ...imported];
await saveBoards();
renderBoards();
e.target.value = '';
alert(`${imported.length} Board(s) mit ${imported.reduce((s,b) => s + b.bookmarks.length, 0)} Bookmarks importiert.`);
});
// Add Board Modal
document.getElementById('btnCancelBoard').addEventListener('click', () => closeModal('addBoardOverlay'));
document.getElementById('addBoardOverlay').addEventListener('click', e => {
if (e.target === document.getElementById('addBoardOverlay')) closeModal('addBoardOverlay');
});
document.getElementById('btnConfirmBoard').addEventListener('click', async () => {
const name = document.getElementById('newBoardName').value.trim();
if (!name) return;
boards.push({ id: uid(), title: name, bookmarks: [] });
await saveBoards();
renderBoards();
closeModal('addBoardOverlay');
});
document.getElementById('newBoardName').addEventListener('keydown', e => {
if (e.key === 'Enter') document.getElementById('btnConfirmBoard').click();
if (e.key === 'Escape') closeModal('addBoardOverlay');
});
// Add Bookmark Modal
document.getElementById('btnCancelBookmark').addEventListener('click', () => closeModal('addBookmarkOverlay'));
document.getElementById('addBookmarkOverlay').addEventListener('click', e => {
if (e.target === document.getElementById('addBookmarkOverlay')) closeModal('addBookmarkOverlay');
});
document.getElementById('btnConfirmBookmark').addEventListener('click', async () => {
const title = document.getElementById('newBmTitle').value.trim();
const url = document.getElementById('newBmUrl').value.trim();
const desc = document.getElementById('newBmDesc').value.trim();
if (!title || !url) return;
try { new URL(url); } catch { alert('Ungültige URL. Bitte mit https:// beginnen.'); return; }
const board = boards.find(b => b.id === pendingBookmarkBoardId);
if (!board) return;
board.bookmarks.push({ id: uid(), title, url, desc });
await saveBoards();
renderBoards();
closeModal('addBookmarkOverlay');
});
document.getElementById('newBmUrl').addEventListener('keydown', e => {
if (e.key === 'Enter') document.getElementById('btnConfirmBookmark').click();
if (e.key === 'Escape') closeModal('addBookmarkOverlay');
});
// Rename Modal
document.getElementById('btnCancelRename').addEventListener('click', () => closeModal('renameOverlay'));
document.getElementById('renameOverlay').addEventListener('click', e => {
if (e.target === document.getElementById('renameOverlay')) closeModal('renameOverlay');
});
document.getElementById('btnConfirmRename').addEventListener('click', () => {
const val = document.getElementById('renameInput').value.trim();
if (pendingRenameCallback) pendingRenameCallback(val);
pendingRenameCallback = null;
closeModal('renameOverlay');
});
document.getElementById('renameInput').addEventListener('keydown', e => {
if (e.key === 'Enter') document.getElementById('btnConfirmRename').click();
if (e.key === 'Escape') closeModal('renameOverlay');
});
}
document.addEventListener('DOMContentLoaded', init);