rhombus 0.2.21

Next generation extendable CTF framework with batteries included
Documentation
{% import "icons.html" as icons %}

<dialog
  data-onload-showmodal
  class="backdrop:bg-background/50 bg-background max-w-prose w-full rounded-lg text-foreground border-4 p-6 shadow-lg"
  style="border-color: {{ category.color }}"
>
  <div class="mb-2 flex justify-between">
    <div class="font-bold">
      <span style="color: {{ category.color }}">{{ category.name }} / </span>
      <span>{{ challenge.name }}</span>
    </div>
    <div class="flex items-center gap-4">
      <rhombus-tooltip class="cursor-pointer">
        <div slot="content">
          <table>
            {%- for division_points in challenge.division_points -%}
              <tr>
                <td class="pr-2 text-right">
                  {{ divisions[division_points.division_id].name }}
                </td>
                <td class="pr-2">
                  {{ t("solves", solves=division_points.solves) }}
                </td>
                <td>{{ t("points", points=division_points.points) }}</td>
              </tr>
            {%- endfor -%}
          </table>
        </div>

        <span
          >{{ t("solves-points", solves=challenge.division_points[0].solves, points=challenge.division_points[0].points) }}</span
        >
      </rhombus-tooltip>
    </div>
  </div>
  <div class="mb-4 prose dark:prose-invert">
    {{ challenge.description | safe }}
  </div>
  {% with solve=team.solves[challenge.id] %}
    {% if not solve %}
      <form
        class="flex gap-2"
        hx-post="/challenges/{{ challenge.id }}"
        hx-target="next"
      >
        <input
          type="text"
          name="flag"
          placeholder="Enter flag..."
          autocomplete="off"
          class="bg-background border p-2 rounded-lg grow focus-visible:outline-none"
        />
        <button class="border rounded-lg p-2" type="submit">Submit Flag</button>
      </form>
      <div></div>
    {% else %}
      {% if not user_writeups[challenge.id] %}
        <form
          class="flex gap-2"
          hx-post="/challenges/{{ challenge.id }}/writeup"
          hx-target="next"
          hx-indicator="#loader"
        >
          <div class="grow flex justify-end items-center relative">
            <input
              type="url"
              name="url"
              placeholder="Enter writeup link..."
              autocomplete="off"
              class="bg-background border p-2 rounded-lg w-full focus-visible:outline-none"
            />
            <div id="loader" class="absolute mr-2 pointer-events-none">
              {{ icons.spinner(attrs='class="animate-spin"') }}
            </div>
          </div>
          <button class="border rounded-lg p-2" type="submit">
            Submit Writeup
          </button>
        </form>
        <div></div>
        <div class="mb-2"></div>
      {% else %}
        <button
          class="bg-destructive p-2 mb-2 rounded-lg"
          hx-delete="/challenges/{{ challenge.id }}/writeup"
        >
          Rescind writeup
        </button>
      {% endif %}
      {% if team.writeups[challenge.id] %}
        <div class="mb-2">
          <div>Team's writeups:</div>
          <ul>
            {% for writeup in team.writeups[challenge.id] %}
              <li class="flex justify-between">
                <a
                  class="underline text-blue-300"
                  target="_blank"
                  href="{{ writeup.url }}"
                  >{{ writeup.url }}</a
                >
                <span>by {{ team.users[writeup.user_id].name }}</span>
              </li>
            {% endfor %}
          </ul>
        </div>
      {% endif %}
    {% endif %}
  {% endwith %}
  {% if challenge.attachments | length > 0 %}
    <div class="flex gap-2 mt-4">
      {% for attachment in challenge.attachments %}
        <a
          class="pr-2 py-1 pl-1 max-w-fit rounded-lg flex"
          style="background-color: {{ category.color }}77"
          href="{{ attachment.url }}"
        >
          <div class="scale-75">{{ icons.attachment() }}</div>
          {{ attachment.name }}</a
        >
      {% endfor %}
    </div>
  {% endif %}
</dialog>