Merge branch 'ui/restyling': login restyle, navbar macros, new brand icon

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-11 16:09:21 +00:00
11 changed files with 283 additions and 371 deletions
+2
View File
@@ -1,6 +1,7 @@
"""TieMeasureFlow Client - Flask Entry Point."""
import json
import os
from datetime import date
from urllib.parse import urlparse
from flask import Flask, redirect, url_for, session, request
@@ -101,6 +102,7 @@ def create_app() -> Flask:
"languages": Config.LANGUAGES,
"company_logo": session.get("company_logo"),
"auto_logout_minutes": session.get("auto_logout_minutes"),
"current_year": date.today().year,
}
return app
@@ -69,6 +69,23 @@
}
/* ============================================================
Brand details
============================================================ */
:root {
accent-color: var(--color-primary);
}
::selection {
background: rgba(37, 99, 235, 0.2);
}
.dark ::selection {
background: rgba(96, 165, 250, 0.3);
}
/* ============================================================
Global Transitions
============================================================ */
@@ -151,6 +168,7 @@ textarea:focus-visible {
.tmf-card:hover {
box-shadow: var(--shadow-md);
border-color: var(--scrollbar-thumb);
}
.tmf-card-header {
@@ -250,11 +268,21 @@ textarea:focus-visible {
border: 1px solid transparent;
}
.btn:active:not(:disabled) {
transform: scale(0.97);
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn-lg {
padding: 0.75rem 1.5rem;
font-size: 1rem;
border-radius: 0.625rem;
}
.btn-primary {
background: var(--color-primary);
color: #FFFFFF;
@@ -1,27 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
<!-- Stylized Caliper Icon for Favicon -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<!-- TieMeasureFlow brand mark: measurement span glyph on brand-blue badge -->
<defs>
<linearGradient id="tmfBadge" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#3B82F6"/>
<stop offset="1" stop-color="#1D4ED8"/>
</linearGradient>
</defs>
<!-- Caliper outer frame -->
<rect x="2" y="3" width="5" height="26" rx="1.5" fill="#2563EB"/>
<rect x="2" y="3" width="19" height="5" rx="1.5" fill="#2563EB"/>
<rect x="2" y="24" width="19" height="5" rx="1.5" fill="#2563EB"/>
<!-- Badge -->
<rect x="2" y="2" width="60" height="60" rx="15" fill="url(#tmfBadge)"/>
<!-- Sliding jaw -->
<rect x="12" y="8" width="4.5" height="6.5" rx="1" fill="#1E40AF"/>
<rect x="12" y="17.5" width="4.5" height="6.5" rx="1" fill="#1E40AF"/>
<!-- Measurement end bars -->
<rect x="14" y="16" width="5" height="32" rx="2.5" fill="#FFFFFF"/>
<rect x="45" y="16" width="5" height="32" rx="2.5" fill="#FFFFFF"/>
<!-- Depth rod -->
<rect x="4" y="14" width="12" height="3.5" rx="1" fill="#3B82F6" opacity="0.55"/>
<!-- Scale markings -->
<rect x="8" y="5" width="1" height="2.5" rx="0.5" fill="#FFFFFF" opacity="0.65"/>
<rect x="11" y="5" width="1" height="2.5" rx="0.5" fill="#FFFFFF" opacity="0.65"/>
<rect x="14" y="5" width="1" height="2.5" rx="0.5" fill="#FFFFFF" opacity="0.65"/>
<rect x="17" y="5" width="1" height="2.5" rx="0.5" fill="#FFFFFF" opacity="0.65"/>
<!-- Flow arrow -->
<path d="M22 16 C25 16, 26.5 11, 29 11"
stroke="#3B82F6" stroke-width="2.2" stroke-linecap="round" fill="none"/>
<path d="M27 8.5 L29.5 11 L27 13.5"
stroke="#3B82F6" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
<!-- Double-headed arrow (measured span) -->
<path d="M24 32 H40" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
<path d="M28 26.5 L22.5 32 L28 37.5" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M36 26.5 L41.5 32 L36 37.5" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 997 B

@@ -1,41 +1,23 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 44" fill="none">
<!-- Stylized Caliper Icon -->
<g transform="translate(2, 2)">
<!-- Caliper outer frame -->
<rect x="0" y="4" width="6" height="32" rx="1.5" fill="#2563EB"/>
<rect x="0" y="4" width="24" height="6" rx="1.5" fill="#2563EB"/>
<rect x="0" y="30" width="24" height="6" rx="1.5" fill="#2563EB"/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 340 64" fill="none">
<!-- TieMeasureFlow full logo: brand badge + wordmark (standalone asset) -->
<defs>
<linearGradient id="tmfBadgeFull" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#3B82F6"/>
<stop offset="1" stop-color="#1D4ED8"/>
</linearGradient>
</defs>
<!-- Caliper sliding jaw -->
<rect x="14" y="10" width="5" height="8" rx="1" fill="#1E40AF"/>
<rect x="14" y="22" width="5" height="8" rx="1" fill="#1E40AF"/>
<!-- Badge -->
<rect x="2" y="2" width="60" height="60" rx="15" fill="url(#tmfBadgeFull)"/>
<rect x="14" y="16" width="5" height="32" rx="2.5" fill="#FFFFFF"/>
<rect x="45" y="16" width="5" height="32" rx="2.5" fill="#FFFFFF"/>
<path d="M24 32 H40" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
<path d="M28 26.5 L22.5 32 L28 37.5" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M36 26.5 L41.5 32 L36 37.5" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<!-- Caliper depth rod -->
<rect x="2" y="18" width="16" height="4" rx="1" fill="#3B82F6" opacity="0.6"/>
<!-- Scale markings -->
<rect x="7" y="7" width="1" height="3" rx="0.5" fill="#FFFFFF" opacity="0.7"/>
<rect x="10" y="7" width="1" height="3" rx="0.5" fill="#FFFFFF" opacity="0.7"/>
<rect x="13" y="7" width="1" height="3" rx="0.5" fill="#FFFFFF" opacity="0.7"/>
<rect x="16" y="7" width="1" height="3" rx="0.5" fill="#FFFFFF" opacity="0.7"/>
<rect x="19" y="7" width="1" height="3" rx="0.5" fill="#FFFFFF" opacity="0.7"/>
<!-- Flow arrow (smooth curve) -->
<path d="M26 20 C30 20, 32 14, 36 14 C40 14, 40 20, 36 20"
stroke="#2563EB" stroke-width="2.5" stroke-linecap="round" fill="none"/>
<path d="M34 17 L37 20 L34 23" stroke="#2563EB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
</g>
<!-- Text: TieMeasureFlow -->
<g transform="translate(48, 0)">
<!-- "Tie" in bold primary -->
<text x="0" y="28" font-family="Inter, system-ui, sans-serif" font-size="20" font-weight="700" fill="#2563EB"
letter-spacing="-0.5">Tie</text>
<!-- "Measure" in medium dark -->
<text x="32" y="28" font-family="Inter, system-ui, sans-serif" font-size="20" font-weight="500" fill="#1E40AF"
letter-spacing="-0.5">Measure</text>
<!-- "Flow" in bold primary -->
<text x="120" y="28" font-family="Inter, system-ui, sans-serif" font-size="20" font-weight="700" fill="#2563EB"
letter-spacing="-0.5">Flow</text>
</g>
<!-- Wordmark: single text element with flowing tspans (cannot be clipped/overlap) -->
<text x="76" y="42" font-family="Inter, system-ui, -apple-system, sans-serif"
font-size="30" letter-spacing="-0.5" fill="#0F172A">
<tspan font-weight="700">Tie</tspan><tspan font-weight="600" fill="#2563EB">Measure</tspan><tspan font-weight="700">Flow</tspan>
</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -2,17 +2,26 @@
{% block title %}Login — TieMeasureFlow{% endblock %}
{% block content %}
<div class="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800 px-4 sm:px-6 lg:px-8">
<div class="max-w-md w-full space-y-8">
<div class="relative min-h-screen flex items-center justify-center overflow-hidden bg-[var(--bg-primary)] px-4 sm:px-6 lg:px-8">
<!-- Decorative brand background -->
<div class="pointer-events-none absolute inset-0" aria-hidden="true">
<div class="absolute -top-32 -left-32 w-96 h-96 rounded-full bg-primary-500/10 dark:bg-primary-400/10 blur-3xl"></div>
<div class="absolute -bottom-40 -right-24 w-[28rem] h-[28rem] rounded-full bg-primary-600/10 dark:bg-primary-500/10 blur-3xl"></div>
</div>
<div class="relative max-w-md w-full space-y-6">
<!-- Card -->
<div class="bg-white dark:bg-slate-800 shadow-lg rounded-xl p-8">
<div class="bg-[var(--bg-card)] border border-[var(--border-color)] shadow-lg rounded-2xl p-8">
<!-- Logo -->
<div class="text-center mb-8">
<div class="mx-auto mb-4 inline-flex justify-center text-slate-900 dark:text-white">
{% set logo_class = 'h-16 w-auto' %}
{% set logo_class = 'h-14 w-14' %}
{% set wordmark_class = 'text-3xl' %}
{% set logo_id = 'login' %}
{% include 'components/_app_logo.html' %}
</div>
<p class="text-sm text-slate-600 dark:text-slate-400">
<p class="text-sm text-[var(--text-secondary)]">
{{ _('Accedi al sistema') }}
</p>
</div>
@@ -22,12 +31,12 @@
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<!-- Username -->
<div>
<label for="username" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
<label for="username" class="tmf-label">
{{ _('Username') }}
</label>
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="h-5 w-5 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg class="h-5 w-5 text-[var(--text-muted)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
</div>
@@ -36,36 +45,52 @@
name="username"
required
autofocus
autocomplete="username"
placeholder="{{ _('Username') }}"
class="block w-full pl-10 pr-3 py-2.5 border border-slate-300 dark:border-slate-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 dark:focus:ring-primary-400 dark:focus:border-primary-400 bg-white dark:bg-slate-700 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-500 transition-colors">
class="tmf-input !pl-10 !py-2.5">
</div>
</div>
<!-- Password -->
<div>
<label for="password" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
<div x-data="{ show: false }">
<label for="password" class="tmf-label">
{{ _('Password') }}
</label>
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="h-5 w-5 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg class="h-5 w-5 text-[var(--text-muted)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
</div>
<input type="password"
<input :type="show ? 'text' : 'password'"
type="password"
id="password"
name="password"
required
autocomplete="current-password"
placeholder="{{ _('Password') }}"
class="block w-full pl-10 pr-3 py-2.5 border border-slate-300 dark:border-slate-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 dark:focus:ring-primary-400 dark:focus:border-primary-400 bg-white dark:bg-slate-700 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-500 transition-colors">
class="tmf-input !pl-10 !pr-12 !py-2.5">
<button type="button"
@click="show = !show"
:aria-label="show ? {{ _('Nascondi password')|tojson_attr }} : {{ _('Mostra password')|tojson_attr }}"
class="absolute inset-y-0 right-0 px-3 flex items-center text-[var(--text-muted)] hover:text-[var(--text-secondary)] transition-colors">
<!-- Eye (password hidden, click to show) -->
<svg x-show="!show" class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
<!-- Eye slash (password visible, click to hide) -->
<svg x-show="show" x-cloak class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 001.934 12c1.292 4.338 5.31 7.5 10.066 7.5.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88"/>
</svg>
</button>
</div>
</div>
<!-- Submit Button -->
<div>
<button type="submit"
class="w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-sm text-sm font-semibold text-white bg-primary-600 hover:bg-primary-700 dark:bg-primary-500 dark:hover:bg-primary-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-all duration-200">
<svg class="h-5 w-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<button type="submit" class="btn btn-primary btn-lg w-full shadow-sm">
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
</svg>
{{ _('Accedi') }}
@@ -75,7 +100,7 @@
<!-- Help Text -->
<div class="mt-6 text-center">
<p class="text-xs text-slate-500 dark:text-slate-400">
<p class="text-xs text-[var(--text-muted)]">
{{ _('Hai dimenticato la password?') }}
<br>
{{ _('Contatta l\'amministratore') }}
@@ -84,8 +109,8 @@
</div>
<!-- Footer -->
<div class="text-center text-xs text-slate-500 dark:text-slate-400">
<p>TieMeasureFlow &copy; 2025 - {{ _('Sistema di misurazione industriale') }}</p>
<div class="text-center text-xs text-[var(--text-muted)]">
<p>TieMeasureFlow &copy; {{ current_year }} - {{ _('Sistema di misurazione industriale') }}</p>
</div>
</div>
</div>
@@ -1,35 +1,33 @@
<!--
Inline TieMeasureFlow logo. Text fills use `currentColor`, so wrap with a
parent that sets `color` (e.g. `text-slate-900 dark:text-white`) to make the
wordmark adapt to the active theme. The caliper/flow icon keeps its brand
blue regardless of theme.
-->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 260 48" fill="none"
class="{{ logo_class|default('h-10 w-auto') }}"
aria-label="TieMeasureFlow">
<!-- Caliper + flow icon (always brand color) -->
<g transform="translate(2, 6)">
<rect x="0" y="4" width="6" height="32" rx="1.5" fill="#2563EB"/>
<rect x="0" y="4" width="24" height="6" rx="1.5" fill="#2563EB"/>
<rect x="0" y="30" width="24" height="6" rx="1.5" fill="#2563EB"/>
<rect x="14" y="10" width="5" height="8" rx="1" fill="#1E40AF"/>
<rect x="14" y="22" width="5" height="8" rx="1" fill="#1E40AF"/>
<rect x="2" y="18" width="16" height="4" rx="1" fill="#3B82F6" opacity="0.6"/>
<rect x="7" y="7" width="1" height="3" rx="0.5" fill="#FFFFFF" opacity="0.7"/>
<rect x="10" y="7" width="1" height="3" rx="0.5" fill="#FFFFFF" opacity="0.7"/>
<rect x="13" y="7" width="1" height="3" rx="0.5" fill="#FFFFFF" opacity="0.7"/>
<rect x="16" y="7" width="1" height="3" rx="0.5" fill="#FFFFFF" opacity="0.7"/>
<rect x="19" y="7" width="1" height="3" rx="0.5" fill="#FFFFFF" opacity="0.7"/>
<path d="M26 20 C30 20, 32 14, 36 14 C40 14, 40 20, 36 20"
stroke="#2563EB" stroke-width="2.5" stroke-linecap="round" fill="none"/>
<path d="M34 17 L37 20 L34 23"
stroke="#2563EB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
</g>
TieMeasureFlow logo: brand badge (SVG) + HTML wordmark.
The wordmark inherits `color` from the parent (set e.g. `text-slate-900
dark:text-white`); "Measure" keeps the brand blue.
<!-- Wordmark: themed via currentColor; "Measure" stays brand-tinted -->
<g transform="translate(52, 0)" font-family="Inter, system-ui, sans-serif" letter-spacing="-0.5">
<text x="0" y="34" font-size="28" font-weight="700" fill="currentColor">Tie</text>
<text x="44" y="34" font-size="28" font-weight="500" fill="#2563EB">Measure</text>
<text x="166" y="34" font-size="28" font-weight="700" fill="currentColor">Flow</text>
</g>
</svg>
Parameters (set before include):
logo_class — badge size, default 'h-10 w-10'
wordmark_class — wordmark text size, default 'text-xl'; '' hides the text
logo_id — unique suffix for the SVG gradient id when the logo
appears more than once per page (default 'tmf')
-->
{% set _logo_id = logo_id|default('tmf') %}
<span class="inline-flex items-center gap-2.5 select-none whitespace-nowrap">
<svg class="{{ logo_class|default('h-10 w-10') }} shrink-0" viewBox="0 0 64 64" fill="none"
xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<defs>
<linearGradient id="tmfBadge-{{ _logo_id }}" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#3B82F6"/>
<stop offset="1" stop-color="#1D4ED8"/>
</linearGradient>
</defs>
<rect x="2" y="2" width="60" height="60" rx="15" fill="url(#tmfBadge-{{ _logo_id }})"/>
<rect x="14" y="16" width="5" height="32" rx="2.5" fill="#FFFFFF"/>
<rect x="45" y="16" width="5" height="32" rx="2.5" fill="#FFFFFF"/>
<path d="M24 32 H40" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
<path d="M28 26.5 L22.5 32 L28 37.5" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M36 26.5 L41.5 32 L36 37.5" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
{% if wordmark_class is not defined or wordmark_class %}
<span class="{{ wordmark_class|default('text-xl') }} font-bold tracking-tight leading-none"
aria-label="TieMeasureFlow">Tie<span class="text-primary-600 dark:text-primary-400">Measure</span>Flow</span>
{% endif %}
</span>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -1,6 +1,45 @@
<!-- TieMeasureFlow Navbar -->
{# SVG path data for nav icons, shared between desktop and mobile menus #}
{% set icon_measure %}<path stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/>{% endset %}
{% set icon_recipes %}<path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>{% endset %}
{% set icon_stats %}<path stroke-linecap="round" stroke-linejoin="round" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>{% endset %}
{% set icon_users %}<path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z"/>{% endset %}
{% set icon_stations %}<path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 01-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0115 18.257V17.25m6-12V15a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 15V5.25m18 0A2.25 2.25 0 0018.75 3H5.25A2.25 2.25 0 003 5.25m18 0V12a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 12V5.25"/>{% endset %}
{% set icon_settings %}<path stroke-linecap="round" stroke-linejoin="round" d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.204-.107-.397.165-.71.505-.78.929l-.15.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.506-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>{% endset %}
{# Single nav link, desktop or mobile variant. `icon` is SVG path markup. #}
{% macro nav_link(href, label, icon, active=false, mobile=false) -%}
<a href="{{ href }}"
{% if active %}aria-current="page"{% endif %}
class="flex items-center {{ 'gap-3 px-3 py-2.5' if mobile else 'gap-2 px-3 py-2' }} rounded-lg text-sm font-medium transition-colors duration-200
{% if active %}text-primary bg-primary-50 dark:bg-primary-900/20{% else %}text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20{% endif %}">
<svg class="{{ 'w-5 h-5' if mobile else 'w-[18px] h-[18px]' }} shrink-0" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">{{ icon }}</svg>
<span>{{ label }}</span>
</a>
{%- endmacro %}
{# Render all role-gated nav links for the current user #}
{% macro nav_links(mobile=false) -%}
{% set ep = request.endpoint or '' %}
{% if current_user.get('roles') and 'MeasurementTec' in current_user.roles %}
{{ nav_link(url_for('measure.select_recipe'), _('Misure'), icon_measure, ep.startswith('measure.'), mobile) }}
{% endif %}
{% if current_user.get('roles') and 'Maker' in current_user.roles %}
{{ nav_link(url_for('maker.recipe_list'), _('Ricette'), icon_recipes, ep.startswith('maker.'), mobile) }}
{% endif %}
{% if current_user.get('roles') and 'Metrologist' in current_user.roles %}
{{ nav_link(url_for('statistics.dashboard'), _('Statistiche'), icon_stats, ep.startswith('statistics.'), mobile) }}
{% endif %}
{% if current_user.get('is_admin') %}
{{ nav_link(url_for('admin.user_list'), _('Utenti'), icon_users, ep == 'admin.user_list', mobile) }}
{{ nav_link(url_for('admin.station_list'), _('Stazioni'), icon_stations, ep == 'admin.station_list', mobile) }}
{{ nav_link(url_for('admin.settings_page'), _('Impostazioni'), icon_settings, ep == 'admin.settings_page', mobile) }}
{% endif %}
{%- endmacro %}
<nav class="sticky top-0 z-40 bg-[var(--bg-card)] border-b border-[var(--border-color)] shadow-sm transition-colors duration-300"
x-data="{ mobileOpen: false, userDropdown: false }">
x-data="{ mobileOpen: false }">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-14">
@@ -12,7 +51,9 @@
<img src="{{ url_for('static', filename='img/' ~ company_logo) }}" alt="Logo" class="h-10 w-auto"
onerror="this.style.display='none'">
{% else %}
{% set logo_class = 'h-10 w-auto' %}
{% set logo_class = 'h-9 w-9' %}
{% set wordmark_class = 'text-xl' %}
{% set logo_id = 'nav' %}
{% include 'components/_app_logo.html' %}
{% endif %}
</a>
@@ -21,103 +62,7 @@
<!-- Center: Navigation Links (Desktop) -->
{% if current_user %}
<div class="hidden md:flex items-center gap-1">
{# MeasurementTec: Misure #}
{% if current_user.get('roles') and 'MeasurementTec' in current_user.roles %}
<a href="{{ url_for('measure.select_recipe') }}"
class="nav-link group flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium
text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20
transition-colors duration-200
{% if request.endpoint and request.endpoint.startswith('measure.') %}
text-primary bg-primary-50 dark:bg-primary-900/20
{% endif %}">
<!-- Clipboard Icon -->
<svg class="w-4.5 h-4.5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/>
</svg>
<span>{{ _('Misure') }}</span>
</a>
{% endif %}
{# Maker: Ricette #}
{% if current_user.get('roles') and 'Maker' in current_user.roles %}
<a href="{{ url_for('maker.recipe_list') }}"
class="nav-link group flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium
text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20
transition-colors duration-200
{% if request.endpoint and request.endpoint.startswith('maker.') %}
text-primary bg-primary-50 dark:bg-primary-900/20
{% endif %}">
<!-- Edit/Pencil Icon -->
<svg class="w-4.5 h-4.5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
</svg>
<span>{{ _('Ricette') }}</span>
</a>
{% endif %}
{# Metrologist: Statistiche #}
{% if current_user.get('roles') and 'Metrologist' in current_user.roles %}
<a href="{{ url_for('statistics.dashboard') }}"
class="nav-link group flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium
text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20
transition-colors duration-200
{% if request.endpoint and request.endpoint.startswith('statistics.') %}
text-primary bg-primary-50 dark:bg-primary-900/20
{% endif %}">
<!-- Chart Icon -->
<svg class="w-4.5 h-4.5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
</svg>
<span>{{ _('Statistiche') }}</span>
</a>
{% endif %}
{# Admin: Utenti #}
{% if current_user.get('is_admin') %}
<a href="{{ url_for('admin.user_list') }}"
class="nav-link group flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium
text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20
transition-colors duration-200
{% if request.endpoint == 'admin.user_list' %}
text-primary bg-primary-50 dark:bg-primary-900/20
{% endif %}">
<!-- Users Icon -->
<svg class="w-4.5 h-4.5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z"/>
</svg>
<span>{{ _('Utenti') }}</span>
</a>
<a href="{{ url_for('admin.station_list') }}"
class="nav-link group flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium
text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20
transition-colors duration-200
{% if request.endpoint == 'admin.station_list' %}
text-primary bg-primary-50 dark:bg-primary-900/20
{% endif %}">
<!-- Station / Workstation Icon -->
<svg class="w-4.5 h-4.5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 01-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0115 18.257V17.25m6-12V15a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 15V5.25m18 0A2.25 2.25 0 0018.75 3H5.25A2.25 2.25 0 003 5.25m18 0V12a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 12V5.25"/>
</svg>
<span>{{ _('Stazioni') }}</span>
</a>
<a href="{{ url_for('admin.settings_page') }}"
class="nav-link group flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium
text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20
transition-colors duration-200
{% if request.endpoint == 'admin.settings_page' %}
text-primary bg-primary-50 dark:bg-primary-900/20
{% endif %}">
<svg class="w-4.5 h-4.5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.204-.107-.397.165-.71.505-.78.929l-.15.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.506-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
<span>{{ _('Impostazioni') }}</span>
</a>
{% endif %}
{{ nav_links() }}
</div>
{% endif %}
@@ -126,24 +71,17 @@
<!-- Language Toggle -->
<div class="flex items-center border border-[var(--border-color)] rounded-lg overflow-hidden">
<a href="{{ url_for('set_language', lang='it') }}"
{% for lang_code in ['it', 'en'] %}
<a href="{{ url_for('set_language', lang=lang_code) }}"
class="px-2 py-1.5 text-xs font-semibold transition-colors duration-200
{% if current_language == 'it' %}
{% if current_language == lang_code %}
bg-primary text-white
{% else %}
text-[var(--text-secondary)] hover:bg-[var(--bg-secondary)]
{% endif %}">
IT
</a>
<a href="{{ url_for('set_language', lang='en') }}"
class="px-2 py-1.5 text-xs font-semibold transition-colors duration-200
{% if current_language == 'en' %}
bg-primary text-white
{% else %}
text-[var(--text-secondary)] hover:bg-[var(--bg-secondary)]
{% endif %}">
EN
{{ lang_code|upper }}
</a>
{% endfor %}
</div>
<!-- Theme Toggle -->
@@ -265,77 +203,7 @@
x-cloak
class="md:hidden border-t border-[var(--border-color)] bg-[var(--bg-card)]">
<div class="px-4 py-3 space-y-1">
{% if current_user.get('roles') and 'MeasurementTec' in current_user.roles %}
<a href="{{ url_for('measure.select_recipe') }}"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium
text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20
transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/>
</svg>
{{ _('Misure') }}
</a>
{% endif %}
{% if current_user.get('roles') and 'Maker' in current_user.roles %}
<a href="{{ url_for('maker.recipe_list') }}"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium
text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20
transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
</svg>
{{ _('Ricette') }}
</a>
{% endif %}
{% if current_user.get('roles') and 'Metrologist' in current_user.roles %}
<a href="{{ url_for('statistics.dashboard') }}"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium
text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20
transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
</svg>
{{ _('Statistiche') }}
</a>
{% endif %}
{# Admin: Utenti + Stazioni #}
{% if current_user.get('is_admin') %}
<a href="{{ url_for('admin.user_list') }}"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium
text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20
transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z"/>
</svg>
{{ _('Utenti') }}
</a>
<a href="{{ url_for('admin.station_list') }}"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium
text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20
transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 01-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0115 18.257V17.25m6-12V15a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 15V5.25m18 0A2.25 2.25 0 0018.75 3H5.25A2.25 2.25 0 003 5.25m18 0V12a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 12V5.25"/>
</svg>
{{ _('Stazioni') }}
</a>
<a href="{{ url_for('admin.settings_page') }}"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium
text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20
transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.204-.107-.397.165-.71.505-.78.929l-.15.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.506-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
{{ _('Impostazioni') }}
</a>
{% endif %}
{{ nav_links(mobile=true) }}
</div>
</div>
{% endif %}
@@ -120,7 +120,7 @@
</div>
<input type="text"
x-model="search"
class="tmf-input pl-10"
class="tmf-input !pl-10"
:placeholder="'{{ _('Cerca per nome, codice o descrizione...') }}'">
</div>
</div>
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: TieMeasureFlow 1.0\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-06-11 12:49+0000\n"
"POT-Creation-Date: 2026-06-11 15:33+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: en\n"
@@ -163,8 +163,7 @@ msgstr "seconds due to inactivity."
msgid "Continua a lavorare"
msgstr "Keep working"
#: templates/admin/settings.html:3 templates/components/navbar.html:117
#: templates/components/navbar.html:335
#: templates/admin/settings.html:3 templates/components/navbar.html:37
msgid "Impostazioni"
msgstr "Settings"
@@ -456,8 +455,8 @@ msgid "Nuovo Utente"
msgstr "New User"
#: templates/admin/users.html:48 templates/admin/users.html:173
#: templates/admin/users.html:179 templates/auth/login.html:26
#: templates/auth/login.html:39 templates/auth/profile.html:36
#: templates/admin/users.html:179 templates/auth/login.html:33
#: templates/auth/login.html:47 templates/auth/profile.html:36
#: templates/measure/task_execute.html:649
msgid "Username"
msgstr "Username"
@@ -509,7 +508,7 @@ msgid "Il nome utente non può essere modificato"
msgstr "Username cannot be changed"
#: templates/admin/users.html:206 templates/admin/users.html:214
#: templates/auth/login.html:47 templates/auth/login.html:59
#: templates/auth/login.html:55 templates/auth/login.html:69
#: templates/measure/task_execute.html:654
msgid "Password"
msgstr "Password"
@@ -579,28 +578,36 @@ msgid "Username, nome visualizzato e password sono obbligatori"
msgstr "Username, display name and password are required"
# Login Page
#: templates/auth/login.html:16
#: templates/auth/login.html:23
msgid "Accedi al sistema"
msgstr "Sign in to your account"
#: templates/auth/login.html:71
#: templates/auth/login.html:73
msgid "Nascondi password"
msgstr "Hide password"
#: templates/auth/login.html:73
msgid "Mostra password"
msgstr "Show password"
#: templates/auth/login.html:94
msgid "Accedi"
msgstr "Sign In"
#: templates/auth/login.html:79
#: templates/auth/login.html:102
msgid "Hai dimenticato la password?"
msgstr "Forgot password?"
#: templates/auth/login.html:81
#: templates/auth/login.html:104
msgid "Contatta l'amministratore"
msgstr "Contact administrator"
# Additional Login Page
#: templates/auth/login.html:88
#: templates/auth/login.html:111
msgid "Sistema di misurazione industriale"
msgstr "Industrial measurement system"
#: templates/auth/profile.html:2 templates/components/navbar.html:211
#: templates/auth/profile.html:2 templates/components/navbar.html:147
msgid "Profilo"
msgstr "Profile"
@@ -650,8 +657,8 @@ msgstr "Logout from system"
msgid "Termina la sessione corrente e torna alla schermata di login"
msgstr "End current session and return to login screen"
#: templates/auth/profile.html:197 templates/components/navbar.html:222
#: templates/components/navbar.html:231
#: templates/auth/profile.html:197 templates/components/navbar.html:158
#: templates/components/navbar.html:167
msgid "Logout"
msgstr "Logout"
@@ -720,33 +727,31 @@ msgid "NON CONFORME"
msgstr "NON-CONFORMING"
# Navbar
#: templates/components/navbar.html:38 templates/components/navbar.html:277
#: templates/measure/task_complete.html:16
#: templates/components/navbar.html:26 templates/measure/task_complete.html:16
#: templates/measure/task_execute.html:2 templates/measure/task_list.html:16
msgid "Misure"
msgstr "Activities"
#: templates/components/navbar.html:55 templates/components/navbar.html:289
#: templates/maker/recipe_editor.html:51 templates/maker/recipe_list.html:83
#: templates/maker/recipe_preview.html:61 templates/maker/task_drawing.html:84
#: templates/maker/task_editor.html:110 templates/maker/version_history.html:73
#: templates/components/navbar.html:29 templates/maker/recipe_editor.html:51
#: templates/maker/recipe_list.html:83 templates/maker/recipe_preview.html:61
#: templates/maker/task_drawing.html:84 templates/maker/task_editor.html:110
#: templates/maker/version_history.html:73
msgid "Ricette"
msgstr "Recipes"
#: templates/components/navbar.html:72 templates/components/navbar.html:301
#: templates/measure/task_complete.html:261
#: templates/components/navbar.html:32 templates/measure/task_complete.html:261
msgid "Statistiche"
msgstr "Statistics"
#: templates/components/navbar.html:89 templates/components/navbar.html:314
#: templates/components/navbar.html:35
msgid "Utenti"
msgstr "Users"
#: templates/components/navbar.html:103 templates/components/navbar.html:324
#: templates/components/navbar.html:36
msgid "Stazioni"
msgstr "Stations"
#: templates/components/navbar.html:218
#: templates/components/navbar.html:154
msgid "Logout bloccato durante le misurazioni"
msgstr "Logout blocked during measurements"
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: TieMeasureFlow 1.0\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-06-11 12:49+0000\n"
"POT-Creation-Date: 2026-06-11 15:33+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: it\n"
@@ -163,8 +163,7 @@ msgstr "secondi per inattività."
msgid "Continua a lavorare"
msgstr "Continua a lavorare"
#: templates/admin/settings.html:3 templates/components/navbar.html:117
#: templates/components/navbar.html:335
#: templates/admin/settings.html:3 templates/components/navbar.html:37
msgid "Impostazioni"
msgstr "Impostazioni"
@@ -458,8 +457,8 @@ msgid "Nuovo Utente"
msgstr "Nuovo Utente"
#: templates/admin/users.html:48 templates/admin/users.html:173
#: templates/admin/users.html:179 templates/auth/login.html:26
#: templates/auth/login.html:39 templates/auth/profile.html:36
#: templates/admin/users.html:179 templates/auth/login.html:33
#: templates/auth/login.html:47 templates/auth/profile.html:36
#: templates/measure/task_execute.html:649
msgid "Username"
msgstr "Username"
@@ -511,7 +510,7 @@ msgid "Il nome utente non può essere modificato"
msgstr "Il nome utente non può essere modificato"
#: templates/admin/users.html:206 templates/admin/users.html:214
#: templates/auth/login.html:47 templates/auth/login.html:59
#: templates/auth/login.html:55 templates/auth/login.html:69
#: templates/measure/task_execute.html:654
msgid "Password"
msgstr "Password"
@@ -581,28 +580,36 @@ msgid "Username, nome visualizzato e password sono obbligatori"
msgstr "Username, nome visualizzato e password sono obbligatori"
# Login Page
#: templates/auth/login.html:16
#: templates/auth/login.html:23
msgid "Accedi al sistema"
msgstr "Accedi al sistema"
#: templates/auth/login.html:71
#: templates/auth/login.html:73
msgid "Nascondi password"
msgstr "Nascondi password"
#: templates/auth/login.html:73
msgid "Mostra password"
msgstr "Mostra password"
#: templates/auth/login.html:94
msgid "Accedi"
msgstr "Accedi"
#: templates/auth/login.html:79
#: templates/auth/login.html:102
msgid "Hai dimenticato la password?"
msgstr "Hai dimenticato la password?"
#: templates/auth/login.html:81
#: templates/auth/login.html:104
msgid "Contatta l'amministratore"
msgstr "Contatta l'amministratore"
# Additional Login Page
#: templates/auth/login.html:88
#: templates/auth/login.html:111
msgid "Sistema di misurazione industriale"
msgstr "Sistema di misurazione industriale"
#: templates/auth/profile.html:2 templates/components/navbar.html:211
#: templates/auth/profile.html:2 templates/components/navbar.html:147
msgid "Profilo"
msgstr "Profilo"
@@ -652,8 +659,8 @@ msgstr "Esci dal sistema"
msgid "Termina la sessione corrente e torna alla schermata di login"
msgstr "Termina la sessione corrente e torna alla schermata di login"
#: templates/auth/profile.html:197 templates/components/navbar.html:222
#: templates/components/navbar.html:231
#: templates/auth/profile.html:197 templates/components/navbar.html:158
#: templates/components/navbar.html:167
msgid "Logout"
msgstr "Logout"
@@ -722,33 +729,31 @@ msgid "NON CONFORME"
msgstr "NON CONFORME"
# Navbar
#: templates/components/navbar.html:38 templates/components/navbar.html:277
#: templates/measure/task_complete.html:16
#: templates/components/navbar.html:26 templates/measure/task_complete.html:16
#: templates/measure/task_execute.html:2 templates/measure/task_list.html:16
msgid "Misure"
msgstr "Attività"
#: templates/components/navbar.html:55 templates/components/navbar.html:289
#: templates/maker/recipe_editor.html:51 templates/maker/recipe_list.html:83
#: templates/maker/recipe_preview.html:61 templates/maker/task_drawing.html:84
#: templates/maker/task_editor.html:110 templates/maker/version_history.html:73
#: templates/components/navbar.html:29 templates/maker/recipe_editor.html:51
#: templates/maker/recipe_list.html:83 templates/maker/recipe_preview.html:61
#: templates/maker/task_drawing.html:84 templates/maker/task_editor.html:110
#: templates/maker/version_history.html:73
msgid "Ricette"
msgstr "Ricette"
#: templates/components/navbar.html:72 templates/components/navbar.html:301
#: templates/measure/task_complete.html:261
#: templates/components/navbar.html:32 templates/measure/task_complete.html:261
msgid "Statistiche"
msgstr "Statistiche"
#: templates/components/navbar.html:89 templates/components/navbar.html:314
#: templates/components/navbar.html:35
msgid "Utenti"
msgstr "Utenti"
#: templates/components/navbar.html:103 templates/components/navbar.html:324
#: templates/components/navbar.html:36
msgid "Stazioni"
msgstr "Stazioni"
#: templates/components/navbar.html:218
#: templates/components/navbar.html:154
msgid "Logout bloccato durante le misurazioni"
msgstr "Logout bloccato durante le misurazioni"
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-06-11 12:49+0000\n"
"POT-Creation-Date: 2026-06-11 15:33+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -160,8 +160,7 @@ msgstr ""
msgid "Continua a lavorare"
msgstr ""
#: templates/admin/settings.html:3 templates/components/navbar.html:117
#: templates/components/navbar.html:335
#: templates/admin/settings.html:3 templates/components/navbar.html:37
msgid "Impostazioni"
msgstr ""
@@ -448,8 +447,8 @@ msgid "Nuovo Utente"
msgstr ""
#: templates/admin/users.html:48 templates/admin/users.html:173
#: templates/admin/users.html:179 templates/auth/login.html:26
#: templates/auth/login.html:39 templates/auth/profile.html:36
#: templates/admin/users.html:179 templates/auth/login.html:33
#: templates/auth/login.html:47 templates/auth/profile.html:36
#: templates/measure/task_execute.html:649
msgid "Username"
msgstr ""
@@ -501,7 +500,7 @@ msgid "Il nome utente non può essere modificato"
msgstr ""
#: templates/admin/users.html:206 templates/admin/users.html:214
#: templates/auth/login.html:47 templates/auth/login.html:59
#: templates/auth/login.html:55 templates/auth/login.html:69
#: templates/measure/task_execute.html:654
msgid "Password"
msgstr ""
@@ -570,27 +569,35 @@ msgstr ""
msgid "Username, nome visualizzato e password sono obbligatori"
msgstr ""
#: templates/auth/login.html:16
#: templates/auth/login.html:23
msgid "Accedi al sistema"
msgstr ""
#: templates/auth/login.html:71
#: templates/auth/login.html:73
msgid "Nascondi password"
msgstr ""
#: templates/auth/login.html:73
msgid "Mostra password"
msgstr ""
#: templates/auth/login.html:94
msgid "Accedi"
msgstr ""
#: templates/auth/login.html:79
#: templates/auth/login.html:102
msgid "Hai dimenticato la password?"
msgstr ""
#: templates/auth/login.html:81
#: templates/auth/login.html:104
msgid "Contatta l'amministratore"
msgstr ""
#: templates/auth/login.html:88
#: templates/auth/login.html:111
msgid "Sistema di misurazione industriale"
msgstr ""
#: templates/auth/profile.html:2 templates/components/navbar.html:211
#: templates/auth/profile.html:2 templates/components/navbar.html:147
msgid "Profilo"
msgstr ""
@@ -638,8 +645,8 @@ msgstr ""
msgid "Termina la sessione corrente e torna alla schermata di login"
msgstr ""
#: templates/auth/profile.html:197 templates/components/navbar.html:222
#: templates/components/navbar.html:231
#: templates/auth/profile.html:197 templates/components/navbar.html:158
#: templates/components/navbar.html:167
msgid "Logout"
msgstr ""
@@ -703,33 +710,31 @@ msgstr ""
msgid "NON CONFORME"
msgstr ""
#: templates/components/navbar.html:38 templates/components/navbar.html:277
#: templates/measure/task_complete.html:16
#: templates/components/navbar.html:26 templates/measure/task_complete.html:16
#: templates/measure/task_execute.html:2 templates/measure/task_list.html:16
msgid "Misure"
msgstr ""
#: templates/components/navbar.html:55 templates/components/navbar.html:289
#: templates/maker/recipe_editor.html:51 templates/maker/recipe_list.html:83
#: templates/maker/recipe_preview.html:61 templates/maker/task_drawing.html:84
#: templates/maker/task_editor.html:110 templates/maker/version_history.html:73
#: templates/components/navbar.html:29 templates/maker/recipe_editor.html:51
#: templates/maker/recipe_list.html:83 templates/maker/recipe_preview.html:61
#: templates/maker/task_drawing.html:84 templates/maker/task_editor.html:110
#: templates/maker/version_history.html:73
msgid "Ricette"
msgstr ""
#: templates/components/navbar.html:72 templates/components/navbar.html:301
#: templates/measure/task_complete.html:261
#: templates/components/navbar.html:32 templates/measure/task_complete.html:261
msgid "Statistiche"
msgstr ""
#: templates/components/navbar.html:89 templates/components/navbar.html:314
#: templates/components/navbar.html:35
msgid "Utenti"
msgstr ""
#: templates/components/navbar.html:103 templates/components/navbar.html:324
#: templates/components/navbar.html:36
msgid "Stazioni"
msgstr ""
#: templates/components/navbar.html:218
#: templates/components/navbar.html:154
msgid "Logout bloccato durante le misurazioni"
msgstr ""