{% macro avatar(username, size="24px", selector_type="username") -%}
<img
    title="{{ username }}'s avatar"
    src="/api/v1/auth/user/{{ username }}/avatar?selector_type={{ selector_type }}"
    alt="@{{ username }}"
    class="avatar shadow"
    loading="lazy"
    style="--size: {{ size }}"
/>
{%- endmacro %} {% macro community_avatar(id, community=false, size="24px") -%}
{% if community %}
<img
    src="/api/v1/communities/{{ id }}/avatar"
    alt="{{ community.title }}'s avatar"
    class="avatar shadow"
    loading="lazy"
    style="--size: {{ size }}"
/>
{% else %}
<img
    src="/api/v1/communities/{{ id }}/avatar"
    alt="{{ id }}'s avatar"
    class="avatar shadow"
    loading="lazy"
    style="--size: {{ size }}"
/>
{% endif %} {%- endmacro %} {% macro banner(username,
border_radius="var(--radius)") -%}
<img
    title="{{ username }}'s banner"
    src="/api/v1/auth/user/{{ username }}/banner"
    alt="@{{ username }}'s banner"
    class="banner shadow w-full"
    loading="lazy"
    style="border-radius: {{ border_radius }};"
/>
{%- endmacro %} {% macro community_banner(id, community=false) -%} {% if
community %}
<img
    src="/api/v1/communities/{{ id }}/banner"
    alt="{{ community.title }}'s banner"
    class="banner shadow"
    loading="lazy"
/>
{% else %}
<img
    src="/api/v1/communities/{{ id }}/banner"
    alt="{{ id }}'s banner"
    class="banner shadow"
    loading="lazy"
/>
{% endif %} {%- endmacro %} {% macro community_listing_card(community) -%}
<a
    class="card secondary w-full flex items-center gap-4"
    href="/community/{{ community.title }}"
>
    {{ self::community_avatar(id=community.id, community=community, size="48px")
    }}
    <div class="flex flex-col">
        <h3 class="name lg:long">{{ community.context.display_name }}</h3>
        <span class="fade"><b>{{ community.member_count }}</b> members</span>
    </div>
</a>
{%- endmacro %} {% macro username(user) -%}
<div style="display: contents">
    {% if user.settings.display_name %} {{ user.settings.display_name }} {% else
    %} {{ user.username }} {% endif %}
</div>
{%- endmacro %} {% macro likes(id, asset_type, likes=0, dislikes=0,
secondary=false) -%}
<button
    title="Like"
    class="{% if secondary %}quaternary{% else %}camo{% endif %} small"
    hook_element="reaction.like"
    onclick="trigger('me::react', [event.target, '{{ id }}', '{{ asset_type }}', true])"
>
    {{ icon "heart" }} {% if likes > 0 %}
    <span>{{ likes }}</span>
    {% endif %}
</button>

{% if not user or not user.settings.hide_dislikes %}
<button
    title="Dislike"
    class="{% if secondary %}quaternary{% else %}camo{% endif %} small"
    hook_element="reaction.dislike"
    onclick="trigger('me::react', [event.target, '{{ id }}', '{{ asset_type }}', false])"
>
    {{ icon "heart-crack" }} {% if dislikes > 0 %}
    <span>{{ dislikes }}</span>
    {% endif %}
</button>
{% endif %} {%- endmacro %} {% macro full_username(user) -%}
<div class="flex items-center">
    <a
        href="/@{{ user.username }}"
        class="flush"
        style="font-weight: 600"
        target="_top"
    >
        {{ self::username(user=user) }}
    </a>

    {{ self::online_indicator(user=user) }} {% if user.is_verified %}
    <span
        title="Verified"
        style="color: var(--color-primary)"
        class="flex items-center"
    >
        {{ icon "badge-check" }}
    </span>
    {% endif %}
</div>
{%- endmacro %} {% macro repost(repost, post, owner, secondary=false,
community=false, show_community=true, can_manage_post=false) -%}
<div style="display: contents">
    <!-- prettier-ignore -->
    <div style="display: none" id="repost-content:{{ post.id }}">
        {% if repost %}
            {{ self::post(post=repost[1], owner=repost[0], secondary=not secondary, community=false, show_community=false, can_manage_post=false) }}
        {% else %}
            <div class="card tertiary red flex items-center gap-2">
                {{ icon "frown" }}
                <span>Could not find original post...</span>
            </div>
        {% endif %}
    </div>

    {{ self::post(post=post, owner=owner, secondary=secondary,
    community=community, show_community=show_community,
    can_manage_post=can_manage_post) }}

    <script>
        document.getElementById("post-content:{{ post.id }}").innerHTML +=
            document.getElementById("repost-content:{{ post.id }}").innerHTML;
        document.getElementById("repost-content:{{ post.id }}").remove();

        document
            .getElementById("post:{{ post.id }}")
            .querySelector(".avatar")
            .setAttribute("style", "--size: 24px");

        document
            .getElementById("post:{{ post.id }}")
            .querySelector(".name")
            .parentElement.prepend(
                document
                    .getElementById("post:{{ post.id }}")
                    .querySelector(".avatar"),
            );
    </script>
</div>
{%- endmacro %} {% macro post(post, owner, question=false, secondary=false,
community=false, show_community=true, can_manage_post=false) -%} {% if community
and show_community and community.id != config.town_square or question %}
<div class="card-nest">
    {% if question %} {{ self::question(question=question[0], owner=question[1])
    }} {% else %}
    <div class="card small">
        <a
            href="/api/v1/communities/find/{{ post.community }}"
            class="flush flex gap-1 items-center"
        >
            {{ self::community_avatar(id=post.community, community=community) }}
            <b>
                <!-- prettier-ignore -->
                {% if community.context.display_name %}
                    {{ community.context.display_name }}
                {% else %}
                    {{ community.title }}
                {% endif %}
            </b>

            {% if post.context.is_pinned or post.context.is_profile_pinned %} {{
            icon "pin" }} {% endif %}
        </a>
    </div>
    {% endif %} {% endif %}
    <div
        class="card flex flex-col gap-2 {% if secondary %}secondary{% endif %}"
        id="post:{{ post.id }}"
    >
        <div class="w-full flex gap-2">
            <a href="/@{{ owner.username }}">
                {{ self::avatar(username=owner.username, size="52px",
                selector_type="username") }}
            </a>

            <div class="flex flex-col w-full gap-1">
                <div class="flex flex-wrap gap-2 items-center">
                    <span class="name"
                        >{{ self::full_username(user=owner) }}</span
                    >

                    {% if post.context.edited != 0 %}
                    <div class="flex">
                        <span class="fade date">{{ post.context.edited }}</span>
                        <sup title="Edited">*</sup>
                    </div>
                    {% else %}
                    <span class="fade date">{{ post.created }}</span>
                    {% endif %} {% if post.context.is_nsfw %}
                    <span
                        title="NSFW post"
                        class="flex items-center"
                        style="color: var(--color-primary)"
                    >
                        {{ icon "square-asterisk" }}
                    </span>
                    {% endif %} {% if post.context.repost and
                    post.context.repost.reposting %}
                    <span
                        title="Repost"
                        class="flex items-center"
                        style="color: var(--color-primary)"
                    >
                        {{ icon "repeat-2" }}
                    </span>
                    {% endif %} {% if post.community == config.town_square %}
                    <span
                        title="Posted to profile"
                        class="flex items-center"
                        style="color: var(--color-primary)"
                    >
                        {{ icon "user-round" }}
                    </span>
                    {% endif %}
                </div>

                {% if not post.context.content_warning %}
                <span id="post-content:{{ post.id }}" class="no_p_margin"
                    >{{ post.content|markdown|safe }}</span
                >
                {% else %}
                <details>
                    <summary
                        class="card flex gap-2 items-center secondary red w-full"
                    >
                        {{ icon "triangle-alert" }}
                        <b>{{ post.context.content_warning }}</b>
                    </summary>

                    <span id="post-content:{{ post.id }}" class="no_p_margin"
                        >{{ post.content|markdown|safe }}</span
                    >
                </details>
                {% endif %}
            </div>
        </div>

        <div class="flex justify-between items-center gap-2 w-full">
            {% if user %}
            <div
                class="flex gap-1 reactions_box"
                hook="check_reactions"
                hook-arg:id="{{ post.id }}"
            >
                <!-- prettier-ignore -->
                {% if post.context.reactions_enabled %}
                    {% if post.content|length > 0 %}
                        {{ self::likes(id=post.id, asset_type="Post", likes=post.likes, dislikes=post.dislikes) }}
                    {% endif %}
                {% endif %}

                {% if post.context.repost and post.context.repost.reposting %}
                <a
                    href="/post/{{ post.context.repost.reposting }}"
                    class="button small camo"
                    title='{{ text "communities:label.expand_original" }}'
                >
                    {{ icon "expand" }}
                </a>
                {% endif %}
            </div>
            {% else %}
            <div></div>
            {% endif %}

            <div class="flex gap-1 buttons_box">
                <a href="/post/{{ post.id }}" class="button camo small">
                    {{ icon "message-circle" }}
                    <span>{{ post.comment_count }}</span>
                </a>

                <a
                    href="/post/{{ post.id }}"
                    class="button camo small"
                    target="_blank"
                >
                    {{ icon "external-link" }}
                </a>

                {% if user %}
                <div class="dropdown">
                    <button
                        class="camo small"
                        onclick="trigger('atto::hooks::dropdown', [event])"
                        exclude="dropdown"
                    >
                        {{ icon "ellipsis" }}
                    </button>

                    <div class="inner">
                        {% if config.town_square and
                        post.context.reposts_enabled %}
                        <b class="title">{{ text "general:label.share" }}</b>
                        <button
                            onclick="trigger('me::repost', ['{{ post.id }}', '', '{{ config.town_square }}'])"
                        >
                            {{ icon "repeat-2" }}
                            <span>{{ text "communities:label.repost" }}</span>
                        </button>

                        <button
                            onclick="window.REPOST_ID = '{{ post.id }}'; document.getElementById('quote_dialog').showModal()"
                        >
                            {{ icon "quote" }}
                            <span
                                >{{ text "communities:label.quote_post" }}</span
                            >
                        </button>
                        {% endif %} {% if user.id != post.owner %}
                        <b class="title">{{ text "general:label.safety" }}</b>
                        <button
                            class="red"
                            onclick="trigger('me::report', ['{{ post.id }}', 'post'])"
                        >
                            {{ icon "flag" }}
                            <span>{{ text "general:action.report" }}</span>
                        </button>
                        {% endif %} {% if (user.id == post.owner) or is_helper
                        or can_manage_post %}
                        <b class="title">{{ text "general:action.manage" }}</b>
                        {% if user.id == post.owner %}
                        <a href="/post/{{ post.id }}#/edit">
                            {{ icon "pen" }}
                            <span
                                >{{ text "communities:label.edit_content"
                                }}</span
                            >
                        </a>
                        {% endif %}

                        <a href="/post/{{ post.id }}#/configure">
                            {{ icon "settings" }}
                            <span
                                >{{ text "communities:action.configure" }}</span
                            >
                        </a>

                        <button
                            class="red"
                            onclick="trigger('me::remove_post', ['{{ post.id }}'])"
                        >
                            {{ icon "trash" }}
                            <span>{{ text "general:action.delete" }}</span>
                        </button>
                        {% endif %}
                    </div>
                </div>
                {% endif %}
            </div>
        </div>
    </div>
    {% if community and show_community and community.id != config.town_square or
    question %}
</div>
{% endif %} {%- endmacro %} {% macro notification(notification) -%}
<div class="w-full card-nest">
    <div class="card small notif_title flex items-center">
        {% if not notification.read %}
        <svg
            width="24"
            height="24"
            viewBox="0 0 24 24"
            style="fill: var(--color-link)"
        >
            <circle cx="12" cy="12" r="6"></circle>
        </svg>
        {% endif %}
        <b class="no_p_margin">{{ notification.title|markdown|safe }}</b>
    </div>

    <div class="card notif_content flex flex-col gap-2">
        <span class="no_p_margin"
            >{{ notification.content|markdown|safe }}</span
        >

        <div class="card secondary w-full flex flex-wrap gap-2">
            {% if notification.read %}
            <button
                class="tertiary"
                onclick="trigger('me::update_notification_read_status', ['{{ notification.id }}', false])"
            >
                {{ icon "undo" }}
                <span>{{ text "notifs:action.mark_as_unread" }}</span>
            </button>
            {% else %}
            <button
                class="green tertiary"
                onclick="trigger('me::update_notification_read_status', ['{{ notification.id }}', true])"
            >
                {{ icon "check" }}
                <span>{{ text "notifs:action.mark_as_read" }}</span>
            </button>
            {% endif %}

            <button
                class="red tertiary"
                onclick="trigger('me::remove_notification', ['{{ notification.id }}'])"
            >
                {{ icon "trash" }}
                <span>{{ text "general:action.delete" }}</span>
            </button>
        </div>
    </div>
</div>
{%- endmacro %} {% macro user_card(user) -%}
<a class="card-nest w-full" href="/@{{ user.username }}">
    <div class="card small" style="padding: 0">
        {{ self::banner(username=user.username, border_radius="0px") }}
    </div>

    <div class="card secondary flex items-center gap-4">
        {{ self::avatar(username=user.username, size="48px") }}
        <div class="flex items-center">
            <b>{{ self::username(user=user) }}</b>
            {{ self::online_indicator(user=user) }}
        </div>
    </div>
</a>
{%- endmacro %} {% macro pagination(page=0, items=0, key="", value="") -%}
<div class="flex justify-between gap-2 w-full">
    {% if page > 0 %}
    <a
        class="button quaternary"
        href="?page={{ page - 1 }}{{ key }}{{ value }}"
    >
        {{ icon "arrow-left" }}
        <span>{{ text "general:link.previous" }}</span>
    </a>
    {% else %}
    <div></div>
    {% endif %} {% if items != 0 %}
    <a
        class="button quaternary"
        href="?page={{ page + 1 }}{{ key }}{{ value }}"
    >
        <span>{{ text "general:link.next" }}</span>
        {{ icon "arrow-right"}}
    </a>
    {% endif %}
</div>
{%- endmacro %} {% macro online_indicator(user) -%} {% if not
user.settings.private_last_seen or is_helper %}
<div
    class="online_indicator"
    style="display: contents"
    hook="online_indicator"
    hook-arg:last_seen="{{ user.last_seen }}"
>
    <div style="display: none" hook_ui_ident="online" title="Online">
        <svg
            width="24"
            height="24"
            viewBox="0 0 24 24"
            style="fill: var(--color-green)"
        >
            <circle cx="12" cy="12" r="6"></circle>
        </svg>
    </div>

    <div style="display: none" hook_ui_ident="idle" title="Idle">
        <svg
            width="24"
            height="24"
            viewBox="0 0 24 24"
            style="fill: var(--color-yellow)"
        >
            <circle cx="12" cy="12" r="6"></circle>
        </svg>
    </div>

    <div style="display: none" hook_ui_ident="offline" title="Offline">
        <svg
            width="24"
            height="24"
            viewBox="0 0 24 24"
            style="fill: hsl(0, 0%, 50%)"
        >
            <circle cx="12" cy="12" r="6"></circle>
        </svg>
    </div>
</div>
{% else %}
<div title="Offline" style="display: contents">
    <svg
        width="24"
        height="24"
        viewBox="0 0 24 24"
        style="fill: hsl(0, 0%, 50%)"
    >
        <circle cx="12" cy="12" r="6"></circle>
    </svg>
</div>
{% endif %} {%- endmacro %} {% macro theme(user, theme_preference) -%} {% if
user %} {% if user.settings.theme_hue %}
<style>
    :root, * {
        --hue: {{ user.settings.theme_hue }} !important;
    }
</style>
{% endif %} {% if user.settings.theme_sat %}
<style>
    :root, * {
        --sat: {{ user.settings.theme_sat }} !important;
    }
</style>
{% endif %} {% if user.settings.theme_lit %}
<style>
    :root, * {
        --lit: {{ user.settings.theme_lit }} !important;
    }
</style>
{% endif %} {% if theme_preference %}
<script>
    function match_user_theme() {
        const pref = "{{ theme_preference }}".toLowerCase();

        if (pref === "auto") {
            return;
        }

        document.documentElement.className = pref;
    }

    setTimeout(() => {
        match_user_theme();
    }, 150);
</script>
{% endif %}
<!-- prettier-ignore -->
<div style="display: none;">
    {{ self::theme_color(color=user.settings.theme_color_surface, css="color-surface") }}
    {{ self::theme_color(color=user.settings.theme_color_text, css="color-text") }}
    {{ self::theme_color(color=user.settings.theme_color_text_link, css="color-link") }}

    {{ self::theme_color(color=user.settings.theme_color_lowered, css="color-lowered") }}
    {{ self::theme_color(color=user.settings.theme_color_text_lowered, css="color-text-lowered") }}
    {{ self::theme_color(color=user.settings.theme_color_super_lowered, css="color-super-lowered") }}

    {{ self::theme_color(color=user.settings.theme_color_raised, css="color-raised") }}
    {{ self::theme_color(color=user.settings.theme_color_text_raised, css="color-text-raised") }}
    {{ self::theme_color(color=user.settings.theme_color_super_raised, css="color-super-raised") }}

    {{ self::theme_color(color=user.settings.theme_color_primary, css="color-primary") }}
    {{ self::theme_color(color=user.settings.theme_color_text_primary, css="color-text-primary") }}
    {{ self::theme_color(color=user.settings.theme_color_primary_lowered, css="color-primary-lowered") }}

    {{ self::theme_color(color=user.settings.theme_color_secondary, css="color-secondary") }}
    {{ self::theme_color(color=user.settings.theme_color_text_secondary, css="color-text-secondary") }}
    {{ self::theme_color(color=user.settings.theme_color_secondary_lowered, css="color-secondary-lowered") }}

    {% if user.permissions|has_supporter %}
    <style>{{ user.settings.theme_custom_css }}</style>
    {% endif %}
</div>
{% endif %} {%- endmacro %} {% macro theme_color(color, css) -%} {% if color %}
<!-- prettier-ignore -->
<style>
    :root,
    * {
        --{{ css }}: {{ color|color }} !important;
    }
</style>
{% endif %} {%- endmacro %} {% macro quote_form() -%} {% if config.town_square
and user %}
<div class="card-nest">
    <div class="card small flex flex-col">
        <div class="flex items-center gap-2">
            {{ icon "quote" }}
            <span>{{ text "communities:label.quote_post" }}</span>
        </div>
    </div>

    <form
        class="card flex flex-col gap-2"
        onsubmit="create_repost_from_form(event)"
    >
        <div class="flex flex-col gap-1">
            <label for="content">{{ text "communities:label.content" }}</label>
            <textarea
                type="text"
                name="content"
                id="content"
                placeholder="content"
                required
                minlength="2"
                maxlength="4096"
            ></textarea>
        </div>

        <button class="primary">{{ text "communities:action.create" }}</button>
    </form>
</div>

<script>
    async function create_repost_from_form(e) {
        e.preventDefault();
        await trigger("atto::debounce", ["posts::create"]);
        await trigger("me::repost", [
            window.REPOST_ID,
            e.target.content.value,
            "{{ config.town_square }}",
        ]);
    }
</script>
{% endif %} {%- endmacro %} {% macro question(question, owner,
show_community=true, secondary=false) -%}
<div class="card{% if secondary %} secondary{% endif %} flex gap-2">
    {% if owner.id == 0 %}
    <span>
        {% if profile and profile.settings.anonymous_avatar_url %}
        <img
            src="/api/v1/util/proxy?url={{ profile.settings.anonymous_avatar_url }}"
            alt="anonymous' avatar"
            class="avatar shadow"
            loading="lazy"
            style="--size: 52px"
        />
        {% else %} {{ self::avatar(username=owner.username,
        selector_type="username", size="52px") }} {% endif %}
    </span>
    {% else %}
    <a href="/@{{ owner.username }}">
        {{ self::avatar(username=owner.username, selector_type="username",
        size="52px") }}
    </a>
    {% endif %}

    <div class="flex flex-col gap-1">
        <div class="flex items-center gap-2 flex-wrap">
            <!-- prettier-ignore -->
            <span class="name">
                {% if owner.id == 0 %}
                    {% if profile and profile.settings.anonymous_username %}
                        <span class="flex items-center gap-2">
                            <b>{{ profile.settings.anonymous_username }}</b>
                            <span
                                title="Anonymous user"
                                class="flex items-center"
                                style="color: var(--color-primary)"
                            >
                                {{ icon "drama" }}
                            </span>
                        </span>
                    {% else %}
                        <b>anonymous</b>
                    {% endif %}
                {% else %}
                    {{ self::full_username(user=owner) }}
                {% endif %}
            </span>

            <span class="date">{{ question.created }}</span>

            <span
                title="Question"
                class="flex items-center"
                style="color: var(--color-primary)"
            >
                {{ icon "message-circle-heart" }}
            </span>

            {% if question.context.is_nsfw %}
            <span
                title="NSFW community"
                class="flex items-center"
                style="color: var(--color-primary)"
            >
                {{ icon "square-asterisk" }}
            </span>
            {% endif %} {% if question.community > 0 and show_community %}
            <a
                href="/api/v1/communities/find/{{ question.community }}"
                class="flex items-center"
            >
                {{ self::community_avatar(id=question.community, size="24px") }}
            </a>
            {% endif %} {% if question.is_global %}
            <a class="notification chip" href="/question/{{ question.id }}"
                >{{ question.answer_count }} answers</a
            >
            {% endif %}
        </div>

        <span class="no_p_margin" style="font-weight: 500"
            >{{ question.content|markdown|safe }}</span
        >

        <div class="flex gap-2 items-center justify-between"></div>
    </div>
</div>
{%- endmacro %} {% macro create_question_form(receiver="0", community="",
header="", is_global=false) -%}
<div class="card-nest">
    <div class="card small flex items-center gap-2">
        {{ icon "message-circle-heart" }}
        <span class="no_p_margin">
            <!-- prettier-ignore -->
            {% if header %}
                {{ header|markdown|safe }}
            {% else %}
                {{ text "requests:label.ask_question" }}
            {% endif %}
        </span>
    </div>

    <form
        class="card flex flex-col gap-2"
        onsubmit="create_question_from_form(event)"
    >
        <div class="flex flex-col gap-1">
            <label for="content">{{ text "communities:label.content" }}</label>
            <textarea
                type="text"
                name="content"
                id="content"
                placeholder="content"
                required
                minlength="2"
                maxlength="4096"
            ></textarea>
        </div>

        <button class="primary">{{ text "communities:action.create" }}</button>
    </form>
</div>

<script>
    async function create_question_from_form(e) {
        e.preventDefault();
        await trigger("atto::debounce", ["questions::create"]);
        fetch("/api/v1/questions", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify({
                content: e.target.content.value,
                receiver: "{{ receiver }}",
                community: "{{ community }}",
                is_global: "{{ is_global }}" == "true",
            }),
        })
            .then((res) => res.json())
            .then((res) => {
                trigger("atto::toast", [
                    res.ok ? "success" : "error",
                    res.message,
                ]);

                if (res.ok) {
                    e.target.reset();
                }
            });
    }
</script>
{%- endmacro %} {% macro global_question(question, can_manage_questions=false,
secondary=false, show_community=true) -%}
<div class="card-nest">
    {{ self::question(question=question[0], owner=question[1],
    show_community=show_community) }}

    <div
        class="small card flex justify-between flex-wrap gap-2{% if secondary %} secondary{% endif %}"
    >
        <div
            class="flex gap-1 reactions_box"
            hook="check_reactions"
            hook-arg:id="{{ question[0].id }}"
        >
            {{ self::likes(id=question[0].id, asset_type="Question",
            likes=question[0].likes, dislikes=question[0].dislikes,
            secondary=false) }}
        </div>

        <div class="flex gap-1 buttons_box">
            <a href="/question/{{ question[0].id }}" class="button small">
                {{ icon "external-link" }} {% if user %}
                <span>{{ text "requests:label.answer" }}</span>
                {% else %}
                <span>{{ text "general:action.open" }}</span>
                {% endif %}
            </a>

            {% if user %} {% if can_manage_questions or is_helper or
            question[1].id == user.id %}
            <div class="dropdown">
                <button
                    class="camo small"
                    onclick="trigger('atto::hooks::dropdown', [event])"
                    exclude="dropdown"
                >
                    {{ icon "ellipsis" }}
                </button>

                <div class="inner">
                    <button
                        class="camo small red"
                        onclick="trigger('me::remove_question', ['{{ question[0].id }}'])"
                    >
                        {{ icon "trash" }}
                        <span>{{ text "general:action.delete" }}</span>
                    </button>
                </div>
            </div>
            {% endif %} {% endif %}
        </div>
    </div>
</div>
{%- endmacro %} {% macro spotify_playing(state, size="60px") -%} {% if state and
state.data %}
<div class="card-nest">
    <div class="card flex items-center justify-between gap-2 small">
        <div class="flex items-center gap-2">
            <b>Listening on</b>
            {{ icon "spotify" }}
        </div>

        <span class="fade date short">{{ state.data.timestamp }}</span>
    </div>

    <div class="card secondary flex gap-2">
        <a href="{{ state.external_urls.album }}">
            <img
                src="{{ state.external_urls.album_img }}"
                alt="Album cover"
                loading="lazy"
                class="avatar"
                style="--size: {{ size }}"
            />
        </a>

        <div class="flex flex-col">
            <h5 class="w-full">
                <a href="{{ state.external_urls.track }}" class="flush"
                    >{{ state.data.track }}</a
                >
            </h5>

            <span class="fade"
                ><a href="{{ state.external_urls.artist }}" class="flush"
                    >{{ state.data.artist }}</a
                ></span
            >

            <span
                hook="spotify_time_text"
                hook-arg:updated="{{ state.data.timestamp }}"
                hook-arg:progress="{{ state.data.progress_ms }}"
                hook-arg:duration="{{ state.data.duration_ms }}"
                hook-arg:display="full"
            ></span>
        </div>
    </div>
</div>
{% endif %} {%- endmacro %} {% macro last_fm_playing(state, size="60px") -%} {%
if state and state.data %}
<div class="card-nest">
    <div class="card flex items-center justify-between gap-2 small">
        <div class="flex items-center gap-2">
            <b>Listening on</b>
            {{ icon "last_fm" }}
        </div>

        <span class="fade date short">{{ state.data.timestamp }}</span>
    </div>

    <div class="card secondary flex gap-2">
        <a href="{{ state.external_urls.track }}">
            <img
                src="{{ state.external_urls.track_img }}"
                alt="Track cover"
                loading="lazy"
                class="avatar"
                style="--size: {{ size }}"
            />
        </a>

        <div class="flex flex-col">
            <h5 class="w-full">
                <a href="{{ state.external_urls.track }}" class="flush"
                    >{{ state.data.track }}</a
                >
            </h5>

            <span class="fade"
                ><a href="{{ state.external_urls.artist }}" class="flush"
                    >{{ state.data.artist }}</a
                ></span
            >

            {% if state.data.duration_ms and state.data.duration_ms != "0" %}
            <span
                hook="spotify_time_text"
                hook-arg:updated="{{ state.data.timestamp }}"
                hook-arg:progress="25000"
                hook-arg:duration="{{ state.data.duration_ms }}"
                hook-arg:display="full"
            ></span>
            {% endif %}
        </div>
    </div>
</div>
{% endif %} {%- endmacro %} {% macro connection_icon(key) -%}
<!-- prettier-ignore -->
<div style="display: contents;">
    {% if key == "Spotify" %}
        {{ icon "spotify" }}
    {% elif key == "LastFm" %}
        {{ icon "last_fm" }}
    {% endif %}
</div>
{%- endmacro %} {% macro connection_url(key, value) -%} {% if value[0].data.url
%} {{ value[0].data.url }} {% elif key == "LastFm" %} https://last.fm/user/{{
value[0].data.name }} {% endif %} {%- endmacro %} {% macro
message_actions(can_manage_message, user, message) -%}
<div class="dropdown">
    <button
        class="camo small"
        onclick="trigger('atto::hooks::dropdown', [event])"
        exclude="dropdown"
    >
        {{ icon "ellipsis" }}
    </button>

    <div class="inner">
        {% if can_manage_message or (user and user.id == message.owner) %}
        <button class="red" onclick="delete_message('{{ message.id }}')">
            {{ icon "trash" }}
            <span>{{ text "general:action.delete" }}</span>
        </button>
        {% endif %}

        <button
            onclick="window.location.href = `${window.location.origin}/chats/{{ community }}/{{ channel }}?message={{ message.id }}`"
        >
            {{ icon "external-link" }}
            <span>{{ text "general:action.open" }}</span>
        </button>

        <button
            onclick="trigger('atto::copy_text', [`${window.location.origin}/chats/{{ community }}/{{ channel }}?message={{ message.id }}`])"
        >
            {{ icon "copy" }}
            <span>{{ text "general:action.copy_link" }}</span>
        </button>
    </div>
</div>
{%- endmacro %} {% macro message(user, message, can_manage_message=false,
grouped=false) -%}
<div
    class="card secondary message flex gap-2 {% if grouped %}grouped{% endif %}"
    id="message-{{ message.id }}"
>
    {% if not grouped %}
    <a href="/@{{ user.username }}" target="_top">
        {{ self::avatar(username=user.username, size="52px") }}
    </a>
    {% endif %}

    <div class="flex flex-col gap-1 w-full">
        {% if not grouped %}
        <div class="flex gap-2 w-full justify-between flex-wrap">
            <div class="flex gap-2">
                {{ self::full_username(user=user) }} {% if message.edited !=
                message.created %}
                <span class="date"
                    >{{ message.edited }}<sup title="Edited">*</sup></span
                >
                {% else %}
                <span class="date">{{ message.created }}</span>
                {% endif %}
            </div>

            <div class="flex gap-2 hidden">
                {{ self::message_actions(user=user, message=message,
                can_manage_message=can_manage_message) }}
            </div>
        </div>
        {% endif %}

        <div class="flex w-full gap-2 justify-between">
            <span class="no_p_margin">{{ message.content|markdown|safe }}</span>

            {% if grouped %}
            <div class="hidden">
                {{ self::message_actions(user=user, message=message,
                can_manage_message=can_manage_message) }}
            </div>
            {% endif %}
        </div>
    </div>
</div>
{%- endmacro %} {% macro user_menu() -%}
<div class="inner">
    <b class="title">{{ user.username }}</b>
    <a href="/@{{ user.username }}">
        {{ icon "circle-user-round" }}
        <span>{{ text "auth:link.my_profile" }}</span>
    </a>

    <a href="/settings">
        {{ icon "settings" }}
        <span>{{ text "auth:link.settings" }}</span>
    </a>

    {% if is_helper %}
    <b class="title">{{ text "general:label.mod" }}</b>

    <a href="/mod_panel/audit_log">
        {{ icon "scroll-text" }}
        <span>{{ text "general:link.audit_log" }}</span>
    </a>

    <a href="/mod_panel/reports">
        {{ icon "flag" }}
        <span>{{ text "general:link.reports" }}</span>
    </a>

    <a href="/mod_panel/ip_bans">
        {{ icon "ban" }}
        <span>{{ text "general:link.ip_bans" }}</span>
    </a>

    <a href="/mod_panel/stats">
        {{ icon "chart-line" }}
        <span>{{ text "general:link.stats" }}</span>
    </a>
    {% endif %}

    <b class="title">{{ config.name }}</b>

    <a href="https://trisua.com/t/tetratto">
        {{ icon "code" }}
        <span>{{ text "general:link.source_code" }}</span>
    </a>

    <!-- <a href="https://trisuaso.github.io/tetratto">
        {{ icon "book" }}
        <span>{{ text "general:link.reference" }}</span>
    </a> -->

    <div class="title"></div>
    <button onclick="trigger('me::switch_account')">
        {{ icon "ellipsis" }}
        <span>{{ text "general:action.switch_account" }}</span>
    </button>

    <button class="red" onclick="trigger('me::logout')">
        {{ icon "log-out" }}
        <span>{{ text "auth:action.logout" }}</span>
    </button>
</div>
{%- endmacro %} {% macro user_status(other_user) -%} {% if
other_user.settings.status %}
<div class="flex items-center gap-2">
    <span>{{ other_user.settings.status }}</span>

    <!-- connection icon -->
    {% if (other_user.connections.LastFm[1].data and
    other_user.connections.LastFm[1].data.track) or
    (other_user.connections.Spotify[1].data and
    other_user.connections.Spotify[1].data.track) %} {{ icon "music" }} {% endif
    %}
</div>
{% elif other_user.connections.LastFm[0].data.name and
other_user.connections.LastFm[1].data and
other_user.connections.LastFm[1].data.track %}
<div class="flex items-center gap-2">
    {{ icon "music" }}
    <span
        ><b>Listening to</b> {{ other_user.connections.LastFm[1].data.artist
        }}</span
    >
</div>
{% elif other_user.connections.Spotify[0].data.name and
other_user.connections.Spotify[1].data and
other_user.connections.Spotify[1].data.track %}
<div class="flex items-center gap-2">
    {{ icon "music" }}
    <span
        ><b>Listening to</b> {{ other_user.connections.Spotify[1].data.artist
        }}</span
    >
</div>
{% endif %} {%- endmacro %} {% macro user_plate(user, show_menu=false,
secondary=false) -%}
<div
    class="flex gap-2 items-center card tiny user_plate {% if secondary %}secondary{% endif %}"
>
    <a href="/@{{ user.username }}">
        {{ self::avatar(username=user.username, size="42px",
        selector_type="username") }}
    </a>

    <div
        class="flex justify-center flex-col"
        style="{% if show_menu %}width: 60%{% endif %}"
    >
        {{ self::full_username(user=user) }}
        <div class="user_status">{{ self::user_status(other_user=user) }}</div>
    </div>

    {% if show_menu %}
    <div class="dropdown">
        <button
            class="camo small square"
            onclick="trigger('atto::hooks::dropdown', [event])"
            exclude="dropdown"
        >
            {{ icon "settings" c(dropdown-arrow) }}
        </button>

        {{ self::user_menu() }}
    </div>
    {% endif %}
</div>
{%- endmacro %} {% macro emoji_picker(element_id, render_dialog=false) -%}
<button
    class="button small square quaternary"
    onclick="window.EMOJI_PICKER_TEXT_ID = '{{ element_id }}'; document.getElementById('emoji_dialog').showModal()"
    title="Emojis"
    type="button"
>
    {{ icon "smile-plus" }}
</button>

{% if render_dialog %}
<dialog id="emoji_dialog">
    <div class="inner flex flex-col gap-2">
        <script
            type="module"
            src="https://unpkg.com/emoji-picker-element@1.22.8/index.js"
        ></script>

        <emoji-picker
            style="
                --border-radius: var(--radius);
                --background: var(--color-super-raised);
                --input-border-radiFus: var(--radius);
                --input-border-color: var(--color-primary);
                --indicator-color: var(--color-primary);
                --emoji-padding: 0.25rem;
                box-shadow: 0 0 4px var(--color-shadow);
            "
            class="w-full"
        ></emoji-picker>

        <script>
            document
                .querySelector("emoji-picker")
                .addEventListener("emoji-click", async (event) => {
                    if (event.detail.skinTone > 0) {
                        document.getElementById(
                            window.EMOJI_PICKER_TEXT_ID,
                        ).value += event.detail.unicode;

                        document.getElementById("emoji_dialog").close();
                        return;
                    }

                    document.getElementById(
                        window.EMOJI_PICKER_TEXT_ID,
                    ).value += ` :${await (
                        await fetch("/api/v1/lookup_emoji", {
                            method: "POST",
                            body: event.detail.unicode,
                        })
                    ).text()}:`;

                    document.getElementById("emoji_dialog").close();
                });
        </script>

        <div class="flex justify-between">
            <div></div>

            <div class="flex gap-2">
                <button
                    class="bold red quaternary"
                    onclick="document.getElementById('emoji_dialog').close()"
                    type="button"
                >
                    {{ icon "x" }} {{ text "dialog:action.close" }}
                </button>
            </div>
        </div>
    </div>
</dialog>
{% endif %} {%- endmacro %}