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 = `
+
+
+
+
+
+
+
昵称: ${u.username}
+
昵称: ${u.username}
+
昵称: ${u.username}
+
昵称: ${u.username}
+
+
+`
+ }
+}
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 = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Create Account
-
Forgot Password?
-
-
-
-`
- 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"