From 3cadef35be91e769484df3474c911afe01134752 Mon Sep 17 00:00:00 2001 From: veypi Date: Tue, 22 Oct 2024 22:50:44 +0800 Subject: [PATCH] feat: add oaer --- oaer/index.html | 2 +- oaer/lib/assets/css/animate.scss | 74 +++++++++++++++++-- oaer/lib/assets/css/oaer.scss | 120 ++++++++++++++++++++----------- oaer/lib/bus.ts | 11 +++ oaer/lib/components/account.ts | 39 ++++++++++ oaer/lib/components/base.ts | 73 +++++++++++++++++++ oaer/lib/components/index.ts | 60 ++++++++++++++++ oaer/lib/components/slide.ts | 75 +++++++++++++++++++ oaer/lib/logic.ts | 0 oaer/lib/main.ts | 108 +++++----------------------- oaer/package.json | 3 +- oaer/src/main.ts | 2 +- oaer/src/style.css | 14 +++- oaer/yarn.lock | 5 ++ 14 files changed, 443 insertions(+), 143 deletions(-) create mode 100644 oaer/lib/bus.ts create mode 100644 oaer/lib/components/account.ts create mode 100644 oaer/lib/components/base.ts create mode 100644 oaer/lib/components/index.ts create mode 100644 oaer/lib/components/slide.ts create mode 100644 oaer/lib/logic.ts diff --git a/oaer/index.html b/oaer/index.html index 4e650ad..399bff7 100644 --- a/oaer/index.html +++ b/oaer/index.html @@ -10,7 +10,7 @@
-
+
diff --git a/oaer/lib/assets/css/animate.scss b/oaer/lib/assets/css/animate.scss index 1ce66c4..25fef38 100644 --- a/oaer/lib/assets/css/animate.scss +++ b/oaer/lib/assets/css/animate.scss @@ -5,11 +5,65 @@ * Distributed under terms of the MIT license. */ -@keyframes scale-up { +:root { + --vanimate-time: 200ms +} + +.voa-animate-slow { + --vanimate-time: 300ms +} + +.voa-hover-line-b { + cursor: pointer; + position: relative; + + &:hover { + opacity: 0.7; + } + + &:after { + content: ""; + position: absolute; + bottom: 0; + left: 50%; + width: 0; + height: 0.1em; + background-color: #000; + transition: all 0.3s; + } + + &:hover::after { + left: 0px; + width: 100%; + } +} + +.voa-scale-off { + transform-origin: center center; + animation: scale-off var(--vanimate-time) ease-out forwards !important; +} + +.voa-scale-in { + transform-origin: center center; + animation: scale-in var(--vanimate-time) ease-in forwards; +} + +.voa-slidein-right { + animation: slidein-right var(--vanimate-time) ease-in forwards; + +} + +.voa-slidein-up { + animation: slidein-up var(--vanimate-time) ease-in forwards; +} + + +@keyframes scale-in { 0% { transform: scale(0); opacity: 0; } + 100% { transform: scale(1); opacity: 1; @@ -21,19 +75,29 @@ transform: scale(1); opacity: 1; } + 100% { transform: scale(0); opacity: 0; } } -@keyframes slide-in { +@keyframes slidein-up { 0% { - transform: translateX(200%) scale(0); - opacity: 0; + transform: translateY(-100%) scale(1); } + + 100% { + transform: translateX(0) scale(1); + } +} + +@keyframes slidein-right { + 0% { + transform: translateX(100%) scale(1); + } + 100% { transform: translateX(0) scale(1); - opacity: 1; } } diff --git a/oaer/lib/assets/css/oaer.scss b/oaer/lib/assets/css/oaer.scss index 93d2e2b..5ae7a0a 100644 --- a/oaer/lib/assets/css/oaer.scss +++ b/oaer/lib/assets/css/oaer.scss @@ -7,57 +7,41 @@ @import "./animate.scss"; +:root { + --bg-base: #efefef; + --fg-base: #090909 +} + .voa { user-select: none; cursor: pointer; - height: 4rem; - width: 4rem; + height: inherit; + width: inherit; display: flex; justify-content: center; align-items: center; - .voa-off { - } + + .voa-off {} + .voa-on { border-radius: 100%; background: #999; - animation: scale-up 100ms ease-out forwards; + height: inherit; + width: inherit; + + img { + height: inherit; + width: inherit; + vertical-align: middle; + border-radius: 50%; + } } + :hover { opacity: 0.9; } } -.voa-scale-off { - transform-origin: center center; - animation: scale-off 200ms ease-out forwards !important; -} -.voa-scale-up { - animation: scale-up 200ms ease-in; -} - -.hover-line-b { - cursor: pointer; - position: relative; - &:hover { - opacity: 0.7; - } - - &:after { - content: ""; - position: absolute; - bottom: 0; - left: 50%; - width: 0; - height: 0.1em; - background-color: #000; - transition: all 0.3s; - } - - &:hover::after { - left: 0px; - width: 100%; - } -} .voa-modal { user-select: none; @@ -69,6 +53,7 @@ z-index: 10000; width: 40%; min-width: 20rem; + &::before { content: ""; position: absolute; @@ -78,19 +63,21 @@ height: 100%; border-radius: 2rem; background-color: rgba(240, 240, 240, 0.5); - backdrop-filter: blur(20px); /* 模糊效果 */ + backdrop-filter: blur(20px); + /* 模糊效果 */ z-index: -1; } } -#voa-mask { +.voa-slide-mask { position: fixed; - display: none; + visibility: hidden; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 999; + &::before { content: ""; position: absolute; @@ -98,11 +85,59 @@ left: 0; width: 100%; height: 100%; - background: rgba(255, 255, 255, 0.01); /* 半透明白色遮罩 */ - backdrop-filter: blur(1px); /* 模糊效果 */ + background: rgba(255, 255, 255, 0.11); + /* 半透明白色遮罩 */ + backdrop-filter: blur(1px); + /* 模糊效果 */ + } + + .voa-slide { + position: absolute; + top: 0; + right: 0; + height: 100vh; + width: 20rem; + + .voa-slide-header { + position: relative; + width: 100%; + height: 4rem; + background: linear-gradient(90deg, #6849E1, #b09ef4); + z-index: 1; + } + + .voa-slide-body { + position: relative; + width: 100%; + height: calc(100% - 4rem); + background: var(--bg-base); + color: var(--fg-base); + transform: translateY(-140%); + + .voa-slide-main { + height: calc(100% - 3rem); + overflow: auto; + } + + .voa-slide-footer { + border-top: solid 2px #000; + height: 3rem; + font-size: 1.5rem; + line-height: 3rem; + text-align: center; + cursor: pointer; + box-sizing: border-box; + opacity: 0.6; + + &:hover { + opacity: 1; + } + } + } } } + .voa-logo { background-image: url("../favicon.svg"); background-size: cover; @@ -114,6 +149,7 @@ text-align: center; display: block; border: none; + &::after { content: ""; position: absolute; @@ -121,10 +157,12 @@ border-radius: inherit; transition: 0.3s; } + &:active::after { box-shadow: 0 1px 0px 0px rgba(0, 0, 0, 0.5); /* opacity: 0; */ } + &:active { opacity: 0.8; } diff --git a/oaer/lib/bus.ts b/oaer/lib/bus.ts new file mode 100644 index 0000000..63c4b2d --- /dev/null +++ b/oaer/lib/bus.ts @@ -0,0 +1,11 @@ +/* + * bus.ts + * Copyright (C) 2024 veypi + * 2024-10-22 21:46 + * Distributed under terms of the GPL license. + */ + +import mitt from "mitt"; + +const bus = mitt() +export default bus diff --git a/oaer/lib/components/account.ts b/oaer/lib/components/account.ts new file mode 100644 index 0000000..0642d35 --- /dev/null +++ b/oaer/lib/components/account.ts @@ -0,0 +1,39 @@ +/* + * account.ts + * Copyright (C) 2024 veypi + * 2024-10-22 22:07 + * Distributed under terms of the GPL license. + */ +import Base from './base' + +export default class extends Base { + doms: { [key: string]: HTMLElement } + main: HTMLElement + constructor() { + super() + this.main = this.build({ + class: 'voa-account' + }) + let u = { + username: 'asd', + icon: 'https://public.veypi.com/img/avatar/0001.jpg' + } + this.main.innerHTML = ` + + +` + } +} diff --git a/oaer/lib/components/base.ts b/oaer/lib/components/base.ts new file mode 100644 index 0000000..67bf95f --- /dev/null +++ b/oaer/lib/components/base.ts @@ -0,0 +1,73 @@ +/* + * base.ts + * Copyright (C) 2024 veypi + * 2024-10-22 18:21 + * Distributed under terms of the GPL license. + */ +interface buildOpts { + id?: string + typ?: 'div' + class?: string + style?: string + innerHtml?: string + onclick?: any + children?: HTMLElement[] +} + +export default class { + class_prefix: string + constructor(p?: string) { + this.class_prefix = p || 'voa-' + } + build(opts: buildOpts) { + let dom = document.createElement(opts.typ || 'div') + if (opts.id) { + dom.id = opts.id + } + if (opts.class) { + this.addClass(dom, opts.class) + } + if (opts.innerHtml) { + dom.innerHTML = opts.innerHtml + } + if (opts.onclick) { + dom.onclick = opts.onclick + } + if (opts.children) { + for (let c in opts.children) { + dom.appendChild(opts.children[c]) + } + } + if (opts.style) { + const regex = /([a-zA-Z-]+)\s*:\s*([^;]+);?/g; + let match; + while ((match = regex.exec(opts.style)) !== null) { + const key = match[1].trim(); + const value = match[2].trim(); + console.log([key, value]) + dom.style.setProperty(key, value) + } + } + return dom + } + addClass(dom: HTMLElement, c: string) { + let items = c.split(' ') + for (let i of items) { + if (i.startsWith(this.class_prefix)) { + dom.classList.add(i) + } else { + dom.classList.add(this.class_prefix + i) + } + } + } + removeClass(dom: HTMLElement, c: string) { + let items = c.split(' ') + for (let i of items) { + if (i.startsWith(this.class_prefix)) { + dom.classList.remove(i) + } else { + dom.classList.remove(this.class_prefix + i) + } + } + } +} diff --git a/oaer/lib/components/index.ts b/oaer/lib/components/index.ts new file mode 100644 index 0000000..f7025de --- /dev/null +++ b/oaer/lib/components/index.ts @@ -0,0 +1,60 @@ +/* + * index.ts + * Copyright (C) 2024 veypi + * 2024-10-22 17:51 + * Distributed under terms of the GPL license. + */ + +import slide from './slide' +import Base from './base' +import bus from '../bus' +export default class extends Base { + slide: slide + frame: HTMLDivElement + frame_login?: HTMLDivElement + frame_user?: HTMLDivElement + constructor(frame: HTMLDivElement) { + super() + this.frame = frame + this.frame.classList.add('voa') + this.slide = new slide() + this.mount_user() + bus.on('logout', () => { + this.mount_login() + this.slide.hide() + }) + } + mount_login() { + this.frame_login = this.build({ + class: 'off hover-line-b scale-in', + innerHtml: '登录', + onclick: () => { + console.log('click login') + this.addClass(this.frame_login!, 'scale-off') + this.mount_user() + } + }) + if (this.frame_user) { + this.frame.removeChild(this.frame_user) + } + this.frame.appendChild(this.frame_login) + } + mount_user() { + let icon = 'https://public.veypi.com/img/avatar/0001.jpg' + this.frame_user = this.build({ + class: 'on scale-in', + innerHtml: ` + +`, + onclick: () => { + this.slide.show() + // this.mount_login() + } + }) + if (this.frame_login) { + this.frame.removeChild(this.frame_login) + } + this.frame.appendChild(this.frame_user) + } +} + diff --git a/oaer/lib/components/slide.ts b/oaer/lib/components/slide.ts new file mode 100644 index 0000000..fce4866 --- /dev/null +++ b/oaer/lib/components/slide.ts @@ -0,0 +1,75 @@ +/* + * slide.ts + * Copyright (C) 2024 veypi + * 2024-10-22 17:57 + * Distributed under terms of the GPL license. + */ +import Base from './base' +import bus from '../bus' +import account from './account' + +/* +mask + slide + header + body + main + footer + * + * */ +export default class extends Base { + mask: HTMLDivElement + slide: HTMLDivElement + header: HTMLDivElement + body: HTMLElement + main: HTMLElement + footer: HTMLElement + constructor() { + super() + this.header = this.build({ + class: 'slide-header animate-slow', + }) + this.footer = this.build({ + class: 'slide-footer', + innerHtml: 'logout', + onclick: () => { + bus.emit('logout') + } + }) + this.main = this.build({ + class: 'slide-main', + children: [new account().main] + }) + this.body = this.build({ + class: 'slide-body animate-slow', + style: 'animation-delay: 300ms', + children: [this.main, this.footer] + }) + this.slide = this.build({ + id: 'voa-slide', + class: 'slide', + children: [this.header, this.body] + }) + this.mask = this.build({ + class: 'slide-mask', + style: 'visibility: hidden', + children: [this.slide], + onclick: (e: MouseEvent) => { + if (e.target === e.currentTarget) { + this.hide() + } + } + }) + document.body.appendChild(this.mask) + } + show() { + this.mask.style.visibility = 'visible' + this.addClass(this.header, 'slidein-right') + this.addClass(this.body, 'slidein-up') + } + hide() { + this.mask.style.visibility = 'hidden' + this.removeClass(this.header, 'slidein-right') + this.removeClass(this.body, 'slidein-up') + } +} diff --git a/oaer/lib/logic.ts b/oaer/lib/logic.ts new file mode 100644 index 0000000..e69de29 diff --git a/oaer/lib/main.ts b/oaer/lib/main.ts index 13a73d7..f6f1cdf 100644 --- a/oaer/lib/main.ts +++ b/oaer/lib/main.ts @@ -6,106 +6,30 @@ */ import './assets/css/oaer.scss' +import bus from './bus' +import ui from './components' export class OAer { - id: string - code: string - domid: string - dom: { - mask: HTMLDivElement - frame: HTMLDivElement - b0?: HTMLDivElement - b1?: HTMLDivElement - login_box?: HTMLDivElement - } - constructor(id: string, code: string, domid?: string) { - this.id = id - this.code = code - this.domid = domid || 'oaer' - this.dom = { - frame: document.querySelector(`#${this.domid}`)!, - mask: document.createElement('div'), + host: string + domid?: string + ui?: ui + constructor(host: string, domid?: string) { + this.host = host + if (domid) { + this.domid = domid + this.ui = new ui(document.querySelector(`#${this.domid}`)!) } - this.dom.mask.id = 'voa-mask' - document.body.appendChild(this.dom.mask) - this.dom.frame.classList.add('voa') - this.build_b0() - this.dom.frame.appendChild(this.dom.b0!) - this.offclick() } - build_b0() { - this.dom.b0 = document.createElement('div') - this.dom.b0.classList.add('hover-line-b') - this.dom.b0.onclick = () => { - console.log('click b0') - this.build_login() - // this.dom.b1?.classList.add('voa-animate-scale-off') - // this.build_b1() - // this.dom.frame.replaceChild(this.dom.b1!, this.dom.b0!) - } - this.dom.b0.innerHTML = ` - 登录 -` + login() { + bus.emit('login') } - build_login() { - if (this.dom.login_box) { - return - } - this.dom.login_box = document.createElement('div') - this.dom.login_box.classList.add('voa-modal', 'voa-scale-up') - this.dom.login_box.innerHTML = ` - -` - document.body.appendChild(this.dom.login_box) - document.querySelector('.voa-login-box .close')?.addEventListener('click', () => { - this.dom.login_box?.classList.add('voa-scale-off') - setTimeout(() => { - this.dom.login_box?.remove() - this.dom.login_box = undefined - }, 300) - }) - let uin = document.querySelector('.voa-login-box .username input') as HTMLInputElement - console.log(uin) + logout() { + bus.emit('logout') } - build_b1() { - this.dom.b1 = document.createElement('div') - this.dom.b1.classList.add('voa-on') - this.dom.b1.innerHTML = ` - -` - } - offclick() { + onlogout(fc: () => void) { + bus.on('logout', fc) } } - diff --git a/oaer/package.json b/oaer/package.json index ca21ce7..c62a177 100644 --- a/oaer/package.json +++ b/oaer/package.json @@ -30,6 +30,7 @@ }, "license": "Apache-2.0", "dependencies": { - "axios": "^1.7.2" + "axios": "^1.7.2", + "mitt": "^3.0.1" } } diff --git a/oaer/src/main.ts b/oaer/src/main.ts index 138854c..06b394d 100644 --- a/oaer/src/main.ts +++ b/oaer/src/main.ts @@ -1,6 +1,6 @@ import './style.css' import { OAer } from '../lib/main' -let t = new OAer('123', '') +let t = new OAer('http://localhost:3000', 'voa') console.log(t.domid) diff --git a/oaer/src/style.css b/oaer/src/style.css index 0e503e2..67ca46d 100644 --- a/oaer/src/style.css +++ b/oaer/src/style.css @@ -14,6 +14,10 @@ -moz-osx-font-smoothing: grayscale; } +html { + overflow: hidden; +} + body { margin: 0; padding: 0; @@ -28,7 +32,13 @@ body { #app { height: 80px; padding-right: 20px; + background: #efefef; + display: flex; + align-items: center; + justify-content: end; } -#oaer { - float: right; + +#voa { + height: 3rem; + width: 3rem; } diff --git a/oaer/yarn.lock b/oaer/yarn.lock index a777a67..d5c35c9 100644 --- a/oaer/yarn.lock +++ b/oaer/yarn.lock @@ -366,6 +366,11 @@ mime-types@^2.1.12: dependencies: mime-db "1.52.0" +mitt@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1" + integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== + nanoid@^3.3.7: version "3.3.7" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"