mirror of
https://github.com/svemagie/indiekit-endpoint-blogroll.git
synced 2026-04-02 15:34:59 +02:00
- Extract ~560 lines of inline CSS to external assets/styles.css - Create intermediate layout (layouts/blogroll.njk) for CSS loading - Use section(), badge(), button(), prose() macros instead of raw HTML - Remove custom page headers (document.njk heading() handles via title/parent) - Add parent breadcrumb navigation to all sub-pages - Add consumeFlashMessage() to dashboard and sources controllers - Rename CSS class prefix from br-* to blogroll-* for clarity - Use upstream CSS custom properties without fallback values - Fix Microsub orphan detection (soft-delete unsubscribed blogs) - Fix upsert to conditionally set microsub fields (avoid path conflicts) - Skip soft-deleted blogs during clear-and-resync Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
117 lines
5.1 KiB
Plaintext
117 lines
5.1 KiB
Plaintext
{% extends "layouts/blogroll.njk" %}
|
|
|
|
{% block blogroll %}
|
|
{% call section({ title: __("blogroll.stats.title") }) %}
|
|
<dl class="blogroll-stats">
|
|
<div class="blogroll-stat">
|
|
<dt>{{ __("blogroll.stats.sources") }}</dt>
|
|
<dd>{{ stats.sources }}</dd>
|
|
</div>
|
|
<div class="blogroll-stat">
|
|
<dt>{{ __("blogroll.stats.blogs") }}</dt>
|
|
<dd>{{ stats.blogs }}</dd>
|
|
</div>
|
|
<div class="blogroll-stat">
|
|
<dt>{{ __("blogroll.stats.items") }}</dt>
|
|
<dd>{{ stats.items }}</dd>
|
|
</div>
|
|
<div class="blogroll-stat">
|
|
<dt>{{ __("blogroll.stats.errors") }}</dt>
|
|
<dd class="{% if stats.errors > 0 %}blogroll-stat--error{% endif %}">{{ stats.errors }}</dd>
|
|
</div>
|
|
<div class="blogroll-stat">
|
|
<dt>{{ __("blogroll.stats.lastSync") }}</dt>
|
|
<dd>{% if syncStatus.lastSync %}{{ syncStatus.lastSync | date("PPpp") }}{% else %}{{ __("blogroll.never") }}{% endif %}</dd>
|
|
</div>
|
|
</dl>
|
|
<div class="blogroll-actions">
|
|
{{ button({ href: baseUrl + "/sources", text: __("blogroll.sources.manage"), classes: "button--secondary" }) }}
|
|
{{ button({ href: baseUrl + "/blogs", text: __("blogroll.blogs.manage"), classes: "button--secondary" }) }}
|
|
</div>
|
|
{% endcall %}
|
|
|
|
{% call section({ title: __("blogroll.actions.title") }) %}
|
|
<div class="blogroll-actions">
|
|
<form method="post" action="{{ baseUrl }}/sync" style="display: inline;">
|
|
{{ button({ type: "submit", text: __("blogroll.actions.syncNow") }) }}
|
|
</form>
|
|
<form method="post" action="{{ baseUrl }}/clear-resync" style="display: inline;" onsubmit="return confirm('{{ __("blogroll.actions.clearConfirm") }}');">
|
|
{{ button({ type: "submit", text: __("blogroll.actions.clearResync"), classes: "button--secondary" }) }}
|
|
</form>
|
|
</div>
|
|
{% endcall %}
|
|
|
|
{% if blogsWithErrors.length > 0 %}
|
|
{% call section({ title: __("blogroll.errors.title") }) %}
|
|
<ul class="blogroll-list">
|
|
{% for blog in blogsWithErrors %}
|
|
<li class="blogroll-list__item blogroll-list__item--compact">
|
|
<div>
|
|
<span class="blogroll-item__title">{{ blog.title }}</span>
|
|
<span class="blogroll-item__error">{{ blog.lastError }}</span>
|
|
</div>
|
|
{{ button({ href: baseUrl + "/blogs/" + blog._id, text: __("blogroll.edit"), classes: "button--small button--secondary" }) }}
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
{% if stats.errors > blogsWithErrors.length %}
|
|
<p class="blogroll-empty">
|
|
<a href="{{ baseUrl }}/blogs?status=error">{{ __("blogroll.errors.seeAll", { count: stats.errors }) }}</a>
|
|
</p>
|
|
{% endif %}
|
|
{% endcall %}
|
|
{% endif %}
|
|
|
|
{% call section({ title: __("blogroll.sources.recent") }) %}
|
|
{% if sources.length > 0 %}
|
|
<ul class="blogroll-list">
|
|
{% for source in sources %}
|
|
<li class="blogroll-list__item blogroll-list__item--compact">
|
|
<div>
|
|
<span class="blogroll-item__title">{{ source.name }}</span>
|
|
<span class="blogroll-item__meta">{{ source.type }} · {% if source.lastSyncAt %}{{ source.lastSyncAt | date("PP") }}{% else %}{{ __("blogroll.never") }}{% endif %}</span>
|
|
</div>
|
|
{{ badge({ color: "green" if source.enabled else "yellow", text: __("blogroll.enabled") if source.enabled else __("blogroll.disabled") }) }}
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
{% else %}
|
|
{{ prose({ text: __("blogroll.sources.empty") }) }}
|
|
{% endif %}
|
|
<div class="blogroll-actions">
|
|
{{ button({ href: baseUrl + "/sources/new", text: __("blogroll.sources.add"), classes: "button--secondary button--small" }) }}
|
|
</div>
|
|
{% endcall %}
|
|
|
|
{% call section({ title: __("blogroll.blogs.recent") }) %}
|
|
{% if recentBlogs.length > 0 %}
|
|
<ul class="blogroll-list">
|
|
{% for blog in recentBlogs %}
|
|
<li class="blogroll-list__item blogroll-list__item--compact">
|
|
<div>
|
|
<span class="blogroll-item__title">{{ blog.title }}</span>
|
|
<span class="blogroll-item__meta">{{ blog.category or "Uncategorized" }} · {{ blog.itemCount }} items</span>
|
|
</div>
|
|
{{ badge({ color: "green" if blog.status == "active" else ("red" if blog.status == "error" else "yellow"), text: blog.status }) }}
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
{% else %}
|
|
{{ prose({ text: __("blogroll.blogs.empty") }) }}
|
|
{% endif %}
|
|
<div class="blogroll-actions">
|
|
{{ button({ href: baseUrl + "/blogs/new", text: __("blogroll.blogs.add"), classes: "button--secondary button--small" }) }}
|
|
</div>
|
|
{% endcall %}
|
|
|
|
{% call section({ title: __("blogroll.api.title") }) %}
|
|
<ul class="blogroll-api-list">
|
|
<li><code>GET {{ baseUrl }}/api/blogs</code> - {{ __("blogroll.api.blogs") }}</li>
|
|
<li><code>GET {{ baseUrl }}/api/items</code> - {{ __("blogroll.api.items") }}</li>
|
|
<li><code>GET {{ baseUrl }}/api/categories</code> - {{ __("blogroll.api.categories") }}</li>
|
|
<li><code>GET {{ baseUrl }}/api/opml</code> - {{ __("blogroll.api.opml") }}</li>
|
|
<li><code>GET {{ baseUrl }}/api/status</code> - {{ __("blogroll.api.status") }}</li>
|
|
</ul>
|
|
{% endcall %}
|
|
{% endblock %}
|