worker-service 0.2.0

Worker Service - A worker administration microservice that interoperates with the worker-matcher crate
{% extends "layout.html.tera" %}

{% block title %}Map — {{ entity_plural | capitalize }} — {{ app_display }}{% endblock title %}

{% block content %}
<nav class="breadcrumb-nav" aria-label="Breadcrumb">
  <ol class="breadcrumb-list" aria-label="Breadcrumb trail">
    <li class="breadcrumb-list-item"><a href="/">Home</a></li>
    <li class="breadcrumb-list-item"><a href="/{{ entity_plural }}">{{ entity_plural | capitalize }}</a></li>
    <li class="breadcrumb-list-item" aria-current="page">Map</li>
  </ol>
</nav>

<section aria-label="{{ entity_plural | capitalize }} map"
         x-data='{
           selected: null,
           pins: {{ pins | json_encode | safe }},
           select(id) {
             this.selected = (this.selected === id) ? null : id;
           },
           selectedPin() {
             var self = this;
             return this.pins.find(function (p) { return p.id === self.selected; });
           }
         }'>
  <h2>{{ entity_plural | capitalize }} map</h2>

  <div class="information-callout" aria-label="Map explainer">
    <p>
      Schematic map of {{ pins | length }} {{ entity_plural }} with geo-coordinates
      on file. Pin positions are projected from lat/lon onto a 1000×500 grid;
      this is a <strong>schematic</strong>, not a cartographic projection.
      Production should render via a real map tile provider (e.g. Leaflet +
      OSM tiles).
    </p>
  </div>

  <div class="diff" role="group" aria-label="Map and details">
    <article class="card" role="region" aria-label="Map">
      <div class="aspect-ratio-container"
           aria-label="World map with {{ pins | length }} pins"
           style="aspect-ratio: 2 / 1;">
        <svg viewBox="0 0 1000 500"
             width="100%"
             height="100%"
             role="img"
             aria-label="Schematic world grid"
             xmlns="http://www.w3.org/2000/svg">
          {# Backdrop and equator/prime-meridian lines #}
          <rect width="1000" height="500" fill="#e8edee" stroke="#768692" stroke-width="1"/>
          {# Latitude lines every 30° #}
          {% for n in [83, 167, 250, 333, 417] %}
            <line x1="0" y1="{{ n }}" x2="1000" y2="{{ n }}" stroke="#bcc4c8" stroke-width="0.5"/>
          {% endfor %}
          {# Longitude lines every 30° #}
          {% for n in [83, 167, 250, 333, 417, 500, 583, 667, 750, 833, 917] %}
            <line x1="{{ n }}" y1="0" x2="{{ n }}" y2="500" stroke="#bcc4c8" stroke-width="0.5"/>
          {% endfor %}
          {# Equator + prime meridian #}
          <line x1="0" y1="250" x2="1000" y2="250" stroke="#768692" stroke-width="1"/>
          <line x1="500" y1="0" x2="500" y2="500" stroke="#768692" stroke-width="1"/>

          {# Pins. Alpine-bound so we re-paint when `selected` changes. #}
          <template x-for="pin in pins" :key="pin.id">
            <g x-bind:aria-label="pin.label" role="button" tabindex="0"
               @click="select(pin.id)"
               @keydown.enter.prevent="select(pin.id)"
               @keydown.space.prevent="select(pin.id)"
               style="cursor: pointer;">
              <circle x-bind:cx="pin.x"
                      x-bind:cy="pin.y"
                      r="10"
                      stroke="#231f20"
                      stroke-width="1"
                      x-bind:fill="selected === pin.id ? '#da291c' : '#005eb8'"/>
              <text x-bind:x="pin.x"
                    x-bind:y="pin.y - 14"
                    text-anchor="middle"
                    font-size="14"
                    font-family="Arial, sans-serif"
                    fill="#231f20"
                    x-text="pin.label"></text>
            </g>
          </template>
        </svg>
      </div>
    </article>

    <article class="card" role="region" aria-label="Selected location detail">
      <h3>
        <span x-show="selectedPin()" x-text="selectedPin() &amp;&amp; selectedPin().label"></span>
        <span x-show="!selectedPin()">No pin selected</span>
      </h3>

      <template x-if="selectedPin()">
        <ol class="summary-list" aria-label="Selected location detail">
          <li class="summary-list-item">
            <dl>
              <dt>Record</dt>
              <dd>
                <a x-bind:href="'/{{ entity_plural }}/' + selectedPin().record_id"
                   x-bind:aria-label="'Open ' + selectedPin().label"
                   x-text="selectedPin().record_label"></a>
              </dd>
            </dl>
          </li>
          <li class="summary-list-item">
            <dl>
              <dt>Latitude</dt>
              <dd><code x-text="selectedPin().lat.toFixed(4)"></code></dd>
            </dl>
          </li>
          <li class="summary-list-item">
            <dl>
              <dt>Longitude</dt>
              <dd><code x-text="selectedPin().lon.toFixed(4)"></code></dd>
            </dl>
          </li>
          <li class="summary-list-item">
            <dl>
              <dt>Locality</dt>
              <dd x-text="selectedPin().locality"></dd>
            </dl>
          </li>
        </ol>
      </template>

      <p x-show="!selectedPin()">
        <span class="hint" aria-label="Empty selection hint">
          Click a pin on the map (or press <kbd class="kbd">Enter</kbd> on a focused pin) to view its record details.
        </span>
      </p>

      <h4>All locations</h4>
      <ol class="summary-list" aria-label="All map pins">
        <template x-for="pin in pins" :key="pin.id">
          <li class="summary-list-item">
            <dl>
              <dt>
                <button type="button"
                        class="button"
                        x-bind:aria-pressed="selected === pin.id ? 'true' : 'false'"
                        x-bind:aria-label="'Select pin: ' + pin.label"
                        @click="select(pin.id)">
                  <span x-text="pin.label"></span>
                </button>
              </dt>
              <dd>
                <span class="hint" x-text="pin.locality"></span>
              </dd>
            </dl>
          </li>
        </template>
      </ol>
    </article>
  </div>
</section>
{% endblock content %}