Web dashboard step 2: full issue pages, article chapters, POST /rate
Signed-in issue page with the Brief, downloads, index and colophon; article, World Briefing and Behind the paper pages under the login guard; the rating widget with its fetch enhancement; the admin-only POST /rate writing dashboard-attributed rating events; the HMAC confirmation page links to the site. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NHyYupFdBiR4VfoUM7NjSM
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
<form class="rating" method="post" action="/rate">
|
||||
<input type="hidden" name="article_id" value="{{ widget.article_id }}">
|
||||
<input type="hidden" name="issue_date" value="{{ widget.issue_date }}">
|
||||
<input type="hidden" name="next" value="{{ widget.next }}">
|
||||
<span class="rating-prompt">Was this a good pick?</span>
|
||||
<button type="submit" name="label" value="loved" data-label="loved"{% if widget.current == "loved" %} class="active" aria-pressed="true"{% else %} aria-pressed="false"{% endif %}>Loved it</button>
|
||||
<button type="submit" name="label" value="good" data-label="good"{% if widget.current == "good" %} class="active" aria-pressed="true"{% else %} aria-pressed="false"{% endif %}>Good</button>
|
||||
<button type="submit" name="label" value="down" data-label="down"{% if widget.current == "down" %} class="active" aria-pressed="true"{% else %} aria-pressed="false"{% endif %}>Not for me</button>
|
||||
{% if widget.show_note %}<label class="rating-note">Note <input name="note"></label>{% endif %}
|
||||
<button class="clear{% if widget.current == "cleared" %} active{% endif %}" type="submit" name="label" value="cleared" data-label="cleared"{% if widget.current == "cleared" %} aria-pressed="true"{% else %} aria-pressed="false"{% endif %}>clear</button>
|
||||
</form>
|
||||
@@ -0,0 +1,20 @@
|
||||
{% extends "layout.html" %}{% block content %}<article class="reading article-page">
|
||||
<header class="article-header">
|
||||
<h1><a href="{{ source_url }}">{{ title }}</a></h1>
|
||||
{% match byline %}{% when Some with (byline) %}<p class="byline">{{ byline }}</p>{% when None %}{% endmatch %}
|
||||
<p class="meta">{{ meta_line }}</p>
|
||||
{% match why %}{% when Some with (why) %}<p class="why"><em>Why it's here: {{ why }}</em></p>{% when None %}{% endmatch %}
|
||||
{% match social_line %}{% when Some with (social) %}<p class="social">{{ social }}</p>{% when None %}{% endmatch %}
|
||||
{% match summary %}{% when Some with (summary) %}<p class="summary">{{ summary }}</p>{% when None %}{% endmatch %}
|
||||
{% if excerpt_only %}<p class="notice">(excerpt only — read online)</p>{% endif %}
|
||||
</header>
|
||||
<hr class="rule">
|
||||
<div class="article-body">{{ body_html|safe }}</div>
|
||||
{% match discussion_html %}{% when Some with (discussion) %}<section class="discussion"><h2>Discussion</h2>{{ discussion|safe }}</section>{% when None %}{% endmatch %}
|
||||
<footer class="article-footer">
|
||||
{% match rating %}{% when Some with (widget) %}{% include "_rating_widget.html" %}{% when None %}{% endmatch %}
|
||||
<p><a href="{{ read_online_url }}">Read online ↗</a></p>
|
||||
<nav class="prev-next">{% match previous %}{% when Some with (previous) %}<a rel="prev" href="{{ previous.href }}">← {{ previous.title }}</a>{% when None %}<span></span>{% endmatch %}{% match next %}{% when Some with (next) %}<a rel="next" href="{{ next.href }}">{{ next.title }} →</a>{% when None %}{% endmatch %}</nav>
|
||||
<p><a href="{{ issue_href }}">← Back to this issue</a></p>
|
||||
</footer>
|
||||
</article>{% endblock %}
|
||||
@@ -0,0 +1,7 @@
|
||||
{% extends "layout.html" %}{% block content %}<article class="reading behind">
|
||||
<h1>Behind the paper</h1>
|
||||
<p class="fact-line">{{ summary_line }}</p><p class="fact-line">{{ admitted_line }}</p><p class="fact-line">{{ learned_line }}</p>
|
||||
<h2>Near misses</h2><p><em>Highest utility not selected.</em></p>
|
||||
{% if near_misses.is_empty() %}<p>None recorded for this run.</p>{% else %}<ul class="near-misses">{% for near_miss in near_misses %}<li>{% if page.is_admin() %}<a href="/dashboard/articles/{{ near_miss.article_id }}">{{ near_miss.line }}</a>{% else %}{{ near_miss.line }}{% endif %}</li>{% endfor %}</ul>{% endif %}
|
||||
<p class="fact-line">{{ models_line }}</p><p><a href="{{ issue_href }}">← Back to this issue</a></p>
|
||||
</article>{% endblock %}
|
||||
@@ -0,0 +1,33 @@
|
||||
{% extends "layout.html" %}{% block content %}<article class="reading issue full-issue">
|
||||
<p class="dateline">{{ display_date }} · No. {{ issue_number }}</p>
|
||||
<p class="stats">{{ stats_line }}</p>
|
||||
<hr class="rule">
|
||||
<h1 class="kicker">The Brief</h1>
|
||||
<div class="editorial">{{ front_page_html|safe }}</div>
|
||||
{% if !downloads.is_empty() %}<p class="downloads">{% for download in downloads %}<a class="button" href="{{ download.href }}">Download {{ download.label }} <small>({{ download.size_bytes }} bytes)</small></a>{% endfor %}</p>{% endif %}
|
||||
<hr class="rule">
|
||||
<h1>In This Issue</h1>
|
||||
{% for section in sections %}<section><h2>{{ section.name }}</h2><ul class="index-list">{% for entry in section.entries %}<li class="index-entry">
|
||||
<h3><a href="{{ entry.href }}">{{ entry.title }}</a></h3>
|
||||
<p class="index-meta">{{ entry.source }} · {{ entry.reading_minutes }} min read</p>
|
||||
{% if !entry.summary.is_empty() %}<p class="index-summary">{{ entry.summary }}</p>{% endif %}
|
||||
{% match entry.why %}{% when Some with (why) %}<p class="index-why"><em>Why it's here: {{ why }}</em></p>{% when None %}{% endmatch %}
|
||||
{% match entry.rating %}{% when Some with (widget) %}{% include "_rating_widget.html" %}{% when None %}{% endmatch %}
|
||||
</li>{% endfor %}</ul></section>{% endfor %}
|
||||
{% if has_world || has_behind %}<nav class="issue-chapters">{% if has_world %}<a href="/issues/{{ date }}/world">World Briefing</a>{% endif %}{% if has_world && has_behind %} · {% endif %}{% if has_behind %}<a href="/issues/{{ date }}/behind">Behind the paper</a>{% endif %}</nav>{% endif %}
|
||||
<footer class="colophon"><h2>Colophon</h2>
|
||||
<p><em>The Daily EPUB</em> is assembled every morning from a personal feed reader.</p>
|
||||
<dl class="kv">
|
||||
<dt>Generated</dt><dd>{{ colophon.generated_at }}</dd>
|
||||
<dt>Bulk model</dt><dd>{{ colophon.bulk_model }}</dd>
|
||||
<dt>Editor model</dt><dd>{{ colophon.editor_model }}</dd>
|
||||
<dt>Summaries model</dt><dd>{{ colophon.summaries_model }}</dd>
|
||||
<dt>Entries considered</dt><dd>{{ colophon.entries_fetched }} from {{ colophon.feeds_seen }} feeds</dd>
|
||||
<dt>Candidates scored</dt><dd>{{ colophon.candidates }}</dd>
|
||||
<dt>Articles selected</dt><dd>{{ colophon.article_count }} across {{ colophon.section_count }} sections</dd>
|
||||
<dt>Words</dt><dd>{{ colophon.total_words }} · ~{{ colophon.reading_minutes }} min read</dd>
|
||||
{% for cost in colophon.provider_costs %}<dt>{{ cost.provider }} cost</dt><dd>{{ cost.cost }}</dd>{% endfor %}
|
||||
<dt>Total token cost</dt><dd>{{ colophon.cost_usd }}</dd>
|
||||
<dt>Generator</dt><dd>{{ colophon.generator_version }}</dd>
|
||||
</dl></footer>
|
||||
</article>{% endblock %}
|
||||
@@ -0,0 +1,5 @@
|
||||
{% extends "layout.html" %}{% block content %}<article class="reading world-briefing">
|
||||
<h1>World Briefing</h1><p class="dateline">{{ display_date }}</p><hr class="rule">
|
||||
<div class="world-body">{{ body_html|safe }}</div>
|
||||
<p><a href="{{ issue_href }}">← Back to this issue</a></p>
|
||||
</article>{% endblock %}
|
||||
Reference in New Issue
Block a user