UX: Apply admin UI to Badges (#28724)

* UX: Add a description about badges

* WIP: Apply admin UI guidelines

* FIX: Add routeModels to dbutton

Allows routeModels to be passed to a DButton along
with route, so we can use them as a LinkTo replacement
in more places.

Also fix up badges admin page header.

* UX: Reorder action buttons

* UX: Change header hierarchy to better align page's content structure

* UX: Update copy and remove unnecessary UI elements

* UX: Adjust header's icon spacing

* UX: Fix the header action buttons on mobile

* Apply prettier

---------

Co-authored-by: Martin Brennan <martin@discourse.org>
This commit is contained in:
Ella E. 2024-09-04 20:18:23 -06:00 committed by GitHub
parent 06d749eadd
commit be5c37a6d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 78 additions and 84 deletions

View File

@ -6,6 +6,7 @@ export const AdminPageActionButton = <template>
...attributes
@action={{@action}}
@route={{@route}}
@routeModels={{@routeModels}}
@label={{@label}}
@title={{@title}}
@icon={{@icon}}
@ -18,6 +19,7 @@ export const PrimaryButton = <template>
...attributes
@action={{@action}}
@route={{@route}}
@routeModels={{@routeModels}}
@label={{@label}}
@title={{@title}}
@icon={{@icon}}
@ -30,6 +32,7 @@ export const DangerButton = <template>
...attributes
@action={{@action}}
@route={{@route}}
@routeModels={{@routeModels}}
@label={{@label}}
@title={{@title}}
@icon={{@icon}}
@ -42,6 +45,7 @@ export const DefaultButton = <template>
...attributes
@action={{@action}}
@route={{@route}}
@routeModels={{@routeModels}}
@label={{@label}}
@title={{@title}}
@icon={{@icon}}

View File

@ -1,22 +1,8 @@
import Route from "@ember/routing/route";
import { emojiUrlFor } from "discourse/lib/text";
const badgeIntroLinks = [
{
text: "admin.badges.badge_intro.what_are_badges_title",
href: "https://meta.discourse.org/t/32540",
icon: "book",
},
{
text: "admin.badges.badge_intro.badge_query_examples_title",
href: "https://meta.discourse.org/t/18978",
icon: "book",
},
];
export default class AdminBadgesIndexRoute extends Route {
setupController(controller) {
controller.badgeIntroLinks = badgeIntroLinks;
controller.badgeIntroEmoji = emojiUrlFor("woman_student:t4");
}
}

View File

@ -1,28 +1,39 @@
<div class="badges">
<div class="badges-header">
<h3 class="badges-heading">{{i18n "admin.badges.title"}}</h3>
<div class="create-new-badge">
<LinkTo @route="adminBadges.award" @model="new" class="btn btn-default">
{{d-icon "upload"}}
<span class="d-button-label">{{i18n
"admin.badges.mass_award.title"
}}</span>
</LinkTo>
<DButton
@action={{route-action "editGroupings"}}
@translatedLabel="Group settings"
@icon="cog"
@class="btn-default edit-groupings-btn"
<AdminPageHeader
@titleLabel="admin.badges.title"
@descriptionLabel="admin.badges.description"
@learnMoreUrl="https://meta.discourse.org/t/understanding-and-using-badges/32540"
>
<:breadcrumbs>
<DBreadcrumbsItem
@path="/admin/badges"
@label={{i18n "admin.badges.title"}}
/>
</:breadcrumbs>
<:actions as |actions|>
<actions.Primary
@route="adminBadges.show"
@routeModels="new"
@icon="plus"
@label="admin.badges.new"
/>
<LinkTo @route="adminBadges.show" @model="new" class="btn btn-primary">
{{d-icon "plus"}}
<span>{{i18n "admin.badges.new"}}</span>
</LinkTo>
</div>
</div>
<actions.Default
@route="adminBadges.award"
@routeModels="new"
@icon="upload"
@label="admin.badges.mass_award.title"
/>
<actions.Default
@action={{routeAction "editGroupings"}}
@title="admin.badges.group_settings"
@label="admin.badges.group_settings"
@icon="cog"
class="edit-groupings-btn"
/>
</:actions>
</AdminPageHeader>
<div class="content-list">
<ul class="admin-badge-list">
{{#each this.model as |badge|}}

View File

@ -1,5 +1,5 @@
<section class="award-badge">
<h1>{{i18n "admin.badges.mass_award.title"}}</h1>
<h2>{{i18n "admin.badges.mass_award.title"}}</h2>
<p>{{i18n "admin.badges.mass_award.description"}}</p>
{{#if this.model}}

View File

@ -1,21 +1,4 @@
<section class="current-badges">
<div class="badge-intro admin-intro">
<img src={{this.badgeIntroEmoji}} class="badge-intro-emoji" alt="" />
<div class="content-wrapper">
<h1>{{i18n "admin.badges.badge_intro.title"}}</h1>
<div class="external-resources">
{{#each this.badgeIntroLinks as |link|}}
<a
href={{link.href}}
class="external-link"
target="_blank"
rel="noopener noreferrer"
>
{{d-icon link.icon}}
<span>{{i18n link.text}}</span>
</a>
{{/each}}
</div>
</div>
</div>
<section class="current-badge content-body">
<h2>{{i18n "admin.badges.badge_intro.title"}}</h2>
<p>{{i18n "admin.badges.badge_intro.description"}}</p>
</section>

View File

@ -7,10 +7,10 @@
as |form data|
>
<h1 class="current-badge-header">
<h2 class="current-badge-header">
{{iconOrImage data}}
<span class="badge-display-name">{{data.name}}</span>
</h1>
</h2>
<form.Field
@name="enabled"

View File

@ -103,7 +103,7 @@ export default class DButton extends GlimmerComponentWithDeprecatedParentView {
}
_triggerAction(event) {
const { action: actionVal, route } = this.args;
const { action: actionVal, route, routeModels } = this.args;
if (actionVal || route) {
if (actionVal) {
@ -134,7 +134,14 @@ export default class DButton extends GlimmerComponentWithDeprecatedParentView {
);
}
} else if (route) {
this.router.transitionTo(route);
if (routeModels) {
const routeModelsArray = Array.isArray(routeModels)
? routeModels
: [routeModels];
this.router.transitionTo(route, ...routeModelsArray);
} else {
this.router.transitionTo(route);
}
}
event.preventDefault();

View File

@ -3,8 +3,12 @@
&__title-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1em;
align-items: stretch;
margin-bottom: var(--space-2);
@media (max-width: $mobile-breakpoint) {
flex-direction: column;
}
h1,
h3 {
@ -14,8 +18,20 @@
.admin-page-header__actions {
display: flex;
align-items: center;
justify-content: flex-end;
@media (max-width: $mobile-breakpoint) {
flex-direction: column;
}
button {
margin-left: 1em;
margin-left: var(--space-2);
@media (max-width: $mobile-breakpoint) {
width: 100%;
margin-bottom: var(--space-2);
margin-left: 0;
}
}
}
}

View File

@ -19,21 +19,8 @@
.content-list {
flex: 0 0 27%;
}
.current-badges {
display: flex;
justify-content: center;
flex: 1 1 72%;
}
}
.badges-header {
padding: 10px 0;
border-top: 1px solid var(--primary-low);
border-bottom: 1px solid var(--primary-low);
.badges-heading {
margin: 0;
padding: 0 10px;
}
}
.content-list {
.admin-badge-list {
height: 70vh;
@ -67,7 +54,7 @@
.current-badge-header {
display: flex;
gap: 1em;
gap: 0.5em;
align-items: center;
font-size: var(--font-up-2-rem);
@ -77,7 +64,7 @@
}
.d-icon {
font-size: 36px;
font-size: var(--font-up-2-rem);
}
.badge-display-name {

View File

@ -7017,9 +7017,10 @@ en:
name: Name
badge: Badge
display_name: Display Name
description: Description
description: Badges reward users for their activities, contributions, and achievements to recognize, validate, and encourage positive behavior and engagement within the community.
long_description: Long description
badge_type: Badge type
group_settings: Group Settings
badge_grouping: Group
badge_groupings:
modal_title: Badge Groupings
@ -7084,9 +7085,8 @@ en:
with_post_time: <span class="username">%{username}</span> for post in %{link} at <span class="time">%{time}</span>
with_time: <span class="username">%{username}</span> at <span class="time">%{time}</span>
badge_intro:
title: "Select an existing badge or create a new one to get started"
what_are_badges_title: "What are badges?"
badge_query_examples_title: "Badge query examples"
title: "Choose a badge or create a new one"
description: "Start by selecting an existing badge to customize, or create a brand new badge"
mass_award:
title: Bulk Award
description: Award the same badge to many users at once.