rustlavel-cli 0.7.4

The rustlavel command-line tool: new, serve, make:*
@extends("layouts.app")
@section("title", "Users")

@section("content")
  {{-- The page's own header, rather than relying on the one in the bar: this
       page has a subtitle and a primary action, and both belong beside the
       title they describe. --}}
  <div class="mb-4 flex flex-wrap items-end justify-between gap-3">
    <div>
      <h2 class="text-xl font-extrabold tracking-tight">Users</h2>
      <p class="mt-0.5 text-xs text-ink-500 dark:text-ink-400">Manage user roles and permissions</p>
    </div>
    @if(can_create)
      <a href="/admin/users/create" class="btn-primary">
        <svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M10 3a.75.75 0 0 1 .75.75v5.5h5.5a.75.75 0 0 1 0 1.5h-5.5v5.5a.75.75 0 0 1-1.5 0v-5.5h-5.5a.75.75 0 0 1 0-1.5h5.5v-5.5A.75.75 0 0 1 10 3Z"/></svg>
        Create User
      </a>
    @endif
  </div>

  <div class="card mb-5">
    <div class="card-body">
      <form method="get" action="/admin/users" class="flex items-center gap-3">
        <label for="q" class="sr-only">Search users by name, email or role</label>
        <input id="q" name="q" type="search" value="{{ q }}"
               placeholder="Search users by name, email or role..." class="field-input min-w-0 flex-1">
        {{-- The role filter stays, but folded away: it was the only thing on
             this row before and it crowded a search box that people reach for
             first. --}}
        <label for="role" class="sr-only">Filter by role</label>
        <select id="role" name="role" class="field-input w-44 shrink-0">
          <option value="">All roles</option>
          @foreach(all_roles as role)
            <option value="{{ role.name }}" @if(role.selected) selected @endif>{{ role.name }}</option>
          @endforeach
        </select>
        <button type="submit" class="btn-primary shrink-0" aria-label="Search">
          <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" d="M9 3.5a5.5 5.5 0 1 0 3.383 9.836l3.14 3.141a.75.75 0 1 0 1.061-1.06l-3.14-3.141A5.5 5.5 0 0 0 9 3.5ZM5 9a4 4 0 1 1 8 0 4 4 0 0 1-8 0Z" clip-rule="evenodd"/></svg>
        </button>
      </form>
    </div>
  </div>

  {{-- Six counts. Each is a real query rather than a placeholder, and each says
       something a person administering this actually asks: how many accounts
       are there, how many have confirmed their address, who has been here
       today, how many hold a role at all, how many carry an exception, and how
       many arrived this week. --}}
  @include("partials.stats")

  <div class="card">
    <div class="table-wrap">
      <table class="table">
        <thead>
          <tr>
            <th>User</th>
            <th class="hidden sm:table-cell">Roles</th>
            <th class="hidden md:table-cell">Direct permissions</th>
            <th class="hidden lg:table-cell">Joined at</th>
            <th class="text-right">Actions</th>
          </tr>
        </thead>
        <tbody>
          @foreach(users as user)
            <tr>
              <td>
                <div class="flex items-center gap-3">
                  <span class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-brand-600 text-sm font-semibold text-white">{{ user.initials }}</span>
                  <div class="min-w-0">
                    <p class="truncate font-medium text-ink-900 dark:text-ink-100">{{ user.name }}</p>
                    <p class="truncate text-xs text-ink-500 dark:text-ink-400">{{ user.email }}</p>
                  </div>
                </div>
              </td>
              <td class="hidden sm:table-cell">
                <span class="flex flex-wrap gap-1">
                  @foreach(user.roles as role)<span class="badge-brand">{{ role }}</span>@endforeach
                  @if(user.roles_empty)<span class="text-xs text-ink-400">&mdash;</span>@endif
                </span>
              </td>
              <td class="hidden md:table-cell tabular-nums">{{ user.direct_permissions }}</td>
              <td class="hidden whitespace-nowrap lg:table-cell">{{ user.joined_at }}</td>
              <td>
                {{-- Icons rather than words: five actions spelled out push the
                     table wider than the screen. Each carries its own label for
                     a screen reader and a title for a hovering mouse. --}}
                <div class="flex items-center justify-end gap-1.5">
                  @if(can_update)
                    <a href="/admin/users/{{ user.id }}/edit" class="icon-action icon-action-neutral" title="View {{ user.name }}" aria-label="View {{ user.name }}">
                      <svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M10 4C5.5 4 2 10 2 10s3.5 6 8 6 8-6 8-6-3.5-6-8-6Zm0 10a4 4 0 1 1 0-8 4 4 0 0 1 0 8Zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z"/></svg>
                    </a>
                    <a href="/admin/users/{{ user.id }}/edit" class="icon-action icon-action-brand" title="Edit {{ user.name }}" aria-label="Edit {{ user.name }}">
                      <svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M13.586 3.586a2 2 0 1 1 2.828 2.828l-.793.793-2.828-2.828.793-.793ZM11.379 5.793 3 14.172V17h2.828l8.379-8.379-2.828-2.828Z"/></svg>
                    </a>
                    <a href="/admin/users/{{ user.id }}/edit#roles" class="icon-action icon-action-violet" title="Roles for {{ user.name }}" aria-label="Roles for {{ user.name }}">
                      <svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M7 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm6 1a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5ZM1.6 15.5A5.6 5.6 0 0 1 7 10.5a5.6 5.6 0 0 1 5.4 5H1.6Zm12.05 0a6.9 6.9 0 0 0-1.6-3.86A4.2 4.2 0 0 1 18.4 15.5h-4.75Z"/></svg>
                    </a>
                    <a href="/admin/users/{{ user.id }}/edit#permissions" class="icon-action icon-action-emerald" title="Permissions for {{ user.name }}" aria-label="Permissions for {{ user.name }}">
                      <svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M13 2a5 5 0 0 0-4.9 6L2 14.1V18h3.9l1.3-1.3v-1.6h1.6l1.3-1.3v-1.6h1.6l.4-.4A5 5 0 1 0 13 2Zm1.5 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"/></svg>
                    </a>
                  @endif
                  @if(can_impersonate && user.impersonatable)
                    <form method="post" action="/impersonate/{{ user.id }}"
                          data-confirm="View the site as {{ user.name }}? Everything you do will be recorded against your own account.">
                      {!! csrf_field !!}
                      <button type="submit" class="icon-action icon-action-amber" title="View the site as {{ user.name }}" aria-label="View the site as {{ user.name }}">
                        <svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M10 3.5a6.5 6.5 0 0 1 6.32 5H18a.75.75 0 0 1 0 1.5h-1.68A6.5 6.5 0 1 1 10 3.5Zm0 2a4.5 4.5 0 1 0 0 9 4.5 4.5 0 0 0 0-9Zm0 2a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5Z"/></svg>
                      </button>
                    </form>
                  @endif
                  @if(can_delete && user.deletable)
                    <form method="post" action="/admin/users/{{ user.id }}/delete"
                          data-confirm="Delete {{ user.name }}? This cannot be undone.">
                      {!! csrf_field !!}
                      <button type="submit" class="icon-action icon-action-danger" title="Delete {{ user.name }}" aria-label="Delete {{ user.name }}">
                        <svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M8.5 2a1 1 0 0 0-1 1v.5h-3a.75.75 0 0 0 0 1.5h11a.75.75 0 0 0 0-1.5h-3V3a1 1 0 0 0-1-1h-3Zm-3 4.5h9l-.7 9.1A1.5 1.5 0 0 1 12.3 17H7.7a1.5 1.5 0 0 1-1.5-1.4L5.5 6.5Z"/></svg>
                      </button>
                    </form>
                  @endif
                </div>
              </td>
            </tr>
          @endforeach
          @if(users_empty)
            <tr><td colspan="5" class="py-16 text-center text-ink-500 dark:text-ink-400">No users match that.</td></tr>
          @endif
        </tbody>
      </table>
    </div>
    @include("partials.pagination")
  </div>
@endsection