Merge branch 'master' into feature-component-modify

This commit is contained in:
wangguoqing 2022-10-13 09:17:01 +08:00
commit 8e9184300f
38 changed files with 1877 additions and 629 deletions

View File

@ -26,3 +26,5 @@
- fix bugs of container
- add gauss blur component
- change container's gesture function
- fix bugs of multiple fingers in container
- add pagination controller of container

View File

@ -11,10 +11,10 @@
],
"scripts": {
"dev": "vite",
"build": "yarn run esbuild:ts && yarn run build:ts",
"build": "yarn run esbuild:ts && yarn run build:ts && yarn build:widgets",
"build:ts": "yarn tsc --build tsconfig-all.json",
"build:vite": "vite build",
"build:widgets": "bin/build-widget",
"build:vite": "vite build && yarn build:widgets",
"build:widgets": "node ./tasks/build-widgets.js",
"esbuild:ts": "node ./tasks/esbuild-packages.js",
"format": "npm run format:prettier",
"format:prettier": "prettier \"**/*.{cjs,html,js,json,md,ts}\" --write"

View File

@ -1,5 +1,5 @@
import {CSSResultArray, LitElement, ReactiveElement} from 'lit'
import GestureDector, {
import GestureDetector, {
GestureEvents,
GestureOptions,
} from '../../lib/gesture/gesture-detector'
@ -26,17 +26,19 @@ export function StarMixin<T extends Constructor<ReactiveElement>>(
export type StarElementEventMap = HTMLElementEventMap & GestureEvents
export class StarBaseElement extends StarMixin(LitElement) {
gestureDetector!: GestureDetector
/**
*
*/
startGestureDetector(options?: GestureOptions) {
GestureDector.embedded(this, options)
GestureDetector.embedded(this, options)
}
/**
*
*/
stopGestureDetector() {
GestureDector.disembedded(this)
GestureDetector.disembedded(this)
}
/**

View File

@ -12,6 +12,7 @@ export class BrightnessSlider extends LitElement {
@property({type: Number}) barWidth = 0
@property({type: Number}) max = 100
@property({type: Number}) _value = 1
@property({type: Number}) progressLen = 0
@property() touchAction = {
// 触摸开始落点
start: {
@ -47,7 +48,7 @@ export class BrightnessSlider extends LitElement {
set value(value: number) {
this._value = value
let len = Math.floor((value * this.sliderBar.offsetWidth) / this.max)
let len = Math.round((value * this.sliderBar.offsetWidth) / this.max)
this.coverLen = len.toString()
}
@ -109,21 +110,21 @@ export class BrightnessSlider extends LitElement {
color: var(--icon-color-lm);
}
@media screen and (min-width: 900px) {
@media screen and (min-width: 300px) {
.sliderBar {
border-radius: 16px;
border-radius: 5px;
}
.progress {
border-radius: 16px;
border-radius: 5px;
}
.sliderBar::before {
width: 48px;
height: 48px;
left: 29px;
top: 29px;
font-size: 48px;
width: 16px;
height: 16px;
left: 10px;
top: 10px;
font-size: 16px;
}
}
@ -144,6 +145,24 @@ export class BrightnessSlider extends LitElement {
font-size: 24px;
}
}
@media screen and (min-width: 900px) {
.sliderBar {
border-radius: 16px;
}
.progress {
border-radius: 16px;
}
.sliderBar::before {
width: 48px;
height: 48px;
left: 29px;
top: 29px;
font-size: 48px;
}
}
`
handleEvent(event: TouchEvent) {
@ -151,36 +170,43 @@ export class BrightnessSlider extends LitElement {
case 'touchstart':
this.touchAction.start.clientX = event.touches[0].clientX
this.barWidth = this.sliderBar.offsetWidth
this.progressLen =
this.touchAction.start.clientX -
this.sliderBar.getBoundingClientRect().left
this.currentDistance = this.progressLen
break
case 'touchmove':
event.preventDefault()
this.touchAction.last.clientX = event.touches[0].clientX
this.distance =
this.touchAction.last.clientX - this.touchAction.start.clientX
this.currentDistance = this.distance + this.progress.offsetWidth
this.currentDistance = this.distance + this.progressLen
if (this.currentDistance < this.barWidth / this.max) {
// this.currentDistance = 0;
this.currentDistance = this.barWidth / this.max
this.currentDistance = Math.round(this.barWidth / this.max)
}
if (this.currentDistance > this.barWidth) {
this.currentDistance = this.barWidth
}
this.progress.style.setProperty('width', this.currentDistance + 'px')
this.coverLen = this.currentDistance.toString()
break
case 'touchend':
this.value = Math.floor(
let preValue = this.value
this.value = Math.round(
(this.currentDistance * this.max) / this.barWidth
)
this.dispatchEvent(
new CustomEvent('brightness-slider-change', {
detail: {
value: this.value,
},
bubbles: true,
composed: true,
})
)
if (preValue !== this.value) {
this.dispatchEvent(
new CustomEvent('brightness-slider-change', {
detail: {
value: this.value,
},
bubbles: true,
composed: true,
})
)
}
break
}
}

View File

@ -26,6 +26,7 @@ export const sharedStyles: CSSResult = css`
);
}
.star-clock-case {
position: relative;
display: inline-block;
width: 100%;
height: 100%;
@ -68,7 +69,7 @@ export const sharedStyles: CSSResult = css`
width: var(--autoPoint);
height: var(--autoPoint);
position: absolute;
right: 50%;
left: 50%;
top: 0;
background: linear-gradient(
90deg,
@ -86,7 +87,7 @@ export const sharedStyles: CSSResult = css`
transform-origin: 0 100%;
display: inline-block;
transform: translate(-50%, 0);
animation: anmiate-hour 86400s linear infinite;
animation: var(--anmiate-hour) 86400s linear infinite;
}
.star-clock-minute-hand {
position: absolute;
@ -96,7 +97,7 @@ export const sharedStyles: CSSResult = css`
transform-origin: 0 100%;
display: inline-block;
transform: translate(-50%, 0);
animation: anmiate-minute 3600s linear infinite;
animation: var(--anmiate-minute) 3600s linear infinite;
}
.star-clock-second-hand {
position: absolute;
@ -106,7 +107,7 @@ export const sharedStyles: CSSResult = css`
height: 43%;
transform-origin: 0 calc(100% - 16px);
transform: translate(-50%, 0);
animation: anmiate-second 60s linear infinite;
animation: var(--anmiate-second) 60s linear infinite;
}
/*有表盘浅色模式*/
.star-clock-main.light {
@ -166,7 +167,7 @@ export const sharedStyles: CSSResult = css`
border-radius: 12px;
z-index: 1;
transform: translate(-50%, 0);
animation: anmiate-hour 86400s linear infinite;
animation: var(--anmiate-hour) 86400s linear infinite;
}
.star-clock-minute-hand-transparent {
position: absolute;
@ -180,7 +181,7 @@ export const sharedStyles: CSSResult = css`
border-radius: 12px;
z-index: 1;
transform: translate(-50%, 0);
animation: anmiate-minute 3600s linear infinite;
animation: var(--anmiate-minute) 3600s linear infinite;
}
.star-clock-second-hand-transparent {
position: absolute;
@ -194,7 +195,7 @@ export const sharedStyles: CSSResult = css`
border-radius: 12px;
z-index: 0;
transform: translate(-50%, 0);
animation: anmiate-second 60s linear infinite;
animation: var(--anmiate-second) 60s linear infinite;
}
/*无表盘浅色模式*/
.star-clock-case-transparent.light .star-clock-point-transparent {

View File

@ -22,16 +22,12 @@ export class StarClock extends LitElement {
@state() rotateMinute = 0
@state() rotateSecond = 0
private _date: String = '0'
@property({type: String})
get date() {
return this._date
}
set date(val: String) {
console.log(val, 'val')
// 1664942295167 (长度13) // Wed Oct 05 2022 11:58:40 GMT+0800 (中国标准时间)
let dateMy = val.length <= 13 ? Number(val) : String(val)
val && this.dateUpdated(dateMy)
set date(val: Date | String | Number) {
if (val.constructor.toString().includes('String')) {
val.toString().length <= 13 ? (val = Number(val)) : ''
}
val && this.dateUpdated(val)
}
@query('.star-clock')
@ -71,7 +67,8 @@ export class StarClock extends LitElement {
>
<span
class="star-clock-point"
style="transform: rotate(${-(360 / 12) * item}deg)"
style="transform: rotate(${-(360 / 12) *
item}deg) translate(-50%, 0)"
></span>
</span>
`
@ -129,15 +126,12 @@ export class StarClock extends LitElement {
this.style.setProperty('--rotateSecond', this.rotateSecond + 'deg')
this.style.setProperty('--rotateMinute', this.rotateMinute + 'deg')
this.style.setProperty('--rotateHour', this.rotateHour + 'deg')
this.style.setProperty(
'--rotateSecondAfter',
this.rotateSecond + 360 + 'deg'
)
this.style.setProperty(
'--rotateMinuteAfter',
this.rotateMinute + 360 + 'deg'
)
this.style.setProperty('--rotateSecondAfter',this.rotateSecond + 360 + 'deg')
this.style.setProperty('--rotateMinuteAfter',this.rotateMinute + 360 + 'deg')
this.style.setProperty('--rotateHourAfter', this.rotateHour + 360 + 'deg')
this.style.setProperty('--anmiate-hour', 'anmiate-hour')
this.style.setProperty('--anmiate-minute', 'anmiate-minute')
this.style.setProperty('--anmiate-second', 'anmiate-second')
}
protected firstUpdated() {
this.resize()

View File

@ -1,6 +1,11 @@
import {html, css, LitElement, HTMLTemplateResult, nothing} from 'lit'
import {customElement, property, queryAssignedElements} from 'lit/decorators.js'
import {HeaderBarType} from '../header-bar/header-bar.js'
import {
customElement,
property,
query,
queryAssignedElements,
} from 'lit/decorators.js'
import {HeaderBar, HeaderBarType} from '../header-bar/header-bar.js'
import {IconControlBarType} from '../icon-control-bar/icon-control-bar.js'
import '../icon-control-bar/icon-control-bar.js'
import '../header-bar/header-bar.js'
@ -13,6 +18,7 @@ export enum DropDownMenuType {
export class DropDownMenu extends LitElement {
@property({type: DropDownMenuType}) type = ''
@queryAssignedElements({flatten: true}) slotElements!: HTMLSlotElement[]
@query('header-bar') headerBar!: HeaderBar
getOnlyTime(): HTMLTemplateResult {
return html`
<div class="inner">
@ -64,6 +70,10 @@ export class DropDownMenu extends LitElement {
}
}
observeTimeFormatChange() {
this.headerBar.autoUpdateDateTime()
}
static styles = css`
:host {
width: inherit;
@ -78,38 +88,39 @@ export class DropDownMenu extends LitElement {
}
.inner {
width: inherit;
height: inherit;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
@media screen and (min-width: 900px) {
@media screen and (min-width: 300px) {
header-bar[type='only-time'] {
dispaly: flex;
width: 512px;
height: 52px;
width: 170px;
height: 17px;
}
header-bar[type='date-time'] {
dispaly: flex;
width: 860px;
height: 64px;
width: 286px;
height: 21px;
}
.all-quick-icons {
width: 100%;
height: calc(100% - 52px);
height: calc(100% - 31px);
position: relative;
top: 40px;
// top: 40px;
top: 2.4%;
}
.others {
display: flex;
flex-direction: column;
position: absolute;
top: 100px;
top: 33.3px;
}
}
@ -128,9 +139,10 @@ export class DropDownMenu extends LitElement {
.all-quick-icons {
width: 100%;
height: calc(100% - 26px);
height: calc(100% - 46px);
position: relative;
top: 20px;
// top: 20px;
top: 2.4%;
}
.others {
@ -140,6 +152,34 @@ export class DropDownMenu extends LitElement {
top: 50px;
}
}
@media screen and (min-width: 900px) {
header-bar[type='only-time'] {
dispaly: flex;
width: 512px;
height: 52px;
}
header-bar[type='date-time'] {
dispaly: flex;
width: 860px;
height: 64px;
}
.all-quick-icons {
width: 100%;
height: calc(100% - 92px);
position: relative;
top: 2.4%;
}
.others {
display: flex;
flex-direction: column;
position: absolute;
top: 100px;
}
}
`
}

View File

@ -4,8 +4,8 @@ export default css`
:host {
position: relative;
display: block;
margin-top: var(--container-margin-top);
margin-left: var(--container-margin-left);
margin-top: var(--container-margin-top, 0px);
margin-left: var(--container-margin-left, 0px);
width: 100%;
height: 100%;
@ -31,11 +31,8 @@ export default css`
::slotted(.gaia-container-page) {
display: grid;
grid-template-columns: repeat(
var(--columns, 4),
calc(100% / var(--columns, 4))
);
grid-template-rows: repeat(var(--rows, 6), calc(100% / var(--rows, 6)));
grid-template-columns: repeat(var(--columns, 4), var(--grid-width));
grid-template-rows: repeat(var(--rows, 6), var(--grid-height));
grid-auto-flow: row dense;
grid-auto-rows: 33%;

View File

@ -95,7 +95,9 @@ const cubic_bezier = (
class GaiaContainer extends StarBaseElement {
name: string = 'gaia-container'
row: number = 6
_row: number = this.row
column: number = 4
_column: number = this.column
_frozen: boolean = false
ready: boolean = false
_pendingStateChanges: Function[] = []
@ -225,8 +227,8 @@ class GaiaContainer extends StarBaseElement {
exchangeTimer: number | undefined
constructor(row = 6, column = 4) {
super()
this.row = row
this.column = column
this.row = this._row = row
this.column = this._column = column
this.exchangeStratege = new ExchangeStrategy(this)
this.startGestureDetector({
panThreshold: 0,
@ -323,6 +325,7 @@ class GaiaContainer extends StarBaseElement {
set status(value) {
if (value !== this._status) {
this._status = value
this.dispatchEvent(
new CustomEvent('statuschange', {
detail: {
@ -333,7 +336,6 @@ class GaiaContainer extends StarBaseElement {
composed: true,
})
)
this._status = value
}
}
@ -341,41 +343,45 @@ class GaiaContainer extends StarBaseElement {
event.type === 'swipeleft' ? this.turnNext('swipe') : this.turnPre('swipe')
}
turnPre(type: string) {
turnPre(type: string, callback?: Function) {
if (this.pagination <= 0) {
this.pagination = 0
} else {
this.status |= STATUS.TURN
this.pagination--
}
this.resetView(type)
this.resetView(type, this.pagination, callback)
}
turnNext(type: string) {
turnNext(type: string, callback?: Function) {
if (this.pagination < this.pages.length - 1) {
this.pagination++
this.status |= STATUS.TURN
} else {
this.pagination = this.pages.length - 1
}
this.resetView(type)
this.resetView(type, this.pagination, callback)
}
resetView(type: string, pagination = this.pagination): boolean {
resetView(
type: string,
pagination = this.pagination,
callback?: Function
): boolean {
const target: HTMLElement = (this.pages as any)[pagination]
if (!target && pagination > 0) return this.resetView(type, --pagination)
this.smoothSlide(target, type)
this.smoothSlide(target, type, callback)
return true
}
// 同时触发划动时,不同触发原因的优先级顺序,越后越优先
typeIndex = ['reset', 'swipe', 'mouseup', 'touchend', 'holdend', 'panend']
typeIndex = ['', 'swipe', 'mouseup', 'touchend', 'holdend', 'panend', 'reset']
// 划动计时器
timer: Function | undefined = undefined
// 触发划动的原因类型
slideType: string = ''
smoothSlide(element: HTMLElement, type: string) {
smoothSlide(element: HTMLElement, type: string, callback?: Function) {
if (
!element ||
this.typeIndex.indexOf(this.slideType) > this.typeIndex.indexOf(type)
@ -386,11 +392,11 @@ class GaiaContainer extends StarBaseElement {
this.slideType = ''
}
const targetPagination = this.pages.indexOf(element)
const animateTime = 450
const animateTime = type == 'reset' ? 1 : 450
const target = -element.offsetLeft
const origin = this.offsetX
const origin = this.pages[0].getBoundingClientRect().left - this.left
// 移动总距离
const distance = target - origin
const distance = target - Number(origin)
const startTime = new Date().getTime()
this.dispatchEvent(
@ -406,14 +412,12 @@ class GaiaContainer extends StarBaseElement {
const cur = new Date().getTime()
const t = (cur - startTime) / animateTime
const ratio = cubic_bezier(0.2, 1, 0.95, 1, t)
this.offsetX = origin + parseInt(String(distance * ratio))
this.offsetX = Number(origin) + parseInt(String(distance * ratio))
// 在切换页面的时候,由以下代码控制拖拽元素的位置
if (this._status & STATUS.DRAG) {
this.status |= STATUS.SWIPE
;(
this._dnd.child as unknown as GaiaContainerChild
).container.style.transform =
;(this._dnd.child as GaiaContainerChild).container.style.transform =
'translate(' +
(this._dnd.left - this.offsetX) +
'px, ' +
@ -446,6 +450,7 @@ class GaiaContainer extends StarBaseElement {
this.status &= ~STATUS.SWIPE
// 如果处于拖拽状态则更新一次落点位置
this.continueDrag()
callback?.()
} else if (this.timer) {
this.timer()
}
@ -491,9 +496,15 @@ class GaiaContainer extends StarBaseElement {
if (value) {
this._dnd.delay = 0
this.status |= STATUS.SORT
// @ts-ignore
this.gestureDetector.setOption('holdThreshold', 100)
this.firstUpdated().then(this.addTailPage)
} else {
this._dnd.delay = DEFAULT_DND_TIMEOUT
this.status &= ~STATUS.SORT
// @ts-ignore
this.gestureDetector.setOption('holdThreshold', DEFAULT_DND_TIMEOUT)
this.removeTailPage()
}
this._sortMode = value
}
@ -501,12 +512,25 @@ class GaiaContainer extends StarBaseElement {
// TODO用于适应旋转屏幕时改变行数与列数需要配合row、column属性
changeLayout = () => {
// this.styleDom.innerHTML = this.shadowStyle;
// 更新位置与高度信息
const {height, width, top, left} = this.getBoundingClientRect()
this.height = height
this.width = width
this.top = top
this.left = left
if (screen.orientation.type.includes('portrait')) {
this.style.setProperty('--columns', String(this._column))
this.style.setProperty('--rows', String(this._row))
this.row = this._row
this.column = this._column
} else {
this.style.setProperty('--rows', String(this._column))
this.style.setProperty('--columns', String(this._row))
this.row = this._column
this.column = this._row
}
this.pageWidth = this.pages.length ? this.pages[0].offsetWidth : 0
this.pageHeight = this.pages.length ? this.pages[0].offsetHeight : 0
this.gridHeight = this.pageHeight / this.row
@ -516,16 +540,10 @@ class GaiaContainer extends StarBaseElement {
this.style.setProperty('--page-height', this.pageHeight + 'px')
this.style.setProperty('--grid-height', this.gridHeight + 'px')
this.style.setProperty('--grid-width', this.gridWidth + 'px')
if (screen.orientation.type.includes('portrait')) {
this.style.setProperty('--columns', String(this.column))
this.style.setProperty('--rows', String(this.row))
} else {
this.style.setProperty('--rows', String(this.column))
this.style.setProperty('--columns', String(this.row))
}
// this._children.forEach((child) => child.changeSize())
this.synchronise()
this.resetView('reset')
}
get containerChildren(): HTMLElement[] {
@ -613,6 +631,7 @@ class GaiaContainer extends StarBaseElement {
pagination: number = this.pagination
) {
let page = this.pages[pagination]
const {width, height} = page.getBoundingClientRect()
x += page.scrollLeft - page.offsetLeft
y += page.scrollTop - page.offsetTop
@ -620,6 +639,10 @@ class GaiaContainer extends StarBaseElement {
x = x < 0 ? 0 : x
y = y < 0 ? 0 : y
// 越界时,需要将落点坐标退回到分页内部
x = x > width ? width - 1 : x
y = y > height ? height - 1 : y
const coordinateX = parseInt(String(x / Math.floor(this.gridWidth)))
const coordinateY = parseInt(String(y / Math.floor(this.gridHeight)))
const gridId = coordinateX + coordinateY * this.column
@ -674,18 +697,18 @@ class GaiaContainer extends StarBaseElement {
if (!page) {
page = this.addPage()
}
const shadowPage = this.pages._shadowPagesMap.get(page)
let proto = HTMLElement.prototype.appendChild
let func
Array.prototype.forEach.call(args, (element) => {
const retainAfterRotate = this.appendShadowPage(element, page)
func = proto.call(page, element)
proto.call(shadowPage, this.getChildByElement(element)?.shadowContainer!)
// 判断插入节点后是否会越界
if (page.offsetHeight < page.scrollHeight) {
if (page.offsetHeight < page.scrollHeight || !retainAfterRotate) {
// 越界后判断是否需要重新拿出来放入下一个页面
if (this._status & STATUS.DRAG) {
// 如果是拖拽中的元素,则返回原位,同时记录本页面无法插入
// TODO: 拖拽中的元素应该强制放入
if (!this._staticElements.includes(page)) {
this._staticElements.push(page)
}
@ -711,6 +734,8 @@ class GaiaContainer extends StarBaseElement {
let func
Array.from(args).forEach((element) => {
const target = element.parentNode
const child = this.getChildByElement(element)
child?.shadowContainer?.remove()
let proto = HTMLElement.prototype.removeChild
func = proto.call(target, element)
@ -727,8 +752,12 @@ class GaiaContainer extends StarBaseElement {
const nodes = args as unknown as [HTMLElement, HTMLElement]
let proto = HTMLElement.prototype.insertBefore
let func = proto.apply(targetParent, nodes)
const retainAfterRotate = this.appendShadowPage(nodes[0], targetParent)
// 判断插入节点后是否会越界
if (targetParent.offsetHeight < targetParent.scrollHeight) {
if (
targetParent.offsetHeight < targetParent.scrollHeight ||
!retainAfterRotate
) {
this.insertCrossBorder(...nodes)
}
return func
@ -745,14 +774,18 @@ class GaiaContainer extends StarBaseElement {
if (!targetParent) throw new Error('parentElement does not exist!')
let func
if (targetParent.lastChild == args[1]) {
func = append.call(targetParent, arguments[0])
func = append.call(targetParent, args[0])
} else {
func = insert.call(targetParent, arguments[0], arguments[1].nextSibling)
func = insert.call(targetParent, args[0], args[1].nextSibling)
}
const retainAfterRotate = this.appendShadowPage(args[0], targetParent)
// 判断插入节点后是否会越界
if (targetParent.offsetHeight < targetParent.scrollHeight) {
this.insertCrossBorder(...arguments)
if (
targetParent.offsetHeight < targetParent.scrollHeight ||
!retainAfterRotate
) {
this.insertCrossBorder(...args)
}
return func
@ -791,6 +824,26 @@ class GaiaContainer extends StarBaseElement {
return this.realAppendChild(this.pagination + 1, args[0])
}
/**
*
* @returns boolean
*/
appendShadowPage(element: HTMLElement, page: HTMLElement) {
const shadowPage = this.pages._shadowPagesMap.get(page)!
const shadowChild = this.getChildByElement(element)?.shadowContainer!
if (!shadowPage || !shadowChild) {
return false
}
shadowPage.appendChild(shadowChild)
if (shadowPage.offsetHeight < shadowPage.scrollHeight) {
shadowPage.removeChild(shadowChild)
return false
} else {
return true
}
}
realReplaceChild(...args: [HTMLElement, HTMLElement]) {
let proto = HTMLElement.prototype.replaceChild
let func = proto.apply(this, args)
@ -908,8 +961,8 @@ class GaiaContainer extends StarBaseElement {
throw 'removeChild called on unknown child'
}
addPage() {
const {page, shadowPage} = this.pages.addPage()
addPage(pages?: {page: HTMLElement; shadowPage: HTMLElement}) {
const {page, shadowPage} = pages ?? this.pages.addPage()
HTMLElement.prototype.appendChild.call(this, page)
HTMLElement.prototype.appendChild.call(this, shadowPage)
@ -918,15 +971,28 @@ class GaiaContainer extends StarBaseElement {
this.pageHeight = page.offsetHeight
this.gridHeight = this.pageHeight / this.row
this.gridWidth = this.pageWidth / this.column
this.style.setProperty('--page-width', this.pageWidth + 'px')
this.style.setProperty('--page-height', this.pageHeight + 'px')
this.style.setProperty('--grid-height', this.gridHeight + 'px')
this.style.setProperty('--grid-width', this.gridWidth + 'px')
}
return page
}
addTailPage() {
if (this._status & STATUS.DRAG || this._status & STATUS.SORT) {
// 仅仅在拖动状态和编辑状态时,允许添加空白尾页
if (this.pages[this.pagination] == this.pages._tail) {
// 当当前页为尾页时,再行添加尾页前,需要去掉当前页面的尾页标记
this.pages._tail = undefined
}
this.pages.addTail()
}
}
removeTailPage() {
if (!(this._status & STATUS.SORT) && !(this._status & STATUS.DRAG)) {
this.pages.removeTail()
}
}
/**
* Reorders the given element to appear before referenceElement.
*/
@ -988,35 +1054,6 @@ class GaiaContainer extends StarBaseElement {
: 'reorderChild called on unknown child'
}
reorderChild_bak(callback?: Function) {
let children: GaiaContainerChild[] = []
let childCoordinate = []
this.pages.forEach((page, pagination) => {
let coordinates: {[gridId: number]: GaiaContainerChild} = {}
const nodes = Array.from(page.children)
for (const childMaster of nodes) {
const child = this.getChildByElement(childMaster as HTMLElement)
if (!child) continue
children.push(child)
for (let i = 0; i < child.row; i++) {
for (let j = 0; j < child.column; j++) {
coordinates[child.gridId + j + i * this.column] = child
}
}
}
childCoordinate[pagination] = coordinates
})
this._children = children
if (callback) {
callback()
}
return
}
insertContainerBefore(
element: HTMLElement,
reference: HTMLElement | null,
@ -1213,6 +1250,9 @@ class GaiaContainer extends StarBaseElement {
gridId,
this._dnd.child
).recommended
if (!this.childCoordinate[this.pagination]) {
this.childCoordinate[this.pagination] = {}
}
children = this.childCoordinate[this.pagination]
child = children[gridId]!
element = child?.element ?? this.pages[this.pagination]
@ -1269,15 +1309,20 @@ class GaiaContainer extends StarBaseElement {
this._dnd.lastDropChild = null
}
// 进行拖拽的手指未松开之前,即使其他手指松开也不会添加空白尾页
if (!(this._status & STATUS.DRAG)) {
this.addTailPage()
}
this.removeTailPage()
this._dnd.child = null
this._dnd.isSpanning = false
this.status &= ~STATUS.DRAG
this.exchangeStratege.reset()
this.synchronise()
}
startDrag() {
this.status |= STATUS.DRAG
this.addTailPage()
const child = this._dnd.child
this._staticElements = [child.element]
this._dnd.start.translateX = child.master.offsetLeft
@ -1328,7 +1373,8 @@ class GaiaContainer extends StarBaseElement {
let left =
(this._dnd.start.translateX as number) -
this.holdDistanceX -
this.pages[this._dnd.pagination!].offsetLeft
this.pages[this._dnd.pagination!].offsetLeft -
this.panDistanceX * this.ratio
let top = (this._dnd.start.translateY as number) - this.holdDistanceY
this._dnd.left = left
this._dnd.top = top
@ -1401,9 +1447,11 @@ class GaiaContainer extends StarBaseElement {
) {
// 拖动中的节点距离分页DOM左上角距离 = 定位坐标 + 手指移动距离 + 与原本页面距离
const distanceX =
gridX ?? this._dnd.gridPosition.x + this.panDistanceX - this.holdDistanceX
this.offsetWidth *
(this.pagination - (this._dnd.pagination ?? this.pagination))
gridX ??
this._dnd.gridPosition.x -
this.holdDistanceX +
this.offsetWidth *
(this.pagination - (this._dnd.pagination ?? this.pagination))
const distanceY =
gridY ??
this._dnd.gridPosition.y +
@ -1699,10 +1747,8 @@ class GaiaContainer extends StarBaseElement {
gridId: number
) {
let resolve!: Function
let reject!: Function
let promise = new Promise((res, rej) => {
let promise = new Promise((res) => {
resolve = res
reject = rej
})
for (let row = 0; row < child.row; row++) {
@ -1712,7 +1758,6 @@ class GaiaContainer extends StarBaseElement {
this.childCoordinate[pagination][targetId] != undefined &&
this.childCoordinate[pagination][targetId] != child
) {
reject()
return false
}
promise.then(() => {
@ -1892,7 +1937,7 @@ class GaiaContainer extends StarBaseElement {
}
handleTransformRatio(x: number) {
if (this._status & STATUS.DRAG) return 1
// if (this._status & STATUS.DRAG) return 1
const percentage = Math.abs(x) / this.pageHeight
this.ratio = 1
@ -1960,6 +2005,7 @@ class GaiaContainer extends StarBaseElement {
) {
this.handleEnd(event)
} else {
this.status &= ~STATUS.DRAG
this.endDrag(event)
}
break
@ -2014,14 +2060,6 @@ class GaiaContainer extends StarBaseElement {
this._dnd.start.clientX = event.touches[0].clientX
this._dnd.start.clientY = event.touches[0].clientY
}
// const detail = (event as CustomEvent).detail
// // 用于计算滑动页面距离
// this._dnd.start.pageX = detail.touches[0].pageX
// this._dnd.start.pageY = detail.touches[0].pageY
// // 用于计算拖动图标距离
// this._dnd.start.clientX = detail.touches[0].clientX
// this._dnd.start.clientY = detail.touches[0].clientY
this._dnd.last.pageX = this._dnd.start.pageX
this._dnd.last.pageY = this._dnd.start.pageY
@ -2055,15 +2093,6 @@ class GaiaContainer extends StarBaseElement {
} else if (this._dnd.delay <= 0) {
this.startDrag()
}
// if (this._dnd.delay > 0) {
// this._dnd.timeout = window.setTimeout(() => {
// this._dnd.timeout = undefined
// this.startDrag()
// }, this._dnd.delay)
// } else {
// this.startDrag()
// }
}
handleHoldMove(event: CustomEvent) {
@ -2074,8 +2103,6 @@ class GaiaContainer extends StarBaseElement {
this.holdDistanceY = this._dnd.start.clientY - clientY
if (this._dnd.active) {
event.preventDefault()
// this._dnd.last.pageX = pageX
// this._dnd.last.pageY = pageY
this._dnd.last.clientX = clientX
this._dnd.last.clientY = clientY
this._dnd.last.timeStamp = event.timeStamp
@ -2084,10 +2111,8 @@ class GaiaContainer extends StarBaseElement {
}
if (this._dnd.child?.priority == 1 && !this._dnd.child.isFolder) {
const centerX =
this.left + this._dnd.center.x + this.panDistanceX - this.holdDistanceX
const centerY =
this.top + this._dnd.center.y + this.panDistanceY - this.holdDistanceY
const centerX = this.left + this._dnd.center.x - this.holdDistanceX
const centerY = this.top + this._dnd.center.y - this.holdDistanceY
const elementHeight = this._dnd.child.element.offsetHeight
const elementWidth = this._dnd.child.element.offsetWidth
@ -2135,40 +2160,16 @@ class GaiaContainer extends StarBaseElement {
return
}
let pageX: number, pageY: number /* , clientX, clientY */
this.panDistanceX = event.detail.absolute.dx
this.panDistanceY = event.detail.absolute.dy
pageX = (event as CustomEvent).detail.touches[0].pageX
pageY = (event as CustomEvent).detail.touches[0].pageY
this.panDistanceX = pageX - this._dnd.last.pageX
this.panDistanceY = pageY - this._dnd.last.pageY
const ratio = this.handleTransformRatio(this.panDistanceX)
this.handleTransformRatio(this.panDistanceX)
this.continueDrag()
this.istouching &&
(this.status |= STATUS.SWIPE) &&
(this.style.transform = `translateX(${
parseInt(String(this.panDistanceX * ratio)) + this.offsetX
parseInt(String(this.panDistanceX * this.ratio)) + this.offsetX
}px`)
// }
/* if (this._dnd.timeout) {
if (
Math.abs(pageX - this._dnd.start.pageX) > DND_THRESHOLD ||
Math.abs(pageY - this._dnd.start.pageY) > DND_THRESHOLD
) {
clearTimeout(this._dnd.timeout)
this._dnd.timeout = undefined
}
} else if (this._dnd.active) {
event.preventDefault()
this._dnd.last.pageX = pageX
this._dnd.last.pageY = pageY
this._dnd.last.clientX = clientX
this._dnd.last.clientY = clientY
this._dnd.last.timeStamp = event.timeStamp
this.continueDrag()
}*/
}
handleEnd(event: CustomEvent) {
@ -2179,27 +2180,18 @@ class GaiaContainer extends StarBaseElement {
}
this.istouching = false
if (!(this._status & STATUS.DRAG)) {
this.offsetX += +this.panDistanceX * this.ratio
this.ratio = 1
if (Math.abs(this.panDistanceX) < this.width / 2) {
} else if (this.panDistanceX > 0) {
this.turnPre(event.type)
} else {
this.turnNext(event.type)
}
this.panDistanceX = 0
this.panDistanceY = 0
this.offsetX += +this.panDistanceX * this.ratio
this.ratio = 1
if (Math.abs(this.panDistanceX) < this.width / 2) {
} else if (this.panDistanceX > 0) {
this.turnPre(event.type)
} else {
// this._dnd.child?.container?.style.setProperty(
// '--offset-position-left',
// '0px'
// )
// this._dnd.child?.container?.style.setProperty(
// '--offset-position-top',
// '0px'
// )
this.turnNext(event.type)
}
this.panDistanceX = 0
this.panDistanceY = 0
this.continueDrag()
this.resetView('')
if (this._dnd.active) {
@ -2262,9 +2254,6 @@ class GaiaContainer extends StarBaseElement {
child.synchroniseMaster()
// }
}
if (Object.keys(this.folders).length) {
// debugger
}
for (let i = 0; i < children.length; i++) {
child = children[i]
@ -2274,6 +2263,7 @@ class GaiaContainer extends StarBaseElement {
if (!child.synchroniseContainer(isActive)) {
return
}
child.anchor()
// 越界
// if (!isActive) {

View File

@ -70,7 +70,7 @@ export default class GaiaContainerChild {
this.priority = row * column
this.manager = manager
this._isStatic = false
this.anchorCoordinate = anchorCoordinate ?? defaultCoordinate // 两种屏幕方向的锚固坐标
this.anchorCoordinate = anchorCoordinate ?? {...defaultCoordinate} // 两种屏幕方向的锚固坐标
this.markDirty()
}
@ -169,7 +169,7 @@ export default class GaiaContainerChild {
* Grid
*/
anchor(type: anchorType = 'recorder') {
const area = this.getArea(type)
const area = this.setArea(type)
if (!area) return
const [rowStart, columnStart] = area
@ -194,14 +194,12 @@ export default class GaiaContainerChild {
return this.anchorCoordinate[orientation]
}
const unitHeight = this.master.offsetHeight / this.row
const unitWidth = this.master.offsetWidth / this.column
const offsetTop = Math.abs(this.master.offsetTop)
const offsetLeft = Math.abs(
this.master.offsetLeft - this.pagination * this.manager.pageHeight
)
const rowStart = Math.floor(offsetTop / unitHeight) + 1
const columnStart = Math.floor(offsetLeft / unitWidth) + 1
const rowStart = Math.floor(offsetTop / this.manager.gridHeight) + 1
const columnStart = Math.floor(offsetLeft / this.manager.gridWidth) + 1
return [rowStart, columnStart]
}
@ -220,8 +218,8 @@ export default class GaiaContainerChild {
*
*/
loosen() {
const orientation = screen.orientation.type.split('-')[0]
this.anchorCoordinate[orientation] = null
// const orientation = screen.orientation.type.split('-')[0]
// this.anchorCoordinate[orientation] = null
this.master.style.gridArea = 'unset'
this.master.style.gridRowStart = `span ${this.row}`
this.master.style.gridColumnStart = `span ${this.column}`

View File

@ -1,19 +1,32 @@
import GaiaContainer from './container'
import {STATUS} from './contianer-interface'
class GaiaContainerPage {
_pages: HTMLElement[] = [] // 存储所有添加进 gaia-container 的页面
// 等待被移除的页面,仅在编辑、拖拽时出现,若结束前两种状态时仍然没有子节点,则删除
_suspending: HTMLElement | null = null
_suspending: HTMLElement[] = []
_manager: GaiaContainer
_shadowPagesMap: WeakMap<HTMLElement, HTMLElement> = new WeakMap()
_tail: HTMLElement | undefined
_shadowTail: HTMLElement | undefined
observerCallback: MutationCallback
constructor(manager: GaiaContainer) {
this._manager = manager
this._manager.addEventListener('statuschange', () => {
// gaia-container 退出拖拽模式,且有待删除页面
if (!(this._manager._status & 2) && this._suspending) {
this.deletePage(this._suspending)
if (
!(this._manager._status & STATUS.DRAG) &&
!(this._manager._status & STATUS.SORT) &&
this._suspending.length
) {
while (this._suspending.length) {
const page = this._suspending.shift()
this.deletePage(page)
}
this.removeTail()
this._manager.turnPre('reset')
}
})
@ -26,7 +39,6 @@ class GaiaContainerPage {
const page = mutation.target as HTMLElement
const container = page.parentElement as any
page.classList.add('removed')
const callback = () => {
if (!container || !page.dataset.page) return
if (
@ -37,7 +49,8 @@ class GaiaContainerPage {
}
if (this.editMode) {
this._suspending = page
// 处于编辑状态时,空白页不被删除
this._suspending.push(page)
} else {
this.deletePage(page)
}
@ -90,8 +103,26 @@ class GaiaContainerPage {
}
}
addTail = () => {
if (!this._tail || !this._shadowTail || this._tail.children.length) {
const pages = this.addPage()
this._tail = pages.page
this._shadowTail = pages.shadowPage
this._manager.addPage({page: this._tail, shadowPage: this._shadowTail})
}
}
removeTail = () => {
if (!this._tail) return
this.deletePage(this._tail)
this._tail = undefined
this._shadowTail = undefined
}
get editMode() {
return this._manager._status & 2 || this._manager._status & 8
return (
this._manager._status & STATUS.DRAG || this._manager._status & STATUS.SORT
)
}
observe = (page: HTMLElement) => {
@ -102,43 +133,55 @@ class GaiaContainerPage {
})
}
deletePage = (page: HTMLElement) => {
if (page.children.length) return
deletePage = (page?: HTMLElement) => {
if (!page || page.children.length) return
let index = this._pages.indexOf(page)
if (this.editMode && index == this.length - 1) {
// 处于拖拽状态时,尾页不被删除
this._suspending = page
this._suspending.push(page)
return
}
if (this._pages.length < 2) {
// 页面数量少于1
return
}
delete this._pages[index]
this._manager.dispatchEvent(
new CustomEvent('page-change', {
detail: {
deleteIndex: index,
},
composed: true,
})
)
if (index > -1) {
page?.remove?.()
this._shadowPagesMap.get(page)?.remove?.()
delete this._pages[index]
let flag = false
let coordinates: GaiaContainer['childCoordinate'] = []
// @ts-ignore
this._pages = this._pages.filter((page, i) => {
if (flag) {
;(page.dataset.page as any) = --i
page.style.setProperty('--pagination', String(i))
}
if (i == index) flag = true
coordinates[i] = this._manager.childCoordinate[i - +flag]
return i !== index
})
this._manager.childCoordinate = coordinates
this.sortPagination()
this._manager.dispatchEvent(
new CustomEvent('page-change', {
detail: {
deleteIndex: index,
},
composed: true,
})
)
}
this._manager.synchronise()
}
sortPagination() {
this._pages.forEach((page, i) => {
page.dataset.page = String(i)
page.style.setProperty('--pagination', String(i))
this._shadowPagesMap
.get(page)
?.style.setProperty('--pagination', String(i))
})
}
get length() {

View File

@ -121,44 +121,44 @@ export class HeaderBar extends LitElement {
color: var(--time-date-date-color-dm);
}
@media screen and (min-width: 900px) {
@media screen and (min-width: 300px) {
.time-outer > #time {
height: 52px;
line-height: 52px;
font-size: 52px;
height: 17px;
line-height: 17px;
font-size: 17px;
}
.time-icons {
display: flex;
width: 136px;
width: 45px;
position: relative;
right: 4px;
right: 1px;
}
.time-icons > ::slotted(:last-child) {
position: relative;
left: 40px;
left: 13px;
}
.time-date {
line-height: 64px;
left: 10px;
line-height: 21px;
left: 3px;
}
.time-date > #time {
font-size: 64px;
font-size: 21px;
}
#date {
height: 34px;
line-height: 34px;
left: 22px;
font-size: 26px;
height: 11px;
line-height: 11px;
left: 7px;
font-size: 9px;
}
.time-date-icons {
position: relative;
right: 11px;
right: 4px;
}
}
@ -202,6 +202,47 @@ export class HeaderBar extends LitElement {
right: 5.5px;
}
}
@media screen and (min-width: 900px) {
.time-outer > #time {
height: 52px;
line-height: 52px;
font-size: 52px;
}
.time-icons {
display: flex;
width: 136px;
position: relative;
right: 4px;
}
.time-icons > ::slotted(:last-child) {
position: relative;
left: 40px;
}
.time-date {
line-height: 64px;
left: 10px;
}
.time-date > #time {
font-size: 64px;
}
#date {
height: 34px;
line-height: 34px;
left: 22px;
font-size: 26px;
}
.time-date-icons {
position: relative;
right: 11px;
}
}
`
firstUpdated() {
@ -248,31 +289,9 @@ export class HeaderBar extends LitElement {
getWeekDay() {
var d = new Date()
let daynumber = d.getDay()
let day = ''
switch (daynumber) {
case 0:
day = '周日'
break
case 1:
day = '周一'
break
case 2:
day = '周二'
break
case 3:
day = '周三'
break
case 4:
day = '周四'
break
case 5:
day = '周五'
break
case 6:
day = '周六'
break
}
let day = d.toLocaleString(navigator.languages as string[], {
weekday: 'short',
})
return day
}
@ -285,8 +304,8 @@ export class HeaderBar extends LitElement {
} else {
return d.toLocaleString(navigator.languages as string[], {
// year: 'numeric',
month: 'long',
day: '2-digit',
month: 'short',
day: 'numeric',
})
}
} else {
@ -304,12 +323,23 @@ export class HeaderBar extends LitElement {
}
return time
} else {
return d.toLocaleString(navigator.languages as string[], {
// hour12: (navigator as any).mozHour12,
hour12: false,
d = d.toLocaleString(navigator.languages as string[], {
hour12: (navigator as any).mozHour12,
hour: 'numeric',
minute: 'numeric',
})
if ((navigator as any).mozHour12) {
if (d.includes('M')) {
d = d.slice(0, -2)
} else {
d = d.slice(2)
}
}
if (d.indexOf(':') === 1) {
d = `0${d}`
}
return d
}
} else {
if (d.indexOf(':') == 1) {

View File

@ -111,19 +111,19 @@ export class IconControlBarGroup extends LitElement {
background: var(--background-dm);
}
@media screen and (min-width: 900px) {
@media screen and (min-width: 300px) {
:host {
border-radius: 16px;
border-radius: 5px;
}
.icon-only > div > ::slotted(*) {
height: 30px;
border-left: 2px solid var(--line-border-lm);
border-radius: 2px;
height: 10px;
border-left: 1px solid var(--line-border-lm);
border-radius: 1px;
}
:host([deep-mode]) .icon-only > div > ::slotted(*) {
border-left: 2px solid var(--line-border-dm);
border-left: 1px solid var(--line-border-dm);
}
}
@ -142,6 +142,22 @@ export class IconControlBarGroup extends LitElement {
border-left: 1px solid var(--line-border-dm);
}
}
@media screen and (min-width: 900px) {
:host {
border-radius: 16px;
}
.icon-only > div > ::slotted(*) {
height: 30px;
border-left: 2px solid var(--line-border-lm);
border-radius: 2px;
}
:host([deep-mode]) .icon-only > div > ::slotted(*) {
border-left: 2px solid var(--line-border-dm);
}
}
`
}

View File

@ -36,10 +36,10 @@ export class IconControlBar extends LitElement {
const iconstyle = html`
<style>
@media screen and (min-width: 900px) {
@media screen and (min-width: 300px) {
:host {
width: 104px;
height: 104px;
width: 34px;
height: 34px;
}
}
@ -49,6 +49,13 @@ export class IconControlBar extends LitElement {
height: 52px;
}
}
@media screen and (min-width: 900px) {
:host {
width: 104px;
height: 104px;
}
}
</style>
`
@ -90,10 +97,10 @@ export class IconControlBar extends LitElement {
const iconstyle = html`
<style>
@media screen and (min-width: 900px) {
@media screen and (min-width: 300px) {
:host {
width: 240px;
height: 108px;
width: 80px;
height: 36px;
}
}
@ -103,6 +110,13 @@ export class IconControlBar extends LitElement {
height: 54px;
}
}
@media screen and (min-width: 900px) {
:host {
width: 240px;
height: 108px;
}
}
</style>
`
@ -322,12 +336,18 @@ export class IconControlBar extends LitElement {
color: var(--text-color-lm);
}
.more-info-icon {
display: flex;
align-items: center;
}
.icon-base {
justify-content: center;
}
p {
position: relative;
left: 13.1%;
color: var(--text-color-lm);
white-space: nowrap;
overflow: hidden;
@ -351,6 +371,45 @@ export class IconControlBar extends LitElement {
color: var(--text-color-dm);
}
.icon-with-state::before {
position: relative;
left: 9.2%;
}
@media screen and (min-width: 300px) {
.with-border {
border-radius: 5px;
}
.icon-button::before {
width: 16px;
height: 16px;
line-height: 16px;
font-size: 16px;
}
.more-info-icon {
width: 5px;
height: 5px;
position: relative;
left: 19px;
}
.more-info-icon::after {
width: 5px;
height: 5px;
line-height: 5px;
font-size: 5px;
}
p {
width: 33px;
height: 7px;
font-size: 7px;
line-height: 7px;
}
}
@media screen and (min-width: 600px) {
.with-border {
border-radius: 8px;
@ -363,11 +422,6 @@ export class IconControlBar extends LitElement {
font-size: 24px;
}
.icon-with-state::before {
position: relative;
left: 11px;
}
.more-info-icon {
width: 8px;
height: 8px;
@ -385,8 +439,6 @@ export class IconControlBar extends LitElement {
p {
width: 50px;
height: 10px;
left: 17px;
font-weight: 400;
font-size: 10.5px;
line-height: 10px;
}

View File

@ -166,24 +166,36 @@ export class StarNotificationGroup extends LitElement {
}
static styles = css`
@media screen and (min-width: 900px) {
@media screen and (min-width: 300px) {
:host {
width: 860px;
width: 286px;
height: 50px;
display: block;
margin: 16px 170px 0;
border-radius: 20px;
margin: 5px 56px 0;
border-radius: 7px;
}
}
@media screen and (min-width: 600px) {
:host {
width: 430px;
height: 76px;
display: block;
margin: 8px 85px 0;
border-radius: 10px;
}
}
@media screen and (min-width: 900px) {
:host {
width: 860px;
height: 152px;
display: block;
margin: 16px 170px 0;
border-radius: 20px;
}
}
:host([show='false']) ::slotted(*) {
display: none;
}

View File

@ -44,7 +44,7 @@ export class StarNotification extends LitElement {
// 仅more-notifiactions-first有
@property({type: String}) secondTitle = ''
@property({type: String}) secondText = ''
@property({type: Boolean}) isToast = false
@query('.notification') notification!: HTMLDivElement
@query('.btn-tool') btnTool!: HTMLDivElement
@query('.arrow-up') arrowUp!: HTMLDivElement
@ -130,42 +130,75 @@ export class StarNotification extends LitElement {
this.notificationType == 'more-notifiactions'
? this.radiusType
: 'border-radius'
return html`
<div class="one">
<div
class="notification ${otherClass}"
role="link"
tabindex="0"
data-notification-id=${this.id}
data-no-clear=${this.noclear}
data-obsolete-a-p-i="false"
data-type=${this.type}
data-manifest-u-r-l=${this.manifesturl}
@touchstart=${this}
@touchmove=${this}
@touchend=${this}
@click=${this}
>
<img src=${this.src} role="presentation" />
<div class="title-container">
<div class="title" dir="auto">${this.title}</div>
<span class="timestamp" data-timestamp=${this.timestamp}>
${this.timestamp}
</span>
if (!this.isToast) {
return html`
<div class="one">
<div
class="notification ${otherClass}"
role="link"
tabindex="0"
data-notification-id=${this.id}
data-no-clear=${this.noclear}
data-obsolete-a-p-i="false"
data-type=${this.type}
data-manifest-u-r-l=${this.manifesturl}
@touchstart=${this}
@touchmove=${this}
@touchend=${this}
@click=${this}
>
<img src=${this.src} role="presentation" />
<div class="title-container">
<div class="title" dir="auto">${this.title}</div>
<span class="timestamp" data-timestamp=${this.timestamp}>
${this.timestamp}
</span>
</div>
<div class="detail">
<div class="detail-content" dir="auto">${this.text}</div>
<span class="arrow-up" data-icon="o"></span>
${arrowShow}
</div>
</div>
<div class="detail">
<div class="detail-content" dir="auto">${this.text}</div>
<span class="arrow-up" data-icon="o"></span>
${arrowShow}
<div class="btn-tool">
<div data-icon="delete" @click=${this}></div>
<div data-icon="settings" @click=${this}></div>
</div>
</div>
<div class="btn-tool">
<div data-icon="delete" @click=${this}></div>
<div data-icon="settings" @click=${this}></div>
`
} else {
return html`
<div class="one">
<div
class="notification ${otherClass}"
role="link"
tabindex="0"
data-notification-id=${this.id}
data-no-clear=${this.noclear}
data-obsolete-a-p-i="false"
data-type=${this.type}
data-manifest-u-r-l=${this.manifesturl}
@touchstart=${this}
@touchmove=${this}
@touchend=${this}
@click=${this}
>
<img src=${this.src} role="presentation" />
<div class="title-container">
<div class="title" dir="auto">${this.title}</div>
<span class="timestamp" data-timestamp=${this.timestamp}>
${this.timestamp}
</span>
</div>
<div class="detail">
<div class="detail-content" dir="auto">${this.text}</div>
<span class="arrow-up" data-icon="o"></span>
${arrowShow}
</div>
</div>
</div>
</div>
`
`
}
}
getmorefirst(): HTMLTemplateResult | typeof nothing {
@ -250,117 +283,141 @@ export class StarNotification extends LitElement {
@eventOptions({passive: false})
handleEvent(event: TouchEvent) {
switch (event.type) {
case 'touchstart':
this.touchAction.start.clientX = event.touches[0].clientX
this.btnTool.style.visibility = 'visiable'
break
case 'touchmove':
this.touchAction.last.clientX = event.touches[0].clientX
let touchPosX =
this.touchAction.last.clientX - this.touchAction.start.clientX
// if (Math.abs(touchPosX) > 266) {
// touchPosX = 266;
// }
// this.notification.style.transform = 'translateX(' + touchPosX + 'px)';
if (touchPosX < 0) {
// if (Math.abs(touchPosX) > 18) {
// (this.btnTool.children[1] as HTMLElement).style.visibility = "visible";
// }
// if (Math.abs(touchPosX) > 142) {
// (this.btnTool.children[0] as HTMLElement).style.visibility = "visible";
if (!this.isToast) {
switch (event.type) {
case 'touchstart':
this.touchAction.start.clientX = event.touches[0].clientX
this.btnTool.style.visibility = 'visiable'
break
case 'touchmove':
event.preventDefault()
let deleteBtn = this.btnTool.children[0] as HTMLElement
let settingsBtn = this.btnTool.children[1] as HTMLElement
this.touchAction.last.clientX = event.touches[0].clientX
let touchPosX =
this.touchAction.last.clientX - this.touchAction.start.clientX
// if (Math.abs(touchPosX) > 266) {
// touchPosX = 266;
// }
// if (Math.abs(touchPosX) > 222) {
// (this.btnTool.children[1] as HTMLElement).style.opacity = "1";
// (this.btnTool.children[0] as HTMLElement).style.opacity = "1";
// }
;(this.btnTool.children[0] as HTMLElement).style.visibility =
'visible'
;(this.btnTool.children[1] as HTMLElement).style.visibility =
'visible'
;(this.btnTool.children[0] as HTMLElement).style.opacity = '1'
;(this.btnTool.children[1] as HTMLElement).style.opacity = '1'
let translateX
if (screen.width >= 900) {
translateX = 266
} else {
translateX = 133
// this.notification.style.transform = 'translateX(' + touchPosX + 'px)';
if (touchPosX < 0) {
// if (Math.abs(touchPosX) > 18) {
// (this.btnTool.children[1] as HTMLElement).style.visibility = "visible";
// }
// if (Math.abs(touchPosX) > 142) {
// (this.btnTool.children[0] as HTMLElement).style.visibility = "visible";
// }
// if (Math.abs(touchPosX) > 222) {
// (this.btnTool.children[1] as HTMLElement).style.opacity = "1";
// (this.btnTool.children[0] as HTMLElement).style.opacity = "1";
// }
let translateX
if (screen.width >= 900) {
translateX = 266
} else if (screen.width >= 600) {
translateX = 133
} else {
translateX = 88
}
this.notification.style.transform =
'translateX(-' + translateX + 'px)'
let self = this
this.notification.addEventListener(
'transitionend',
function tranEnd() {
self.notification.removeEventListener('transitionend', tranEnd)
deleteBtn.style.visibility = 'visible'
settingsBtn.style.visibility = 'visible'
deleteBtn.style.opacity = '1'
settingsBtn.style.opacity = '1'
}
)
} else if (touchPosX > 0) {
// if (touchPosX > 44) {
// (this.btnTool.children[0] as any).style.opacity = 0.6;
// }
// if (touchPosX > 124) {
// (this.btnTool.children[0] as any).style.visibility = "hidden";
// }
// if (touchPosX > 168) {
// (this.btnTool.children[1] as any).style.opacity = 0.6;
// }
// if (touchPosX > 248) {
// (this.btnTool.children[1] as any).style.visibility = "hidden";
// }
deleteBtn.style.visibility = 'hidden'
settingsBtn.style.visibility = 'hidden'
this.notification.style.transform = 'translateX(' + 0 + 'px)'
}
this.notification.style.transform =
'translateX(-' + translateX + 'px)'
} else if (touchPosX > 0) {
// if (touchPosX > 44) {
// (this.btnTool.children[0] as any).style.opacity = 0.6;
// }
// if (touchPosX > 124) {
// (this.btnTool.children[0] as any).style.visibility = "hidden";
// }
// if (touchPosX > 168) {
// (this.btnTool.children[1] as any).style.opacity = 0.6;
// }
// if (touchPosX > 248) {
// (this.btnTool.children[1] as any).style.visibility = "hidden";
// }
;(this.btnTool.children[0] as any).style.visibility = 'hidden'
;(this.btnTool.children[1] as any).style.visibility = 'hidden'
this.notification.style.transform = 'translateX(' + 0 + 'px)'
}
break
case 'touchend':
break
case 'click':
event.stopPropagation()
switch ((event.target as HTMLElement).dataset.icon) {
case 'delete':
;(event.target as HTMLElement).setAttribute('clicked', 'true')
window.setTimeout(() => {
;(event.target as HTMLElement).removeAttribute('clicked')
this.dispatchEvent(
new CustomEvent('notification-delete', {
detail: {
id: this.id,
notification: this,
},
bubbles: true,
composed: true,
})
break
case 'touchend':
break
case 'click':
event.stopPropagation()
let self = this
let target = event.target as HTMLElement
switch (target.dataset.icon) {
case 'delete':
target.setAttribute('clicked', 'true')
target.addEventListener('transitionend', function tranEnd() {
target.removeEventListener('transitionend', tranEnd)
target.removeAttribute('clicked')
self.dispatchEvent(
new CustomEvent('notification-delete', {
detail: {
id: self.id,
notification: self,
},
bubbles: true,
composed: true,
})
)
})
break
case 'settings':
target.setAttribute('clicked', 'true')
target.addEventListener('transitionend', function tranEnd() {
target.removeEventListener('transitionend', tranEnd)
target.removeAttribute('clicked')
self.dispatchEvent(
new CustomEvent('notification-settings-configure', {
bubbles: true,
composed: true,
})
)
})
break
default:
this.notification.setAttribute('clicked', 'true')
this.notification.addEventListener(
'transitionend',
function tranEnd() {
self.notification.removeEventListener(
'transitionend',
tranEnd
)
self.notification.removeAttribute('clicked')
self.dispatchEvent(
new CustomEvent('notification-click', {
detail: {
id: self.id,
notification: self,
},
bubbles: true,
composed: true,
})
)
}
)
}, 100)
break
case 'settings':
;(event.target as HTMLElement).setAttribute('clicked', 'true')
window.setTimeout(() => {
this.dispatchEvent(
new CustomEvent('notification-settings-configure', {
bubbles: true,
composed: true,
})
)
}, 100)
break
default:
this.notification.setAttribute('clicked', 'true')
window.setTimeout(() => {
this.notification.removeAttribute('clicked')
this.dispatchEvent(
new CustomEvent('notification-click', {
detail: {
id: this.id,
notification: this,
},
bubbles: true,
composed: true,
})
)
}, 100)
break
}
break
break
}
break
}
}
}
@ -387,6 +444,7 @@ export class StarNotification extends LitElement {
}
.notification[clicked] {
transition: transform 0.1s;
transform: scale(0.9);
background: var(--notification-background-active);
}
@ -404,6 +462,7 @@ export class StarNotification extends LitElement {
flex: none;
order: 0;
flex-grow: 0;
font-weight: 600;
}
.notification > div.title-container .timestamp {
@ -482,6 +541,7 @@ export class StarNotification extends LitElement {
background: var(--button-background-color-lm);
border-radius: 50%;
opacity: 0.6;
transition: transform 0.1s;
}
.btn-tool > div[clicked] {
@ -558,148 +618,148 @@ export class StarNotification extends LitElement {
color: #f4f4f4;
}
@media screen and (min-width: 900px) {
@media screen and (min-width: 300px) {
:host([notificationType='one-notification']) {
margin: 16px 0 0 0;
margin: 5px 0 0 0;
}
.notification {
height: 152px;
width: 860px;
height: 50px;
width: 286px;
}
.top-border-radius {
border-top-left-radius: 20px;
border-top-right-radius: 20px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
.bottom-border-radius {
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
}
.border-radius {
border-radius: 20px;
border-radius: 6px;
}
.notification > img {
width: 48px;
height: 48px;
width: 16px;
height: 16px;
pointer-events: none;
margin: 26px 10px 78px 26px;
margin: 9px 3px 26px 9px;
}
.notification > div.title-container {
width: calc(100% - 84px);
left: 84px;
top: 36px;
width: calc(100% - 28px);
left: 28px;
top: 23.7%;
}
.notification > div.title-container .title {
height: 28px;
line-height: 28px;
font-size: 28px;
height: 9px;
line-height: 9px;
font-size: 9px;
}
.notification > div.title-container .timestamp {
height: 32px;
right: 32px;
top: -4px;
font-size: 24px;
line-height: 32px;
height: 10px;
right: 10px;
top: -1px;
font-size: 8px;
line-height: 10px;
}
.notification > div.detail {
width: calc(100% - 84px);
left: 84px;
top: 84px;
width: calc(100% - 28px);
left: 28px;
top: 55.3%;
}
.notification > div.detail .detail-content {
width: 740px;
height: 34px;
font-size: 26px;
line-height: 34px;
width: 246px;
height: 11px;
font-size: 8px;
line-height: 11px;
}
.notification > div.detail .arrow-up {
width: 56px;
height: 34px;
right: 26px;
bottom: 30px;
line-height: 34px;
border-radius: 189px;
width: 18px;
height: 11px;
right: 9px;
bottom: 10px;
line-height: 11px;
border-radius: 63px;
}
.notification > div.detail .arrow-up::after {
font-size: 35px;
font-size: 12px;
}
.btn-tool {
right: 18px;
right: 6px;
}
.btn-tool > div:first-child {
margin-right: 44px;
margin-right: 15px;
visibility: hidden;
}
.btn-tool > div {
width: 80px;
height: 80px;
width: 26px;
height: 26px;
}
.btn-tool > div::after {
width: 32px;
height: 32px;
line-height: 32px;
font-size: 32px;
width: 10px;
height: 10px;
line-height: 10px;
font-size: 10px;
}
.container {
width: calc(100% - 84px);
left: 84px;
width: calc(100% - 28px);
left: 28px;
}
.one-container {
top: 36px;
top: 12px;
}
.another-container {
top: 89px;
top: 29px;
}
.container .title {
height: 28px;
line-height: 28px;
font-size: 28px;
height: 9px;
line-height: 9px;
font-size: 9px;
}
.container .detail-content {
height: 34px;
line-height: 34px;
left: 24px;
top: -3px;
font-size: 26px;
height: 11px;
line-height: 11px;
left: 8px;
top: -1px;
font-size: 9px;
}
.one-container .timestamp {
height: 34px;
right: 34px;
top: -4px;
font-size: 24px;
line-height: 32px;
height: 11px;
right: 11px;
top: -1px;
font-size: 8px;
line-height: 11px;
}
.another-container .notificaiton-counts {
width: 56px;
height: 34px;
right: 26px;
bottom: 30px;
width: 18px;
height: 11px;
right: 8px;
bottom: 10px;
top: -1px;
line-height: 34px;
font-size: 20px;
border-radius: 189px;
line-height: 11px;
font-size: 7px;
border-radius: 63px;
}
}
@ -738,6 +798,7 @@ export class StarNotification extends LitElement {
width: calc(100% - 42px);
left: 42px;
top: 18px;
top: 23.7%;
}
.notification > div.title-container .title {
@ -758,6 +819,7 @@ export class StarNotification extends LitElement {
width: calc(100% - 42px);
left: 42px;
top: 42px;
top: 55.3%;
}
.notification > div.detail .detail-content {
@ -847,6 +909,155 @@ export class StarNotification extends LitElement {
border-radius: 94.5px;
}
}
@media screen and (min-width: 900px) {
:host([notificationType='one-notification']) {
margin: 16px 0 0 0;
}
.notification {
height: 152px;
width: 860px;
}
.top-border-radius {
border-top-left-radius: 20px;
border-top-right-radius: 20px;
}
.bottom-border-radius {
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
}
.border-radius {
border-radius: 20px;
}
.notification > img {
width: 48px;
height: 48px;
pointer-events: none;
margin: 26px 10px 78px 26px;
}
.notification > div.title-container {
width: calc(100% - 84px);
left: 84px;
top: 36px;
top: 23.7%;
}
.notification > div.title-container .title {
height: 28px;
line-height: 28px;
font-size: 28px;
}
.notification > div.title-container .timestamp {
height: 32px;
right: 32px;
top: -4px;
font-size: 24px;
line-height: 32px;
}
.notification > div.detail {
width: calc(100% - 84px);
left: 84px;
top: 84px;
top: 55.3%;
}
.notification > div.detail .detail-content {
width: 740px;
height: 34px;
font-size: 26px;
line-height: 34px;
}
.notification > div.detail .arrow-up {
width: 56px;
height: 34px;
right: 26px;
bottom: 30px;
line-height: 34px;
border-radius: 189px;
}
.notification > div.detail .arrow-up::after {
font-size: 35px;
}
.btn-tool {
right: 18px;
}
.btn-tool > div:first-child {
margin-right: 44px;
visibility: hidden;
}
.btn-tool > div {
width: 80px;
height: 80px;
}
.btn-tool > div::after {
width: 32px;
height: 32px;
line-height: 32px;
font-size: 32px;
}
.container {
width: calc(100% - 84px);
left: 84px;
}
.one-container {
top: 36px;
}
.another-container {
top: 89px;
}
.container .title {
height: 28px;
line-height: 28px;
font-size: 28px;
}
.container .detail-content {
height: 34px;
line-height: 34px;
left: 24px;
top: -3px;
font-size: 26px;
}
.one-container .timestamp {
height: 34px;
right: 34px;
top: -4px;
font-size: 24px;
line-height: 32px;
}
.another-container .notificaiton-counts {
width: 56px;
height: 34px;
right: 26px;
bottom: 30px;
top: -1px;
line-height: 34px;
font-size: 20px;
border-radius: 189px;
}
}
`
}

View File

@ -0,0 +1,39 @@
# star-weather
星光 Web 组件——天气组件weather组件介绍10 月 08 日)
## 介绍
star-weather 组件主要是用来显示当前天气状况和预测1周内天气详情的组件
star-weather 属性:
### 1、type 属性
天气风格样式类型,type一共包含6种类型分别为type11、type12、type21、type22、type23和type32其中
type="type11"的内容排布为只包含天气图标的样式,
type="type12"的内容排布(从左向右)为包含地理位置信息、温度和对应的天气图标,
type="type21"的内容排布(从上至下)为包含天气图标,地理位置和温度信息,
type="type22"的内容排布(从上至下)为包含地理位置、温度、天气图标、空气质量、体感温度、湿度、风级、能见度、紫外线等详细信息。
`html demo <star-weather type="type22"></star-weather> `
### 2、data 属性
天气详细信息,其中包含地理位置、温度、日期、天气情况、风级、湿度、空气质量、体感温度、能见度、紫外线等具体信息
`html demo <star-weather type="type22" .data="${this.data}"></star-weather> `
### 3、自适应布局
天气组件整体布局设计为自适应布局,可自适应缩放显示天气组件。
### 4、weatherData数据格式说明
weatherData = {
location: "", //位置信息
weatherInfo: [ //天气详情信息,包含天气情况、风级、湿度、空气质量、体感温度、能见度、紫外线等详情信息
{
date: new Date(), 日期
……
},
{
date: new Date(),
}
]
}

View File

@ -0,0 +1,22 @@
{
"name": "@star-web-components/weather",
"version": "0.0.1",
"description": "",
"type": "module",
"main": "./index.js",
"module": "./index.js",
"exports": {
".": {
"default": "./index.js"
},
"./index": {
"default": "./index.js"
},
"./weather.js": {
"default": "./weather.js"
},
"./package.json": "./package.json"
},
"author": "",
"license": "ISC"
}

View File

@ -0,0 +1,21 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_2914_176526)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.3043 38H32.8696C37.3571 38 41 34.3071 41 29.7451C41 25.3341 37.5789 21.7277 33.2814 21.5117C31.9404 15.4919 26.6398 11 20.3043 11C12.9553 11 7 17.0468 7 24.4973C7 31.4457 12.1739 37.1686 18.8261 37.919L20.3043 38Z" fill="url(#paint0_linear_2914_176526)"/>
</g>
<defs>
<filter id="filter0_d_2914_176526" x="3" y="9" width="42" height="35" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.25 0 0 0 0 0.25 0 0 0 0 0.25 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2914_176526"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2914_176526" result="shape"/>
</filter>
<linearGradient id="paint0_linear_2914_176526" x1="48.0217" y1="20.8478" x2="23.747" y2="2.34606" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFEDBA"/>
<stop offset="1" stop-color="#FFFCF2"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,38 @@
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_1658_81628)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M119 53.9935C119 31.9083 101.091 14 78.9935 14C56.9093 14 39 31.9083 39 53.9935C39 76.0917 56.9093 94 78.9935 94C101.091 94 119 76.0917 119 53.9935Z" fill="url(#paint0_linear_1658_81628)"/>
<path d="M78.9935 14.5C100.815 14.5 118.5 32.1846 118.5 53.9935C118.5 75.8155 100.815 93.5 78.9935 93.5C57.1855 93.5 39.5 75.8156 39.5 53.9935C39.5 32.1845 57.1854 14.5 78.9935 14.5Z" stroke="#F2F2F2" stroke-opacity="0.9"/>
</g>
<g filter="url(#filter1_d_1658_81628)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M44.2174 114H77.4783C89.3571 114 99 104.426 99 92.5983C99 81.1626 89.9441 71.8124 78.5683 71.2525C75.0186 55.6457 60.9876 44 44.2174 44C24.764 44 9 59.6769 9 78.993C9 97.0074 22.6957 111.844 40.3043 113.79L44.2174 114Z" fill="url(#paint1_linear_1658_81628)"/>
</g>
<defs>
<filter id="filter0_d_1658_81628" x="31" y="6" width="96" height="96" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="4"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1658_81628"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1658_81628" result="shape"/>
</filter>
<filter id="filter1_d_1658_81628" x="5" y="42" width="98" height="78" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.25 0 0 0 0 0.25 0 0 0 0 0.25 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1658_81628"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1658_81628" result="shape"/>
</filter>
<linearGradient id="paint0_linear_1658_81628" x1="42.5" y1="46.5" x2="91.7273" y2="106.727" gradientUnits="userSpaceOnUse">
<stop offset="0.0028" stop-color="#DDDBD9"/>
<stop offset="1" stop-color="#989CA5"/>
</linearGradient>
<linearGradient id="paint1_linear_1658_81628" x1="117.587" y1="69.5314" x2="54.3175" y2="20.2954" gradientUnits="userSpaceOnUse">
<stop stop-color="#C7C9D0"/>
<stop offset="1" stop-color="#F4F4F3"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,21 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_2914_176524)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.3043 37H32.8696C37.3571 37 41 33.3071 41 28.7451C41 24.3341 37.5789 20.7277 33.2814 20.5117C31.9404 14.4919 26.6398 10 20.3043 10C12.9553 10 7 16.0468 7 23.4973C7 30.4457 12.1739 36.1686 18.8261 36.919L20.3043 37Z" fill="url(#paint0_linear_2914_176524)"/>
</g>
<defs>
<filter id="filter0_d_2914_176524" x="3" y="8" width="42" height="35" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.25 0 0 0 0 0.25 0 0 0 0 0.25 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2914_176524"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2914_176524" result="shape"/>
</filter>
<linearGradient id="paint0_linear_2914_176524" x1="48.0217" y1="19.8478" x2="23.747" y2="1.34606" gradientUnits="userSpaceOnUse">
<stop stop-color="#80848D"/>
<stop offset="1" stop-color="#BCC2CC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,38 @@
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_1425_53262)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M119 55.9935C119 33.9083 101.091 16 78.9935 16C56.9093 16 39 33.9083 39 55.9935C39 78.0917 56.9093 96 78.9935 96C101.091 96 119 78.0917 119 55.9935Z" fill="url(#paint0_linear_1425_53262)"/>
<path d="M78.9935 16.5C100.815 16.5 118.5 34.1846 118.5 55.9935C118.5 77.8155 100.815 95.5 78.9935 95.5C57.1855 95.5 39.5 77.8156 39.5 55.9935C39.5 34.1845 57.1854 16.5 78.9935 16.5Z" stroke="#FFDD80" stroke-opacity="0.9"/>
</g>
<g filter="url(#filter1_d_1425_53262)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M44.2174 116H77.4783C89.3571 116 99 106.426 99 94.5983C99 83.1626 89.9441 73.8124 78.5683 73.2525C75.0186 57.6457 60.9876 46 44.2174 46C24.764 46 9 61.6769 9 80.993C9 99.0074 22.6957 113.844 40.3043 115.79L44.2174 116Z" fill="url(#paint1_linear_1425_53262)"/>
</g>
<defs>
<filter id="filter0_d_1425_53262" x="31" y="8" width="96" height="96" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="4"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.827451 0 0 0 0 0.309804 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1425_53262"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1425_53262" result="shape"/>
</filter>
<filter id="filter1_d_1425_53262" x="5" y="44" width="98" height="78" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.25 0 0 0 0 0.25 0 0 0 0 0.25 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1425_53262"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1425_53262" result="shape"/>
</filter>
<linearGradient id="paint0_linear_1425_53262" x1="29.9091" y1="61.4545" x2="91.7273" y2="108.727" gradientUnits="userSpaceOnUse">
<stop offset="0.0028" stop-color="#FFC338"/>
<stop offset="1" stop-color="#FF9C12"/>
</linearGradient>
<linearGradient id="paint1_linear_1425_53262" x1="117.587" y1="71.5314" x2="54.3175" y2="22.2954" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFEDBA"/>
<stop offset="1" stop-color="#FFFCF2"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,38 @@
<svg width="54" height="51" viewBox="0 0 54 51" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_2914_176531)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M46 22.9976C46 14.7156 39.284 8 30.9976 8C22.716 8 16 14.7156 16 22.9976C16 31.2844 22.716 38 30.9976 38C39.284 38 46 31.2844 46 22.9976Z" fill="url(#paint0_linear_2914_176531)"/>
<path d="M30.9976 8.5C39.008 8.5 45.5 14.9919 45.5 22.9976C45.5 31.0082 39.0079 37.5 30.9976 37.5C22.9922 37.5 16.5 31.0083 16.5 22.9976C16.5 14.9918 22.9921 8.5 30.9976 8.5Z" stroke="#FFDD80" stroke-opacity="0.9"/>
</g>
<g filter="url(#filter1_d_2914_176531)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.3043 45H29.8696C34.3571 45 38 41.4439 38 37.0508C38 32.8032 34.5789 29.3303 30.2814 29.1224C28.9404 23.3255 23.6398 19 17.3043 19C9.95528 19 4 24.8228 4 31.9974C4 38.6885 9.17391 44.1994 15.8261 44.922L17.3043 45Z" fill="url(#paint1_linear_2914_176531)"/>
</g>
<defs>
<filter id="filter0_d_2914_176531" x="8" y="0" width="46" height="46" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="4"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.827451 0 0 0 0 0.309804 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2914_176531"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2914_176531" result="shape"/>
</filter>
<filter id="filter1_d_2914_176531" x="0" y="17" width="42" height="34" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.25 0 0 0 0 0.25 0 0 0 0 0.25 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2914_176531"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2914_176531" result="shape"/>
</filter>
<linearGradient id="paint0_linear_2914_176531" x1="12.5909" y1="25.0455" x2="35.7727" y2="42.7727" gradientUnits="userSpaceOnUse">
<stop offset="0.0028" stop-color="#FFC338"/>
<stop offset="1" stop-color="#FF9C12"/>
</linearGradient>
<linearGradient id="paint1_linear_2914_176531" x1="45.0217" y1="28.4831" x2="21.4268" y2="9.80775" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFEDBA"/>
<stop offset="1" stop-color="#FFFCF2"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,21 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_2914_176529)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M40 23.9974C40 15.1633 32.8363 8 23.9974 8C15.1637 8 8 15.1633 8 23.9974C8 32.8367 15.1637 40 23.9974 40C32.8363 40 40 32.8367 40 23.9974Z" fill="url(#paint0_linear_2914_176529)"/>
<path d="M23.9974 8.5C32.5603 8.5 39.5 15.4396 39.5 23.9974C39.5 32.5605 32.5602 39.5 23.9974 39.5C15.44 39.5 8.5 32.5606 8.5 23.9974C8.5 15.4395 15.4398 8.5 23.9974 8.5Z" stroke="#FFDD80" stroke-opacity="0.9"/>
</g>
<defs>
<filter id="filter0_d_2914_176529" x="0" y="0" width="48" height="48" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="4"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.827451 0 0 0 0 0.309804 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2914_176529"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2914_176529" result="shape"/>
</filter>
<linearGradient id="paint0_linear_2914_176529" x1="4.36364" y1="26.1818" x2="29.0909" y2="45.0909" gradientUnits="userSpaceOnUse">
<stop offset="0.0028" stop-color="#FFC338"/>
<stop offset="1" stop-color="#FF9C12"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,148 @@
import {css, CSSResult} from 'lit'
export const sharedStyles: CSSResult = css`
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.star-weather-main {
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
/* 背景框 */
.star-weather {
width: var(--autoWidth--);
min-width: var(--autoWidth--);
height: var(--autoHeight--);
min-height: var(--autoHeight--);
transform: scale(var(--autoScale--));
border-radius: 20px;
overflow: hidden;
background: linear-gradient(
137.64deg,
#f5f0f5 0%,
#fafafa 20.46%,
#d5daf2 90.45%
);
display: flex;
flex-direction: column;
}
.star-weather * {
white-space: nowrap;
}
/* .star-weather-top */
.star-weather-top {
display: flex;
align-items: center;
justify-content: space-between;
}
.type12 .star-weather-top {
width: 100%;
height: 100%;
}
.type21 .star-weather-top {
width: 100%;
height: 100%;
flex-direction: column-reverse;
align-items: center;
}
.type22 .star-weather-top {
width: 100%;
height: 45%;
/* border:1px solid red; */
}
/* .star-weather-bottom */
.star-weather-bottom {
display: flex;
flex-wrap: wrap;
}
.type22 .star-weather-bottom {
height: 50%;
}
/* 天气图标 */
.star-weather-img {
display: flex;
justify-content: center;
align-items: center;
transform: scale(0.7);
}
.type11 .star-weather-img {
height: 100%;
width: 100%;
}
.type12 .star-weather-img {
height: 100%;
margin-right: 30px;
}
.type21 .star-weather-img {
width: 100%;
}
.type22 .star-weather-img {
height: 90%;
margin-right: 30px;
/* border:1px solid red; */
}
.weather-img {
width: 100%;
height: 100%;
}
/* 位置温度()*/
.star-weather-location-temperature {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.type12 .star-weather-location-temperature {
height: 100%;
margin-left: 47px;
}
.type21 .star-weather-location-temperature {
width: 100%;
margin-bottom: 40px;
}
.type22 .star-weather-location-temperature {
height: 100%;
/* margin-top:10%; */
margin-left: 47px;
}
.star-weather-location {
text-align: left;
margin-bottom: 10px;
font-size: 22px;
color: rgba(38, 38, 38, 0.45);
}
.type21 .star-weather-location {
text-align: center;
}
.star-weather-temperature {
font-size: 40px;
font-weight: bold;
position: relative;
display: flex;
align-items: center;
}
/* detailType() */
.detail-today-item {
height: 50%;
width: 31%;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 47px;
}
.detail-today-item-top {
font-size: 16px;
color: rgba(38, 38, 38, 0.45);
margin-bottom: 5px;
}
.detail-today-item-bottom {
font-size: 26px;
text-align: left;
color: #4d4d4d;
}
`

View File

@ -0,0 +1,169 @@
import {html, LitElement, CSSResultArray} from 'lit'
import {customElement, property, query} from 'lit/decorators.js'
import {sharedStyles} from './weather-style'
import Sunny from './svg/Sunny.svg'
import Cloudy from './svg/Cloudy.svg'
import Noload from './svg/Noload.svg'
import PartlyCloudy from './svg/Partly Cloudy.svg'
const weatherMy: Record<string, boolean> = {
Sunny: Sunny,
Cloudy: Cloudy,
PartlyCloudy: PartlyCloudy,
}
const typeMy: Record<string, string> = {
// height / width
type11: '1',
type12: '0.4',
type21: '1.9',
type22: '0.8',
type23: '0.7',
type32: '1.6',
}
const minAll: Record<string, string> = {
// width
type11: '100',
type12: '400',
type21: '200',
type22: '500',
type23: '600',
type32: '600',
}
@customElement('star-weather')
export class StarWeather extends LitElement {
public static override get styles(): CSSResultArray {
return [sharedStyles]
}
@property({type: String}) type = 'type11'
@property({type: Object}) data = Object()
@query('.star-weather-main')
starWeather: HTMLDivElement | undefined
dataBoo() {
return !!Object.keys(this.data).length
}
render() {
return html`
<div class="star-weather-main">
<div class="star-weather ${this.type}">
<div class="star-weather-top">
${this.locationType()} ${this.weatherType()}
</div>
<div class="star-weather-bottom">${this.detailType()}</div>
</div>
</div>
`
}
weatherType() {
return html`
<div class="star-weather-img">
<img
class="weather-img"
src="${weatherMy[
this.dataBoo() && this.data.weatherInfo[0]?.weather?.labelEn] || Noload}"
/>
</div>
`
}
locationType() {
if (this.type !== 'type11' && typeMy[this.type]) {
return html`
<div class="star-weather-location-temperature">
<div class="star-weather-location-temperature-main">
<div class="star-weather-location">
${(this.dataBoo() && this.data.location) || ''}
</div>
<div class="star-weather-temperature">
${(this.dataBoo() && this.data.weatherInfo[0]?.temperature?.max) || ''}
</div>
</div>
</div>
`
} else {
return ''
}
}
detailType() {
if (this.type === 'type22') {
return html`
<span class="detail-today-item">
<span class="detail-today-item-top"></span>
<span class="detail-today-item-bottom">
${this.dataBoo() && (this.data.weatherInfo[0]?.airQuality?.value +
this.data.weatherInfo[0]?.airQuality?.type) || ''}
</span>
</span>
<span class="detail-today-item">
<span class="detail-today-item-top"></span>
<span class="detail-today-item-bottom">
${(this.dataBoo() &&
this.data.weatherInfo[0].somatosensoryTemperature) || ''}
</span>
</span>
<span class="detail-today-item">
<span class="detail-today-item-top">湿</span>
<span class="detail-today-item-bottom">
${(this.dataBoo() && this.data.weatherInfo[0]?.humidity) || ''}
</span>
</span>
<span class="detail-today-item">
<span class="detail-today-item-top">
${(this.dataBoo() && this.data.weatherInfo[0]?.wind?.label) || '风向'}
</span>
<span class="detail-today-item-bottom">
${(this.dataBoo() && this.data.weatherInfo[0]?.wind?.value) || ''}
</span>
</span>
<span class="detail-today-item">
<span class="detail-today-item-top"></span>
<span class="detail-today-item-bottom">
${(this.dataBoo() && this.data.weatherInfo[0]?.visibility) || ''}
</span>
</span>
<span class="detail-today-item">
<span class="detail-today-item-top">线</span>
<span class="detail-today-item-bottom">
${(this.dataBoo() && this.data.weatherInfo[0]?.ultravioletRys) || ''}
</span>
</span>
`
} else {
return ''
}
}
protected firstUpdated() {
this.resize()
window.addEventListener('resize', () => {
this.resize()
})
}
protected resize() {
let parentHeight, parentWidth
if (this.parentElement){
parentHeight = this.parentElement.offsetHeight
parentWidth = this.parentElement.offsetWidth
}else if(this.parentNode instanceof ShadowRoot){
parentHeight=(this.parentNode.host as HTMLElement).offsetHeight
parentWidth=(this.parentNode.host as HTMLElement).offsetWidth
}
let height = parentHeight || 10
let width = parentWidth || 10
// console.log(height,width,'111111111')
// this.style.setProperty('--autoWidth2--', width + 'px')
// this.style.setProperty('--autoHeight2--', height + 'px')
let proportion: any = typeMy[this.type]
let minOne: any = minAll[this.type]
this.style.setProperty('--autoWidth--', minOne + 'px')
this.style.setProperty('--autoHeight--', minOne * proportion + 'px')
if (height / width >= proportion) {
this.style.setProperty('--autoScale--', width / minOne + '')
} else {
this.style.setProperty('--autoScale--', height / (minOne * proportion) + '')
}
}
}
declare global {
interface HTMLElementTagNameMap {
'star-weather': StarWeather
}
}

View File

@ -12,6 +12,7 @@ import './components/radio/radio-group'
import './components/radio/radio'
import './components/confirm/confirm'
import './components/clock/clock'
import './components/weather/weather'
import './components/toast/toast'
import './components/picker/picker'
import './components/overflowmenu/overflowmenu'

View File

@ -11,10 +11,10 @@
### 1.在普通 HTMLElement 上使用 GestureDetector 的方法:
```js
import GestureDector from '@star-web-lib/gesture-detector/gesture-detector.js'
import GestureDetector from '@star-web-lib/gesture-detector/gesture-detector.js'
const myElement = document.querySelector('#myel')
GestureDector.embedded(myElement)
GestureDetector.embedded(myElement)
myElement.addEventListener('tap', function () {})
myElement.addEventListener('doubletap', function () {}, {once: true})
```

View File

@ -262,7 +262,7 @@ type GestureTouchEvent = TouchEvent & {
type EmbededGestureHTMLElement = HTMLElement & {
_addEventListener?: HTMLElement['addEventListener']
gestureDector?: GestureDector
gestureDetector?: GestureDetector
cacheListeners?: {
type: keyof HTMLElementEventMap & GestureEvents
listener: EventListenerOrEventListenerObject
@ -477,31 +477,58 @@ const getTouchFromTouches = (
})[0]
}
export default class GestureDector {
export default class GestureDetector {
// 进入长按状态的阈值
static HOLD_THRESHOLD = 300
static #HOLD_THRESHOLD = 300
static get HOLD_THRESHOLD() {
return this.#HOLD_THRESHOLD
}
// 进入滑动状态的阈值
static PAN_THRESHOLD = 20
static #PAN_THRESHOLD = 20
static get PAN_THRESHOLD() {
return this.#PAN_THRESHOLD
}
// 判定是swipe事件的速度阈值单位: px/ms
static VELOCITY_THRESHOLD = 0.3
static #VELOCITY_THRESHOLD = 0.3
static get VELOCITY_THRESHOLD() {
return this.#VELOCITY_THRESHOLD
}
static THRESHOLD_SMOOTHING = 0.9
static #THRESHOLD_SMOOTHING = 0.9
static get THRESHOLD_SMOOTHING() {
return this.#THRESHOLD_SMOOTHING
}
static VELOCITY_SMOOTHING = 0.5
static #VELOCITY_SMOOTHING = 0.5
static get VELOCITY_SMOOTHING() {
return this.#VELOCITY_SMOOTHING
}
// 连续两次点触(双击或三击)允许的x和y坐标的最大偏移量
static DOUBLE_TAP_DISTANCE = 50
static #DOUBLE_TAP_DISTANCE = 50
static get DOUBLE_TAP_DISTANCE() {
return this.#DOUBLE_TAP_DISTANCE
}
// 连续两次点触(双击或三击)允许的最大间隔时间
static DOUBLE_TAP_TIME = 300
static #DOUBLE_TAP_TIME = 300
static get DOUBLE_TAP_TIME() {
return this.#DOUBLE_TAP_TIME
}
// scale 触发阈值, 单位: px
static SCALE_THRESHOLD = 20
static #SCALE_THRESHOLD = 20
static get SCALE_THRESHOLD() {
return this.#SCALE_THRESHOLD
}
// rotate 触发阈值, 单位: 度°
static ROTATE_THRESHOLD = 22.5
static #ROTATE_THRESHOLD = 22.5
static get ROTATE_THRESHOLD() {
return this.#ROTATE_THRESHOLD
}
// _options 是 option 的备份,用于重置
_options!: GestureOptions | null
@ -583,16 +610,16 @@ export default class GestureDector {
this.element = el
this.options = {
...{
holdThreshold: GestureDector.HOLD_THRESHOLD,
panThreshold: GestureDector.PAN_THRESHOLD,
velocityThreshold: GestureDector.VELOCITY_THRESHOLD,
holdThreshold: GestureDetector.HOLD_THRESHOLD,
panThreshold: GestureDetector.PAN_THRESHOLD,
velocityThreshold: GestureDetector.VELOCITY_THRESHOLD,
},
...options,
}
this.state = this.initialState
// 用于审计
GestureDector._GestureDetectorId++
GestureDetector._GestureDetectorId++
}
/**
@ -921,12 +948,12 @@ export default class GestureDector {
// 否则,
if (
Math.abs(distance - this.startDistance) >
GestureDector.SCALE_THRESHOLD
GestureDetector.SCALE_THRESHOLD
) {
this.scaled = true
this.startDistance = this.lastDistance = Math.floor(
this.startDistance +
GestureDector.THRESHOLD_SMOOTHING *
GestureDetector.THRESHOLD_SMOOTHING *
(distance - this.startDistance)
)
} else {
@ -936,7 +963,7 @@ export default class GestureDector {
if (this.rotated === false) {
// 如果达到触发 rotate 的阈值, 则进入旋转状态, 更新
if (Math.abs(rotation) > GestureDector.ROTATE_THRESHOLD) {
if (Math.abs(rotation) > GestureDetector.ROTATE_THRESHOLD) {
this.rotated = true
} else {
direction = this.startDirection
@ -1185,7 +1212,7 @@ export default class GestureDector {
const gValue = (
oldvx: number,
newvx: number,
r = GestureDector.VELOCITY_SMOOTHING
r = GestureDetector.VELOCITY_SMOOTHING
) => oldvx * r + newvx * (1 - r)
this.vx = gValue(this.vx, vx)
@ -1386,9 +1413,9 @@ export default class GestureDector {
const dt = thisTap.timeStamp - lastTap.timeStamp
return (
dx < GestureDector.DOUBLE_TAP_DISTANCE &&
dy < GestureDector.DOUBLE_TAP_DISTANCE &&
dt < GestureDector.DOUBLE_TAP_TIME
dx < GestureDetector.DOUBLE_TAP_DISTANCE &&
dy < GestureDetector.DOUBLE_TAP_DISTANCE &&
dt < GestureDetector.DOUBLE_TAP_TIME
)
}
@ -1399,7 +1426,7 @@ export default class GestureDector {
* (THRESHOLD_SMOOTHING),
*/
private gBtCoordinate<T extends GestureCoordinate>(c1: T, c2: T): T {
const r = GestureDector.THRESHOLD_SMOOTHING
const r = GestureDetector.THRESHOLD_SMOOTHING
const gValue = (arg: keyof GestureCoordinate) =>
Math.floor(c1[arg] + r * (c2[arg] - c1[arg]))
@ -1549,7 +1576,7 @@ export default class GestureDector {
}
/**
* GestureDector
* GestureDetector
*
* option options
*/
@ -1583,14 +1610,13 @@ export default class GestureDector {
public static embedded<T extends EmbededGestureHTMLElement>(
el: T,
options?: GestureOptions
): T {
if (el._addEventListener || el.gestureDector) {
console.error(el + 'had been embedded!')
return el
): GestureDetector {
if (el._addEventListener || el.gestureDetector) {
throw new Error(el + 'had been embedded!')
}
el._addEventListener = el.addEventListener
el.gestureDector = new GestureDector(el, options)
el.gestureDetector = new GestureDetector(el, options)
el.cacheListeners = []
el.addEventListener = function cAddEventListener<
K extends keyof HTMLElementEventMap & GestureEvents
@ -1619,7 +1645,7 @@ export default class GestureDector {
case 'swiperight':
case 'swipedown':
case 'swipeup':
this.gestureDector!.add(type, options)
this.gestureDetector!.add(type, options)
break
}
el.cacheListeners!.push({
@ -1629,25 +1655,23 @@ export default class GestureDector {
})
el._addEventListener!.bind(this)(type, listener, options)
}
return el
return el.gestureDetector
}
public static disembedded<T extends EmbededGestureHTMLElement>(el: T): T {
if (!(el._addEventListener && el.gestureDector)) {
console.error(el + "can't be disembedded!")
return el
public static disembedded<T extends EmbededGestureHTMLElement>(el: T) {
if (!(el._addEventListener && el.gestureDetector)) {
throw new Error(el + "can't be disembedded!")
}
el.cacheListeners?.forEach(({type, listener, options}) => {
el.removeEventListener(type, listener, options)
})
// TODO: 清理 GestureDetector 中的内容
el.gestureDector.listenEvents.clear()
el.gestureDector.listenOnceEvents.clear()
el.gestureDetector.listenEvents.clear()
el.gestureDetector.listenOnceEvents.clear()
el.cacheListeners = []
delete el._addEventListener
delete el.gestureDector
return el
delete el.gestureDetector
}
private static _GestureDetectorId = 0

View File

@ -1,11 +1,16 @@
import {html, css, LitElement} from 'lit'
import {customElement, property, state} from 'lit/decorators.js'
import {customElement, property, query, state} from 'lit/decorators.js'
import {StarClock} from '../../../components/clock/clock'
@customElement('panel-clock')
export class PanelClock extends LitElement {
@property()
foo = ''
@state()
date: any = '0'
@query('#test1') clockTest1!: StarClock
@query('#test2') clockTest2!: StarClock
@query('#test3') clockTest3!: StarClock
@query('#test4') clockTest4!: StarClock
render() {
return html`
<h3
@ -17,14 +22,10 @@ export class PanelClock extends LitElement {
style="display:flex;justify-content: center; align-items: center; padding: 20px 0;"
>
<div style=" width: 380px; height: 380px;overflow: hidden">
<star-clock date="${this.date}" type="diale"></star-clock>
<star-clock id="test1" type="diale"></star-clock>
</div>
<div style="width: 380px; height: 380px;overflow: hidden">
<star-clock
date="${this.date}"
type="diale"
mode="light"
></star-clock>
<star-clock id="test2" type="diale" mode="light"></star-clock>
</div>
</div>
<h3
@ -36,26 +37,23 @@ export class PanelClock extends LitElement {
style="display:flex;justify-content: center; align-items: center; padding: 20px 0"
>
<div style="width: 380px; height: 380px;overflow: hidden">
<star-clock date="${this.date}" type="transparent"></star-clock>
<star-clock id="test3" type="transparent"></star-clock>
</div>
<div style="width: 380px; height: 380px;overflow: hidden">
<star-clock
date="${this.date}"
type="transparent"
mode="light"
></star-clock>
<star-clock id="test4" type="transparent" mode="light"></star-clock>
</div>
</div>
`
}
static styles = css``
protected firstUpdated() {
this.date = new Date() //.getTime()
// let timeMy = new Date(Number(this.date))
// let hour = timeMy.getHours()
// let minute = timeMy.getMinutes()
// let second = timeMy.getSeconds()
// console.log('传的值和类型:000', hour, minute, second)
this.clockTest1.date = new Date() // 传Date型
this.clockTest2.date = new Date().getTime() // 传Number型
this.clockTest3.date = new Date().toString() // 传string型
this.clockTest4.date = new Date().toString() // 传string型
// this.date = new Date().toString()
// this.date = new Date().getTime()
// this.date = new Date()
}
}
declare global {

View File

@ -75,6 +75,7 @@ export class PanelContainer extends LitElement {
// 存储全局变量
;(window as any).dock = this.dock
;(window as any).container = this.container
;(window as any).pageIndicator = this.pageIndicator
;(window as any).home = this
// container 相关事件
@ -128,6 +129,7 @@ export class PanelContainer extends LitElement {
})
} else {
this.addAppIcon(1, 1)
this.container.changeLayout()
let promise = new Promise((res) => {
res(undefined)
})

View File

@ -21,6 +21,7 @@ import './container/container'
import './radio/radio'
import './confirm/confirm'
import './clock/clock'
import './weather/weather'
import './overflowmenu/overflowmenu'
import './switch/switch'
import './slider/slider'
@ -317,6 +318,14 @@ export class PanelRoot extends LitElement {
iconcolor="green"
href="#clock"
></star-li>
<hr />
<star-li
type=${LiType.ICON_LABEL}
label="天气"
icon="moon"
iconcolor="green"
href="#weather"
></star-li>
</star-ul>
<star-ul type=${UlType.ONLY_HEADER} title="手势">

View File

@ -0,0 +1,53 @@
import {html, css, LitElement} from 'lit'
import {customElement, query, state} from 'lit/decorators.js'
import {StarWeather} from '../../../components/weather/weather.js'
import {weatherData} from './weatherData.js'
@customElement('panel-weather')
export class PanelWeather extends LitElement {
@state()
foo = ''
@state()
data = Array()
@query('#type11') weatherDemo1!: StarWeather
@query('#type12') weatherDemo2!: StarWeather
@query('#type21') weatherDemo3!: StarWeather
@query('#type22') weatherDemo4!: StarWeather
render() {
return html`
<div
style="width: 100vw; height: 100vh;background: rgba(53,168,239,0.3);display:flex;justify-content: center; align-items: center;padding: 90px 0; flex-wrap: wrap"
>
<!-- <div style="width: 20%;height:20%; border: 1px dashed #bd135f; ">
<star-weather id="type11" type="type11"></star-weather>
</div>
<div style="width: 25%;height:50%; border: 1px dashed #bd135f; ">
<star-weather id="type12" type="type12"></star-weather>
</div>
<div style="width: 25%;height:50%;border: 1px dashed #bd135f;">
<star-weather id="type21" type="type21"></star-weather>
</div> -->
<!-- <div style="width: 50%;height:50%; border: 1px dashed #e72517;"> -->
<star-weather id="type22" type="type22"></star-weather>
<!-- </div> -->
</div>
`
}
static styles = css`
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
`
protected firstUpdated() {
// this.weatherDemo1.data = weatherData
// this.weatherDemo2.data = weatherData
// this.weatherDemo3.data = weatherData
this.weatherDemo4.data = weatherData
}
}
declare global {
interface HTMLElementTagNameMap {
'panel-weather': PanelWeather
}
}

View File

@ -0,0 +1,30 @@
export const weatherData = {
location: '长沙市',
weatherInfo: [
{
date: new Date(),
temperature: {
min: '22℃',
max: '29℃',
},
weather: {
labelZh: '多云',
labelEn: 'PartlyCloudy',
},
wind: {
label: '南风',
value: '6级',
},
humidity: '40%',
airQuality: {
label: '空气质量',
value: '28',
type: '优',
},
somatosensoryTemperature: '32°C',
visibility: '33km',
ultravioletRys: '强',
},
{},
],
}

View File

@ -1,6 +1,8 @@
// import {html, LitElement, css} from 'lit'
// import {customElement} from 'lit/decorators.js'
import {StarBaseElement} from '../components/base'
/**
* :
*
@ -27,7 +29,12 @@
* <template>
*/
// @customElement('gaia-widget')
export default class GaiaWidget extends HTMLElement {
function lowerCase(str: string) {
str = str.replace(/\s/g, '')
return str.toLocaleLowerCase()
}
export default class GaiaWidget extends StarBaseElement {
url!: string
size!: [number, number]
origin!: string
@ -59,15 +66,14 @@ export default class GaiaWidget extends HTMLElement {
this.url = url // 组件文件地址
this.origin = origin // 注册应用 origin
this.size = size // 组件行列大小
this.appName = appName
this.appName = lowerCase(appName)
this.attachShadow({mode: 'open'})
this.shadowRoot!.innerHTML = this.template
this.init()
this.dispatchReady()
}
connectedCallback() {}
init() {
// 补全小组件入口地址
if (!/^http(s)?:\/\//.test(this.url)) {
@ -84,20 +90,16 @@ export default class GaiaWidget extends HTMLElement {
this.container.addEventListener('touchmove', this)
this.container.addEventListener('touchend', this)
this.container.addEventListener('click', this)
}
dispatchReady = () => {
// 需要在构造函数中被调用在connectedCallback中调用会导致移动元素时刷新的问题
this.querySources(this.url)
// @ts-ignore
.then(this.parseHTML)
.then(() => {
// 防止安装、更新应用时,首次 Activity 请求因注册方 Service Worker 未完成安装而丢失
let n = 0
this.activityRequestTimer = window.setInterval(() => {
if (n++ > 4) clearInterval(this.activityRequestTimer)
this.openActivity({data: {type: 'ready'}})
}, 100)
})
.catch((err) => console.error(err))
// 防止安装、更新应用时,首次 Activity 请求因注册方 Service Worker 未完成安装而丢失
let n = 0
this.activityRequestTimer = window.setInterval(() => {
if (n++ > 4) clearInterval(this.activityRequestTimer)
this.openActivity({data: {type: 'ready'}})
}, 100)
}
refresh(widgetInfo: {size: [number, number]; url: string}) {
@ -259,10 +261,11 @@ export default class GaiaWidget extends HTMLElement {
* Activity
*/
handleActivity = (data: any) => {
const {changeContext, changeAttributes} = data
const {changeContext, changeAttributes, changeProperties} = data
this.changeAttributes(changeAttributes)
this.changeContext(changeContext)
this.changeProperties(changeProperties)
}
changeContext = (data: any) => {
@ -293,6 +296,16 @@ export default class GaiaWidget extends HTMLElement {
})
}
changeProperties = (data: any) => {
if (!data) return
for (const key in data) {
const value = data[key] as string
// @ts-ignore
this[key] = value
}
}
/**
* TBD: 需要考虑更多元素
* img资源请求路径
@ -428,6 +441,3 @@ export default class GaiaWidget extends HTMLElement {
`
}
}
try {
customElements.define('gaia-widget', GaiaWidget)
} catch (error) {}

View File

@ -0,0 +1,88 @@
import GaiaWidget from '../gaia-widget'
import '../../components/weather/weather'
import {StarWeather} from '../../components/weather/weather'
import {customElement} from 'lit/decorators.js'
@customElement('gaia-weather')
class WeatherWidget extends GaiaWidget {
_type: string = 'type22'
_data: any
widget!: StarWeather
constructor({
url,
appName,
origin,
size,
manifestWidgetName,
}: {
url: string
size: [number, number]
origin: string
appName: string
manifestWidgetName: string
}) {
super({
url: url || 'js/widgets/weather.js',
appName: appName || 'homescreen',
origin: origin || 'http://homescreen.localhost/manifest.webmanifest',
size: size || [2, 2],
manifestWidgetName: manifestWidgetName || 'weather',
})
}
get type() {
return this._type
}
set type(value) {
this.type = value
this.widget.type = value
}
get data() {
return this._data
}
set data(value: any) {
this._data = value
if (!this.widget) {
setTimeout(() => {
this.widget.data = value
}, 100)
} else {
this.widget.data = value
}
}
init() {}
connectedCallback() {
this.widget = this.shadowRoot?.querySelector('star-weather') as StarWeather
}
static get observedAttributes() {
return ['type']
}
attributeChangedCallback(name: string, _: string, newValue: string) {
switch (name) {
case 'type':
this.type = newValue
break
}
}
get template() {
return `
<star-weather type="type22"></star-weather>
<style>
:host {
height: 100%;
width:100%;
}
</style>
`
}
}
export default WeatherWidget

77
tasks/build-widgets.js Normal file
View File

@ -0,0 +1,77 @@
import fs from 'fs'
import {build} from 'vite'
const PWD = process.cwd()
const clearDir = (path, exclude) => {
var files = []
if (fs.existsSync(path)) {
files = fs.readdirSync(path)
for (const file of files) {
if (file === exclude) continue
var curPath = path + '/' + file
if (fs.statSync(curPath).isDirectory()) {
clearDir(curPath)
fs.rmdirSync(curPath)
} else {
fs.unlinkSync(curPath)
}
}
}
}
const fun = async (widgetName, entryName) => {
await build({
build: {
lib: {
entry: `src/widgets/${widgetName}/${entryName}.ts`,
formats: ['es'],
fileName: `${widgetName}`,
},
outDir: `dist/widgets/${widgetName}/`,
},
})
clearDir(`dist/widgets/${widgetName}`, `${widgetName}.js`)
}
const safeReadDirSync = (path) => {
let dirData = {}
try {
dirData = fs.readdirSync(path)
} catch (ex) {
if (ex.code == 'EACCES' || ex.code == 'EPERM') {
// 无权访问该文件夹,跳过
return null
} else {
throw ex
}
}
return dirData
}
const buildAll = () => {
const widgetsFilePath = `${PWD}/src/widgets`
const dirData = safeReadDirSync(widgetsFilePath)
dirData?.forEach((fileName) => {
const widgetPath = `${widgetsFilePath}/${fileName}`
const stats = fs.statSync(widgetPath)
if (stats.isDirectory()) {
const files = safeReadDirSync(widgetPath)
if (files.includes(`${fileName}.ts`)) {
fun(fileName, fileName)
} else if (files.includes(`index.ts`)) {
fun(fileName, 'index')
} else {
throw new Error(`Entry file of ${fileName} widget dose not exist!`)
}
}
})
}
buildAll()

View File

@ -1,13 +0,0 @@
import {defineConfig} from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
build: {
lib: {
entry: `src/widgets/${process.env.WIDGET_FILE_NAME}/${process.env.WIDGET_FILE_NAME}.ts`,
formats: ['es'],
fileName: `${process.env.WIDGET_FILE_NAME}`,
},
outDir: `dist/widgets/${process.env.WIDGET_FILE_NAME}/`,
},
})