refactor ciagl dalszy

This commit is contained in:
Mateusz Gruszczyński
2025-08-29 10:46:50 +02:00
parent 01b8ff656e
commit bc45c91d92
15 changed files with 1592 additions and 1492 deletions

View File

@@ -1,292 +1,152 @@
<!DOCTYPE html>
<html lang="en">
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hosts Converter</title>
<style>
:root {
--bg-color: #1a1a1a;
--card-bg: #2d2d2d;
--text-color: #e0e0e0;
--accent: #007bff;
--accent-light: #4da6ff;
--border-color: #404040;
--link-color: #4da6ff;
}
[data-theme="light"] {
--bg-color: #f5f5f5;
--card-bg: #ffffff;
--text-color: #333333;
--border-color: #dddddd;
--link-color: #0066cc;
--accent: #0066cc;
--accent-light: #007bff;
}
* {
transition: background-color 0.3s, color 0.3s;
}
body {
font-family: 'Segoe UI', system-ui, sans-serif;
background-color: var(--bg-color);
color: var(--text-color);
max-width: 800px;
margin: 20px auto;
padding: 20px;
line-height: 1.6;
display: flex;
flex-direction: column;
min-height: 100vh;
}
.theme-toggle {
position: fixed;
top: 20px;
right: 20px;
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 20px;
padding: 8px 15px;
cursor: pointer;
color: var(--text-color);
}
h1 {
color: var(--accent);
margin-bottom: 30px;
text-align: center;
}
form {
background: var(--card-bg);
padding: 25px;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
flex: 1;
}
.form-group {
margin: 15px 0;
padding: 0 15px;
}
input[type="text"] {
width: calc(100% - 30px);
padding: 10px 15px;
margin: 8px 0;
background: var(--bg-color);
border: 1px solid var(--border-color);
border-radius: 6px;
color: var(--text-color);
}
button {
background: linear-gradient(135deg, var(--accent), var(--accent-light));
color: white;
padding: 12px 25px;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
margin: 0 15px;
}
button:hover {
opacity: 0.9;
}
.result-box {
background: var(--card-bg);
padding: 20px;
border-radius: 12px;
margin: 25px 15px;
border: 1px solid var(--border-color);
}
.recent-links {
margin: 35px 15px 0;
padding: 25px 15px 0;
border-top: 1px solid var(--border-color);
}
.link-item {
background: var(--card-bg);
padding: 15px;
margin: 12px 0;
border-radius: 8px;
border: 1px solid var(--border-color);
}
.link-item:hover {
transform: translateX(5px);
transition: transform 0.2s;
}
.timestamp {
color: #888;
font-size: 0.85em;
}
a {
color: var(--link-color);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
footer {
text-align: center;
margin-top: 40px;
padding: 20px;
border-top: 1px solid var(--border-color);
color: #888;
}
footer a {
color: var(--link-color);
text-decoration: none;
}
footer a:hover {
text-decoration: underline;
}
@media (max-width: 768px) {
body {
padding: 15px;
margin: 10px;
}
form {
padding: 15px 0;
}
.form-group {
padding: 0 10px;
}
input[type="text"] {
width: calc(100% - 20px);
padding: 10px;
}
button {
width: calc(100% - 20px);
padding: 15px;
margin: 0 10px;
}
.result-box {
margin: 25px 10px;
padding: 15px;
}
.recent-links {
margin: 35px 10px 0;
padding: 25px 10px 0;
}
}
.copy-btn {
position: relative;
}
.copy-btn::after {
content: "Copied!";
position: absolute;
background: var(--card-bg);
color: var(--text-color);
padding: 5px 10px;
border-radius: 4px;
right: -80px;
top: 50%;
transform: translateY(-50%);
opacity: 0;
transition: opacity 0.3s;
}
.copy-btn.copied::after {
opacity: 1;
}
</style>
<meta name="theme-color" content="#0f1115" />
<link rel="preload" href="{{ url_for('static', filename='css/main.css') }}" as="style">
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
</head>
<body data-theme="dark">
<button class="theme-toggle" onclick="toggleTheme()">🌓 Toggle Theme</button>
<h1>Hosts File Converter</h1>
<form method="GET" action="/">
<div class="form-group">
<label>URL to hosts file:</label>
<input type="text" name="url" required
placeholder="ex. https://paulgb.github.io/BarbBlock/blacklists/hosts-file.txt">
<body>
<header class="site-header">
<div class="brand">
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">
<path d="M4 4h16v4H4zM4 10h10v4H4zM4 16h16v4H4z" fill="currentColor" />
</svg>
<span>Hosts Converter</span>
</div>
<nav class="actions">
<button class="btn ghost" type="button" data-action="toggle-theme" aria-label="Toggle theme">🌓</button>
<a class="btn primary" href="https://www.linuxiarz.pl" target="_blank" rel="noopener">linuxiarz.pl</a>
</nav>
</header>
<div class="form-group">
<label>Target IP:</label>
<input type="text" name="ip" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
value="195.187.6.34" required>
</div>
<button type="submit">Generate convert link</button>
</form>
{% if generated_link %}
<div class="result-box">
<h3>Link to MikroTik/Adguard:</h3>
<input type="text" value="{{ generated_link }}" readonly>
<button class="copy-btn" onclick="copyToClipboard(this)">Copy link</button>
</div>
{% endif %}
<div class="recent-links">
<h3>Last converts:</h3>
{% if recent_links %}
{% for link_data in recent_links %}
<div class="link-item">
<div class="timestamp">{{ link_data[0]|datetimeformat }}</div>
<a href="/convert?url={{ link_data[1]|urlencode }}&ip={{ link_data[2] }}" target="_blank">
{{ link_data[1] }} → {{ link_data[2] }}
</a>
<main class="container">
<section class="card hero">
<div class="hero-text">
<h1>Convert adblock lists to MikroTik / hosts</h1>
<p class="muted">Paste a list URL (AdGuard/uBlock/hosts/dnsmasq), pick the target IP, and generate a
<kbd>/convert</kbd> link.
</p>
</div>
{% endfor %}
{% else %}
<p>Empty..</p>
{% endif %}
</div>
<div class="hero-cta">
<a class="btn primary large" href="#form">Start</a>
</div>
</section>
<footer>
&copy; 2025 <a href="https://www.linuxiarz.pl" target="_blank">linuxiarz.pl</a> - All rights reserved <br>
Your IP address: <strong>{{ client_ip }}</strong> | Your User Agent: <strong>{{ user_agent }}</strong>
<section id="form" class="card form-card" aria-labelledby="form-title">
<h2 id="form-title">Link generator</h2>
<form method="GET" action="/" novalidate>
<div class="grid">
<div class="form-group col-12">
<label for="url-input">URL to hosts/adblock list</label>
<input id="url-input" type="url" name="url" required placeholder="https://example.com/list.txt"
inputmode="url" autocomplete="url" aria-describedby="url-help" autofocus>
<small id="url-help" class="hint"> Supported formats: <code>||domain^</code>,
<code>address=/domain/</code>, hosts files, plain domains.</small>
<div class="error" data-error-for="url-input"></div>
</div>
<div class="form-group col-6">
<label for="ip-input">Target IP</label>
<input id="ip-input" type="text" name="ip" pattern="^\d{1,3}(?:\.\d{1,3}){3}$"
value="195.187.6.34" required inputmode="numeric" autocomplete="off"
aria-describedby="ip-help">
<small id="ip-help" class="hint">Common choices: <code>0.0.0.0</code>, <code>127.0.0.1</code>,
or your device IP.</small>
<div class="error" data-error-for="ip-input"></div>
</div>
<div class="form-group col-6">
<label for="ip-preset">Presets</label>
<select id="ip-preset" class="select">
<option value="">— choose preset —</option>
<option value="0.0.0.0">0.0.0.0 (blackhole)</option>
<option value="127.0.0.1">127.0.0.1 (localhost)</option>
<option value="195.187.6.34">195.187.6.34 (current)</option>
<option value="custom">Custom…</option>
</select>
</div>
<div class="form-actions col-12">
<button type="submit" class="btn primary">Generate convert link</button>
<button class="btn ghost" type="button" data-action="clear">Clear</button>
</div>
</div>
</form>
<div class="result-box" data-state="empty" aria-live="polite" aria-atomic="true">
<div class="result-row">
<input id="generated-link" type="text" value="{{ generated_link or '' }}" readonly
placeholder="Link will appear here…">
<div class="result-buttons">
<button class="btn" type="button" data-action="copy" data-target="#generated-link">Copy</button>
<a class="btn outline" id="open-link" href="{{ generated_link or '#' }}" target="_blank"
rel="noopener" aria-disabled="{{ 'false' if generated_link else 'true' }}">Open</a>
</div>
</div>
<small class="hint">The preview updates live while you type.</small>
</div>
</section>
<section class="card recent-card">
<div class="section-head">
<h2>Recent converts</h2>
<div class="head-actions">
<button class="btn ghost" type="button" data-action="collapse" aria-expanded="false"
aria-controls="recent-list">Expand</button>
</div>
</div>
<div id="recent-list" class="recent-list" style="display:none">
{% if recent_links %}
{% for link_data in recent_links %}
<article class="link-item">
<div class="link-main">
<a class="mono ellipsis" title="{{ link_data[1] }}"
href="/convert?url={{ link_data[1]|urlencode }}&ip={{ link_data[2] }}" target="_blank"
rel="noopener">
{{ link_data[1] }}
</a>
<span class="arrow"></span>
<span class="mono ellipsis" title="{{ link_data[2] }}">{{ link_data[2] }}</span>
</div>
<div class="link-meta">
<span class="timestamp">{{ link_data[0]|datetimeformat }}</span>
<div class="link-actions">
<button class="btn tiny" type="button" data-action="copy-text"
data-text="/convert?url={{ link_data[1]|urlencode }}&ip={{ link_data[2] }}">Copy</button>
<a class="btn tiny outline"
href="/convert?url={{ link_data[1]|urlencode }}&ip={{ link_data[2] }}" target="_blank"
rel="noopener">Open</a>
</div>
</div>
</article>
{% endfor %}
{% else %}
<p class="muted">Empty..</p>
{% endif %}
</div>
</section>
</main>
<footer class="site-footer">
<div>&copy; 2025 <a href="https://www.linuxiarz.pl" target="_blank" rel="noopener">linuxiarz.pl</a> · All rights
reserved</div>
<div class="meta">Your IP: <strong>{{ client_ip }}</strong> · UA: <strong>{{ user_agent }}</strong></div>
</footer>
<div id="toast" role="status" aria-live="polite" aria-atomic="true"></div>
<script defer src="{{ url_for('static', filename='js/main.js') }}"></script>
<script>
function toggleTheme() {
const body = document.body;
body.setAttribute('data-theme',
body.getAttribute('data-theme') === 'dark' ? 'light' : 'dark');
localStorage.setItem('theme', body.getAttribute('data-theme'));
}
function copyToClipboard(btn) {
const copyText = document.querySelector("input[readonly]");
copyText.select();
document.execCommand("copy");
btn.classList.add('copied');
setTimeout(() => btn.classList.remove('copied'), 2000);
}
// Load saved theme
const savedTheme = localStorage.getItem('theme') || 'dark';
document.body.setAttribute('data-theme', savedTheme);
// no-flash theme bootstrap
(function () { const t = localStorage.getItem('theme') || 'dark'; document.documentElement.setAttribute('data-theme', t); })();
</script>
</body>
</html>
</html>