UX: Improve user tips (#22518)

- Add an icon to the bootstrap user tip to draw attention
- Remove the second "don't show user tip" button from every user tip
This commit is contained in:
Bianca Nenciu 2023-07-11 18:22:40 +03:00 committed by GitHub
parent 5a30583174
commit bdb9ee8507
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 26 additions and 62 deletions

View File

@ -7,7 +7,8 @@
{{#if this.showUserTip}}
<UserTip
@id="admin_guide"
@primaryLabel="user_tips.admin_guide.primary"
@buttonLabel="user_tips.admin_guide.button"
@buttonIcon="link"
@onDismiss={{this.routeToAdminGuide}}
/>
{{else}}

View File

@ -20,9 +20,9 @@ export default class UserTip extends Component {
selector,
content,
placement,
primaryLabel,
buttonLabel,
buttonIcon,
onDismiss,
onDismissAll,
} = this.args;
element = element.parentElement;
@ -30,14 +30,14 @@ export default class UserTip extends Component {
id,
titleText: I18n.t(`user_tips.${id}.title`),
contentText: content || I18n.t(`user_tips.${id}.content`),
primaryText: primaryLabel ? I18n.t(primaryLabel) : null,
buttonLabel,
buttonIcon,
reference:
(selector && element.parentElement.querySelector(selector)) ||
element,
appendTo: element.parentElement,
placement,
onDismiss,
onDismissAll,
});
});
}

View File

@ -67,6 +67,11 @@ export function showUserTip(options) {
return;
}
let buttonText = escape(I18n.t(options.buttonLabel || "user_tips.button"));
if (options.buttonIcon) {
buttonText = `${iconHTML(options.buttonIcon)} ${buttonText}`;
}
instancesMap[options.id] = tippy(options.reference, {
hideOnClick: false,
trigger: "manual",
@ -87,12 +92,7 @@ export function showUserTip(options) {
<div class='user-tip__title'>${escape(options.titleText)}</div>
<div class='user-tip__content'>${escape(options.contentText)}</div>
<div class='user-tip__buttons'>
<button class="btn btn-primary btn-dismiss">${escape(
options.primaryText || I18n.t("user_tips.primary")
)}</button>
<button class="btn btn-flat btn-text btn-dismiss-all">${escape(
options.secondaryBtnText || I18n.t("user_tips.secondary")
)}</button>
<button class="btn btn-primary">${buttonText}</button>
</div>
</div>`,
@ -101,18 +101,11 @@ export function showUserTip(options) {
tippyInstance.popper.classList.add("user-tip");
tippyInstance.popper
.querySelector(".btn-dismiss")
.querySelector(".btn")
.addEventListener("click", (event) => {
options.onDismiss?.();
event.preventDefault();
});
tippyInstance.popper
.querySelector(".btn-dismiss-all")
.addEventListener("click", (event) => {
options.onDismissAll?.();
event.preventDefault();
});
},
});

View File

@ -37,7 +37,6 @@ import { cancel } from "@ember/runloop";
import discourseLater from "discourse-common/lib/later";
import { isTesting } from "discourse-common/config/environment";
import {
hideAllUserTips,
hideUserTip,
showNextUserTip,
showUserTip,
@ -1202,10 +1201,6 @@ const User = RestModel.extend({
options.onDismiss?.();
this.hideUserTipForever(options.id);
},
onDismissAll: () => {
options.onDismissAll?.();
this.hideUserTipForever();
},
});
}
},
@ -1217,45 +1212,29 @@ const User = RestModel.extend({
}
// Empty userTipId means all user tips.
if (userTipId && !userTips[userTipId]) {
if (!userTips[userTipId]) {
// eslint-disable-next-line no-console
console.warn("Cannot hide user tip with type =", userTipId);
return;
}
// Hide user tips and maybe show the next one.
if (userTipId) {
hideUserTip(userTipId, true);
showNextUserTip();
} else {
hideAllUserTips();
}
hideUserTip(userTipId, true);
showNextUserTip();
// Update list of seen user tips.
let seenUserTips = this.user_option?.seen_popups || [];
if (userTipId) {
if (seenUserTips.includes(userTips[userTipId])) {
return;
}
seenUserTips.push(userTips[userTipId]);
} else {
if (seenUserTips.includes(-1)) {
return;
}
seenUserTips = [-1];
if (seenUserTips.includes(userTips[userTipId])) {
return;
}
seenUserTips.push(userTips[userTipId]);
// Save seen user tips on the server.
if (!this.user_option) {
this.set("user_option", {});
}
this.set("user_option.seen_popups", seenUserTips);
if (userTipId) {
return this.save(["seen_popups"]);
} else {
this.set("user_option.skip_new_user_tips", true);
return this.save(["seen_popups", "skip_new_user_tips"]);
}
return this.save(["seen_popups"]);
},
});

View File

@ -235,16 +235,4 @@ module("Unit | Model | user", function (hooks) {
assert.ok(hideSpy.calledWith("first_notification"));
assert.ok(showNextSpy.calledWith());
});
test("hideUserTipForever() can hide all the user tips", async function (assert) {
const site = getOwner(this).lookup("service:site");
site.set("user_tips", { first_notification: 1 });
const store = getOwner(this).lookup("service:store");
const user = store.createRecord("user", { username: "eviltrout" });
const hideAllSpy = sinon.spy(userTips, "hideAllUserTips");
await user.hideUserTipForever();
assert.ok(hideAllSpy.calledWith());
});
});

View File

@ -18,6 +18,10 @@
&:hover {
color: var(--tertiary-hover);
}
.d-icon {
color: var(--tertiary);
}
}
> .tippy-svg-arrow {

View File

@ -1909,8 +1909,7 @@ en:
remove_status: "Remove status"
user_tips:
primary: "Got it!"
secondary: "don't show me these tips"
button: "Got it!"
first_notification:
title: "Your first notification!"
@ -1935,7 +1934,7 @@ en:
admin_guide:
title: "Welcome to your new site!"
content: "Read the admin guide to continue building your site and community."
primary: "Let's go!"
button: "Let's go!"
loading: "Loading..."
errors: