[lisa]fix: page
This commit is contained in:
@@ -8,7 +8,8 @@
|
||||
"pages/logs/logs",
|
||||
"pages/history/history",
|
||||
"pages/terms/terms",
|
||||
"pages/privacy/privacy"
|
||||
"pages/privacy/privacy",
|
||||
"pages/analyze/analyze"
|
||||
],
|
||||
"window": {
|
||||
"navigationBarTextStyle": "black",
|
||||
@@ -17,16 +18,6 @@
|
||||
"backgroundColor": "#ffffff",
|
||||
"backgroundTextStyle": "light"
|
||||
},
|
||||
|
||||
"permission": {
|
||||
"scope.camera": {
|
||||
"desc": "需要使用相机拍照识别图片"
|
||||
},
|
||||
"scope.writePhotosAlbum": {
|
||||
"desc": "需要访问相册选择图片"
|
||||
}
|
||||
},
|
||||
"componentFramework": "glass-easel",
|
||||
"sitemapLocation": "sitemap.json",
|
||||
"lazyCodeLoading": "requiredComponents",
|
||||
"useExtendedLib" : {
|
||||
|
||||
6
miniprogram/pages/analyze/analyze.json
Normal file
6
miniprogram/pages/analyze/analyze.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"navigationBarTitleText": "图片解析中",
|
||||
"navigationStyle": "default",
|
||||
"disableScroll": true,
|
||||
"backgroundColor": "#000000"
|
||||
}
|
||||
123
miniprogram/pages/analyze/analyze.ts
Normal file
123
miniprogram/pages/analyze/analyze.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
Page({
|
||||
data: {
|
||||
imageUrl: '/static/sun.png',
|
||||
// 用于驱动 CSS 变量的角度与边缘接近度(0-100)
|
||||
pointerAngle: 110,
|
||||
pointerD: 0
|
||||
},
|
||||
// 旧的 canvas 动画相关字段不再使用
|
||||
wrapperRect: null as any,
|
||||
|
||||
onLoad(query: Record<string, string>) {
|
||||
const { imageUrl } = query
|
||||
if (imageUrl) {
|
||||
this.setData({ imageUrl })
|
||||
}
|
||||
},
|
||||
|
||||
onReady() {
|
||||
// 预先获取容器尺寸,避免首次触摸时未取到
|
||||
this.ensureWrapperRect()
|
||||
// 首屏引导动画,参考 test.html 的节奏
|
||||
// this.playIntroAnimation()
|
||||
},
|
||||
|
||||
onImageLoad() {
|
||||
// 不再初始化 canvas 动画;仅确保容器尺寸缓存
|
||||
this.ensureWrapperRect()
|
||||
},
|
||||
|
||||
ensureWrapperRect(cb?: Function) {
|
||||
if (this.wrapperRect) {
|
||||
cb && cb()
|
||||
return
|
||||
}
|
||||
const qs = wx.createSelectorQuery()
|
||||
qs.select('.bg-wrapper').boundingClientRect().exec((res) => {
|
||||
const rect = res?.[0]
|
||||
if (rect && rect.width && rect.height) {
|
||||
this.wrapperRect = rect
|
||||
}
|
||||
cb && cb()
|
||||
})
|
||||
},
|
||||
|
||||
// 触控更新光晕方向与强度(边缘接近度)
|
||||
// onGlowTouchMove(e: any) {
|
||||
// const touch = e?.changedTouches?.[0]
|
||||
// if (!touch) return
|
||||
// this.ensureWrapperRect(() => {
|
||||
// const rect = this.wrapperRect
|
||||
// if (!rect) return
|
||||
// const { left, top, width, height } = rect
|
||||
// const x = Math.max(0, Math.min(width, touch.pageX - left))
|
||||
// const y = Math.max(0, Math.min(height, touch.pageY - top))
|
||||
// const cx = width / 2
|
||||
// const cy = height / 2
|
||||
// const dx = x - cx
|
||||
// const dy = y - cy
|
||||
// let angleRadians = 0
|
||||
// let angleDegrees = 0
|
||||
// if (dx !== 0 || dy !== 0) {
|
||||
// angleRadians = Math.atan2(dy, dx)
|
||||
// angleDegrees = angleRadians * (180 / Math.PI) + 90
|
||||
// if (angleDegrees < 0) angleDegrees += 360
|
||||
// }
|
||||
// let kx = Infinity, ky = Infinity
|
||||
// if (dx !== 0) kx = cx / Math.abs(dx)
|
||||
// if (dy !== 0) ky = cy / Math.abs(dy)
|
||||
// const closeness = Math.min(Math.max(1 / Math.min(kx, ky), 0), 1)
|
||||
// const pointerD = Math.round(closeness * 100)
|
||||
// this.setData({ pointerAngle: Math.round(angleDegrees * 100) / 100, pointerD })
|
||||
// })
|
||||
// },
|
||||
|
||||
// 引导动画:角度扫过 + 边缘接近度渐变
|
||||
playIntroAnimation() {
|
||||
const angleStart = 110
|
||||
const angleEnd = 465
|
||||
this.setData({ pointerAngle: angleStart })
|
||||
|
||||
// 阶段 1:pointerD 从 0 -> 50
|
||||
this.animateNumber({ duration: 500, startValue: 0, endValue: 50, ease: this.easeOutCubic, onUpdate: (v: number) => {
|
||||
this.setData({ pointerD: Math.round(v) })
|
||||
}})
|
||||
|
||||
// 阶段 2:角度 110 -> 465,pointerD 维持 50
|
||||
this.animateNumber({ delay: 0, duration: 1500, startValue: angleStart, endValue: angleEnd, ease: this.easeInCubic, onUpdate: (v: number) => {
|
||||
this.setData({ pointerAngle: Math.round(v * 100) / 100 })
|
||||
}})
|
||||
|
||||
// 阶段 3:继续角度,pointerD 50 -> 100
|
||||
this.animateNumber({ delay: 1500, duration: 2250, startValue: 50, endValue: 100, ease: this.easeOutCubic, onUpdate: (v: number) => {
|
||||
this.setData({ pointerD: Math.round(v) })
|
||||
}})
|
||||
|
||||
// 阶段 4:pointerD 100 -> 0,角度保持循环动画由 CSS 完成
|
||||
this.animateNumber({ delay: 2500, duration: 1500, startValue: 100, endValue: 0, ease: this.easeInCubic, onUpdate: (v: number) => {
|
||||
this.setData({ pointerD: Math.round(v) })
|
||||
}})
|
||||
},
|
||||
|
||||
// 简化的数值动画(基于 setTimeout 模拟 rAF)
|
||||
animateNumber(options: { startValue?: number, endValue?: number, duration?: number, delay?: number, ease?: Function, onUpdate?: Function }) {
|
||||
const { startValue = 0, endValue = 100, duration = 1000, delay = 0, onUpdate = () => {}, ease = (t: number) => t } = options
|
||||
const startTime = Date.now() + delay
|
||||
const step = () => {
|
||||
const now = Date.now()
|
||||
const elapsed = now - startTime
|
||||
const t = Math.max(0, Math.min(elapsed / duration, 1))
|
||||
const eased = startValue + (endValue - startValue) * ease(t)
|
||||
onUpdate(eased)
|
||||
if (t < 1) setTimeout(step, 16)
|
||||
}
|
||||
setTimeout(step, delay)
|
||||
},
|
||||
|
||||
easeOutCubic(x: number) { return 1 - Math.pow(1 - x, 3) },
|
||||
easeInCubic(x: number) { return x * x * x },
|
||||
|
||||
onUnload() {
|
||||
// 无需清理 canvas 计时器
|
||||
}
|
||||
})
|
||||
11
miniprogram/pages/analyze/analyze.wxml
Normal file
11
miniprogram/pages/analyze/analyze.wxml
Normal file
@@ -0,0 +1,11 @@
|
||||
<view class="container">
|
||||
<!-- <view class="bg-wrapper" bindtouchmove="onGlowTouchMove" bindtouchstart="onGlowTouchMove" style="--pointer-°: {{pointerAngle}}deg; --pointer-d: {{pointerD}}; --glow-sens: 30; --color-sens: 50;"> -->
|
||||
<view class="card" style="--pointer-°: {{pointerAngle}}deg; --pointer-d: {{pointerD}}; --glow-sens: 30; --color-sens: 50;">
|
||||
<image class="bg-image" src="{{imageUrl}}" mode="widthFix" bindload="onImageLoad"></image>
|
||||
<view class="glow"></view>
|
||||
</view>
|
||||
<!-- <div class="mic">
|
||||
<div class="mic-shadow"></div>
|
||||
</div> -->
|
||||
<view class="card-1">magic</view>
|
||||
</view>
|
||||
268
miniprogram/pages/analyze/analyze.wxss
Normal file
268
miniprogram/pages/analyze/analyze.wxss
Normal file
@@ -0,0 +1,268 @@
|
||||
.container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.bg-wrapper {
|
||||
position: relative;
|
||||
width: 80vw;
|
||||
max-width: 1000rpx;
|
||||
border-radius: 24rpx;
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
.bg-image {
|
||||
width: 400rpx;
|
||||
height: auto;
|
||||
display: block;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* :root {
|
||||
--glow-sens: 30;
|
||||
--card-bg: linear-gradient(8deg,var(--dark) 75%, color-mix(in hsl, var(--dark), white 2.5%) 75.5%);
|
||||
--blend: soft-light;
|
||||
--glow-blend: plus-lighter;
|
||||
--glow-color: 40deg 80% 80%;
|
||||
--glow-boost: 0%;
|
||||
--pads: 40px;
|
||||
--color-sens: calc(var(--glow-sens) + 20);
|
||||
--pointer-°: 45deg;
|
||||
} */
|
||||
|
||||
|
||||
.card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: clamp(320px, calc(100svw - calc(40px * 2)), 600px);
|
||||
height: calc(100svh - calc(40px * 2));
|
||||
max-height: 600px;
|
||||
border-radius: 1.768em;
|
||||
isolation: isolate;
|
||||
transform: translate3d(0, 0, 0.01px);
|
||||
display: grid;
|
||||
border: 1px solid rgb(255 255 255 / 25%);
|
||||
/* background: var(--card-bg); */
|
||||
background-repeat: no-repeat;
|
||||
box-shadow:
|
||||
rgba(0, 0, 0, 0.1) 0px 1px 2px,
|
||||
rgba(0, 0, 0, 0.1) 0px 2px 4px,
|
||||
rgba(0, 0, 0, 0.1) 0px 4px 8px,
|
||||
rgba(0, 0, 0, 0.1) 0px 8px 16px,
|
||||
rgba(0, 0, 0, 0.1) 0px 16px 32px,
|
||||
rgba(0, 0, 0, 0.1) 0px 32px 64px;
|
||||
}
|
||||
|
||||
.card::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
transition: opacity 0.25s ease-out;
|
||||
z-index: -1;
|
||||
border: 1px solid transparent;
|
||||
background:
|
||||
radial-gradient(at 80% 55%, hsla(268,100%,76%,1) 0px, transparent 50%) padding-box,
|
||||
radial-gradient(at 69% 34%, hsla(349,100%,74%,1) 0px, transparent 50%) padding-box,
|
||||
radial-gradient(at 8% 6%, hsla(136,100%,78%,1) 0px, transparent 50%) padding-box,
|
||||
radial-gradient(at 41% 38%, hsla(192,100%,64%,1) 0px, transparent 50%) padding-box,
|
||||
radial-gradient(at 86% 85%, hsla(186,100%,74%,1) 0px, transparent 50%) padding-box,
|
||||
radial-gradient(at 82% 18%, hsla(52,100%,65%,1) 0px, transparent 50%) padding-box,
|
||||
radial-gradient(at 51% 4%, hsla(12,100%,72%,1) 0px, transparent 50%) padding-box,
|
||||
linear-gradient(#c299ff 0 100%) padding-box;
|
||||
mask-image:
|
||||
linear-gradient( to bottom, black, black ),
|
||||
radial-gradient( ellipse at 50% 50%, black 40%, transparent 65% ),
|
||||
radial-gradient( ellipse at 66% 66%, black 5%, transparent 40% ),
|
||||
radial-gradient( ellipse at 33% 33%, black 5%, transparent 40% ),
|
||||
radial-gradient( ellipse at 66% 33%, black 5%, transparent 40% ),
|
||||
radial-gradient( ellipse at 33% 66%, black 5%, transparent 40% ),
|
||||
conic-gradient( from 45deg at center, transparent 5%, black 15%, black 85%, transparent 95% );
|
||||
|
||||
mask-composite: subtract,add,add,add,add,add;
|
||||
|
||||
/* opacity increases as pointer gets near edge */
|
||||
opacity: calc((var(--pointer-d) - 50) / (100 - 50));
|
||||
mix-blend-mode: soft-light;
|
||||
}
|
||||
.card::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
transition: opacity 0.25s ease-out;
|
||||
z-index: -1;
|
||||
border: 1px solid transparent;
|
||||
|
||||
background:
|
||||
linear-gradient(linear-gradient(8deg,var(--dark) 75%, color-mix(in hsl, var(--dark), white 2.5%) 75.5%) 0 100%) padding-box,
|
||||
linear-gradient(rgb(255 255 255 / 0%) 0% 100%) border-box,
|
||||
radial-gradient(at 80% 55%, hsla(268,100%,76%,1) 0px, transparent 50%) border-box,
|
||||
radial-gradient(at 69% 34%, hsla(349,100%,74%,1) 0px, transparent 50%) border-box,
|
||||
radial-gradient(at 8% 6%, hsla(136,100%,78%,1) 0px, transparent 50%) border-box,
|
||||
radial-gradient(at 41% 38%, hsla(192,100%,64%,1) 0px, transparent 50%) border-box,
|
||||
radial-gradient(at 86% 85%, hsla(186,100%,74%,1) 0px, transparent 50%) border-box,
|
||||
radial-gradient(at 82% 18%, hsla(52,100%,65%,1) 0px, transparent 50%) border-box,
|
||||
radial-gradient(at 51% 4%, hsla(12,100%,72%,1) 0px, transparent 50%) border-box,
|
||||
linear-gradient(#c299ff 0 100%) border-box;
|
||||
|
||||
/* opacity increases as pointer gets near edge */
|
||||
opacity: calc((var(--pointer-d) - 50) / (100 - 50));
|
||||
|
||||
/* border is masked to a cone, originating from the center towards the pointer */
|
||||
mask-image:
|
||||
conic-gradient(
|
||||
from 45deg at center, black 25%, transparent 40%, transparent 60%, black 75%
|
||||
);
|
||||
}
|
||||
|
||||
.glow {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
transition: opacity 0.25s ease-out;
|
||||
z-index: -1;
|
||||
/* glowing border edges */
|
||||
|
||||
--outset: 40px;
|
||||
|
||||
/* outer padding so the glow can overflow the element without being masked */
|
||||
inset: calc(var(--outset) * -1);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
|
||||
/* glow is masked to a cone, originating from the center towards the pointer */
|
||||
mask-image:
|
||||
conic-gradient(
|
||||
from 45deg at center, black 2.5%, transparent 10%, transparent 90%, black 97.5%
|
||||
);
|
||||
|
||||
/* opacity increases as pointer gets near edge */
|
||||
opacity: calc((var(--pointer-d) - 30) / (100 - 30));
|
||||
mix-blend-mode: 'plus-lighter';
|
||||
}
|
||||
.glow::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: var(--outset);
|
||||
border-radius: inherit;
|
||||
box-shadow:
|
||||
inset 0 0 0 1px hsl( 40deg 80% 80% / 100%),
|
||||
|
||||
inset 0 0 1px 0 hsl( 40deg 80% 80% / calc(0% + 60%)),
|
||||
inset 0 0 3px 0 hsl( 40deg 80% 80% / calc(0% + 50%)),
|
||||
inset 0 0 6px 0 hsl( 40deg 80% 80% / calc(0% + 40%)),
|
||||
inset 0 0 15px 0 hsl( 40deg 80% 80% / calc(0% + 30%)),
|
||||
inset 0 0 25px 2px hsl( 40deg 80% 80% / calc(0% + 20%)),
|
||||
inset 0 0 50px 2px hsl( 40deg 80% 80% / calc(0% + 10%)),
|
||||
|
||||
0 0 1px 0 hsl( 40deg 80% 80% / calc(0% + 60%)),
|
||||
0 0 3px 0 hsl( 40deg 80% 80% / calc(0% + 50%)),
|
||||
0 0 6px 0 hsl( 40deg 80% 80% / calc(0% + 40%)),
|
||||
0 0 15px 0 hsl( 40deg 80% 80% / calc(0% + 30%)),
|
||||
0 0 25px 2px hsl( 40deg 80% 80% / calc(0% + 20%)),
|
||||
0 0 50px 2px hsl( 40deg 80% 80% / calc(0% + 10%));
|
||||
}
|
||||
|
||||
@keyframes fadeContent {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
body, html {
|
||||
height: 100svh;
|
||||
overflow: auto;
|
||||
background: hsl(var(--h), 18%, 12%);
|
||||
}
|
||||
|
||||
main {
|
||||
justify-items: center;
|
||||
align-content: center;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
/* .sun {
|
||||
opacity: 0.25;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
} */
|
||||
.moon {
|
||||
opacty: 1;
|
||||
}
|
||||
|
||||
.sun, .moon {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.card-1 {
|
||||
background: #191c29;
|
||||
width:200rpx;
|
||||
height: 200rpx;
|
||||
padding: 10rpx;
|
||||
position: relative;
|
||||
border-radius: 6rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
font-size: 1.5em;
|
||||
color: rgb(88 199 250 / 0%);
|
||||
cursor: pointer;
|
||||
font-family: cursive;
|
||||
animation: spin 2.5s linear infinite;
|
||||
}
|
||||
|
||||
.card-1:before {
|
||||
content: "";
|
||||
width: 104%;
|
||||
height: 102%;
|
||||
border-radius: 8rpx;
|
||||
background-image: linear-gradient(
|
||||
var(--rotate)
|
||||
, #5ddcff, #3c67e3 43%, #4e00c2);
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: -1%;
|
||||
left: -2%;
|
||||
animation: spin 2.5s linear infinite;
|
||||
}
|
||||
|
||||
.card-1:after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
top: 10rpx;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: -1;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
transform: scale(0.8);
|
||||
filter: blur(10rpx);
|
||||
background-image: linear-gradient(
|
||||
var(--rotate)
|
||||
, #5ddcff, #3c67e3 43%, #4e00c2);
|
||||
opacity: 1;
|
||||
transition: opacity .5s;
|
||||
animation: spin 2.5s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
--rotate: 0deg;
|
||||
}
|
||||
100% {
|
||||
--rotate: 360deg;
|
||||
}
|
||||
}
|
||||
@@ -35,11 +35,15 @@
|
||||
<view class="button-row">
|
||||
<t-icon name="{{isPlaying ? 'pause' : 'play'}}" class="bottom-button" size="48rpx" bind:tap="playStandardVoice" />
|
||||
<view class="bottom-button-img-wrap bottom-button" bind:tap="onTransTap">
|
||||
<!-- <image src="{{transDisplayMode === 'en_ipa' ? '/static/英.png' : transDisplayMode === 'en' ? '/static/文-中.png' : '/static/文.png'}}" style="width: 32rpx; height: 32rpx;" mode="aspectFit" /> -->
|
||||
<t-icon name="translate" class="trans-button left-half {{transDisplayMode === 'en_ipa' ? 'trans-active' : 'trans-deactive'}}" size="48rpx"/>
|
||||
<t-icon name="translate" class="trans-button right-half {{transDisplayMode === 'en_zh' ? 'trans-active' : 'trans-deactive'}}" size="48rpx"/>
|
||||
<t-icon name="translate" class="trans-button left-half {{transDisplayMode === 'en_ipa' ? 'trans-active' : 'trans-deactive'}}" size="48rpx" />
|
||||
<t-icon name="translate" class="trans-button right-half {{transDisplayMode === 'en_zh' ? 'trans-active' : 'trans-deactive'}}" size="48rpx" />
|
||||
</view>
|
||||
<view class="bottom-button mic-wrap">
|
||||
<t-icon name="microphone-1" color="{{isRecording ? '#FFFFFF' : '#333333'}}" class="microphone {{isRecording ? 'recording' : 'bottom-button'}}" size="48rpx" bind:longpress="handleRecordStart" bind:touchend="handleRecordEnd" bind:touchcancel="handleRecordEnd" />
|
||||
<view wx:if="{{isRecording}}" class="mic">
|
||||
<view class="mic-shadow"></view>
|
||||
</view>
|
||||
</view>
|
||||
<t-icon name="microphone-1" class="microphone bottom-button {{isRecording ? 'recording' : ''}}" size="48rpx" bind:longpress="handleRecordStart" bind:touchend="handleRecordEnd" bind:touchcancel="handleRecordEnd" />
|
||||
<t-icon name="fact-check" class="bottom-button {{hasScoreInfo ? '' : 'disabled'}}" size="48rpx" bind:tap="onScoreTap" />
|
||||
<t-icon name="ellipsis" class="bottom-button {{isMoreMenuOpen ? 'more-open' : ''}}" size="48rpx" bind:tap="onMoreTap" />
|
||||
</view>
|
||||
|
||||
@@ -194,13 +194,19 @@
|
||||
|
||||
.microphone {
|
||||
transition: all 0.3s ease;
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.microphone.recording {
|
||||
transform: scale(1.1);
|
||||
background: #ff3b30 !important;
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 59, 48, 0.3);
|
||||
animation: pulse 1.5s infinite;
|
||||
background: transparent;
|
||||
/* transform: scale(1.1); */
|
||||
/* background: #ff3b30 !important; */
|
||||
/* box-shadow: 0 4rpx 16rpx rgba(255, 59, 48, 0.3); */
|
||||
/* animation: pulse 1.5s infinite; */
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
@@ -1215,4 +1221,75 @@
|
||||
line-height: 28rpx;
|
||||
color: #909090;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
/* mic 动效容器,跟随底部按钮位置 */
|
||||
.mic-wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 仅在 isRecording 时显示的动效,居中覆盖在按钮上方 */
|
||||
.mic {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #fff;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.mic::before, .mic::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 100%;
|
||||
z-index: 2;
|
||||
box-shadow: 0 0 4.8px 4.8px #1c084f; /* 原为 4px 4px */
|
||||
}
|
||||
.mic::before {
|
||||
width: 72rpx; /* 原为 60rpx */
|
||||
height: 72rpx; /* 原为 60rpx */
|
||||
background-color: #1a084e;
|
||||
}
|
||||
.mic::after {
|
||||
width: 48rpx; /* 原为 40rpx */
|
||||
height: 48rpx; /* 原为 40rpx */
|
||||
background-color: #2f1e5f;
|
||||
animation: mic-circle-size 0.8s linear infinite alternate;
|
||||
}
|
||||
|
||||
.mic-shadow {
|
||||
width: 72rpx; /* 原为 60rpx */
|
||||
height: 72rpx; /* 原为 60rpx */
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
border-radius: 100%;
|
||||
z-index: 1;
|
||||
box-shadow: 3.6rpx -14.4rpx 7.2rpx 3.6rpx #823ca6,
|
||||
9.6rpx -2.4rpx 14.4rpx 3.6rpx #aab3d2,
|
||||
9.6rpx 7.2rpx 26.4rpx 3.6rpx #5acee3,
|
||||
19.2rpx 2.4rpx 7.2rpx 3.6rpx #1b7d8f,
|
||||
2.4rpx 1.2rpx 21.6rpx 3.6rpx #f30bf5;
|
||||
transform: translate(-50%, -50%);
|
||||
transform-origin: 0% 0%;
|
||||
animation: mic-shadow-rotate 2s linear infinite; /* 略慢的旋转节奏 */
|
||||
}
|
||||
|
||||
@keyframes mic-circle-size {
|
||||
from {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
}
|
||||
to {
|
||||
width: 57.6rpx;
|
||||
height: 57.6rpx;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes mic-shadow-rotate {
|
||||
from { rotate: 0deg; }
|
||||
to { rotate: 360deg; }
|
||||
}
|
||||
@@ -44,12 +44,34 @@
|
||||
<view class="hello">{{DayTypeMap[day_type]}}</view>
|
||||
<!-- <view class="begin-text">用一个新单词, 开启美好的一天</view> -->
|
||||
<!-- 功能按钮区域 -->
|
||||
<view class="action-section welcome-card">
|
||||
<!-- <view class="action-section welcome-card">
|
||||
<view class="action-buttons">
|
||||
<t-icon name="image-add" size="140rpx" bind:click="handleImageSelect" />
|
||||
<t-action-sheet id="t-action-sheet" bind:selected="handleSelected" />
|
||||
</view>
|
||||
</view> -->
|
||||
<view class="camera" bind:click="handleImageSelect">
|
||||
<view class="strip"></view>
|
||||
<view class="lens">
|
||||
<view class="lens-shutter"></view>
|
||||
</view>
|
||||
<!-- <view class="shutter">
|
||||
<view class="lens-outer"></view>
|
||||
<view class="lens-inner"></view>
|
||||
<view class="leaf a"></view>
|
||||
<view class="leaf b"></view>
|
||||
<view class="leaf c"></view>
|
||||
</view> -->
|
||||
<view class="led"></view>
|
||||
<view class="btn"></view>
|
||||
<view class="bottom"></view>
|
||||
</view>
|
||||
<view class="photo-wrapper">
|
||||
<view class="photo">
|
||||
<view class="photo-inner"></view>
|
||||
</view>
|
||||
</view>
|
||||
<t-action-sheet id="t-action-sheet" bind:selected="handleSelected" />
|
||||
</view>
|
||||
<view class="history-wrap">
|
||||
<view class="today-card" wx:for="{{todaySummary}}" wx:key="index">
|
||||
|
||||
@@ -722,4 +722,389 @@
|
||||
@keyframes bubbleFloat {
|
||||
0%, 100% { transform: translateY(0px) rotate(0deg); }
|
||||
50% { transform: translateY(-20px) rotate(180deg); }
|
||||
}
|
||||
|
||||
|
||||
.camera {
|
||||
position:relative;
|
||||
/* left:50%; top:50%; */
|
||||
width:300rpx; height:300rpx;
|
||||
margin-top:40rpx;
|
||||
background:#eaeaea;
|
||||
border:1px solid rgba(0,0,0,.2); border-radius:50rpx;
|
||||
overflow:hidden;
|
||||
transition: all .5s ease-in-out;
|
||||
-webkit-transition: all .5s ease-in-out;
|
||||
-moz-transition: all .5s ease-in-out;
|
||||
-ms-transition: all .5s ease-in-out;
|
||||
-o-transition: all .5s ease-in-out;
|
||||
z-index:2;
|
||||
}
|
||||
|
||||
.btn {
|
||||
position: absolute;
|
||||
top: 20rpx; right: 30rpx;
|
||||
width: 45rpx; height: 35rpx;
|
||||
background-color: #2e3e4f;
|
||||
border-radius: 15rpx;
|
||||
box-shadow: 0px 3rpx 0px rgba(0,0,0,.4);
|
||||
transition:all .2 ease-in-out;
|
||||
-webkit-transition:all .2 ease-in-out;
|
||||
-moz-transition:all .2 ease-in-out;
|
||||
-ms-transition:all .2 ease-in-out;
|
||||
-o-transition:all .2 ease-in-out;
|
||||
animation: .5s btn;
|
||||
-webkit-animation: .5s btn;
|
||||
-moz-animation: .5s btn;
|
||||
-ms-animation: .5s btn;
|
||||
-o-animation: .5s btn;
|
||||
animation-iteration-count:5;
|
||||
-webkit-animation-iteration-count:5;
|
||||
-moz-animation-iteration-count:5;
|
||||
-ms-animation-iteration-count:5;
|
||||
-o-animation-iteration-count:5;
|
||||
}
|
||||
|
||||
.strip {
|
||||
height: 110rpx;
|
||||
background-color: #54b59a;
|
||||
border-top: 10rpx solid #479a83;
|
||||
border-bottom: 10rpx solid #479a83;
|
||||
margin: 80rpx 0px;
|
||||
box-shadow: 0px 2rpx 0px rgba(0,0,0,.4);
|
||||
}
|
||||
|
||||
.lens {
|
||||
position:absolute;
|
||||
top:50%; left:50%;
|
||||
width:144rpx; height:144rpx;
|
||||
margin:-90rpx;
|
||||
border:18rpx solid #b44b37;
|
||||
border-radius:50%;
|
||||
background-color:#111;
|
||||
box-shadow: 0px 5rpx 0px rgba(0,0,0,.4);
|
||||
}
|
||||
|
||||
.lens::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 50rpx; height: 50rpx;
|
||||
margin: 27rpx;
|
||||
border: 20rpx solid rgb(60, 60, 60);
|
||||
border-radius: 50%;
|
||||
background: rgb(34, 34, 34);
|
||||
}
|
||||
|
||||
.lens::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 8rpx; height: 8rpx;
|
||||
margin: 57rpx;
|
||||
border: 11rpx solid rgb(22, 22, 22);
|
||||
border-radius: 50%;
|
||||
background: rgb(131, 131, 131);
|
||||
}
|
||||
|
||||
.lens-shutter {
|
||||
position:relative;
|
||||
width:144rpx; height:144rpx;
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.lens-shutter::after {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
transition: .5s all linear;
|
||||
/* animation: shutter 2.0s infinite ease-in-out; */
|
||||
background:
|
||||
linear-gradient(-150deg, transparent 52%, #000 calc(52% + 2rpx) calc(52% + 4rpx), grey calc(52% + 6rpx)) bottom/100% 40% no-repeat,
|
||||
linear-gradient(150deg, transparent 52%, #000 calc(52% + 2rpx) calc(52% + 4rpx), grey calc(52% + 6rpx)),
|
||||
linear-gradient(90deg, transparent 30%, #000 calc(30% + 2rpx) calc(30% + 4rpx), grey calc(30% + 6rpx)),
|
||||
linear-gradient(30deg, transparent 52%, #000 calc(52% + 2rpx) calc(52% + 4rpx), grey calc(52% + 6rpx));
|
||||
transform: rotate(180deg);
|
||||
transform-origin: left;
|
||||
}
|
||||
.lens-shutter::before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
transition: .5s all linear;
|
||||
/* animation: shutter 2.0s infinite ease-in-out; */
|
||||
background:
|
||||
linear-gradient(-150deg, transparent 52%, #000 calc(52% + 2rpx) calc(52% + 4rpx), grey calc(52% + 6rpx)) bottom/100% 40% no-repeat,
|
||||
linear-gradient(150deg, transparent 52%, #000 calc(52% + 2rpx) calc(52% + 4rpx), grey calc(52% + 6rpx)),
|
||||
linear-gradient(90deg, transparent 30%, #000 calc(30% + 2rpx) calc(30% + 4rpx), grey calc(30% + 6rpx)),
|
||||
linear-gradient(30deg, transparent 52%, #000 calc(52% + 2rpx) calc(52% + 4rpx), grey calc(52% + 6rpx));
|
||||
}
|
||||
|
||||
@keyframes shutter {
|
||||
0%, 100% {
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
} 50% {
|
||||
top: -120%;
|
||||
height: 340%;
|
||||
width: 170%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.led {
|
||||
position: absolute;
|
||||
left: 35rpx; top: 30rpx;
|
||||
width: 15rpx; height: 15rpx;
|
||||
border-radius: 50%;
|
||||
background-color: rgb(255, 136, 115);
|
||||
box-shadow: inset 0px 1rpx 0px rgba(0,0,0,.1);
|
||||
animation: led .8s infinite;
|
||||
}
|
||||
|
||||
@keyframes led {
|
||||
from {
|
||||
opacity:.2;
|
||||
}
|
||||
to {
|
||||
opacity:1;
|
||||
}
|
||||
}
|
||||
|
||||
.shutter {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin:-90rpx;
|
||||
background: #181816;
|
||||
box-shadow: 0 0 0 5rpx #181816, 0 0 0 3rpx #373737;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 24rpx;
|
||||
background-color: #c6c6c6;
|
||||
border-radius: 14rpx 14rpx 0 0;
|
||||
}
|
||||
|
||||
.photo-wrapper {
|
||||
position: relative;
|
||||
bottom: 12rpx;
|
||||
left: 0rpx;
|
||||
width: 264rpx;
|
||||
height: 284rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.photo {
|
||||
position: relative;
|
||||
bottom: 0rpx;
|
||||
left: 0rpx;
|
||||
width: 240rpx;
|
||||
height: 240rpx;
|
||||
background-color: white;
|
||||
border-style: solid;
|
||||
border-color: white;
|
||||
border-width: 12rpx 12rpx 32rpx 12rpx;
|
||||
/* box-shadow: 0 4rpx 6rpx rgba(0, 0, 0, 0.1); */
|
||||
overflow: hidden;
|
||||
z-index: 2;
|
||||
animation: reveal 5s;
|
||||
}
|
||||
|
||||
.photo-inner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: black;
|
||||
filter: blur(10rpx) brightness(0%) saturate(0%);
|
||||
}
|
||||
|
||||
@keyframes reveal {
|
||||
0% {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
30% {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
80% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
}
|
||||
|
||||
.lens-outer{
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
margin: 50rpx 0 0 50rpx;
|
||||
position: relative;
|
||||
background: -moz-radial-gradient(83% 83%, circle closest-side, #c0b9c0, #968d9a 35%, #495057);
|
||||
background: -webkit-radial-gradient(83% 83%, circle closest-side, #c0b9c0, #968d9a 35%, #495057);
|
||||
background: -o-radial-gradient(83% 83%, circle closest-side, #c0b9c0, #968d9a 35%, #495057);
|
||||
background: -ms-radial-gradient(83% 83%, circle closest-side, #c0b9c0, #968d9a 35%, #495057);
|
||||
}
|
||||
.lens-outer::before{
|
||||
content: "";
|
||||
display: block;
|
||||
width: 68rpx;
|
||||
height: 68rpx;
|
||||
position: absolute;
|
||||
top: 6rpx;
|
||||
left: 6rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #351c3c;
|
||||
background-image: -webkit-linear-gradient(-45deg, #112b3c, #351c3c 70%);
|
||||
background-image: -moz-linear-gradient(-45deg, #112b3c, #351c3c 70%);
|
||||
background-image: -ms-linear-gradient(-45deg, #112b3c, #351c3c 70%);
|
||||
background-image: -o-linear-gradient(-45deg, #112b3c, #351c3c 70%);
|
||||
box-shadow: 0 0 0 2rpx #111d29;
|
||||
}
|
||||
.lens-outer::after{
|
||||
content: "";
|
||||
display: block;
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
position: absolute;
|
||||
top: 16rpx;
|
||||
left: 16rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #150619;
|
||||
background-image: -webkit-linear-gradient(-45deg, #0a2035, #17081b 70%);
|
||||
background-image: -moz-linear-gradient(-45deg, #0a2035, #17081b 70%);
|
||||
background-image: -ms-linear-gradient(-45deg, #0a2035, #17081b 70%);
|
||||
background-image: -o-linear-gradient(-45deg, #0a2035, #17081b 70%);
|
||||
box-shadow: 0 0 0 2rpx #393745;
|
||||
}
|
||||
.lens-inner{
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
border-radius: 50%;
|
||||
background: #000;
|
||||
position: absolute;
|
||||
top: 76rpx;
|
||||
left: 76rpx;
|
||||
border: 2rpx solid #221f27;
|
||||
}
|
||||
.lens-inner::before{
|
||||
content: "";
|
||||
display: block;
|
||||
width: 66rpx;
|
||||
height: 66rpx;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: -20rpx;
|
||||
left: -20rpx;
|
||||
-webkit-transform: rotate(45deg);
|
||||
-o-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
box-shadow: inset -6rpx 0 6rpx -4rpx #7c4c88;
|
||||
}
|
||||
|
||||
.leaf {
|
||||
width: 176rpx;
|
||||
height: 176rpx;
|
||||
position: absolute;
|
||||
border-radius: 0 0 72rpx 104rpx/0 0 24rpx 40rpx;
|
||||
}
|
||||
.a{
|
||||
bottom: 40rpx;
|
||||
right: 10rpx;
|
||||
box-shadow: 0 2rpx 0 #4c2f4d, -64rpx 24rpx 32rpx #442149, 0 80rpx 0 #7a21a3,inset 0 -2rpx 2rpx #200526;
|
||||
}
|
||||
.a::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 176rpx;
|
||||
height: 176rpx;
|
||||
position: absolute;
|
||||
border-radius: 0 0 72rpx 104rpx/0 0 24rpx 40rpx;
|
||||
bottom: -32rpx;
|
||||
right: 32rpx;
|
||||
box-shadow: 24rpx 16rpx 24rpx #5d206e, 0 80rpx 0 #9731c5,inset 0 -2rpx 2rpx #200526;
|
||||
-webkit-transform: rotate(300deg);
|
||||
-o-transform: rotate(300deg);
|
||||
-moz-transform: rotate(300deg);
|
||||
transform: rotate(300deg);
|
||||
}
|
||||
.a::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 176rpx;
|
||||
height: 176rpx;
|
||||
position: absolute;
|
||||
border-radius: 0 0 72rpx 104rpx/0 0 24rpx 40rpx;
|
||||
bottom: -72rpx;
|
||||
right: 16rpx;
|
||||
box-shadow: 64rpx 40rpx 40rpx #361d3b, 0 80rpx 0 #8829b7,inset 0 -2rpx 2rpx #200526;
|
||||
-webkit-transform: rotate(240deg);
|
||||
-o-transform: rotate(240deg);
|
||||
-moz-transform: rotate(240deg);
|
||||
transform: rotate(240deg);
|
||||
}
|
||||
.b{
|
||||
bottom: -36rpx;
|
||||
right: -6rpx;
|
||||
-webkit-transform: rotate(180deg);
|
||||
-o-transform: rotate(180deg);
|
||||
-moz-transform: rotate(180deg);
|
||||
transform: rotate(180deg);
|
||||
box-shadow: 80rpx 56rpx 48rpx #1e618b, 0 80rpx 0 #522162,inset 0 -2rpx 2rpx #200526;
|
||||
}
|
||||
|
||||
.b::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 176rpx;
|
||||
height: 176rpx;
|
||||
position: absolute;
|
||||
border-radius: 0 0 72rpx 104rpx/0 0 24rpx 40rpx;
|
||||
bottom: -32rpx;
|
||||
right: 32rpx;
|
||||
-webkit-transform: rotate(-60deg);
|
||||
-o-transform: rotate(-60deg);
|
||||
-moz-transform: rotate(-60deg);
|
||||
transform: rotate(-60deg);
|
||||
clip: rect(0em, 144rpx, 344.88rpx, 0em);
|
||||
box-shadow: 44rpx 80rpx 32rpx #256186, 0 80rpx 0 #2f3241,inset 0 -2rpx 2rpx #200526;
|
||||
}
|
||||
.b::after{
|
||||
content: "";
|
||||
display: block;
|
||||
width: 176rpx;
|
||||
height: 176rpx;
|
||||
position: absolute;
|
||||
border-radius: 0 0 72rpx 104rpx/0 0 24rpx 40rpx;
|
||||
bottom: -68rpx;
|
||||
right: 18rpx;
|
||||
-webkit-transform: rotate(-120deg);
|
||||
-o-transform: rotate(-120deg);
|
||||
-moz-transform: rotate(-120deg);
|
||||
transform: rotate(-120deg);
|
||||
clip: rect(0em, 144rpx, 344.88rpx, 0em);
|
||||
box-shadow: -5rpx 0em 5.8rpx #4a7693,-88rpx 16rpx 40rpx #1e618b, 0 80rpx 0 #411e46,inset 0 -2rpx 2rpx #200526;
|
||||
}
|
||||
|
||||
.c{
|
||||
bottom: 40rpx;
|
||||
right: 8rpx;
|
||||
clip: rect(0em, 80rpx, 344.88rpx, 0em);
|
||||
box-shadow: 0 2rpx 0 #4c2f4d, -24rpx 20rpx 32rpx #442149, 0 80rpx 0 #7a21a3,inset 0 -2rpx 2rpx #200526;
|
||||
}
|
||||
BIN
miniprogram/static/.DS_Store
vendored
BIN
miniprogram/static/.DS_Store
vendored
Binary file not shown.
502
miniprogram/test.html
Normal file
502
miniprogram/test.html
Normal file
@@ -0,0 +1,502 @@
|
||||
<html>
|
||||
<main id="app">
|
||||
|
||||
<div class="card">
|
||||
<span class="glow"></span>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</html>
|
||||
<style>
|
||||
:root {
|
||||
|
||||
/* vars */
|
||||
--glow-sens: 30;
|
||||
--card-bg: linear-gradient(8deg,var(--dark) 75%, color-mix(in hsl, var(--dark), white 2.5%) 75.5%);
|
||||
--blend: soft-light;
|
||||
--glow-blend: plus-lighter;
|
||||
--glow-color: 40deg 80% 80%;
|
||||
--glow-boost: 0%;
|
||||
|
||||
}
|
||||
|
||||
.light .card {
|
||||
--card-bg: linear-gradient(8deg,color-mix(in hsl, hsl(260, 25%, 95%), var(--dark) 2.5%) 75%, hsl(260, 25%, 95%) 75.5%);
|
||||
--blend: darken;
|
||||
--glow-blend: luminosity;
|
||||
--glow-color: 280deg 90% 95%;
|
||||
--glow-boost: 15%;
|
||||
--fg: black;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
body.light {
|
||||
|
||||
background-image:
|
||||
linear-gradient(
|
||||
180deg,
|
||||
hsl(var(--h), 8%, 58%),
|
||||
hsl(var(--h), 15%, 42%)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
.card {
|
||||
|
||||
--pads: 40px;
|
||||
--color-sens: calc(var(--glow-sens) + 20);
|
||||
--pointer-°: 45deg;
|
||||
|
||||
position: relative;
|
||||
width: clamp(320px, calc(100svw - calc(var(--pads) * 2)), 600px);
|
||||
height: calc(100svh - calc(var(--pads) * 2));
|
||||
max-height: 600px;
|
||||
border-radius: 1.768em;
|
||||
isolation: isolate;
|
||||
transform: translate3d(0, 0, 0.01px);
|
||||
display: grid;
|
||||
border: 1px solid rgb(255 255 255 / 25%);
|
||||
background: var(--card-bg);
|
||||
background-repeat: no-repeat;
|
||||
|
||||
&::before,
|
||||
&::after,
|
||||
& > .glow {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
transition: opacity 0.25s ease-out;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
&:not(:hover):not(.animating) {
|
||||
&::before,
|
||||
&::after,
|
||||
& > .glow {
|
||||
opacity: 0;
|
||||
transition: opacity 0.75s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
|
||||
/* mesh gradient border */
|
||||
|
||||
border: 1px solid transparent;
|
||||
|
||||
background:
|
||||
linear-gradient(var(--card-bg) 0 100%) padding-box,
|
||||
linear-gradient(rgb(255 255 255 / 0%) 0% 100%) border-box,
|
||||
radial-gradient(at 80% 55%, hsla(268,100%,76%,1) 0px, transparent 50%) border-box,
|
||||
radial-gradient(at 69% 34%, hsla(349,100%,74%,1) 0px, transparent 50%) border-box,
|
||||
radial-gradient(at 8% 6%, hsla(136,100%,78%,1) 0px, transparent 50%) border-box,
|
||||
radial-gradient(at 41% 38%, hsla(192,100%,64%,1) 0px, transparent 50%) border-box,
|
||||
radial-gradient(at 86% 85%, hsla(186,100%,74%,1) 0px, transparent 50%) border-box,
|
||||
radial-gradient(at 82% 18%, hsla(52,100%,65%,1) 0px, transparent 50%) border-box,
|
||||
radial-gradient(at 51% 4%, hsla(12,100%,72%,1) 0px, transparent 50%) border-box,
|
||||
linear-gradient(#c299ff 0 100%) border-box;
|
||||
|
||||
/* opacity increases as pointer gets near edge */
|
||||
opacity: calc((var(--pointer-d) - var(--color-sens)) / (100 - var(--color-sens)));
|
||||
|
||||
/* border is masked to a cone, originating from the center towards the pointer */
|
||||
mask-image:
|
||||
conic-gradient(
|
||||
from var(--pointer-°) at center, black 25%, transparent 40%, transparent 60%, black 75%
|
||||
);
|
||||
}
|
||||
|
||||
&::after {
|
||||
|
||||
/* mesh gradient background */
|
||||
|
||||
border: 1px solid transparent;
|
||||
|
||||
background:
|
||||
radial-gradient(at 80% 55%, hsla(268,100%,76%,1) 0px, transparent 50%) padding-box,
|
||||
radial-gradient(at 69% 34%, hsla(349,100%,74%,1) 0px, transparent 50%) padding-box,
|
||||
radial-gradient(at 8% 6%, hsla(136,100%,78%,1) 0px, transparent 50%) padding-box,
|
||||
radial-gradient(at 41% 38%, hsla(192,100%,64%,1) 0px, transparent 50%) padding-box,
|
||||
radial-gradient(at 86% 85%, hsla(186,100%,74%,1) 0px, transparent 50%) padding-box,
|
||||
radial-gradient(at 82% 18%, hsla(52,100%,65%,1) 0px, transparent 50%) padding-box,
|
||||
radial-gradient(at 51% 4%, hsla(12,100%,72%,1) 0px, transparent 50%) padding-box,
|
||||
linear-gradient(#c299ff 0 100%) padding-box;
|
||||
|
||||
/* 5 radial masks to create a squircle-cut-out, and then a cone-gradient
|
||||
originating from the center towards the pointer to highlight the edges */
|
||||
mask-image:
|
||||
linear-gradient( to bottom, black, black ),
|
||||
radial-gradient( ellipse at 50% 50%, black 40%, transparent 65% ),
|
||||
radial-gradient( ellipse at 66% 66%, black 5%, transparent 40% ),
|
||||
radial-gradient( ellipse at 33% 33%, black 5%, transparent 40% ),
|
||||
radial-gradient( ellipse at 66% 33%, black 5%, transparent 40% ),
|
||||
radial-gradient( ellipse at 33% 66%, black 5%, transparent 40% ),
|
||||
conic-gradient( from var(--pointer-°) at center, transparent 5%, black 15%, black 85%, transparent 95% );
|
||||
|
||||
mask-composite: subtract,add,add,add,add,add;
|
||||
|
||||
/* opacity increases as pointer gets near edge */
|
||||
opacity: calc((var(--pointer-d) - var(--color-sens)) / (100 - var(--color-sens)));
|
||||
mix-blend-mode: var(--blend);
|
||||
|
||||
}
|
||||
|
||||
& > .glow {
|
||||
|
||||
/* glowing border edges */
|
||||
|
||||
--outset: var(--pads);
|
||||
|
||||
/* outer padding so the glow can overflow the element without being masked */
|
||||
inset: calc(var(--outset) * -1);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
|
||||
/* glow is masked to a cone, originating from the center towards the pointer */
|
||||
mask-image:
|
||||
conic-gradient(
|
||||
from var(--pointer-°) at center, black 2.5%, transparent 10%, transparent 90%, black 97.5%
|
||||
);
|
||||
|
||||
/* opacity increases as pointer gets near edge */
|
||||
opacity: calc((var(--pointer-d) - var(--glow-sens)) / (100 - var(--glow-sens)));
|
||||
mix-blend-mode: var(--glow-blend);
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: var(--outset);
|
||||
border-radius: inherit;
|
||||
box-shadow:
|
||||
inset 0 0 0 1px hsl( var(--glow-color) / 100%),
|
||||
|
||||
inset 0 0 1px 0 hsl( var(--glow-color) / calc(var(--glow-boost) + 60%)),
|
||||
inset 0 0 3px 0 hsl( var(--glow-color) / calc(var(--glow-boost) + 50%)),
|
||||
inset 0 0 6px 0 hsl( var(--glow-color) / calc(var(--glow-boost) + 40%)),
|
||||
inset 0 0 15px 0 hsl( var(--glow-color) / calc(var(--glow-boost) + 30%)),
|
||||
inset 0 0 25px 2px hsl( var(--glow-color) / calc(var(--glow-boost) + 20%)),
|
||||
inset 0 0 50px 2px hsl( var(--glow-color) / calc(var(--glow-boost) + 10%)),
|
||||
|
||||
0 0 1px 0 hsl( var(--glow-color) / calc(var(--glow-boost) + 60%)),
|
||||
0 0 3px 0 hsl( var(--glow-color) / calc(var(--glow-boost) + 50%)),
|
||||
0 0 6px 0 hsl( var(--glow-color) / calc(var(--glow-boost) + 40%)),
|
||||
0 0 15px 0 hsl( var(--glow-color) / calc(var(--glow-boost) + 30%)),
|
||||
0 0 25px 2px hsl( var(--glow-color) / calc(var(--glow-boost) + 20%)),
|
||||
0 0 50px 2px hsl( var(--glow-color) / calc(var(--glow-boost) + 10%));
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
box-shadow:
|
||||
rgba(0, 0, 0, 0.1) 0px 1px 2px,
|
||||
rgba(0, 0, 0, 0.1) 0px 2px 4px,
|
||||
rgba(0, 0, 0, 0.1) 0px 4px 8px,
|
||||
rgba(0, 0, 0, 0.1) 0px 8px 16px,
|
||||
rgba(0, 0, 0, 0.1) 0px 16px 32px,
|
||||
rgba(0, 0, 0, 0.1) 0px 32px 64px;
|
||||
}
|
||||
|
||||
.inner {
|
||||
text-align: center;
|
||||
h2 {
|
||||
color: inherit;
|
||||
font-weight: 500;
|
||||
font-size: 1.25em;
|
||||
margin-block: 0.5em;
|
||||
}
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.5em 1em;
|
||||
|
||||
}
|
||||
svg {
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
}
|
||||
|
||||
.card .inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
container-type: inline-size;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.card .content {
|
||||
padding: 1em;
|
||||
font-weight: 300;
|
||||
text-align: left;
|
||||
line-height: 1.4;
|
||||
color: color-mix(var(--fg), transparent 60%);
|
||||
overflow: auto;
|
||||
scrollbar-width: none;
|
||||
mask-image: linear-gradient( to top, transparent 5px, black 2em);
|
||||
|
||||
& em,
|
||||
& strong {
|
||||
color: color-mix(var(--fg), transparent 40%);
|
||||
}
|
||||
|
||||
& p {
|
||||
opacity: 0;
|
||||
animation: fadeContent 1.5s ease-in-out 2s both;
|
||||
&:nth-child(2) {
|
||||
animation-delay: 2.25s;
|
||||
}
|
||||
&:nth-child(3) {
|
||||
animation-delay: 2.5s;
|
||||
}
|
||||
&:nth-child(4) {
|
||||
animation-delay: 2.75s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes fadeContent {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
body, html {
|
||||
height: 100svh;
|
||||
overflow: auto;
|
||||
background: hsl(var(--h), 18%, 12%);
|
||||
}
|
||||
|
||||
main {
|
||||
justify-items: center;
|
||||
align-content: center;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.sun {
|
||||
opacity: 0.25;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.moon {
|
||||
opacty: 1;
|
||||
}
|
||||
|
||||
.sun, .moon {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.light {
|
||||
--link: hsl(var(--canvas), 90%, 50%);
|
||||
--linkh: hsl(150, 85%, 40%);
|
||||
& .sun {
|
||||
opacity: 1;
|
||||
}
|
||||
& .moon {
|
||||
opacity: 0.25;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
h2 {
|
||||
text-shadow: 0 1px 1px lightslategray;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
const $card = document.querySelector(".card");
|
||||
|
||||
const cardUpdate = (e) => {
|
||||
|
||||
const position = pointerPositionRelativeToElement( $card, e );
|
||||
const [px,py] = position.pixels;
|
||||
const [perx, pery] = position.percent;
|
||||
const [dx,dy] = distanceFromCenter( $card, px, py );
|
||||
const edge = closenessToEdge( $card, px, py );
|
||||
const angle = angleFromPointerEvent( $card, dx, dy );
|
||||
|
||||
$card.style.setProperty('--pointer-x', `${round(perx)}%`);
|
||||
$card.style.setProperty('--pointer-y', `${round(pery)}%`);
|
||||
$card.style.setProperty('--pointer-°', `${round(angle)}deg`);
|
||||
$card.style.setProperty('--pointer-d', `${round(edge * 100)}`);
|
||||
|
||||
$card.classList.remove('animating');
|
||||
|
||||
};
|
||||
|
||||
$card.addEventListener("pointermove", cardUpdate);
|
||||
|
||||
|
||||
const centerOfElement = ($el) => {
|
||||
const { left, top, width, height } = $el.getBoundingClientRect();
|
||||
return [ width/2, height/2 ];
|
||||
}
|
||||
|
||||
const pointerPositionRelativeToElement = ($el, e) => {
|
||||
const pos = [e.clientX, e.clientY];
|
||||
const { left, top, width, height } = $el.getBoundingClientRect();
|
||||
const x = pos[0] - left;
|
||||
const y = pos[1] - top;
|
||||
const px = clamp((100 / width) * x);
|
||||
const py = clamp((100 / height) * y);
|
||||
return { pixels: [x,y], percent: [px,py] }
|
||||
}
|
||||
|
||||
const angleFromPointerEvent = ($el, dx, dy ) => {
|
||||
// in degrees
|
||||
let angleRadians = 0;
|
||||
let angleDegrees = 0;
|
||||
if ( dx !== 0 || dy !== 0 ) {
|
||||
angleRadians = Math.atan2(dy, dx);
|
||||
angleDegrees = angleRadians * (180 / Math.PI) + 90;
|
||||
if (angleDegrees < 0) {
|
||||
angleDegrees += 360;
|
||||
}
|
||||
}
|
||||
return angleDegrees;
|
||||
}
|
||||
|
||||
const distanceFromCenter = ( $card, x, y ) => {
|
||||
// in pixels
|
||||
const [cx,cy] = centerOfElement( $card );
|
||||
return [ x - cx, y - cy ];
|
||||
}
|
||||
|
||||
const closenessToEdge = ( $card, x, y ) => {
|
||||
// in fraction (0,1)
|
||||
const [cx,cy] = centerOfElement( $card );
|
||||
const [dx,dy] = distanceFromCenter( $card, x, y );
|
||||
let k_x = Infinity;
|
||||
let k_y = Infinity;
|
||||
if (dx !== 0) {
|
||||
k_x = cx / Math.abs(dx);
|
||||
}
|
||||
if (dy !== 0) {
|
||||
k_y = cy / Math.abs(dy);
|
||||
}
|
||||
return clamp((1 / Math.min(k_x, k_y)), 0, 1);
|
||||
}
|
||||
|
||||
const round = (value, precision = 3) => parseFloat(value.toFixed(precision));
|
||||
|
||||
const clamp = (value, min = 0, max = 100) =>
|
||||
Math.min(Math.max(value, min), max);
|
||||
|
||||
/** code for the intro animation, not related to teh interaction */
|
||||
|
||||
const playAnimation = () => {
|
||||
|
||||
const angleStart = 110;
|
||||
const angleEnd = 465;
|
||||
|
||||
$card.style.setProperty('--pointer-°', `${angleStart}deg`);
|
||||
$card.classList.add('animating');
|
||||
|
||||
animateNumber({
|
||||
ease: easeOutCubic,
|
||||
duration: 500,
|
||||
onUpdate: (v) => {
|
||||
$card.style.setProperty('--pointer-d', v);
|
||||
}
|
||||
});
|
||||
|
||||
animateNumber({
|
||||
ease: easeInCubic,
|
||||
delay: 0,
|
||||
duration: 1500,
|
||||
endValue: 50,
|
||||
onUpdate: (v) => {
|
||||
const d = (angleEnd - angleStart) * (v / 100) + angleStart;
|
||||
$card.style.setProperty('--pointer-°', `${d}deg`);
|
||||
}
|
||||
});
|
||||
|
||||
animateNumber({
|
||||
ease: easeOutCubic,
|
||||
delay: 1500,
|
||||
duration: 2250,
|
||||
startValue: 50,
|
||||
endValue: 100,
|
||||
onUpdate: (v) => {
|
||||
const d = (angleEnd - angleStart) * (v / 100) + angleStart;
|
||||
$card.style.setProperty('--pointer-°', `${d}deg`);
|
||||
}
|
||||
});
|
||||
|
||||
animateNumber({
|
||||
ease: easeInCubic,
|
||||
duration: 1500,
|
||||
delay: 2500,
|
||||
startValue: 100,
|
||||
endValue: 0,
|
||||
onUpdate: (v) => {
|
||||
$card.style.setProperty('--pointer-d', v);
|
||||
},
|
||||
onEnd: () => {
|
||||
$card.classList.remove('animating');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
playAnimation();
|
||||
|
||||
|
||||
function easeOutCubic(x) {
|
||||
return 1 - Math.pow(1 - x, 3);
|
||||
}
|
||||
function easeInCubic(x) {
|
||||
return x * x * x;
|
||||
}
|
||||
|
||||
function animateNumber(options) {
|
||||
const {
|
||||
startValue = 0,
|
||||
endValue = 100,
|
||||
duration = 1000,
|
||||
delay = 0,
|
||||
onUpdate = () => {},
|
||||
ease = (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2,
|
||||
onStart = () => {},
|
||||
onEnd = () => {},
|
||||
} = options;
|
||||
|
||||
const startTime = performance.now() + delay;
|
||||
|
||||
function update() {
|
||||
const currentTime = performance.now();
|
||||
const elapsed = currentTime - startTime;
|
||||
const t = Math.min(elapsed / duration, 1); // Normalize to [0, 1]
|
||||
const easedValue = startValue + (endValue - startValue) * ease(t); // Apply easing
|
||||
|
||||
onUpdate(easedValue);
|
||||
|
||||
if (t < 1) {
|
||||
requestAnimationFrame(update); // Continue the animation
|
||||
} else if (t >= 1) {
|
||||
onEnd();
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
onStart();
|
||||
requestAnimationFrame(update); // Start the animation after the delay
|
||||
}, delay);
|
||||
}
|
||||
</script>
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
// API 基础域名
|
||||
export const BASE_URL = 'https://app.xhzone.cn'
|
||||
// export const BASE_URL = 'https://prod-201510-4-1385696640.sh.run.tcloudbase.com'
|
||||
|
||||
// 文件服务基础路径
|
||||
export const FILE_BASE_URL = `${BASE_URL}/api/v1/file`
|
||||
@@ -51,5 +51,7 @@
|
||||
"ignore": [],
|
||||
"include": []
|
||||
},
|
||||
"appid": "wxe739c0e6fb02eda8"
|
||||
"ignoreDevUnusedFiles": false,
|
||||
"ignoreUploadUnusedFiles": false,
|
||||
"appid": "wxd6917f77eb2723fb"
|
||||
}
|
||||
@@ -42,6 +42,13 @@
|
||||
"query": "imageId=2089419112290844672",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"pathName": "pages/analyze/analyze",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user