{% extends "base.html" %} {% from "_when.html" import when_field with context %} {% from "_kit_fields.html" import spec_fields with context %} {% block title %}Kit Β· {{ app_name }}{% endblock %} {% block body %}

🦴 Kit βš™

{{ totals.owned }} owned Β· {{ totals.by_kind.toy }} toy{{ '' if totals.by_kind.toy == 1 else 's' }} Β· {{ totals.by_kind.gear }} gear Β· {{ totals.by_kind.consumable }} consumable{{ '' if totals.by_kind.consumable == 1 else 's' }} {%- if totals.wishlist %} Β· {{ totals.wishlist }} on the wishlist{% endif %} {%- if totals.bouts %} Β· {{ totals.bouts }} bouts Β· {{ totals.seconds|dur }}{% endif %} {%- if totals.priced %} Β· {{ cur }}{{ '%.2f'|format(totals.spend_cents / 100) }} spent (of {{ totals.priced }} you priced){% endif %}

{# ── what is on right now ────────────────────────────────────────────────── #} {% if open %}

On right now

{% for b in open %}
{{ b.things|map(attribute='name')|join(' Β· ') }} {{ '🦴 play' if b.kind == 'play' else '🧺 wear' }} {% if b.locked %}πŸ”’ caged{% endif %} {% if b.source == 'session' %}auto{% endif %}

on since {{ b.started_at|local }} Β· {{ (now - b.started_at)|dur }}

{% endfor %}
{% endif %} {% if stale %} {#- πŸ”΄ Reported, never auto-closed. The app does not know when you took it off and will not invent an end time β€” see service.stale_bouts. -#}

⚠ {{ stale|length }} play bout{{ '' if stale|length == 1 else 's' }} still open since {{ stale[0].started_at|rel(now) }}. Finish it with the real time, or discard it β€” nothing will guess an end for you.

{% endif %}
{# ── start a bout ───────────────────────────────────────────────────────── #} {#- πŸ”΄ A REFUSED SAVE COMES BACK FILLED IN (#40, web/kept.py). `kv` reads what a refused form sent, only for that form's own action; rendered server-side, so the words are in the page whether or not JavaScript runs. -#} {%- macro kv(action, name, default='') -%}{{ kept.value(action, name, default) }}{%- endmacro -%} {%- macro kept_err(action) -%}{% if kept.on(action) %}

{{ kept.err }}

{% endif %}{%- endmacro -%} {%- macro kind_pick(action) -%} {%- set k = kv(action, 'bout_kind', 'play') -%}
{%- endmacro -%} {%- macro item_pick(action) -%} {%- set on = kept.values(action, 'item_id') -%}
{% for i in playable %} {% else %}

Nothing owned yet. Add something below.

{% endfor %}
{%- endmacro -%}

Put something on

{#- πŸ”΄ Say which is which (#41): the two kinds are measured differently, and the page used to leave the pup to guess from a dropdown. -#}

🦴 Play is a session that ends somehow β€” you say how, and answer the questions. 🧺 Wear is time something is on β€” the hours are the point. Start one now and finish it when it comes off, or πŸ“ log one from earlier.

{% set a = '/kit/start' %}
{{ kept_err(a) }} {{ item_pick(a) }} {{ kind_pick(a) }}
{{ when_field('⏱ started earlier and it’s still on? set the time', value=kv(a, 'when')) }}
{# ── πŸ“ a whole bout from earlier (#41) ─────────────────────────────────── #}

πŸ“ Log one from earlier

Done and dusted? Tell it in one go β€” it lands at the time it happened, marked β†Ά logged later. Local time, {{ tz }}.

{% set a = '/kit/log' %}
{{ kept_err(a) }} {{ item_pick(a) }} {{ kind_pick(a) }}
🦴 how it ended, the questions, a note

How it ended is for play; wear has no ending to tell.

{%- set o = kv(a, 'outcome', 'none') %}
{% for x in outcomes %} {% endfor %}
{#- the same unnamed-until-moved sliders as the end form (kit_end.html); an answer comes back only if it was sent -#} {% for q in survey %} {%- set ans = kv(a, 'score.' ~ q.key) %}
{{ (ans ~ ' / ' ~ smax) if ans else 'not asked' }}
{% endfor %} {% if lubes %}
{% endif %}
{# ── the quick log: an outcome without a bout ───────────────────────────── #}

πŸ’¦ Log a finish

{% set a = '/kit/finish' %}
{{ kept_err(a) }} {%- set o = kv(a, 'outcome', 'squirt') %}{% set cg = kv(a, 'caged', 'auto') %}{% set on = kept.values(a, 'item_id') %}
{% if playable %}
{% for i in playable if i.kind == 'toy' %} {% endfor %}
{% endif %}

Leave When empty for right now; anything earlier is marked β†Ά logged later (local time, {{ tz }}). Caged comes from the lock at that moment; pick out of the cage for a break during a lock. Toys and length are optional.

{# ── things that want attention ─────────────────────────────────────────── #}

Wants attention

{% if low %}

Running out

{% endif %} {% if expiring %}

Going off

{% endif %} {% if neglected %}

Gathering dust

{% endif %} {% if not low and not expiring and not neglected %}

Nothing running low, nothing going off, nothing neglected. Tidy kennel.

{% endif %}
{# ── the inventory ──────────────────────────────────────────────────────── #}
all {% for k in kinds %} {{ kind_icon[k] }} {{ kind_title[k] }} {% endfor %} ✨ wishlist πŸ“• retired
{% for i in items %} {% set s = stats[i.id] %}
{% if i.media_id %} {% else %}{{ i.cat_icon }}{% endif %} {% if badges.get(i.id) %} {% for b in badges[i.id][:3] %}{{ b.icon }}{% endfor %} {% endif %}
{{ i.name }} {{ i.cat_title }} {%- if i.status == 'wishlist' %} Β· ✨ want{% elif i.status == 'retired' %} Β· retired{% endif %} {%- if i.kind == 'consumable' -%} {% if s.level is not none %}{{ '%g'|format(s.level) }} {{ i.qty_unit }} left {%- else %}level unknown{% endif %} {%- elif s.uses -%} {{ s.uses }} bout{{ '' if s.uses == 1 else 's' }} {%- if s.total_seconds %} Β· {{ s.total_seconds|dur }}{% endif %} {%- if s.last_used %} Β· {{ s.last_used|rel(now) }}{% endif %} {%- elif i.status == 'wishlist' -%} not yours yet {%- else -%} never used {%- endif -%} {% if s.squirts %}πŸ’¦ {{ s.squirts }}{% if s.caged_squirts %} Β· πŸ”’ {{ s.caged_squirts }} caged{% endif %}{% endif %}
{% else %}

Nothing here yet.

{% endfor %}
{# ── add ────────────────────────────────────────────────────────────────── #}
βž• Add something
{{ spec_fields(categories) }}
{{ when_field('⏱ got it earlier? set the date') }}
{% endblock %} {% block scripts %} {% endblock %}