Compare commits
2
Commits
81b2a17b37
...
571e7cb8c8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
571e7cb8c8 | ||
|
|
27b2611a20 |
+101
-83
@@ -451,7 +451,10 @@ input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: 1; }
|
||||
|
||||
/* ---------------------------------------------------------------- tables */
|
||||
|
||||
.table-wrap { overflow-x: auto; }
|
||||
.table-wrap {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
table.data {
|
||||
width: 100%;
|
||||
@@ -480,21 +483,18 @@ table.data tbody tr:hover { background: var(--bg-raised-2); }
|
||||
table.data .num { font-family: var(--mono); text-align: right; white-space: nowrap; }
|
||||
table.data .comment { color: var(--text-muted); font-size: .84rem; }
|
||||
|
||||
/* On a narrow screen the tables reflow into stacked cards.
|
||||
/* A heading that is too long for a phone column. The long form shows
|
||||
on a desktop and the short form on a phone - see the media query. */
|
||||
table.data .short { display: none; }
|
||||
table.data .advice-trigger .short { display: none; }
|
||||
|
||||
A seven-column table does not fit a phone. It was left to scroll
|
||||
sideways inside its wrapper, which meant the columns on the right were
|
||||
off the screen and the brewer had to pan the table to see them.
|
||||
/* On a narrow screen the header wraps onto two rows: the brand and the
|
||||
sign-out on the first, the nav tabs on the second where they get the
|
||||
full width.
|
||||
|
||||
Each row becomes a card: the header cell becomes a label above its
|
||||
value, and the cells stack. */
|
||||
They used to sit on one row with the brand and the sign-out, and the
|
||||
last tab was cut off mid-word. */
|
||||
@media (max-width: 720px) {
|
||||
/* The header wraps onto two rows on a phone: the brand and the
|
||||
sign-out on the first, the nav tabs on the second where they get
|
||||
the full width and scroll sideways if they still do not fit.
|
||||
|
||||
They used to sit on one row with the brand and the sign-out, and
|
||||
the last tab was cut off mid-word. */
|
||||
.topbar__inner {
|
||||
flex-wrap: wrap;
|
||||
row-gap: .5rem;
|
||||
@@ -537,79 +537,97 @@ table.data .comment { color: var(--text-muted); font-size: .84rem; }
|
||||
letter-spacing: .01em;
|
||||
}
|
||||
|
||||
/* The tables stay tables on a phone.
|
||||
|
||||
They scroll sideways inside their card, which is what a table
|
||||
does. They used to be squeezed to fit instead, and with seven
|
||||
to nine columns on a 390px screen that meant every heading and
|
||||
every value was truncated to a few characters - a gravity of
|
||||
"1.0..." and a date of "202..." are worse than useless.
|
||||
|
||||
So the columns keep their natural width, the table scrolls, and
|
||||
the advice is a small button so the column that matters is
|
||||
narrow. */
|
||||
table.data {
|
||||
table-layout: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.data th,
|
||||
table.data td {
|
||||
padding-left: .5rem;
|
||||
padding-right: .5rem;
|
||||
}
|
||||
|
||||
/* A name and a comment are words, so they get a sensible minimum
|
||||
width and wrap on a word boundary - not one word per line. */
|
||||
table.data td.col-name,
|
||||
table.data td.col-comment {
|
||||
min-width: 7rem;
|
||||
max-width: 12rem;
|
||||
white-space: normal;
|
||||
word-break: normal;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
/* The heading gets a short form, because a heading that is cut off
|
||||
is worse than a heading that is brief. */
|
||||
table.data .col-abv .long,
|
||||
table.data .col-advice .long,
|
||||
table.data .col-finished .long,
|
||||
table.data .col-comment .long {
|
||||
display: none;
|
||||
}
|
||||
|
||||
table.data .col-abv .short,
|
||||
table.data .col-advice .short,
|
||||
table.data .col-finished .short,
|
||||
table.data .col-comment .short {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* The advice trigger is small on a phone - it is a button, and
|
||||
the advice itself is in the pop-out. */
|
||||
table.data .advice-trigger {
|
||||
font-size: .68rem;
|
||||
padding: .25rem .4rem;
|
||||
gap: .2rem;
|
||||
}
|
||||
|
||||
table.data .advice-trigger .long {
|
||||
display: none;
|
||||
}
|
||||
|
||||
table.data .advice-trigger .short {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* The action column holds a button. */
|
||||
table.data .col-action {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
table.data .col-action .btn {
|
||||
padding-left: .5rem;
|
||||
padding-right: .5rem;
|
||||
font-size: .72rem;
|
||||
}
|
||||
|
||||
/* The secondary columns go away on a phone - the details are still
|
||||
on the run's own page. */
|
||||
table.data .col-drop,
|
||||
table.data .col-legacy,
|
||||
table.data .col-days {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The scroll area keeps a visible scrollbar on a phone, so it is
|
||||
obvious there is more of the table to the right. */
|
||||
.table-wrap {
|
||||
overflow-x: visible;
|
||||
scrollbar-width: thin;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
table.data,
|
||||
table.data tbody,
|
||||
table.data tr,
|
||||
table.data td {
|
||||
display: block;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
table.data thead {
|
||||
/* HIDDEN in the stacked layout. Each cell shows its column
|
||||
name as a label, so the header row would be a duplicate - and
|
||||
it was 230px of the first card. */
|
||||
display: none;
|
||||
}
|
||||
|
||||
table.data tr {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
margin-bottom: .75rem;
|
||||
padding: .25rem .1rem;
|
||||
background: var(--bg-raised-2);
|
||||
}
|
||||
|
||||
table.data tbody tr:hover {
|
||||
background: var(--bg-raised-2);
|
||||
}
|
||||
|
||||
table.data th {
|
||||
display: block;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
table.data td {
|
||||
display: grid;
|
||||
grid-template-columns: 8.5rem 1fr;
|
||||
gap: .5rem;
|
||||
align-items: baseline;
|
||||
padding: .45rem .7rem;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, .04);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
table.data td::before {
|
||||
/* The column heading, shown as the row's label. */
|
||||
content: attr(data-label);
|
||||
font-size: .65rem;
|
||||
font-weight: 650;
|
||||
letter-spacing: .07em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-faint);
|
||||
}
|
||||
|
||||
table.data td.num {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
table.data td.right,
|
||||
table.data td:empty {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
table.data td.right::before {
|
||||
content: none;
|
||||
}
|
||||
|
||||
/* A cell with nothing in it must not leave a gap. */
|
||||
table.data td:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- chips */
|
||||
|
||||
@@ -207,36 +207,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
function labelTableCells() {
|
||||
var tables = document.querySelectorAll("table.data");
|
||||
for (var t = 0; t < tables.length; t++) {
|
||||
var headerRow = tables[t].querySelector("thead tr");
|
||||
if (!headerRow) { continue; }
|
||||
var labels = [];
|
||||
var headers = headerRow.querySelectorAll("th");
|
||||
for (var h = 0; h < headers.length; h++) {
|
||||
labels.push(headers[h].textContent.trim());
|
||||
}
|
||||
|
||||
var rows = tables[t].querySelectorAll("tbody tr");
|
||||
for (var r = 0; r < rows.length; r++) {
|
||||
var cells = rows[r].querySelectorAll("td");
|
||||
for (var c = 0; c < cells.length && c < labels.length; c++) {
|
||||
if (labels[c] && !cells[c].getAttribute("data-label")) {
|
||||
cells[c].setAttribute("data-label", labels[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
focusFirstEmpty();
|
||||
defaultDateFields();
|
||||
wireToggles();
|
||||
wireConfirms();
|
||||
wireAdvicePopouts();
|
||||
labelTableCells();
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
|
||||
@@ -99,43 +99,43 @@
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Run</th>
|
||||
<th>Name</th>
|
||||
<th class="num">OG</th>
|
||||
<th class="num">FG</th>
|
||||
<th class="num">ABV</th>
|
||||
<th class="num">Attenuation</th>
|
||||
<th class="num">Days</th>
|
||||
<th class="num">To 1.010</th>
|
||||
<th>Finished</th>
|
||||
<th class="col-run">Run</th>
|
||||
<th class="col-name">Name</th>
|
||||
<th class="num col-gravity">OG</th>
|
||||
<th class="num col-gravity">FG</th>
|
||||
<th class="num col-abv">ABV</th>
|
||||
<th class="num col-abv" title="Attenuation"><span class="long">Attenuation</span><span class="short">Att.</span></th>
|
||||
<th class="num col-abv col-days">Days</th>
|
||||
<th class="num col-abv" title="Days to reach 1.010"><span class="long">To 1.010</span><span class="short">1.010</span></th>
|
||||
<th class="col-finished" title="Finished"><span class="long">Finished</span><span class="short">Done</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in rows %}
|
||||
<tr{% if row.suspect %} class="is-suspect"{% endif %}>
|
||||
<td class="mono">{{ row.beer_run_id }}</td>
|
||||
<td>{{ row.name }}{% if row.suspect %} <span class="chip chip--warn">not counted</span>{% endif %}</td>
|
||||
<td class="num">
|
||||
<td class="col-run mono">{{ row.beer_run_id }}</td>
|
||||
<td class="col-name">{{ row.name }}{% if row.suspect %} <span class="chip chip--warn">not counted</span>{% endif %}</td>
|
||||
<td class="col-gravity num">
|
||||
{% if row.og_points is not none %}
|
||||
{{ '%.3f' % (row.og_points / 1000) }}
|
||||
{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="num">
|
||||
<td class="col-gravity num">
|
||||
{% if row.fg_points is not none %}
|
||||
{{ '%.3f' % (row.fg_points / 1000) }}
|
||||
{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="num">
|
||||
<td class="col-abv num">
|
||||
{% if row.abv is not none %}{{ '%.2f' % row.abv }}%{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="num">
|
||||
<td class="col-abv num">
|
||||
{% if row.attenuation is not none %}
|
||||
<strong>{{ row.attenuation }}%</strong>
|
||||
{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="num">{{ row.days if row.days is not none else '—' }}</td>
|
||||
<td class="num">{{ row.days_to_1010 if row.days_to_1010 is not none else '—' }}</td>
|
||||
<td class="mono nowrap">{{ row.final_date or '—' }}</td>
|
||||
<td class="col-abv col-days num">{{ row.days if row.days is not none else '—' }}</td>
|
||||
<td class="col-abv num">{{ row.days_to_1010 if row.days_to_1010 is not none else '—' }}</td>
|
||||
<td class="col-finished mono nowrap">{{ row.final_date or '—' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@@ -155,21 +155,21 @@
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Run</th>
|
||||
<th class="num">OG</th>
|
||||
<th class="num">FG</th>
|
||||
<th>Problem</th>
|
||||
<th class="col-run">Run</th>
|
||||
<th class="num col-gravity">OG</th>
|
||||
<th class="num col-gravity">FG</th>
|
||||
<th class="col-comment">Problem</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in suspect %}
|
||||
<tr>
|
||||
<td class="mono">
|
||||
<td class="col-run mono">
|
||||
<a href="{{ url_for('brews.run_detail', run_id=row.beer_run_id) }}">{{ row.beer_run_id }}</a>
|
||||
</td>
|
||||
<td class="num">{{ '%.3f' % (row.og_points / 1000) }}</td>
|
||||
<td class="num"><span class="chip chip--warn">{{ '%.3f' % (row.fg_points / 1000) }}</span></td>
|
||||
<td class="comment">{{ row.problem }}</td>
|
||||
<td class="col-gravity num">{{ '%.3f' % (row.og_points / 1000) }}</td>
|
||||
<td class="col-gravity num"><span class="chip chip--warn">{{ '%.3f' % (row.fg_points / 1000) }}</span></td>
|
||||
<td class="col-comment comment">{{ row.problem }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@@ -78,48 +78,52 @@
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Run</th>
|
||||
<th>Name</th>
|
||||
<th class="num">Gravity</th>
|
||||
<th class="num">Est. ABV</th>
|
||||
<th>Comment</th>
|
||||
<th>Brewing advice</th>
|
||||
<th></th>
|
||||
<th class="col-run">Run</th>
|
||||
<th class="col-name">Name</th>
|
||||
<th class="num col-gravity">Gravity</th>
|
||||
<th class="num col-abv" title="Estimated alcohol by volume"><span class="long">Est. ABV</span><span class="short">ABV</span></th>
|
||||
<th class="col-comment" title="Comment"><span class="long">Comment</span><span class="short">Note</span></th>
|
||||
<th class="col-advice" title="Brewing advice"><span class="long">Brewing advice</span><span class="short">Advice</span></th>
|
||||
<th class="col-action"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for run in active_runs %}
|
||||
<tr>
|
||||
<td class="mono">{{ run.beer_run_id }}</td>
|
||||
<td>{{ run.canonical_name }}</td>
|
||||
<td class="num">
|
||||
<td class="mono col-run">{{ run.beer_run_id }}</td>
|
||||
<td class="col-name">{{ run.canonical_name }}</td>
|
||||
<td class="num col-gravity">
|
||||
{% if run.min_sg is not none %}
|
||||
<span class="mono strong">{{ run.min_sg_decimal }}</span>
|
||||
<div class="faint tiny">{{ run.min_sg_point_scale }} points</div>
|
||||
<div class="faint tiny point-scale">{{ run.min_sg_point_scale }} points</div>
|
||||
{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="num">
|
||||
<td class="num col-abv">
|
||||
{% if run.projected_abv is not none %}
|
||||
{{ '%.2f' % run.projected_abv }}%
|
||||
{% else %}
|
||||
<span class="faint" title="Record another reading, or set the original gravity, to get an estimate">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="comment">
|
||||
<td class="comment col-comment">
|
||||
{% if run.comments %}
|
||||
{{ run.comments[-1] }}
|
||||
{% else %}
|
||||
<span class="faint">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="advice-cell">
|
||||
<td class="advice-cell col-advice">
|
||||
{% if run.advice %}
|
||||
<button type="button"
|
||||
class="advice-trigger{% if not run.advice_ok %} advice-trigger--failed{% endif %}"
|
||||
aria-expanded="false">
|
||||
<span class="advice-trigger__icon" aria-hidden="true">✎</span>
|
||||
<span class="advice-trigger__label">
|
||||
{% if run.advice_ok %}Read the advice{% else %}Advice failed{% endif %}
|
||||
{% if run.advice_ok %}
|
||||
<span class="long">Read the advice</span><span class="short">Advice</span>
|
||||
{% else %}
|
||||
<span class="long">Advice failed</span><span class="short">Failed</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</button>
|
||||
<div class="advice-pop" role="tooltip">
|
||||
@@ -134,7 +138,7 @@
|
||||
<span class="faint">Thinking…</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="right">
|
||||
<td class="right col-action">
|
||||
<a class="btn btn--ghost btn--sm"
|
||||
href="{{ url_for('brews.run_detail', run_id=run.beer_run_id) }}">Open</a>
|
||||
</td>
|
||||
@@ -163,41 +167,41 @@
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Run</th>
|
||||
<th>Name</th>
|
||||
<th class="num">OG</th>
|
||||
<th class="num">FG</th>
|
||||
<th class="num">ABV</th>
|
||||
<th>Finished</th>
|
||||
<th>Comment</th>
|
||||
<th></th>
|
||||
<th class="col-run">Run</th>
|
||||
<th class="col-name">Name</th>
|
||||
<th class="num col-gravity">OG</th>
|
||||
<th class="num col-gravity">FG</th>
|
||||
<th class="num col-abv">ABV</th>
|
||||
<th class="col-finished" title="Finished"><span class="long">Finished</span><span class="short">Done</span></th>
|
||||
<th class="col-comment" title="Comment"><span class="long">Comment</span><span class="short">Note</span></th>
|
||||
<th class="col-action"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for run in completed_runs %}
|
||||
<tr>
|
||||
<td class="mono">{{ run.beer_run_id }}</td>
|
||||
<td>{{ run.canonical_name }}</td>
|
||||
<td class="num">
|
||||
<td class="mono col-run">{{ run.beer_run_id }}</td>
|
||||
<td class="col-name">{{ run.canonical_name }}</td>
|
||||
<td class="num col-gravity">
|
||||
{% if run.og_points is not none %}{{ run.og_points }}{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="num">
|
||||
<td class="num col-gravity">
|
||||
{% if run.fg_points is not none %}{{ run.fg_points }}{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="num">
|
||||
<td class="num col-abv">
|
||||
{% if run.abv is not none %}
|
||||
<strong>{{ '%.2f' % run.abv }}%</strong>
|
||||
{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="mono nowrap">{{ run.final_date or '—' }}</td>
|
||||
<td class="comment">
|
||||
<td class="mono nowrap col-finished">{{ run.final_date or '—' }}</td>
|
||||
<td class="comment col-comment">
|
||||
{% if run.comments %}
|
||||
{{ run.comments[-1] }}
|
||||
{% else %}
|
||||
<span class="faint">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="right">
|
||||
<td class="right col-action">
|
||||
<a class="btn btn--ghost btn--sm"
|
||||
href="{{ url_for('brews.run_detail', run_id=run.beer_run_id) }}">Open</a>
|
||||
</td>
|
||||
|
||||
@@ -84,21 +84,21 @@
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Run</th>
|
||||
<th>Name</th>
|
||||
<th>Date</th>
|
||||
<th class="num">Reading</th>
|
||||
<th>Comment</th>
|
||||
<th class="col-run">Run</th>
|
||||
<th class="col-name">Name</th>
|
||||
<th class="col-finished">Date</th>
|
||||
<th class="num col-gravity">Reading</th>
|
||||
<th class="col-comment" title="Comment"><span class="long">Comment</span><span class="short">Note</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in outliers %}
|
||||
<tr>
|
||||
<td class="mono">{{ row.beer_run_id }}</td>
|
||||
<td>{{ row.name }}</td>
|
||||
<td class="mono nowrap">{{ row.date or '—' }}</td>
|
||||
<td class="num"><span class="chip chip--warn">{{ row.sg }}</span></td>
|
||||
<td class="comment">{{ row.comment or '—' }}</td>
|
||||
<td class="col-run mono">{{ row.beer_run_id }}</td>
|
||||
<td class="col-name">{{ row.name }}</td>
|
||||
<td class="col-finished mono nowrap">{{ row.date or '—' }}</td>
|
||||
<td class="col-gravity num"><span class="chip chip--warn">{{ row.sg }}</span></td>
|
||||
<td class="col-comment comment">{{ row.comment or '—' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@@ -118,45 +118,45 @@
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Run</th>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
<th class="num">OG</th>
|
||||
<th class="num">FG</th>
|
||||
<th class="num">Drop</th>
|
||||
<th class="num">ABV</th>
|
||||
<th class="num">Legacy</th>
|
||||
<th>Finished</th>
|
||||
<th>Comment</th>
|
||||
<th></th>
|
||||
<th class="col-run">Run</th>
|
||||
<th class="col-name">Name</th>
|
||||
<th class="col-finished" title="Status"><span class="long">Status</span><span class="short">Stat</span></th>
|
||||
<th class="num col-gravity">OG</th>
|
||||
<th class="num col-gravity">FG</th>
|
||||
<th class="num col-drop">Drop</th>
|
||||
<th class="num col-abv">ABV</th>
|
||||
<th class="num col-legacy">Legacy</th>
|
||||
<th class="col-finished" title="Finished"><span class="long">Finished</span><span class="short">Done</span></th>
|
||||
<th class="col-comment" title="Comment"><span class="long">Comment</span><span class="short">Note</span></th>
|
||||
<th class="col-action"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for run in summaries %}
|
||||
<tr>
|
||||
<td class="mono">{{ run.beer_run_id }}</td>
|
||||
<td>{{ run.canonical_name }}</td>
|
||||
<td>
|
||||
<td class="col-run mono">{{ run.beer_run_id }}</td>
|
||||
<td class="col-name">{{ run.canonical_name }}</td>
|
||||
<td class="col-finished">
|
||||
{% if run.active %}
|
||||
<span class="chip chip--active">Active</span>
|
||||
{% else %}
|
||||
<span class="chip chip--done">Finished</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="num">{{ run.og_points or '—' }}</td>
|
||||
<td class="num">{{ run.fg_points or '—' }}</td>
|
||||
<td class="num">{{ run.drop_points if run.drop_points is not none else '—' }}</td>
|
||||
<td class="num">
|
||||
<td class="col-drop col-gravity num">{{ run.og_points or '—' }}</td>
|
||||
<td class="col-gravity num">{{ run.fg_points or '—' }}</td>
|
||||
<td class="col-gravity num">{{ run.drop_points if run.drop_points is not none else '—' }}</td>
|
||||
<td class="col-abv num">
|
||||
{% if run.abv is not none %}<strong>{{ '%.2f' % run.abv }}%</strong>
|
||||
{% elif run.projected_abv is not none %}{{ '%.2f' % run.projected_abv }}%*
|
||||
{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="num muted">{{ run.legacy_abv if run.legacy_abv is not none else '—' }}</td>
|
||||
<td class="mono nowrap">{{ run.final_date or '—' }}</td>
|
||||
<td class="comment">
|
||||
<td class="col-legacy col-abv num muted">{{ run.legacy_abv if run.legacy_abv is not none else '—' }}</td>
|
||||
<td class="col-finished mono nowrap">{{ run.final_date or '—' }}</td>
|
||||
<td class="col-comment comment">
|
||||
{% if run.comments %}{{ run.comments[-1] }}{% else %}<span class="faint">—</span>{% endif %}
|
||||
</td>
|
||||
<td class="right">
|
||||
<td class="right col-action">
|
||||
<a class="btn btn--ghost btn--sm"
|
||||
href="{{ url_for('brews.run_detail', run_id=run.beer_run_id) }}">Open</a>
|
||||
</td>
|
||||
@@ -178,29 +178,29 @@
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Run</th>
|
||||
<th>Name</th>
|
||||
<th class="num">Standard ABV</th>
|
||||
<th class="num">Legacy ABV</th>
|
||||
<th class="num">Overstated by</th>
|
||||
<th>Finished</th>
|
||||
<th class="col-run">Run</th>
|
||||
<th class="col-name">Name</th>
|
||||
<th class="num col-abv" title="Standard ABV"><span class="long">Standard ABV</span><span class="short">Std</span></th>
|
||||
<th class="num col-legacy col-abv" title="Legacy ABV"><span class="long">Legacy ABV</span><span class="short">Old</span></th>
|
||||
<th class="num col-abv" title="Overstated by"><span class="long">Overstated by</span><span class="short">Over</span></th>
|
||||
<th class="col-finished" title="Finished"><span class="long">Finished</span><span class="short">Done</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in abv_rows %}
|
||||
<tr>
|
||||
<td class="mono">{{ row.beer_run_id }}</td>
|
||||
<td>{{ row.name }}</td>
|
||||
<td class="num">{{ '%.2f' % row.abv }}%</td>
|
||||
<td class="num muted">{{ '%.2f' % row.legacy_abv }}%</td>
|
||||
<td class="num">
|
||||
<td class="col-run mono">{{ row.beer_run_id }}</td>
|
||||
<td class="col-name">{{ row.name }}</td>
|
||||
<td class="col-abv num">{{ '%.2f' % row.abv }}%</td>
|
||||
<td class="col-abv num muted">{{ '%.2f' % row.legacy_abv }}%</td>
|
||||
<td class="col-abv num">
|
||||
{% if row.delta > 0 %}
|
||||
<span class="chip chip--warn">+{{ '%.2f' % row.delta }}</span>
|
||||
{% else %}
|
||||
<span class="faint">{{ '%.2f' % row.delta }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="mono nowrap">{{ row.final_date or '—' }}</td>
|
||||
<td class="col-finished mono nowrap">{{ row.final_date or '—' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@@ -1024,6 +1024,31 @@ def test_the_advice_in_the_table_is_a_popout_not_the_text(client, repo):
|
||||
assert "Warm it to 21C and wait." in body
|
||||
|
||||
|
||||
def test_the_tables_keep_their_columns_on_a_phone(client, repo):
|
||||
"""The tables are readable on a phone, not squeezed into nothing.
|
||||
|
||||
The advice is a button and the table scrolls, so nothing is
|
||||
truncated to an unreadable stub.
|
||||
"""
|
||||
repo.users.insert_one({"username": "beer", "password": "beer_pass"})
|
||||
client.post("/login", data={"username": "beer", "password": "beer_pass"},
|
||||
follow_redirects=True)
|
||||
|
||||
seed_readings(repo, [("1", "Cider raspberry elderberry", "1045", "2026-01-01", False, "")])
|
||||
doc = repo.readings.find_one({"beer_run_id": "1"})
|
||||
repo.set_reading_advice(str(doc["_id"]), "Warm it to 21C and wait.", ok=True)
|
||||
|
||||
body = client.get("/brews").get_data(as_text=True)
|
||||
|
||||
# The long heading has a short form for a phone, and the long form
|
||||
# is still in the page for a desktop.
|
||||
assert "Brewing advice" in body
|
||||
assert ">Advice<" in body.replace("\n", "")
|
||||
|
||||
# The beer name is not truncated in the markup.
|
||||
assert "Cider raspberry elderberry" in body
|
||||
|
||||
|
||||
def test_a_failed_advice_is_marked_as_such(client, repo):
|
||||
"""A generation failure reads differently from real advice."""
|
||||
repo.users.insert_one({"username": "beer", "password": "beer_pass"})
|
||||
|
||||
Reference in New Issue
Block a user