Jul 22 - Initial code

This commit is contained in:
2026-07-22 14:50:16 -04:00
commit ade7c5b33c
21 changed files with 1588 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Admin{% endblock %} · JQC</title>
<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=Bricolage+Grotesque:opsz,wght@12..96,600;12..96,700&family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/admin.css') }}">
</head>
<body class="{% block body_class %}{% endblock %}">
{% if session.get('admin') %}
<nav class="anav">
<a class="anav__brand" href="{{ url_for('admin.dashboard') }}">JQC<span>admin</span></a>
<div class="anav__right">
<a class="anav__link" href="{{ url_for('index') }}" target="_blank" rel="noopener">View site ↗</a>
<span class="anav__user">{{ session.get('admin') }}</span>
<form method="post" action="{{ url_for('admin.logout') }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button class="btn btn--ghost btn--sm" type="submit">Sign out</button>
</form>
</div>
</nav>
{% endif %}
<main class="awrap">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="flashes">
{% for cat, msg in messages %}
<div class="flash flash--{{ cat }}">{{ msg }}</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</main>
</body>
</html>
+64
View File
@@ -0,0 +1,64 @@
{% extends "admin/base.html" %}
{% block title %}Dashboard{% endblock %}
{% block content %}
<header class="page-head">
<div>
<h1>Content</h1>
<p class="muted">Edit the sections and topics shown on the public site.</p>
</div>
<div class="page-head__actions">
<a class="btn btn--ghost" href="{{ url_for('admin.section_form') }}">+ Section</a>
<a class="btn btn--primary" href="{{ url_for('admin.topic_form') }}">+ Topic</a>
</div>
</header>
{% if not sections %}
<div class="empty">No sections yet. Start by adding one.</div>
{% endif %}
{% for section in sections %}
<section class="sec-card">
<div class="sec-card__head">
<div class="sec-card__meta">
<span class="pill">§{{ '%02d' % section.num }}</span>
<h2>{{ section.title }}</h2>
{% if section.subtitle %}<span class="muted">{{ section.subtitle }}</span>{% endif %}
</div>
<div class="sec-card__actions">
<a class="btn btn--ghost btn--sm" href="{{ url_for('admin.section_form', section_id=section.id) }}">Edit</a>
<a class="btn btn--ghost btn--sm" href="{{ url_for('admin.topic_form') }}?section={{ section.id }}">+ Topic</a>
<form method="post" action="{{ url_for('admin.section_delete', section_id=section.id) }}"
onsubmit="return confirm('Delete section “{{ section.title }}” and ALL its topics?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button class="btn btn--danger btn--sm" type="submit">Delete</button>
</form>
</div>
</div>
{% if section.topics %}
<ul class="topic-rows">
{% for topic in section.topics %}
<li class="topic-row">
<div class="topic-row__main">
<span class="topic-row__order">{{ topic.sort_order }}</span>
<a class="topic-row__title" href="{{ url_for('admin.topic_form', topic_id=topic.id) }}">{{ topic.title | safe }}</a>
{% if topic.media_type and topic.media_type != 'none' %}<span class="chip">{{ topic.media_type }}</span>{% endif %}
{% if topic.link_url %}<span class="chip chip--link">link</span>{% endif %}
</div>
<div class="topic-row__actions">
<a class="btn btn--ghost btn--sm" href="{{ url_for('admin.topic_form', topic_id=topic.id) }}">Edit</a>
<form method="post" action="{{ url_for('admin.topic_delete', topic_id=topic.id) }}"
onsubmit="return confirm('Delete topic “{{ topic.title }}”?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button class="btn btn--danger btn--sm" type="submit">Delete</button>
</form>
</div>
</li>
{% endfor %}
</ul>
{% else %}
<p class="muted sec-card__empty">No topics in this section yet.</p>
{% endif %}
</section>
{% endfor %}
{% endblock %}
+21
View File
@@ -0,0 +1,21 @@
{% extends "admin/base.html" %}
{% block title %}Sign in{% endblock %}
{% block body_class %}login-body{% endblock %}
{% block content %}
<div class="login-card">
<div class="login-brand">JQC<span>admin</span></div>
<p class="login-hint">Sign in to edit site content.</p>
<form method="post" action="{{ url_for('admin.login') }}" class="stack">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<label class="field">
<span>Username</span>
<input type="text" name="username" autocomplete="username" autofocus required>
</label>
<label class="field">
<span>Password</span>
<input type="password" name="password" autocomplete="current-password" required>
</label>
<button class="btn btn--primary" type="submit">Sign in</button>
</form>
</div>
{% endblock %}
+49
View File
@@ -0,0 +1,49 @@
{% extends "admin/base.html" %}
{% block title %}{{ 'Edit section' if section else 'New section' }}{% endblock %}
{% macro val(field, default='') -%}
{%- if form is not none -%}{{ form.get(field, default) }}
{%- elif section is not none -%}{{ section[field] if section[field] is not none else default }}
{%- else -%}{{ default }}{%- endif -%}
{%- endmacro %}
{% block content %}
<header class="page-head">
<div>
<h1>{{ 'Edit section' if section else 'New section' }}</h1>
<p class="muted">{{ section.title if section else 'Sections group topics on the public page.' }}</p>
</div>
<a class="btn btn--ghost" href="{{ url_for('admin.dashboard') }}">← Back</a>
</header>
<form method="post" class="form-card stack"
action="{{ url_for('admin.section_form', section_id=section.id) if section else url_for('admin.section_form') }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div class="grid-2">
<label class="field">
<span>Number * <small class="muted">(shown as §NN, must be unique)</small></span>
<input type="number" name="num" value="{{ val('num') }}" required>
</label>
<label class="field">
<span>Sort order <small class="muted">(defaults to number × 10)</small></span>
<input type="number" name="sort_order" value="{{ val('sort_order') }}" placeholder="auto">
</label>
</div>
<label class="field">
<span>Title *</span>
<input type="text" name="title" value="{{ val('title') }}" required>
</label>
<label class="field">
<span>Subtitle</span>
<input type="text" name="subtitle" value="{{ val('subtitle') }}">
</label>
<div class="form-actions">
<a class="btn btn--ghost" href="{{ url_for('admin.dashboard') }}">Cancel</a>
<button class="btn btn--primary" type="submit">Save section</button>
</div>
</form>
{% endblock %}
+101
View File
@@ -0,0 +1,101 @@
{% extends "admin/base.html" %}
{% block title %}{{ 'Edit topic' if topic else 'New topic' }}{% endblock %}
{% macro val(field, default='') -%}
{%- if form is not none -%}{{ form.get(field, default) }}
{%- elif topic is not none -%}{{ topic[field] if topic[field] is not none else default }}
{%- else -%}{{ default }}{%- endif -%}
{%- endmacro %}
{% block content %}
{% set current_section = (form.get('section_id') if form else (topic.section_id if topic else request.args.get('section'))) %}
{% set current_media = (form.get('media_type') if form else (topic.media_type if topic else 'none')) %}
<header class="page-head">
<div>
<h1>{{ 'Edit topic' if topic else 'New topic' }}</h1>
<p class="muted">{{ topic.title if topic else 'Add a new topic to a section.' }}</p>
</div>
<a class="btn btn--ghost" href="{{ url_for('admin.dashboard') }}">← Back</a>
</header>
<form method="post" class="form-card stack"
action="{{ url_for('admin.topic_form', topic_id=topic.id) if topic else url_for('admin.topic_form') }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div class="grid-2">
<label class="field">
<span>Section *</span>
<select name="section_id" required>
{% for s in sections %}
<option value="{{ s.id }}" {{ 'selected' if current_section and s.id|string == current_section|string }}>
§{{ '%02d' % s.num }} — {{ s.title }}
</option>
{% endfor %}
</select>
</label>
<label class="field">
<span>Sort order</span>
<input type="number" name="sort_order" value="{{ val('sort_order', '10') }}">
</label>
</div>
<label class="field">
<span>Title *</span>
<input type="text" name="title" value="{{ val('title') }}" required>
</label>
<label class="field">
<span>Slug <small class="muted">(optional — auto-generated from the title, must be unique)</small></span>
<input type="text" name="slug" value="{{ val('slug') }}" placeholder="auto">
</label>
<label class="field">
<span>Body <small class="muted">(HTML — use &lt;p&gt;, &lt;strong&gt;, &lt;ul&gt;&lt;li&gt;)</small></span>
<textarea name="body_html" rows="7">{{ val('body_html') }}</textarea>
</label>
<fieldset class="fieldset">
<legend>Media</legend>
<div class="grid-2">
<label class="field">
<span>Type</span>
<select name="media_type">
{% for mt in media_types %}
<option value="{{ mt }}" {{ 'selected' if mt == current_media }}>{{ mt }}</option>
{% endfor %}
</select>
</label>
<label class="field">
<span>Caption</span>
<input type="text" name="media_caption" value="{{ val('media_caption') }}">
</label>
</div>
<label class="field">
<span>Media URL</span>
<input type="text" name="media_url" value="{{ val('media_url') }}"
placeholder="/static/img/photo.jpg · /static/vid/demo.mp4 · https://www.youtube.com/embed/ID">
</label>
<p class="hint muted">image → &lt;img&gt; · video → &lt;video&gt; · embed → &lt;iframe&gt; (use a YouTube <code>/embed/</code> URL)</p>
</fieldset>
<fieldset class="fieldset">
<legend>Link button (optional)</legend>
<div class="grid-2">
<label class="field">
<span>Link URL</span>
<input type="text" name="link_url" value="{{ val('link_url') }}" placeholder="https://…">
</label>
<label class="field">
<span>Link label</span>
<input type="text" name="link_label" value="{{ val('link_label') }}" placeholder="Learn more">
</label>
</div>
</fieldset>
<div class="form-actions">
<a class="btn btn--ghost" href="{{ url_for('admin.dashboard') }}">Cancel</a>
<button class="btn btn--primary" type="submit">Save topic</button>
</div>
</form>
{% endblock %}
+110
View File
@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JQC — Janitorial Quality Control · LT Services</title>
<meta name="description" content="The features of LT Services' JQC quality control platform — inspections, real-time issue tracking, SLA alerts, and QR access.">
<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=Bricolage+Grotesque:opsz,wght@12..96,500;12..96,700;12..96,800&family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<div class="grain" aria-hidden="true"></div>
<header class="hero">
<div class="hero__inner">
<div class="hero__eyebrow">
<span class="dot"></span> LT Services · Quality Control Program
</div>
<h1 class="hero__title">JQC<span class="hero__title-sub">Janitorial Quality Control</span></h1>
<p class="hero__lede">
A closer look at what the JQC Inspector can do — a unified, paperless
program that keeps every party in the loop, on every visit.
</p>
<div class="hero__meta">
<span class="tag">iPad &amp; Web</span>
<span class="tag">Real-time</span>
<span class="tag tag--signal">SLA alerts</span>
<span class="tag">No login QR access</span>
</div>
</div>
<div class="hero__stamp" aria-hidden="true">
<span>QC</span><em>verified</em>
</div>
</header>
<main class="report">
{% for section in sections %}
<section class="block" id="section-{{ section.num }}">
<div class="block__rail">
<div class="block__num">§{{ '%02d' % section.num }}</div>
<h2 class="block__title">{{ section.title }}</h2>
{% if section.subtitle %}<p class="block__sub">{{ section.subtitle }}</p>{% endif %}
</div>
<ul class="topics" role="list">
{% for topic in section.topics %}
<li class="topic" data-topic>
<button class="topic__head" type="button"
aria-expanded="false"
aria-controls="body-{{ topic.slug }}"
id="head-{{ topic.slug }}">
<span class="topic__idx">{{ '%02d' % loop.index }}</span>
<span class="topic__title">{{ topic.title | safe }}</span>
<span class="topic__mark" aria-hidden="true">
<svg viewBox="0 0 24 24" class="ic-plus"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
<svg viewBox="0 0 24 24" class="ic-check"><polyline points="4 12 10 18 20 6"/></svg>
</span>
</button>
<div class="topic__panel" id="body-{{ topic.slug }}"
role="region" aria-labelledby="head-{{ topic.slug }}" hidden>
<div class="topic__inner">
{% if topic.body_html %}<div class="prose">{{ topic.body }}</div>{% endif %}
{% if topic.media_type == 'image' and topic.media_url %}
<figure class="media">
<img src="{{ topic.media_url }}" alt="{{ topic.media_caption or topic.title }}" loading="lazy">
{% if topic.media_caption %}<figcaption>{{ topic.media_caption }}</figcaption>{% endif %}
</figure>
{% elif topic.media_type == 'video' and topic.media_url %}
<figure class="media">
<video src="{{ topic.media_url }}" controls preload="metadata"></video>
{% if topic.media_caption %}<figcaption>{{ topic.media_caption }}</figcaption>{% endif %}
</figure>
{% elif topic.media_type == 'embed' and topic.media_url %}
<figure class="media media--embed">
<iframe src="{{ topic.media_url }}" title="{{ topic.media_caption or topic.title }}"
loading="lazy" allowfullscreen></iframe>
{% if topic.media_caption %}<figcaption>{{ topic.media_caption }}</figcaption>{% endif %}
</figure>
{% endif %}
{% if topic.link_url %}
<a class="topic__link" href="{{ topic.link_url }}" target="_blank" rel="noopener">
{{ topic.link_label or 'Learn more' }}
<svg viewBox="0 0 24 24"><path d="M7 17 17 7M9 7h8v8"/></svg>
</a>
{% endif %}
</div>
</div>
</li>
{% endfor %}
</ul>
</section>
{% endfor %}
</main>
<footer class="cta">
<div class="cta__inner">
<p class="cta__kicker">Paperless · Maintenance-free · No subscription</p>
<h2 class="cta__title">LT would be glad to run a live demonstration.</h2>
<a class="cta__btn" href="{{ demo_url }}">Request a demo</a>
</div>
<p class="cta__legal">© LT Services Inc. · JQC Quality Control Program</p>
</footer>
<script src="{{ url_for('static', filename='js/main.js') }}" defer></script>
</body>
</html>