mirror of
https://github.com/discourse/discourse.git
synced 2025-01-31 11:44:00 +08:00
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:
parent
5a30583174
commit
bdb9ee8507
|
@ -7,7 +7,8 @@
|
||||||
{{#if this.showUserTip}}
|
{{#if this.showUserTip}}
|
||||||
<UserTip
|
<UserTip
|
||||||
@id="admin_guide"
|
@id="admin_guide"
|
||||||
@primaryLabel="user_tips.admin_guide.primary"
|
@buttonLabel="user_tips.admin_guide.button"
|
||||||
|
@buttonIcon="link"
|
||||||
@onDismiss={{this.routeToAdminGuide}}
|
@onDismiss={{this.routeToAdminGuide}}
|
||||||
/>
|
/>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
@ -20,9 +20,9 @@ export default class UserTip extends Component {
|
||||||
selector,
|
selector,
|
||||||
content,
|
content,
|
||||||
placement,
|
placement,
|
||||||
primaryLabel,
|
buttonLabel,
|
||||||
|
buttonIcon,
|
||||||
onDismiss,
|
onDismiss,
|
||||||
onDismissAll,
|
|
||||||
} = this.args;
|
} = this.args;
|
||||||
element = element.parentElement;
|
element = element.parentElement;
|
||||||
|
|
||||||
|
@ -30,14 +30,14 @@ export default class UserTip extends Component {
|
||||||
id,
|
id,
|
||||||
titleText: I18n.t(`user_tips.${id}.title`),
|
titleText: I18n.t(`user_tips.${id}.title`),
|
||||||
contentText: content || I18n.t(`user_tips.${id}.content`),
|
contentText: content || I18n.t(`user_tips.${id}.content`),
|
||||||
primaryText: primaryLabel ? I18n.t(primaryLabel) : null,
|
buttonLabel,
|
||||||
|
buttonIcon,
|
||||||
reference:
|
reference:
|
||||||
(selector && element.parentElement.querySelector(selector)) ||
|
(selector && element.parentElement.querySelector(selector)) ||
|
||||||
element,
|
element,
|
||||||
appendTo: element.parentElement,
|
appendTo: element.parentElement,
|
||||||
placement,
|
placement,
|
||||||
onDismiss,
|
onDismiss,
|
||||||
onDismissAll,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,11 @@ export function showUserTip(options) {
|
||||||
return;
|
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, {
|
instancesMap[options.id] = tippy(options.reference, {
|
||||||
hideOnClick: false,
|
hideOnClick: false,
|
||||||
trigger: "manual",
|
trigger: "manual",
|
||||||
|
@ -87,12 +92,7 @@ export function showUserTip(options) {
|
||||||
<div class='user-tip__title'>${escape(options.titleText)}</div>
|
<div class='user-tip__title'>${escape(options.titleText)}</div>
|
||||||
<div class='user-tip__content'>${escape(options.contentText)}</div>
|
<div class='user-tip__content'>${escape(options.contentText)}</div>
|
||||||
<div class='user-tip__buttons'>
|
<div class='user-tip__buttons'>
|
||||||
<button class="btn btn-primary btn-dismiss">${escape(
|
<button class="btn btn-primary">${buttonText}</button>
|
||||||
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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>`,
|
</div>`,
|
||||||
|
|
||||||
|
@ -101,18 +101,11 @@ export function showUserTip(options) {
|
||||||
tippyInstance.popper.classList.add("user-tip");
|
tippyInstance.popper.classList.add("user-tip");
|
||||||
|
|
||||||
tippyInstance.popper
|
tippyInstance.popper
|
||||||
.querySelector(".btn-dismiss")
|
.querySelector(".btn")
|
||||||
.addEventListener("click", (event) => {
|
.addEventListener("click", (event) => {
|
||||||
options.onDismiss?.();
|
options.onDismiss?.();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
tippyInstance.popper
|
|
||||||
.querySelector(".btn-dismiss-all")
|
|
||||||
.addEventListener("click", (event) => {
|
|
||||||
options.onDismissAll?.();
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,6 @@ import { cancel } from "@ember/runloop";
|
||||||
import discourseLater from "discourse-common/lib/later";
|
import discourseLater from "discourse-common/lib/later";
|
||||||
import { isTesting } from "discourse-common/config/environment";
|
import { isTesting } from "discourse-common/config/environment";
|
||||||
import {
|
import {
|
||||||
hideAllUserTips,
|
|
||||||
hideUserTip,
|
hideUserTip,
|
||||||
showNextUserTip,
|
showNextUserTip,
|
||||||
showUserTip,
|
showUserTip,
|
||||||
|
@ -1202,10 +1201,6 @@ const User = RestModel.extend({
|
||||||
options.onDismiss?.();
|
options.onDismiss?.();
|
||||||
this.hideUserTipForever(options.id);
|
this.hideUserTipForever(options.id);
|
||||||
},
|
},
|
||||||
onDismissAll: () => {
|
|
||||||
options.onDismissAll?.();
|
|
||||||
this.hideUserTipForever();
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1217,45 +1212,29 @@ const User = RestModel.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty userTipId means all user tips.
|
// Empty userTipId means all user tips.
|
||||||
if (userTipId && !userTips[userTipId]) {
|
if (!userTips[userTipId]) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.warn("Cannot hide user tip with type =", userTipId);
|
console.warn("Cannot hide user tip with type =", userTipId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide user tips and maybe show the next one.
|
// Hide user tips and maybe show the next one.
|
||||||
if (userTipId) {
|
hideUserTip(userTipId, true);
|
||||||
hideUserTip(userTipId, true);
|
showNextUserTip();
|
||||||
showNextUserTip();
|
|
||||||
} else {
|
|
||||||
hideAllUserTips();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update list of seen user tips.
|
// Update list of seen user tips.
|
||||||
let seenUserTips = this.user_option?.seen_popups || [];
|
let seenUserTips = this.user_option?.seen_popups || [];
|
||||||
if (userTipId) {
|
if (seenUserTips.includes(userTips[userTipId])) {
|
||||||
if (seenUserTips.includes(userTips[userTipId])) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
seenUserTips.push(userTips[userTipId]);
|
|
||||||
} else {
|
|
||||||
if (seenUserTips.includes(-1)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
seenUserTips = [-1];
|
|
||||||
}
|
}
|
||||||
|
seenUserTips.push(userTips[userTipId]);
|
||||||
|
|
||||||
// Save seen user tips on the server.
|
// Save seen user tips on the server.
|
||||||
if (!this.user_option) {
|
if (!this.user_option) {
|
||||||
this.set("user_option", {});
|
this.set("user_option", {});
|
||||||
}
|
}
|
||||||
this.set("user_option.seen_popups", seenUserTips);
|
this.set("user_option.seen_popups", seenUserTips);
|
||||||
if (userTipId) {
|
return this.save(["seen_popups"]);
|
||||||
return this.save(["seen_popups"]);
|
|
||||||
} else {
|
|
||||||
this.set("user_option.skip_new_user_tips", true);
|
|
||||||
return this.save(["seen_popups", "skip_new_user_tips"]);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -235,16 +235,4 @@ module("Unit | Model | user", function (hooks) {
|
||||||
assert.ok(hideSpy.calledWith("first_notification"));
|
assert.ok(hideSpy.calledWith("first_notification"));
|
||||||
assert.ok(showNextSpy.calledWith());
|
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());
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
&:hover {
|
&:hover {
|
||||||
color: var(--tertiary-hover);
|
color: var(--tertiary-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.d-icon {
|
||||||
|
color: var(--tertiary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .tippy-svg-arrow {
|
> .tippy-svg-arrow {
|
||||||
|
|
|
@ -1909,8 +1909,7 @@ en:
|
||||||
remove_status: "Remove status"
|
remove_status: "Remove status"
|
||||||
|
|
||||||
user_tips:
|
user_tips:
|
||||||
primary: "Got it!"
|
button: "Got it!"
|
||||||
secondary: "don't show me these tips"
|
|
||||||
|
|
||||||
first_notification:
|
first_notification:
|
||||||
title: "Your first notification!"
|
title: "Your first notification!"
|
||||||
|
@ -1935,7 +1934,7 @@ en:
|
||||||
admin_guide:
|
admin_guide:
|
||||||
title: "Welcome to your new site!"
|
title: "Welcome to your new site!"
|
||||||
content: "Read the admin guide to continue building your site and community."
|
content: "Read the admin guide to continue building your site and community."
|
||||||
primary: "Let's go!"
|
button: "Let's go!"
|
||||||
|
|
||||||
loading: "Loading..."
|
loading: "Loading..."
|
||||||
errors:
|
errors:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user