@opentiny/next-sdk 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{SimulatorMask-BHVXyogh-CARX3Rff.js → SimulatorMask-BHVXyogh-CKmEDsYG.js} +1 -1
- package/dist/{index-R_HIbfUX.js → index-CHMa2zG4.js} +1065 -1042
- package/dist/index.js +1 -1
- package/dist/page-tools/a11y/config.d.ts +6 -3
- package/dist/page-tools/a11y/constants.d.ts +20 -0
- package/dist/page-tools/a11y/utils.d.ts +14 -0
- package/dist/page-tools/constants.d.ts +4 -2
- package/dist/page-tools/context.d.ts +2 -0
- package/dist/page-tools/handlers/hover.d.ts +9 -0
- package/dist/page-tools/schema.d.ts +3 -3
- package/dist/page-tools/utils/dom.d.ts +8 -2
- package/dist/runtime.js +19 -172
- package/package.json +6 -1
- package/WebMcpClient.ts +0 -505
- package/WebMcpServer.ts +0 -447
- package/agent/AgentModelProvider.ts +0 -932
- package/agent/type.ts +0 -91
- package/agent/utils/generateReActPrompt.ts +0 -71
- package/agent/utils/getAISDKTools.ts +0 -34
- package/agent/utils/getBuiltinMcpTools.ts +0 -86
- package/agent/utils/parseReActAction.ts +0 -34
- package/core.ts +0 -26
- package/index.ts +0 -91
- package/page-tools/a11y/build.ts +0 -74
- package/page-tools/a11y/config.ts +0 -465
- package/page-tools/a11y/constants.ts +0 -131
- package/page-tools/a11y/search.ts +0 -127
- package/page-tools/a11y/types.ts +0 -105
- package/page-tools/a11y/utils.ts +0 -239
- package/page-tools/a11y/vnode.ts +0 -439
- package/page-tools/a11y-tree.ts +0 -14
- package/page-tools/bridge.ts +0 -722
- package/page-tools/configs/console-cloud.ts +0 -172
- package/page-tools/constants.ts +0 -12
- package/page-tools/context.ts +0 -50
- package/page-tools/effects.ts +0 -345
- package/page-tools/handlers/browserState.ts +0 -12
- package/page-tools/handlers/click.ts +0 -30
- package/page-tools/handlers/executeJavascript.ts +0 -22
- package/page-tools/handlers/fill.ts +0 -65
- package/page-tools/handlers/scroll.ts +0 -66
- package/page-tools/handlers/searchTree.ts +0 -27
- package/page-tools/handlers/select.ts +0 -39
- package/page-tools/initialize-builtin-WebMCP.ts +0 -20
- package/page-tools/page-agent-highlight/index.ts +0 -245
- package/page-tools/page-agent-mask/SimulatorMask.module.css +0 -14
- package/page-tools/page-agent-mask/SimulatorMask.ts +0 -299
- package/page-tools/page-agent-mask/checkDarkMode.ts +0 -181
- package/page-tools/page-agent-mask/cursor-border.svg +0 -3
- package/page-tools/page-agent-mask/cursor-fill.svg +0 -5
- package/page-tools/page-agent-mask/cursor.module.css +0 -70
- package/page-tools/page-agent-mask/hauwei.svg +0 -25
- package/page-tools/page-agent-prompt.md +0 -139
- package/page-tools/page-agent-tool-event.ts +0 -113
- package/page-tools/page-agent-tool.ts +0 -207
- package/page-tools/page-state-cache.ts +0 -78
- package/page-tools/schema.ts +0 -52
- package/page-tools/tool-config.ts +0 -100
- package/page-tools/utils/dom.ts +0 -158
- package/page-tools/utils/scroll.ts +0 -58
- package/remoter/QrCode.ts +0 -54
- package/remoter/createRemoter.ts +0 -957
- package/remoter/svgs/chat.svg +0 -43
- package/remoter/svgs/icon-copy.svg +0 -25
- package/remoter/svgs/link.svg +0 -28
- package/remoter/svgs/logo.svg +0 -45
- package/remoter/svgs/qrcode.svg +0 -35
- package/remoter/svgs/scan.svg +0 -21
- package/remoter/tooltips.ts +0 -260
- package/runtime.html +0 -39
- package/runtime.ts +0 -44
- package/script/utils.ts +0 -26
- package/skills/index.ts +0 -287
- package/test/page-tools/a11y/build.test.ts +0 -638
- package/test/page-tools/a11y/config.test.ts +0 -370
- package/test/page-tools/configs/console-cloud.test.ts +0 -168
- package/test/page-tools/page-agent-highlight.test.ts +0 -110
- package/test/page-tools/page-agent-tool-dispatch.test.ts +0 -208
- package/test/page-tools/page-agent-tool.test.ts +0 -102
- package/test/page-tools/tool-config.test.ts +0 -112
- package/test/page-tools/utils/dom.test.ts +0 -122
- package/tsconfig.json +0 -16
- package/utils/builtinProxy.ts +0 -144
- package/utils/env.ts +0 -13
- package/utils/uuid.ts +0 -10
- package/vite.config.runtime.ts +0 -22
- package/vite.config.ts +0 -63
- package/vitest.config.ts +0 -10
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
import { Motion } from 'ai-motion'
|
|
2
|
-
|
|
3
|
-
import { isPageDark } from './checkDarkMode'
|
|
4
|
-
|
|
5
|
-
const injectStyles = `
|
|
6
|
-
.webmcp-page-agent-cursor {
|
|
7
|
-
position: absolute;
|
|
8
|
-
width: var(--cursor-size, 75px);
|
|
9
|
-
height: var(--cursor-size, 75px);
|
|
10
|
-
pointer-events: none;
|
|
11
|
-
z-index: 10000;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.webmcp-page-agent-cursorFilling {
|
|
15
|
-
position: absolute;
|
|
16
|
-
width: 100%;
|
|
17
|
-
height: 100%;
|
|
18
|
-
background: url("data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%2079.0834%2079.4553%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20%20width%3D%2779.083374%27%20height%3D%2779.455322%27%20fill%3D%27none%27%20%3E--%3Cdefs%3E%3Cfilter%20id%3D%27filter_0%27%20width%3D%2779.083374%27%20height%3D%2779.455322%27%20x%3D%270.000000%27%20y%3D%270.000000%27%20filterUnits%3D%27userSpaceOnUse%27%20%20color-interpolation-filters%3D%27sRGB%27%3E%3CfeFlood%20flood-opacity%3D%270%27%20result%3D%27BackgroundImageFix%27%20%2F%3E%3CfeOffset%20dx%3D%276.000000%27%20dy%3D%276.000000%27%20in%3D%27SourceAlpha%27%20%2F%3E%3CfeGaussianBlur%20stdDeviation%3D%276.66666651%27%20%2F%3E%3CfeColorMatrix%20type%3D%27matrix%27%20values%3D%270%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200.18%200%20%27%20%2F%3E%3CfeBlend%20result%3D%27effect_dropShadow_1%27%20in2%3D%27BackgroundImageFix%27%20mode%3D%27normal%27%20%2F%3E%3CfeBlend%20result%3D%27shape%27%20in%3D%27SourceGraphic%27%20in2%3D%27effect_dropShadow_1%27%20mode%3D%27normal%27%20%2F%3E%3C%2Ffilter%3E%3ClinearGradient%20id%3D%27paint_linear_0%27%20x1%3D%2718.4743214%27%20x2%3D%2718.4213886%27%20y1%3D%27-1.86264515e-09%27%20y2%3D%2734.9221306%27%20gradientUnits%3D%27userSpaceOnUse%27%3E%3Cstop%20stop-color%3D%27rgb%28255%2C181%2C96%29%27%20offset%3D%270%27%20stop-opacity%3D%271%27%20%2F%3E%3Cstop%20stop-color%3D%27rgb%28255%2C120%2C114%29%27%20offset%3D%270.5%27%20stop-opacity%3D%271%27%20%2F%3E%3Cstop%20stop-color%3D%27rgb%28241%2C109%2C237%29%27%20offset%3D%271%27%20stop-opacity%3D%271%27%20%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Cg%20filter%3D%27url%28%23filter_0%29%27%3E%3Cpath%20d%3D%27M20.2632%203.57771L34.6257%2032.3027C35.4444%2033.9402%2033.8152%2035.7258%2032.1097%2035.0603L19.2014%2030.0229C18.7339%2029.8404%2018.2148%2029.8404%2017.7472%2030.0229L4.83891%2035.0603C3.13343%2035.7258%201.50423%2033.9402%202.32297%2032.3027L16.6855%203.57771C17.4225%202.10361%2019.5261%202.10361%2020.2632%203.57771Z%27%20fill%3D%27url%28%23paint_linear_0%29%27%20fill-rule%3D%27evenodd%27%20transform%3D%27matrix%280.719908%2C-0.69407%2C0.69407%2C0.719908%2C2.00256%2C28.0095%29%27%20%2F%3E%3Cpath%20d%3D%27M37.2169%2032.6848C37.1578%2032.189%2037.0096%2031.7039%2036.7723%2031.2294L22.4098%202.5044C22.1973%202.07946%2021.9328%201.70554%2021.6163%201.38261C21.3524%201.11342%2021.0524%200.879671%2020.7162%200.681366C20.3925%200.490407%2020.0558%200.34434%2019.7061%200.243163C19.312%200.129145%2018.9014%200.0721366%2018.4743%200.0721366C18.0472%200.0721366%2017.6367%200.129145%2017.2426%200.243163C16.8929%200.34434%2016.5562%200.490407%2016.2324%200.681366C15.8962%200.879671%2015.5962%201.11342%2015.3323%201.38261C15.0158%201.70553%2014.7513%202.07946%2014.5388%202.5044L0.176342%2031.2294C-0.0609121%2031.7039%20-0.209128%2032.189%20-0.268305%2032.6848C-0.316251%2033.0865%20-0.305747%2033.4951%20-0.236792%2033.9108C-0.171059%2034.307%20-0.0570567%2034.6809%200.105216%2035.0326C0.292784%2035.4391%200.544845%2035.8158%200.861397%2036.1627C1.17794%2036.5097%201.53001%2036.7951%201.91761%2037.0191C2.25297%2037.2128%202.61492%2037.3606%203.00348%2037.4623C3.41106%2037.5689%203.81704%2037.6168%204.22142%2037.6058C4.72053%2037.5922%205.21719%2037.4889%205.71141%2037.2961L18.4743%2032.3154L31.2372%2037.2961C31.7315%2037.4889%2032.2281%2037.5922%2032.7272%2037.6058C33.1316%2037.6168%2033.5376%2037.5689%2033.9452%2037.4623C34.3337%2037.3606%2034.6957%2037.2128%2035.0311%2037.0191C35.4187%2036.7951%2035.7707%2036.5097%2036.0873%2036.1627C36.4038%2035.8158%2036.6558%2035.4391%2036.8434%2035.0327C37.0057%2034.681%2037.1197%2034.307%2037.1854%2033.9108C37.2544%2033.4951%2037.2649%2033.0865%2037.2169%2032.6848ZM34.6257%2032.3027L20.2632%203.57771C19.5261%202.10361%2017.4225%202.10361%2016.6855%203.57771L2.32297%2032.3027C1.50423%2033.9402%203.13343%2035.7258%204.83891%2035.0603L17.7472%2030.0229C18.2148%2029.8404%2018.7339%2029.8404%2019.2014%2030.0229L32.1097%2035.0603C33.8152%2035.7258%2035.4444%2033.9402%2034.6257%2032.3027Z%27%20fill%3D%27rgb%28255%2C255%2C255%29%27%20fill-rule%3D%27evenodd%27%20transform%3D%27matrix%280.719908%2C-0.69407%2C0.69407%2C0.719908%2C2.00256%2C28.0095%29%27%20%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
19
|
-
background-size: 100% 100%;
|
|
20
|
-
background-repeat: no-repeat;
|
|
21
|
-
|
|
22
|
-
transform-origin: center;
|
|
23
|
-
margin-left: -10px;
|
|
24
|
-
margin-top: -18px;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.webmcp-page-agent-cursorRipple {
|
|
28
|
-
position: absolute;
|
|
29
|
-
width: 100%;
|
|
30
|
-
height: 100%;
|
|
31
|
-
pointer-events: none;
|
|
32
|
-
margin-left: -50%;
|
|
33
|
-
margin-top: -50%;
|
|
34
|
-
|
|
35
|
-
&::after {
|
|
36
|
-
content: '';
|
|
37
|
-
opacity: 0;
|
|
38
|
-
position: absolute;
|
|
39
|
-
inset: 0;
|
|
40
|
-
border: 4px solid rgba(57, 182, 255, 1);
|
|
41
|
-
border-radius: 50%;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.webmcp-page-agent-cursor.clicking .webmcp-page-agent-cursorRipple::after {
|
|
46
|
-
animation: webmcp-page-agent-cursor-ripple 300ms ease-out forwards;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@keyframes webmcp-page-agent-cursor-ripple {
|
|
50
|
-
0% {
|
|
51
|
-
transform: scale(0);
|
|
52
|
-
opacity: 1;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
100% {
|
|
56
|
-
transform: scale(2);
|
|
57
|
-
opacity: 0;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.webmcp-page-agent-wrapper {
|
|
62
|
-
position: fixed;
|
|
63
|
-
inset: 0;
|
|
64
|
-
z-index: 2147483641;
|
|
65
|
-
/* 确保在所有元素之上,除了 panel */
|
|
66
|
-
cursor: wait;
|
|
67
|
-
overflow: hidden;
|
|
68
|
-
|
|
69
|
-
display: none;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.webmcp-page-agent-wrapper.visible {
|
|
73
|
-
display: block;
|
|
74
|
-
}
|
|
75
|
-
`
|
|
76
|
-
|
|
77
|
-
export class SimulatorMask extends EventTarget {
|
|
78
|
-
shown: boolean = false
|
|
79
|
-
wrapper = document.createElement('div')
|
|
80
|
-
motion: Motion | null = null
|
|
81
|
-
|
|
82
|
-
#disposed = false
|
|
83
|
-
|
|
84
|
-
#cursor = document.createElement('div')
|
|
85
|
-
|
|
86
|
-
#currentCursorX = 0
|
|
87
|
-
#currentCursorY = 0
|
|
88
|
-
|
|
89
|
-
#targetCursorX = 0
|
|
90
|
-
#targetCursorY = 0
|
|
91
|
-
|
|
92
|
-
constructor() {
|
|
93
|
-
super()
|
|
94
|
-
// 注入样式,防止打包失败
|
|
95
|
-
document.head.appendChild(document.createElement('style')).textContent = injectStyles
|
|
96
|
-
this.wrapper.id = 'page-agent-runtime_simulator-mask'
|
|
97
|
-
this.wrapper.className = 'webmcp-page-agent-wrapper'
|
|
98
|
-
this.wrapper.setAttribute('data-browser-use-ignore', 'true')
|
|
99
|
-
this.wrapper.setAttribute('data-page-agent-ignore', 'true')
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
const motion = new Motion({
|
|
103
|
-
mode: isPageDark() ? 'dark' : 'light',
|
|
104
|
-
styles: { position: 'absolute', inset: '0' },
|
|
105
|
-
glowWidth: 80,
|
|
106
|
-
borderWidth: 8,
|
|
107
|
-
colors: ['rgb(121, 216, 247)', 'rgb(171, 219, 110)', 'rgb(252, 188, 114)', 'rgb(235, 117, 231)']
|
|
108
|
-
})
|
|
109
|
-
this.motion = motion
|
|
110
|
-
this.wrapper.appendChild(motion.element)
|
|
111
|
-
motion.autoResize(this.wrapper)
|
|
112
|
-
} catch (e) {
|
|
113
|
-
console.warn('[SimulatorMask] Motion overlay unavailable:', e)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const stopEvent = (e: Event) => {
|
|
117
|
-
e.stopPropagation()
|
|
118
|
-
e.preventDefault()
|
|
119
|
-
}
|
|
120
|
-
;['click', 'mousedown', 'mouseup', 'mousemove', 'wheel', 'keydown', 'keyup'].forEach((eventName) =>
|
|
121
|
-
this.wrapper.addEventListener(eventName, stopEvent)
|
|
122
|
-
)
|
|
123
|
-
// Create AI cursor
|
|
124
|
-
this.#createCursor()
|
|
125
|
-
// this.show()
|
|
126
|
-
|
|
127
|
-
document.body.appendChild(this.wrapper)
|
|
128
|
-
|
|
129
|
-
this.#moveCursorToTarget()
|
|
130
|
-
|
|
131
|
-
// global events
|
|
132
|
-
// @note Mask should be isolated from the rest of the code.
|
|
133
|
-
// Global events are easier to manage and cleanup.
|
|
134
|
-
|
|
135
|
-
const movePointerToListener = (event: Event) => {
|
|
136
|
-
const { x, y } = (event as CustomEvent).detail
|
|
137
|
-
this.setCursorPosition(x, y)
|
|
138
|
-
}
|
|
139
|
-
const clickPointerListener = () => {
|
|
140
|
-
this.triggerClickAnimation()
|
|
141
|
-
}
|
|
142
|
-
const enablePassThroughListener = () => {
|
|
143
|
-
this.wrapper.style.pointerEvents = 'none'
|
|
144
|
-
}
|
|
145
|
-
const disablePassThroughListener = () => {
|
|
146
|
-
this.wrapper.style.pointerEvents = 'auto'
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
window.addEventListener('PageAgent::MovePointerTo', movePointerToListener)
|
|
150
|
-
window.addEventListener('PageAgent::ClickPointer', clickPointerListener)
|
|
151
|
-
window.addEventListener('PageAgent::EnablePassThrough', enablePassThroughListener)
|
|
152
|
-
window.addEventListener('PageAgent::DisablePassThrough', disablePassThroughListener)
|
|
153
|
-
|
|
154
|
-
this.addEventListener('dispose', () => {
|
|
155
|
-
window.removeEventListener('PageAgent::MovePointerTo', movePointerToListener)
|
|
156
|
-
window.removeEventListener('PageAgent::ClickPointer', clickPointerListener)
|
|
157
|
-
window.removeEventListener('PageAgent::EnablePassThrough', enablePassThroughListener)
|
|
158
|
-
window.removeEventListener('PageAgent::DisablePassThrough', disablePassThroughListener)
|
|
159
|
-
})
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
#createCursor() {
|
|
163
|
-
this.#cursor.className = 'webmcp-page-agent-cursor'
|
|
164
|
-
|
|
165
|
-
// Create ripple effect container
|
|
166
|
-
const rippleContainer = document.createElement('div')
|
|
167
|
-
rippleContainer.className = 'webmcp-page-agent-cursorRipple'
|
|
168
|
-
this.#cursor.appendChild(rippleContainer)
|
|
169
|
-
|
|
170
|
-
// Create filling layer
|
|
171
|
-
const fillingLayer = document.createElement('div')
|
|
172
|
-
fillingLayer.className = 'webmcp-page-agent-cursorFilling'
|
|
173
|
-
this.#cursor.appendChild(fillingLayer)
|
|
174
|
-
|
|
175
|
-
// Create border layer
|
|
176
|
-
// const borderLayer = document.createElement('div')
|
|
177
|
-
// borderLayer.className = 'webmcp-page-agent-cursorBorder'
|
|
178
|
-
// this.#cursor.appendChild(borderLayer)
|
|
179
|
-
|
|
180
|
-
this.wrapper.appendChild(this.#cursor)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
#moveCursorToTarget() {
|
|
184
|
-
if (this.#disposed) return
|
|
185
|
-
|
|
186
|
-
const newX = this.#currentCursorX + (this.#targetCursorX - this.#currentCursorX) * 0.2
|
|
187
|
-
const newY = this.#currentCursorY + (this.#targetCursorY - this.#currentCursorY) * 0.2
|
|
188
|
-
|
|
189
|
-
const xDistance = Math.abs(newX - this.#targetCursorX)
|
|
190
|
-
if (xDistance > 0) {
|
|
191
|
-
if (xDistance < 2) {
|
|
192
|
-
this.#currentCursorX = this.#targetCursorX
|
|
193
|
-
} else {
|
|
194
|
-
this.#currentCursorX = newX
|
|
195
|
-
}
|
|
196
|
-
this.#cursor.style.left = `${this.#currentCursorX}px`
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const yDistance = Math.abs(newY - this.#targetCursorY)
|
|
200
|
-
if (yDistance > 0) {
|
|
201
|
-
if (yDistance < 2) {
|
|
202
|
-
this.#currentCursorY = this.#targetCursorY
|
|
203
|
-
} else {
|
|
204
|
-
this.#currentCursorY = newY
|
|
205
|
-
}
|
|
206
|
-
this.#cursor.style.top = `${this.#currentCursorY}px`
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
requestAnimationFrame(() => this.#moveCursorToTarget())
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
setCursorPosition(x: number, y: number) {
|
|
213
|
-
if (this.#disposed) return
|
|
214
|
-
|
|
215
|
-
this.#targetCursorX = x
|
|
216
|
-
this.#targetCursorY = y
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
triggerClickAnimation() {
|
|
220
|
-
if (this.#disposed) return
|
|
221
|
-
|
|
222
|
-
this.#cursor.classList.remove('clicking')
|
|
223
|
-
// Force reflow to restart animation
|
|
224
|
-
void this.#cursor.offsetHeight
|
|
225
|
-
this.#cursor.classList.add('clicking')
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
show() {
|
|
229
|
-
if (this.shown || this.#disposed) return
|
|
230
|
-
|
|
231
|
-
this.shown = true
|
|
232
|
-
this.motion?.start()
|
|
233
|
-
this.motion?.fadeIn()
|
|
234
|
-
|
|
235
|
-
this.wrapper.classList.add('visible')
|
|
236
|
-
|
|
237
|
-
// Initialize cursor position
|
|
238
|
-
this.#currentCursorX = window.innerWidth / 2
|
|
239
|
-
this.#currentCursorY = window.innerHeight / 2
|
|
240
|
-
this.#targetCursorX = this.#currentCursorX
|
|
241
|
-
this.#targetCursorY = this.#currentCursorY
|
|
242
|
-
this.#cursor.style.left = `${this.#currentCursorX}px`
|
|
243
|
-
this.#cursor.style.top = `${this.#currentCursorY}px`
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
hide() {
|
|
247
|
-
if (!this.shown || this.#disposed) return
|
|
248
|
-
|
|
249
|
-
this.shown = false
|
|
250
|
-
this.motion?.fadeOut()
|
|
251
|
-
this.motion?.pause()
|
|
252
|
-
|
|
253
|
-
this.#cursor.classList.remove('clicking')
|
|
254
|
-
|
|
255
|
-
setTimeout(() => {
|
|
256
|
-
this.wrapper.classList.remove('visible')
|
|
257
|
-
}, 800) // Match the animation duration
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
dispose() {
|
|
261
|
-
this.#disposed = true
|
|
262
|
-
this.motion?.dispose()
|
|
263
|
-
this.wrapper.remove()
|
|
264
|
-
this.dispatchEvent(new Event('dispose'))
|
|
265
|
-
}
|
|
266
|
-
// 根据目标元素大小,在 wrapper 添加绝对定位边框:2px 宽、与目标间距 2px,对角渐变 (0,0 → 1,1)
|
|
267
|
-
borderElement(targetElement: HTMLElement) {
|
|
268
|
-
if (!targetElement) return
|
|
269
|
-
|
|
270
|
-
this.wrapper.querySelector('.webmcp-page-agent-border')?.remove()
|
|
271
|
-
|
|
272
|
-
const rect = targetElement.getBoundingClientRect()
|
|
273
|
-
const gap = 2
|
|
274
|
-
const borderWidth = 2
|
|
275
|
-
const offset = gap + borderWidth
|
|
276
|
-
|
|
277
|
-
const el = document.createElement('div')
|
|
278
|
-
el.className = 'webmcp-page-agent-border'
|
|
279
|
-
el.style.position = 'absolute'
|
|
280
|
-
el.style.left = `${rect.left - offset}px`
|
|
281
|
-
el.style.top = `${rect.top - offset}px`
|
|
282
|
-
el.style.width = `${rect.width + offset * 2}px`
|
|
283
|
-
el.style.height = `${rect.height + offset * 2}px`
|
|
284
|
-
el.style.boxSizing = 'border-box'
|
|
285
|
-
el.style.pointerEvents = 'none'
|
|
286
|
-
el.style.zIndex = '10000'
|
|
287
|
-
el.style.border = `${borderWidth}px solid transparent`
|
|
288
|
-
// 对角渐变:左上 (0,0) → 右下 (1,1)
|
|
289
|
-
el.style.borderImageSource = 'linear-gradient(to bottom right, #79D8F7, #ABDB6E, #FCBC72, #FA8682, #EB75E7)'
|
|
290
|
-
el.style.borderImageSlice = '1'
|
|
291
|
-
el.style.borderImageWidth = `${borderWidth}px`
|
|
292
|
-
|
|
293
|
-
this.wrapper.appendChild(el)
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
removeBorderElement() {
|
|
297
|
-
this.wrapper.querySelector('.webmcp-page-agent-border')?.remove()
|
|
298
|
-
}
|
|
299
|
-
}
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A comprehensive function to determine if the page is currently in a dark theme.
|
|
3
|
-
* Heuristic check. Only work for common patterns. Return false by default.
|
|
4
|
-
*/
|
|
5
|
-
export function isPageDark() {
|
|
6
|
-
try {
|
|
7
|
-
if (hasDarkModeClass()) return true
|
|
8
|
-
if (hasDarkModeDataAttribute()) return true
|
|
9
|
-
if (isColorSchemeDark()) return true
|
|
10
|
-
if (isBackgroundDark()) return true
|
|
11
|
-
if (isMainContentBackgroundDark()) return true
|
|
12
|
-
if (isTextColorLight()) return true
|
|
13
|
-
|
|
14
|
-
return false
|
|
15
|
-
} catch (error) {
|
|
16
|
-
console.warn('Error determining if page is dark:', error)
|
|
17
|
-
return false
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Checks for common dark mode CSS classes on the html or body elements.
|
|
23
|
-
*/
|
|
24
|
-
function hasDarkModeClass() {
|
|
25
|
-
const DEFAULT_DARK_MODE_CLASSES = ['dark', 'dark-mode', 'theme-dark', 'night', 'night-mode']
|
|
26
|
-
|
|
27
|
-
const htmlElement = document.documentElement
|
|
28
|
-
const bodyElement = document.body || document.documentElement // can be null in some cases
|
|
29
|
-
|
|
30
|
-
// Check class names on <html> and <body>
|
|
31
|
-
for (const className of DEFAULT_DARK_MODE_CLASSES) {
|
|
32
|
-
if (htmlElement.classList.contains(className) || bodyElement?.classList.contains(className)) {
|
|
33
|
-
return true
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return false
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Some UI frameworks use data attributes to indicate theme
|
|
42
|
-
*/
|
|
43
|
-
function hasDarkModeDataAttribute() {
|
|
44
|
-
const htmlElement = document.documentElement
|
|
45
|
-
const bodyElement = document.body || document.documentElement // can be null in some cases
|
|
46
|
-
|
|
47
|
-
const dataAttrs = ['data-theme', 'data-color-mode', 'data-bs-theme', 'data-mui-color-scheme']
|
|
48
|
-
for (const attr of dataAttrs) {
|
|
49
|
-
const bodyValue = bodyElement?.getAttribute(attr)
|
|
50
|
-
const htmlValue = htmlElement.getAttribute(attr)
|
|
51
|
-
|
|
52
|
-
if (bodyValue?.toLowerCase() === 'dark' || htmlValue?.toLowerCase() === 'dark') {
|
|
53
|
-
return true
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return false
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Checks the CSS `color-scheme` property and `<meta name="color-scheme">` tag.
|
|
62
|
-
* Only "dark"/"only dark" counts as dark; "light dark" is ambiguous and ignored.
|
|
63
|
-
*/
|
|
64
|
-
function isColorSchemeDark() {
|
|
65
|
-
// Check <meta name="color-scheme" content="dark">
|
|
66
|
-
const meta = document.querySelector<HTMLMetaElement>('meta[name="color-scheme"]')
|
|
67
|
-
const metaContent = meta?.content.toLowerCase()
|
|
68
|
-
if (metaContent === 'dark' || metaContent === 'only dark') return true
|
|
69
|
-
|
|
70
|
-
// Check the computed color-scheme CSS property on :root
|
|
71
|
-
const rootStyle = window.getComputedStyle(document.documentElement)
|
|
72
|
-
const colorScheme = rootStyle.getPropertyValue('color-scheme').trim().toLowerCase()
|
|
73
|
-
return colorScheme === 'dark' || colorScheme === 'only dark'
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Checks the background color of the body element to determine if the page is dark.
|
|
78
|
-
*/
|
|
79
|
-
function isBackgroundDark() {
|
|
80
|
-
// We check both <html> and <body> because some pages set the color on <html>
|
|
81
|
-
const htmlStyle = window.getComputedStyle(document.documentElement)
|
|
82
|
-
const bodyStyle = window.getComputedStyle(document.body || document.documentElement)
|
|
83
|
-
|
|
84
|
-
// Get background colors
|
|
85
|
-
const htmlBgColor = htmlStyle.backgroundColor
|
|
86
|
-
const bodyBgColor = bodyStyle.backgroundColor
|
|
87
|
-
|
|
88
|
-
// The body's background might be transparent, in which case we should
|
|
89
|
-
// fall back to the html element's background.
|
|
90
|
-
if (isColorDark(bodyBgColor)) {
|
|
91
|
-
return true
|
|
92
|
-
} else if (bodyBgColor === 'transparent' || bodyBgColor.startsWith('rgba(0, 0, 0, 0)')) {
|
|
93
|
-
return isColorDark(htmlBgColor)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return false
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Checks if the text color on the body is light, which implies a dark background.
|
|
101
|
-
*/
|
|
102
|
-
function isTextColorLight() {
|
|
103
|
-
/** Luminance (0-255) above which body text is considered light */
|
|
104
|
-
const LIGHT_TEXT_LUMINANCE = 200
|
|
105
|
-
|
|
106
|
-
const bodyStyle = window.getComputedStyle(document.body || document.documentElement)
|
|
107
|
-
const luminance = getLuminance(bodyStyle.color)
|
|
108
|
-
|
|
109
|
-
// Light text has high luminance (e.g. white text on dark bg)
|
|
110
|
-
return luminance !== null && luminance > LIGHT_TEXT_LUMINANCE
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Checks the background color of major layout elements (#app, #root, etc.).
|
|
115
|
-
* Many SPAs render into a container that may have its own dark background while
|
|
116
|
-
* <body> remains transparent.
|
|
117
|
-
*/
|
|
118
|
-
function isMainContentBackgroundDark() {
|
|
119
|
-
const { innerWidth: vw, innerHeight: vh } = window
|
|
120
|
-
const minArea = vw * vh * 0.5
|
|
121
|
-
|
|
122
|
-
const selectors = ['#app', '#root', '#__next']
|
|
123
|
-
for (const selector of selectors) {
|
|
124
|
-
const el = document.querySelector(selector)
|
|
125
|
-
if (!el) continue
|
|
126
|
-
|
|
127
|
-
const rect = el.getBoundingClientRect()
|
|
128
|
-
if (rect.width * rect.height < minArea) continue
|
|
129
|
-
|
|
130
|
-
if (isColorDark(window.getComputedStyle(el).backgroundColor)) return true
|
|
131
|
-
}
|
|
132
|
-
return false
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// --- utils ---
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Parses an RGB or RGBA color string and returns an object with r, g, b properties.
|
|
139
|
-
* @param {string} colorString - e.g., "rgb(34, 34, 34)" or "rgba(0, 0, 0, 0.5)"
|
|
140
|
-
* @returns {{r: number, g: number, b: number}|null}
|
|
141
|
-
*/
|
|
142
|
-
function parseRgbColor(colorString: string) {
|
|
143
|
-
const rgbMatch = /rgba?\((\d+),\s*(\d+),\s*(\d+)/.exec(colorString)
|
|
144
|
-
if (!rgbMatch) {
|
|
145
|
-
return null // Not a valid rgb/rgba string
|
|
146
|
-
}
|
|
147
|
-
return {
|
|
148
|
-
r: parseInt(rgbMatch[1]),
|
|
149
|
-
g: parseInt(rgbMatch[2]),
|
|
150
|
-
b: parseInt(rgbMatch[3]),
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Calculates the perceived luminance (0-255) of a CSS color string.
|
|
156
|
-
* @param {string} colorString - e.g., "rgb(50, 50, 50)" or "rgba(0, 0, 0, 0.5)"
|
|
157
|
-
* @returns {number|null} - The luminance, or null if the color is transparent or unparseable.
|
|
158
|
-
*/
|
|
159
|
-
function getLuminance(colorString: string): number | null {
|
|
160
|
-
if (!colorString || colorString === 'transparent' || colorString.startsWith('rgba(0, 0, 0, 0)')) {
|
|
161
|
-
return null // Transparent has no meaningful luminance
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const rgb = parseRgbColor(colorString)
|
|
165
|
-
if (!rgb) {
|
|
166
|
-
return null // Could not parse color
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Standard perceived luminance formula
|
|
170
|
-
return 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Determines if a color is "dark" based on its calculated luminance.
|
|
175
|
-
* @param {string} colorString - The CSS color string (e.g., "rgb(50, 50, 50)").
|
|
176
|
-
* @param {number} threshold - A value between 0 and 255. Colors with luminance below this will be considered dark. Default is 128.
|
|
177
|
-
*/
|
|
178
|
-
function isColorDark(colorString: string, threshold = 128) {
|
|
179
|
-
const luminance = getLuminance(colorString)
|
|
180
|
-
return luminance !== null && luminance < threshold
|
|
181
|
-
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="none">
|
|
2
|
-
<g><path d="M 15 42 L 15 36.99 Q 15 31.99 23.7 31.99 L 28.05 31.99 Q 32.41 31.99 32.41 21.99 L 32.41 17 Q 32.41 12 41.09 16.95 L 76.31 37.05 Q 85 42 76.31 46.95 L 41.09 67.05 Q 32.41 72 32.41 62.01 L 32.41 57.01 Q 32.41 52.01 23.7 52.01 L 19.35 52.01 Q 15 52.01 15 47.01 Z" fill="none" stroke="#000000" stroke-width="6" stroke-miterlimit="10" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g>
|
|
3
|
-
</svg>
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
2
|
-
<defs>
|
|
3
|
-
</defs>
|
|
4
|
-
<g xmlns="http://www.w3.org/2000/svg" style="filter: drop-shadow(light-dark(rgba(0, 0, 0, 0.4), rgba(237, 237, 237, 0.4)) 3px 4px 4px);"><path d="M 15 42 L 15 36.99 Q 15 31.99 23.7 31.99 L 28.05 31.99 Q 32.41 31.99 32.41 21.99 L 32.41 17 Q 32.41 12 41.09 16.95 L 76.31 37.05 Q 85 42 76.31 46.95 L 41.09 67.05 Q 32.41 72 32.41 62.01 L 32.41 57.01 Q 32.41 52.01 23.7 52.01 L 19.35 52.01 Q 15 52.01 15 47.01 Z" fill="#ffffff" stroke="none" style="fill: #ffffff;"/></g>
|
|
5
|
-
</svg>
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
.webmcp-page-agent-cursor {
|
|
2
|
-
position: absolute;
|
|
3
|
-
width: var(--cursor-size, 75px);
|
|
4
|
-
height: var(--cursor-size, 75px);
|
|
5
|
-
pointer-events: none;
|
|
6
|
-
z-index: 10000;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
.webmcp-page-agent-cursorBorder {
|
|
10
|
-
position: absolute;
|
|
11
|
-
width: 100%;
|
|
12
|
-
height: 100%;
|
|
13
|
-
background: linear-gradient(45deg, rgb(57, 182, 255), rgb(189, 69, 251));
|
|
14
|
-
mask-image: url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20100%20100'%20fill='none'%3e%3cg%3e%3cpath%20d='M%2015%2042%20L%2015%2036.99%20Q%2015%2031.99%2023.7%2031.99%20L%2028.05%2031.99%20Q%2032.41%2031.99%2032.41%2021.99%20L%2032.41%2017%20Q%2032.41%2012%2041.09%2016.95%20L%2076.31%2037.05%20Q%2085%2042%2076.31%2046.95%20L%2041.09%2067.05%20Q%2032.41%2072%2032.41%2062.01%20L%2032.41%2057.01%20Q%2032.41%2052.01%2023.7%2052.01%20L%2019.35%2052.01%20Q%2015%2052.01%2015%2047.01%20Z'%20fill='none'%20stroke='%23000000'%20stroke-width='6'%20stroke-miterlimit='10'%20style='stroke:%20light-dark(rgb(0,%200,%200),%20rgb(255,%20255,%20255));'/%3e%3c/g%3e%3c/svg%3e");
|
|
15
|
-
mask-size: 100% 100%;
|
|
16
|
-
mask-repeat: no-repeat;
|
|
17
|
-
|
|
18
|
-
transform-origin: center;
|
|
19
|
-
transform: rotate(-90deg) scale(0.8);
|
|
20
|
-
margin-left: -10px;
|
|
21
|
-
margin-top: -18px;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.webmcp-page-agent-cursorFilling {
|
|
25
|
-
position: absolute;
|
|
26
|
-
width: 100%;
|
|
27
|
-
height: 100%;
|
|
28
|
-
background: url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20100%20100'%3e%3cdefs%3e%3c/defs%3e%3cg%20xmlns='http://www.w3.org/2000/svg'%20style='filter:%20drop-shadow(light-dark(rgba(0,%200,%200,%200.4),%20rgba(237,%20237,%20237,%200.4))%203px%204px%204px);'%3e%3cpath%20d='M%2015%2042%20L%2015%2036.99%20Q%2015%2031.99%2023.7%2031.99%20L%2028.05%2031.99%20Q%2032.41%2031.99%2032.41%2021.99%20L%2032.41%2017%20Q%2032.41%2012%2041.09%2016.95%20L%2076.31%2037.05%20Q%2085%2042%2076.31%2046.95%20L%2041.09%2067.05%20Q%2032.41%2072%2032.41%2062.01%20L%2032.41%2057.01%20Q%2032.41%2052.01%2023.7%2052.01%20L%2019.35%2052.01%20Q%2015%2052.01%2015%2047.01%20Z'%20fill='%23ffffff'%20stroke='none'%20style='fill:%20%23ffffff;'/%3e%3c/g%3e%3c/svg%3e");
|
|
29
|
-
background-size: 100% 100%;
|
|
30
|
-
background-repeat: no-repeat;
|
|
31
|
-
|
|
32
|
-
transform-origin: center;
|
|
33
|
-
transform: rotate(-90deg) scale(0.8);
|
|
34
|
-
margin-left: -10px;
|
|
35
|
-
margin-top: -18px;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.webmcp-page-agent-cursorRipple {
|
|
39
|
-
position: absolute;
|
|
40
|
-
width: 100%;
|
|
41
|
-
height: 100%;
|
|
42
|
-
pointer-events: none;
|
|
43
|
-
margin-left: -50%;
|
|
44
|
-
margin-top: -50%;
|
|
45
|
-
|
|
46
|
-
&::after {
|
|
47
|
-
content: '';
|
|
48
|
-
opacity: 0;
|
|
49
|
-
position: absolute;
|
|
50
|
-
inset: 0;
|
|
51
|
-
border: 4px solid rgba(57, 182, 255, 1);
|
|
52
|
-
border-radius: 50%;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.webmcp-page-agent-cursor.clicking .webmcp-page-agent-cursorRipple::after {
|
|
57
|
-
animation: webmcp-page-agent-cursor-ripple 300ms ease-out forwards;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
@keyframes webmcp-page-agent-cursor-ripple {
|
|
61
|
-
0% {
|
|
62
|
-
transform: scale(0);
|
|
63
|
-
opacity: 1;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
100% {
|
|
67
|
-
transform: scale(2);
|
|
68
|
-
opacity: 0;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
<svg viewBox="0 0 79.0834 79.4553" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="79.083374" height="79.455322" fill="none" customFrame="#000000">
|
|
2
|
-
--
|
|
3
|
-
<defs>
|
|
4
|
-
<g id="pixso_custom_effect_0">
|
|
5
|
-
<effect x="6.000000" y="6.000000" visibility="visible" fill="rgb(0,0,0)" fill-opacity="0.180000007" effectType="dropShadow" stdDeviation="20" radius="0" />
|
|
6
|
-
</g>
|
|
7
|
-
<filter id="filter_0" width="79.083374" height="79.455322" x="0.000000" y="0.000000" filterUnits="userSpaceOnUse" customEffect="url(#pixso_custom_effect_0)" color-interpolation-filters="sRGB">
|
|
8
|
-
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
|
9
|
-
<feOffset dx="6.000000" dy="6.000000" in="SourceAlpha" />
|
|
10
|
-
<feGaussianBlur stdDeviation="6.66666651" />
|
|
11
|
-
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.18 0 " />
|
|
12
|
-
<feBlend result="effect_dropShadow_1" in2="BackgroundImageFix" mode="normal" />
|
|
13
|
-
<feBlend result="shape" in="SourceGraphic" in2="effect_dropShadow_1" mode="normal" />
|
|
14
|
-
</filter>
|
|
15
|
-
<linearGradient id="paint_linear_0" x1="18.4743214" x2="18.4213886" y1="-1.86264515e-09" y2="34.9221306" gradientUnits="userSpaceOnUse">
|
|
16
|
-
<stop stop-color="rgb(255,181,96)" offset="0" stop-opacity="1" />
|
|
17
|
-
<stop stop-color="rgb(255,120,114)" offset="0.5" stop-opacity="1" />
|
|
18
|
-
<stop stop-color="rgb(241,109,237)" offset="1" stop-opacity="1" />
|
|
19
|
-
</linearGradient>
|
|
20
|
-
</defs>
|
|
21
|
-
<g filter="url(#filter_0)">
|
|
22
|
-
<path id="多边形 11" d="M20.2632 3.57771L34.6257 32.3027C35.4444 33.9402 33.8152 35.7258 32.1097 35.0603L19.2014 30.0229C18.7339 29.8404 18.2148 29.8404 17.7472 30.0229L4.83891 35.0603C3.13343 35.7258 1.50423 33.9402 2.32297 32.3027L16.6855 3.57771C17.4225 2.10361 19.5261 2.10361 20.2632 3.57771Z" fill="url(#paint_linear_0)" fill-rule="evenodd" transform="matrix(0.719908,-0.69407,0.69407,0.719908,2.00256,28.0095)" />
|
|
23
|
-
<path id="多边形 11" d="M37.2169 32.6848C37.1578 32.189 37.0096 31.7039 36.7723 31.2294L22.4098 2.5044C22.1973 2.07946 21.9328 1.70554 21.6163 1.38261C21.3524 1.11342 21.0524 0.879671 20.7162 0.681366C20.3925 0.490407 20.0558 0.34434 19.7061 0.243163C19.312 0.129145 18.9014 0.0721366 18.4743 0.0721366C18.0472 0.0721366 17.6367 0.129145 17.2426 0.243163C16.8929 0.34434 16.5562 0.490407 16.2324 0.681366C15.8962 0.879671 15.5962 1.11342 15.3323 1.38261C15.0158 1.70553 14.7513 2.07946 14.5388 2.5044L0.176342 31.2294C-0.0609121 31.7039 -0.209128 32.189 -0.268305 32.6848C-0.316251 33.0865 -0.305747 33.4951 -0.236792 33.9108C-0.171059 34.307 -0.0570567 34.6809 0.105216 35.0326C0.292784 35.4391 0.544845 35.8158 0.861397 36.1627C1.17794 36.5097 1.53001 36.7951 1.91761 37.0191C2.25297 37.2128 2.61492 37.3606 3.00348 37.4623C3.41106 37.5689 3.81704 37.6168 4.22142 37.6058C4.72053 37.5922 5.21719 37.4889 5.71141 37.2961L18.4743 32.3154L31.2372 37.2961C31.7315 37.4889 32.2281 37.5922 32.7272 37.6058C33.1316 37.6168 33.5376 37.5689 33.9452 37.4623C34.3337 37.3606 34.6957 37.2128 35.0311 37.0191C35.4187 36.7951 35.7707 36.5097 36.0873 36.1627C36.4038 35.8158 36.6558 35.4391 36.8434 35.0327C37.0057 34.681 37.1197 34.307 37.1854 33.9108C37.2544 33.4951 37.2649 33.0865 37.2169 32.6848ZM34.6257 32.3027L20.2632 3.57771C19.5261 2.10361 17.4225 2.10361 16.6855 3.57771L2.32297 32.3027C1.50423 33.9402 3.13343 35.7258 4.83891 35.0603L17.7472 30.0229C18.2148 29.8404 18.7339 29.8404 19.2014 30.0229L32.1097 35.0603C33.8152 35.7258 35.4444 33.9402 34.6257 32.3027Z" fill="rgb(255,255,255)" fill-rule="evenodd" transform="matrix(0.719908,-0.69407,0.69407,0.719908,2.00256,28.0095)" />
|
|
24
|
-
</g>
|
|
25
|
-
</svg>
|