Files

435 lines
11 KiB
HTML
Raw Permalink Normal View History

2026-05-26 11:26:37 -03:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>URL Launcher</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600&family=Syne:wght@400;700;800&display=swap');
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--bg: #0d0d0f;
--surface: #16161a;
--border: #2a2a32;
--accent: #7fff6e;
--accent-dim:#3a7a33;
--text: #e8e8ec;
--muted: #6b6b7a;
--danger: #ff6b6b;
--radius: 6px;
}
body {
width: 600px;
/*min-height: 400px;*/
2026-05-26 11:26:37 -03:00
background: var(--bg);
color: var(--text);
font-family: 'Syne', sans-serif;
padding: 0;
overflow: hidden;
}
/* ── Header ── */
.header {
display: flex;
align-items: center;
gap: 10px;
padding: 16px 18px 14px;
border-bottom: 1px solid var(--border);
background: var(--surface);
}
.logo {
width: 28px;
height: 28px;
background: var(--accent);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.logo svg {
width: 16px;
height: 16px;
fill: var(--bg);
}
.title {
font-size: 15px;
font-weight: 800;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--text);
}
.subtitle {
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
color: var(--muted);
margin-left: auto;
}
/* ── Body ── */
.body {
padding: 16px 18px;
display: flex;
flex-direction: column;
gap: 14px;
}
/* ── Textarea ── */
.textarea-wrap {
position: relative;
}
textarea {
width: 100%;
height: 190px;
2026-05-26 11:26:37 -03:00
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text);
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
line-height: 1.7;
padding: 10px 12px;
resize: vertical;
outline: none;
transition: border-color 0.15s;
caret-color: var(--accent);
}
textarea::placeholder {
color: var(--muted);
}
textarea:focus {
border-color: var(--accent-dim);
}
.url-count {
position: absolute;
bottom: 8px;
right: 10px;
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
color: var(--muted);
pointer-events: none;
transition: color 0.15s;
}
.url-count.has-urls {
color: var(--accent);
}
/* ── Options row ── */
.options {
display: flex;
align-items: center;
gap: 10px;
}
.checkbox-label {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
user-select: none;
flex: 1;
}
.checkbox-label input[type="checkbox"] {
display: none;
}
.custom-checkbox {
width: 16px;
height: 16px;
border: 1.5px solid var(--border);
border-radius: 3px;
background: var(--surface);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: border-color 0.15s, background 0.15s;
}
.checkbox-label input[type="checkbox"]:checked + .custom-checkbox {
background: var(--accent);
border-color: var(--accent);
}
.custom-checkbox svg {
display: none;
width: 10px;
height: 10px;
}
.checkbox-label input[type="checkbox"]:checked + .custom-checkbox svg {
display: block;
}
.checkbox-text {
font-size: 12px;
color: var(--muted);
line-height: 1;
}
.checkbox-label:hover .checkbox-text {
color: var(--text);
}
/* ── Button ── */
.launch-btn {
background: var(--accent);
color: var(--bg);
border: none;
border-radius: var(--radius);
font-family: 'Syne', sans-serif;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
padding: 9px 18px;
cursor: pointer;
white-space: nowrap;
transition: opacity 0.15s, transform 0.1s;
display: flex;
align-items: center;
gap: 6px;
}
.launch-btn:hover:not(:disabled) {
opacity: 0.88;
}
.launch-btn:active:not(:disabled) {
transform: scale(0.97);
}
.launch-btn:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.launch-btn svg {
width: 13px;
height: 13px;
fill: var(--bg);
}
/* ── Status bar ── */
.status {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
color: var(--muted);
min-height: 16px;
display: flex;
align-items: center;
gap: 6px;
}
.status.success { color: var(--accent); }
.status.error { color: var(--danger); }
.status-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: currentColor;
flex-shrink: 0;
}
/* ── Toolbar above textarea ── */
.textarea-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 6px;
}
.textarea-label {
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
}
.extract-btn {
display: flex;
align-items: center;
gap: 5px;
background: transparent;
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--muted);
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
letter-spacing: 0.05em;
padding: 4px 9px;
cursor: pointer;
transition: border-color 0.15s, color 0.15s, background 0.15s;
white-space: nowrap;
}
.extract-btn svg {
width: 11px;
height: 11px;
flex-shrink: 0;
transition: stroke 0.15s;
}
.extract-btn:hover {
border-color: var(--accent-dim);
color: var(--accent);
background: rgba(127,255,110,0.05);
}
.extract-btn:active {
transform: scale(0.96);
}
.extract-btn.flash {
border-color: var(--accent);
color: var(--accent);
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;
}
2026-05-26 11:26:37 -03:00
/* ── Focus mode indicator ── */
.mode-badge {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 3px 8px;
border-radius: 100px;
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
font-weight: 600;
letter-spacing: 0.03em;
background: rgba(127,255,110,0.08);
border: 1px solid var(--accent-dim);
color: var(--accent);
transition: opacity 0.2s;
}
.mode-badge.off {
background: rgba(107,107,122,0.12);
border-color: var(--border);
color: var(--muted);
}
.mode-badge::before {
content: '';
width: 5px;
height: 5px;
border-radius: 50%;
background: currentColor;
}
</style>
</head>
<body>
<div class="header">
<div class="logo">
<!-- Tab icon -->
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<rect x="1" y="4" width="14" height="10" rx="1.5"/>
<rect x="1" y="1" width="6" height="4" rx="1"/>
</svg>
</div>
<span class="title">URL Launcher</span>
<span class="subtitle" id="modeBadge">
<span class="mode-badge" id="modeBadgeInner">lazy</span>
</span>
</div>
<div class="body">
<div class="textarea-toolbar">
<span class="textarea-label">URLs / Text</span>
<button class="extract-btn" id="extractBtn" title="Extract all URLs from pasted text">
<svg viewBox="0 0 11 11" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round">
<path d="M4.5 2.5H3a2 2 0 0 0 0 4h1.5"/>
<path d="M6.5 2.5H8a2 2 0 0 1 0 4H6.5"/>
<line x1="3.5" y1="4.5" x2="7.5" y2="4.5"/>
</svg>
Extract URLs
</button>
</div>
<div class="textarea-wrap">
<textarea
id="urlInput"
placeholder="Paste any text here — emails, docs, HTML, markdown…&#10;Hit 'Extract URLs' to pull out links automatically.&#10;&#10;Or just type one URL per line:&#10;https://example.com&#10;https://github.com"
spellcheck="false"
autocomplete="off"
></textarea>
<span class="url-count" id="urlCount">0 URLs</span>
</div>
<div class="options">
<div class="checkboxes">
<label class="checkbox-label" title="Each URL opens via an intermediate page and only navigates when you focus that tab">
<input type="checkbox" id="lazyLoad" 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">Wait for focus to load</span>
</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>
2026-05-26 11:26:37 -03:00
<button class="launch-btn" id="openBtn" disabled>
<svg viewBox="0 0 13 13" xmlns="http://www.w3.org/2000/svg">
<path d="M2 6.5h9M7.5 3l4 3.5-4 3.5" stroke="#0d0d0f" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
</svg>
Open URLs
</button>
</div>
<div class="status" id="status"></div>
</div>
<script src="popup.js"></script>
</body>
</html>