@things-factory/menu-ui 8.0.0-beta.8 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/client/apptools/favorite-tool.js +130 -0
  2. package/client/bootstrap.js +57 -0
  3. package/client/components/child-menus-selector.js +150 -0
  4. package/client/components/role-select-popup.js +179 -0
  5. package/client/pages/menu-list-page.js +200 -0
  6. package/client/pages/menu-management-detail.js +384 -0
  7. package/client/pages/menu-management.js +294 -0
  8. package/client/pages/role-menus-management.js +215 -0
  9. package/client/route.js +15 -0
  10. package/client/viewparts/menu-bar.js +114 -0
  11. package/client/viewparts/menu-tile-list.js +222 -0
  12. package/client/viewparts/menu-tree-bar.js +295 -0
  13. package/dist-server/tsconfig.tsbuildinfo +1 -1
  14. package/package.json +18 -21
  15. package/server/index.ts +0 -0
  16. package/things-factory.config.js +14 -5
  17. package/dist-client/apptools/favorite-tool.d.ts +0 -28
  18. package/dist-client/apptools/favorite-tool.js +0 -139
  19. package/dist-client/apptools/favorite-tool.js.map +0 -1
  20. package/dist-client/bootstrap.d.ts +0 -4
  21. package/dist-client/bootstrap.js +0 -52
  22. package/dist-client/bootstrap.js.map +0 -1
  23. package/dist-client/components/child-menus-selector.d.ts +0 -1
  24. package/dist-client/components/child-menus-selector.js +0 -146
  25. package/dist-client/components/child-menus-selector.js.map +0 -1
  26. package/dist-client/components/role-select-popup.d.ts +0 -1
  27. package/dist-client/components/role-select-popup.js +0 -180
  28. package/dist-client/components/role-select-popup.js.map +0 -1
  29. package/dist-client/index.js +0 -2
  30. package/dist-client/index.js.map +0 -1
  31. package/dist-client/pages/menu-list-page.d.ts +0 -2
  32. package/dist-client/pages/menu-list-page.js +0 -204
  33. package/dist-client/pages/menu-list-page.js.map +0 -1
  34. package/dist-client/pages/menu-management-detail.d.ts +0 -2
  35. package/dist-client/pages/menu-management-detail.js +0 -376
  36. package/dist-client/pages/menu-management-detail.js.map +0 -1
  37. package/dist-client/pages/menu-management.d.ts +0 -3
  38. package/dist-client/pages/menu-management.js +0 -280
  39. package/dist-client/pages/menu-management.js.map +0 -1
  40. package/dist-client/pages/role-menus-management.d.ts +0 -4
  41. package/dist-client/pages/role-menus-management.js +0 -215
  42. package/dist-client/pages/role-menus-management.js.map +0 -1
  43. package/dist-client/route.d.ts +0 -1
  44. package/dist-client/route.js +0 -14
  45. package/dist-client/route.js.map +0 -1
  46. package/dist-client/tsconfig.tsbuildinfo +0 -1
  47. package/dist-client/viewparts/menu-bar.d.ts +0 -12
  48. package/dist-client/viewparts/menu-bar.js +0 -108
  49. package/dist-client/viewparts/menu-bar.js.map +0 -1
  50. package/dist-client/viewparts/menu-tile-list.d.ts +0 -13
  51. package/dist-client/viewparts/menu-tile-list.js +0 -234
  52. package/dist-client/viewparts/menu-tile-list.js.map +0 -1
  53. package/dist-client/viewparts/menu-tree-bar.d.ts +0 -28
  54. package/dist-client/viewparts/menu-tree-bar.js +0 -307
  55. package/dist-client/viewparts/menu-tree-bar.js.map +0 -1
  56. /package/{dist-client/index.d.ts → client/index.js} +0 -0
  57. /package/{dist-client → client}/themes/menu-theme.css +0 -0
@@ -0,0 +1,130 @@
1
+ import '@material/web/icon/icon.js'
2
+
3
+ import { LitElement, html, css } from 'lit'
4
+ import { connect } from 'pwa-helpers/connect-mixin.js'
5
+ import gql from 'graphql-tag'
6
+
7
+ import { store, client } from '@things-factory/shell'
8
+ import { UPDATE_FAVORITES } from '@things-factory/fav-base'
9
+
10
+ export class FavoriteTool extends connect(store)(LitElement) {
11
+ static get properties() {
12
+ return {
13
+ favorites: Array,
14
+ user: Object,
15
+ page: String,
16
+ resourceId: String,
17
+ favored: Boolean,
18
+ routingTypes: Object,
19
+ blackList: Array
20
+ }
21
+ }
22
+
23
+ static get styles() {
24
+ return css`
25
+ :host {
26
+ display: inline-block;
27
+ vertical-align: middle;
28
+ line-height: 0;
29
+ }
30
+
31
+ [favorable] {
32
+ opacity: 0.5;
33
+ }
34
+ `
35
+ }
36
+
37
+ render() {
38
+ var renderable = (this.blackList || []).indexOf(this.page) == -1
39
+
40
+ return renderable
41
+ ? html`
42
+ <md-icon @click=${this.onclick.bind(this)} ?favorable=${!this.favored}
43
+ >${this.favored ? 'star' : 'star_border'}</md-icon
44
+ >
45
+ `
46
+ : html``
47
+ }
48
+
49
+ updated(changes) {
50
+ if (changes.has('user')) {
51
+ this.refreshFavorites()
52
+ }
53
+
54
+ this.favored = (this.favorites || []).includes(this.getFullRouting())
55
+ }
56
+
57
+ stateChanged(state) {
58
+ this.favorites = state.favorite.favorites
59
+ this.user = state.auth.user
60
+ this.page = state.route.page
61
+ this.resourceId = state.route.resourceId
62
+ this.routingTypes = state.menu.routingTypes
63
+ }
64
+
65
+ onclick(event) {
66
+ if (this.favored) {
67
+ this.removeFavorite(this.getFullRouting())
68
+ } else {
69
+ this.addFavorite(this.getFullRouting())
70
+ }
71
+ }
72
+
73
+ async refreshFavorites() {
74
+ if (!this.user || !this.user.email) {
75
+ return
76
+ }
77
+
78
+ const response = await client.query({
79
+ query: gql`
80
+ query {
81
+ myFavorites {
82
+ id
83
+ routing
84
+ }
85
+ }
86
+ `
87
+ })
88
+
89
+ store.dispatch({
90
+ type: UPDATE_FAVORITES,
91
+ favorites: response.data.myFavorites.map(favorite => favorite.routing)
92
+ })
93
+ }
94
+
95
+ async removeFavorite(routing) {
96
+ await client.query({
97
+ query: gql`
98
+ mutation {
99
+ deleteFavorite(routing: "${routing}")
100
+ }
101
+ `
102
+ })
103
+
104
+ this.refreshFavorites()
105
+ }
106
+
107
+ async addFavorite(routing) {
108
+ await client.query({
109
+ query: gql`
110
+ mutation {
111
+ createFavorite(favorite: {
112
+ routing: "${routing}"
113
+ }) {
114
+ id
115
+ routing
116
+ }
117
+ }
118
+ `
119
+ })
120
+
121
+ this.refreshFavorites()
122
+ }
123
+
124
+ getFullRouting() {
125
+ var routingType = Object.values(this.routingTypes).find(type => type.page == this.page)
126
+ return routingType ? `${this.page}/${this.resourceId}` : this.page
127
+ }
128
+ }
129
+
130
+ customElements.define('favorite-tool', FavoriteTool)
@@ -0,0 +1,57 @@
1
+ import '@operato/i18n'
2
+ import './apptools/favorite-tool'
3
+ import './viewparts/menu-tree-bar'
4
+
5
+ import { html } from 'lit-html'
6
+
7
+ import { appendViewpart, TOOL_POSITION, VIEWPART_POSITION } from '@operato/layout'
8
+ import { APPEND_APP_TOOL } from '@things-factory/apptool-base/client'
9
+ import { auth } from '@things-factory/auth-base/dist-client'
10
+ import { ADD_MORENDA } from '@things-factory/more-base/client'
11
+ import { navigate, store } from '@operato/shell'
12
+ import { isMobileDevice } from '@operato/utils'
13
+
14
+ export default function bootstrap() {
15
+ if (!isMobileDevice()) {
16
+ appendViewpart({
17
+ name: 'menu-tree-bar',
18
+ viewpart: {
19
+ show: true,
20
+ template: html` <menu-tree-bar></menu-tree-bar> `
21
+ },
22
+ position: VIEWPART_POSITION.NAVBAR
23
+ })
24
+ }
25
+
26
+ store.dispatch({
27
+ type: APPEND_APP_TOOL,
28
+ tool: {
29
+ name: 'favorite-tool',
30
+ template: html` <favorite-tool .blackList=${['menu-list']}></favorite-tool> `,
31
+ position: TOOL_POSITION.REAR
32
+ }
33
+ })
34
+
35
+ auth.on('profile', ({ credential }) => {
36
+ if (credential.owner) {
37
+ appendRoleMenusManagementMorenda()
38
+ }
39
+ })
40
+ }
41
+
42
+ function appendRoleMenusManagementMorenda() {
43
+ const useRoleByMenusManagementMenu = store.getState()?.menu?.useRoleByMenusManagementMenu || false
44
+
45
+ if (useRoleByMenusManagementMenu) {
46
+ store.dispatch({
47
+ type: ADD_MORENDA,
48
+ morenda: {
49
+ icon: html` <md-icon>menu</md-icon> `,
50
+ name: html` <ox-i18n msgid="title.role_menus_management"></ox-i18n> `,
51
+ action: () => {
52
+ navigate('role-menus')
53
+ }
54
+ }
55
+ })
56
+ }
57
+ }
@@ -0,0 +1,150 @@
1
+ import { i18next, localize } from '@operato/i18n'
2
+ import { client } from '@operato/graphql'
3
+ import gql from 'graphql-tag'
4
+ import { css, html, LitElement } from 'lit'
5
+
6
+ class ChildMenusSelector extends localize(i18next)(LitElement) {
7
+ static get styles() {
8
+ return [
9
+ css`
10
+ :host {
11
+ display: flex;
12
+ flex-direction: column;
13
+ border: 1px solid var(--md-sys-color-primary);
14
+ font: normal 15px var(--theme-font);
15
+ color: var(--md-sys-color-secondary);
16
+ }
17
+ div {
18
+ margin: var(--spacing-medium);
19
+ }
20
+ ul {
21
+ flex: 1;
22
+ background-color: var(--md-sys-color-surface);
23
+ overflow: auto;
24
+ display: grid;
25
+ grid-template-columns: 1fr 1fr;
26
+ margin: 0;
27
+ padding: var(--spacing-medium);
28
+ list-style: none;
29
+ border: 1px dashed rgba(0, 0, 0, 0.1);
30
+ border-width: 1px 0;
31
+ }
32
+
33
+ input[type='checkbox'] {
34
+ display: inline;
35
+ }
36
+
37
+ li {
38
+ padding: var(--spacing-small);
39
+ }
40
+
41
+ #checkAll,
42
+ [for='checkAll'] {
43
+ margin-bottom: var(--spacing-medium);
44
+ padding-bottom: var(--spacing-small);
45
+ font-weight: bold;
46
+ }
47
+
48
+ @media screen and (max-width: 480px) {
49
+ ul {
50
+ grid-template-columns: 1fr;
51
+ }
52
+ }
53
+ `
54
+ ]
55
+ }
56
+
57
+ static get properties() {
58
+ return {
59
+ parentMenu: Object,
60
+ roleMenus: Array,
61
+ targetRole: Object
62
+ }
63
+ }
64
+
65
+ render() {
66
+ const parentMenu = this.parentMenu || {}
67
+ const menus = parentMenu.children || []
68
+ const roleMenus = this.roleMenus || []
69
+
70
+ return html`
71
+ <div>
72
+ <input id="checkAll" type="checkbox" @change=${e => this.onCheckAll(e)} />
73
+ <label for="checkAll">Check all</label>
74
+ </div>
75
+
76
+ <ul menus>
77
+ ${menus?.map(
78
+ menu => html`
79
+ <li>
80
+ <label for="${menu.id}"
81
+ >${menu.name}
82
+ <input
83
+ type="checkbox"
84
+ id="${menu.id}"
85
+ .checked=${roleMenus.map(p => p.id).indexOf(menu.id) > -1}
86
+ .data-menu=${menu.id}
87
+ @change=${e => this.onSave(e)}
88
+ />
89
+ </label>
90
+ </li>
91
+ `
92
+ )}
93
+ </ul>
94
+ `
95
+ }
96
+
97
+ get menuList() {
98
+ return this.renderRoot.querySelectorAll('ul[menus] input[type=checkbox]')
99
+ }
100
+
101
+ async onCheckAll(e) {
102
+ const checked = e.currentTarget.checked
103
+
104
+ Array.from(this.menuList).forEach(checkbox => (checkbox.checked = checked))
105
+
106
+ const response = await client.mutate({
107
+ mutation: gql`
108
+ mutation ($roleId: String!, $parentMenuId: String!, $isCheckedAll: Boolean!) {
109
+ updateRoleMenus(roleId: $roleId, parentMenuId: $parentMenuId, isCheckedAll: $isCheckedAll) {
110
+ name
111
+ }
112
+ }
113
+ `,
114
+ variables: { roleId: this.targetRole.id, parentMenuId: this.parentMenu.id, isCheckedAll: checked }
115
+ })
116
+
117
+ if (!response.errors) {
118
+ this.dispatchEvent(new CustomEvent('updateRoleMenus'))
119
+ this.showToast(i18next.t('text.data_updated_successfully'))
120
+ }
121
+ }
122
+
123
+ async onSave(e) {
124
+ const menuId = e.currentTarget.id
125
+ const isCheckedMenu = e.currentTarget.checked
126
+
127
+ const response = await client.mutate({
128
+ mutation: gql`
129
+ mutation ($roleId: String!, $targetMenuId: String!, $isCheckedMenu: Boolean!) {
130
+ updateRoleMenu(roleId: $roleId, targetMenuId: $targetMenuId, isCheckedMenu: $isCheckedMenu) {
131
+ id
132
+ name
133
+ }
134
+ }
135
+ `,
136
+ variables: { roleId: this.targetRole.id, targetMenuId: menuId, isCheckedMenu }
137
+ })
138
+
139
+ if (!response.errors) {
140
+ this.dispatchEvent(new CustomEvent('updateRoleMenus'))
141
+ this.showToast(i18next.t('text.data_updated_successfully'))
142
+ }
143
+ }
144
+
145
+ showToast(message) {
146
+ document.dispatchEvent(new CustomEvent('notify', { detail: { message, option: { timer: 1000 } } }))
147
+ }
148
+ }
149
+
150
+ customElements.define('child-menus-selector', ChildMenusSelector)
@@ -0,0 +1,179 @@
1
+ import { i18next, localize } from '@operato/i18n'
2
+ import { client } from '@operato/graphql'
3
+ import gql from 'graphql-tag'
4
+ import { css, html, LitElement } from 'lit'
5
+ import { isMobileDevice } from '@operato/utils'
6
+ import '@operato/data-grist'
7
+ import { CommonHeaderStyles } from '@operato/styles'
8
+
9
+ class RoleSelectPopup extends localize(i18next)(LitElement) {
10
+ static get styles() {
11
+ return [
12
+ CommonHeaderStyles,
13
+ css`
14
+ :host {
15
+ display: flex;
16
+ flex-direction: column;
17
+ overflow: hidden;
18
+ background-color: var(--md-sys-color-surface);
19
+ }
20
+
21
+ .container {
22
+ flex: 1;
23
+ display: flex;
24
+ overflow-y: auto;
25
+ min-height: 20vh;
26
+ }
27
+
28
+ .grist {
29
+ display: flex;
30
+ flex-direction: column;
31
+ flex: 1;
32
+ overflow-y: auto;
33
+ }
34
+
35
+ ox-grist {
36
+ overflow-y: hidden;
37
+ flex: 1;
38
+ }
39
+ `
40
+ ]
41
+ }
42
+
43
+ static get properties() {
44
+ return {
45
+ _searchFields: Array,
46
+ config: Object
47
+ }
48
+ }
49
+
50
+ render() {
51
+ return html`
52
+ <search-form .fields=${this._searchFields} @submit=${async () => this.dataGrist.fetch()}></search-form>
53
+
54
+ <div class="container">
55
+ <div class="grist">
56
+ <ox-grist
57
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
58
+ .config=${this.config}
59
+ .fetchHandler="${this.fetchHandler.bind(this)}"
60
+ ></ox-grist>
61
+ </div>
62
+ </div>
63
+
64
+ <div class="footer">
65
+ <div filler></div>
66
+ <button @click=${this._selectRole.bind(this)} label=${i18next.t('button.select')} done></button>
67
+ </div>
68
+ `
69
+ }
70
+
71
+ get searchForm() {
72
+ return this.shadowRoot.querySelector('search-form')
73
+ }
74
+
75
+ get dataGrist() {
76
+ return this.shadowRoot.querySelector('ox-grist')
77
+ }
78
+
79
+ firstUpdated() {
80
+ this._searchFields = [
81
+ {
82
+ name: 'name',
83
+ type: 'text',
84
+ props: {
85
+ placeholder: i18next.t('field.name'),
86
+ searchOper: 'i_like'
87
+ }
88
+ },
89
+ {
90
+ name: 'description',
91
+ type: 'text',
92
+ props: {
93
+ placeholder: i18next.t('field.description'),
94
+ searchOper: 'i_like'
95
+ }
96
+ }
97
+ ]
98
+
99
+ this.config = {
100
+ rows: {
101
+ appendable: false
102
+ },
103
+ columns: [
104
+ { type: 'gutter', gutterName: 'sequence' },
105
+ { type: 'gutter', gutterName: 'row-selector', multiple: false },
106
+ {
107
+ type: 'string',
108
+ name: 'name',
109
+ header: i18next.t('field.name'),
110
+ record: {
111
+ editable: false
112
+ },
113
+ width: 200
114
+ },
115
+ {
116
+ type: 'string',
117
+ name: 'description',
118
+ header: i18next.t('field.description'),
119
+ record: {
120
+ editable: true
121
+ },
122
+ width: 250
123
+ },
124
+ {
125
+ type: 'datetime',
126
+ name: 'updatedAt',
127
+ header: i18next.t('field.updated_at'),
128
+ width: 180
129
+ }
130
+ ]
131
+ }
132
+ }
133
+
134
+ async fetchHandler({ page, limit, sorters = [] }) {
135
+ const filters = this.searchForm?.queryFilters || []
136
+
137
+ const response = await client.query({
138
+ query: gql`
139
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
140
+ roles(filters: $filters, pagination: $pagination, sortings: $sortings) {
141
+ items {
142
+ id
143
+ name
144
+ description
145
+ updatedAt
146
+ }
147
+ total
148
+ }
149
+ }
150
+ `,
151
+ variables: {
152
+ filters,
153
+ pagination: { page, limit },
154
+ sortings: sorters
155
+ }
156
+ })
157
+
158
+ return {
159
+ total: response.data.roles.total || 0,
160
+ records: response.data.roles.items || []
161
+ }
162
+ }
163
+
164
+ _selectRole() {
165
+ const selectedRole = this.dataGrist.selected[0]
166
+ if (selectedRole) {
167
+ this.dispatchEvent(new CustomEvent('selected', { detail: this.dataGrist.selected[0] }))
168
+ history.back()
169
+ } else {
170
+ this.showToast(i18next.t('text.target_is_not_selected'))
171
+ }
172
+ }
173
+
174
+ showToast(message) {
175
+ document.dispatchEvent(new CustomEvent('notify', { detail: { message, option: { timer: 1000 } } }))
176
+ }
177
+ }
178
+
179
+ window.customElements.define('role-select-popup', RoleSelectPopup)
@@ -0,0 +1,200 @@
1
+ import '../viewparts/menu-bar'
2
+ import '../viewparts/menu-tile-list'
3
+
4
+ import gql from 'graphql-tag'
5
+ import { css, html } from 'lit'
6
+ import { connect } from 'pwa-helpers/connect-mixin.js'
7
+
8
+ import { client, navigate, PageView, store } from '@things-factory/shell'
9
+ import { ScrollbarStyles } from '@operato/styles'
10
+ import { pulltorefresh, swipe } from '@things-factory/utils'
11
+
12
+ class MenuListPage extends connect(store)(PageView) {
13
+ static get styles() {
14
+ return [
15
+ ScrollbarStyles,
16
+ css`
17
+ :host {
18
+ display: flex;
19
+ flex-direction: column;
20
+
21
+ overflow: hidden;
22
+ }
23
+
24
+ menu-bar {
25
+ z-index: 1;
26
+ }
27
+
28
+ menu-tile-list {
29
+ flex: 1;
30
+ overflow-y: auto;
31
+ }
32
+ `
33
+ ]
34
+ }
35
+
36
+ static get properties() {
37
+ return {
38
+ menuId: String,
39
+ menus: Array,
40
+ routingTypes: Object,
41
+ favorites: Array,
42
+ user: Object,
43
+ showSpinner: Boolean
44
+ }
45
+ }
46
+
47
+ render() {
48
+ return html`
49
+ <menu-bar .menus=${this.menus} .menuId=${this.menuId}></menu-bar>
50
+
51
+ <menu-tile-list
52
+ .menus=${this.menus}
53
+ .routingTypes=${this.routingTypes}
54
+ .menuId=${this.menuId}
55
+ .favorites=${this.favorites}
56
+ .showSpinner=${this.showSpinner}
57
+ ></menu-tile-list>
58
+ `
59
+ }
60
+
61
+ get context() {
62
+ return {
63
+ title: 'Menu'
64
+ }
65
+ }
66
+
67
+ async fetchMenus() {
68
+ const response = await client.query({
69
+ query: gql`
70
+ query {
71
+ userMenus {
72
+ id
73
+ name
74
+ role {
75
+ id
76
+ name
77
+ description
78
+ }
79
+ children {
80
+ id
81
+ name
82
+ routingType
83
+ idField
84
+ titleField
85
+ resourceName
86
+ resourceUrl
87
+ template
88
+ role {
89
+ id
90
+ name
91
+ description
92
+ }
93
+ }
94
+ }
95
+ }
96
+ `
97
+ })
98
+
99
+ return response.data.userMenus
100
+ }
101
+
102
+ async updated(changes) {
103
+ if (changes.has('user')) {
104
+ if (this.user && this.user.email) {
105
+ this.refresh()
106
+ }
107
+ }
108
+ }
109
+
110
+ stateChanged(state) {
111
+ this.page = state.route.page
112
+ this.routingTypes = state.menu.routingTypes
113
+ this.menuId = state.route.resourceId
114
+ this.favorites = state.favorite.favorites
115
+ this.user = state.auth.user
116
+
117
+ var provider = state.menu.provider
118
+ this.getMenus = typeof provider === 'function' ? provider.bind(this) : this.fetchMenus
119
+ }
120
+
121
+ async refresh() {
122
+ this.showSpinner = true
123
+ this.menus = await this.getMenus()
124
+ this.showSpinner = false
125
+ }
126
+
127
+ async firstUpdated() {
128
+ var list = this.shadowRoot.querySelector('menu-tile-list')
129
+
130
+ pulltorefresh({
131
+ container: this.shadowRoot,
132
+ scrollable: list,
133
+ refresh: () => {
134
+ return this.refresh()
135
+ }
136
+ })
137
+
138
+ swipe({
139
+ container: this.shadowRoot.querySelector('menu-tile-list'),
140
+ animates: {
141
+ dragging: async (d, opts) => {
142
+ var currentIndex = Number(this.menuId)
143
+ var isHome = this.menuId === '' || this.menuId === undefined
144
+
145
+ if ((d > 0 && isHome) || (d < 0 && currentIndex >= this.menus.length - 1)) {
146
+ /* TODO blocked gesture */
147
+ return false
148
+ }
149
+
150
+ list.style.transform = `translate3d(${d}px, 0, 0)`
151
+ },
152
+ aborting: async opts => {
153
+ list.style.transition = 'transform 0.3s'
154
+ list.style.transform = `translate3d(0, 0, 0)`
155
+
156
+ setTimeout(() => {
157
+ list.style.transition = ''
158
+ }, 300)
159
+ },
160
+ swiping: async (d, opts) => {
161
+ var currentIndex = Number(this.menuId)
162
+ var isHome = this.menuId === '' || this.menuId === undefined
163
+
164
+ if ((d > 0 && isHome) || (d < 0 && currentIndex >= this.menus.length - 1)) {
165
+ list.style.transform = `translate3d(0, 0, 0)`
166
+
167
+ return
168
+ }
169
+
170
+ list.style.transition = 'transform 0.3s'
171
+ list.style.transform = `translate3d(${d < 0 ? '-100%' : '100%'}, 0, 0)`
172
+
173
+ setTimeout(() => {
174
+ if (isHome) {
175
+ navigate(`${this.page}/0`)
176
+ } else if (d > 0 && currentIndex == 0) {
177
+ navigate(`${this.page}`)
178
+ } else {
179
+ navigate(`${this.page}/${currentIndex + (d < 0 ? 1 : -1)}`)
180
+ }
181
+
182
+ list.style.transition = ''
183
+ list.style.transform = `translate3d(${d < 0 ? '100%' : '-100%'}, 0, 0)`
184
+
185
+ requestAnimationFrame(() => {
186
+ list.style.transition = 'transform 0.3s'
187
+ list.style.transform = `translate3d(0, 0, 0)`
188
+ })
189
+ }, 300)
190
+ }
191
+ }
192
+ })
193
+
194
+ await this.updateComplete
195
+
196
+ this.refresh()
197
+ }
198
+ }
199
+
200
+ window.customElements.define('menu-list-page', MenuListPage)