2015-08-27 03:51:56 +08:00
|
|
|
.menu-panel.slide-in {
|
2015-08-26 00:50:19 +08:00
|
|
|
position: fixed;
|
|
|
|
right: 0;
|
2023-06-14 04:38:31 +08:00
|
|
|
box-shadow: var(--shadow-header);
|
2015-09-11 00:49:54 +08:00
|
|
|
|
|
|
|
.panel-body {
|
2020-03-24 01:25:33 +08:00
|
|
|
width: 100%;
|
2015-09-11 00:49:54 +08:00
|
|
|
}
|
2015-08-27 02:42:42 +08:00
|
|
|
}
|
2018-12-12 01:15:20 +08:00
|
|
|
.header-cloak {
|
|
|
|
display: none;
|
|
|
|
}
|
2015-08-27 02:42:42 +08:00
|
|
|
|
2015-08-27 03:51:56 +08:00
|
|
|
.menu-panel.drop-down {
|
2015-08-27 05:21:20 +08:00
|
|
|
position: absolute;
|
2015-09-09 06:31:44 +08:00
|
|
|
// positions are relative to the .d-header .panel div
|
|
|
|
top: 100%; // directly underneath .panel
|
|
|
|
right: -10px; // 10px to the right of .panel - adjust as needed
|
2020-08-11 04:17:15 +08:00
|
|
|
max-height: 80vh;
|
2023-08-26 05:09:18 +08:00
|
|
|
border-radius: var(--d-border-radius-large);
|
2015-08-27 02:42:42 +08:00
|
|
|
}
|
|
|
|
|
2015-08-27 03:51:56 +08:00
|
|
|
.menu-panel {
|
2020-08-04 10:57:10 +08:00
|
|
|
border: 1px solid var(--primary-low);
|
2023-06-14 04:38:31 +08:00
|
|
|
box-shadow: var(--shadow-menu-panel);
|
2020-08-04 10:57:10 +08:00
|
|
|
background-color: var(--secondary);
|
2018-01-17 08:05:12 +08:00
|
|
|
z-index: z("header");
|
2015-08-30 07:26:02 +08:00
|
|
|
padding: 0.5em;
|
2020-12-18 11:50:50 +08:00
|
|
|
width: 320px;
|
2020-08-11 04:17:15 +08:00
|
|
|
overflow: hidden;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
2023-02-21 21:55:38 +08:00
|
|
|
box-sizing: border-box;
|
|
|
|
|
2015-09-02 05:33:37 +08:00
|
|
|
hr {
|
|
|
|
margin: 3px 0;
|
|
|
|
}
|
|
|
|
|
2015-08-27 03:51:56 +08:00
|
|
|
.panel-header {
|
2015-08-26 11:44:48 +08:00
|
|
|
position: absolute;
|
|
|
|
right: 20px;
|
|
|
|
}
|
|
|
|
|
2015-08-26 00:50:19 +08:00
|
|
|
ul {
|
|
|
|
list-style: none;
|
|
|
|
margin: 0;
|
|
|
|
padding: 0;
|
|
|
|
}
|
|
|
|
|
2015-08-27 03:51:56 +08:00
|
|
|
.panel-body {
|
2020-08-11 04:17:15 +08:00
|
|
|
display: flex;
|
2018-12-12 01:15:20 +08:00
|
|
|
touch-action: pan-y pinch-zoom;
|
2020-08-11 04:17:15 +08:00
|
|
|
overflow: hidden;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
.panel-body-contents {
|
|
|
|
max-height: 100%;
|
|
|
|
width: 100%;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
}
|
|
|
|
|
|
|
|
.panel-body-bottom {
|
|
|
|
display: flex;
|
|
|
|
flex: 1 0 0%; // safari height fix
|
|
|
|
margin-top: 0.5em;
|
2020-12-18 23:03:51 +08:00
|
|
|
flex-wrap: wrap;
|
|
|
|
|
2020-08-11 04:17:15 +08:00
|
|
|
.show-all {
|
2021-06-03 12:14:24 +08:00
|
|
|
display: flex;
|
2020-08-11 04:17:15 +08:00
|
|
|
flex: 1 1 auto;
|
|
|
|
button {
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.notifications-dismiss {
|
|
|
|
margin-left: 0.5em;
|
|
|
|
}
|
|
|
|
|
2020-08-13 05:14:48 +08:00
|
|
|
.btn {
|
2020-08-11 04:17:15 +08:00
|
|
|
background-color: var(--primary-very-low);
|
|
|
|
color: var(--primary-high);
|
|
|
|
&:hover {
|
|
|
|
background: var(--primary-low);
|
|
|
|
color: var(--primary);
|
|
|
|
}
|
|
|
|
}
|
2015-08-27 03:51:56 +08:00
|
|
|
}
|
2019-01-18 00:42:03 +08:00
|
|
|
|
|
|
|
.badge-notification {
|
|
|
|
vertical-align: text-bottom;
|
|
|
|
}
|
2015-08-27 03:51:56 +08:00
|
|
|
}
|
|
|
|
|
2023-02-21 23:40:22 +08:00
|
|
|
.search-menu .menu-panel {
|
|
|
|
width: 500px;
|
|
|
|
}
|
|
|
|
|
2022-07-19 10:35:02 +08:00
|
|
|
.user-menu.revamped {
|
|
|
|
right: 0;
|
|
|
|
width: 320px;
|
|
|
|
padding: 0;
|
2023-08-26 05:09:18 +08:00
|
|
|
border-top-right-radius: 0px;
|
2022-07-19 10:35:02 +08:00
|
|
|
|
|
|
|
.panel-body-bottom {
|
|
|
|
flex: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.menu-tabs-container {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
border-left: 1px solid var(--primary-low);
|
2022-08-19 18:02:11 +08:00
|
|
|
padding: 0.75em 0 0;
|
2022-09-21 04:48:00 +08:00
|
|
|
overflow-y: auto;
|
2023-03-22 01:49:19 +08:00
|
|
|
overscroll-behavior: contain;
|
2022-07-19 10:35:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
.tabs-list {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
|
|
.btn {
|
|
|
|
display: flex;
|
|
|
|
padding: 0.857em;
|
|
|
|
position: relative;
|
2023-08-26 05:09:18 +08:00
|
|
|
border-radius: 0px;
|
2022-07-19 10:35:02 +08:00
|
|
|
|
|
|
|
.d-icon {
|
|
|
|
color: var(--primary-medium);
|
|
|
|
}
|
|
|
|
|
|
|
|
.badge-notification {
|
|
|
|
background-color: var(--tertiary-med-or-tertiary);
|
|
|
|
position: absolute;
|
|
|
|
right: 6px;
|
|
|
|
top: 6px;
|
|
|
|
font-size: var(--font-down-3);
|
|
|
|
}
|
|
|
|
|
|
|
|
&.active {
|
2023-02-21 17:15:49 +08:00
|
|
|
background-color: var(--d-selected);
|
2022-07-19 10:35:02 +08:00
|
|
|
}
|
|
|
|
&:hover {
|
2023-02-21 17:15:49 +08:00
|
|
|
background-color: var(--d-hover);
|
2022-07-19 10:35:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-19 18:02:11 +08:00
|
|
|
.bottom-tabs {
|
|
|
|
border-top: 1px solid var(--primary-low);
|
|
|
|
}
|
|
|
|
|
2022-07-19 10:35:02 +08:00
|
|
|
.panel-body-contents {
|
|
|
|
display: flex;
|
2022-09-21 00:31:56 +08:00
|
|
|
flex-direction: row-reverse;
|
2022-07-19 10:35:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
.quick-access-panel {
|
|
|
|
width: 320px;
|
|
|
|
padding: 0.75em;
|
2023-03-21 09:46:13 +08:00
|
|
|
padding-bottom: max(env(safe-area-inset-bottom), 0.75em);
|
2022-07-19 10:35:02 +08:00
|
|
|
justify-content: space-between;
|
|
|
|
box-sizing: border-box;
|
2022-08-29 10:29:21 +08:00
|
|
|
min-width: 0; // makes sure menu tabs don't go off screen
|
2022-08-05 12:55:00 +08:00
|
|
|
}
|
2022-08-19 18:02:11 +08:00
|
|
|
|
|
|
|
#quick-access-profile {
|
|
|
|
display: inline;
|
2022-08-26 03:18:26 +08:00
|
|
|
max-height: 99%; // macOS Chrome sometimes adds an unneeded scrollbar at 100%
|
|
|
|
|
|
|
|
ul {
|
|
|
|
flex-wrap: nowrap;
|
|
|
|
height: 100%;
|
|
|
|
align-items: center;
|
|
|
|
overflow-y: auto; // really short viewports
|
|
|
|
}
|
|
|
|
li {
|
|
|
|
flex: 1 1 auto;
|
|
|
|
max-height: 3em; // prevent buttons from getting too tall
|
|
|
|
> * {
|
|
|
|
// button, a, and everything else
|
|
|
|
height: 100%;
|
|
|
|
align-items: center;
|
|
|
|
margin: 0;
|
|
|
|
padding: 0 0.5em;
|
|
|
|
}
|
2023-04-08 01:55:11 +08:00
|
|
|
img.emoji {
|
|
|
|
height: 1em;
|
|
|
|
width: 1em;
|
|
|
|
padding-top: 0.2em;
|
|
|
|
margin-right: 0.5em;
|
|
|
|
}
|
2022-08-26 03:18:26 +08:00
|
|
|
.d-icon {
|
|
|
|
padding-top: 0;
|
|
|
|
}
|
|
|
|
}
|
2022-08-19 18:02:11 +08:00
|
|
|
|
2022-08-25 22:14:42 +08:00
|
|
|
.set-user-status {
|
|
|
|
.emoji {
|
|
|
|
padding-top: 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-19 18:02:11 +08:00
|
|
|
.profile-tab-btn {
|
2022-08-25 22:14:42 +08:00
|
|
|
.relative-date {
|
2022-10-12 21:31:59 +08:00
|
|
|
font-size: var(--font-down-3);
|
2022-08-25 22:14:42 +08:00
|
|
|
color: var(--primary-medium);
|
|
|
|
}
|
|
|
|
|
2022-08-19 18:02:11 +08:00
|
|
|
justify-content: unset;
|
2022-10-12 22:05:42 +08:00
|
|
|
line-height: var(--line-height-large);
|
2022-08-19 18:02:11 +08:00
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
.d-icon {
|
|
|
|
padding: 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.do-not-disturb {
|
|
|
|
.d-icon-toggle-on {
|
|
|
|
color: var(--tertiary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-05 12:55:00 +08:00
|
|
|
}
|
|
|
|
|
2020-09-29 09:59:45 +08:00
|
|
|
.hamburger-panel {
|
DEV: Upgrade search-menu to glimmer (#20482)
# Top level view
This PR is the first version of converting the search menu and its logic from (deprecated) widgets to glimmer components. The changes are hidden behind a group based feature flag. This will give us the ability to test the new implementation in a production setting before fully committing to the new search menu.
# What has changed
The majority of the logic from the widget implementation has been updated to fit within the context of a glimmer component, but it has not fundamentally changed. Instead of having a single widget - [search-menu.js](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/widgets/search-menu.js) - that built the bulk of the search menu logic, we split the logic into (20+) bite size components. This greatly increases the readability and makes extending a component in the search menu much more straightforward.
That being said, certain pieces needed to be rewritten from scratch as they did not translate from widget -> glimmer, or there was a general code upgraded needed. There are a few of these changes worth noting:
### Search Service
**Search Term** -> In the widget implementation we had a overly complex way of managing the current search term. We tracked the search term across multiple different states (`term`, `opts.term`, `searchData.term`) causing headaches. This PR introduces a single source of truth:
```js
this.search.activeGlobalSearchTerm
```
This tracked value is available anywhere the `search` service is injected. In the case the search term should be needs to be updated you can call
```js
this.search.activeGlobalSearchTerm = "foo"
```
**event listeners** -> In the widget implementation we defined event listeners **only** on the search input to handle things such as
- keyboard navigation / shortcuts
- closing the search menu
- performing a search with "enter"
Having this in one place caused a lot of bloat in our logic as we had to handle multiple different cases in one location. Do _x_ if it is this element, but do _y_ if it is another. This PR updates the event listeners to be attached to individual components, allowing for a more fine tuned set of actions per element. To not duplicate logic across multiple components, we have condensed shared logic to actions on the search service to be reused. For example - `this.search.handleArrowUpOrDown` - to handle keyboard navigation.
### Search Context
We have unique logic based on the current search context (topic / tag / category / user / etc). This context is set within a models route file. We have updated the search service with a tracked value `searchContext` that can be utilized and updated from any component where the search service is injected.
```js
# before
this.searchService.set("searchContext", user.searchContext);
# after
this.searchService.searchContext = user.searchContext;
```
# Views
<img width="434" alt="Screenshot 2023-06-15 at 11 01 01 AM" src="https://github.com/discourse/discourse/assets/50783505/ef57e8e6-4e7b-4ba0-a770-8f2ed6310569">
<img width="418" alt="Screenshot 2023-06-15 at 11 04 11 AM" src="https://github.com/discourse/discourse/assets/50783505/2c1e0b38-d12c-4339-a1d5-04f0c1932b08">
<img width="413" alt="Screenshot 2023-06-15 at 11 04 34 AM" src="https://github.com/discourse/discourse/assets/50783505/b871d164-88cb-405e-9b78-d326a6f63686">
<img width="419" alt="Screenshot 2023-06-15 at 11 07 51 AM" src="https://github.com/discourse/discourse/assets/50783505/c7309a19-f541-47f4-94ef-10fa65658d8c">
<img width="424" alt="Screenshot 2023-06-15 at 11 04 48 AM" src="https://github.com/discourse/discourse/assets/50783505/f3dba06e-b029-431c-b3d0-36727b9e6dce">
<img width="415" alt="Screenshot 2023-06-15 at 11 08 57 AM" src="https://github.com/discourse/discourse/assets/50783505/ad4e7250-040c-4d06-bf06-99652f4c7b7c">
2023-06-16 22:24:07 +08:00
|
|
|
// remove once glimmer search menu in place
|
2021-01-15 07:25:19 +08:00
|
|
|
a.widget-link {
|
|
|
|
width: 100%;
|
|
|
|
box-sizing: border-box;
|
|
|
|
@include ellipsis;
|
|
|
|
}
|
DEV: Upgrade search-menu to glimmer (#20482)
# Top level view
This PR is the first version of converting the search menu and its logic from (deprecated) widgets to glimmer components. The changes are hidden behind a group based feature flag. This will give us the ability to test the new implementation in a production setting before fully committing to the new search menu.
# What has changed
The majority of the logic from the widget implementation has been updated to fit within the context of a glimmer component, but it has not fundamentally changed. Instead of having a single widget - [search-menu.js](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/widgets/search-menu.js) - that built the bulk of the search menu logic, we split the logic into (20+) bite size components. This greatly increases the readability and makes extending a component in the search menu much more straightforward.
That being said, certain pieces needed to be rewritten from scratch as they did not translate from widget -> glimmer, or there was a general code upgraded needed. There are a few of these changes worth noting:
### Search Service
**Search Term** -> In the widget implementation we had a overly complex way of managing the current search term. We tracked the search term across multiple different states (`term`, `opts.term`, `searchData.term`) causing headaches. This PR introduces a single source of truth:
```js
this.search.activeGlobalSearchTerm
```
This tracked value is available anywhere the `search` service is injected. In the case the search term should be needs to be updated you can call
```js
this.search.activeGlobalSearchTerm = "foo"
```
**event listeners** -> In the widget implementation we defined event listeners **only** on the search input to handle things such as
- keyboard navigation / shortcuts
- closing the search menu
- performing a search with "enter"
Having this in one place caused a lot of bloat in our logic as we had to handle multiple different cases in one location. Do _x_ if it is this element, but do _y_ if it is another. This PR updates the event listeners to be attached to individual components, allowing for a more fine tuned set of actions per element. To not duplicate logic across multiple components, we have condensed shared logic to actions on the search service to be reused. For example - `this.search.handleArrowUpOrDown` - to handle keyboard navigation.
### Search Context
We have unique logic based on the current search context (topic / tag / category / user / etc). This context is set within a models route file. We have updated the search service with a tracked value `searchContext` that can be utilized and updated from any component where the search service is injected.
```js
# before
this.searchService.set("searchContext", user.searchContext);
# after
this.searchService.searchContext = user.searchContext;
```
# Views
<img width="434" alt="Screenshot 2023-06-15 at 11 01 01 AM" src="https://github.com/discourse/discourse/assets/50783505/ef57e8e6-4e7b-4ba0-a770-8f2ed6310569">
<img width="418" alt="Screenshot 2023-06-15 at 11 04 11 AM" src="https://github.com/discourse/discourse/assets/50783505/2c1e0b38-d12c-4339-a1d5-04f0c1932b08">
<img width="413" alt="Screenshot 2023-06-15 at 11 04 34 AM" src="https://github.com/discourse/discourse/assets/50783505/b871d164-88cb-405e-9b78-d326a6f63686">
<img width="419" alt="Screenshot 2023-06-15 at 11 07 51 AM" src="https://github.com/discourse/discourse/assets/50783505/c7309a19-f541-47f4-94ef-10fa65658d8c">
<img width="424" alt="Screenshot 2023-06-15 at 11 04 48 AM" src="https://github.com/discourse/discourse/assets/50783505/f3dba06e-b029-431c-b3d0-36727b9e6dce">
<img width="415" alt="Screenshot 2023-06-15 at 11 08 57 AM" src="https://github.com/discourse/discourse/assets/50783505/ad4e7250-040c-4d06-bf06-99652f4c7b7c">
2023-06-16 22:24:07 +08:00
|
|
|
a.search-link {
|
|
|
|
width: 100%;
|
|
|
|
box-sizing: border-box;
|
|
|
|
@include ellipsis;
|
|
|
|
}
|
2020-09-29 09:59:45 +08:00
|
|
|
.panel-body {
|
|
|
|
overflow-y: auto;
|
|
|
|
}
|
2020-08-13 04:03:08 +08:00
|
|
|
}
|
|
|
|
|
2015-09-04 03:57:00 +08:00
|
|
|
.menu-links.columned {
|
|
|
|
li {
|
|
|
|
width: 50%;
|
|
|
|
float: left;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-29 02:32:53 +08:00
|
|
|
.menu-panel {
|
DEV: Upgrade search-menu to glimmer (#20482)
# Top level view
This PR is the first version of converting the search menu and its logic from (deprecated) widgets to glimmer components. The changes are hidden behind a group based feature flag. This will give us the ability to test the new implementation in a production setting before fully committing to the new search menu.
# What has changed
The majority of the logic from the widget implementation has been updated to fit within the context of a glimmer component, but it has not fundamentally changed. Instead of having a single widget - [search-menu.js](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/widgets/search-menu.js) - that built the bulk of the search menu logic, we split the logic into (20+) bite size components. This greatly increases the readability and makes extending a component in the search menu much more straightforward.
That being said, certain pieces needed to be rewritten from scratch as they did not translate from widget -> glimmer, or there was a general code upgraded needed. There are a few of these changes worth noting:
### Search Service
**Search Term** -> In the widget implementation we had a overly complex way of managing the current search term. We tracked the search term across multiple different states (`term`, `opts.term`, `searchData.term`) causing headaches. This PR introduces a single source of truth:
```js
this.search.activeGlobalSearchTerm
```
This tracked value is available anywhere the `search` service is injected. In the case the search term should be needs to be updated you can call
```js
this.search.activeGlobalSearchTerm = "foo"
```
**event listeners** -> In the widget implementation we defined event listeners **only** on the search input to handle things such as
- keyboard navigation / shortcuts
- closing the search menu
- performing a search with "enter"
Having this in one place caused a lot of bloat in our logic as we had to handle multiple different cases in one location. Do _x_ if it is this element, but do _y_ if it is another. This PR updates the event listeners to be attached to individual components, allowing for a more fine tuned set of actions per element. To not duplicate logic across multiple components, we have condensed shared logic to actions on the search service to be reused. For example - `this.search.handleArrowUpOrDown` - to handle keyboard navigation.
### Search Context
We have unique logic based on the current search context (topic / tag / category / user / etc). This context is set within a models route file. We have updated the search service with a tracked value `searchContext` that can be utilized and updated from any component where the search service is injected.
```js
# before
this.searchService.set("searchContext", user.searchContext);
# after
this.searchService.searchContext = user.searchContext;
```
# Views
<img width="434" alt="Screenshot 2023-06-15 at 11 01 01 AM" src="https://github.com/discourse/discourse/assets/50783505/ef57e8e6-4e7b-4ba0-a770-8f2ed6310569">
<img width="418" alt="Screenshot 2023-06-15 at 11 04 11 AM" src="https://github.com/discourse/discourse/assets/50783505/2c1e0b38-d12c-4339-a1d5-04f0c1932b08">
<img width="413" alt="Screenshot 2023-06-15 at 11 04 34 AM" src="https://github.com/discourse/discourse/assets/50783505/b871d164-88cb-405e-9b78-d326a6f63686">
<img width="419" alt="Screenshot 2023-06-15 at 11 07 51 AM" src="https://github.com/discourse/discourse/assets/50783505/c7309a19-f541-47f4-94ef-10fa65658d8c">
<img width="424" alt="Screenshot 2023-06-15 at 11 04 48 AM" src="https://github.com/discourse/discourse/assets/50783505/f3dba06e-b029-431c-b3d0-36727b9e6dce">
<img width="415" alt="Screenshot 2023-06-15 at 11 08 57 AM" src="https://github.com/discourse/discourse/assets/50783505/ad4e7250-040c-4d06-bf06-99652f4c7b7c">
2023-06-16 22:24:07 +08:00
|
|
|
// remove once glimmer search menu in place
|
2021-06-03 12:14:24 +08:00
|
|
|
.widget-link,
|
|
|
|
.categories-link {
|
|
|
|
padding: 0.25em 0.5em;
|
|
|
|
display: block;
|
|
|
|
color: var(--primary);
|
|
|
|
&:hover,
|
|
|
|
&:focus {
|
2023-02-21 17:15:49 +08:00
|
|
|
background-color: var(--d-hover);
|
2021-06-03 12:14:24 +08:00
|
|
|
outline: none;
|
|
|
|
}
|
2020-05-29 14:05:21 +08:00
|
|
|
|
2021-06-03 12:14:24 +08:00
|
|
|
.d-icon {
|
|
|
|
color: var(--primary-medium);
|
2015-08-26 00:50:19 +08:00
|
|
|
}
|
2015-09-05 04:56:02 +08:00
|
|
|
|
|
|
|
.new {
|
2022-10-12 21:31:59 +08:00
|
|
|
font-size: var(--font-down-1);
|
2015-09-05 04:56:02 +08:00
|
|
|
margin-left: 0.5em;
|
2020-08-04 10:57:10 +08:00
|
|
|
color: var(--primary-med-or-secondary-med);
|
2015-09-05 04:56:02 +08:00
|
|
|
}
|
2021-06-03 12:14:24 +08:00
|
|
|
|
|
|
|
&.show-help,
|
|
|
|
&.filter {
|
|
|
|
color: var(--tertiary);
|
|
|
|
}
|
2015-08-26 00:50:19 +08:00
|
|
|
}
|
|
|
|
|
DEV: Upgrade search-menu to glimmer (#20482)
# Top level view
This PR is the first version of converting the search menu and its logic from (deprecated) widgets to glimmer components. The changes are hidden behind a group based feature flag. This will give us the ability to test the new implementation in a production setting before fully committing to the new search menu.
# What has changed
The majority of the logic from the widget implementation has been updated to fit within the context of a glimmer component, but it has not fundamentally changed. Instead of having a single widget - [search-menu.js](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/widgets/search-menu.js) - that built the bulk of the search menu logic, we split the logic into (20+) bite size components. This greatly increases the readability and makes extending a component in the search menu much more straightforward.
That being said, certain pieces needed to be rewritten from scratch as they did not translate from widget -> glimmer, or there was a general code upgraded needed. There are a few of these changes worth noting:
### Search Service
**Search Term** -> In the widget implementation we had a overly complex way of managing the current search term. We tracked the search term across multiple different states (`term`, `opts.term`, `searchData.term`) causing headaches. This PR introduces a single source of truth:
```js
this.search.activeGlobalSearchTerm
```
This tracked value is available anywhere the `search` service is injected. In the case the search term should be needs to be updated you can call
```js
this.search.activeGlobalSearchTerm = "foo"
```
**event listeners** -> In the widget implementation we defined event listeners **only** on the search input to handle things such as
- keyboard navigation / shortcuts
- closing the search menu
- performing a search with "enter"
Having this in one place caused a lot of bloat in our logic as we had to handle multiple different cases in one location. Do _x_ if it is this element, but do _y_ if it is another. This PR updates the event listeners to be attached to individual components, allowing for a more fine tuned set of actions per element. To not duplicate logic across multiple components, we have condensed shared logic to actions on the search service to be reused. For example - `this.search.handleArrowUpOrDown` - to handle keyboard navigation.
### Search Context
We have unique logic based on the current search context (topic / tag / category / user / etc). This context is set within a models route file. We have updated the search service with a tracked value `searchContext` that can be utilized and updated from any component where the search service is injected.
```js
# before
this.searchService.set("searchContext", user.searchContext);
# after
this.searchService.searchContext = user.searchContext;
```
# Views
<img width="434" alt="Screenshot 2023-06-15 at 11 01 01 AM" src="https://github.com/discourse/discourse/assets/50783505/ef57e8e6-4e7b-4ba0-a770-8f2ed6310569">
<img width="418" alt="Screenshot 2023-06-15 at 11 04 11 AM" src="https://github.com/discourse/discourse/assets/50783505/2c1e0b38-d12c-4339-a1d5-04f0c1932b08">
<img width="413" alt="Screenshot 2023-06-15 at 11 04 34 AM" src="https://github.com/discourse/discourse/assets/50783505/b871d164-88cb-405e-9b78-d326a6f63686">
<img width="419" alt="Screenshot 2023-06-15 at 11 07 51 AM" src="https://github.com/discourse/discourse/assets/50783505/c7309a19-f541-47f4-94ef-10fa65658d8c">
<img width="424" alt="Screenshot 2023-06-15 at 11 04 48 AM" src="https://github.com/discourse/discourse/assets/50783505/f3dba06e-b029-431c-b3d0-36727b9e6dce">
<img width="415" alt="Screenshot 2023-06-15 at 11 08 57 AM" src="https://github.com/discourse/discourse/assets/50783505/ad4e7250-040c-4d06-bf06-99652f4c7b7c">
2023-06-16 22:24:07 +08:00
|
|
|
.search-link,
|
|
|
|
.categories-link {
|
|
|
|
padding: 0.25em 0.5em;
|
|
|
|
display: block;
|
|
|
|
color: var(--primary);
|
|
|
|
&:hover,
|
|
|
|
&:focus {
|
|
|
|
background-color: var(--d-hover);
|
|
|
|
outline: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.d-icon {
|
|
|
|
color: var(--primary-medium);
|
|
|
|
}
|
|
|
|
|
|
|
|
.new {
|
|
|
|
font-size: var(--font-down-1);
|
|
|
|
margin-left: 0.5em;
|
|
|
|
color: var(--primary-med-or-secondary-med);
|
|
|
|
}
|
|
|
|
|
|
|
|
&.show-help,
|
|
|
|
&.filter {
|
|
|
|
color: var(--tertiary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-26 00:50:19 +08:00
|
|
|
li.category-link {
|
|
|
|
float: left;
|
|
|
|
background-color: transparent;
|
2018-02-03 08:03:25 +08:00
|
|
|
display: inline-flex;
|
2018-08-11 02:00:06 +08:00
|
|
|
align-items: center;
|
2018-05-24 16:15:57 +08:00
|
|
|
padding: 0.25em 0.5em;
|
|
|
|
width: 50%;
|
|
|
|
box-sizing: border-box;
|
2018-08-04 05:43:07 +08:00
|
|
|
a {
|
2018-08-07 21:47:01 +08:00
|
|
|
display: inline-flex;
|
2018-08-04 05:43:07 +08:00
|
|
|
&:hover,
|
|
|
|
&:focus {
|
|
|
|
background: transparent;
|
2020-05-29 14:05:21 +08:00
|
|
|
|
|
|
|
.category-name {
|
2020-08-04 10:57:10 +08:00
|
|
|
color: var(--primary);
|
2020-05-29 14:05:21 +08:00
|
|
|
}
|
2018-08-04 05:43:07 +08:00
|
|
|
}
|
|
|
|
}
|
2015-08-26 00:50:19 +08:00
|
|
|
.badge-notification {
|
2020-08-04 10:57:10 +08:00
|
|
|
color: var(--primary-med-or-secondary-med);
|
2015-08-26 00:50:19 +08:00
|
|
|
background-color: transparent;
|
2015-08-29 02:32:53 +08:00
|
|
|
display: inline;
|
2015-09-03 03:42:20 +08:00
|
|
|
padding: 0;
|
2022-10-12 21:31:59 +08:00
|
|
|
font-size: var(--font-down-1);
|
2022-10-12 22:05:42 +08:00
|
|
|
line-height: var(--line-height-large);
|
2018-02-03 08:03:25 +08:00
|
|
|
}
|
2015-08-26 00:50:19 +08:00
|
|
|
}
|
2018-06-08 17:49:31 +08:00
|
|
|
|
2015-08-26 00:50:19 +08:00
|
|
|
// note these topic counts only appear for anons in the category hamburger drop down
|
|
|
|
b.topics-count {
|
2020-08-04 10:57:10 +08:00
|
|
|
color: var(--primary-med-or-secondary-med);
|
2015-08-26 00:50:19 +08:00
|
|
|
font-weight: normal;
|
2022-10-12 21:31:59 +08:00
|
|
|
font-size: var(--font-down-1);
|
2018-02-03 08:03:25 +08:00
|
|
|
}
|
2015-09-03 03:42:20 +08:00
|
|
|
|
2019-06-28 01:26:14 +08:00
|
|
|
div.discourse-tags {
|
2022-10-12 21:31:59 +08:00
|
|
|
font-size: var(--font-down-1);
|
2019-06-28 01:26:14 +08:00
|
|
|
}
|
2024-02-28 09:15:02 +08:00
|
|
|
|
|
|
|
.sidebar-filter {
|
|
|
|
width: calc(100% - 2.35rem);
|
|
|
|
}
|
2024-03-11 08:08:44 +08:00
|
|
|
|
|
|
|
.sidebar-sections {
|
|
|
|
&__back-to-forum {
|
|
|
|
margin: 0 var(--d-sidebar-row-horizontal-padding) 0.5em
|
|
|
|
var(--d-sidebar-row-horizontal-padding);
|
|
|
|
color: var(--d-sidebar-link-color);
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
svg {
|
|
|
|
margin-right: var(--d-sidebar-section-link-prefix-margin-right);
|
|
|
|
height: 0.75em;
|
|
|
|
width: 0.75em;
|
|
|
|
color: var(--d-sidebar-link-icon-color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-08-26 00:50:19 +08:00
|
|
|
}
|
2015-08-27 02:42:42 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
// Panel / user-notification-list styles. **not** menu panel sizing styles
|
|
|
|
.user-menu .quick-access-panel,
|
|
|
|
.user-notifications-list {
|
|
|
|
width: 100%;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
min-height: 0;
|
|
|
|
max-height: 100%;
|
|
|
|
border-top: 1px solid var(--primary-low);
|
|
|
|
padding-top: 0.75em;
|
|
|
|
margin-top: -1px;
|
|
|
|
|
|
|
|
&:focus {
|
|
|
|
outline: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.double-user,
|
|
|
|
.multi-user {
|
|
|
|
white-space: unset;
|
|
|
|
}
|
|
|
|
|
|
|
|
.item-label {
|
|
|
|
overflow: hidden;
|
|
|
|
white-space: nowrap;
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
color: var(--primary);
|
|
|
|
}
|
|
|
|
|
|
|
|
h3 {
|
|
|
|
padding: 0 0.4em;
|
|
|
|
font-weight: bold;
|
|
|
|
margin: 0.5em 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.d-icon,
|
|
|
|
&:hover .d-icon {
|
|
|
|
color: var(--primary-medium);
|
|
|
|
}
|
|
|
|
.icon {
|
|
|
|
color: var(--primary-high);
|
|
|
|
}
|
|
|
|
|
|
|
|
.btn-primary {
|
|
|
|
.d-icon {
|
|
|
|
color: var(--secondary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ul {
|
2020-08-11 04:17:15 +08:00
|
|
|
display: flex;
|
2023-12-12 01:04:43 +08:00
|
|
|
flex-flow: column wrap;
|
|
|
|
overflow: hidden;
|
2020-08-11 04:17:15 +08:00
|
|
|
max-height: 100%;
|
2023-12-12 01:04:43 +08:00
|
|
|
}
|
2015-08-29 02:32:53 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
li {
|
|
|
|
background-color: var(--secondary);
|
|
|
|
box-sizing: border-box;
|
|
|
|
list-style-type: none;
|
|
|
|
|
|
|
|
&.unread,
|
|
|
|
&.pending {
|
|
|
|
background-color: var(--tertiary-low);
|
2018-06-08 17:49:31 +08:00
|
|
|
}
|
2023-12-12 01:04:43 +08:00
|
|
|
&:hover {
|
|
|
|
background-color: var(--d-hover);
|
|
|
|
outline: none;
|
2018-06-08 17:49:31 +08:00
|
|
|
}
|
2020-05-29 14:05:21 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
&:focus-within {
|
|
|
|
background: var(--d-hover);
|
|
|
|
a {
|
|
|
|
// we don't need the link focus because we're styling the parent
|
|
|
|
outline: 0;
|
2021-04-01 08:22:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
// This is until other languages remove the HTML from within
|
|
|
|
// notifications. It can then be removed
|
|
|
|
div .fa {
|
|
|
|
display: none;
|
2020-08-11 04:17:15 +08:00
|
|
|
}
|
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
span.double-user,
|
|
|
|
// e.g., "username, username2"
|
|
|
|
span.multi-user
|
|
|
|
// e.g., "username and n others"
|
|
|
|
{
|
|
|
|
display: inline;
|
|
|
|
max-width: 100%;
|
|
|
|
align-items: baseline;
|
|
|
|
white-space: nowrap;
|
|
|
|
}
|
2017-09-15 02:26:31 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
span.multi-user
|
|
|
|
// e.g., "username, username2, and n others"
|
|
|
|
{
|
|
|
|
span.multi-username:nth-of-type(2) {
|
|
|
|
// margin between username2 and "and n others"
|
|
|
|
margin-right: 0.25em;
|
2020-11-09 13:06:52 +08:00
|
|
|
}
|
2023-12-12 01:04:43 +08:00
|
|
|
}
|
2020-11-09 13:06:52 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
// truncate when usernames are very long
|
|
|
|
span.multi-username {
|
|
|
|
@include ellipsis;
|
|
|
|
flex: 0 1 auto;
|
|
|
|
min-width: 1.2em;
|
|
|
|
max-width: 10em;
|
|
|
|
&:nth-of-type(2) {
|
|
|
|
// margin for comma between username and username2
|
|
|
|
margin-left: 0.25em;
|
2020-11-09 13:06:52 +08:00
|
|
|
}
|
2023-12-12 01:04:43 +08:00
|
|
|
}
|
2020-11-09 13:06:52 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
&:hover {
|
|
|
|
background-color: var(--d-hover);
|
|
|
|
outline: none;
|
|
|
|
}
|
2020-11-09 13:06:52 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
&:focus-within {
|
|
|
|
background: var(--d-hover);
|
|
|
|
a {
|
|
|
|
// we don't need the link focus because we're styling the parent
|
|
|
|
outline: 0;
|
2018-04-14 00:53:04 +08:00
|
|
|
}
|
2023-12-12 01:04:43 +08:00
|
|
|
.btn-flat:focus {
|
|
|
|
// undo default btn-flat style
|
|
|
|
background: transparent;
|
2021-05-24 16:10:01 +08:00
|
|
|
}
|
2023-12-12 01:04:43 +08:00
|
|
|
}
|
2021-05-24 16:10:01 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
a,
|
|
|
|
.profile-tab-btn {
|
|
|
|
display: flex;
|
|
|
|
margin: 0.25em;
|
|
|
|
padding: 0em 0.25em;
|
|
|
|
}
|
2021-01-21 01:50:36 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
button {
|
|
|
|
padding: 0.25em 0.5em;
|
|
|
|
}
|
2020-05-29 14:05:21 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
a,
|
|
|
|
button {
|
|
|
|
> div {
|
|
|
|
overflow: hidden; // clears the text from wrapping below icons
|
|
|
|
overflow-wrap: anywhere;
|
|
|
|
@supports not (overflow-wrap: anywhere) {
|
|
|
|
word-break: break-word;
|
2018-08-10 00:04:34 +08:00
|
|
|
}
|
2018-04-14 00:53:04 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
// Truncate items with more than 2 lines.
|
|
|
|
@include line-clamp(2);
|
2015-08-29 02:32:53 +08:00
|
|
|
}
|
|
|
|
}
|
2023-12-08 01:30:44 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
p {
|
|
|
|
margin: 0;
|
|
|
|
overflow: hidden;
|
2015-08-29 02:32:53 +08:00
|
|
|
}
|
2023-12-12 01:04:43 +08:00
|
|
|
}
|
|
|
|
li:not(.show-all) {
|
|
|
|
padding: 0;
|
|
|
|
align-self: flex-start;
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
.d-icon {
|
|
|
|
padding-top: 0.2em;
|
|
|
|
margin-right: 0.5em;
|
2015-08-29 02:32:53 +08:00
|
|
|
}
|
2023-12-12 01:04:43 +08:00
|
|
|
}
|
|
|
|
.is-warning {
|
|
|
|
.d-icon-envelope {
|
|
|
|
color: var(--danger);
|
2015-08-29 02:32:53 +08:00
|
|
|
}
|
2023-12-12 01:04:43 +08:00
|
|
|
}
|
|
|
|
.read {
|
|
|
|
background-color: var(--secondary);
|
|
|
|
}
|
|
|
|
.none {
|
|
|
|
padding-top: 5px;
|
|
|
|
}
|
|
|
|
.spinner-container {
|
|
|
|
min-height: 2em;
|
|
|
|
}
|
|
|
|
.spinner {
|
|
|
|
width: 20px;
|
|
|
|
height: 20px;
|
|
|
|
border-width: 2px;
|
|
|
|
margin: 0 auto;
|
|
|
|
}
|
|
|
|
.show-all a {
|
|
|
|
width: 100%;
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
min-height: 30px;
|
|
|
|
color: var(--primary-med-or-secondary-high);
|
|
|
|
background: var(--blend-primary-secondary-5);
|
|
|
|
&:hover {
|
|
|
|
color: var(--primary);
|
|
|
|
background: var(--primary-low);
|
2017-11-08 02:48:35 +08:00
|
|
|
}
|
2015-08-29 02:32:53 +08:00
|
|
|
}
|
2023-12-12 01:04:43 +08:00
|
|
|
/* as a big ol' click target, don't let text inside be selected */
|
|
|
|
@include unselectable;
|
2020-08-29 08:20:59 +08:00
|
|
|
}
|
2017-11-07 23:41:12 +08:00
|
|
|
|
2023-12-12 01:04:43 +08:00
|
|
|
// Styles to have user avatar positioned and sized correctly
|
|
|
|
.user-menu.show-avatars,
|
|
|
|
.user-notifications-list.show-avatars {
|
2023-12-13 04:28:29 +08:00
|
|
|
li.notification,
|
|
|
|
li.bookmark,
|
|
|
|
li.message {
|
2023-12-08 01:30:44 +08:00
|
|
|
a {
|
2023-12-12 04:44:14 +08:00
|
|
|
align-items: center;
|
|
|
|
padding: 0.15em 0;
|
|
|
|
|
2023-12-13 04:28:29 +08:00
|
|
|
.item-label {
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
.item-description {
|
|
|
|
color: var(--primary);
|
|
|
|
}
|
|
|
|
|
2023-12-08 01:30:44 +08:00
|
|
|
.icon-avatar {
|
|
|
|
display: flex;
|
|
|
|
position: relative;
|
|
|
|
overflow: visible;
|
|
|
|
margin-right: 0.5em;
|
|
|
|
flex-shrink: 0;
|
2023-12-12 04:44:14 +08:00
|
|
|
width: 2em;
|
|
|
|
height: 2em;
|
|
|
|
margin: 0.3em 1em 0 0;
|
2023-12-08 01:30:44 +08:00
|
|
|
|
|
|
|
.avatar {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
}
|
2023-12-13 04:28:29 +08:00
|
|
|
&__icon-wrapper {
|
2023-12-08 01:30:44 +08:00
|
|
|
position: absolute;
|
2023-12-13 04:28:29 +08:00
|
|
|
right: -0.65em;
|
2023-12-13 05:32:16 +08:00
|
|
|
top: -0.45em;
|
2023-12-13 04:28:29 +08:00
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
width: 22px;
|
|
|
|
height: 22px;
|
2023-12-08 01:30:44 +08:00
|
|
|
border-radius: 100%;
|
2023-12-12 04:44:14 +08:00
|
|
|
background: var(--secondary);
|
2023-12-13 04:28:29 +08:00
|
|
|
|
|
|
|
.d-icon {
|
|
|
|
display: block;
|
|
|
|
margin: 0;
|
|
|
|
padding: 0;
|
|
|
|
font-size: var(--font-down-1);
|
|
|
|
color: var(--primary);
|
|
|
|
}
|
2023-12-08 01:30:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
& + div {
|
|
|
|
padding: 0.25em 0;
|
|
|
|
}
|
|
|
|
}
|
2023-12-13 04:28:29 +08:00
|
|
|
&.unread .icon-avatar__icon-wrapper {
|
2023-12-12 04:44:14 +08:00
|
|
|
background: var(--tertiary);
|
2023-12-13 04:28:29 +08:00
|
|
|
|
|
|
|
.d-icon {
|
|
|
|
color: var(--secondary);
|
|
|
|
}
|
2023-12-12 04:44:14 +08:00
|
|
|
}
|
2023-12-08 01:30:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-25 12:33:26 +08:00
|
|
|
.hamburger-panel .menu-panel.slide-in {
|
|
|
|
left: 0;
|
|
|
|
|
|
|
|
.panel-body {
|
|
|
|
display: block;
|
|
|
|
}
|
|
|
|
.panel-body-contents {
|
|
|
|
max-height: unset;
|
|
|
|
min-height: 100%;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.header-cloak {
|
|
|
|
height: 100%;
|
|
|
|
width: 100%;
|
|
|
|
position: fixed;
|
UX: improve touch, swipe, panning performance on mobile menus (#23775)
PERF: improve touch, swipe, panning performance on mobile menus
---
* stop event propagation on swipe events: other touch events were stealing a huge amount of time here. Stop event
propagation when handling pan events.
* animate with [web animations api](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API)
* prefer translate3d to hint for gpu rendering.
* query document for elements only on start move event, not on subsequent move
events
* remove unused calculations for directioned velocity and distance: all swipe/pan elements function in x/y direction only.
* re-implement scroll locking behavior.
re-implemented scroll lock behavior
---
With stop event propagation, we need to re-implement scroll locking on menu swipes.
Previously, this was using onTouchMove which was costly.
We may now use styling with overflow-y:hidden to lock scroll behavior.
overflow:hidden on html/body elements is now supported by iOS as of 2022
https://bugs.webkit.org/show_bug.cgi?id=153852
https://bugs.webkit.org/show_bug.cgi?id=220908
UX: improve swipe
---
Some improvements to get gestures and swipes feeling a little more polished.
This focuses on end gesture, and how we transfer it to a css animation to
complete a menu open/close action.
Multitouch: events may pan, scroll, and zoom - especially on iOS safari.
Cancelling the swipe event allows for a more pleasant zooming experience.
* ease-out on menus opening, linear on close
* calculate animation duration for opening and closing,
attempt to better transfer user swipe velocity to css animation.
* more timely close/open and cleanup from calculated animation timing.
* add animation to closing menus on cloak tap
* correctly animate menus with ease-in and ease-out
* add swipe cancel event on multitouch event
DEV
---
* lean on promises
js animations api gives us promises to listen to. Update test waiters
to use waitForPromise from @ember/test-waiters instead of reigster/unregister.
* convert swipe mixin to its own class.
Convert swipe callbacks to custom events on the element.
Move shared functions for max animation time and close logic to
new shared class.
swipe-events lib uses custom events to trigger callbacks, rather than assuming
implemented hard coded function from the mixin's base class. Custom events are
triggered from the bound element as swipestart, swipeend, swipe
Add shared convenience functions for swipe events so they can be more easily
shared.
A client receives an initial swipe event and can check some state to see if it
wants to handle the swipe event and if it doesn't, calling
`event.preventDefault();` will prevent `swipe` and `swipeend` events from firing
until another distinct swipestart event is fired. Swipe events will auto-cancel on multitouch.
The scroll lock has also exposed as its own utility class.
2023-10-17 02:27:00 +08:00
|
|
|
background-color: rgba(0, 0, 0, 0.3);
|
2023-02-21 21:55:38 +08:00
|
|
|
top: var(--header-top);
|
2022-11-25 12:33:26 +08:00
|
|
|
left: 0;
|
|
|
|
display: none;
|
|
|
|
touch-action: pan-y pinch-zoom;
|
|
|
|
}
|
|
|
|
|
|
|
|
.menu-panel.slide-in {
|
2023-02-21 21:55:38 +08:00
|
|
|
top: var(--header-top);
|
|
|
|
box-sizing: border-box;
|
2023-05-01 22:41:28 +08:00
|
|
|
// ensure there's always space to click outside on tiny devices
|
|
|
|
max-width: 90vw;
|
2023-02-21 21:55:38 +08:00
|
|
|
|
2023-03-14 22:41:38 +08:00
|
|
|
--100dvh: 100%;
|
|
|
|
@supports (height: 100dvh) {
|
|
|
|
--100dvh: 100dvh;
|
|
|
|
}
|
UX: improve touch, swipe, panning performance on mobile menus (#23775)
PERF: improve touch, swipe, panning performance on mobile menus
---
* stop event propagation on swipe events: other touch events were stealing a huge amount of time here. Stop event
propagation when handling pan events.
* animate with [web animations api](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API)
* prefer translate3d to hint for gpu rendering.
* query document for elements only on start move event, not on subsequent move
events
* remove unused calculations for directioned velocity and distance: all swipe/pan elements function in x/y direction only.
* re-implement scroll locking behavior.
re-implemented scroll lock behavior
---
With stop event propagation, we need to re-implement scroll locking on menu swipes.
Previously, this was using onTouchMove which was costly.
We may now use styling with overflow-y:hidden to lock scroll behavior.
overflow:hidden on html/body elements is now supported by iOS as of 2022
https://bugs.webkit.org/show_bug.cgi?id=153852
https://bugs.webkit.org/show_bug.cgi?id=220908
UX: improve swipe
---
Some improvements to get gestures and swipes feeling a little more polished.
This focuses on end gesture, and how we transfer it to a css animation to
complete a menu open/close action.
Multitouch: events may pan, scroll, and zoom - especially on iOS safari.
Cancelling the swipe event allows for a more pleasant zooming experience.
* ease-out on menus opening, linear on close
* calculate animation duration for opening and closing,
attempt to better transfer user swipe velocity to css animation.
* more timely close/open and cleanup from calculated animation timing.
* add animation to closing menus on cloak tap
* correctly animate menus with ease-in and ease-out
* add swipe cancel event on multitouch event
DEV
---
* lean on promises
js animations api gives us promises to listen to. Update test waiters
to use waitForPromise from @ember/test-waiters instead of reigster/unregister.
* convert swipe mixin to its own class.
Convert swipe callbacks to custom events on the element.
Move shared functions for max animation time and close logic to
new shared class.
swipe-events lib uses custom events to trigger callbacks, rather than assuming
implemented hard coded function from the mixin's base class. Custom events are
triggered from the bound element as swipestart, swipeend, swipe
Add shared convenience functions for swipe events so they can be more easily
shared.
A client receives an initial swipe event and can check some state to see if it
wants to handle the swipe event and if it doesn't, calling
`event.preventDefault();` will prevent `swipe` and `swipeend` events from firing
until another distinct swipestart event is fired. Swipe events will auto-cancel on multitouch.
The scroll lock has also exposed as its own utility class.
2023-10-17 02:27:00 +08:00
|
|
|
box-shadow: 0px 0 30px -2px rgba(0, 0, 0, 0.5);
|
2023-02-21 21:55:38 +08:00
|
|
|
|
2023-03-17 07:23:15 +08:00
|
|
|
--base-height: calc(var(--100dvh) - var(--header-top));
|
2023-02-21 21:55:38 +08:00
|
|
|
|
|
|
|
height: var(--base-height);
|
|
|
|
|
2024-02-01 17:24:44 +08:00
|
|
|
html.footer-nav-ipad & {
|
|
|
|
height: calc(var(--base-height) - var(--footer-nav-height));
|
2023-02-21 21:55:38 +08:00
|
|
|
}
|
2022-11-25 12:33:26 +08:00
|
|
|
}
|