cabloy 5.1.247 → 5.1.249
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.
- package/.cabloy-version +1 -1
- package/.vscode/settings.json +1 -2
- package/CHANGELOG.md +27 -0
- package/package.json +1 -7
- package/repo-docs/frontend/column-configuration-guide.md +3 -1
- package/repo-docs/frontend/table-guide.md +27 -2
- package/repo-e2e/specs/a-commerce.spec.ts +32 -0
- package/repo-e2e/specs/cabloy-basic.spec.ts +1236 -0
- package/vona/package.original.json +1 -7
- package/vona/pnpm-lock.yaml +139 -1011
- package/zova/package.original.json +0 -6
- package/zova/packages-cli/cli/package.json +2 -2
- package/zova/packages-cli/cli-set-front/package.json +2 -2
- package/zova/packages-utils/zova-vite/package.json +1 -1
- package/zova/packages-utils/zova-vite/src/teleports.ts +7 -0
- package/zova/packages-utils/zova-vite/test/teleports.test.ts +114 -0
- package/zova/packages-zova/zova/package.json +2 -2
- package/zova/pnpm-lock.yaml +6 -958
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/controller.tsx +267 -0
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/render.header.tsx +42 -10
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/render.locale.tsx +10 -5
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/render.tabs.tsx +97 -11
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/render.theme.tsx +19 -10
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/render.user.tsx +11 -0
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/style.ts +128 -0
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/config/locale/en-us.ts +6 -0
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/config/locale/zh-cn.ts +6 -0
- package/zova/src/suite/a-home/modules/home-layoutweb/src/.metadata/component/layoutWeb.ts +10 -8
- package/zova/src/suite/a-home/modules/home-layoutweb/src/.metadata/index.ts +25 -0
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/controller.tsx +83 -0
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.header.tsx +37 -8
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.locale.tsx +25 -8
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.tabs.tsx +3 -1
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.theme.tsx +10 -5
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.user.tsx +64 -21
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/style.ts +42 -0
- package/zova/src/suite/a-home/modules/home-layoutweb/src/config/locale/en-us.ts +4 -0
- package/zova/src/suite/a-home/modules/home-layoutweb/src/config/locale/zh-cn.ts +4 -0
- package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/rowOperations/controller.tsx +2 -1
- package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/table/controller.tsx +6 -10
- package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/table/render.tsx +9 -6
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssr.ts +17 -1
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssrProfile.ts +15 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/types/ssr.ts +1 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/test/lib/ssrProfile.test.ts +23 -1
- package/zova/src/suite-vendor/a-zova/modules/a-ssrserver/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-ssrserver/src/service/ssrHandler.ts +11 -11
- package/zova/src/suite-vendor/a-zova/package.json +3 -3
- package/vona/.textlintrc.json +0 -19
|
@@ -4,8 +4,136 @@ import { Style } from 'zova-module-a-bean';
|
|
|
4
4
|
@Style()
|
|
5
5
|
export class StyleLayoutAdmin extends BeanStyleBase {
|
|
6
6
|
cTab: string;
|
|
7
|
+
cHeaderActions: string;
|
|
8
|
+
cHeader: string;
|
|
9
|
+
cTabItems: string;
|
|
10
|
+
cTabItemsMenu: string;
|
|
7
11
|
|
|
8
12
|
protected async __init__() {
|
|
13
|
+
this.cHeader = this.$style({
|
|
14
|
+
$nest: {
|
|
15
|
+
'& .header-title': { minWidth: 0 },
|
|
16
|
+
'&:has(.tab-items) .header-title': {
|
|
17
|
+
flex: '0 1 auto',
|
|
18
|
+
maxWidth: '10rem',
|
|
19
|
+
overflow: 'hidden',
|
|
20
|
+
textOverflow: 'ellipsis',
|
|
21
|
+
whiteSpace: 'nowrap',
|
|
22
|
+
},
|
|
23
|
+
'&:has(.tab-items) .header-navigation': { marginInline: 0, paddingInline: 0 },
|
|
24
|
+
'@media (width < 600px)': {
|
|
25
|
+
$nest: { '&:has(.tab-items) .header-title': { display: 'none' } },
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
this.cTabItems = this.$style({
|
|
30
|
+
display: 'flex',
|
|
31
|
+
alignItems: 'center',
|
|
32
|
+
minWidth: 0,
|
|
33
|
+
height: '48px',
|
|
34
|
+
$nest: {
|
|
35
|
+
'& .tab-items-viewport': { position: 'relative', minWidth: 0, flex: '1 1 0' },
|
|
36
|
+
'& .tab-items-scroll': { overflowX: 'auto', scrollbarWidth: 'none' },
|
|
37
|
+
'& .tab-items-scroll::-webkit-scrollbar': { display: 'none' },
|
|
38
|
+
'& .tab-items-content': {
|
|
39
|
+
display: 'flex',
|
|
40
|
+
flexWrap: 'nowrap',
|
|
41
|
+
width: 'max-content',
|
|
42
|
+
minWidth: '100%',
|
|
43
|
+
},
|
|
44
|
+
'& .tab': { flexShrink: 0, height: '48px', gap: '4px' },
|
|
45
|
+
'& .tab > svg': { flexShrink: 0 },
|
|
46
|
+
'& .tab > div': { minWidth: 0 },
|
|
47
|
+
'& .tab .tab-close': { top: '2px', right: '2px' },
|
|
48
|
+
'& .tab-items-more': { flex: '0 0 40px', width: '40px', height: '40px', fontSize: '20px' },
|
|
49
|
+
'&.is-compact .tab-items-content': { width: '100%' },
|
|
50
|
+
'&.is-compact .tab': { minWidth: 0, maxWidth: '100%', paddingInline: '12px' },
|
|
51
|
+
'&.is-compact .tab-close': { display: 'none' },
|
|
52
|
+
'& .tab-items-viewport::before, & .tab-items-viewport::after': {
|
|
53
|
+
content: '""',
|
|
54
|
+
position: 'absolute',
|
|
55
|
+
top: 0,
|
|
56
|
+
bottom: 0,
|
|
57
|
+
width: '16px',
|
|
58
|
+
zIndex: 1,
|
|
59
|
+
pointerEvents: 'none',
|
|
60
|
+
opacity: 0,
|
|
61
|
+
},
|
|
62
|
+
'& .tab-items-viewport::before': {
|
|
63
|
+
left: 0,
|
|
64
|
+
background: 'linear-gradient(to right, var(--color-base-300), transparent)',
|
|
65
|
+
},
|
|
66
|
+
'& .tab-items-viewport::after': {
|
|
67
|
+
right: 0,
|
|
68
|
+
background: 'linear-gradient(to left, var(--color-base-300), transparent)',
|
|
69
|
+
},
|
|
70
|
+
'& .tab-items-viewport.has-start::before, & .tab-items-viewport.has-end::after': {
|
|
71
|
+
opacity: 1,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
this.cTabItemsMenu = this.$style({
|
|
76
|
+
display: 'none',
|
|
77
|
+
position: 'fixed',
|
|
78
|
+
inset: 'auto',
|
|
79
|
+
margin: 0,
|
|
80
|
+
width: '22rem',
|
|
81
|
+
maxWidth: 'calc(100vw - 16px)',
|
|
82
|
+
maxHeight: 'calc(100dvh - 16px)',
|
|
83
|
+
overflowY: 'auto',
|
|
84
|
+
$nest: {
|
|
85
|
+
'&:popover-open': { display: 'flex', flexDirection: 'column', gap: '4px' },
|
|
86
|
+
'& .tab-items-select': {
|
|
87
|
+
flex: '1 1 0',
|
|
88
|
+
minWidth: 0,
|
|
89
|
+
height: 'auto',
|
|
90
|
+
minHeight: '40px',
|
|
91
|
+
justifyContent: 'flex-start',
|
|
92
|
+
textTransform: 'none',
|
|
93
|
+
paddingBlock: '8px',
|
|
94
|
+
},
|
|
95
|
+
'& .tab-items-select svg': { flexShrink: 0 },
|
|
96
|
+
'& .tab-items-label': {
|
|
97
|
+
flex: '1 1 0',
|
|
98
|
+
minWidth: 0,
|
|
99
|
+
whiteSpace: 'normal',
|
|
100
|
+
overflowWrap: 'anywhere',
|
|
101
|
+
textAlign: 'start',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
this.cHeaderActions = this.$style({
|
|
106
|
+
$nest: {
|
|
107
|
+
'& .header-actions-panel > ul > li > details > ul': {
|
|
108
|
+
maxHeight: 'calc(100dvh - 5rem)',
|
|
109
|
+
overflowY: 'auto',
|
|
110
|
+
},
|
|
111
|
+
'@media (width < 64rem)': {
|
|
112
|
+
$nest: {
|
|
113
|
+
'& .header-actions-panel': {
|
|
114
|
+
width: '16rem',
|
|
115
|
+
maxWidth: 'calc(100vw - 1rem)',
|
|
116
|
+
maxHeight: 'calc(100dvh - 5rem)',
|
|
117
|
+
overflowY: 'auto',
|
|
118
|
+
},
|
|
119
|
+
'& .header-actions-panel > ul > li > details > ul': {
|
|
120
|
+
width: 'auto',
|
|
121
|
+
maxWidth: '100%',
|
|
122
|
+
whiteSpace: 'normal',
|
|
123
|
+
overflowWrap: 'anywhere',
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
'@media (min-width: 64rem)': {
|
|
128
|
+
$nest: {
|
|
129
|
+
'& .header-actions-panel > ul > li > details > ul': {
|
|
130
|
+
right: 0,
|
|
131
|
+
maxWidth: 'calc(100vw - 1rem)',
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
});
|
|
9
137
|
this.cTab = this.$style({
|
|
10
138
|
fontSize: '1.0rem',
|
|
11
139
|
$nest: {
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
'Home': 'Home',
|
|
3
|
+
'MoreActions': 'More actions',
|
|
4
|
+
'AllTabs': 'All tabs',
|
|
5
|
+
'CloseTab': 'Close tab: %s',
|
|
6
|
+
'Language': 'Language',
|
|
7
|
+
'ColorMode': 'Color mode',
|
|
8
|
+
'Theme': 'Theme',
|
|
3
9
|
'Logout': 'Logout',
|
|
4
10
|
'Account Settings': 'Account Settings',
|
|
5
11
|
'LanguageEnglish': 'English',
|
|
@@ -7,6 +7,7 @@ import type { ControllerLayoutWebProps } from '../../component/layoutWeb/control
|
|
|
7
7
|
|
|
8
8
|
import { ControllerLayoutWeb } from '../../component/layoutWeb/controller.tsx';
|
|
9
9
|
import { RenderLayoutWeb } from '../../component/layoutWeb/render.tsx';
|
|
10
|
+
import { StyleLayoutWeb } from '../../component/layoutWeb/style.ts';
|
|
10
11
|
export type ZLayoutWebProps = {
|
|
11
12
|
controllerRef?: (ref: ControllerLayoutWeb) => void;
|
|
12
13
|
} & ControllerLayoutWebProps;
|
|
@@ -21,16 +22,17 @@ declare module 'zova-module-home-layoutweb' {
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
declare module 'zova-module-home-layoutweb' {
|
|
24
|
-
export interface
|
|
25
|
-
export interface
|
|
26
|
-
export interface
|
|
27
|
-
export interface
|
|
28
|
-
export interface
|
|
29
|
-
export interface
|
|
30
|
-
export interface
|
|
25
|
+
export interface StyleLayoutWeb extends ControllerLayoutWeb {}
|
|
26
|
+
export interface RenderLayoutWeb extends StyleLayoutWeb {}
|
|
27
|
+
export interface RenderContent extends StyleLayoutWeb {}
|
|
28
|
+
export interface RenderHeader extends StyleLayoutWeb {}
|
|
29
|
+
export interface RenderLocale extends StyleLayoutWeb {}
|
|
30
|
+
export interface RenderTabs extends StyleLayoutWeb {}
|
|
31
|
+
export interface RenderTheme extends StyleLayoutWeb {}
|
|
32
|
+
export interface RenderUser extends StyleLayoutWeb {}
|
|
31
33
|
}
|
|
32
34
|
export const ZLayoutWeb = defineComponent((_props: ZLayoutWebProps) => {
|
|
33
|
-
useController(ControllerLayoutWeb, RenderLayoutWeb,
|
|
35
|
+
useController(ControllerLayoutWeb, RenderLayoutWeb, StyleLayoutWeb);
|
|
34
36
|
return () => {};
|
|
35
37
|
}, prepareComponentOptions());
|
|
36
38
|
declare module 'zova-module-a-bean' {
|
|
@@ -165,6 +165,31 @@ declare module 'zova' {
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
/** render: end */
|
|
168
|
+
/** style: begin */
|
|
169
|
+
export * from '../component/layoutWeb/style.ts';
|
|
170
|
+
|
|
171
|
+
import 'zova';
|
|
172
|
+
declare module 'zova' {
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
}
|
|
176
|
+
declare module 'zova-module-home-layoutweb' {
|
|
177
|
+
|
|
178
|
+
export interface StyleLayoutWeb {
|
|
179
|
+
/** @internal */
|
|
180
|
+
get scope(): ScopeModuleHomeLayoutweb;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/** style: end */
|
|
184
|
+
/** style: begin */
|
|
185
|
+
import type { StyleLayoutWeb } from '../component/layoutWeb/style.ts';
|
|
186
|
+
import 'zova';
|
|
187
|
+
declare module 'zova' {
|
|
188
|
+
export interface IBeanRecordLocal {
|
|
189
|
+
'home-layoutweb.style.layoutWeb': StyleLayoutWeb;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/** style: end */
|
|
168
193
|
/** config: begin */
|
|
169
194
|
export * from '../config/config.ts';
|
|
170
195
|
import { config } from '../config/config.ts';
|
|
@@ -39,14 +39,28 @@ export class ControllerLayoutWeb extends BeanControllerBase {
|
|
|
39
39
|
private viewportWidth: number = 0;
|
|
40
40
|
private _windowResizeHandler?: () => void;
|
|
41
41
|
|
|
42
|
+
headerActionsOpen = false;
|
|
43
|
+
headerActionsId = 'home-layoutweb-header-actions';
|
|
44
|
+
private _headerActionsElement?: HTMLDivElement;
|
|
45
|
+
private _headerOutsideHandler: (event: PointerEvent) => void;
|
|
46
|
+
private _headerClickHandler: (event: MouseEvent) => void;
|
|
47
|
+
|
|
42
48
|
protected async __init__() {
|
|
49
|
+
this._headerClickHandler = event => this.onHeaderActionsClick(event);
|
|
50
|
+
this._headerOutsideHandler = event => {
|
|
51
|
+
if (event.target instanceof Node && !this._headerActionsElement?.contains(event.target)) {
|
|
52
|
+
this.closeHeaderActions();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
43
55
|
// viewport
|
|
44
56
|
if (process.env.CLIENT) {
|
|
45
57
|
this._windowResizeHandler = () => {
|
|
46
58
|
this.viewportWidth = document.documentElement.clientWidth;
|
|
59
|
+
this.closeHeaderActions();
|
|
47
60
|
};
|
|
48
61
|
this._windowResizeHandler();
|
|
49
62
|
window.addEventListener('resize', this._windowResizeHandler);
|
|
63
|
+
document.addEventListener('pointerdown', this._headerOutsideHandler);
|
|
50
64
|
}
|
|
51
65
|
// belowBreakpoint
|
|
52
66
|
this.belowBreakpoint = this.$computed(() => {
|
|
@@ -78,8 +92,77 @@ export class ControllerLayoutWeb extends BeanControllerBase {
|
|
|
78
92
|
}
|
|
79
93
|
|
|
80
94
|
protected __dispose__() {
|
|
95
|
+
this.setHeaderActionsElement();
|
|
81
96
|
if (this._windowResizeHandler) {
|
|
82
97
|
window.removeEventListener('resize', this._windowResizeHandler);
|
|
98
|
+
document.removeEventListener('pointerdown', this._headerOutsideHandler);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
setHeaderActionsElement(element?: HTMLDivElement) {
|
|
103
|
+
if (element === this._headerActionsElement) return;
|
|
104
|
+
this._headerActionsElement?.removeEventListener('click', this._headerClickHandler, true);
|
|
105
|
+
this._headerActionsElement = element;
|
|
106
|
+
element?.addEventListener('click', this._headerClickHandler, true);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
toggleHeaderActions() {
|
|
110
|
+
if (this.headerActionsOpen) {
|
|
111
|
+
this.closeHeaderActions();
|
|
112
|
+
} else {
|
|
113
|
+
this.headerActionsOpen = true;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
closeHeaderActions(restoreFocus = false) {
|
|
118
|
+
this.headerActionsOpen = false;
|
|
119
|
+
this._headerActionsElement
|
|
120
|
+
?.querySelectorAll<HTMLDetailsElement>('details[open]')
|
|
121
|
+
.forEach(details => {
|
|
122
|
+
details.open = false;
|
|
123
|
+
});
|
|
124
|
+
if (restoreFocus) {
|
|
125
|
+
this._headerActionsElement?.querySelector<HTMLButtonElement>('button')?.focus();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
onHeaderActionsFocusout(event: FocusEvent) {
|
|
130
|
+
if (
|
|
131
|
+
this.headerActionsOpen &&
|
|
132
|
+
(!(event.relatedTarget instanceof Node) ||
|
|
133
|
+
!this._headerActionsElement?.contains(event.relatedTarget))
|
|
134
|
+
) {
|
|
135
|
+
this.closeHeaderActions();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
onHeaderActionsClick(event: MouseEvent) {
|
|
140
|
+
if (!this.headerActionsOpen || !(event.target instanceof Element)) return;
|
|
141
|
+
const action = event.target.closest('a, button');
|
|
142
|
+
if (action?.closest('details') && !action.matches(':disabled, [aria-disabled="true"]')) {
|
|
143
|
+
this.closeHeaderActions(true);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
onHeaderActionsKeydown(event: KeyboardEvent) {
|
|
148
|
+
if (
|
|
149
|
+
event.key !== 'Escape' ||
|
|
150
|
+
event.defaultPrevented ||
|
|
151
|
+
!(event.target instanceof Element) ||
|
|
152
|
+
event.target.closest('dialog[open], [role="dialog"]')
|
|
153
|
+
) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const details = event.target.closest<HTMLDetailsElement>('details[open]');
|
|
157
|
+
if (details) {
|
|
158
|
+
event.preventDefault();
|
|
159
|
+
event.stopPropagation();
|
|
160
|
+
details.open = false;
|
|
161
|
+
details.querySelector<HTMLElement>('summary')?.focus();
|
|
162
|
+
} else if (this.headerActionsOpen) {
|
|
163
|
+
event.preventDefault();
|
|
164
|
+
event.stopPropagation();
|
|
165
|
+
this.closeHeaderActions(true);
|
|
83
166
|
}
|
|
84
167
|
}
|
|
85
168
|
|
package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.header.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { classes } from 'typestyle';
|
|
1
2
|
import { BeanRenderBase, Use } from 'zova';
|
|
2
3
|
import { Render } from 'zova-module-a-bean';
|
|
3
4
|
import { ZIcon } from 'zova-module-a-icon';
|
|
@@ -12,7 +13,7 @@ export class RenderHeader extends BeanRenderBase {
|
|
|
12
13
|
public render() {
|
|
13
14
|
return (
|
|
14
15
|
<>
|
|
15
|
-
<div class="navbar bg-base-300 w-full">
|
|
16
|
+
<div class="navbar bg-base-300 w-full flex-wrap lg:flex-nowrap">
|
|
16
17
|
<div class="flex-none">
|
|
17
18
|
<button
|
|
18
19
|
class="btn btn-square btn-ghost"
|
|
@@ -24,13 +25,41 @@ export class RenderHeader extends BeanRenderBase {
|
|
|
24
25
|
</button>
|
|
25
26
|
</div>
|
|
26
27
|
<div class="text-xl px-4">{this.sys.env.APP_TITLE}</div>
|
|
27
|
-
<div class="mx-2 min-w-0
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
<div class="order-last mx-2 min-w-0 basis-full px-2 lg:order-none lg:basis-auto lg:flex-1">
|
|
29
|
+
{this.$$r.$$renderTabs.renderTabs()}
|
|
30
|
+
</div>
|
|
31
|
+
<div
|
|
32
|
+
ref={ref => this.setHeaderActionsElement?.((ref as HTMLDivElement | null) ?? undefined)}
|
|
33
|
+
class={classes('relative ml-auto flex-none lg:ml-0', this.cHeaderActions)}
|
|
34
|
+
data-testid="header-actions"
|
|
35
|
+
onFocusout={event => this.onHeaderActionsFocusout?.(event)}
|
|
36
|
+
onKeydown={event => this.onHeaderActionsKeydown(event)}
|
|
37
|
+
>
|
|
38
|
+
<button
|
|
39
|
+
type="button"
|
|
40
|
+
class="btn btn-square btn-ghost lg:hidden"
|
|
41
|
+
aria-label={this.scope.locale.MoreActions()}
|
|
42
|
+
title={this.scope.locale.MoreActions()}
|
|
43
|
+
aria-expanded={this.headerActionsOpen}
|
|
44
|
+
aria-controls={this.headerActionsId}
|
|
45
|
+
onClick={() => this.toggleHeaderActions()}
|
|
46
|
+
>
|
|
47
|
+
<ZIcon name="::more-horiz" width={24} aria-hidden="true" />
|
|
48
|
+
</button>
|
|
49
|
+
<div
|
|
50
|
+
id={this.headerActionsId}
|
|
51
|
+
class={classes(
|
|
52
|
+
'header-actions-panel absolute right-0 top-full z-30 rounded-box bg-base-100 shadow-lg lg:static lg:bg-transparent lg:shadow-none',
|
|
53
|
+
this.headerActionsOpen ? 'block' : 'hidden',
|
|
54
|
+
'lg:block',
|
|
55
|
+
)}
|
|
56
|
+
>
|
|
57
|
+
<ul class="menu w-full lg:w-auto lg:menu-horizontal">
|
|
58
|
+
{this.$$r.$$renderLocale.render()}
|
|
59
|
+
{this.$$r.$$renderTheme.renderThemeDark()}
|
|
60
|
+
{this.$$r.$$renderUser.render()}
|
|
61
|
+
</ul>
|
|
62
|
+
</div>
|
|
34
63
|
</div>
|
|
35
64
|
</div>
|
|
36
65
|
</>
|
package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.locale.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BeanRenderBase, ClientOnly } from 'zova';
|
|
2
2
|
import { Render } from 'zova-module-a-bean';
|
|
3
3
|
import { $icon } from 'zova-module-a-icon';
|
|
4
|
+
import { ZButton } from 'zova-module-basic-button';
|
|
4
5
|
import { closeNearestDetails } from 'zova-module-home-base';
|
|
5
6
|
|
|
6
7
|
@Render()
|
|
@@ -12,29 +13,45 @@ export class RenderLocale extends BeanRenderBase {
|
|
|
12
13
|
return (
|
|
13
14
|
<li>
|
|
14
15
|
<details>
|
|
15
|
-
<summary
|
|
16
|
+
<summary aria-label={this.scope.locale.Language()} title={this.scope.locale.Language()}>
|
|
17
|
+
{$icon('::language', 24)}
|
|
18
|
+
<span class="lg:hidden">{this.scope.locale.Language()}</span>
|
|
19
|
+
</summary>
|
|
16
20
|
<ClientOnly>
|
|
17
21
|
<ul class="bg-base-100 rounded-t-none p-2 w-48">
|
|
18
22
|
{Object.keys(locales).map(key => {
|
|
19
23
|
const title = this.$scopeBase.locale[locales[key]]();
|
|
20
24
|
return (
|
|
21
25
|
<li key={key} class={this.app.meta.locale.current === key ? 'disabled' : ''}>
|
|
22
|
-
<
|
|
23
|
-
|
|
26
|
+
<ZButton
|
|
27
|
+
disabled={this.app.meta.locale.current === key}
|
|
28
|
+
onPerform={async event => {
|
|
29
|
+
closeNearestDetails({ currentTarget: event.target });
|
|
24
30
|
if (metaLocale) {
|
|
25
|
-
|
|
26
|
-
params: {
|
|
31
|
+
const options = {
|
|
32
|
+
params: {
|
|
33
|
+
...currentRoute.params,
|
|
34
|
+
locale: key === this.sys.config.locale.default ? '' : key,
|
|
35
|
+
},
|
|
27
36
|
query: currentRoute.query,
|
|
28
|
-
}
|
|
37
|
+
};
|
|
38
|
+
const name = this.$router.getRealRouteName(currentRoute.name);
|
|
39
|
+
const alias =
|
|
40
|
+
name && this.$router.getAliasPath(name as never, options as never);
|
|
41
|
+
// A root alias with only a query must not resolve against the current path.
|
|
42
|
+
const target = alias?.startsWith('?') ? `/${alias}` : alias;
|
|
43
|
+
await this.app.$gotoPage(
|
|
44
|
+
target || currentRoute.matched[0].path,
|
|
45
|
+
target ? undefined : options,
|
|
46
|
+
);
|
|
29
47
|
} else {
|
|
30
48
|
this.app.meta.locale.current = key as any;
|
|
31
49
|
}
|
|
32
|
-
closeNearestDetails(event);
|
|
33
50
|
}}
|
|
34
51
|
>
|
|
35
52
|
{$icon(this.app.meta.locale.current === key ? '::done' : '::none', 24)}
|
|
36
53
|
{title}
|
|
37
|
-
</
|
|
54
|
+
</ZButton>
|
|
38
55
|
</li>
|
|
39
56
|
);
|
|
40
57
|
})}
|
package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.tabs.tsx
CHANGED
|
@@ -20,7 +20,9 @@ export class RenderTabs extends BeanRenderBase {
|
|
|
20
20
|
return this._renderMenuItem(tab.info as TypeMenuItem, true, tab.tabKey);
|
|
21
21
|
});
|
|
22
22
|
const domWrapper = (
|
|
23
|
-
<ul class="menu menu-horizontal w-
|
|
23
|
+
<ul class="menu menu-horizontal w-full flex-wrap gap-1 px-0 lg:w-max lg:min-w-full lg:flex-nowrap">
|
|
24
|
+
{domTabs}
|
|
25
|
+
</ul>
|
|
24
26
|
);
|
|
25
27
|
if (!$$modelTabs.cache) return domWrapper;
|
|
26
28
|
return <ClientOnly>{domWrapper}</ClientOnly>;
|
package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.theme.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import type { IThemeRecord } from 'zova-module-a-style';
|
|
|
3
3
|
import { BeanRenderBase, ClientOnly } from 'zova';
|
|
4
4
|
import { Render } from 'zova-module-a-bean';
|
|
5
5
|
import { $icon } from 'zova-module-a-icon';
|
|
6
|
+
import { ZButton } from 'zova-module-basic-button';
|
|
6
7
|
import { closeNearestDetails } from 'zova-module-home-base';
|
|
7
8
|
|
|
8
9
|
@Render()
|
|
@@ -25,7 +26,10 @@ export class RenderTheme extends BeanRenderBase {
|
|
|
25
26
|
return (
|
|
26
27
|
<li>
|
|
27
28
|
<details>
|
|
28
|
-
<summary
|
|
29
|
+
<summary aria-label={this.scope.locale.ColorMode()} title={this.scope.locale.ColorMode()}>
|
|
30
|
+
{$icon('::dark-theme', 24)}
|
|
31
|
+
<span class="lg:hidden">{this.scope.locale.ColorMode()}</span>
|
|
32
|
+
</summary>
|
|
29
33
|
<ClientOnly>
|
|
30
34
|
<ul class="bg-base-100 rounded-t-none p-2 w-48">
|
|
31
35
|
{themes.map(item => {
|
|
@@ -34,15 +38,16 @@ export class RenderTheme extends BeanRenderBase {
|
|
|
34
38
|
key={item.mode.toString()}
|
|
35
39
|
class={this.$theme.darkMode === item.mode ? 'disabled' : ''}
|
|
36
40
|
>
|
|
37
|
-
<
|
|
38
|
-
|
|
41
|
+
<ZButton
|
|
42
|
+
disabled={this.$theme.darkMode === item.mode}
|
|
43
|
+
onPerform={event => {
|
|
39
44
|
this.$theme.darkMode = item.mode as any;
|
|
40
|
-
closeNearestDetails(event);
|
|
45
|
+
closeNearestDetails({ currentTarget: event.target });
|
|
41
46
|
}}
|
|
42
47
|
>
|
|
43
48
|
{$icon(this.$theme.darkMode === item.mode ? '::done' : '::none', 24)}
|
|
44
49
|
{item.title}
|
|
45
|
-
</
|
|
50
|
+
</ZButton>
|
|
46
51
|
</li>
|
|
47
52
|
);
|
|
48
53
|
})}
|
package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.user.tsx
CHANGED
|
@@ -8,30 +8,62 @@ import { closeNearestDetails } from 'zova-module-home-base';
|
|
|
8
8
|
export class RenderUser extends BeanRenderBase {
|
|
9
9
|
public render() {
|
|
10
10
|
return (
|
|
11
|
-
<
|
|
12
|
-
<
|
|
13
|
-
<
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this.$
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
<li class="min-w-0">
|
|
12
|
+
<details>
|
|
13
|
+
<summary aria-label={this.scope.locale.Account()} title={this.scope.locale.Account()}>
|
|
14
|
+
<ClientOnly
|
|
15
|
+
v-slots={{
|
|
16
|
+
placeholder: () => (
|
|
17
|
+
<img
|
|
18
|
+
class="h-6 w-6 shrink-0 rounded-full object-cover"
|
|
19
|
+
alt=""
|
|
20
|
+
src={this.$scopeBase.config.avatar.empty}
|
|
21
|
+
/>
|
|
22
|
+
),
|
|
23
|
+
default: () => (
|
|
24
|
+
<img
|
|
25
|
+
class="h-6 w-6 shrink-0 rounded-full object-cover"
|
|
26
|
+
alt=""
|
|
27
|
+
src={
|
|
28
|
+
resolveImagePreviewUrl(
|
|
29
|
+
this.$passport.user?.avatar,
|
|
30
|
+
this.sys.config.api.baseURL,
|
|
31
|
+
) || this.$scopeBase.config.avatar.empty
|
|
32
|
+
}
|
|
33
|
+
/>
|
|
34
|
+
),
|
|
35
|
+
}}
|
|
36
|
+
/>
|
|
37
|
+
<span class="h-lh min-w-0 flex-1 truncate lg:w-32 lg:flex-none">
|
|
38
|
+
<ClientOnly
|
|
39
|
+
v-slots={{
|
|
40
|
+
placeholder: () => '',
|
|
41
|
+
default: () =>
|
|
42
|
+
this.$passport.isAuthenticated
|
|
43
|
+
? this.$passport.displayName
|
|
44
|
+
: this.scope.locale.NotLoggedIn(),
|
|
45
|
+
}}
|
|
24
46
|
/>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
</summary>
|
|
47
|
+
</span>
|
|
48
|
+
</summary>
|
|
49
|
+
<ClientOnly>
|
|
29
50
|
<ul class="bg-base-100 rounded-t-none p-2 w-40">
|
|
30
51
|
{this.$passport.isAuthenticated ? (
|
|
31
52
|
<>
|
|
32
53
|
<li>
|
|
33
54
|
<a
|
|
55
|
+
href={this.$router.getPagePath('/home/user/account')}
|
|
34
56
|
onClick={event => {
|
|
57
|
+
if (
|
|
58
|
+
event.button !== 0 ||
|
|
59
|
+
event.metaKey ||
|
|
60
|
+
event.ctrlKey ||
|
|
61
|
+
event.shiftKey ||
|
|
62
|
+
event.altKey
|
|
63
|
+
) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
event.preventDefault();
|
|
35
67
|
this.app.$gotoPage('/home/user/account');
|
|
36
68
|
closeNearestDetails(event);
|
|
37
69
|
}}
|
|
@@ -42,7 +74,7 @@ export class RenderUser extends BeanRenderBase {
|
|
|
42
74
|
<li>
|
|
43
75
|
<ZButton
|
|
44
76
|
onPerform={async event => {
|
|
45
|
-
closeNearestDetails(event);
|
|
77
|
+
closeNearestDetails({ currentTarget: event.target });
|
|
46
78
|
await this.$passport.logout().mutateAsync();
|
|
47
79
|
}}
|
|
48
80
|
>
|
|
@@ -53,7 +85,18 @@ export class RenderUser extends BeanRenderBase {
|
|
|
53
85
|
) : (
|
|
54
86
|
<li>
|
|
55
87
|
<a
|
|
88
|
+
href={this.app.$getPagePathLogin(true)}
|
|
56
89
|
onClick={event => {
|
|
90
|
+
if (
|
|
91
|
+
event.button !== 0 ||
|
|
92
|
+
event.metaKey ||
|
|
93
|
+
event.ctrlKey ||
|
|
94
|
+
event.shiftKey ||
|
|
95
|
+
event.altKey
|
|
96
|
+
) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
event.preventDefault();
|
|
57
100
|
this.app.$gotoLogin(true);
|
|
58
101
|
closeNearestDetails(event);
|
|
59
102
|
}}
|
|
@@ -63,9 +106,9 @@ export class RenderUser extends BeanRenderBase {
|
|
|
63
106
|
</li>
|
|
64
107
|
)}
|
|
65
108
|
</ul>
|
|
66
|
-
</
|
|
67
|
-
</
|
|
68
|
-
</
|
|
109
|
+
</ClientOnly>
|
|
110
|
+
</details>
|
|
111
|
+
</li>
|
|
69
112
|
);
|
|
70
113
|
}
|
|
71
114
|
}
|