feat: Give scope lists and device cards a fresh coat of paint

This commit is contained in:
Ginger authored and Ellis Git committed 2026-10-05 14:22:53 +00:00
1 parent 38f8011b95
commit 0d48c9681d
10 files changed
+147 -54

No files matched your search

-2
View File
@@ -122,7 +122,6 @@ pub(super) struct DeviceCard {
pub display_name: Option<String>,
pub avatar: Avatar,
pub last_active: String,
pub oauth_metadata: Option<ClientMetadata>,
pub style: DeviceCardStyle,
pub dehydrated: bool,
}
@@ -192,7 +191,6 @@ impl DeviceCard {
display_name,
avatar,
last_active,
oauth_metadata,
style,
dehydrated,
}
+74 -10
View File
@@ -16,6 +16,8 @@
--card-bg: oklch(from var(--panel-bg) calc(l - 0.05) c h);
--c1: oklch(0.44 0.177 353.06);
--c2: oklch(0.59 0.158 150.88);
--danger-color: oklch(87.303% 0.06774 18.457);
--danger-color-dark: oklch(0.2 0.197 20.272);
--avatar-color: var(--c2);
--name-lightness: 0.45;
@@ -41,6 +43,7 @@
--secondary: var(--secondary-dark);
--bg: var(--bg-dark);
--panel-bg: var(--panel-bg-dark);
--danger-color: var(--danger-color-dark);
--name-lightness: 0.8;
--background-lightness: 0.2;
@@ -143,7 +146,6 @@ small.error {
margin-bottom: 0.5rem;
}
img.matrix-icon {
@media (prefers-color-scheme: dark) {
filter: invert();
@@ -173,7 +175,8 @@ label {
margin-bottom: 0.2em;
}
a, a:visited {
a,
a:visited {
color: oklch(from var(--c1) var(--name-lightness) c h);
}
@@ -182,13 +185,15 @@ code {
}
pre {
background-color: oklch(from var(--panel-bg) calc(l - 0.05) c h);
background-color: var(--card-bg);
border-radius: var(--border-radius-sm);
padding: 8px;
overflow-x: scroll;
}
input, button, a.button {
input,
button,
a.button {
display: inline-block;
padding: 0.5em;
@@ -218,10 +223,11 @@ input[type="checkbox"] {
width: auto !important;
}
button, a.button {
button,
a.button {
color: white;
background-color: var(--c1);
transition: opacity .2s;
transition: opacity 0.2s;
text-align: center;
margin: 0.5rem 0;
@@ -231,7 +237,9 @@ button, a.button {
}
&:not(:disabled) {
transition: linear color, background-color 0.1s;
transition:
linear color,
background-color 0.1s;
&:hover {
opacity: 0.8;
@@ -265,6 +273,44 @@ ul.bullet-separated {
}
}
ul.list-group {
list-style: none;
display: flex;
flex-direction: column;
padding: 0;
li {
display: block;
background-color: var(--card-bg);
padding: 10px;
margin-bottom: 3px;
color: var(--secondary);
&:first-child {
border-top-left-radius: var(--border-radius-lg);
border-top-right-radius: var(--border-radius-lg);
}
&:last-child {
border-bottom-left-radius: var(--border-radius-lg);
border-bottom-right-radius: var(--border-radius-lg);
margin-bottom: 0;
}
&.danger {
color: var(--text-color);
background-color: var(--danger-color);
}
svg {
vertical-align: center;
margin-inline-end: 0.5rem;
width: 20px;
height: 20px;
}
}
}
.fullwidth {
width: 100%;
margin-bottom: 0 !important;
@@ -274,6 +320,10 @@ ul.bullet-separated {
user-select: all;
}
.small-text {
font-size: small;
}
.panel {
--preferred-width: 12rem + 40dvw;
--maximum-width: 48rem;
@@ -297,7 +347,9 @@ ul.bullet-separated {
--preferred-width: 12rem + 20dvw;
--maximum-width: 36rem;
input, button, a.button {
input,
button,
a.button {
width: 100%;
}
}
@@ -340,7 +392,12 @@ ul.bullet-separated {
}
}
@media (max-width: 450px) {
.bi {
display: inline-block;
vertical-align: -.125em;
}
@media (max-width: 425px) {
main {
padding-block-start: 2rem;
width: 100%;
@@ -362,7 +419,14 @@ ul.bullet-separated {
}
@media (max-width: 799px) {
input, button, a.button {
input,
button,
a.button {
width: 100%;
}
}
@font-face {
font-family: "Boots";
src: url();
}
+2 -1
View File
@@ -48,7 +48,8 @@
&.danger {
display: block;
background-color: oklch(from red 0.2 c h);
color: var(--text-color);
background-color: var(--danger-color);
border: 1px dashed red;
}
+6
View File
@@ -9,6 +9,12 @@
color: var(--secondary);
font-size: x-large;
user-select: none;
svg {
vertical-align: center;
width: 24px;
height: 24px;
}
}
}
@@ -1,10 +1,18 @@
<ul>
{% import "../_icons.html.j2" as icons %}
<ul class="list-group">
{% for scope in scopes %}
{% match scope %}
{% when OAuthClientScope::ApiFullAccess %}
<li>Access and control all features of your Matrix account</li>
<li>
{{ icons::person_circle() }}
Access and control all features of your Matrix account
</li>
{% when OAuthClientScope::ServerAdministration %}
<li>⚠️ Access your homeserver's administrator tools</li>
<li class="danger">
{{ icons::house_gear() }}
Access your homeserver's administrator tools
</li>
{% when _ %}
<li>missingno</li>
{% endmatch %}
@@ -14,22 +14,12 @@
</span>
{% if style == DeviceCardStyle::Detailed %}
<span class="id">
<span class="mobile-hidden">•</span>
<ul class="bullet-separated">
<li>{{ device_id }}</li>
<li>
{% if let Some(metadata) = oauth_metadata %}
<a href="{{ metadata.client_uri }}">Client website</a>
{% else %}
legacy
{% endif %}
</li>
</span>
#{{ device_id }}
</span>
{% endif %}
</div>
<div>
Last active: {{ last_active }}
Last active {{ last_active }}
</div>
<div>
{% if style != DeviceCardStyle::Detailed %}
+25
View File
@@ -0,0 +1,25 @@
{% macro person_circle() %}
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16">
<path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0"/>
<path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1"/>
</svg>
{% endmacro %}
{% macro house_gear() %}
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-house-gear" viewBox="0 0 16 16">
<path d="M7.293 1.5a1 1 0 0 1 1.414 0L11 3.793V2.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v3.293l2.354 2.353a.5.5 0 0 1-.708.708L8 2.207l-5 5V13.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 1 0 1h-4A1.5 1.5 0 0 1 2 13.5V8.207l-.646.647a.5.5 0 1 1-.708-.708z"/>
<path d="M11.886 9.46c.18-.613 1.048-.613 1.229 0l.043.148a.64.64 0 0 0 .921.382l.136-.074c.561-.306 1.175.308.87.869l-.075.136a.64.64 0 0 0 .382.92l.149.045c.612.18.612 1.048 0 1.229l-.15.043a.64.64 0 0 0-.38.921l.074.136c.305.561-.309 1.175-.87.87l-.136-.075a.64.64 0 0 0-.92.382l-.045.149c-.18.612-1.048.612-1.229 0l-.043-.15a.64.64 0 0 0-.921-.38l-.136.074c-.561.305-1.175-.309-.87-.87l.075-.136a.64.64 0 0 0-.382-.92l-.148-.044c-.613-.181-.613-1.049 0-1.23l.148-.043a.64.64 0 0 0 .382-.921l-.074-.136c-.306-.561.308-1.175.869-.87l.136.075a.64.64 0 0 0 .92-.382zM14 12.5a1.5 1.5 0 1 0-3 0 1.5 1.5 0 0 0 3 0"/>
</svg>
{% endmacro %}
{% macro person_lock() %}
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person-fill-lock" viewBox="0 0 16 16">
<path d="M11 5a3 3 0 1 1-6 0 3 3 0 0 1 6 0m-9 8c0 1 1 1 1 1h5v-1a2 2 0 0 1 .01-.2 4.49 4.49 0 0 1 1.534-3.693Q8.844 9.002 8 9c-5 0-6 3-6 4m7 0a1 1 0 0 1 1-1v-1a2 2 0 1 1 4 0v1a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1zm3-3a1 1 0 0 0-1 1v1h2v-1a1 1 0 0 0-1-1"/>
</svg>
{% endmacro %}
{% macro arrow_left_right() %}
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1 11.5a.5.5 0 0 0 .5.5h11.793l-3.147 3.146a.5.5 0 0 0 .708.708l4-4a.5.5 0 0 0 0-.708l-4-4a.5.5 0 0 0-.708.708L13.293 11H1.5a.5.5 0 0 0-.5.5m14-7a.5.5 0 0 1-.5.5H2.707l3.147 3.146a.5.5 0 1 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 4H14.5a.5.5 0 0 1 .5.5"/>
</svg>
{% endmacro %}
+3 -2
View File
@@ -1,4 +1,5 @@
{% extends "_layout.html.j2" %}
{% import "_icons.html.j2" as icons %}
{%- block title -%}
Your account
@@ -12,7 +13,7 @@ Your account
{% when AccountBody::Unlocked { suspended, email_requirement, email, devices, oidc_enabled, dehydrated_device_id } %}
{% if suspended %}
<p class="card danger">
⚠️ Your account has been suspended by your homeserver's administrator.
{{ icons::person_lock() }} Your account has been suspended by your homeserver's administrator.
Some functionality may be restricted.
</p>
{% endif %}
@@ -73,7 +74,7 @@ Your account
</section>
{% when AccountBody::Locked %}
<p class="card danger">
⚠️ Your account has been locked by your homeserver's administrator.
{{ icons::person_lock() }} Your account has been locked by your homeserver's administrator.
</p>
<section>
<a class="button fullwidth" href="logout">Log out</a>
+22 -23
View File
@@ -9,36 +9,35 @@ Device information
<h1>About device <a class="back" href="{{ crate::ROUTE_PREFIX }}/account/">Back</a></h1>
{{ device_card }}
{% if let Some((client_metadata, _)) = client_metadata %}
{% if client_metadata.tos_uri.is_some() || client_metadata.policy_uri.is_some() %}
<section>
<ul class="bullet-separated">
{% if let Some(tos_uri) = &client_metadata.tos_uri %}
<li><a href="{{ tos_uri }}">Terms of service</a></li>
{% endif %}
{% if let Some(policy_uri) = &client_metadata.policy_uri %}
<li><a href="{{ policy_uri }}">Policies</a></li>
{% endif %}
</ul>
</section>
{% endif %}
<section>
<ul class="bullet-separated">
<li><a href="{{ client_metadata.client_uri }}">Client website</a></li>
{% if let Some(tos_uri) = &client_metadata.tos_uri %}
<li><a href="{{ tos_uri }}">Terms of service</a></li>
{% endif %}
{% if let Some(policy_uri) = &client_metadata.policy_uri %}
<li><a href="{{ policy_uri }}">Policies</a></li>
{% endif %}
</ul>
</section>
{% endif %}
<section>
<p>
{% if let Some((_, session_info)) = client_metadata %}
This device has permission to:
{{ ClientScopes { scopes: session_info.scopes() } }}
{% else if device_card.dehydrated %}
This is your dehydrated device. It saves encryption keys for you while you're offline.
{% else %}
{% if let Some((_, session_info)) = client_metadata %}
<p>This device has permission to:</p>
{{ ClientScopes { scopes: session_info.scopes() } }}
{% else if device_card.dehydrated %}
<p>This is your dehydrated device. It saves encryption keys for you while you're offline.</p>
{% else %}
<p>
This device can access and control all features of your Matrix account.
<br>
<small>❖ This is a legacy device. Legacy devices always have full access to your account.</small>
{% endif %}
</p>
</p>
{% endif %}
<a class="button" href="remove">Remove this device</a>
</section>
<a class="button" href="remove">Remove this device</a>
{% if let Some((client_metadata, session_info)) = client_metadata %}
<details>
<details class="small-text">
<summary>Client registration</summary>
<p>
OAuth client ID: <code>{{ session_info.client_id }}</code>
+2 -1
View File
@@ -1,4 +1,5 @@
{% extends "_layout.html.j2" %}
{% import "_icons.html.j2" as icons %}
{%- block head -%}
<link rel="stylesheet" href="{{ crate::ROUTE_PREFIX }}/resources/grant.css">
@@ -17,7 +18,7 @@ Authorize client
{{ user_avatar }}
</div>
<div class="separator" aria-hidden="true">
⇄
{{ icons::arrow_left_right() }}
</div>
{{ Avatar::for_client(client_metadata) }}
</div>