feat: add storybook

This commit is contained in:
2024-10-19 08:31:14 +08:00
parent 8e7277022b
commit a7144104e8
37 changed files with 11148 additions and 2 deletions

0
apps/message/message.js Normal file
View File

270
apps/ui/deploy/message.js Normal file
View File

@@ -0,0 +1,270 @@
export class MessageContainer {
container;
id = 'for-message';
root = document.body;
constructor(opts) {
const { id } = opts || {};
if (id) {
this.id = id;
}
this.initContainer();
}
initContainer() {
const id = this.id;
const root = this.root;
let forModal = document.querySelector('#' + id);
if (!forModal) {
forModal = document.createElement('div');
forModal.id = id;
forModal.style = ``;
// 点击穿透
root.appendChild(forModal);
}
this.initStyle();
this.container = forModal;
}
initStyle(force) {
const id = this.id;
const styleId = id + '-style';
const _style = document.querySelector('#' + styleId);
if (force && _style) {
_style.remove();
}
if (!force && _style) {
return;
}
const style = document.createElement('style');
style.id = styleId;
style.innerHTML = `
#${id} {
position: fixed; top: 0; left: 0; z-index: 1000; width: 100vw;height: 100vh;pointer-events: none; display: flex; flex-direction: column; gap: 10px;
}
.message-wrapper {
display: flex;
transition: transform 2s ease-in-out, opacity 1.2s ease-in-out; /* 缩小并淡出 */
}
.message-wrapper:first-child {
margin-top: 20px;
}
.message {
display: flex;
gap: 10px;
padding: 6px 10px;
margin: 0 auto;
border-radius: 4px;
background-color: white;
box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
justify-content: center;
align-item: center;
animation: message-slide-down 0.5s ease-out forwards; /* 应用动画 */
}
/* 添加消失类时 */
.message-wrapper.message-hide {
transform: scale(0);
opacity: 0;
pointer-events: none; /* 防止交互 */
}
.message-success {
}
@keyframes message-slide-down {
0% {
transform: translateY(-100px); /* 从上方开始 */
opacity: 0; /* 从不可见状态开始 */
}
50% {
opacity: 0.5; /* 渐渐变为半透明 */
}
100% {
transform: translateY(0); /* 移动到初始位置 */
opacity: 1; /* 最终完全可见 */
}
}
.message-icon {
position: relative;
width: 24px;
height: 24px;
box-sizing: border-box;
}
.message-icon::before {
content: "";
position: absolute;
left: 7px;
top: 3px;
width: 5px;
height: 10px;
}
.icon-success {
border: 2px solid green; /* 外圆圈 */
border-radius: 50%; /* 使其为圆形 */
}
.icon-success::before {
border-right: 2px solid green; /* 打勾的右边部分 */
border-bottom: 2px solid green; /* 打勾的下边部分 */
transform: rotate(45deg);
}
.icon-info {
border: 2px solid blue; /* 外圆圈 */
border-radius: 50%; /* 使其为圆形 */
}
.icon-info::before {
content: "i";
position: absolute;
top: 0px;
color: blue;
font-weight: bold;
font-size: 16px;
left: 8px;
}
.icon-error::before, .icon-error::after {
content: "";
position: absolute;
top: 4px;
left: 50%;
width: 2px;
height: 12px;
background-color: red;
transform-origin: center;
}
.icon-error {
border: 2px solid red; /* 外圆圈 */
border-radius: 50%; /* 使其为圆形 */
}
.icon-error::before {
transform: translateX(-50%) rotate(45deg); /* 旋转形成叉号的一部分 */
}
.icon-error::after {
transform: translateX(-50%) rotate(-45deg); /* 旋转形成叉号的另一部分 */
}
.icon-warning {
position: relative;
width: 0;
height: 0;
border-left: 12px solid transparent;
border-right: 12px solid transparent;
border-bottom: 24px solid orange; /* 三角形 */
display: inline-block;
transform: scale(0.8); /* 缩小三角形 */
}
.icon-warning::before {
content: "!";
position: absolute;
top: 5px;
left: 50%;
transform: translateX(-50%);
color: white;
font-weight: bold;
font-size: 16px;
}
.icon-loading {
width: 24px;
height: 24px;
border: 3px solid #f3f3f3; /* 边框颜色,用于加载圈的背景 */
border-top: 3px solid #3498db; /* 顶部边框的颜色,用于显示加载进度 */
border-radius: 50%; /* 圆形 */
animation: spin 1s linear infinite; /* 旋转动画 */
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
`;
document.head.appendChild(style);
}
setRoot(root) {
if (root instanceof HTMLElement) {
this.root = root;
root.appendChild(this.container);
}
}
}
const controller = new MessageContainer();
export const createMessage = (content, opts) => {
let { icon, key, style, className, type } = opts || {};
const div = document.createElement('div');
div.className = 'message-wrapper' + (className ? ' ' + className : '');
if (style) div.style = style;
if (key) div.setAttribute('data-key', key);
const contentDiv = document.createElement('div');
contentDiv.className = 'message';
if (icon) {
const i = document.createElement('i');
i.className = icon;
i.classList.add('message-icon');
contentDiv.appendChild(i);
} else if (type) {
const i = document.createElement('div');
i.className = 'icon-' + type;
i.classList.add('message-icon');
contentDiv.appendChild(i);
}
console.log(content, type, icon, 'content');
if (content instanceof HTMLElement) {
contentDiv.appendChild(content);
} else {
const text = document.createElement('span');
text.innerText = content;
contentDiv.appendChild(text);
}
div.appendChild(contentDiv);
return div;
};
const methods = ['success', 'info', 'warning', 'error', 'loading'];
export class Message {
static controller = controller;
static open = (message, timeout = 3000, onClose, opts) => {
const div = createMessage(message, opts);
const remove = () => {
div.classList.add('message-hide');
setTimeout(() => {
if (div.isConnected) {
div.remove();
} else {
console.log('not connected');
controller.container.removeChild(div);
}
}, 1000);
onClose && onClose();
};
controller.container.appendChild(div);
controller.initStyle(true);
if (timeout === 0) {
return () => {
remove();
};
}
const time = setTimeout(() => {
remove();
}, timeout);
return () => {
clearTimeout(time);
remove();
};
};
static success = (message, timeout = 3000, onClose) => {
return Message.open(message, timeout, onClose, { type: 'success' });
};
static info = (message, timeout = 3000, onClose) => {
return Message.open(message, timeout, onClose, { type: 'info' });
};
static warning = (message, timeout = 3000, onClose) => {
return Message.open(message, timeout, onClose, { type: 'warning' });
};
static error = (message, timeout = 3000, onClose) => {
return Message.open(message, timeout, onClose, { type: 'error' });
};
static loading = (message, timeout = 0, onClose) => {
return Message.open(message, timeout, onClose, { type: 'loading' });
};
}

View File

@@ -0,0 +1,53 @@
import { Message, createMessage } from '../deploy/message.js';
export default {
title: 'ui/message',
tags: ['autodocs'],
render: ({ label, fn, ...args }) => {
const div = createMessage(label, { type: 'success' });
div.addEventListener('click', () => {
fn('Hello World', 2000);
});
div.style.border = '1px solid #000';
const uiMessage = document.createElement('div');
uiMessage.style = 'display: flex;gap:10px; flex-direction: column;background: #f0f0f0; padding: 20px';
uiMessage.appendChild(div);
const info = createMessage('Info', { type: 'info' });
info.style.border = '1px solid #000';
info.addEventListener('click', () => {
Message.info('Hello World', 1000);
});
uiMessage.appendChild(info);
const error = createMessage('Error', { type: 'error' });
error.style.border = '1px solid #000';
error.addEventListener('click', () => {
Message.error('Hello World', 1500);
});
uiMessage.appendChild(error);
const warning = createMessage('Warning', { type: 'warning' });
warning.style.border = '1px solid #000';
warning.addEventListener('click', () => {
Message.warning('Hello World', 3000);
});
uiMessage.appendChild(warning);
const loading = createMessage('Loading', { type: 'loading' });
loading.style.border = '1px solid #000';
loading.addEventListener('click', () => {
Message.loading('Hello World');
});
uiMessage.appendChild(loading);
return uiMessage;
},
};
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Success = {
args: {
label: 'Success',
fn: Message.success,
},
};

15
apps/ui/index.html Normal file
View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UI</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./deploy/me.js"></script>
</body>
</html>

13
apps/ui/package.json Normal file
View File

@@ -0,0 +1,13 @@
{
"name": "ui",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"pub": "envision switchOrg system && envision deploy ./deploy -v 0.0.1 -k ui -y y",
"dev": "vite"
},
"keywords": [],
"author": "",
"license": "ISC"
}