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:
parent
06d749eadd
commit
be5c37a6d4
|
@ -6,6 +6,7 @@ export const AdminPageActionButton = <template>
|
||||||
...attributes
|
...attributes
|
||||||
@action={{@action}}
|
@action={{@action}}
|
||||||
@route={{@route}}
|
@route={{@route}}
|
||||||
|
@routeModels={{@routeModels}}
|
||||||
@label={{@label}}
|
@label={{@label}}
|
||||||
@title={{@title}}
|
@title={{@title}}
|
||||||
@icon={{@icon}}
|
@icon={{@icon}}
|
||||||
|
@ -18,6 +19,7 @@ export const PrimaryButton = <template>
|
||||||
...attributes
|
...attributes
|
||||||
@action={{@action}}
|
@action={{@action}}
|
||||||
@route={{@route}}
|
@route={{@route}}
|
||||||
|
@routeModels={{@routeModels}}
|
||||||
@label={{@label}}
|
@label={{@label}}
|
||||||
@title={{@title}}
|
@title={{@title}}
|
||||||
@icon={{@icon}}
|
@icon={{@icon}}
|
||||||
|
@ -30,6 +32,7 @@ export const DangerButton = <template>
|
||||||
...attributes
|
...attributes
|
||||||
@action={{@action}}
|
@action={{@action}}
|
||||||
@route={{@route}}
|
@route={{@route}}
|
||||||
|
@routeModels={{@routeModels}}
|
||||||
@label={{@label}}
|
@label={{@label}}
|
||||||
@title={{@title}}
|
@title={{@title}}
|
||||||
@icon={{@icon}}
|
@icon={{@icon}}
|
||||||
|
@ -42,6 +45,7 @@ export const DefaultButton = <template>
|
||||||
...attributes
|
...attributes
|
||||||
@action={{@action}}
|
@action={{@action}}
|
||||||
@route={{@route}}
|
@route={{@route}}
|
||||||
|
@routeModels={{@routeModels}}
|
||||||
@label={{@label}}
|
@label={{@label}}
|
||||||
@title={{@title}}
|
@title={{@title}}
|
||||||
@icon={{@icon}}
|
@icon={{@icon}}
|
||||||
|
|
|
@ -1,22 +1,8 @@
|
||||||
import Route from "@ember/routing/route";
|
import Route from "@ember/routing/route";
|
||||||
import { emojiUrlFor } from "discourse/lib/text";
|
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 {
|
export default class AdminBadgesIndexRoute extends Route {
|
||||||
setupController(controller) {
|
setupController(controller) {
|
||||||
controller.badgeIntroLinks = badgeIntroLinks;
|
|
||||||
controller.badgeIntroEmoji = emojiUrlFor("woman_student:t4");
|
controller.badgeIntroEmoji = emojiUrlFor("woman_student:t4");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,39 @@
|
||||||
<div class="badges">
|
<div class="badges">
|
||||||
<div class="badges-header">
|
<AdminPageHeader
|
||||||
<h3 class="badges-heading">{{i18n "admin.badges.title"}}</h3>
|
@titleLabel="admin.badges.title"
|
||||||
<div class="create-new-badge">
|
@descriptionLabel="admin.badges.description"
|
||||||
|
@learnMoreUrl="https://meta.discourse.org/t/understanding-and-using-badges/32540"
|
||||||
<LinkTo @route="adminBadges.award" @model="new" class="btn btn-default">
|
>
|
||||||
{{d-icon "upload"}}
|
<:breadcrumbs>
|
||||||
<span class="d-button-label">{{i18n
|
<DBreadcrumbsItem
|
||||||
"admin.badges.mass_award.title"
|
@path="/admin/badges"
|
||||||
}}</span>
|
@label={{i18n "admin.badges.title"}}
|
||||||
</LinkTo>
|
/>
|
||||||
|
</:breadcrumbs>
|
||||||
<DButton
|
<:actions as |actions|>
|
||||||
@action={{route-action "editGroupings"}}
|
<actions.Primary
|
||||||
@translatedLabel="Group settings"
|
@route="adminBadges.show"
|
||||||
@icon="cog"
|
@routeModels="new"
|
||||||
@class="btn-default edit-groupings-btn"
|
@icon="plus"
|
||||||
|
@label="admin.badges.new"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<LinkTo @route="adminBadges.show" @model="new" class="btn btn-primary">
|
<actions.Default
|
||||||
{{d-icon "plus"}}
|
@route="adminBadges.award"
|
||||||
<span>{{i18n "admin.badges.new"}}</span>
|
@routeModels="new"
|
||||||
</LinkTo>
|
@icon="upload"
|
||||||
</div>
|
@label="admin.badges.mass_award.title"
|
||||||
</div>
|
/>
|
||||||
|
|
||||||
|
<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">
|
<div class="content-list">
|
||||||
<ul class="admin-badge-list">
|
<ul class="admin-badge-list">
|
||||||
{{#each this.model as |badge|}}
|
{{#each this.model as |badge|}}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<section class="award-badge">
|
<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>
|
<p>{{i18n "admin.badges.mass_award.description"}}</p>
|
||||||
|
|
||||||
{{#if this.model}}
|
{{#if this.model}}
|
||||||
|
|
|
@ -1,21 +1,4 @@
|
||||||
<section class="current-badges">
|
<section class="current-badge content-body">
|
||||||
<div class="badge-intro admin-intro">
|
<h2>{{i18n "admin.badges.badge_intro.title"}}</h2>
|
||||||
<img src={{this.badgeIntroEmoji}} class="badge-intro-emoji" alt="" />
|
<p>{{i18n "admin.badges.badge_intro.description"}}</p>
|
||||||
<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>
|
</section>
|
|
@ -7,10 +7,10 @@
|
||||||
as |form data|
|
as |form data|
|
||||||
>
|
>
|
||||||
|
|
||||||
<h1 class="current-badge-header">
|
<h2 class="current-badge-header">
|
||||||
{{iconOrImage data}}
|
{{iconOrImage data}}
|
||||||
<span class="badge-display-name">{{data.name}}</span>
|
<span class="badge-display-name">{{data.name}}</span>
|
||||||
</h1>
|
</h2>
|
||||||
|
|
||||||
<form.Field
|
<form.Field
|
||||||
@name="enabled"
|
@name="enabled"
|
||||||
|
|
|
@ -103,7 +103,7 @@ export default class DButton extends GlimmerComponentWithDeprecatedParentView {
|
||||||
}
|
}
|
||||||
|
|
||||||
_triggerAction(event) {
|
_triggerAction(event) {
|
||||||
const { action: actionVal, route } = this.args;
|
const { action: actionVal, route, routeModels } = this.args;
|
||||||
|
|
||||||
if (actionVal || route) {
|
if (actionVal || route) {
|
||||||
if (actionVal) {
|
if (actionVal) {
|
||||||
|
@ -134,7 +134,14 @@ export default class DButton extends GlimmerComponentWithDeprecatedParentView {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (route) {
|
} 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();
|
event.preventDefault();
|
||||||
|
|
|
@ -3,8 +3,12 @@
|
||||||
&__title-row {
|
&__title-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: stretch;
|
||||||
margin-bottom: 1em;
|
margin-bottom: var(--space-2);
|
||||||
|
|
||||||
|
@media (max-width: $mobile-breakpoint) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
h3 {
|
h3 {
|
||||||
|
@ -14,8 +18,20 @@
|
||||||
.admin-page-header__actions {
|
.admin-page-header__actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
@media (max-width: $mobile-breakpoint) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
margin-left: 1em;
|
margin-left: var(--space-2);
|
||||||
|
|
||||||
|
@media (max-width: $mobile-breakpoint) {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: var(--space-2);
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,21 +19,8 @@
|
||||||
.content-list {
|
.content-list {
|
||||||
flex: 0 0 27%;
|
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 {
|
.content-list {
|
||||||
.admin-badge-list {
|
.admin-badge-list {
|
||||||
height: 70vh;
|
height: 70vh;
|
||||||
|
@ -67,7 +54,7 @@
|
||||||
|
|
||||||
.current-badge-header {
|
.current-badge-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1em;
|
gap: 0.5em;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: var(--font-up-2-rem);
|
font-size: var(--font-up-2-rem);
|
||||||
|
|
||||||
|
@ -77,7 +64,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.d-icon {
|
.d-icon {
|
||||||
font-size: 36px;
|
font-size: var(--font-up-2-rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-display-name {
|
.badge-display-name {
|
||||||
|
|
|
@ -7017,9 +7017,10 @@ en:
|
||||||
name: Name
|
name: Name
|
||||||
badge: Badge
|
badge: Badge
|
||||||
display_name: Display Name
|
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
|
long_description: Long description
|
||||||
badge_type: Badge type
|
badge_type: Badge type
|
||||||
|
group_settings: Group Settings
|
||||||
badge_grouping: Group
|
badge_grouping: Group
|
||||||
badge_groupings:
|
badge_groupings:
|
||||||
modal_title: 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_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>
|
with_time: <span class="username">%{username}</span> at <span class="time">%{time}</span>
|
||||||
badge_intro:
|
badge_intro:
|
||||||
title: "Select an existing badge or create a new one to get started"
|
title: "Choose a badge or create a new one"
|
||||||
what_are_badges_title: "What are badges?"
|
description: "Start by selecting an existing badge to customize, or create a brand new badge"
|
||||||
badge_query_examples_title: "Badge query examples"
|
|
||||||
mass_award:
|
mass_award:
|
||||||
title: Bulk Award
|
title: Bulk Award
|
||||||
description: Award the same badge to many users at once.
|
description: Award the same badge to many users at once.
|
||||||
|
|
Loading…
Reference in New Issue