style: aggiunti effetti per le overperformance.

This commit is contained in:
Gabriele Cimaschi committed 2026-08-26 21:05:31 +02:00
1 parent a5401e35d8
commit 146d4ed661
11 files changed
+63 -18

No files matched your search

+3
View File
@@ -41,6 +41,9 @@ CRYPTO_KEY=f30b91e92d77a06c59b20b2272e2cfbc
# Soglia in percentuale del target tempo giornaliero per l'attivazione delle frasi demotivazionali (es. 70 per il 70%) # Soglia in percentuale del target tempo giornaliero per l'attivazione delle frasi demotivazionali (es. 70 per il 70%)
PHRASE_THRESHOLD=70 PHRASE_THRESHOLD=70
# Immagine ironica mostrata in caso di overperformance (default over9000.jpg nella cartella public/img)
OVERPERFORMANCE_IMAGE=over9000.jpg
# Configurazioni per la consuntivazione automatica fine giornata # Configurazioni per la consuntivazione automatica fine giornata
AUTO_TIME_MIN_HOUR=18:00 AUTO_TIME_MIN_HOUR=18:00
AUTO_TIME_QUEUE=Assistenza AUTO_TIME_QUEUE=Assistenza
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

+5 -5
View File
@@ -2403,8 +2403,8 @@ body {
.timer-tooltip { .timer-tooltip {
position: absolute; position: absolute;
left: 105%; left: 105%;
top: 50%; top: -5px;
transform: translateY(-50%) translateX(-8px); transform: translateX(-8px);
width: 290px; width: 290px;
background: var(--bg-secondary); background: var(--bg-secondary);
border: 1px solid var(--border-light); border: 1px solid var(--border-light);
@@ -2423,7 +2423,7 @@ body {
.timer-tooltip::after { .timer-tooltip::after {
content: ""; content: "";
position: absolute; position: absolute;
top: 50%; top: 18px;
right: 100%; right: 100%;
transform: translateY(-50%); transform: translateY(-50%);
border-width: 6px; border-width: 6px;
@@ -2433,7 +2433,7 @@ body {
.timer-tooltip-border { .timer-tooltip-border {
position: absolute; position: absolute;
top: 50%; top: 18px;
right: 100%; right: 100%;
transform: translateY(-50%); transform: translateY(-50%);
border-width: 7px; border-width: 7px;
@@ -2444,7 +2444,7 @@ body {
.sidebar-timer:hover .timer-tooltip { .sidebar-timer:hover .timer-tooltip {
opacity: 1; opacity: 1;
transform: translateY(-50%) translateX(0); transform: translateX(0);
pointer-events: auto; pointer-events: auto;
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

+53 -12
View File
@@ -23,7 +23,7 @@ const App = {
if (saved) this.tabs = JSON.parse(saved); if (saved) this.tabs = JSON.parse(saved);
const savedDrafts = localStorage.getItem('otrs_turbo_drafts'); const savedDrafts = localStorage.getItem('otrs_turbo_drafts');
if (savedDrafts) this.drafts = JSON.parse(savedDrafts); if (savedDrafts) this.drafts = JSON.parse(savedDrafts);
} catch (e) {} } catch (e) { }
this.renderTabs(); this.renderTabs();
}, },
@@ -756,6 +756,32 @@ const App = {
} }
} }
const overDelta = Math.max(0, mathematicalPercentage - 100);
const visualBarWidth = hasOverperformance ? (100 + (overDelta * 3.5)) : percentage;
let overImgName = 'over9000.jpg';
let overPhraseText = '';
if (mathematicalPercentage > 150) {
overImgName = this.lookups?.config?.overperformanceImage || 'over9000.jpg';
overPhraseText = "IT'S OVER 9000! Il livello di consuntivazione ha superato ogni limite!";
} else if (mathematicalPercentage > 140) {
overImgName = 'over_150.jpg';
overPhraseText = 'Questo livello di consuntivazione è impossibile.';
} else if (mathematicalPercentage > 130) {
overImgName = 'over_140.jpg';
overPhraseText = 'Io sono il principe dei Saiyan, non glielo permetterò';
} else if (mathematicalPercentage > 120) {
overImgName = 'over_130.jpg';
overPhraseText = 'Sono un Saiyan, non può consuntivare più di me.';
} else if (mathematicalPercentage > 110) {
overImgName = 'over_120.jpg';
overPhraseText = 'Non è possibile! La sua consuntivazione continua ad aumentare.';
} else {
overImgName = 'over_110.jpg';
overPhraseText = "C'è qualcosa di sicuro nella vita. Il più forte è al di sopra di tutti e può consuntivare tutto!";
}
timerEl.innerHTML = ` timerEl.innerHTML = `
<div class="timer-display" style="display:flex; justify-content:space-between; align-items:center; width:100%; font-size:0.75rem; font-weight:500;"> <div class="timer-display" style="display:flex; justify-content:space-between; align-items:center; width:100%; font-size:0.75rem; font-weight:500;">
<span>⏱ ${todayTime} / ${targetTime} m</span> <span>⏱ ${todayTime} / ${targetTime} m</span>
@@ -764,21 +790,36 @@ const App = {
</div> </div>
<div class="timer-tooltip"> <div class="timer-tooltip">
<div class="timer-tooltip-border"></div> <div class="timer-tooltip-border"></div>
<div style="font-size:0.75rem; font-weight:600; color:var(--text-primary); margin-bottom:4px; display:flex; justify-content:space-between;"> <div style="font-size:0.75rem; font-weight:600; color:var(--text-primary); margin-bottom:4px; display:flex; justify-content:space-between; align-items:center;">
<span>Progresso Giornaliero</span> <span>Progresso Giornaliero</span>
<strong>${mathematicalPercentage}%</strong> <strong>${mathematicalPercentage}% ${hasOverperformance ? '<span style="animation: pulse 1.5s infinite; display:inline-block; margin-left:4px;">⚠️</span>' : ''}</strong>
</div> </div>
<div style="background:var(--border-light); border-radius:var(--radius-full); height:10px; width:100%; overflow:hidden; border:1px solid var(--border-subtle);"> <div style="background:var(--border-light); border-radius:var(--radius-full); height:10px; width:100%; position:relative; overflow:visible; border:1px solid var(--border-subtle);">
<div style="width:${percentage}%; background:linear-gradient(90deg, var(--accent-primary), var(--accent-secondary)); height:100%; border-radius:inherit; transition: width 0.3s ease;"></div> <div style="width:${visualBarWidth}%; background:${hasOverperformance ? 'linear-gradient(90deg, var(--accent-primary), #ef4444, #f59e0b, #ec4899)' : 'linear-gradient(90deg, var(--accent-primary), var(--accent-secondary))'}; height:100%; border-radius:var(--radius-full); transition: width 0.3s ease; ${hasOverperformance ? 'box-shadow: 0 0 10px rgba(239, 68, 68, 0.8);' : ''}"></div>
</div> </div>
${hasOverperformance ? ` ${hasOverperformance ? (() => {
<div style="font-size:0.72rem; color:var(--error); font-weight:700; line-height:1.3; text-transform:uppercase; margin-top:8px; border-top:1px solid var(--border-subtle); padding-top:8px; text-align:center; animation: pulse 1.5s infinite;"> const overImgSrc = (overImgName.startsWith('http://') || overImgName.startsWith('https://') || overImgName.startsWith('/')) ? overImgName : `img/${overImgName}`;
⚠️ Rilevata una overperformance allontanarsi dalla postazione immediatamente const imgWidth = Math.min(500, 180 + Math.round(overDelta * 10));
return `
<div style="font-size:0.72rem; color:var(--error); font-weight:700; line-height:1.3; text-transform:uppercase; margin-top:8px; border-top:1px solid var(--border-subtle); padding-top:8px; text-align:center; animation: pulse 1.5s infinite;">
Rilevata una overperformance allontanarsi <span style="font-size:1.4rem; display:block; font-weight:900; margin-top:2px;">IMMEDIATAMENTE</span>
</div>
<div style="margin-top:6px; text-align:center; position:relative; overflow:visible;">
<a href="${App.escapeHtml(overImgSrc)}" target="_blank" title="Apri immagine originale in una nuova scheda" style="display:inline-block; text-decoration:none;">
<img src="${App.escapeHtml(overImgSrc)}" alt="Overperformance Meme" style="width:${imgWidth}px; max-width:none; border-radius:var(--radius-md); box-shadow:var(--shadow-md); display:block; margin:0 auto; transition: width 0.3s ease; cursor:pointer;" />
</a>
</div>
${overPhraseText ? `
<div style="font-size:0.75rem; color:var(--text-primary); font-weight:600; line-height:1.35; font-style:italic; margin-top:8px; border-top:1px dashed var(--border-subtle); padding-top:6px; text-align:center;">
"${App.escapeHtml(overPhraseText)}"
</div>
` : ''}
`;
})() : `
<div style="font-size:0.72rem; color:var(--text-secondary); line-height:1.35; font-style:italic; margin-top:6px; border-top:1px solid var(--border-subtle); padding-top:6px; text-align:center;">
"${phrase}"
</div> </div>
` : ''} `}
<div style="font-size:0.72rem; color:var(--text-secondary); line-height:1.35; font-style:italic; margin-top:6px; border-top:1px solid var(--border-subtle); padding-top:6px; text-align:center;">
"${phrase}"
</div>
</div> </div>
`; `;
// Update sidebar counts as well // Update sidebar counts as well
+2 -1
View File
@@ -151,7 +151,8 @@ router.get('/config', async (req, res) => {
phraseThreshold: parseInt(process.env.PHRASE_THRESHOLD, 10) || 70, phraseThreshold: parseInt(process.env.PHRASE_THRESHOLD, 10) || 70,
autoTimeMinHour: process.env.AUTO_TIME_MIN_HOUR || '18:00', autoTimeMinHour: process.env.AUTO_TIME_MIN_HOUR || '18:00',
helpdeskEmail: process.env.OTRS_MAIL_BCC || '', helpdeskEmail: process.env.OTRS_MAIL_BCC || '',
agentEmail: agentEmail agentEmail: agentEmail,
overperformanceImage: process.env.OVERPERFORMANCE_IMAGE || 'over9000.jpg'
}); });
}); });