add window guard
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<link rel="icon" type="image/jpeg" href="/src/assets/logo.jpeg"/>
|
||||
<title>Simple Care — Rikkei Education</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -93,6 +93,20 @@ body {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.brand-logo-img {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: var(--radius-sm);
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.login-brand-row .brand-logo-img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
@@ -413,24 +427,61 @@ body {
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.65rem;
|
||||
margin-bottom: 0.4rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.card-title-sub {
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.72rem;
|
||||
color: var(--text-muted);
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.clock-display-summary {
|
||||
margin-bottom: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.45rem;
|
||||
margin-bottom: 0.45rem;
|
||||
padding-bottom: 0.45rem;
|
||||
border-bottom: 1px dashed var(--border-color);
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.clock-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
padding: 0.2rem 0.5rem;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--bg-subtle);
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
.clock-chip em {
|
||||
font-style: normal;
|
||||
color: var(--text-muted);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.clock-chip strong {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.clock-chip--online strong {
|
||||
color: var(--online-color);
|
||||
}
|
||||
|
||||
.clock-chip--offline strong {
|
||||
color: var(--offline-color);
|
||||
}
|
||||
|
||||
.shifts-wrap {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
max-height: min(32vh, 220px);
|
||||
}
|
||||
|
||||
.shifts-table {
|
||||
@@ -571,10 +622,11 @@ body {
|
||||
.clocks-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.65rem;
|
||||
gap: 0.4rem;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
padding: 0.75rem 0.85rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
|
||||
BIN
client/frontend/src/assets/logo.jpeg
Normal file
BIN
client/frontend/src/assets/logo.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
@@ -1,5 +1,8 @@
|
||||
import './style.css';
|
||||
import './app.css';
|
||||
import logoUrl from './assets/logo.jpeg';
|
||||
|
||||
const brandLogoHtml = `<img src="${logoUrl}" alt="Simple Care" class="brand-logo-img" />`;
|
||||
|
||||
// Trạng thái cục bộ
|
||||
let loggedIn = false;
|
||||
@@ -68,7 +71,7 @@ function renderLoginPrompt() {
|
||||
<div class="login-prompt-container">
|
||||
<div class="card">
|
||||
<div class="login-brand-row">
|
||||
<div class="login-logo">RE</div>
|
||||
${brandLogoHtml}
|
||||
<div class="login-brand-text">
|
||||
<div class="login-brand-name">Simple Care</div>
|
||||
<div class="login-brand-sub">Rikkei Education</div>
|
||||
@@ -157,7 +160,7 @@ function renderDashboard() {
|
||||
<div class="dashboard-wrapper">
|
||||
<header class="header">
|
||||
<div class="brand">
|
||||
<div class="brand-logo">RE</div>
|
||||
${brandLogoHtml}
|
||||
<div class="brand-text">
|
||||
<span class="brand-name">Simple Care</span>
|
||||
<span class="brand-sub">Rikkei Education</span>
|
||||
@@ -228,14 +231,14 @@ function renderDashboard() {
|
||||
<div class="card-title-sub" id="session-date">${stats.sessionDate || ''}</div>
|
||||
</div>
|
||||
<div class="clock-display clock-display-summary">
|
||||
<div class="clock-item">
|
||||
<div class="clock-label">Tổng trực tuyến</div>
|
||||
<div class="clock-value online" id="clock-online">00:00:00</div>
|
||||
</div>
|
||||
<div class="clock-item">
|
||||
<div class="clock-label">Tổng ngoại tuyến</div>
|
||||
<div class="clock-value offline" id="clock-offline">00:00:00</div>
|
||||
</div>
|
||||
<span class="clock-chip clock-chip--online">
|
||||
<em>Trực tuyến</em>
|
||||
<strong id="clock-online">00:00:00</strong>
|
||||
</span>
|
||||
<span class="clock-chip clock-chip--offline">
|
||||
<em>Ngoại tuyến</em>
|
||||
<strong id="clock-offline">00:00:00</strong>
|
||||
</span>
|
||||
</div>
|
||||
<div class="shifts-wrap" id="shifts-wrap">
|
||||
${renderShiftsTable(stats.shifts)}
|
||||
@@ -265,7 +268,7 @@ function formatDuration(totalSeconds) {
|
||||
}
|
||||
|
||||
function startStatsTicker() {
|
||||
setInterval(async () => {
|
||||
const pullStats = async () => {
|
||||
if (!loggedIn) return;
|
||||
try {
|
||||
const freshStats = await window.go.main.App.GetStats();
|
||||
@@ -330,7 +333,9 @@ function startStatsTicker() {
|
||||
} catch (err) {
|
||||
console.error('Error fetching stats:', err);
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
pullStats();
|
||||
setInterval(pullStats, 1000);
|
||||
}
|
||||
|
||||
async function startWebcam() {
|
||||
|
||||
Reference in New Issue
Block a user