v0.6.0: Sobors.hu parser, HTTP auth, recipe validation, UI polish

- New sobors.hu parser with ingredient groups and section headers
- Incomplete recipe warnings (missing ingredients/instructions)
- Optional HTTP Basic Auth (configurable on settings page)
- Brand text: "Recept" in white, "Importáló" in blue
- Larger logo (36px), favicon using logo_notext.svg

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 18:07:05 +01:00
parent 76290770f4
commit a0bcb62588
7 changed files with 237 additions and 12 deletions
+5 -3
View File
@@ -7,6 +7,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="icon" type="image/svg+xml" href="/assets/logo_notext.svg">
<style>
:root {
--bg: #0d1117;
@@ -53,11 +54,12 @@
gap: 0.6rem;
font-size: 1.25rem;
font-weight: 700;
color: var(--accent-light);
text-decoration: none;
}
nav .brand .brand-white { color: var(--text); }
nav .brand .brand-blue { color: var(--accent-light); }
nav .brand img {
height: 28px;
height: 36px;
width: auto;
}
nav a {
@@ -212,7 +214,7 @@
<nav>
<a href="/" class="brand">
<img src="/assets/logo.svg" alt="felhom.eu">
Recept Importáló
<span class="brand-white">Recept</span> <span class="brand-blue">Importáló</span>
</a>
<a href="/import" {% if request.path == '/import' %}class="active"{% endif %}>Importálás</a>
<a href="/settings" {% if request.path == '/settings' %}class="active"{% endif %}>Beállítások</a>
+26 -7
View File
@@ -561,17 +561,29 @@ async function scrapeRecipe() {
showSingleButtons();
document.getElementById('previewCard').classList.add('visible');
const warnings = [];
const statusParts = [];
// Completeness warnings (missing ingredients/instructions)
if (data.warnings && data.warnings.length > 0) {
statusParts.push('<span class="text-warning">&#9888; ' + data.warnings.map(escHtml).join(' | ') + '</span>');
}
// Duplicate warnings
const dupWarnings = [];
if (data.duplicate) {
warnings.push('Mealie: <a href="' + escHtml(data.duplicate.url) + '" target="_blank" style="color:var(--accent)">'
dupWarnings.push('Mealie: <a href="' + escHtml(data.duplicate.url) + '" target="_blank" style="color:var(--accent)">'
+ escHtml(data.duplicate.name) + '</a>');
}
if (data.tandoor_duplicate) {
warnings.push('Tandoor: <a href="' + escHtml(data.tandoor_duplicate.url) + '" target="_blank" style="color:var(--accent)">'
dupWarnings.push('Tandoor: <a href="' + escHtml(data.tandoor_duplicate.url) + '" target="_blank" style="color:var(--accent)">'
+ escHtml(data.tandoor_duplicate.name) + '</a>');
}
if (warnings.length > 0) {
status.innerHTML = '<span class="text-warning">&#9888; Ez a recept már létezik: ' + warnings.join(' | ') + '</span>';
if (dupWarnings.length > 0) {
statusParts.push('<span class="text-warning">&#9888; Ez a recept már létezik: ' + dupWarnings.join(' | ') + '</span>');
}
if (statusParts.length > 0) {
status.innerHTML = statusParts.join('<br>');
} else {
status.innerHTML = '<span class="text-success">&#10003; Beolvasva</span>';
}
@@ -1143,8 +1155,12 @@ async function scrapeForBulk(idx) {
document.getElementById('previewCard').classList.add('visible');
document.getElementById('previewCard').scrollIntoView({ behavior: 'smooth' });
// Show duplicate warning in bulk status
// Show warnings in bulk status
const bulkStatus = document.getElementById('bulkSendStatus');
const bulkStatusParts = [];
if (data.warnings && data.warnings.length > 0) {
bulkStatusParts.push('&#9888; ' + data.warnings.map(escHtml).join(' | '));
}
const dupWarnings = [];
if (data.duplicate && (bulkState.target === 'mealie' || bulkState.target === 'both')) {
dupWarnings.push('Mealie: ' + escHtml(data.duplicate.name));
@@ -1153,7 +1169,10 @@ async function scrapeForBulk(idx) {
dupWarnings.push('Tandoor: ' + escHtml(data.tandoor_duplicate.name));
}
if (dupWarnings.length > 0) {
bulkStatus.innerHTML = '<span class="text-warning" style="font-size:0.85rem">&#9888; Duplikátum: ' + dupWarnings.join(' | ') + '</span>';
bulkStatusParts.push('&#9888; Duplikátum: ' + dupWarnings.join(' | '));
}
if (bulkStatusParts.length > 0) {
bulkStatus.innerHTML = '<span class="text-warning" style="font-size:0.85rem">' + bulkStatusParts.join('<br>') + '</span>';
} else {
bulkStatus.innerHTML = '';
}
+26
View File
@@ -90,6 +90,32 @@
</div>
</div>
<div class="card">
<h2>Hozzáférés-védelem</h2>
<p class="text-dim mb-2" style="font-size:0.85rem;">
HTTP Basic Auth bekapcsolásával jelszóval védheted az alkalmazást.
Hagyd üresen a kikapcsoláshoz.
</p>
<label for="auth_username">Felhasználónév</label>
<input type="text" id="auth_username" name="auth_username"
value="{{ cfg.auth_username or '' }}"
placeholder="admin" autocomplete="username">
<label for="auth_password">Jelszó</label>
<input type="password" id="auth_password" name="auth_password"
value="" placeholder="{% if cfg.auth_password_hash %}(nem változott){% else %}Jelszó megadása{% endif %}"
autocomplete="new-password">
<p class="text-dim mb-2" style="font-size:0.85rem;">
{% if cfg.auth_password_hash %}
A védelem aktív. Új jelszó megadásával frissítheted, üresen hagyva marad a jelenlegi.
A felhasználónév törlésével kikapcsolhatod a védelmet.
{% else %}
Jelenleg nincs védelem beállítva.
{% endif %}
</p>
</div>
<div class="card">
<button type="submit" class="btn btn-primary">Mentés</button>
</div>