1
0
This repository has been archived on 2026-03-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Timmy-time-dashboard/src/dashboard/templates/marketplace.html
Alexander Whitestone 622a6a9204 polish: extract inline CSS, add connection status, panel macro, favicon, ollama cache, toast system (#164)
Major:
- Extract all inline <style> blocks from 22 Jinja2 templates into
  static/css/mission-control.css — single cacheable stylesheet
- Add tox lint check that fails on inline <style> in templates

Minor:
1. Connection status indicator in topbar (green/amber/red dot) reflecting
   WebSocket + Ollama reachability, with auto-reconnect
2. Jinja2 {% macro panel(title) %} in macros.html — eliminates repeated
   .card.mc-panel markup; index.html converted as example
3. SVG favicon (purple T + orange dot)
4. 30-second TTL cache on _check_ollama() to avoid blocking the event loop
   on every health poll (asyncio.to_thread was already in place)
5. Toast notification system (McToast.show) for transient status messages —
   wired into connection status for Ollama/WebSocket state changes

Enforcement:
- CLAUDE.md updated with conventions 11-14 (no inline CSS, use panel macro,
  use toasts, never block the event loop)
- tox lint + pre-push environments now fail on inline <style> blocks

https://claude.ai/code/session_014FQ785MQdyJQ4BAXrRSo9w

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-11 09:52:57 -04:00

99 lines
4.0 KiB
HTML

{% extends "base.html" %}
{% block title %}{{ page_title }}{% endblock %}
{% block extra_styles %}{% endblock %}
{% block content %}
<div class="market-container py-3">
<div class="market-header">
<div class="market-title">AGENT MARKETPLACE</div>
<div class="market-subtitle">Hire agents with Bitcoin. Lowest bid wins.</div>
<div class="market-stats">
<span class="up">{{ active_count }}</span> active &middot;
<span>{{ planned_count }}</span> planned
</div>
</div>
<div class="card mc-panel">
<div class="card-header mc-panel-header">// AVAILABLE AGENTS</div>
<div class="card-body">
{% if agents %}
{% for agent in agents %}
<div class="market-agent">
<div class="agent-avatar">{{ agent.name[0] }}</div>
<div class="agent-info" style="flex:1; min-width:0;">
<div class="agent-name">
{{ agent.name | e }}
<span style="font-size:0.7rem; font-weight:400; color:var(--text-dim); margin-left:6px;">{{ agent.role | e }}</span>
</div>
<div class="agent-meta">{{ (agent.description or 'No description') | e }}</div>
<div class="agent-meta" style="margin-top:4px; display:flex; gap:4px; flex-wrap:wrap;">
<span class="badge badge-{{ 'success' if agent.status == 'idle' else 'warning' if agent.status == 'busy' else 'danger' if agent.status == 'offline' else 'secondary' }}">
{{ agent.status }}
</span>
{% if agent.capabilities %}
{% for cap in agent.capabilities.split(',') %}
<span class="badge badge-secondary">{{ cap.strip() | e }}</span>
{% endfor %}
{% endif %}
</div>
</div>
<div class="market-agent-price">
<div class="price-amount">{% if agent.rate_sats == 0 %}FREE{% else %}{{ agent.rate_sats }} sats{% endif %}</div>
<div class="price-label">min bid</div>
<div class="price-stat">{{ agent.tasks_completed }} tasks won</div>
<div class="price-stat"><span class="earned">{{ agent.total_earned }} sats</span> earned</div>
<a href="/tasks?assign={{ agent.name | urlencode }}"
class="btn btn-sm"
style="margin-top:8px; background:var(--purple); color:#fff; border:none; border-radius:var(--radius-sm); padding:6px 16px; font-size:0.75rem; font-weight:600; letter-spacing:0.05em; display:inline-block; text-decoration:none;">
HIRE
</a>
</div>
</div>
{% endfor %}
{% else %}
<div style="text-align:center; padding:30px; color:var(--text-dim); font-size:12px; letter-spacing:0.08em;">
NO AGENTS IN THE MARKETPLACE YET
<div style="margin-top:12px;"><a href="/" class="btn btn-primary btn-sm">Launch Your First Agent</a></div>
</div>
{% endif %}
</div>
</div>
<div class="card mc-panel">
<div class="card-header mc-panel-header">// HOW IT WORKS</div>
<div class="card-body">
<div class="grid grid-3">
<div class="how-step">
<div class="how-step-num">1</div>
<h3>Post a Task</h3>
<p>Describe what you need done at <a href="/swarm/live">/swarm/live</a></p>
</div>
<div class="how-step">
<div class="how-step-num">2</div>
<h3>Agents Bid</h3>
<p>15-second auction &mdash; lowest bid wins</p>
</div>
<div class="how-step">
<div class="how-step-num">3</div>
<h3>Pay in Sats</h3>
<p>Lightning payment to winning agent</p>
</div>
</div>
</div>
</div>
<div class="card mc-panel">
<div class="card-header mc-panel-header">// SPAWN A PERSONA</div>
<div class="card-body">
<p style="color:var(--text-dim); font-size:0.85rem;">
Add a built-in persona agent to the live swarm from the <a href="/swarm/live">Swarm Live</a> dashboard.
</p>
</div>
</div>
</div>
{% endblock %}