[MTM] Tweaks and fixes #120
7 changed files with 135 additions and 45 deletions
Restyle the Micropub tokens admin table
Breaks the table out of the centred content column to full page width via a subgrid on <main> (adds a reusable .full-bleed utility), and reworks the table itself to match a Claude Design mockup: a rounded card wrapper, scope values as pill chips, a dotted status pill, and proportional column widths. Colours use the site's existing --primary-hue/light-dark() tokens so it stays correct in both themes. The card scrolls horizontally on narrow viewports instead of clipping content. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LHN7V9kyZxrsxaspMSqoGJ
commit
6a0bb623fc
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
|
@ -1,21 +1,34 @@
|
||||||
@layer components {
|
@layer components {
|
||||||
|
.token-list-wrapper {
|
||||||
|
margin-block-start: 1em;
|
||||||
|
border: 1px solid var(--clr-border);
|
||||||
|
border-radius: 16px;
|
||||||
|
overflow: auto hidden;
|
||||||
|
background: light-dark(
|
||||||
|
oklch(99% 0.02 var(--primary-hue)),
|
||||||
|
oklch(22% 0.05 var(--primary-hue))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
.token-list {
|
.token-list {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
min-width: 640px;
|
||||||
|
table-layout: fixed;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
margin-block-start: 1em;
|
|
||||||
|
|
||||||
th,
|
th,
|
||||||
td {
|
td {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 0.6em 0.8em;
|
padding: 0.9em 1.2em;
|
||||||
border-bottom: 1px solid var(--clr-border);
|
border-bottom: 1px solid var(--clr-border);
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
font-size: 0.85em;
|
font-size: 0.8em;
|
||||||
|
font-weight: 700;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.03em;
|
letter-spacing: 0.08em;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,14 +39,65 @@
|
||||||
a {
|
a {
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
th:nth-child(1),
|
||||||
|
td:nth-child(1) {
|
||||||
|
width: 31%;
|
||||||
|
}
|
||||||
|
|
||||||
|
th:nth-child(2),
|
||||||
|
td:nth-child(2) {
|
||||||
|
width: 24%;
|
||||||
|
}
|
||||||
|
|
||||||
|
th:nth-child(3),
|
||||||
|
td:nth-child(3) {
|
||||||
|
width: 15%;
|
||||||
|
}
|
||||||
|
|
||||||
|
th:nth-child(4),
|
||||||
|
td:nth-child(4) {
|
||||||
|
width: 16%;
|
||||||
|
}
|
||||||
|
|
||||||
|
th:nth-child(5),
|
||||||
|
td:nth-child(5) {
|
||||||
|
width: 14%;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:last-child td {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scope-chips {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scope-chip {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.2em 0.7em;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: light-dark(
|
||||||
|
oklch(92% 0.05 var(--primary-hue)),
|
||||||
|
oklch(35% 0.08 var(--primary-hue))
|
||||||
|
);
|
||||||
|
font-size: 0.85em;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge,
|
.badge,
|
||||||
.token-list button.revoke {
|
.token-list button.revoke {
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
padding: 0.2em 0.7em;
|
align-items: center;
|
||||||
|
gap: 0.4em;
|
||||||
|
padding: 0.3em 0.8em;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
|
font-weight: 600;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
@ -45,10 +109,18 @@
|
||||||
|
|
||||||
.badge-active {
|
.badge-active {
|
||||||
color: light-dark(oklch(35% 0.16 145deg), oklch(75% 0.16 145deg));
|
color: light-dark(oklch(35% 0.16 145deg), oklch(75% 0.16 145deg));
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: currentcolor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-revoked {
|
.badge-revoked {
|
||||||
color: var(--clr-text);
|
color: var(--clr-text);
|
||||||
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.token-list button.revoke {
|
.token-list button.revoke {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
> main {
|
> main {
|
||||||
grid-column: 2/3;
|
grid-column: 1/-1;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: subgrid;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
grid-column: 2/3;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .full-bleed {
|
||||||
|
grid-column: 1/-1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> footer {
|
> footer {
|
||||||
|
|
|
||||||
|
|
@ -7,41 +7,49 @@
|
||||||
@if($tokens->isEmpty())
|
@if($tokens->isEmpty())
|
||||||
<p>No tokens have been issued.</p>
|
<p>No tokens have been issued.</p>
|
||||||
@else
|
@else
|
||||||
<table class="token-list">
|
<div class="full-bleed token-list-wrapper">
|
||||||
<thead>
|
<table class="token-list">
|
||||||
<tr>
|
<thead>
|
||||||
<th scope="col">Client</th>
|
<tr>
|
||||||
<th scope="col">Scope</th>
|
<th scope="col">Client</th>
|
||||||
<th scope="col">Issued</th>
|
<th scope="col">Scope</th>
|
||||||
<th scope="col">Status</th>
|
<th scope="col">Issued</th>
|
||||||
<th scope="col">Action</th>
|
<th scope="col">Status</th>
|
||||||
</tr>
|
<th scope="col">Action</th>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody>
|
</thead>
|
||||||
@foreach($tokens as $token)
|
<tbody>
|
||||||
<tr class="{{ $token->isRevoked ? 'is-revoked' : '' }}">
|
@foreach($tokens as $token)
|
||||||
<td><a href="{{ $token->client_id }}" rel="noopener">{{ $token->client_id }}</a></td>
|
<tr class="{{ $token->isRevoked ? 'is-revoked' : '' }}">
|
||||||
<td>{{ $token->scope }}</td>
|
<td><a href="{{ $token->client_id }}" rel="noopener">{{ $token->client_id }}</a></td>
|
||||||
<td><time datetime="{{ $token->created_at->toIso8601String() }}" title="{{ $token->created_at }}">{{ $token->created_at->diffForHumans() }}</time></td>
|
<td>
|
||||||
<td>
|
<span class="scope-chips">
|
||||||
@if($token->isRevoked)
|
@foreach(explode(' ', $token->scope) as $scope)
|
||||||
<span class="badge badge-revoked">Revoked {{ $token->revoked_at->diffForHumans() }}</span>
|
<span class="scope-chip">{{ $scope }}</span>
|
||||||
@else
|
@endforeach
|
||||||
<span class="badge badge-active">Active</span>
|
</span>
|
||||||
@endif
|
</td>
|
||||||
</td>
|
<td><time datetime="{{ $token->created_at->toIso8601String() }}" title="{{ $token->created_at }}">{{ $token->created_at->diffForHumans() }}</time></td>
|
||||||
<td>
|
<td>
|
||||||
@unless($token->isRevoked)
|
@if($token->isRevoked)
|
||||||
<form action="/admin/tokens/{{ $token->id }}/revoke" method="post" onsubmit="return confirm('Revoke this token? This cannot be undone.')">
|
<span class="badge badge-revoked">Revoked {{ $token->revoked_at->diffForHumans() }}</span>
|
||||||
{{ csrf_field() }}
|
@else
|
||||||
{{ method_field('PUT') }}
|
<span class="badge badge-active"><span class="dot"></span>Active</span>
|
||||||
<button type="submit" class="revoke" name="revoke">Revoke</button>
|
@endif
|
||||||
</form>
|
</td>
|
||||||
@endunless
|
<td>
|
||||||
</td>
|
@unless($token->isRevoked)
|
||||||
</tr>
|
<form action="/admin/tokens/{{ $token->id }}/revoke" method="post" onsubmit="return confirm('Revoke this token? This cannot be undone.')">
|
||||||
@endforeach
|
{{ csrf_field() }}
|
||||||
</tbody>
|
{{ method_field('PUT') }}
|
||||||
</table>
|
<button type="submit" class="revoke" name="revoke">Revoke</button>
|
||||||
|
</form>
|
||||||
|
@endunless
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue