Adicionar opção para carregamento delayed (apos n segundos)

This commit is contained in:
2026-05-29 10:42:52 -03:00
parent acb9208cec
commit 49e01836dd
5 changed files with 88 additions and 25 deletions
+3 -2
View File
@@ -11,6 +11,7 @@
--accent: #7fff6e; --accent: #7fff6e;
--muted: #6b6b7a; --muted: #6b6b7a;
--text: #e8e8ec; --text: #e8e8ec;
--border: #2a2a32;
} }
body { body {
@@ -22,7 +23,7 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: 100vh; height: 100vh;
gap: 24px; gap: 20px;
user-select: none; user-select: none;
} }
@@ -65,7 +66,7 @@
text-align: center; text-align: center;
word-break: break-all; word-break: break-all;
padding: 8px 16px; padding: 8px 16px;
border: 1px solid #2a2a32; border: 1px solid var(--border);
border-radius: 6px; border-radius: 6px;
line-height: 1.6; line-height: 1.6;
margin-bottom: 1em; margin-bottom: 1em;
+12 -1
View File
@@ -1,6 +1,7 @@
(() => { (() => {
const params = new URLSearchParams(location.search); const params = new URLSearchParams(location.search);
const destUrl = params.get('url'); const destUrl = params.get('url');
const loadDelay = params.get('load_delay'); // seconds, or null
if (!destUrl) { if (!destUrl) {
document.querySelector('.label').textContent = 'No URL provided.'; document.querySelector('.label').textContent = 'No URL provided.';
@@ -17,7 +18,13 @@
function navigate() { function navigate() {
if (navigated) return; if (navigated) return;
navigated = true; navigated = true;
location.replace(destUrl); if( destUrl.indexOf('chrome://')==0 ) {
document.querySelector('.ring').style.display = 'none';
document.querySelector('.label').textContent = 'Cant load url';
}
else {
location.replace(destUrl);
}
} }
// "Load now" button — immediate bypass // "Load now" button — immediate bypass
@@ -36,4 +43,8 @@
} }
}); });
} }
if( loadDelay!=null ) {
setTimeout(navigate, loadDelay*1000);
}
})(); })();
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "URL Launcher", "name": "URL Launcher",
"version": "1.0.1", "version": "1.1.0",
"description": "Paste a list of URLs and open them all as tabs, with optional lazy-load on focus.", "description": "Paste a list of URLs and open them all as tabs, with optional lazy-load on focus.",
"action": { "action": {
"default_popup": "popup.html", "default_popup": "popup.html",
+40 -10
View File
@@ -305,6 +305,25 @@
background: rgba(127,255,110,0.1); background: rgba(127,255,110,0.1);
} }
/* ── Checkboxes stack ── */
.checkboxes {
display: flex;
flex-direction: column;
gap: 8px;
flex: 1;
}
.delay-hint {
color: var(--muted);
font-size: 10px;
font-family: 'JetBrains Mono', monospace;
}
.checkbox-label.disabled {
opacity: 0.35;
pointer-events: none;
}
/* ── Focus mode indicator ── */ /* ── Focus mode indicator ── */
.mode-badge { .mode-badge {
display: inline-flex; display: inline-flex;
@@ -377,16 +396,27 @@
</div> </div>
<div class="options"> <div class="options">
<label class="checkbox-label" title="Each URL opens via an intermediate page and only navigates when you focus that tab"> <div class="checkboxes">
<input type="checkbox" id="lazyLoad" checked /> <label class="checkbox-label" title="Each URL opens via an intermediate page and only navigates when you focus that tab">
<span class="custom-checkbox"> <input type="checkbox" id="lazyLoad" checked />
<!-- checkmark --> <span class="custom-checkbox">
<svg viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.5 5L4 7.5L8.5 2.5" stroke="#0d0d0f" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/> <path d="M1.5 5L4 7.5L8.5 2.5" stroke="#0d0d0f" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>
</span> </span>
<span class="checkbox-text">Wait for focus to load</span> <span class="checkbox-text">Wait for focus to load</span>
</label> </label>
<label class="checkbox-label" id="delayedLoadLabel" title="Each tab auto-loads after a staggered timer: 1s, 2s, 3s… Requires 'Wait for focus'">
<input type="checkbox" id="delayedLoad" checked />
<span class="custom-checkbox">
<svg viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.5 5L4 7.5L8.5 2.5" stroke="#0d0d0f" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</span>
<span class="checkbox-text">Delayed load <span class="delay-hint" id="delayHint">(1s, 2s, 3s…)</span></span>
</label>
</div>
<button class="launch-btn" id="openBtn" disabled> <button class="launch-btn" id="openBtn" disabled>
<svg viewBox="0 0 13 13" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 13 13" xmlns="http://www.w3.org/2000/svg">
+32 -11
View File
@@ -1,11 +1,13 @@
(() => { (() => {
const urlInput = document.getElementById('urlInput'); const urlInput = document.getElementById('urlInput');
const lazyLoad = document.getElementById('lazyLoad'); const lazyLoad = document.getElementById('lazyLoad');
const openBtn = document.getElementById('openBtn'); const delayedLoad = document.getElementById('delayedLoad');
const extractBtn = document.getElementById('extractBtn'); const delayedLoadLabel = document.getElementById('delayedLoadLabel');
const urlCount = document.getElementById('urlCount'); const openBtn = document.getElementById('openBtn');
const status = document.getElementById('status'); const extractBtn = document.getElementById('extractBtn');
const modeBadge = document.getElementById('modeBadgeInner'); const urlCount = document.getElementById('urlCount');
const status = document.getElementById('status');
const modeBadge = document.getElementById('modeBadgeInner');
// ── Helpers ──────────────────────────────────────────────── // ── Helpers ────────────────────────────────────────────────
function parseURLs(text) { function parseURLs(text) {
@@ -52,13 +54,22 @@
} }
function updateBadge() { function updateBadge() {
if (lazyLoad.checked) { const isLazy = lazyLoad.checked;
const isDelayed = delayedLoad.checked;
if (isLazy && isDelayed) {
modeBadge.textContent = 'lazy + delay';
modeBadge.className = 'mode-badge';
} else if (isLazy) {
modeBadge.textContent = 'lazy'; modeBadge.textContent = 'lazy';
modeBadge.className = 'mode-badge'; modeBadge.className = 'mode-badge';
} else { } else {
modeBadge.textContent = 'eager'; modeBadge.textContent = 'eager';
modeBadge.className = 'mode-badge off'; modeBadge.className = 'mode-badge off';
} }
// Delayed load only makes sense when lazy is on
delayedLoadLabel.classList.toggle('disabled', !isLazy);
} }
// ── Event listeners ──────────────────────────────────────── // ── Event listeners ────────────────────────────────────────
@@ -68,6 +79,7 @@
}); });
lazyLoad.addEventListener('change', updateBadge); lazyLoad.addEventListener('change', updateBadge);
delayedLoad.addEventListener('change', updateBadge);
extractBtn.addEventListener('click', () => { extractBtn.addEventListener('click', () => {
const urls = extractURLs(urlInput.value); const urls = extractURLs(urlInput.value);
@@ -91,17 +103,26 @@
openBtn.disabled = true; openBtn.disabled = true;
setStatus(''); setStatus('');
const useLazy = lazyLoad.checked; const useLazy = lazyLoad.checked;
const useDelayed = delayedLoad.checked && useLazy;
let opened = 0; let opened = 0;
for (const url of urls) { for (let i = 0; i < urls.length; i++) {
const url = urls[i];
try { try {
let targetUrl = url; let targetUrl = url;
if (useLazy) { if (useLazy) {
// Build the extension loader URL with the target as ?url=… // Build the extension loader URL with the target as ?url=…
const loaderBase = chrome.runtime.getURL('loader.html'); const loaderBase = chrome.runtime.getURL('loader.html');
targetUrl = `${loaderBase}?url=${encodeURIComponent(url)}`; const params = new URLSearchParams({ url });
if (useDelayed) {
// 1-based delay: first tab = 1s, second = 2s, …
params.set('load_delay', i + 1);
}
targetUrl = `${loaderBase}?${params.toString()}`;
} }
await chrome.tabs.create({ url: targetUrl, active: false }); await chrome.tabs.create({ url: targetUrl, active: false });