186 lines
4.9 KiB
TypeScript
186 lines
4.9 KiB
TypeScript
interface AlertButton {
|
|
text: string;
|
|
onPress?: () => void;
|
|
style?: 'default' | 'cancel' | 'destructive';
|
|
}
|
|
|
|
class PlatformAlert {
|
|
alert(title: string, message?: string, buttons?: AlertButton[]) {
|
|
const overlay = this.createOverlay();
|
|
const modal = this.createModal(title, message, buttons, overlay);
|
|
|
|
document.body.appendChild(overlay);
|
|
overlay.appendChild(modal);
|
|
|
|
requestAnimationFrame(() => {
|
|
overlay.style.opacity = '1';
|
|
modal.style.transform = 'translateY(0)';
|
|
});
|
|
}
|
|
|
|
private createOverlay(): HTMLDivElement {
|
|
const overlay = document.createElement('div');
|
|
Object.assign(overlay.style, {
|
|
position: 'fixed',
|
|
top: '0',
|
|
left: '0',
|
|
right: '0',
|
|
bottom: '0',
|
|
backgroundColor: 'rgba(5, 5, 5, 0.68)',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
zIndex: '9999',
|
|
opacity: '0',
|
|
transition: 'opacity 200ms ease-out',
|
|
});
|
|
return overlay;
|
|
}
|
|
|
|
private createModal(
|
|
title: string,
|
|
message?: string,
|
|
buttons?: AlertButton[],
|
|
overlay?: HTMLDivElement
|
|
): HTMLDivElement {
|
|
const modal = document.createElement('div');
|
|
Object.assign(modal.style, {
|
|
backgroundColor: '#121216',
|
|
borderRadius: '24px',
|
|
padding: '28px',
|
|
maxWidth: '360px',
|
|
width: 'calc(100% - 56px)',
|
|
border: '1px solid #1D1E24',
|
|
transform: 'translateY(20px)',
|
|
transition: 'transform 200ms ease-out',
|
|
});
|
|
|
|
const titleEl = document.createElement('div');
|
|
Object.assign(titleEl.style, {
|
|
fontSize: '18px',
|
|
fontWeight: '700',
|
|
color: '#F6F7FA',
|
|
marginBottom: message ? '12px' : '24px',
|
|
textAlign: 'center',
|
|
});
|
|
titleEl.textContent = title;
|
|
modal.appendChild(titleEl);
|
|
|
|
if (message) {
|
|
const messageEl = document.createElement('div');
|
|
Object.assign(messageEl.style, {
|
|
fontSize: '15px',
|
|
lineHeight: '1.5',
|
|
color: 'rgba(255, 255, 255, 0.75)',
|
|
marginBottom: '24px',
|
|
textAlign: 'center',
|
|
});
|
|
messageEl.textContent = message;
|
|
modal.appendChild(messageEl);
|
|
}
|
|
|
|
const buttonContainer = document.createElement('div');
|
|
Object.assign(buttonContainer.style, {
|
|
display: 'flex',
|
|
gap: '12px',
|
|
flexDirection: buttons && buttons.length > 2 ? 'column' : 'row',
|
|
});
|
|
|
|
const buttonList = buttons && buttons.length > 0 ? buttons : [{ text: '确定', style: 'default' as const }];
|
|
|
|
buttonList.forEach((btn) => {
|
|
const button = document.createElement('button');
|
|
const isDestructive = btn.style === 'destructive';
|
|
const isCancel = btn.style === 'cancel';
|
|
|
|
Object.assign(button.style, {
|
|
flex: '1',
|
|
padding: '14px 20px',
|
|
borderRadius: '999px',
|
|
border: isCancel ? '1px solid #1D1E24' : 'none',
|
|
backgroundColor: isDestructive ? '#FF4444' : isCancel ? '#101014' : '#D1FE17',
|
|
color: isDestructive ? '#FFFFFF' : isCancel ? '#8E9098' : '#050505',
|
|
fontSize: '16px',
|
|
fontWeight: '700',
|
|
cursor: 'pointer',
|
|
transition: 'all 150ms ease-out',
|
|
});
|
|
|
|
button.textContent = btn.text;
|
|
|
|
button.onmouseover = () => {
|
|
button.style.opacity = '0.85';
|
|
button.style.transform = 'translateY(-1px)';
|
|
};
|
|
|
|
button.onmouseout = () => {
|
|
button.style.opacity = '1';
|
|
button.style.transform = 'translateY(0)';
|
|
};
|
|
|
|
button.onclick = () => {
|
|
this.closeModal(overlay!);
|
|
btn.onPress?.();
|
|
};
|
|
|
|
buttonContainer.appendChild(button);
|
|
});
|
|
|
|
modal.appendChild(buttonContainer);
|
|
return modal;
|
|
}
|
|
|
|
private closeModal(overlay: HTMLDivElement) {
|
|
overlay.style.opacity = '0';
|
|
const modal = overlay.querySelector('div') as HTMLDivElement;
|
|
if (modal) {
|
|
modal.style.transform = 'translateY(20px)';
|
|
}
|
|
|
|
setTimeout(() => {
|
|
overlay.remove();
|
|
}, 200);
|
|
}
|
|
|
|
toast(message: string, duration: number = 2000) {
|
|
const toast = document.createElement('div');
|
|
Object.assign(toast.style, {
|
|
position: 'fixed',
|
|
bottom: '80px',
|
|
left: '50%',
|
|
transform: 'translateX(-50%) translateY(20px)',
|
|
backgroundColor: '#18181D',
|
|
color: '#F6F7FA',
|
|
padding: '14px 24px',
|
|
borderRadius: '999px',
|
|
fontSize: '15px',
|
|
fontWeight: '600',
|
|
border: '1px solid #1D1E24',
|
|
zIndex: '10000',
|
|
opacity: '0',
|
|
transition: 'all 200ms ease-out',
|
|
maxWidth: 'calc(100% - 56px)',
|
|
textAlign: 'center',
|
|
});
|
|
|
|
toast.textContent = message;
|
|
document.body.appendChild(toast);
|
|
|
|
requestAnimationFrame(() => {
|
|
toast.style.opacity = '1';
|
|
toast.style.transform = 'translateX(-50%) translateY(0)';
|
|
});
|
|
|
|
setTimeout(() => {
|
|
toast.style.opacity = '0';
|
|
toast.style.transform = 'translateX(-50%) translateY(20px)';
|
|
|
|
setTimeout(() => {
|
|
toast.remove();
|
|
}, 200);
|
|
}, duration);
|
|
}
|
|
}
|
|
|
|
export const Alert = new PlatformAlert();
|