Aug 5 - Update (new design)
This commit is contained in:
@@ -30,8 +30,9 @@ body.jqc-modern {
|
|||||||
--jqc-faint: #93A1AB;
|
--jqc-faint: #93A1AB;
|
||||||
--jqc-border: #E3E8EC;
|
--jqc-border: #E3E8EC;
|
||||||
--jqc-border-2: #CFD9E0;
|
--jqc-border-2: #CFD9E0;
|
||||||
--jqc-surface: #F5F8FA;
|
--jqc-surface: #F5F8FA; /* subtle fill — hovers, muted rows (theme.css) */
|
||||||
--jqc-surface-2: #EEF3F6;
|
--jqc-surface-2: #EEF3F6;
|
||||||
|
--jqc-card-bg: #FFFFFF; /* raised surfaces — cards, KPI tiles, sidebar */
|
||||||
--jqc-accent: #155F82;
|
--jqc-accent: #155F82;
|
||||||
--jqc-accent-700: #0F4A66;
|
--jqc-accent-700: #0F4A66;
|
||||||
--jqc-accent-50: #DCEBF5;
|
--jqc-accent-50: #DCEBF5;
|
||||||
@@ -164,7 +165,7 @@ body.jqc-modern {
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: var(--jqc-sidebar-w);
|
width: var(--jqc-sidebar-w);
|
||||||
background: #fff;
|
background: var(--jqc-card-bg);
|
||||||
border-right: 1px solid var(--jqc-border);
|
border-right: 1px solid var(--jqc-border);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
z-index: 1030;
|
z-index: 1030;
|
||||||
@@ -274,8 +275,11 @@ body.jqc-modern {
|
|||||||
letter-spacing: -.02em;
|
letter-spacing: -.02em;
|
||||||
color: var(--jqc-ink);
|
color: var(--jqc-ink);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
/* Opt-in centring — the default is left-aligned. `.center` on the head block
|
||||||
|
centres the title and its sub-line together. */
|
||||||
|
.jqc-modern .jqc-page-head.center,
|
||||||
|
.jqc-modern .jqc-page-title.center { text-align: center; }
|
||||||
.jqc-modern .jqc-page-sub {
|
.jqc-modern .jqc-page-sub {
|
||||||
color: var(--jqc-muted);
|
color: var(--jqc-muted);
|
||||||
font-size: .95rem;
|
font-size: .95rem;
|
||||||
@@ -289,18 +293,18 @@ body.jqc-modern {
|
|||||||
box-shadow: var(--jqc-shadow);
|
box-shadow: var(--jqc-shadow);
|
||||||
}
|
}
|
||||||
.jqc-modern .card-header {
|
.jqc-modern .card-header {
|
||||||
background: #fff;
|
background: var(--jqc-card-bg);
|
||||||
border-bottom: 1px solid var(--jqc-border);
|
border-bottom: 1px solid var(--jqc-border);
|
||||||
color: var(--jqc-ink);
|
color: var(--jqc-ink);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
padding: .9rem 1.15rem;
|
padding: .9rem 1.15rem;
|
||||||
}
|
}
|
||||||
.jqc-modern .card-header.bg-light,
|
.jqc-modern .card-header.bg-light,
|
||||||
.jqc-modern .card-header.bg-white { background: #fff !important; }
|
.jqc-modern .card-header.bg-white { background: var(--jqc-card-bg) !important; }
|
||||||
.jqc-modern .card-body { padding: 1.15rem; }
|
.jqc-modern .card-body { padding: 1.15rem; }
|
||||||
|
|
||||||
.jqc-modern .jqc-card {
|
.jqc-modern .jqc-card {
|
||||||
background: #fff;
|
background: var(--jqc-card-bg);
|
||||||
border: 1px solid var(--jqc-border);
|
border: 1px solid var(--jqc-border);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: var(--jqc-shadow);
|
box-shadow: var(--jqc-shadow);
|
||||||
@@ -333,7 +337,7 @@ body.jqc-modern {
|
|||||||
|
|
||||||
/* KPI tiles */
|
/* KPI tiles */
|
||||||
.jqc-modern .jqc-kpi {
|
.jqc-modern .jqc-kpi {
|
||||||
background: #fff;
|
background: var(--jqc-card-bg);
|
||||||
border: 1px solid var(--jqc-border);
|
border: 1px solid var(--jqc-border);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: var(--jqc-shadow);
|
box-shadow: var(--jqc-shadow);
|
||||||
@@ -379,7 +383,7 @@ a.jqc-kpi:hover { box-shadow: var(--jqc-shadow-md); transform: translateY(-1px);
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: #fff;
|
background: var(--jqc-card-bg);
|
||||||
border: 1px solid var(--jqc-border);
|
border: 1px solid var(--jqc-border);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: var(--jqc-shadow);
|
box-shadow: var(--jqc-shadow);
|
||||||
@@ -399,17 +403,27 @@ a.jqc-kpi:hover { box-shadow: var(--jqc-shadow-md); transform: translateY(-1px);
|
|||||||
|
|
||||||
/* ── 7. Tables — dark teal header, as in the deck ────────────────────────── */
|
/* ── 7. Tables — dark teal header, as in the deck ────────────────────────── */
|
||||||
.jqc-modern .table { --bs-table-border-color: var(--jqc-border); margin-bottom: 0; }
|
.jqc-modern .table { --bs-table-border-color: var(--jqc-border); margin-bottom: 0; }
|
||||||
|
|
||||||
|
/* Recoloured via Bootstrap's own table CSS variables rather than !important, so
|
||||||
|
a page that deliberately wants a different header (table-dark, a tinted
|
||||||
|
report header) can still override it with a normal rule. */
|
||||||
.jqc-modern .table > thead > tr > th,
|
.jqc-modern .table > thead > tr > th,
|
||||||
.jqc-modern .table thead.table-light > tr > th,
|
.jqc-modern .table thead.table-light > tr > th,
|
||||||
.jqc-modern .table > thead th {
|
.jqc-modern .table > thead th {
|
||||||
background: var(--jqc-brand) !important;
|
--bs-table-bg: var(--jqc-brand);
|
||||||
color: #fff !important;
|
--bs-table-color: #fff;
|
||||||
border-color: var(--jqc-brand-700) !important;
|
background-color: var(--jqc-brand);
|
||||||
|
color: #fff;
|
||||||
|
border-color: var(--jqc-brand-700);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: .88rem;
|
font-size: .88rem;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* nowrap only where the column set is known-narrow (dashboard panels); wide
|
||||||
|
tables such as the issues list and audit trail must be free to wrap rather
|
||||||
|
than force a horizontal scroll on iPad portrait. */
|
||||||
|
.jqc-modern .jqc-card .table > thead th { white-space: nowrap; }
|
||||||
.jqc-modern .table > tbody > tr > td { vertical-align: middle; font-size: .92rem; }
|
.jqc-modern .table > tbody > tr > td { vertical-align: middle; font-size: .92rem; }
|
||||||
.jqc-modern .table-hover > tbody > tr:hover > * { background-color: var(--jqc-brand-025); }
|
.jqc-modern .table-hover > tbody > tr:hover > * { background-color: var(--jqc-brand-025); }
|
||||||
.jqc-modern .jqc-table-wrap {
|
.jqc-modern .jqc-table-wrap {
|
||||||
@@ -447,7 +461,7 @@ a.jqc-kpi:hover { box-shadow: var(--jqc-shadow-md); transform: translateY(-1px);
|
|||||||
|
|
||||||
/* Filter bar — the rounded pill row from the deck */
|
/* Filter bar — the rounded pill row from the deck */
|
||||||
.jqc-modern .jqc-filter-bar {
|
.jqc-modern .jqc-filter-bar {
|
||||||
background: #fff;
|
background: var(--jqc-card-bg);
|
||||||
border: 1px solid var(--jqc-border);
|
border: 1px solid var(--jqc-border);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: var(--jqc-shadow);
|
box-shadow: var(--jqc-shadow);
|
||||||
|
|||||||
@@ -93,10 +93,13 @@
|
|||||||
<span class="jqc-brand-sub">By L.T. Services, Inc</span>
|
<span class="jqc-brand-sub">By L.T. Services, Inc</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
{# Scoped to inspection ID only — the placeholder says so explicitly so
|
||||||
|
nobody types a facility name and assumes the search is broken. #}
|
||||||
<form class="jqc-search" method="GET" action="{{ url_for('inspections.index') }}" role="search">
|
<form class="jqc-search" method="GET" action="{{ url_for('inspections.index') }}" role="search">
|
||||||
<i class="bi bi-search"></i>
|
<i class="bi bi-search"></i>
|
||||||
<input type="text" name="inspection_id" class="form-control"
|
<input type="search" name="inspection_id" class="form-control" inputmode="numeric"
|
||||||
placeholder="Search inspection number" aria-label="Search inspection number">
|
placeholder="Inspection # (e.g. 1423)" aria-label="Search by inspection number"
|
||||||
|
title="Search by inspection number">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="jqc-topbar-actions">
|
<div class="jqc-topbar-actions">
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
{# ── Header ───────────────────────────────────────────────────────────── #}
|
{# ── Header ───────────────────────────────────────────────────────────── #}
|
||||||
<div class="d-flex flex-wrap justify-content-between align-items-end mb-4 gap-2">
|
<div class="d-flex flex-wrap justify-content-between align-items-end mb-4 gap-2">
|
||||||
<div>
|
<div>
|
||||||
<div class="jqc-page-title" style="text-align:left;">Welcome, {{ current_user.display_name }}</div>
|
<div class="jqc-page-title">Welcome, {{ current_user.display_name }}</div>
|
||||||
<div class="jqc-page-sub">{{ current_user.role.replace('_',' ')|title }}</div>
|
<div class="jqc-page-sub">{{ current_user.role.replace('_',' ')|title }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-muted">{{ now_display }}</div>
|
<div class="text-muted">{{ now_display }}</div>
|
||||||
@@ -242,8 +242,15 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for insp in recent_inspections %}
|
{% for insp in recent_inspections %}
|
||||||
<tr style="cursor:pointer;" onclick="window.location='{{ url_for('inspections.view', inspection_id=insp.id) }}'">
|
{# The row stays click-anywhere for the mouse, but the date is a real
|
||||||
<td><small>{{ insp.inspection_date.strftime('%b %d, %Y') }}</small></td>
|
link so the row is keyboard-reachable and openable in a new tab.
|
||||||
|
The guard stops the row handler from double-firing on that link. #}
|
||||||
|
<tr style="cursor:pointer;"
|
||||||
|
onclick="if(!event.target.closest('a')) window.location='{{ url_for('inspections.view', inspection_id=insp.id) }}'">
|
||||||
|
<td>
|
||||||
|
<a href="{{ url_for('inspections.view', inspection_id=insp.id) }}"
|
||||||
|
class="text-decoration-none"><small>{{ insp.inspection_date.strftime('%b %d, %Y') }}</small></a>
|
||||||
|
</td>
|
||||||
<td>{{ insp.facility.name }}</td>
|
<td>{{ insp.facility.name }}</td>
|
||||||
<td>{{ insp.area.name if insp.area else '—' }}</td>
|
<td>{{ insp.area.name if insp.area else '—' }}</td>
|
||||||
{% if current_user.role != 'inspector' %}<td>{{ insp.inspector.display_name }}</td>{% endif %}
|
{% if current_user.role != 'inspector' %}<td>{{ insp.inspector.display_name }}</td>{% endif %}
|
||||||
@@ -383,10 +390,16 @@
|
|||||||
<span class="jqc-tile-icon"><i class="bi bi-building"></i></span>Your Facilities
|
<span class="jqc-tile-icon"><i class="bi bi-building"></i></span>Your Facilities
|
||||||
<span class="badge bg-secondary rounded-pill ms-2">{{ customer_facilities|length }}</span>
|
<span class="badge bg-secondary rounded-pill ms-2">{{ customer_facilities|length }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row g-3">
|
{% if customer_facilities|length > 6 %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<input type="text" id="facilitySearch" class="form-control form-control-sm"
|
||||||
|
placeholder="Search facilities…" aria-label="Search facilities">
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="row g-3" id="facilityGrid">
|
||||||
{% for f in customer_facilities %}
|
{% for f in customer_facilities %}
|
||||||
<div class="col-12 col-sm-6 col-lg-4">
|
<div class="col-12 col-sm-6 col-lg-4 facility-col">
|
||||||
<div class="border rounded-3 p-3 h-100 d-flex flex-column">
|
<div class="border rounded-3 p-3 h-100 d-flex flex-column facility-card">
|
||||||
<div class="fw-semibold mb-1">{{ f.name }}</div>
|
<div class="fw-semibold mb-1">{{ f.name }}</div>
|
||||||
<div class="text-muted" style="font-size:.82rem;">{{ f.address or '—' }}</div>
|
<div class="text-muted" style="font-size:.82rem;">{{ f.address or '—' }}</div>
|
||||||
<div class="my-2">
|
<div class="my-2">
|
||||||
@@ -402,7 +415,49 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
{% if customer_facilities|length > 9 %}
|
||||||
|
<div id="facilityShowMore" class="text-center mt-3">
|
||||||
|
<button class="btn btn-sm btn-link text-muted" id="toggleFacilities">
|
||||||
|
Show all {{ customer_facilities|length }} facilities <i class="bi bi-chevron-down"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{# Same VISIBLE = 9 / search > 6 thresholds as the classic dashboard (rule 65). #}
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
{% if customer_facilities|length > 9 %}
|
||||||
|
var VISIBLE = 9;
|
||||||
|
var cols = document.querySelectorAll('#facilityGrid .facility-col');
|
||||||
|
var btn = document.getElementById('toggleFacilities');
|
||||||
|
var expanded = false;
|
||||||
|
|
||||||
|
cols.forEach(function (c, i) { if (i >= VISIBLE) c.style.display = 'none'; });
|
||||||
|
|
||||||
|
btn.addEventListener('click', function () {
|
||||||
|
expanded = !expanded;
|
||||||
|
cols.forEach(function (c, i) {
|
||||||
|
if (i >= VISIBLE) c.style.display = expanded ? '' : 'none';
|
||||||
|
});
|
||||||
|
btn.innerHTML = expanded
|
||||||
|
? 'Show fewer <i class="bi bi-chevron-up"></i>'
|
||||||
|
: 'Show all {{ customer_facilities|length }} facilities <i class="bi bi-chevron-down"></i>';
|
||||||
|
});
|
||||||
|
{% endif %}
|
||||||
|
{% if customer_facilities|length > 6 %}
|
||||||
|
document.getElementById('facilitySearch').addEventListener('input', function () {
|
||||||
|
var q = this.value.toLowerCase();
|
||||||
|
document.querySelectorAll('#facilityGrid .facility-col').forEach(function (col) {
|
||||||
|
var match = col.querySelector('.facility-card').textContent.toLowerCase().includes(q);
|
||||||
|
col.style.display = match ? '' : 'none';
|
||||||
|
});
|
||||||
|
var more = document.getElementById('facilityShowMore');
|
||||||
|
if (more) more.style.display = this.value ? 'none' : '';
|
||||||
|
});
|
||||||
|
{% endif %}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#}
|
#}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="jqc-page-head">
|
<div class="jqc-page-head center">
|
||||||
<div class="jqc-page-title">Facilities</div>
|
<div class="jqc-page-title">Facilities</div>
|
||||||
<div class="jqc-page-sub text-center">Manage facility records, statistics and QR access</div>
|
<div class="jqc-page-sub text-center">Manage facility records, statistics and QR access</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
{# About Us — new page (design A/B test). Linked from the modern sidebar. #}
|
{# About Us — new page (design A/B test). Linked from the modern sidebar. #}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="jqc-page-head">
|
<div class="jqc-page-head center">
|
||||||
<div class="jqc-page-title">About Us</div>
|
<div class="jqc-page-title">About Us</div>
|
||||||
<div class="jqc-page-sub text-center">Janitorial Quality Control by L.T. Services, Inc.</div>
|
<div class="jqc-page-sub text-center">Janitorial Quality Control by L.T. Services, Inc.</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#}
|
#}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="jqc-page-head">
|
<div class="jqc-page-head center">
|
||||||
<div class="jqc-page-title">Support</div>
|
<div class="jqc-page-title">Support</div>
|
||||||
<div class="jqc-page-sub text-center">JQC Features — find answers and how-to guides</div>
|
<div class="jqc-page-sub text-center">JQC Features — find answers and how-to guides</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user