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> </:actions>
</AdminPageSubheader> </AdminPageSubheader>
<div class="container admin-flags"> <div class="container admin-flags">
<table class="admin-flags__items grid"> <table class="d-admin-table admin-flags__items">
<thead> <thead>
<th>{{i18n "admin.config_areas.flags.description"}}</th> <th>{{i18n "admin.config_areas.flags.description"}}</th>
<th>{{i18n "admin.config_areas.flags.enabled"}}</th> <th>{{i18n "admin.config_areas.flags.enabled"}}</th>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,44 +5,14 @@
margin-top: 1em; margin-top: 1em;
} }
table { .d-admin-table {
@media screen and (min-width: 550px) { .backup-size {
td.backup-filename { text-align: right;
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;
}
}
} }
@include breakpoint(mobile-extra-large) {
td.backup-filename { .backup-filename {
grid-column-start: 1; width: 80%;
grid-column-end: 3; text-wrap: balance;
}
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;
}
} }
} }
} }

View File

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

View File

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

View File

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