lupine.components 1.1.13 → 1.1.15
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/README.md +3 -3
- package/package.json +42 -42
- package/src/components/action-sheet.tsx +419 -419
- package/src/components/button-push-animation.tsx +147 -138
- package/src/components/button.tsx +55 -55
- package/src/components/desktop-footer.tsx +17 -17
- package/src/components/desktop-header.tsx +52 -52
- package/src/components/drag-refresh.tsx +129 -129
- package/src/components/editable-label.tsx +83 -83
- package/src/components/float-window.tsx +233 -233
- package/src/components/grid.tsx +18 -18
- package/src/components/html-load.tsx +41 -41
- package/src/components/html-var.tsx +81 -81
- package/src/components/index.ts +43 -44
- package/src/components/input-with-title.tsx +24 -24
- package/src/components/link-item.tsx +13 -13
- package/src/components/link-list.tsx +62 -62
- package/src/components/menu-bar.tsx +219 -219
- package/src/components/menu-item-props.tsx +13 -13
- package/src/components/menu-sidebar.tsx +325 -318
- package/src/components/message-box.tsx +44 -44
- package/src/components/meta-data.tsx +36 -36
- package/src/components/meta-description.tsx +12 -12
- package/src/components/mobile-components/icon-menu-item-props.ts +6 -6
- package/src/components/mobile-components/index.ts +8 -9
- package/src/components/mobile-components/mobile-footer-menu.tsx +95 -95
- package/src/components/mobile-components/mobile-header-component.tsx +101 -101
- package/src/components/mobile-components/mobile-header-title-icon.tsx +109 -101
- package/src/components/mobile-components/mobile-header-with-back.tsx +127 -117
- package/src/components/mobile-components/mobile-side-menu.tsx +154 -154
- package/src/components/mobile-components/mobile-top-sys-icon.tsx +18 -18
- package/src/components/mobile-components/mobile-top-sys-menu.tsx +62 -62
- package/src/components/modal.tsx +33 -33
- package/src/components/notice-message.tsx +118 -118
- package/src/components/page-title.tsx +6 -6
- package/src/components/paging-link.tsx +175 -175
- package/src/components/panel.tsx +21 -21
- package/src/components/popup-menu.tsx +289 -289
- package/src/components/progress.tsx +91 -91
- package/src/components/radio-label-component.tsx +36 -36
- package/src/components/redirect.tsx +19 -19
- package/src/components/resizable-splitter.tsx +128 -128
- package/src/components/select-angle-component.tsx +127 -127
- package/src/components/select-with-title.tsx +37 -37
- package/src/components/slide-tab-component.tsx +144 -149
- package/src/components/spinner.tsx +106 -100
- package/src/components/stars-component.tsx +66 -66
- package/src/components/svg.tsx +24 -24
- package/src/components/tabs.tsx +279 -279
- package/src/components/text-glow.tsx +37 -37
- package/src/components/text-scale.tsx +42 -42
- package/src/components/text-wave.tsx +55 -55
- package/src/components/theme-selector.tsx +28 -28
- package/src/components/toggle-base.tsx +285 -269
- package/src/components/toggle-switch.tsx +160 -160
- package/src/frames/index.ts +3 -3
- package/src/frames/responsive-frame.tsx +83 -83
- package/src/frames/slider-frame.tsx +111 -111
- package/src/frames/top-frame.tsx +30 -30
- package/src/index.ts +5 -5
- package/src/lib/back-action-helper.ts +54 -54
- package/src/lib/base62.ts +23 -23
- package/src/lib/blob-utils.ts +23 -23
- package/src/lib/calculate-text-width.ts +13 -13
- package/src/lib/date-utils.ts +317 -317
- package/src/lib/deep-merge.ts +37 -37
- package/src/lib/document-ready.ts +34 -34
- package/src/lib/dom-utils.ts +32 -32
- package/src/lib/download-file.ts +118 -118
- package/src/lib/download-link.ts +12 -12
- package/src/lib/download-stream.ts +19 -19
- package/src/lib/drag-util.ts +118 -118
- package/src/lib/dynamical-load.ts +134 -134
- package/src/lib/encode-html.ts +27 -27
- package/src/lib/find-parent-tag.ts +8 -8
- package/src/lib/format-bytes.ts +11 -11
- package/src/lib/index.ts +24 -24
- package/src/lib/lite-dom.ts +225 -225
- package/src/lib/message-hub.ts +103 -104
- package/src/lib/observable.ts +188 -188
- package/src/lib/path-utils.ts +42 -42
- package/src/lib/promise-timeout.ts +1 -1
- package/src/lib/simple-storage.ts +40 -40
- package/src/lib/stop-propagation.ts +7 -7
- package/src/lib/upload-file.ts +101 -101
- package/src/styles/base-themes.ts +17 -17
- package/src/styles/dark-themes.ts +99 -99
- package/src/styles/index.ts +5 -5
- package/src/styles/light-themes.ts +106 -106
- package/src/styles/media-query.ts +93 -93
- package/src/styles/shared-themes.ts +57 -57
- package/tsconfig.json +113 -113
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import { FloatWindow, FloatWindowCloseProps, FloatWindowShowProps } from './float-window';
|
|
2
|
-
|
|
3
|
-
export enum MessageBoxButtonProps {
|
|
4
|
-
YesNo = 'yesno',
|
|
5
|
-
OkCancel = 'okcancel',
|
|
6
|
-
Ok = 'ok',
|
|
7
|
-
}
|
|
8
|
-
export type MessageBoxProps = FloatWindowShowProps & {
|
|
9
|
-
buttonType: MessageBoxButtonProps;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export class MessageBox {
|
|
13
|
-
static async show({
|
|
14
|
-
title,
|
|
15
|
-
children,
|
|
16
|
-
contentMaxHeight,
|
|
17
|
-
contentMinWidth,
|
|
18
|
-
buttonType = MessageBoxButtonProps.OkCancel,
|
|
19
|
-
noMoving = false,
|
|
20
|
-
noModal = false,
|
|
21
|
-
closeEvent,
|
|
22
|
-
handleClicked,
|
|
23
|
-
closeWhenClickOutside = false,
|
|
24
|
-
}: MessageBoxProps): Promise<FloatWindowCloseProps> {
|
|
25
|
-
const buttons =
|
|
26
|
-
buttonType === MessageBoxButtonProps.OkCancel
|
|
27
|
-
? ['OK', 'Cancel']
|
|
28
|
-
: buttonType === MessageBoxButtonProps.YesNo
|
|
29
|
-
? ['Yes', 'No']
|
|
30
|
-
: ['OK'];
|
|
31
|
-
return FloatWindow.show({
|
|
32
|
-
title,
|
|
33
|
-
children,
|
|
34
|
-
contentMaxHeight,
|
|
35
|
-
contentMinWidth,
|
|
36
|
-
buttons,
|
|
37
|
-
noMoving,
|
|
38
|
-
noModal,
|
|
39
|
-
closeEvent,
|
|
40
|
-
handleClicked,
|
|
41
|
-
closeWhenClickOutside,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
}
|
|
1
|
+
import { FloatWindow, FloatWindowCloseProps, FloatWindowShowProps } from './float-window';
|
|
2
|
+
|
|
3
|
+
export enum MessageBoxButtonProps {
|
|
4
|
+
YesNo = 'yesno',
|
|
5
|
+
OkCancel = 'okcancel',
|
|
6
|
+
Ok = 'ok',
|
|
7
|
+
}
|
|
8
|
+
export type MessageBoxProps = FloatWindowShowProps & {
|
|
9
|
+
buttonType: MessageBoxButtonProps;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export class MessageBox {
|
|
13
|
+
static async show({
|
|
14
|
+
title,
|
|
15
|
+
children,
|
|
16
|
+
contentMaxHeight,
|
|
17
|
+
contentMinWidth,
|
|
18
|
+
buttonType = MessageBoxButtonProps.OkCancel,
|
|
19
|
+
noMoving = false,
|
|
20
|
+
noModal = false,
|
|
21
|
+
closeEvent,
|
|
22
|
+
handleClicked,
|
|
23
|
+
closeWhenClickOutside = false,
|
|
24
|
+
}: MessageBoxProps): Promise<FloatWindowCloseProps> {
|
|
25
|
+
const buttons =
|
|
26
|
+
buttonType === MessageBoxButtonProps.OkCancel
|
|
27
|
+
? ['OK', 'Cancel']
|
|
28
|
+
: buttonType === MessageBoxButtonProps.YesNo
|
|
29
|
+
? ['Yes', 'No']
|
|
30
|
+
: ['OK'];
|
|
31
|
+
return FloatWindow.show({
|
|
32
|
+
title,
|
|
33
|
+
children,
|
|
34
|
+
contentMaxHeight,
|
|
35
|
+
contentMinWidth,
|
|
36
|
+
buttons,
|
|
37
|
+
noMoving,
|
|
38
|
+
noModal,
|
|
39
|
+
closeEvent,
|
|
40
|
+
handleClicked,
|
|
41
|
+
closeWhenClickOutside,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
// import { bindPageResetEvent } from '../core/page-reset-events';
|
|
2
|
-
import { addMetaDataTags } from 'lupine.web';
|
|
3
|
-
type NameMeta = { name: string; content: string };
|
|
4
|
-
type PropertyMeta = { property: string; content: string };
|
|
5
|
-
type HttpEquivMeta = { httpEquiv: string; content: string };
|
|
6
|
-
type AllMeta = NameMeta | PropertyMeta | HttpEquivMeta;
|
|
7
|
-
|
|
8
|
-
function isNameMeta(data: any): data is NameMeta {
|
|
9
|
-
return !!(data.name && data.content);
|
|
10
|
-
}
|
|
11
|
-
function isPropertyMeta(data: any): data is PropertyMeta {
|
|
12
|
-
return !!(data.property && data.content);
|
|
13
|
-
}
|
|
14
|
-
function isHttpEquivMeta(data: any): data is HttpEquivMeta {
|
|
15
|
-
return !!(data.httpEquiv && data.content);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// should use description tag instead of meta tag ( <meta name="description" content="..."> )
|
|
19
|
-
export const MetaData = (data: AllMeta) => {
|
|
20
|
-
if (isNameMeta(data)) {
|
|
21
|
-
addMetaDataTags(`name:${data.name}`, `<meta name="${data.name}" content="${data.content}">`);
|
|
22
|
-
} else if (isPropertyMeta(data)) {
|
|
23
|
-
addMetaDataTags(`property:${data.property}`, `<meta property="${data.property}" content="${data.content}">`);
|
|
24
|
-
} else if (isHttpEquivMeta(data)) {
|
|
25
|
-
addMetaDataTags(`http-equiv:${data.httpEquiv}`, `<meta http-equiv="${data.httpEquiv}" content="${data.content}">`);
|
|
26
|
-
} else if ((data as any).key && (data as any).string) {
|
|
27
|
-
addMetaDataTags(`${(data as any).key}`, `${(data as any).string}`);
|
|
28
|
-
} else {
|
|
29
|
-
console.warn('Unknown meta data:', data);
|
|
30
|
-
}
|
|
31
|
-
return <></>;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// bindPageResetEvent(() => {
|
|
35
|
-
// _metaData = {};
|
|
36
|
-
// });
|
|
1
|
+
// import { bindPageResetEvent } from '../core/page-reset-events';
|
|
2
|
+
import { addMetaDataTags } from 'lupine.web';
|
|
3
|
+
type NameMeta = { name: string; content: string };
|
|
4
|
+
type PropertyMeta = { property: string; content: string };
|
|
5
|
+
type HttpEquivMeta = { httpEquiv: string; content: string };
|
|
6
|
+
type AllMeta = NameMeta | PropertyMeta | HttpEquivMeta;
|
|
7
|
+
|
|
8
|
+
function isNameMeta(data: any): data is NameMeta {
|
|
9
|
+
return !!(data.name && data.content);
|
|
10
|
+
}
|
|
11
|
+
function isPropertyMeta(data: any): data is PropertyMeta {
|
|
12
|
+
return !!(data.property && data.content);
|
|
13
|
+
}
|
|
14
|
+
function isHttpEquivMeta(data: any): data is HttpEquivMeta {
|
|
15
|
+
return !!(data.httpEquiv && data.content);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// should use description tag instead of meta tag ( <meta name="description" content="..."> )
|
|
19
|
+
export const MetaData = (data: AllMeta) => {
|
|
20
|
+
if (isNameMeta(data)) {
|
|
21
|
+
addMetaDataTags(`name:${data.name}`, `<meta name="${data.name}" content="${data.content}">`);
|
|
22
|
+
} else if (isPropertyMeta(data)) {
|
|
23
|
+
addMetaDataTags(`property:${data.property}`, `<meta property="${data.property}" content="${data.content}">`);
|
|
24
|
+
} else if (isHttpEquivMeta(data)) {
|
|
25
|
+
addMetaDataTags(`http-equiv:${data.httpEquiv}`, `<meta http-equiv="${data.httpEquiv}" content="${data.content}">`);
|
|
26
|
+
} else if ((data as any).key && (data as any).string) {
|
|
27
|
+
addMetaDataTags(`${(data as any).key}`, `${(data as any).string}`);
|
|
28
|
+
} else {
|
|
29
|
+
console.warn('Unknown meta data:', data);
|
|
30
|
+
}
|
|
31
|
+
return <></>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// bindPageResetEvent(() => {
|
|
35
|
+
// _metaData = {};
|
|
36
|
+
// });
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// import { bindPageResetEvent } from '../core/page-reset-events';
|
|
2
|
-
|
|
3
|
-
import { addMetaDataTags } from
|
|
4
|
-
|
|
5
|
-
export const MetaDescription = ({ children }: { children: string }) => {
|
|
6
|
-
addMetaDataTags('name:description', `<meta name="description" content="${children}">`);
|
|
7
|
-
return <></>;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
// bindPageResetEvent(() => {
|
|
11
|
-
// _description.value = '';
|
|
12
|
-
// });
|
|
1
|
+
// import { bindPageResetEvent } from '../core/page-reset-events';
|
|
2
|
+
|
|
3
|
+
import { addMetaDataTags } from 'lupine.web';
|
|
4
|
+
|
|
5
|
+
export const MetaDescription = ({ children }: { children: string }) => {
|
|
6
|
+
addMetaDataTags('name:description', `<meta name="description" content="${children}">`);
|
|
7
|
+
return <></>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// bindPageResetEvent(() => {
|
|
11
|
+
// _description.value = '';
|
|
12
|
+
// });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export interface IconMenuItemProps {
|
|
2
|
-
icon: string;
|
|
3
|
-
href: string;
|
|
4
|
-
text: string;
|
|
5
|
-
topout?: boolean; // Topout for mobile bottom icon menu
|
|
6
|
-
}
|
|
1
|
+
export interface IconMenuItemProps {
|
|
2
|
+
icon: string;
|
|
3
|
+
href: string;
|
|
4
|
+
text: string;
|
|
5
|
+
topout?: boolean; // Topout for mobile bottom icon menu
|
|
6
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
export * from './icon-menu-item-props';
|
|
2
|
-
export * from './mobile-footer-menu';
|
|
3
|
-
export * from './mobile-header-with-back';
|
|
4
|
-
export * from './mobile-header-component';
|
|
5
|
-
export * from './mobile-header-title-icon';
|
|
6
|
-
export * from './mobile-side-menu';
|
|
7
|
-
export * from './mobile-top-sys-icon';
|
|
8
|
-
export * from './mobile-top-sys-menu';
|
|
9
|
-
|
|
1
|
+
export * from './icon-menu-item-props';
|
|
2
|
+
export * from './mobile-footer-menu';
|
|
3
|
+
export * from './mobile-header-with-back';
|
|
4
|
+
export * from './mobile-header-component';
|
|
5
|
+
export * from './mobile-header-title-icon';
|
|
6
|
+
export * from './mobile-side-menu';
|
|
7
|
+
export * from './mobile-top-sys-icon';
|
|
8
|
+
export * from './mobile-top-sys-menu';
|
|
@@ -1,95 +1,95 @@
|
|
|
1
|
-
import { CssProps, MediaQueryRange } from 'lupine.components';
|
|
2
|
-
import { IconMenuItemProps } from './icon-menu-item-props';
|
|
3
|
-
|
|
4
|
-
export interface MobileFooterMenuProps {
|
|
5
|
-
items: IconMenuItemProps[];
|
|
6
|
-
color?: string;
|
|
7
|
-
activeColor?: string;
|
|
8
|
-
topoutColor?: string;
|
|
9
|
-
topoutBackgroundColor?: string;
|
|
10
|
-
}
|
|
11
|
-
export const MobileFooterMenu = (props: MobileFooterMenuProps) => {
|
|
12
|
-
const css: CssProps = {
|
|
13
|
-
'.footer-menu': {
|
|
14
|
-
display: 'none',
|
|
15
|
-
// position: 'fixed',
|
|
16
|
-
// left: 0,
|
|
17
|
-
// right: 0,
|
|
18
|
-
// bottom: 0,
|
|
19
|
-
width: '100%',
|
|
20
|
-
background: 'var(--sidebar-bg-color)',
|
|
21
|
-
paddingBottom: 'env(safe-area-inset-bottom)',
|
|
22
|
-
minHeight: '50px',
|
|
23
|
-
justifyContent: 'space-around',
|
|
24
|
-
alignItems: 'center',
|
|
25
|
-
borderTop: 'var(--primary-border)',
|
|
26
|
-
},
|
|
27
|
-
'.footer-menu, .footer-menu a': {
|
|
28
|
-
textDecoration: 'none',
|
|
29
|
-
color: props.color || 'var(--primary-color)',
|
|
30
|
-
},
|
|
31
|
-
'.footer-menu .footer-menu-item': {
|
|
32
|
-
padding: '4px 16px 4px 16px',
|
|
33
|
-
fontSize: '11px',
|
|
34
|
-
height: '55px', // 和主页保留的底部菜单高度一致
|
|
35
|
-
width: '55px',
|
|
36
|
-
display: 'flex',
|
|
37
|
-
flexWrap: 'wrap',
|
|
38
|
-
alignItems: 'center',
|
|
39
|
-
},
|
|
40
|
-
'.footer-menu .footer-menu-item i': {
|
|
41
|
-
display: 'block',
|
|
42
|
-
fontSize: '22px',
|
|
43
|
-
marginBottom: '4px',
|
|
44
|
-
},
|
|
45
|
-
'.footer-menu .footer-menu-item.footer-menu-topout': {
|
|
46
|
-
marginTop: '-43px',
|
|
47
|
-
borderRadius: '50%',
|
|
48
|
-
backgroundColor: props.topoutBackgroundColor || '#f33939',
|
|
49
|
-
color: props.topoutColor || 'var(--primary-color)',
|
|
50
|
-
},
|
|
51
|
-
'.footer-menu .footer-menu-item-a': {
|
|
52
|
-
zIndex: 'var(--layer-header-footer)',
|
|
53
|
-
},
|
|
54
|
-
'.footer-menu .footer-menu-item.active': {
|
|
55
|
-
color: props.activeColor || 'var(--primary-accent-color)',
|
|
56
|
-
},
|
|
57
|
-
[MediaQueryRange.TabletBelow]: {
|
|
58
|
-
'.footer-menu': {
|
|
59
|
-
display: 'flex',
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
const onClick = (index: number, href: string) => {
|
|
64
|
-
const items = document.querySelector('.footer-menu-item.active');
|
|
65
|
-
items?.classList.remove('active');
|
|
66
|
-
// find footer-menu-item by index
|
|
67
|
-
const item = document.querySelector(`a:nth-child(${index + 1}) .footer-menu-item`);
|
|
68
|
-
item?.classList.add('active');
|
|
69
|
-
};
|
|
70
|
-
let curretnUrl = typeof window !== 'undefined' ? window.location.pathname : '';
|
|
71
|
-
return (
|
|
72
|
-
<div css={css} class='footer-menu-box'>
|
|
73
|
-
<div class='footer-menu'>
|
|
74
|
-
{props.items.map((item, index) => (
|
|
75
|
-
<a class='footer-menu-item-a' href={item.href} key={index}>
|
|
76
|
-
<div
|
|
77
|
-
class={`footer-menu-item ${item.topout ? 'footer-menu-topout' : ''} ${
|
|
78
|
-
curretnUrl === item.href ? 'active' : ''
|
|
79
|
-
}`}
|
|
80
|
-
onClick={() => onClick(index, item.href)}
|
|
81
|
-
>
|
|
82
|
-
<i class={`ifc-icon ${item.icon}`}></i>
|
|
83
|
-
{item.text}
|
|
84
|
-
</div>
|
|
85
|
-
</a>
|
|
86
|
-
))}
|
|
87
|
-
{/* <div class='footer-menu-item'><a href='/'><i class="ifc-icon ma-home-outline"></i>主页</a></div>
|
|
88
|
-
<div class='footer-menu-item'><a href='/user/tools'><i class="ifc-icon bo-multimedia-music-note"></i>工具</a></div>
|
|
89
|
-
<div class='footer-menu-item footer-menu-topout'><a href='/user/customer'><i class="ifc-icon co-cil-chat-bubble"></i>客服</a></div>
|
|
90
|
-
<div class='footer-menu-item'><a href='/user/member'><i class="ifc-icon ma-crown-outline"></i>会员</a></div>
|
|
91
|
-
<div class='footer-menu-item'><a href='/user/mine'><i class="ifc-icon ma-account-cog-outline"></i>我的</a></div> */}
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
);
|
|
95
|
-
};
|
|
1
|
+
import { CssProps, MediaQueryRange } from 'lupine.components';
|
|
2
|
+
import { IconMenuItemProps } from './icon-menu-item-props';
|
|
3
|
+
|
|
4
|
+
export interface MobileFooterMenuProps {
|
|
5
|
+
items: IconMenuItemProps[];
|
|
6
|
+
color?: string;
|
|
7
|
+
activeColor?: string;
|
|
8
|
+
topoutColor?: string;
|
|
9
|
+
topoutBackgroundColor?: string;
|
|
10
|
+
}
|
|
11
|
+
export const MobileFooterMenu = (props: MobileFooterMenuProps) => {
|
|
12
|
+
const css: CssProps = {
|
|
13
|
+
'.footer-menu': {
|
|
14
|
+
display: 'none',
|
|
15
|
+
// position: 'fixed',
|
|
16
|
+
// left: 0,
|
|
17
|
+
// right: 0,
|
|
18
|
+
// bottom: 0,
|
|
19
|
+
width: '100%',
|
|
20
|
+
background: 'var(--sidebar-bg-color)',
|
|
21
|
+
paddingBottom: 'env(safe-area-inset-bottom)',
|
|
22
|
+
minHeight: '50px',
|
|
23
|
+
justifyContent: 'space-around',
|
|
24
|
+
alignItems: 'center',
|
|
25
|
+
borderTop: 'var(--primary-border)',
|
|
26
|
+
},
|
|
27
|
+
'.footer-menu, .footer-menu a': {
|
|
28
|
+
textDecoration: 'none',
|
|
29
|
+
color: props.color || 'var(--primary-color)',
|
|
30
|
+
},
|
|
31
|
+
'.footer-menu .footer-menu-item': {
|
|
32
|
+
padding: '4px 16px 4px 16px',
|
|
33
|
+
fontSize: '11px',
|
|
34
|
+
height: '55px', // 和主页保留的底部菜单高度一致
|
|
35
|
+
width: '55px',
|
|
36
|
+
display: 'flex',
|
|
37
|
+
flexWrap: 'wrap',
|
|
38
|
+
alignItems: 'center',
|
|
39
|
+
},
|
|
40
|
+
'.footer-menu .footer-menu-item i': {
|
|
41
|
+
display: 'block',
|
|
42
|
+
fontSize: '22px',
|
|
43
|
+
marginBottom: '4px',
|
|
44
|
+
},
|
|
45
|
+
'.footer-menu .footer-menu-item.footer-menu-topout': {
|
|
46
|
+
marginTop: '-43px',
|
|
47
|
+
borderRadius: '50%',
|
|
48
|
+
backgroundColor: props.topoutBackgroundColor || '#f33939',
|
|
49
|
+
color: props.topoutColor || 'var(--primary-color)',
|
|
50
|
+
},
|
|
51
|
+
'.footer-menu .footer-menu-item-a': {
|
|
52
|
+
zIndex: 'var(--layer-header-footer)',
|
|
53
|
+
},
|
|
54
|
+
'.footer-menu .footer-menu-item.active': {
|
|
55
|
+
color: props.activeColor || 'var(--primary-accent-color)',
|
|
56
|
+
},
|
|
57
|
+
[MediaQueryRange.TabletBelow]: {
|
|
58
|
+
'.footer-menu': {
|
|
59
|
+
display: 'flex',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
const onClick = (index: number, href: string) => {
|
|
64
|
+
const items = document.querySelector('.footer-menu-item.active');
|
|
65
|
+
items?.classList.remove('active');
|
|
66
|
+
// find footer-menu-item by index
|
|
67
|
+
const item = document.querySelector(`a:nth-child(${index + 1}) .footer-menu-item`);
|
|
68
|
+
item?.classList.add('active');
|
|
69
|
+
};
|
|
70
|
+
let curretnUrl = typeof window !== 'undefined' ? window.location.pathname : '';
|
|
71
|
+
return (
|
|
72
|
+
<div css={css} class='footer-menu-box'>
|
|
73
|
+
<div class='footer-menu'>
|
|
74
|
+
{props.items.map((item, index) => (
|
|
75
|
+
<a class='footer-menu-item-a' href={item.href} key={index}>
|
|
76
|
+
<div
|
|
77
|
+
class={`footer-menu-item ${item.topout ? 'footer-menu-topout' : ''} ${
|
|
78
|
+
curretnUrl === item.href ? 'active' : ''
|
|
79
|
+
}`}
|
|
80
|
+
onClick={() => onClick(index, item.href)}
|
|
81
|
+
>
|
|
82
|
+
<i class={`ifc-icon ${item.icon}`}></i>
|
|
83
|
+
{item.text}
|
|
84
|
+
</div>
|
|
85
|
+
</a>
|
|
86
|
+
))}
|
|
87
|
+
{/* <div class='footer-menu-item'><a href='/'><i class="ifc-icon ma-home-outline"></i>主页</a></div>
|
|
88
|
+
<div class='footer-menu-item'><a href='/user/tools'><i class="ifc-icon bo-multimedia-music-note"></i>工具</a></div>
|
|
89
|
+
<div class='footer-menu-item footer-menu-topout'><a href='/user/customer'><i class="ifc-icon co-cil-chat-bubble"></i>客服</a></div>
|
|
90
|
+
<div class='footer-menu-item'><a href='/user/member'><i class="ifc-icon ma-crown-outline"></i>会员</a></div>
|
|
91
|
+
<div class='footer-menu-item'><a href='/user/mine'><i class="ifc-icon ma-account-cog-outline"></i>我的</a></div> */}
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
@@ -1,101 +1,101 @@
|
|
|
1
|
-
/*
|
|
2
|
-
MobileHeaderComponent is the topest header for mobile, and Left, Center and Right part can be updated by other components
|
|
3
|
-
|
|
4
|
-
If Left and Right are not set, then Center (100% width) can be used by temporiry headers like MobileHeaderTitleIcon,
|
|
5
|
-
to set Left and Right icons inside Center part.
|
|
6
|
-
|
|
7
|
-
For example, the header can be updated like this with different Left and Right icons:
|
|
8
|
-
<MobileHeaderCenter>
|
|
9
|
-
<MobileHeaderTitleIcon title='工具' left={<MobileHeaderEmptyIcon />} right={<MobileTopSysIcon />} />
|
|
10
|
-
</MobileHeaderCenter>
|
|
11
|
-
You can update Left, Right and Center separately, but it's convenient to use MobileHeaderCenter to set both Left and Right icons..
|
|
12
|
-
*/
|
|
13
|
-
import { CssProps, HtmlVar, VNode } from 'lupine.components';
|
|
14
|
-
|
|
15
|
-
export class MobileHeaderHelper {
|
|
16
|
-
private static instance: MobileHeaderHelper;
|
|
17
|
-
|
|
18
|
-
private leftContent = new HtmlVar('');
|
|
19
|
-
private centerContent = new HtmlVar('');
|
|
20
|
-
private rightContent = new HtmlVar('');
|
|
21
|
-
private constructor() {}
|
|
22
|
-
|
|
23
|
-
public static getInstance(): MobileHeaderHelper {
|
|
24
|
-
if (!MobileHeaderHelper.instance) {
|
|
25
|
-
MobileHeaderHelper.instance = new MobileHeaderHelper();
|
|
26
|
-
}
|
|
27
|
-
return MobileHeaderHelper.instance;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public setLeftContent(content: string | VNode<any>) {
|
|
31
|
-
this.leftContent.value = content;
|
|
32
|
-
}
|
|
33
|
-
public getLeftContent() {
|
|
34
|
-
return this.leftContent;
|
|
35
|
-
}
|
|
36
|
-
public setCenterContent(content: string | VNode<any>) {
|
|
37
|
-
this.centerContent.value = content;
|
|
38
|
-
}
|
|
39
|
-
public getCenterContent() {
|
|
40
|
-
return this.centerContent;
|
|
41
|
-
}
|
|
42
|
-
public setRightContent(content: string | VNode<any>) {
|
|
43
|
-
this.rightContent.value = content;
|
|
44
|
-
}
|
|
45
|
-
public getRightContent() {
|
|
46
|
-
return this.rightContent;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
public hideHeader() {
|
|
50
|
-
this.leftContent.value = '';
|
|
51
|
-
this.centerContent.value = '';
|
|
52
|
-
this.rightContent.value = '';
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
export const mobileHeaderHelper = MobileHeaderHelper.getInstance();
|
|
56
|
-
|
|
57
|
-
export const MobileHeaderLeft = (props: { children: VNode<any> }) => {
|
|
58
|
-
mobileHeaderHelper.setLeftContent(props.children);
|
|
59
|
-
return <></>;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export const MobileHeaderCenter = (props: { children: VNode<any> }) => {
|
|
63
|
-
mobileHeaderHelper.setCenterContent(props.children);
|
|
64
|
-
return <></>;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export const MobileHeaderRight = (props: { children: VNode<any> }) => {
|
|
68
|
-
mobileHeaderHelper.setRightContent(props.children);
|
|
69
|
-
return <></>;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export const MobileHeaderHide = () => {
|
|
73
|
-
mobileHeaderHelper.hideHeader();
|
|
74
|
-
return <></>;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// there should be only one MobileHeaderComponent on a page
|
|
78
|
-
export const MobileHeaderComponent = (props: any) => {
|
|
79
|
-
const css: CssProps = {
|
|
80
|
-
display: 'flex',
|
|
81
|
-
flexDirection: 'row',
|
|
82
|
-
width: '100%',
|
|
83
|
-
height: 'auto',
|
|
84
|
-
// padding: '2px 0',
|
|
85
|
-
// boxShadow: 'var(--mobile-header-shadow)', // 第二项 2px 的话,顶部有阴影(线)
|
|
86
|
-
'& > *': {
|
|
87
|
-
height: '100%',
|
|
88
|
-
},
|
|
89
|
-
'.mobile-header-center': {
|
|
90
|
-
flex: 1,
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
return (
|
|
95
|
-
<div css={css} class='mobile-header-component'>
|
|
96
|
-
<div class='mobile-header-left'>{mobileHeaderHelper.getLeftContent().node}</div>
|
|
97
|
-
<div class='mobile-header-center'>{mobileHeaderHelper.getCenterContent().node}</div>
|
|
98
|
-
<div class='mobile-header-right'>{mobileHeaderHelper.getRightContent().node}</div>
|
|
99
|
-
</div>
|
|
100
|
-
);
|
|
101
|
-
};
|
|
1
|
+
/*
|
|
2
|
+
MobileHeaderComponent is the topest header for mobile, and Left, Center and Right part can be updated by other components
|
|
3
|
+
|
|
4
|
+
If Left and Right are not set, then Center (100% width) can be used by temporiry headers like MobileHeaderTitleIcon,
|
|
5
|
+
to set Left and Right icons inside Center part.
|
|
6
|
+
|
|
7
|
+
For example, the header can be updated like this with different Left and Right icons:
|
|
8
|
+
<MobileHeaderCenter>
|
|
9
|
+
<MobileHeaderTitleIcon title='工具' left={<MobileHeaderEmptyIcon />} right={<MobileTopSysIcon />} />
|
|
10
|
+
</MobileHeaderCenter>
|
|
11
|
+
You can update Left, Right and Center separately, but it's convenient to use MobileHeaderCenter to set both Left and Right icons..
|
|
12
|
+
*/
|
|
13
|
+
import { CssProps, HtmlVar, VNode } from 'lupine.components';
|
|
14
|
+
|
|
15
|
+
export class MobileHeaderHelper {
|
|
16
|
+
private static instance: MobileHeaderHelper;
|
|
17
|
+
|
|
18
|
+
private leftContent = new HtmlVar('');
|
|
19
|
+
private centerContent = new HtmlVar('');
|
|
20
|
+
private rightContent = new HtmlVar('');
|
|
21
|
+
private constructor() {}
|
|
22
|
+
|
|
23
|
+
public static getInstance(): MobileHeaderHelper {
|
|
24
|
+
if (!MobileHeaderHelper.instance) {
|
|
25
|
+
MobileHeaderHelper.instance = new MobileHeaderHelper();
|
|
26
|
+
}
|
|
27
|
+
return MobileHeaderHelper.instance;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public setLeftContent(content: string | VNode<any>) {
|
|
31
|
+
this.leftContent.value = content;
|
|
32
|
+
}
|
|
33
|
+
public getLeftContent() {
|
|
34
|
+
return this.leftContent;
|
|
35
|
+
}
|
|
36
|
+
public setCenterContent(content: string | VNode<any>) {
|
|
37
|
+
this.centerContent.value = content;
|
|
38
|
+
}
|
|
39
|
+
public getCenterContent() {
|
|
40
|
+
return this.centerContent;
|
|
41
|
+
}
|
|
42
|
+
public setRightContent(content: string | VNode<any>) {
|
|
43
|
+
this.rightContent.value = content;
|
|
44
|
+
}
|
|
45
|
+
public getRightContent() {
|
|
46
|
+
return this.rightContent;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public hideHeader() {
|
|
50
|
+
this.leftContent.value = '';
|
|
51
|
+
this.centerContent.value = '';
|
|
52
|
+
this.rightContent.value = '';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export const mobileHeaderHelper = MobileHeaderHelper.getInstance();
|
|
56
|
+
|
|
57
|
+
export const MobileHeaderLeft = (props: { children: VNode<any> }) => {
|
|
58
|
+
mobileHeaderHelper.setLeftContent(props.children);
|
|
59
|
+
return <></>;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const MobileHeaderCenter = (props: { children: VNode<any> }) => {
|
|
63
|
+
mobileHeaderHelper.setCenterContent(props.children);
|
|
64
|
+
return <></>;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const MobileHeaderRight = (props: { children: VNode<any> }) => {
|
|
68
|
+
mobileHeaderHelper.setRightContent(props.children);
|
|
69
|
+
return <></>;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const MobileHeaderHide = () => {
|
|
73
|
+
mobileHeaderHelper.hideHeader();
|
|
74
|
+
return <></>;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// there should be only one MobileHeaderComponent on a page
|
|
78
|
+
export const MobileHeaderComponent = (props: any) => {
|
|
79
|
+
const css: CssProps = {
|
|
80
|
+
display: 'flex',
|
|
81
|
+
flexDirection: 'row',
|
|
82
|
+
width: '100%',
|
|
83
|
+
height: 'auto',
|
|
84
|
+
// padding: '2px 0',
|
|
85
|
+
// boxShadow: 'var(--mobile-header-shadow)', // 第二项 2px 的话,顶部有阴影(线)
|
|
86
|
+
'& > *': {
|
|
87
|
+
height: '100%',
|
|
88
|
+
},
|
|
89
|
+
'.mobile-header-center': {
|
|
90
|
+
flex: 1,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div css={css} class='mobile-header-component'>
|
|
96
|
+
<div class='mobile-header-left'>{mobileHeaderHelper.getLeftContent().node}</div>
|
|
97
|
+
<div class='mobile-header-center'>{mobileHeaderHelper.getCenterContent().node}</div>
|
|
98
|
+
<div class='mobile-header-right'>{mobileHeaderHelper.getRightContent().node}</div>
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
};
|