UX: horitzontal scroll controls for new user nav (#18583)

This commit is contained in:
Kris 2022-10-14 09:32:02 -04:00 committed by GitHub
parent a5156d18ff
commit 6b4b279141
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 266 additions and 90 deletions

View File

@ -0,0 +1,106 @@
{{!-- template-lint-disable no-down-event-binding --}}
<div class="user-navigation user-navigation-secondary {{if this.hasScroll "has-scroll"}}">
{{#if this.hasScroll}}
<a
role="button"
{{on "mousedown" this.horizScroll}}
data-direction="left"
class="nav-overflow__scroll-left btn-flat {{if this.hideLeftScroll "transparent"}}"
>
{{d-icon "chevron-left"}}
</a>
{{/if}}
<ul
{{did-insert this.scrollToActive}}
{{on-resize this.checkScroll}}
{{on "scroll" this.watchScroll}}
class="nav-pills action-list"
>
<li class="nav-account">
<LinkTo @route="preferences.account">
{{d-icon "user"}}
<span>{{i18n "user.preferences_nav.account"}}</span>
</LinkTo>
</li>
<li class="nav-security">
<LinkTo @route="preferences.security">
{{d-icon "lock"}}
<span>{{i18n "user.preferences_nav.security"}}</span>
</LinkTo>
</li>
<li class="nav-profile">
<LinkTo @route="preferences.profile">
{{d-icon "user"}}
<span>{{i18n "user.preferences_nav.profile"}}</span>
</LinkTo>
</li>
<li class="nav-emails">
<LinkTo @route="preferences.emails">
{{d-icon "envelope"}}
<span>{{i18n "user.preferences_nav.emails"}}</span>
</LinkTo>
</li>
<li class="nav-notifications">
<LinkTo @route="preferences.notifications">
{{d-icon "bell"}}
<span>{{i18n "user.preferences_nav.notifications"}}</span>
</LinkTo>
</li>
{{#if @model.can_change_tracking_preferences}}
<li class="indent nav-categories">
<LinkTo @route="preferences.categories">
{{d-icon "folder"}}
<span>{{i18n "user.preferences_nav.categories"}}</span>
</LinkTo>
</li>
{{/if}}
<li class="indent nav-users">
<LinkTo @route="preferences.users">
{{d-icon "users"}}
<span>{{i18n "user.preferences_nav.users"}}</span>
</LinkTo>
</li>
{{#if (and @model.can_change_tracking_preferences @siteSettings.tagging_enabled)}}
<li class="indent nav-tags">
<LinkTo @route="preferences.tags">
{{d-icon "tag"}}
<span>{{i18n "user.preferences_nav.tags"}}</span>
</LinkTo>
</li>
{{/if}}
<li class="nav-interface">
<LinkTo @route="preferences.interface">
{{d-icon "desktop"}}
<span>{{i18n "user.preferences_nav.interface"}}</span>
</LinkTo>
</li>
{{#if @siteSettings.enable_experimental_sidebar_hamburger}}
<li class="indent nav-sidebar">
<LinkTo @route="preferences.sidebar">
{{d-icon "bars"}}
<span>{{i18n "user.preferences_nav.sidebar"}}</span>
</LinkTo>
</li>
{{/if}}
<PluginOutlet @name="user-preferences-nav-under-interface" @connectorTagName="div" @args={{hash model=@model}} />
<li class="nav-apps">
<LinkTo @route="preferences.apps">
{{d-icon "mobile-alt"}}
<span>{{i18n "user.preferences_nav.apps"}}</span>
</LinkTo>
</li>
<PluginOutlet @name="user-preferences-nav" @connectorTagName="li" @args={{hash model=@model}} />
</ul>
{{#if this.hasScroll}}
<a
role="button"
{{on "mousedown" this.horizScroll}}
class="nav-overflow__scroll-right btn-flat {{if this.hideRightScroll "transparent"}}"
>
{{d-icon "chevron-right"}}
</a>
{{/if}}
</div>

View File

@ -0,0 +1,80 @@
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { bind } from "discourse-common/utils/decorators";
import { inject as service } from "@ember/service";
import { tracked } from "@glimmer/tracking";
export default class UserNavPreferencesNav extends Component {
@service site;
@tracked hasScroll;
@tracked hideRightScroll = false;
@tracked hideLeftScroll = true;
scrollInterval;
@bind
scrollToActive() {
document
.querySelector(".user-navigation-secondary a.active")
.scrollIntoView({ inline: "center" });
}
@bind
checkScroll(element) {
if (this.site.mobileView) {
return;
}
this.watchScroll(element);
return (this.hasScroll =
element.target.scrollWidth > element.target.offsetWidth);
}
@bind
stopScroll() {
clearInterval(this.scrollInterval);
}
@bind
watchScroll(element) {
if (this.site.mobileView) {
return;
}
if (
element.target.offsetWidth + element.target.scrollLeft ===
element.target.scrollWidth
) {
this.hideRightScroll = true;
clearInterval(this.scrollInterval);
} else {
this.hideRightScroll = false;
}
if (element.target.scrollLeft === 0) {
this.hideLeftScroll = true;
clearInterval(this.scrollInterval);
} else {
this.hideLeftScroll = false;
}
}
@action
horizScroll(element) {
let scrollSpeed = 50;
let siblingTarget = element.target.previousElementSibling;
if (element.target.dataset.direction === "left") {
scrollSpeed = scrollSpeed * -1;
siblingTarget = element.target.nextElementSibling;
}
this.scrollInterval = setInterval(function () {
siblingTarget.scrollLeft += scrollSpeed;
}, 50);
this.scrollTimer;
element.target.addEventListener("mouseup", this.stopScroll);
element.target.addEventListener("mouseleave", this.stopScroll);
}
}

View File

@ -1,88 +1,12 @@
{{#if this.currentUser.redesigned_user_page_nav_enabled}}
<DSection @pageClass="user-preferences" />
<div class="user-navigation user-navigation-secondary">
<ul class="nav-pills action-list">
<li class="nav-account">
<LinkTo @route="preferences.account">
{{d-icon "user"}}
<span>{{i18n "user.preferences_nav.account"}}</span>
</LinkTo>
</li>
<li class="nav-security">
<LinkTo @route="preferences.security">
{{d-icon "lock"}}
<span>{{i18n "user.preferences_nav.security"}}</span>
</LinkTo>
</li>
<li class="nav-profile">
<LinkTo @route="preferences.profile">
{{d-icon "user"}}
<span>{{i18n "user.preferences_nav.profile"}}</span>
</LinkTo>
</li>
<li class="nav-emails">
<LinkTo @route="preferences.emails">
{{d-icon "envelope"}}
<span>{{i18n "user.preferences_nav.emails"}}</span>
</LinkTo>
</li>
<li class="nav-notifications">
<LinkTo @route="preferences.notifications">
{{d-icon "bell"}}
<span>{{i18n "user.preferences_nav.notifications"}}</span>
</LinkTo>
</li>
{{#if this.model.can_change_tracking_preferences}}
<li class="indent nav-categories">
<LinkTo @route="preferences.categories">
{{d-icon "folder"}}
<span>{{i18n "user.preferences_nav.categories"}}</span>
</LinkTo>
</li>
{{/if}}
<li class="indent nav-users">
<LinkTo @route="preferences.users">
{{d-icon "users"}}
<span>{{i18n "user.preferences_nav.users"}}</span>
</LinkTo>
</li>
{{#if (and this.model.can_change_tracking_preferences this.siteSettings.tagging_enabled)}}
<li class="indent nav-tags">
<LinkTo @route="preferences.tags">
{{d-icon "tag"}}
<span>{{i18n "user.preferences_nav.tags"}}</span>
</LinkTo>
</li>
{{/if}}
<li class="nav-interface">
<LinkTo @route="preferences.interface">
{{d-icon "desktop"}}
<span>{{i18n "user.preferences_nav.interface"}}</span>
</LinkTo>
</li>
{{#if this.siteSettings.enable_experimental_sidebar_hamburger}}
<li class="indent nav-sidebar">
<LinkTo @route="preferences.sidebar">
{{d-icon "bars"}}
<span>{{i18n "user.preferences_nav.sidebar"}}</span>
</LinkTo>
</li>
{{/if}}
<PluginOutlet @name="user-preferences-nav-under-interface" @connectorTagName="div" @args={{hash model=this.model}} />
<li class="nav-apps">
<LinkTo @route="preferences.apps">
{{d-icon "mobile-alt"}}
<span>{{i18n "user.preferences_nav.apps"}}</span>
</LinkTo>
</li>
<PluginOutlet @name="user-preferences-nav" @connectorTagName="li" @args={{hash model=this.model}} />
</ul>
</div>
<UserNav::PreferencesNav
@user={{this.model}}
@viewingSelf={{this.viewingSelf}}
@model={{this.model}}
@siteSettings={{this.siteSettings}}
/>
{{else}}
<DSection @pageClass="user-preferences" @class="user-secondary-navigation">
<MobileNav @class="preferences-nav" @desktopClass="preferences-list action-list nav-stacked">

View File

@ -2,10 +2,12 @@
margin-top: -15px; // temp, can remove margin from sibling element after nav finalized
.user-navigation {
--user-navigation__border-width: 4px;
&.user-navigation-primary {
border-bottom: 1px solid var(--primary-low);
}
.nav-pills {
width: 100%;
margin: 0;
border-bottom: 1px solid var(--primary-low);
.d-icon {
font-size: var(--font-down-1);
}
@ -80,9 +82,12 @@
.user-navigation-secondary {
--user-navigation__border-width: 2px;
position: relative;
display: flex;
min-width: 0;
margin: 0.5em 0;
gap: 0 0.5em;
border-bottom: 1px solid var(--primary-low);
.select-kit .select-kit-header {
height: 100%;
@ -103,18 +108,84 @@
}
}
.nav-overflow__scroll-right,
.nav-overflow__scroll-left {
--fade-width: 20px;
opacity: 1;
position: absolute;
z-index: 2;
background-color: var(--secondary);
top: 0;
bottom: 0;
display: flex;
align-items: center;
transition: opacity 0.25s;
.d-icon {
pointer-events: none;
margin-bottom: 0.2em;
color: var(--tertiary);
}
&.transparent {
// hiding with opacity so we can transition visibility
opacity: 0;
pointer-events: none;
}
}
.nav-overflow__scroll-right {
right: 0;
&:before {
content: "";
margin-left: -1.5em;
height: 100%;
width: 1.5em;
background: linear-gradient(
to left,
rgba(var(--secondary-rgb), 1),
rgba(var(--secondary-rgb), 0)
);
}
}
.nav-overflow__scroll-left {
left: 0;
&:after {
content: "";
margin-right: -1.5em;
height: 100%;
width: 1.5em;
background: linear-gradient(
to right,
rgba(var(--secondary-rgb), 1),
rgba(var(--secondary-rgb), 0)
);
}
}
.nav-pills {
flex: 1 1 auto;
font-size: var(--font-down-1);
flex-wrap: wrap;
justify-content: flex-start;
overflow: auto;
position: relative;
scroll-behavior: smooth;
// hides scrollbars, but allows mouse scrolling
scrollbar-width: none;
&::-webkit-scrollbar {
height: 0;
}
li {
flex: 1 1 auto;
flex: 1 0 auto;
a {
padding: 0.5em 0.5em
calc(0.5em + var(--user-navigation__border-width));
span {
text-overflow: unset;
}
}
}
}

View File

@ -3,7 +3,6 @@
width: 100%;
.nav-pills {
margin: 0.5em 0;
overflow-x: auto;
scrollbar-width: none;
@ -56,10 +55,6 @@
#navigation-bar {
flex-wrap: nowrap;
}
.navigation-controls {
margin-top: 1em;
}
}
.new-user-content-wrapper {