UX: Consistent styling for admin tables on mobile (#29360)

* UX: Apply admin table classes for consistent mobile styling on custom flags

* UX: Apply admin table classes for consistent mobile styling on custom flags

* UX: Apply admin table classes for consistent mobile styling on backups

* UX: Apply admin table classes for consistent mobile styling on plugins list

* DEV: tweaks on admin table

* UX: Apply admin table classes for consistent mobile styling on chat plugin

* apply prettier

* apply lint

* DEV: removed commented out code

* DEV: removed unnecessary div element

* scroll to the element

* remove the workaround

* revert

* add an extra assertion

* add enabled check

* improve switching

* rm

---------

Co-authored-by: Jarek Radosz <jradosz@gmail.com>
This commit is contained in:
Ella E. 2024-10-23 16:26:21 -06:00 committed by GitHub
parent bff9e723e1
commit 98a3e7d6e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 202 additions and 225 deletions

View File

@ -82,7 +82,7 @@ export default class AdminConfigAreasFlags extends Component {
</:actions>
</AdminPageSubheader>
<div class="container admin-flags">
<table class="admin-flags__items grid">
<table class="d-admin-table admin-flags__items">
<thead>
<th>{{i18n "admin.config_areas.flags.description"}}</th>
<th>{{i18n "admin.config_areas.flags.enabled"}}</th>

View File

@ -119,26 +119,31 @@ export default class AdminFlagItem extends Component {
<template>
<tr
class={{concatClass
"admin-flag-item"
"d-admin-row__content admin-flag-item"
@flag.name_key
(if this.isSaved "saved")
}}
>
<td>
<p class="admin-flag-item__name">{{@flag.name}}</p>
<p class="admin-flag-item__description">{{htmlSafe
<td class="d-admin-row__overview">
<div
class="d-admin-row__overview-name admin-flag-item__name"
>{{@flag.name}}</div>
<div class="d-admin-row__overview-about">{{htmlSafe
@flag.description
}}</p>
}}</div>
</td>
<td>
<td class="d-admin-row__detail">
<div class="d-admin-row__mobile-label">
{{i18n "admin.config_areas.flags.enabled"}}
</div>
<DToggleSwitch
@state={{this.enabled}}
class="admin-flag-item__toggle {{@flag.name_key}}"
{{on "click" (fn this.toggleFlagEnabled @flag)}}
/>
</td>
<td>
<div class="admin-flag-item__options admin-table-row-controls">
<td class="d-admin-row__controls">
<div class="d-admin-row__controls-options">
<DButton
class="btn-small admin-flag-item__edit"

View File

@ -61,13 +61,13 @@ export default class AdminPluginsListItem extends Component {
<tr
data-plugin-name={{@plugin.name}}
class={{concat
"admin-plugins-list__row"
"d-admin-row__content admin-plugins-list__row"
(if this.isAdminSearchFiltered "-admin-search-filtered")
}}
>
<td class="admin-plugins-list__name-details">
<td class="d-admin-row__overview admin-plugins-list__name-details">
<div class="admin-plugins-list__name-with-badges">
<div class="admin-plugins-list__name">
<div class="d-admin-row__overview-name admin-plugins-list__name">
{{@plugin.nameTitleized}}
</div>
@ -85,10 +85,10 @@ export default class AdminPluginsListItem extends Component {
@outletArgs={{hash plugin=@plugin}}
/>
</div>
<div class="admin-plugins-list__author">
<div class="d-admin-row__overview-author admin-plugins-list__author">
{{@plugin.author}}
</div>
<div class="admin-plugins-list__about">
<div class="d-admin-row__overview-about admin-plugins-list__about">
{{@plugin.about}}
{{#if @plugin.linkUrl}}
<a
@ -102,22 +102,28 @@ export default class AdminPluginsListItem extends Component {
{{/if}}
</div>
</td>
<td class="admin-plugins-list__version">
<PluginOutlet
@name="admin-plugin-list-item-version"
@outletArgs={{hash plugin=@plugin}}
>
<div class="label">{{i18n "admin.plugins.version"}}</div>
{{@plugin.version}}<br />
<PluginCommitHash @plugin={{@plugin}} />
</PluginOutlet>
<td class="d-admin-row__detail admin-plugins-list__version">
<div class="d-admin-row__mobile-label">
{{i18n "admin.plugins.version"}}
</div>
<div class="plugin-version">
<PluginOutlet
@name="admin-plugin-list-item-version"
@outletArgs={{hash plugin=@plugin}}
>
{{@plugin.version}}<br />
<PluginCommitHash @plugin={{@plugin}} />
</PluginOutlet>
</div>
</td>
<td class="admin-plugins-list__enabled">
<td class="d-admin-row__detail admin-plugins-list__enabled">
<div class="d-admin-row__mobile-label">
{{i18n "admin.plugins.enabled"}}
</div>
<PluginOutlet
@name="admin-plugin-list-item-enabled"
@outletArgs={{hash plugin=@plugin}}
>
<div class="label">{{i18n "admin.plugins.enabled"}}</div>
{{#if @plugin.enabledSetting}}
<DToggleSwitch
@state={{@plugin.enabled}}
@ -128,7 +134,7 @@ export default class AdminPluginsListItem extends Component {
{{/if}}
</PluginOutlet>
</td>
<td class="admin-plugins-list__settings">
<td class="d-admin-row__controls admin-plugins-list__settings">
<PluginOutlet
@name="admin-plugin-list-item-settings"
@outletArgs={{hash plugin=@plugin}}

View File

@ -2,7 +2,7 @@ import i18n from "discourse-common/helpers/i18n";
import AdminPluginsListItem from "./admin-plugins-list-item";
const AdminPluginsList = <template>
<table class="admin-plugins-list grid">
<table class="d-admin-table admin-plugins-list">
<thead>
<tr>
<th>{{i18n "admin.plugins.name"}}</th>

View File

@ -29,56 +29,70 @@
</div>
{{/if}}
<table class="grid admin-backups-list">
<table class="d-admin-table admin-backups-list">
<thead>
<th width="55%">{{i18n "admin.backups.columns.filename"}}</th>
<th width="10%">{{i18n "admin.backups.columns.size"}}</th>
<th>{{i18n "admin.backups.columns.filename"}}</th>
<th>{{i18n "admin.backups.columns.size"}}</th>
<th></th>
</thead>
<tbody>
{{#each this.model as |backup|}}
<tr class="backup-item-row" data-backup-filename={{backup.filename}}>
<td class="backup-filename">{{backup.filename}}</td>
<td class="backup-size">{{human-size backup.size}}</td>
<td class="backup-controls admin-table-row-controls">
<DButton
@action={{fn this.download backup}}
@title="admin.backups.operations.download.title"
@label="admin.backups.operations.download.label"
class="btn-default btn-small backup-item-row__download"
/>
<tr
class="d-admin-row__content backup-item-row"
data-backup-filename={{backup.filename}}
>
<td class="d-admin-row__detail">
<div class="backup-filename">
{{backup.filename}}
</div>
</td>
<td class="d-admin-row__detail backup-size">
<div class="d-admin-row__mobile-label">
{{i18n "admin.backups.columns.size"}}
</div>
{{human-size backup.size}}
</td>
<td class="d-admin-row__controls backup-controls">
<div class="d-admin-row__controls-options">
<DButton
@action={{fn this.download backup}}
@title="admin.backups.operations.download.title"
@label="admin.backups.operations.download.label"
class="btn-default btn-small backup-item-row__download"
/>
<DMenu
@identifier="backup-item-menu"
@title={{i18n "more_options"}}
@icon="ellipsis-vertical"
class="btn-small"
>
<:content>
<DropdownMenu as |dropdown|>
<dropdown.item>
<DButton
@icon="trash-can"
@action={{fn (route-action "destroyBackup") backup}}
@disabled={{this.status.isOperationRunning}}
@title={{this.deleteTitle}}
@label="admin.backups.operations.destroy.title"
class="btn-transparent btn-danger backup-item-row__delete"
/>
</dropdown.item>
<dropdown.item>
<DButton
@icon="play"
@action={{fn (route-action "startRestore") backup}}
@disabled={{this.status.restoreDisabled}}
@title={{this.restoreTitle}}
@label="admin.backups.operations.restore.label"
class="btn-transparent backup-item-row__restore"
/>
</dropdown.item>
</DropdownMenu>
</:content>
</DMenu>
<DMenu
@identifier="backup-item-menu"
@title={{i18n "more_options"}}
@icon="ellipsis-vertical"
class="btn-small"
>
<:content>
<DropdownMenu as |dropdown|>
<dropdown.item>
<DButton
@icon="trash-can"
@action={{fn (route-action "destroyBackup") backup}}
@disabled={{this.status.isOperationRunning}}
@title={{this.deleteTitle}}
@label="admin.backups.operations.destroy.title"
class="btn-transparent btn-danger backup-item-row__delete"
/>
</dropdown.item>
<dropdown.item>
<DButton
@icon="play"
@action={{fn (route-action "startRestore") backup}}
@disabled={{this.status.restoreDisabled}}
@title={{this.restoreTitle}}
@label="admin.backups.operations.restore.label"
class="btn-transparent backup-item-row__restore"
/>
</dropdown.item>
</DropdownMenu>
</:content>
</DMenu>
</div>
</td>
</tr>
{{else}}

View File

@ -26,32 +26,56 @@
}
td {
vertical-align: top;
padding-top: var(--space-3);
padding-bottom: var(--space-3);
@include breakpoint("tablet") {
display: block;
border-top: 1px solid var(--primary-very-low);
border-top: 1px solid var(--primary-low);
}
&:first-child,
&:last-child {
&:first-child {
@include breakpoint("tablet") {
border-top: 0;
}
}
&.d-admin-row__detail {
@include breakpoint("tablet") {
display: flex;
justify-content: space-between;
}
}
}
}
.d-admin-row__overview {
width: 55%;
@include breakpoint("tablet") {
width: auto;
border-top: 0;
}
&-name {
font-weight: 700;
max-width: 80%;
margin-bottom: var(--space-1);
}
&-author {
font-size: var(--font-down-2);
padding: 0 0 var(--space-1) 0;
font-size: var(--font-down-1);
margin-bottom: var(--space-1);
}
&-about {
padding-right: var(--space-4);
@include breakpoint("tablet") {
padding-top: var(--space-1);
}
.d-icon {
font-size: var(--font-down-3);
margin-bottom: 0.1em;
@ -59,21 +83,13 @@
}
}
td.d-admin-row__detail {
.d-admin-row__controls {
@include breakpoint("tablet") {
display: flex;
justify-content: space-between;
border-top: 1px solid var(--primary-low);
position: absolute;
top: 0;
right: 0;
}
}
.d-admin-row__toggle {
.d-toggle-switch {
display: inline-block;
}
}
.d-admin-row__control {
&-options {
text-align: right;
display: flex;
@ -85,12 +101,6 @@ td.d-admin-row__detail {
font-size: var(--font-down-1);
}
}
@include breakpoint("tablet") {
position: absolute;
top: 0;
right: 0;
}
}
.d-admin-row__mobile-label {

View File

@ -5,44 +5,14 @@
margin-top: 1em;
}
table {
@media screen and (min-width: 550px) {
td.backup-filename {
grid-column-start: 1;
grid-column-end: 6;
}
td.backup-size {
grid-column-end: -1;
text-align: right;
}
td.backup-controls {
margin-top: 0.25em;
grid-row: 2;
grid-column-start: 1;
grid-column-end: 5;
text-align: right;
.btn {
margin-top: 0.25em;
}
}
.d-admin-table {
.backup-size {
text-align: right;
}
@include breakpoint(mobile-extra-large) {
td.backup-filename {
grid-column-start: 1;
grid-column-end: 3;
}
td.backup-size {
text-align: right;
}
td.backup-controls {
grid-column-start: 1;
grid-column-end: 4;
}
}
@include breakpoint(tablet) {
td.backup-controls {
text-align: left;
}
.backup-filename {
width: 80%;
text-wrap: balance;
}
}
}

View File

@ -1,19 +1,16 @@
.admin-flag-item {
&__name {
font-weight: bold;
padding-bottom: 0;
margin-bottom: 0;
}
&__description {
margin-top: 0.5em;
}
.d-toggle-switch__label {
margin-bottom: 0;
}
.d-toggle-switch {
margin-right: 2em;
}
.admin-flags {
table.d-admin-table {
td:first-child {
width: 70%;
@include breakpoint("tablet") {
width: auto;
}
}
}
}
.admin-flag-item {
&__delete.btn,
&__delete.btn:hover {
border-top: 1px solid var(--primary-low);

View File

@ -8,42 +8,9 @@
}
.admin-plugins-list {
@media screen and (min-width: 550px) {
.admin-plugins-list__row {
grid-template-columns: 0fr repeat(4, 1fr);
}
}
@include breakpoint(mobile-extra-large) {
.admin-plugins-list__row {
grid-template-columns: 0fr repeat(3, 1fr);
}
.admin-plugins-list {
&__name-details {
grid-column-start: 2;
grid-column-end: -1;
}
&__settings {
grid-row: 2;
grid-column-start: 4;
text-align: right;
button {
display: flex;
}
}
&__version {
grid-row: 2;
grid-column-start: 3;
}
&__enabled {
grid-row: 2;
grid-column-start: 2;
}
.plugin-version {
@include breakpoint("tablet") {
text-align: right;
}
}
@ -51,19 +18,13 @@
background-color: var(--primary-low);
}
&__author {
font-size: var(--font-down-2);
padding: 0 0 0.25em 0;
}
&__name-with-badges {
display: flex;
padding: 8px 0 4px;
flex-wrap: wrap;
}
&__name {
font-weight: bold;
margin-right: 0.5em;
.badges {
margin-left: var(--space-1);
}
&__badge {
@ -74,22 +35,11 @@
padding: 4px 8px;
& + .admin-plugins-list__badge {
margin-left: 0.5em;
margin-left: var(--space-1);
}
}
&__version {
.commit-hash {
font-size: var(--font-down-1);
}
}
&__about {
padding: 8px 0;
.d-icon {
font-size: var(--font-down-3);
margin-bottom: 0.1em;
&:last-of-type {
margin-right: var(--space-1);
}
}
}

View File

@ -43,39 +43,64 @@ export default class AdminChatIncomingWebhooksList extends Component {
}
<template>
<table>
<table class="d-admin-table">
<thead>
<th>{{i18n "chat.incoming_webhooks.name"}}</th>
<th>{{i18n "chat.incoming_webhooks.emoji"}}</th>
<th>{{i18n "chat.incoming_webhooks.username"}}</th>
<th>{{i18n "chat.incoming_webhooks.description"}}</th>
<th>{{i18n "chat.incoming_webhooks.channel"}}</th>
<th></th>
</thead>
<tbody>
{{#each this.sortedWebhooks as |webhook|}}
<tr class="incoming-chat-webhooks-row" data-webhook-id={{webhook.id}}>
<td>{{webhook.name}}</td>
<td>{{replaceEmoji webhook.emoji}}</td>
<td>{{webhook.username}}</td>
<td>{{webhook.description}}</td>
<td><ChannelTitle @channel={{webhook.chat_channel}} /></td>
<tr
class="d-admin-row__content incoming-chat-webhooks-row"
data-webhook-id={{webhook.id}}
>
<td class="d-admin-row__overview">
<div class="d-admin-row__overview-name">
{{webhook.name}}
</div>
<div class="d-admin-row__overview-about">
{{webhook.description}}
</div>
</td>
<td class="d-admin-row__detail">
<div class="d-admin-row__mobile-label">
{{i18n "chat.incoming_webhooks.emoji"}}
</div>
{{replaceEmoji webhook.emoji}}
</td>
<td class="d-admin-row__detail">
<div class="d-admin-row__mobile-label">
{{i18n "chat.incoming_webhooks.username"}}
</div>
{{webhook.username}}
</td>
<td class="d-admin-row__detail">
<div class="d-admin-row__mobile-label">
{{i18n "chat.incoming_webhooks.channel"}}
</div>
<ChannelTitle @channel={{webhook.chat_channel}} />
</td>
<td
class="incoming-chat-webhooks-row__controls admin-table-row-controls"
class="d-admin-row__controls incoming-chat-webhooks-row__controls"
>
<LinkTo
@route="adminPlugins.show.discourse-chat-incoming-webhooks.show"
@model={{webhook.id}}
class="btn btn-small admin-chat-incoming-webhooks-edit"
>{{i18n "chat.incoming_webhooks.edit"}}</LinkTo>
<div class="d-admin-row__controls-options">
<LinkTo
@route="adminPlugins.show.discourse-chat-incoming-webhooks.show"
@model={{webhook.id}}
class="btn btn-small admin-chat-incoming-webhooks-edit"
>{{i18n "chat.incoming_webhooks.edit"}}</LinkTo>
<DButton
@icon="trash-alt"
@title="chat.incoming_webhooks.delete"
@action={{fn this.destroyWebhook webhook}}
class="btn-danger btn-small admin-chat-incoming-webhooks-delete"
/>
<DButton
@icon="trash-alt"
@title="chat.incoming_webhooks.delete"
@action={{fn this.destroyWebhook webhook}}
class="btn-danger btn-small admin-chat-incoming-webhooks-delete"
/>
</div>
</td>
</tr>
{{/each}}