From 7a2ef864a3273bb5a25fb0817fa2fce1101e4d5c Mon Sep 17 00:00:00 2001 From: veypi Date: Wed, 23 Oct 2024 16:56:11 +0800 Subject: [PATCH] feat: add js base build function --- oaer/lib/assets/css/oaer.scss | 67 ++++++++++++++++++++++++--- oaer/lib/cfg.ts | 17 +++++-- oaer/lib/components/account.ts | 43 ++++++----------- oaer/lib/components/app.ts | 24 ++++++++++ oaer/lib/components/base.ts | 73 ----------------------------- oaer/lib/components/build.ts | 84 ++++++++++++++++++++++++++++++++++ oaer/lib/components/index.ts | 25 +++++----- oaer/lib/components/slide.ts | 48 +++++++++---------- 8 files changed, 233 insertions(+), 148 deletions(-) create mode 100644 oaer/lib/components/app.ts delete mode 100644 oaer/lib/components/base.ts create mode 100644 oaer/lib/components/build.ts diff --git a/oaer/lib/assets/css/oaer.scss b/oaer/lib/assets/css/oaer.scss index 5ae7a0a..1bdbc19 100644 --- a/oaer/lib/assets/css/oaer.scss +++ b/oaer/lib/assets/css/oaer.scss @@ -7,12 +7,21 @@ @import "./animate.scss"; -:root { - --bg-base: #efefef; - --fg-base: #090909 + +div[voa] { + box-sizing: border-box; + --oabg-base: var(--bg-base, #efefef); + --oafg-base: var(--fg-base, #090909); + --oaheader-bg: linear-gradient(90deg, #6849E1, #b09ef4); + + div { + box-sizing: border-box; + } } + .voa { + user-select: none; cursor: pointer; height: inherit; @@ -102,7 +111,7 @@ position: relative; width: 100%; height: 4rem; - background: linear-gradient(90deg, #6849E1, #b09ef4); + background: var(--oaheader-bg); z-index: 1; } @@ -110,13 +119,22 @@ position: relative; width: 100%; height: calc(100% - 4rem); - background: var(--bg-base); - color: var(--fg-base); + background: var(--oabg-base); + color: var(--oafg-base); transform: translateY(-140%); .voa-slide-main { height: calc(100% - 3rem); overflow: auto; + padding: 1rem; + + .voa-sm-separate { + height: 1px; + margin: 1rem 0; + background: var(--oafg-base); + width: 100%; + opacity: 0.4; + } } .voa-slide-footer { @@ -137,6 +155,43 @@ } } +.voa-account { + padding: 0 1rem; + + .voa-account-header { + display: flex; + justify-content: space-between; + align-items: center; + height: 3rem; + line-height: 3rem; + font-size: 1.25rem; + } + + .voa-account-body { + width: 100%; + height: 7rem; + display: flex; + align-items: center; + gap: 2rem; + + .voa-ab-ico { + display: contents; + + img { + width: 4rem; + height: 4rem; + vertical-align: middle; + border-radius: 50%; + } + } + + .voa-ab-info { + display: flex; + flex-direction: column; + } + } +} + .voa-logo { background-image: url("../favicon.svg"); diff --git a/oaer/lib/cfg.ts b/oaer/lib/cfg.ts index 4072c72..0fbd324 100644 --- a/oaer/lib/cfg.ts +++ b/oaer/lib/cfg.ts @@ -12,6 +12,13 @@ let cfg = { app_data: {}, + user: { + username: 'asd', + nickname: '', + email: '', + phone: '', + icon: 'https://public.veypi.com/img/avatar/0001.jpg' + }, ready: false, local_user: {}, @@ -20,7 +27,7 @@ let cfg = { nats_pub_key: '', prefix: '/api', BaseUrl() { - return this.host.value + this.prefix + return this.host + this.prefix }, NatsHost() { if (this._host_nats.startsWith('ws')) { @@ -29,7 +36,7 @@ let cfg = { return 'ws://' + this._host_nats }, media(u: string) { - return this.host.value + u + return this.host + u }, goto(url: string) { if (url.startsWith('http')) { @@ -39,16 +46,16 @@ let cfg = { if (!url.startsWith('/')) { url = '/' + url } - window.location.href = this.host.value + url + window.location.href = this.host + url }, Host() { - return this.host.value || window.location.host + return this.host || window.location.host }, userFileUrl() { return '/fs/u/' }, appFileUrl() { - return `/fs/a/${this.uuid.value}/` + return `/fs/a/${this.uuid}/` }, } diff --git a/oaer/lib/components/account.ts b/oaer/lib/components/account.ts index 0642d35..90f25c8 100644 --- a/oaer/lib/components/account.ts +++ b/oaer/lib/components/account.ts @@ -4,36 +4,23 @@ * 2024-10-22 22:07 * Distributed under terms of the GPL license. */ -import Base from './base' +import b from './build' +import cfg from '../cfg' -export default class extends Base { - doms: { [key: string]: HTMLElement } +export default class { 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 = ` -
-
my account
-
account center
-
-
-
- -
-
-
昵称: ${u.username}
-
昵称: ${u.username}
-
昵称: ${u.username}
-
昵称: ${u.username}
-
-
-` + this.main = b('voa-account', [ + b('voa-account-header', [b('voa-ah-1', '我的账户'), b('voa-ah-2')]), + b('voa-account-body', [ + b('voa-ab-ico', [b('img', '', (d) => { d.setAttribute('src', cfg.user.icon) })]), + b('voa-ab-info', [ + b('voa-abi-1', [b('span', '昵称:'), b('span', '', (d) => { d.innerHTML = cfg.user.nickname })]), + b('voa-abi-2', [b('span', '账户:'), b('span', '', (d) => { d.innerHTML = cfg.user.username })]), + b('voa-abi-3', [b('span', '邮箱:'), b('span', '', (d) => { d.innerHTML = cfg.user.email })]), + b('voa-abi-4', [b('span', '手机:'), b('span', '', (d) => { d.innerHTML = cfg.user.phone })]), + ]) + ]) + ]) } } diff --git a/oaer/lib/components/app.ts b/oaer/lib/components/app.ts new file mode 100644 index 0000000..1926cf4 --- /dev/null +++ b/oaer/lib/components/app.ts @@ -0,0 +1,24 @@ +/* + * app.ts + * Copyright (C) 2024 veypi + * 2024-10-23 15:35 + * Distributed under terms of the GPL license. + */ + +import b from "./build"; + + +export default class { + main: HTMLElement + body: HTMLElement + constructor() { + this.body = b('voa-apps-body') + this.main = b({ + class: 'voa-apps', + children: [ + b({ class: 'voa-apps-header', children: [b('voa-apps-title')] }), + this.body + ] + }) + } +} diff --git a/oaer/lib/components/base.ts b/oaer/lib/components/base.ts deleted file mode 100644 index 67bf95f..0000000 --- a/oaer/lib/components/base.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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/build.ts b/oaer/lib/components/build.ts new file mode 100644 index 0000000..9e028f1 --- /dev/null +++ b/oaer/lib/components/build.ts @@ -0,0 +1,84 @@ +/* + * build.ts + * Copyright (C) 2024 veypi + * 2024-10-23 15:54 + * Distributed under terms of the GPL license. + */ + + +interface buildOpts { + id?: string + typ?: string + class?: string + style?: string + innerHtml?: string + onclick?: any + children?: HTMLElement[] + updator?: (p: HTMLElement) => void +} + +const typs = ['div', 'img', 'span', 'p', 'a'] +const caches: (() => void)[] = [] +function update() { + for (let c of caches) { + c() + } +} +export { update } + +export default (opts: buildOpts | string, inner?: string | HTMLElement[], updator?: (p: HTMLElement) => void) => { + if (typeof opts === 'string') { + if (typs.indexOf(opts) >= 0) { + opts = { typ: opts } + } else { + opts = { class: opts } + } + } + if (inner) { + if (typeof inner == 'string') { + opts.innerHtml = inner + } else { + opts.children = inner + } + } + if (opts.updator) { + updator = opts.updator + } + let dom = document.createElement(opts.typ || 'div') + if (opts.id) { + dom.id = opts.id + } + if (opts.class) { + dom.classList.add(...opts.class.split(' ')) + } + 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: any + 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) + } + } + dom.setAttribute('voa', '1') + if (updator) { + caches.push(() => { + updator(dom) + }) + updator(dom) + } + return dom +} + diff --git a/oaer/lib/components/index.ts b/oaer/lib/components/index.ts index f7025de..6266e95 100644 --- a/oaer/lib/components/index.ts +++ b/oaer/lib/components/index.ts @@ -6,15 +6,14 @@ */ import slide from './slide' -import Base from './base' +import b from './build' import bus from '../bus' -export default class extends Base { +export default class { slide: slide - frame: HTMLDivElement - frame_login?: HTMLDivElement - frame_user?: HTMLDivElement - constructor(frame: HTMLDivElement) { - super() + frame: HTMLElement + frame_login?: HTMLElement + frame_user?: HTMLElement + constructor(frame: HTMLElement) { this.frame = frame this.frame.classList.add('voa') this.slide = new slide() @@ -25,12 +24,12 @@ export default class extends Base { }) } mount_login() { - this.frame_login = this.build({ - class: 'off hover-line-b scale-in', + this.frame_login = b({ + class: 'voa-off voa-hover-line-b voa-scale-in', innerHtml: '登录', onclick: () => { console.log('click login') - this.addClass(this.frame_login!, 'scale-off') + this.frame_login?.classList.add('voa-scale-off') this.mount_user() } }) @@ -41,10 +40,10 @@ export default class extends Base { } mount_user() { let icon = 'https://public.veypi.com/img/avatar/0001.jpg' - this.frame_user = this.build({ - class: 'on scale-in', + this.frame_user = b({ + class: 'voa-on voa-scale-in', innerHtml: ` - + `, onclick: () => { this.slide.show() diff --git a/oaer/lib/components/slide.ts b/oaer/lib/components/slide.ts index fce4866..20fa365 100644 --- a/oaer/lib/components/slide.ts +++ b/oaer/lib/components/slide.ts @@ -4,7 +4,7 @@ * 2024-10-22 17:57 * Distributed under terms of the GPL license. */ -import Base from './base' +import b from './build' import bus from '../bus' import account from './account' @@ -17,41 +17,43 @@ mask footer * * */ -export default class extends Base { - mask: HTMLDivElement - slide: HTMLDivElement - header: HTMLDivElement +export default class { + mask: HTMLElement + slide: HTMLElement + header: HTMLElement body: HTMLElement main: HTMLElement footer: HTMLElement constructor() { - super() - this.header = this.build({ - class: 'slide-header animate-slow', + this.header = b({ + class: 'voa-slide-header voa-animate-slow', }) - this.footer = this.build({ - class: 'slide-footer', + this.footer = b({ + class: 'voa-slide-footer', innerHtml: 'logout', onclick: () => { bus.emit('logout') } }) - this.main = this.build({ - class: 'slide-main', - children: [new account().main] + this.main = b({ + class: 'voa-slide-main', + children: [ + new account().main, + b({ class: 'voa-sm-separate' }) + ] }) - this.body = this.build({ - class: 'slide-body animate-slow', + this.body = b({ + class: 'voa-slide-body voa-animate-slow', style: 'animation-delay: 300ms', children: [this.main, this.footer] }) - this.slide = this.build({ + this.slide = b({ id: 'voa-slide', - class: 'slide', + class: 'voa-slide', children: [this.header, this.body] }) - this.mask = this.build({ - class: 'slide-mask', + this.mask = b({ + class: 'voa-slide-mask', style: 'visibility: hidden', children: [this.slide], onclick: (e: MouseEvent) => { @@ -64,12 +66,12 @@ export default class extends Base { } show() { this.mask.style.visibility = 'visible' - this.addClass(this.header, 'slidein-right') - this.addClass(this.body, 'slidein-up') + this.header.classList.add('voa-slidein-right') + this.body.classList.add('voa-slidein-up') } hide() { this.mask.style.visibility = 'hidden' - this.removeClass(this.header, 'slidein-right') - this.removeClass(this.body, 'slidein-up') + this.header.classList.remove('voa-slidein-right') + this.body.classList.remove('voa-slidein-up') } }