diff --git a/packages/core/assets/css/style.css b/packages/core/assets/css/style.css index 5d1cda2c..3d160aac 100644 --- a/packages/core/assets/css/style.css +++ b/packages/core/assets/css/style.css @@ -1,17 +1,53 @@ +/** 默认字体 */ +/** 输入框默认边距 */ +.base-style-active-form-control { + border: 1px solid #ffffff00; +} +.base-style-active-form-control:focus { + border: 1px solid #0e8de290; + box-shadow: 0px 0px 4px #0e8de252; +} +.base-style-active-form-control:focus:not([type='checkbox'], [type='radio']) { + border: 1px solid #0e8de290; + box-shadow: 0px 0px 4px #0e8de252; + background-color: white !important; +} +.base-style-active-form-control:hover { + background-color: #ebeef4; +} +.base-style-input { + outline: none; + border: 1px solid #ffffff00; + padding: 2px 8px; + margin: 0px; + background-color: #eef2f7; + border-radius: 2px; + color: black; +} +.base-style-input::placeholder { + color: #bababa; +} +.base-style-button { + appearance: none; + border: 1px solid #ffffff00; + background-color: #94bfff; + color: white; + border-radius: 4px; + cursor: pointer; +} +.base-style-button:active { + box-shadow: 0px 0px 8px #0e8de2a5; +} container-element { position: fixed; top: 10%; left: 10%; - z-index: 99999999; + z-index: 99; text-align: left; - border-radius: 4px; - background-color: white; - box-shadow: 0 0 24px -12px #3f3f3f; - border: 1px solid #c8c8c8; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #636363; - user-select: none; + font: 12px/1.5 Menlo, Monaco, Consolas, 'Courier New', monospace; } .header { cursor: move; @@ -22,7 +58,12 @@ container-element { line-height: 32px; height: 32px; vertical-align: middle; - background: #ededed73; + background: #fbfbfbee; + border-radius: 4px; + border: 1px solid #e6e6e6; + box-shadow: 0 0 24px -12px #3f3f3f; + margin-bottom: 4px; + user-select: none; } .header > * { margin-left: 12px; @@ -59,11 +100,14 @@ container-element { border-radius: 100%; } .body { - background: white; padding: 8px; width: auto; height: 100%; overflow: auto; + background-color: white; + box-shadow: 0 0 24px -12px #3f3f3f; + border: 1px solid #e6e6e6; + border-radius: 4px; } .script-panel + .script-panel { margin-top: 12px; @@ -120,13 +164,13 @@ container-element { display: table-cell; } .configs .configs-body config-element .config-wrapper > *:not(.tooltip) { - background-color: #f5f7fa; + background-color: #eef2f7; border-radius: 2px; color: black; - width: -webkit-fill-available; } .configs .configs-body config-element .config-wrapper > *:disabled { cursor: not-allowed; + background-color: #f7f7f78b; } .configs .configs-body config-element label { font-size: 13px; @@ -142,31 +186,75 @@ container-element { border: none; border: 1px solid #e4e4e4; border-radius: 4px; + padding: 2px 8px; height: 22px; + border: 1px solid #ffffff00; +} +.configs .configs-body config-element select:focus { + border: 1px solid #0e8de290; + box-shadow: 0px 0px 4px #0e8de252; +} +.configs .configs-body config-element select:focus:not([type='checkbox'], [type='radio']) { + border: 1px solid #0e8de290; + box-shadow: 0px 0px 4px #0e8de252; + background-color: white !important; +} +.configs .configs-body config-element select:hover { + background-color: #ebeef4; } .configs .configs-body config-element textarea { - padding: 4px; + padding: 2px 8px; outline: none; border: none; + border: 1px solid #ffffff00; +} +.configs .configs-body config-element textarea:focus { + border: 1px solid #0e8de290; + box-shadow: 0px 0px 4px #0e8de252; +} +.configs .configs-body config-element textarea:focus:not([type='checkbox'], [type='radio']) { + border: 1px solid #0e8de290; + box-shadow: 0px 0px 4px #0e8de252; + background-color: white !important; +} +.configs .configs-body config-element textarea:hover { + background-color: #ebeef4; } .configs .configs-body config-element input { outline: none; - border: none; - padding: 2px 0px; + padding: 2px 8px; margin: 0px; - text-align: center; + background-color: #eef2f7; + border-radius: 2px; + color: black; + border: 1px solid #ffffff00; +} +.configs .configs-body config-element input::placeholder { + color: #bababa; +} +.configs .configs-body config-element input:focus { + border: 1px solid #0e8de290; + box-shadow: 0px 0px 4px #0e8de252; +} +.configs .configs-body config-element input:focus:not([type='checkbox'], [type='radio']) { + border: 1px solid #0e8de290; + box-shadow: 0px 0px 4px #0e8de252; + background-color: white !important; +} +.configs .configs-body config-element input:hover { + background-color: #ebeef4; } .configs .configs-body config-element .input-switch { appearance: none; width: fit-content; min-width: 32px; height: 16px; - background: #c5c5c5; - border-radius: 100px; + border-radius: 100px !important; display: flex; align-items: center; padding: 2px 4px; transition: all 0.2s ease-in-out; + width: auto; } .configs .configs-body config-element .input-switch:checked { background: #1890ff !important; @@ -182,67 +270,184 @@ container-element { height: 12px; content: ''; } -.configs .configs-body config-element input:not([type='checkbox'], [type='radio']) { - width: 100%; +.configs .configs-body config-element input:not([type='checkbox'], [type='radio']), +.configs .configs-body config-element textarea, +.configs .configs-body config-element select { + width: -webkit-fill-available; } .configs .configs-body config-element input[type='checkbox'], .configs .configs-body config-element input[type='radio'], .configs .configs-body config-element input[type='range'] { accent-color: #0e8ee2; } -.alert-container { +.message-container { margin-bottom: 4px; position: absolute; - z-index: 999999; bottom: 100%; left: 50%; width: 100%; transform: translate(-50%, 0px); } -.alert-container .alert-closer { - float: right; - border-radius: 50%; - border: 1px solid; - text-align: center; - cursor: pointer; - font: icon; - line-height: 14px; - width: 14px; -} -.alert-container .hide .alert { - width: 200px; - transform: translate(-82px, 0px); -} -.alert-container .alert { +.message-container message-element { + display: block; border-radius: 4px; margin-bottom: 4px; - padding: 4px; + padding: 4px 12px; font-size: 12px; } -.alert-container .alert .alert-text { +.message-container message-element .message-text { letter-spacing: 1px; font-weight: bold; } -.alert-container .alert.error { +.message-container message-element .message-closer { + width: 18px; + cursor: pointer; + background-color: white; + color: #a8a8a8; + border-radius: 100%; + float: right; + text-align: center; + height: 18px; + line-height: 18px; +} +.message-container message-element.error { background-color: #ff000699; color: #fff; border: 1px solid #f36c70; } -.alert-container .alert.info { +.message-container message-element.info { background-color: #2196f3a3; color: white; border: 1px solid #1890ff; } -.alert-container .alert.success { +.message-container message-element.success { background-color: #84d346d1; color: #fff; border: 1px solid #6fd91d; } -.alert-container .alert.warn { +.message-container message-element.warn { background-color: #fbbf30e6; color: #725206; border: 1px solid #ffc107; } +model-element { + position: absolute; + top: 50%; + left: 50%; + background-color: white; + border-radius: 4px; + box-shadow: 0px 0px 24px -12px black; + border: 1px solid #929292; + min-width: 300px; + height: fit-content; + transform: translate(-50%, -50%); + padding: 12px 18px 18px 18px; + font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; + z-index: 99999; +} +model-element .model-profile { + zoom: 0.8; + color: #969696; + user-select: none; + margin-bottom: 4px; +} +model-element .model-title { + font-size: 18px; + font-weight: bold; + user-select: none; +} +model-element .model-body { + margin: 12px 0px; +} +model-element .model-footer { + display: flex; + white-space: nowrap; + justify-content: end; +} +model-element .model-footer * + * { + margin-left: 12px; +} +model-element .model-input { + outline: none; + padding: 2px 8px; + margin: 0px; + background-color: #eef2f7; + border-radius: 2px; + color: black; + border: 1px solid #ffffff00; + width: -webkit-fill-available; +} +model-element .model-input::placeholder { + color: #bababa; +} +model-element .model-input:focus { + border: 1px solid #0e8de290; + box-shadow: 0px 0px 4px #0e8de252; +} +model-element .model-input:focus:not([type='checkbox'], [type='radio']) { + border: 1px solid #0e8de290; + box-shadow: 0px 0px 4px #0e8de252; + background-color: white !important; +} +model-element .model-input:hover { + background-color: #ebeef4; +} +model-element .model-cancel-button { + appearance: none; + border: 1px solid #ffffff00; + background-color: #94bfff; + color: white; + border-radius: 4px; + cursor: pointer; + min-width: 60px; + color: gray; + background-color: white; + border: 1px solid #dcdcdc; +} +model-element .model-cancel-button:active { + box-shadow: 0px 0px 8px #0e8de2a5; +} +model-element .model-confirm-button { + appearance: none; + border: 1px solid #ffffff00; + background-color: #94bfff; + color: white; + border-radius: 4px; + cursor: pointer; + min-width: 60px; +} +model-element .model-confirm-button:active { + box-shadow: 0px 0px 8px #0e8de2a5; +} +model-element.alert .model-input, +model-element.alert .model-cancel-button { + display: none; +} +model-element.alert .model-confirm-button { + margin: 0; +} +model-element.prompt .model-input, +model-element.prompt .model-cancel-button, +model-element.prompt .model-confirm-button { + display: block; +} +model-element.confirm .model-input { + display: none; +} +.model-container { + width: 100%; + height: 100%; + position: absolute; + top: 0px; + left: 0px; +} +.model-wrapper { + position: fixed; + width: 100%; + height: 100%; + z-index: 9999; + background-color: rgba(0, 0, 0, 0.265); +} .pointer { cursor: pointer; } diff --git a/packages/core/assets/less/style.less b/packages/core/assets/less/style.less index 0f984bc3..6542cfe0 100644 --- a/packages/core/assets/less/style.less +++ b/packages/core/assets/less/style.less @@ -1,17 +1,64 @@ +/** 默认字体 */ +@base-font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; +/** 输入框默认边距 */ +@form-control-padding: 2px 8px; +@form-control-bg: #eef2f7; + +.base-style-active-form-control { + border: 1px solid #ffffff00; + &:focus { + border: 1px solid #0e8de290; + box-shadow: 0px 0px 4px #0e8de252; + } + + &:focus:not([type='checkbox'], [type='radio']) { + border: 1px solid #0e8de290; + box-shadow: 0px 0px 4px #0e8de252; + background-color: white !important; + } + + &:hover { + background-color: #ebeef4; + } +} + +.base-style-input { + outline: none; + border: 1px solid #ffffff00; + padding: @form-control-padding; + margin: 0px; + background-color: @form-control-bg; + border-radius: 2px; + color: black; + + &::placeholder { + color: #bababa; + } +} + +.base-style-button { + appearance: none; + border: 1px solid #ffffff00; + background-color: #94bfff; + color: white; + border-radius: 4px; + cursor: pointer; + + &:active { + box-shadow: 0px 0px 8px #0e8de2a5; + } +} + container-element { position: fixed; top: 10%; left: 10%; - z-index: 99999999; + z-index: 99; text-align: left; - border-radius: 4px; - background-color: white; - box-shadow: 0 0 24px -12px #3f3f3f; - border: 1px solid #c8c8c8; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #636363; - user-select: none; + font: 12px/1.5 @base-font-family; } .header { @@ -26,7 +73,12 @@ container-element { line-height: @base-height; height: @base-height; vertical-align: middle; - background: #ededed73; + background: #fbfbfbee; + border-radius: 4px; + border: 1px solid #e6e6e6; + box-shadow: 0 0 24px -12px #3f3f3f; + margin-bottom: 4px; + user-select: none; & > * { margin-left: 12px; @@ -69,11 +121,14 @@ container-element { } .body { - background: white; padding: 8px; width: auto; height: 100%; overflow: auto; + background-color: white; + box-shadow: 0 0 24px -12px #3f3f3f; + border: 1px solid #e6e6e6; + border-radius: 4px; } .script-panel + .script-panel { @@ -142,13 +197,13 @@ container-element { } .config-wrapper > *:not(.tooltip) { - background-color: #f5f7fa; + background-color: @form-control-bg; border-radius: 2px; color: black; - width: -webkit-fill-available; } .config-wrapper > *:disabled { cursor: not-allowed; + background-color: #f7f7f78b; } label { @@ -166,21 +221,22 @@ container-element { border: none; border: 1px solid #e4e4e4; border-radius: 4px; + padding: @form-control-padding; height: 22px; + + .base-style-active-form-control(); } textarea { - padding: 4px; + padding: @form-control-padding; outline: none; border: none; + .base-style-active-form-control(); } input { - outline: none; - border: none; - padding: 2px 0px; - margin: 0px; - text-align: center; + .base-style-input(); + .base-style-active-form-control(); } /** check box 的样式 */ @@ -189,12 +245,12 @@ container-element { width: fit-content; min-width: 32px; height: 16px; - background: #c5c5c5; - border-radius: 100px; + border-radius: 100px !important; display: flex; align-items: center; padding: 2px 4px; transition: all 0.2s ease-in-out; + width: auto; &:checked { background: #1890ff !important; @@ -214,8 +270,10 @@ container-element { } } - input:not([type='checkbox'], [type='radio']) { - width: 100%; + input:not([type='checkbox'], [type='radio']), + textarea, + select { + width: -webkit-fill-available; } input[type='checkbox'], @@ -227,47 +285,42 @@ container-element { } } -// 提示内容 -// alert 提示父元素 -.alert-container { +// 消息推送 + +.message-container { margin-bottom: 4px; position: absolute; - z-index: 999999; bottom: 100%; left: 50%; width: 100%; transform: translate(-50%, 0px); - // 关闭按钮 - .alert-closer { - float: right; - border-radius: 50%; - border: 1px solid; - text-align: center; - cursor: pointer; - font: icon; - line-height: 14px; - width: 14px; - } - - // 隐藏模式下的提示样式 - .hide .alert { - width: 200px; - transform: translate(-82px, 0px); - } - // 提示内容 - .alert { + message-element { + display: block; border-radius: 4px; margin-bottom: 4px; - padding: 4px; + padding: 4px 12px; font-size: 12px; - .alert-text { + .message-text { letter-spacing: 1px; font-weight: bold; } + // 关闭按钮 + .message-closer { + width: 18px; + cursor: pointer; + background-color: white; + color: #a8a8a8; + border-radius: 100%; + float: right; + text-align: center; + height: 18px; + line-height: 18px; + } + &.error { background-color: #ff000699; color: #fff; @@ -294,6 +347,107 @@ container-element { } } +model-element { + position: absolute; + top: 50%; + left: 50%; + background-color: white; + border-radius: 4px; + box-shadow: 0px 0px 24px -12px black; + border: 1px solid #929292; + min-width: 300px; + height: fit-content; + transform: translate(-50%, -50%); + padding: 12px 18px 18px 18px; + font-family: @base-font-family; + z-index: 99999; + + .model-profile { + zoom: 0.8; + color: #969696; + user-select: none; + margin-bottom: 4px; + } + + .model-title { + font-size: 18px; + font-weight: bold; + user-select: none; + } + + .model-body { + margin: 12px 0px; + } + + .model-footer { + display: flex; + white-space: nowrap; + justify-content: end; + + * + * { + margin-left: 12px; + } + } + + .model-input { + .base-style-input(); + .base-style-active-form-control(); + width: -webkit-fill-available; + } + + .model-cancel-button { + .base-style-button(); + min-width: 60px; + color: gray; + background-color: white; + border: 1px solid #dcdcdc; + } + .model-confirm-button { + .base-style-button(); + min-width: 60px; + } +} + +model-element.alert { + .model-input, + .model-cancel-button { + display: none; + } + .model-confirm-button { + margin: 0; + } +} + +model-element.prompt { + .model-input, + .model-cancel-button, + .model-confirm-button { + display: block; + } +} + +model-element.confirm { + .model-input { + display: none; + } +} + +.model-container { + width: 100%; + height: 100%; + position: absolute; + top: 0px; + left: 0px; +} + +.model-wrapper { + position: fixed; + width: 100%; + height: 100%; + z-index: 9999; + background-color: rgba(0, 0, 0, 0.265); +} + .pointer { cursor: pointer; } diff --git a/packages/core/src/elements/config.ts b/packages/core/src/elements/config.ts index daa23685..ff98fea7 100644 --- a/packages/core/src/elements/config.ts +++ b/packages/core/src/elements/config.ts @@ -5,7 +5,7 @@ import { ConfigTagMap } from './configs/interface'; import { IElement } from './interface'; export class ConfigElement extends IElement { - label: HTMLElement = el('label'); + label: HTMLLabelElement = el('label'); key: string = ''; tag?: T; provider!: ConfigTagMap[T]; diff --git a/packages/core/src/elements/container.ts b/packages/core/src/elements/container.ts index 9e5ecdf4..d93b523b 100644 --- a/packages/core/src/elements/container.ts +++ b/packages/core/src/elements/container.ts @@ -2,8 +2,8 @@ import { el, tooltip } from '../utils/dom'; import { IElement } from './interface'; export class ContainerElement extends IElement { - header: HTMLElement = tooltip(el('div', { className: 'header', title: '菜单栏-可拖动区域' })); - body: HTMLElement = el('div', { className: 'body', clientHeight: window.innerHeight / 2 }); + header: HTMLDivElement = tooltip(el('div', { className: 'header', title: '菜单栏-可拖动区域' })); + body: HTMLDivElement = el('div', { className: 'body', clientHeight: window.innerHeight / 2 }); connectedCallback() { this.append(this.header, this.body); diff --git a/packages/core/src/elements/index.ts b/packages/core/src/elements/index.ts index 9e029c54..36525630 100644 --- a/packages/core/src/elements/index.ts +++ b/packages/core/src/elements/index.ts @@ -1,4 +1,6 @@ import { ConfigElement } from './config'; import { ContainerElement } from './container'; +import { MessageElement } from './message'; +import { ModelElement } from './model'; -export const definedCustomElements = [ConfigElement, ContainerElement]; +export const definedCustomElements = [ConfigElement, ContainerElement, ModelElement, MessageElement]; diff --git a/packages/core/src/elements/interface.ts b/packages/core/src/elements/interface.ts index 1cbf409e..a48330bb 100644 --- a/packages/core/src/elements/interface.ts +++ b/packages/core/src/elements/interface.ts @@ -1,9 +1,13 @@ import { ConfigElement } from './config'; import { ContainerElement } from './container'; +import { MessageElement } from './message'; +import { ModelElement } from './model'; export class IElement extends HTMLElement {} export interface CustomElementTagMap { 'container-element': ContainerElement; 'config-element': ConfigElement; + 'model-element': ModelElement; + 'message-element': MessageElement; } diff --git a/packages/core/src/elements/message.ts b/packages/core/src/elements/message.ts new file mode 100644 index 00000000..4a77f563 --- /dev/null +++ b/packages/core/src/elements/message.ts @@ -0,0 +1,36 @@ +import { el } from '../utils/dom'; +import { IElement } from './interface'; + +export class MessageElement extends IElement { + closer: HTMLSpanElement = el('span', { className: 'message-closer', innerText: 'x' }); + text: HTMLSpanElement = el('span', { className: 'message-text' }); + + type: 'info' | 'success' | 'warn' | 'error' = 'info'; + content: string = ''; + /** 持续时间,如果为0的话则一直存在 */ + duration: number = 5; + closeable?: boolean = true; + onClose?: () => void; + + connectedCallback() { + this.classList.add(this.type); + this.text.innerText = this.content; + this.duration = Math.max(this.duration, 0); + this.append(this.text); + + if (this.closeable) { + this.append(this.closer); + this.closer.addEventListener('click', () => { + this.onClose?.(); + this.remove(); + }); + } + + if (this.duration) { + setTimeout(() => { + this.onClose?.(); + this.remove(); + }, this.duration * 1000); + } + } +} diff --git a/packages/core/src/elements/model.ts b/packages/core/src/elements/model.ts new file mode 100644 index 00000000..9da928c0 --- /dev/null +++ b/packages/core/src/elements/model.ts @@ -0,0 +1,45 @@ +import { el } from '../utils/dom'; +import { IElement } from './interface'; + +export class ModelElement extends IElement { + modelProfile: HTMLDivElement = el('div', { + innerText: '弹窗来自: OCS-' + process.env.__VERSION__, + className: 'model-profile' + }); + + modalTitle: HTMLDivElement = el('div', { className: 'model-title' }); + modalBody: HTMLDivElement = el('div', { className: 'model-body' }); + modalFooter: HTMLDivElement = el('div', { className: 'model-footer' }); + confirmButton: HTMLButtonElement = el('button', { className: 'model-confirm-button' }); + cancelButton: HTMLButtonElement = el('button', { className: 'model-cancel-button' }); + modalInput: HTMLInputElement = el('input', { className: 'model-input' }); + + type: 'prompt' | 'alert' | 'confirm' = 'alert'; + content: string = ''; + placeholder?: string = ''; + cancelButtonText: string = '取消'; + confirmButtonText: string = '确定'; + onConfirm?: (value?: string) => void; + onCancel?: () => void; + + connectedCallback() { + this.classList.add(this.type); + this.modalTitle.innerText = this.title; + this.modalBody.innerText = this.content; + this.cancelButton.innerText = this.cancelButtonText; + this.confirmButton.innerText = this.confirmButtonText; + this.modalInput.placeholder = this.placeholder || ''; + this.modalFooter.append(this.modalInput, this.cancelButton, this.confirmButton); + this.append(this.modelProfile, this.modalTitle, this.modalBody, this.modalFooter); + + this.confirmButton.addEventListener('click', () => { + this.onConfirm?.(this.modalInput.value); + this.remove(); + }); + + this.cancelButton.addEventListener('click', () => { + this.onCancel?.(); + this.remove(); + }); + } +} diff --git a/packages/core/src/projects/cx.ts b/packages/core/src/projects/cx.ts index 1d6f5f14..e7191657 100644 --- a/packages/core/src/projects/cx.ts +++ b/packages/core/src/projects/cx.ts @@ -57,6 +57,14 @@ export const CXProject: Project = { label: '测试3---输入框', attrs: { title: '测试' }, tag: 'textarea' + }, + switch: { + label: '测试4', + attrs: { type: 'checkbox', className: 'input-switch' } + }, + radio: { + label: '测试5', + attrs: { type: 'radio' } } } }) diff --git a/packages/core/src/projects/init.ts b/packages/core/src/projects/init.ts index 36c46c9e..467c400e 100644 --- a/packages/core/src/projects/init.ts +++ b/packages/core/src/projects/init.ts @@ -1,13 +1,18 @@ import { definedCustomElements } from '../elements'; +import { MessageElement } from '../elements/message'; +import { ModelElement } from '../elements/model'; import { Config } from '../interfaces/config'; import { Project } from '../interfaces/project'; import { Script } from '../interfaces/script'; -import { getConfig, getMatchedScripts, namespaceKey, setConfig } from '../utils/common'; +import { getMatchedScripts, namespaceKey } from '../utils/common'; import { el, enableElementDraggable, tooltip } from '../utils/dom'; import { StartConfig } from '../utils/start'; import { humpToTarget } from '../utils/string'; +const modelContainer = el('div', { className: 'model-container' }); +const messageContainer = el('div', { className: 'message-container' }); + const InitPanelScript = new Script({ name: '初始化页面', url: [/.*/], @@ -18,7 +23,6 @@ const InitPanelScript = new Script({ y: { defaultValue: window.innerWidth * 0.1 }, visual: { defaultValue: 'normal' }, expandAll: { defaultValue: false }, - alerts: { defaultValue: '' }, currentPanelName: { defaultValue: 'init.panel' } }, onactive({ style, projects }: StartConfig) { @@ -255,11 +259,12 @@ const InitPanelScript = new Script({ const { profile, projectSelector, logo, expandSwitcher, visualSwitcher, closeButton } = createHeader(); // 创建样式元素 - container.append(el('style', { textContent: style || '' })); + container.append(el('style', { textContent: style || '' }), messageContainer); container.header.append(profile, projectSelector, logo, expandSwitcher, visualSwitcher, closeButton); + replaceBody(); // 插入操作面板到页面 - panel.attachShadow({ mode: 'closed' }).append(container); + panel.attachShadow({ mode: 'closed' }).append(modelContainer, container); document.body.appendChild(panel); handlePosition(); } @@ -274,8 +279,45 @@ export const InitProject: Project = { scripts: [InitPanelScript] }; -export function $alert(message: string) { - const key = namespaceKey(InitPanelScript.namespace, 'alerts'); - const value = getConfig(key); - setConfig(key, value + message + '\n'); +/** + * 创建一个模态框代替原生的 alert, confirm, prompt + */ +export function $model( + attrs: Pick & { + disableWrapperCloseable?: boolean; + title?: string; + } +) { + const { disableWrapperCloseable, onConfirm, onCancel, ..._attrs } = attrs; + modelContainer.append( + el('div', { className: 'model-wrapper' }, (wrapper) => { + const model = el('model-element', { + onConfirm(val) { + onConfirm?.apply(model, [val]); + wrapper.remove(); + }, + onCancel() { + onCancel?.apply(model); + wrapper.remove(); + }, + ..._attrs + }); + wrapper.append(model); + + model.addEventListener('click', (e) => { + e.stopPropagation(); + }); + if (!disableWrapperCloseable) { + /** 点击遮罩层关闭模态框 */ + wrapper.addEventListener('click', () => wrapper.remove()); + } + }) + ); +} + +/** + * 消息推送 + */ +export function $message(attrs: Pick) { + messageContainer.append(el('message-element', attrs)); }