fix conflict

This commit is contained in:
wurou 2022-09-22 20:02:16 +08:00
commit 8bed4c0ed1
133 changed files with 4953 additions and 930 deletions

10
.gitignore vendored
View File

@ -23,4 +23,12 @@ dist-ssr
*.sln
*.sw?
temp/
types/
types/
src/components/**/*.d.ts
src/components/**/*.js
src/components/**/*.js.map
src/lib/**/*.d.ts
src/lib/**/*.js
src/lib/**/*.js.map
*.tsbuildinfo

View File

@ -18,3 +18,8 @@
- add delay exchange feature
- fix bugs of container exchange stradegy
- add confirm
- add dock
- add function for dragging icon into dock
- add function for dragging icon into container
- add homescreen function for storing apps' order
- fix bugs of container

View File

@ -34,32 +34,6 @@
font-weight: 500;
font-style: normal;
}
:root {
--left-transform: -100vw;
--right-transform: +100vw;
--li-base-height: 43px;
--li-left-padding: 10px;
--li-right-padding: 10px;
--blur-image: '';
--blur-radius-factor: 20;
--blur-radius: calc(1px * var(--blur-radius-factor));
--blur-scale-base-factor: 1.05;
--blur-scale-factor: calc(
var(--blur-scale-base-factor) + (var(--blur-radius-factor) - 20) *
0.0025
);
}
/* for nanopcT4 */
@media (max-width: 500px) {
:root {
--blur-radius-factor: 5;
--blur-scale-factor: calc(
var(--blur-scale-base-factor) + (var(--blur-radius-factor)) * 0.005
);
}
}
</style>
</body>
</html>

View File

@ -1,12 +1,9 @@
{
"name": "start-element",
"name": "star-element",
"private": true,
"version": "0.0.1",
"type": "module",
"main": "dist/my-element.es.js",
"exports": {
".": "./dist/my-element.es.js"
},
"types": "types/my-element.d.ts",
"files": [
"dist",
@ -14,7 +11,10 @@
],
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"build": "yarn run esbuild:ts && yarn run build:ts",
"build:ts": "yarn tsc --build tsconfig-all.json",
"build:vite": "tsc && vite build",
"esbuild:ts": "node ./tasks/esbuild-packages.js",
"format": "npm run format:prettier",
"format:prettier": "prettier \"**/*.{cjs,html,js,json,md,ts}\" --write"
},
@ -23,7 +23,13 @@
},
"devDependencies": {
"prettier": "^2.7.1",
"typescript": "^4.6.4",
"vite": "^3.0.0"
}
"vite": "^3.0.0",
"esbuild": "^0.15.8",
"fast-glob": "^3.2.12",
"typescript": "^4.8.3"
},
"workspaces": [
"src/components/*",
"src/lib/*"
]
}

1
src/assets/close_eye.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1662551454749" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1825" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M938.666667 317.866667m-29.866667 0a29.866667 29.866667 0 1 0 59.733333 0 29.866667 29.866667 0 1 0-59.733333 0Z" fill="#666666" p-id="1826"></path><path d="M876.8 454.4c6.4-6.4 12.8-14.933333 19.2-21.333333 8.533333-8.533333 6.4-23.466667-2.133333-29.866667-8.533333-8.533333-23.466667-6.4-29.866667 2.133333-85.333333 100.266667-209.066667 157.866667-341.333333 157.866667-166.4 0-317.866667-91.733333-394.666667-238.933333-6.4-10.666667-19.2-14.933333-27.733333-8.533334-10.666667 6.4-14.933333 19.2-8.533334 27.733334 14.933333 27.733333 32 53.333333 49.066667 76.8L64 499.2c-8.533333 8.533333-8.533333 23.466667 0 32 4.266667 4.266667 8.533333 6.4 14.933333 6.4 6.4 0 12.8-2.133333 17.066667-8.533333l72.533333-76.8c36.266667 40.533333 81.066667 72.533333 128 98.133333l-55.466666 102.4c-6.4 10.666667-2.133333 25.6 8.533333 32 2.133333 2.133333 6.4 2.133333 8.533333 2.133333 8.533333 0 17.066667-4.266667 21.333334-12.8l55.466666-104.533333c51.2 21.333333 106.666667 34.133333 162.133334 36.266667v106.666666c0 12.8 10.666667 23.466667 21.333333 23.466667 12.8 0 21.333333-10.666667 21.333333-23.466667v-106.666666c53.333333-2.133333 104.533333-12.8 151.466667-29.866667l55.466667 102.4c4.266667 8.533333 12.8 12.8 21.333333 12.8 2.133333 0 6.4 0 8.533333-2.133333 10.666667-6.4 12.8-19.2 8.533334-32l-53.333334-98.133334c40.533333-19.2 78.933333-44.8 113.066667-74.666666l74.666667 78.933333c4.266667 4.266667 10.666667 8.533333 17.066666 8.533333 4.266667 0 10.666667-2.133333 14.933334-6.4 8.533333-8.533333 8.533333-23.466667 0-32l-74.666667-78.933333z" fill="#666666" p-id="1827"></path></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1662622097048" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="860" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M938.666667 317.866667m-29.866667 0a29.866667 29.866667 0 1 0 59.733333 0 29.866667 29.866667 0 1 0-59.733333 0Z" fill="#ffffff" p-id="861"></path><path d="M876.8 454.4c6.4-6.4 12.8-14.933333 19.2-21.333333 8.533333-8.533333 6.4-23.466667-2.133333-29.866667-8.533333-8.533333-23.466667-6.4-29.866667 2.133333-85.333333 100.266667-209.066667 157.866667-341.333333 157.866667-166.4 0-317.866667-91.733333-394.666667-238.933333-6.4-10.666667-19.2-14.933333-27.733333-8.533334-10.666667 6.4-14.933333 19.2-8.533334 27.733334 14.933333 27.733333 32 53.333333 49.066667 76.8L64 499.2c-8.533333 8.533333-8.533333 23.466667 0 32 4.266667 4.266667 8.533333 6.4 14.933333 6.4 6.4 0 12.8-2.133333 17.066667-8.533333l72.533333-76.8c36.266667 40.533333 81.066667 72.533333 128 98.133333l-55.466666 102.4c-6.4 10.666667-2.133333 25.6 8.533333 32 2.133333 2.133333 6.4 2.133333 8.533333 2.133333 8.533333 0 17.066667-4.266667 21.333334-12.8l55.466666-104.533333c51.2 21.333333 106.666667 34.133333 162.133334 36.266667v106.666666c0 12.8 10.666667 23.466667 21.333333 23.466667 12.8 0 21.333333-10.666667 21.333333-23.466667v-106.666666c53.333333-2.133333 104.533333-12.8 151.466667-29.866667l55.466667 102.4c4.266667 8.533333 12.8 12.8 21.333333 12.8 2.133333 0 6.4 0 8.533333-2.133333 10.666667-6.4 12.8-19.2 8.533334-32l-53.333334-98.133334c40.533333-19.2 78.933333-44.8 113.066667-74.666666l74.666667 78.933333c4.266667 4.266667 10.666667 8.533333 17.066666 8.533333 4.266667 0 10.666667-2.133333 14.933334-6.4 8.533333-8.533333 8.533333-23.466667 0-32l-74.666667-78.933333z" fill="#ffffff" p-id="862" data-spm-anchor-id="a313x.7781069.0.i1"></path></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

1
src/assets/eye.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1662604947168" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1462" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3-7.7 16.2-7.7 35.2 0 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766z" p-id="1463"></path><path d="M508 336c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176z m0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z" p-id="1464"></path></svg>

After

Width:  |  Height:  |  Size: 871 B

1
src/assets/eye_deep.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1662623767353" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1877" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3-7.7 16.2-7.7 35.2 0 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766z" p-id="1878" fill="#ffffff"></path><path d="M508 336c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176z m0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z" p-id="1879" fill="#ffffff"></path></svg>

After

Width:  |  Height:  |  Size: 901 B

View File

@ -0,0 +1,247 @@
import {html} from 'lit'
// 主题
export const store = html`
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1201_77537)">
<path
opacity="0.3"
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 14C10 11.7909 11.7909 10 14 10H34C36.2091 10 38 11.7909 38 14C38 16.2091 36.2091 18 34 18H14C11.7909 18 10 16.2091 10 14ZM16 14C16 12.9 15.1 12 14 12C12.9 12 12 12.9 12 14C12 15.1 12.9 16 14 16C15.1 16 16 15.1 16 14ZM10 24C10 21.7909 11.7909 20 14 20H34C36.2091 20 38 21.7909 38 24C38 26.2091 36.2091 28 34 28H14C11.7909 28 10 26.2091 10 24ZM16 24C16 22.9 15.1 22 14 22C12.9 22 12 22.9 12 24C12 25.1 12.9 26 14 26C15.1 26 16 25.1 16 24ZM14 30C11.7909 30 10 31.7909 10 34C10 36.2091 11.7909 38 14 38H34C36.2091 38 38 36.2091 38 34C38 31.7909 36.2091 30 34 30H14ZM14 32C15.1 32 16 32.9 16 34C16 35.1 15.1 36 14 36C12.9 36 12 35.1 12 34C12 32.9 12.9 32 14 32Z"
fill="#00B32F"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 14C10 11.7909 11.7909 10 14 10H34C36.2091 10 38 11.7909 38 14C38 16.2091 36.2091 18 34 18H14C11.7909 18 10 16.2091 10 14ZM16 14C16 12.9 15.1 12 14 12C12.9 12 12 12.9 12 14C12 15.1 12.9 16 14 16C15.1 16 16 15.1 16 14ZM10 24C10 21.7909 11.7909 20 14 20H31C33.2091 20 35 21.7909 35 24C35 26.2091 33.2091 28 31 28H14C11.7909 28 10 26.2091 10 24ZM16 24C16 22.9 15.1 22 14 22C12.9 22 12 22.9 12 24C12 25.1 12.9 26 14 26C15.1 26 16 25.1 16 24ZM14 30C11.7909 30 10 31.7909 10 34C10 36.2091 11.7909 38 14 38H28C30.2091 38 32 36.2091 32 34C32 31.7909 30.2091 30 28 30H14ZM14 32C15.1 32 16 32.9 16 34C16 35.1 15.1 36 14 36C12.9 36 12 35.1 12 34C12 32.9 12.9 32 14 32Z"
fill="#00B32F"
/>
</g>
<defs>
<clipPath id="clip0_1201_77537">
<rect width="48" height="48" fill="white" />
</clipPath>
</defs>
</svg>
`
// 图标
export const app = html`
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1201_77538)">
<path
opacity="0.3"
fill-rule="evenodd"
clip-rule="evenodd"
d="M25.636 18.1213C24.4644 16.9497 24.4644 15.0503 25.636 13.8787L29.8786 9.63604C31.0502 8.46447 32.9497 8.46447 34.1212 9.63604L38.3639 13.8787C39.5355 15.0503 39.5355 16.9497 38.3639 18.1213L34.1212 22.364C32.9497 23.5355 31.0502 23.5355 29.8786 22.364L25.636 18.1213Z"
fill="url(#paint0_linear_1201_77538)"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 13C10 11.3431 11.3431 10 13 10H19C20.6569 10 22 11.3431 22 13V19C22 20.6569 20.6569 22 19 22H13C11.3431 22 10 20.6569 10 19V13ZM10 29C10 27.3431 11.3431 26 13 26H19C20.6569 26 22 27.3431 22 29V35C22 36.6569 20.6569 38 19 38H13C11.3431 38 10 36.6569 10 35V29ZM29 26C27.3431 26 26 27.3431 26 29V35C26 36.6569 27.3431 38 29 38H35C36.6569 38 38 36.6569 38 35V29C38 27.3431 36.6569 26 35 26H29Z"
fill="url(#paint1_linear_1201_77538)"
/>
</g>
<defs>
<linearGradient
id="paint0_linear_1201_77538"
x1="28.0069"
y1="11.7574"
x2="36.3674"
y2="20.1179"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#F5987B" />
<stop offset="1" stop-color="#E24E3D" />
</linearGradient>
<linearGradient
id="paint1_linear_1201_77538"
x1="24.4118"
y1="10.4118"
x2="24.4118"
y2="38"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#F5987B" />
<stop offset="1" stop-color="#E24E3D" />
</linearGradient>
<clipPath id="clip0_1201_77538">
<rect width="48" height="48" fill="white" />
</clipPath>
</defs>
</svg>
`
// 桌面壁纸
export const desktopWallpaper = html`
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1201_77536)">
<circle
opacity="0.3"
cx="18"
cy="20"
r="4"
fill="url(#paint0_linear_1201_77536)"
/>
<path
opacity="0.3"
fill-rule="evenodd"
clip-rule="evenodd"
d="M23.8606 33.6647V31.6213L19.4646 28.4921C18.458 27.774 17.0309 27.8499 16.1198 28.6672L9.04797 35.0017C8.86321 35.1651 9.26503 35.2781 9.3606 35.5C9.45616 35.716 9.2391 36 9.49394 36H21.3122C22.7202 36 23.8606 34.955 23.8606 33.6647Z"
fill="url(#paint1_linear_1201_77536)"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M8 16C8 12.6863 10.6863 10 14 10H35C38.3137 10 41 12.6863 41 16V33C41 36.3137 38.3137 39 35 39H14C10.6863 39 8 36.3137 8 33V16ZM14 13C12 13 11 14.5 11 16V33C11 34.5 12.5 36 14 36H16.415L28.1308 24.251C29.5277 22.7185 31.716 22.5762 33.2595 23.9226L38 28.7679V16C38 14.5 37 13 35 13H14ZM18 17C19.66 17 21 18.34 21 20C21 21.66 19.66 23 18 23C16.34 23 15 21.66 15 20C15 18.34 16.34 17 18 17Z"
fill="url(#paint2_linear_1201_77536)"
/>
</g>
<defs>
<linearGradient
id="paint0_linear_1201_77536"
x1="18.0377"
y1="16"
x2="18.0377"
y2="24"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#A6C0FF" />
<stop offset="1" stop-color="#5546DE" />
</linearGradient>
<linearGradient
id="paint1_linear_1201_77536"
x1="16.5003"
y1="28"
x2="16.5003"
y2="36"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#A6C0FF" />
<stop offset="1" stop-color="#5546DE" />
</linearGradient>
<linearGradient
id="paint2_linear_1201_77536"
x1="24.5"
y1="0.333333"
x2="24.5"
y2="46.7333"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#A6C0FF" />
<stop offset="1" stop-color="#5546DE" />
</linearGradient>
<clipPath id="clip0_1201_77536">
<rect width="48" height="48" fill="white" />
</clipPath>
</defs>
</svg>
`
// 锁屏
export const lockscreen = html`
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1201_77532)">
<path
opacity="0.3"
d="M19.5 18C19.5 15.5147 21.5147 13.5 24 13.5C26.4853 13.5 28.5 15.5147 28.5 18V24.5H19.5V18Z"
stroke="url(#paint0_linear_1201_77532)"
stroke-width="3"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M17 20H31V18C31 14.134 27.866 11 24 11C20.134 11 17 14.134 17 18V20ZM14 20H13C10.7909 20 9 21.7909 9 24V35C9 37.2091 10.7909 39 13 39H35C37.2091 39 39 37.2091 39 35V24C39 21.7909 37.2091 20 35 20H34V18C34 12.4772 29.5228 8 24 8C18.4772 8 14 12.4772 14 18V20ZM25 29.7324C25.5978 29.3866 26 28.7403 26 28C26 26.8954 25.1046 26 24 26C22.8954 26 22 26.8954 22 28C22 28.7403 22.4022 29.3866 23 29.7324V32C23 32.5523 23.4477 33 24 33C24.5523 33 25 32.5523 25 32V29.7324Z"
fill="url(#paint1_linear_1201_77532)"
/>
</g>
<defs>
<linearGradient
id="paint0_linear_1201_77532"
x1="24"
y1="12"
x2="24"
y2="26"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#F79F84" />
<stop offset="1" stop-color="#E96A56" />
</linearGradient>
<linearGradient
id="paint1_linear_1201_77532"
x1="24.4412"
y1="7.47059"
x2="24.4412"
y2="39"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#F8A287" />
<stop offset="1" stop-color="#E24E3D" />
</linearGradient>
<clipPath id="clip0_1201_77532">
<rect width="48" height="48" fill="white" />
</clipPath>
</defs>
</svg>
`
// 隐私
export const privacy = html`
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1201_77539)">
<path
opacity="0.3"
fill-rule="evenodd"
clip-rule="evenodd"
d="M23.3984 40.8793C23.1856 40.7897 18.6128 38.8644 15.9 36.78C12.15 33.89 10 29.7 10 25.28V15.67C10 14.36 10.73 13.19 11.9 12.61L22.48 7.36C23.43 6.88 24.57 6.88 25.52 7.36L36.1 12.61C37.27 13.19 38 14.36 38 15.67V25.28C38 29.7 35.85 33.89 32.1 36.78C29.3872 38.8644 24.8144 40.7897 24.6016 40.8793L24.6 40.88C24.41 40.96 24.2 41 24 41C23.8 41 23.59 40.96 23.4 40.88L23.3984 40.8793ZM22.4 23.45C20.99 22.85 20 21.48 20 19.89C20 17.74 21.79 16 24 16C26.21 16 28 17.74 28 19.89C28 21.49 27.01 22.85 25.6 23.45V28.44C25.6 29.3 24.88 30 24 30C23.12 30 22.4 29.3 22.4 28.44V23.45Z"
fill="url(#paint0_linear_1201_77539)"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M23.3984 37.8793C23.186 37.7899 18.6129 35.8645 15.9 33.78C12.15 30.89 10 23.7 10 19.28V15.67C10 14.36 10.73 13.19 11.9 12.61L22.48 7.36C23.43 6.88 24.57 6.88 25.52 7.36L36.1 12.61C37.27 13.19 38 14.36 38 15.67V19.28C38 23.7 35.85 30.89 32.1 33.78C29.3871 35.8645 24.814 37.7899 24.6016 37.8793L24.6 37.88C24.41 37.96 24.2 38 24 38C23.8 38 23.59 37.96 23.4 37.88L23.3984 37.8793ZM22.4 23.45C20.99 22.85 20 21.48 20 19.89C20 17.74 21.79 16 24 16C26.21 16 28 17.74 28 19.89C28 21.49 27.01 22.85 25.6 23.45V28.44C25.6 29.3 24.88 30 24 30C23.12 30 22.4 29.3 22.4 28.44V23.45Z"
fill="url(#paint1_linear_1201_77539)"
/>
</g>
<defs>
<linearGradient
id="paint0_linear_1201_77539"
x1="23.9993"
y1="6.97134"
x2="24.8586"
y2="44.0158"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#68C9F9" />
<stop offset="1" stop-color="#1466D0" />
</linearGradient>
<linearGradient
id="paint1_linear_1201_77539"
x1="23.9993"
y1="6.97387"
x2="24"
y2="43"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#68C9F9" />
<stop offset="1" stop-color="#1466D0" />
</linearGradient>
<clipPath id="clip0_1201_77539">
<rect width="48" height="48" fill="white" />
</clipPath>
</defs>
</svg>
`
export type stackInstances = typeof store
export default {
store,
app,
desktopWallpaper,
lockscreen,
privacy,
} as {
[key: string]: stackInstances
}

View File

@ -0,0 +1 @@
export * from './svg-icon.js'

View File

@ -0,0 +1,30 @@
{
"name": "@star-web-components/asset",
"version": "0.0.1",
"description": "",
"type": "module",
"main": "./index.js",
"module": "./index.js",
"exports": {
".": {
"default": "./index.js"
},
"./index": {
"default": "./index.js"
},
"./index.js": {
"default": "./index.js"
},
"./icons/index.js": {
"default": "./icons/index.js"
},
"./package.json": "./package.json"
},
"dependencies": {
"lit": "^2.2.7",
"tslib": "^2.4.0",
"typescript": "^4.6.4"
},
"author": "",
"license": "ISC"
}

View File

@ -0,0 +1,37 @@
import {html, LitElement, css} from 'lit'
import {customElement, property} from 'lit/decorators.js'
import icons from './icons/index.js'
@customElement('star-svg-icon')
export class StarSvgIcon extends LitElement {
@property({type: Number}) width = 24
@property({type: Number}) height = 24
@property({type: String}) symbol = 'privacy'
render() {
const iconpath = icons[this.symbol]
return html`
<svg
width=${this.width}
height=${this.height}
class="svg-icon"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
${iconpath}
</svg>
`
}
static styles = css`
:host {
display: flex;
}
`
}
declare global {
interface HTMLElementTagNameMap {
'star-svg-icon': StarSvgIcon
}
}

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "./"
},
"include": ["*.ts", "icons/*.ts"]
}

View File

@ -0,0 +1,107 @@
import {css, CSSResult} from 'lit'
export const baseStyles: CSSResult = css`
:host {
/* 文字/正文黑 */
--font-main-black: #292929;
/* 文字/辅助字-黑 */
--font-auxiliary-black: rgba(38, 38, 38, 0.5);
/* 文字/标题黑 */
--font-heading-black: #4d4d4d;
/* 文字/正文白 */
--font-main-white: #f0f0f0;
/* 文字/高亮白 */
--font-highlight-white: #fafafa;
/* 文字/辅助字-白 */
--font-auxiliary-white: rgba(245, 245, 245, 0.5);
/* 倒角 */
--base-menu-radius: 16px;
--base-dialog-radius: 20px;
--base-border-radius: 34px;
/* 线性图标/32及以下-常规黑 */
--icon-regular: #333333;
/* 分隔符 */
--split-line: #cfd8e8;
/* 主题色/蓝 */
--theme-blue: #1d98f0;
/* 主题色/红 */
--theme-red: #ec4949;
--pure-white: #ffffff;
--font-main-size: 14px;
/* --font-main-weight: 400; */
--font-main-weight: bold;
--line-height: calc(3 * var(--font-main-size));
--li-left-padding: 10px;
--li-right-padding: 10px;
--li-base-height: 43px;
/***********默认浅色**************/
/* 商务/组件浅/白调-斜线渐变 */
--bg-dialog-gradient: linear-gradient(
137.64deg,
#f5f0f5 0%,
#fafafa 20.46%,
#d5daf2 90.45%
);
/* 底色/弹窗浅 */
--bg-dialog: linear-gradient(
134.78deg,
#f7f5f7 2.34%,
#fafafa 34.11%,
#e1e4f2 100%
);
/* 全/ hover_lm */
--bg-hover: rgba(0, 0, 0, 0.06);
--bg-gray-button: rgba(51, 51, 51, 0.06);
--bg-icon-button: rgba(255, 255, 255, 0.68);
--bg-button: rgba(247, 247, 247, 0.75);
}
@media (prefers-color-scheme: light) {
:host {
/* 底色/弹窗浅 */
--bg-dialog: linear-gradient(
134.78deg,
#f7f5f7 2.34%,
#fafafa 34.11%,
#e1e4f2 100%
);
/* 商务/组件浅/白调-斜线渐变 */
--bg-dialog-gradient: linear-gradient(
137.64deg,
#f5f0f5 0%,
#fafafa 20.46%,
#d5daf2 90.45%
);
/* 全/ hover_lm */
--bg-hover: rgba(0, 0, 0, 0.06);
--bg-button: rgba(247, 247, 247, 0.75);
--bg-gray-button: rgba(51, 51, 51, 0.06);
--bg-icon-button: rgba(255, 255, 255, 0.68);
}
}
@media (prefers-color-scheme: dark) {
:host {
/* 底色/弹窗深 */
--bg-dialog: linear-gradient(101.98deg, #4e5161 1.12%, #363a47 96.75%);
/* 全/ hover_dm */
--bg-hover: rgba(255, 255, 255, 0.09);
--bg-button: rgba(64, 64, 64, 0.7);
--bg-gray-button: rgba(228, 228, 228, 0.1);
--bg-icon-button: rgba(0, 0, 0, 0.3);
}
}
`

View File

@ -0,0 +1,2 @@
export * from './star-base-element.js'
export * from './base-style.js'

View File

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

View File

@ -1,5 +1,7 @@
import {LitElement, ReactiveElement} from 'lit'
import GestureDector, {GestureEvents} from '../../lib/gesture/gesture-detector'
import GestureDector, {
GestureEvents,
} from '../../lib/gesture/gesture-detector.js'
export interface StarInterface {
hello(): void

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts", "../../lib/gesture/gesture-detector.ts"]
}

View File

@ -12,7 +12,7 @@ export class StarBlur extends LitElement {
if (name === 'imagesrc') {
if (!this.imagesrc) console.error('StarBlur has no imagesrc')
document.documentElement.style.setProperty('--blur-image', this.imagesrc)
this.style.setProperty('--blur-image', this.imagesrc)
}
}
@ -28,6 +28,15 @@ export class StarBlur extends LitElement {
static styles = css`
:host {
--blur-image: '';
--blur-radius-factor: 20;
--blur-radius: calc(1px * var(--blur-radius-factor));
--blur-scale-base-factor: 1.05;
--blur-scale-factor: calc(
var(--blur-scale-base-factor) + (var(--blur-radius-factor) - 20) *
0.0025
);
position: absolute;
width: 100vw;
height: 100vh;
@ -35,6 +44,15 @@ export class StarBlur extends LitElement {
top: 0;
overflow: hidden;
}
/* for nanopcT4 */
@media (max-width: 500px) {
:host {
--blur-radius-factor: 5;
--blur-scale-factor: calc(
var(--blur-scale-base-factor) + (var(--blur-radius-factor)) * 0.005
);
}
}
#blur-mask {
position: absolute;
width: inherit;

View File

@ -0,0 +1 @@
export * from './blur.js'

View File

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

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts"]
}

View File

@ -27,6 +27,8 @@ export class StarBubble extends LitElement {
static styles = css`
:host {
--li-base-height: 43px;
display: inline-block;
width: calc(var(--li-base-height) - 16px); /* 尽量节省宽度 */
height: var(--li-base-height);

View File

@ -0,0 +1 @@
export * from './bubble.js'

View File

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

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts"]
}

View File

@ -1,6 +1,6 @@
import {LitElement, html, CSSResultArray, HTMLTemplateResult} from 'lit'
import {property, customElement} from 'lit/decorators.js'
import {sharedStyles} from './button-group'
import {sharedStyles} from './button-group.js'
@customElement('star-buttongroup')
export class StarButtonGroup extends LitElement {

View File

@ -0,0 +1 @@
export * from './buttongroup.js'

View File

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

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts"]
}

View File

@ -1,6 +1,25 @@
# star-button
星光 Web 组件——按钮组件本组件样式及代码风格依然在完善阶段现阶段介绍如下8 月 27 日)
星光按钮组件本组件样式及代码风格依然在完善阶段现阶段介绍如下8 月 27 日)
## 参照设计稿
基础原则:
1. 按钮的
2. 按钮具备大小属性(small,medium,large,extralarge)
3. 按钮中的图标位于左侧,图标应是可选的;如果存在图标,则文字是可选的,对应图标按钮。
默认值:
1. 按钮底色:无色
2. 按钮文字颜色:正文黑
3. 按钮文字:确定
按钮类型 1无底色 + 文字(带颜色 白|黑|蓝|红|灰))的自适应矩形块, 用于弹窗按钮、菜单按钮
按钮类型 2给定底色 + 图标)的圆形块, 用于工具按钮(如通知栏左滑处,任务管理器关闭处)
按钮类型 3给定底色 + 文字)的倒角矩形块, 用于强调按钮(如主题选择)
按钮类型 4图标 + 文字)的矩形块, 用于菜单按钮、主题选择处
## 介绍
@ -8,7 +27,7 @@ star-button 属性:
1. type按钮类型包括文本按钮 base、图标文本按钮 iconlabel 和图标按钮 icononly。
```html demo
```html
<star-button type="base" label="文本按钮"></star-button>
<star-button type="iconlabel" label="图标文本按钮"></star-button>
<star-button type="icononly" label="图标按钮"></star-button>
@ -16,14 +35,14 @@ star-button 属性:
2. variant按钮样式包括 accent、primary、secondary、negative、black 和 white默认为 accent。
```html demo
```html
<star-button type="base" variant="accent" label="accent"></star-button>
<star-button type="base" variant="primary" label="primary"></star-button>
```
3. size控制按钮大小包括 small、medium、large 和 extralarge 四种,默认为 medium。
```html demo
```html
<star-button
type="base"
variant="accent"
@ -40,19 +59,19 @@ star-button 属性:
4. label显示按钮名如省略则显示为“默认”。
```html demo
```html
<star-button type="base" variant="accent" label="按钮名"></star-button>
```
5. disabled控制按钮禁用状态默认为false。
```html demo
```html
<star-button type="base" variant="accent" label="禁用" disabled></star-button>
```
6. treatment控制按钮填充状态包括 fill 和 outline默认为fill。
```html demo
```html
<star-button
type="base"
variant="accent"
@ -69,7 +88,7 @@ star-button 属性:
7. icon 和 iconcolor控制图标样式和其颜色。
```html demo
```html
<star-button
type="base"
variant="accent"

View File

@ -1,12 +1,13 @@
import {
html,
LitElement,
css,
CSSResultArray,
HTMLTemplateResult,
nothing,
} from 'lit'
import {customElement, property} from 'lit/decorators.js'
import {sharedStyles} from './button-styles'
import {baseStyles} from '../base/base-style.js'
export enum ButtonType {
BASE = 'base',
@ -34,7 +35,100 @@ export enum ButtonVariants {
@customElement('star-button')
export class StarButton extends LitElement {
public static override get styles(): CSSResultArray {
return [sharedStyles]
return [
baseStyles,
css`
:host {
width: 100%;
height: 100%;
display: block;
}
:host([type='icononly']) {
width: var(--line-height);
height: var(--line-height);
background-color: var(--bg-gray-button);
border-radius: 50%;
}
:host(.confirm),
:host(.cancel) {
margin: 10px;
}
button {
width: inherit;
height: inherit;
text-align: center;
color: var(--font-main-black);
font-size: var(--font-main-size);
font-family: 'OPPOSans';
background-color: unset;
padding: unset;
border: none;
line-height: var(--line-height);
white-space: nowrap;
cursor: pointer;
}
:host([type='icononly']) button {
padding: unset;
position: absolute;
}
:host([type='iconlabel']) button {
text-align: left;
}
:host(.left) button {
text-align: left;
padding-inline-start: var(--li-left-padding);
}
:host(.normal) button,
:host(.ok) button,
:host(.warning) button,
:host(.cancel) button,
:host(.confirm) button,
:host(.auxiliary) button {
font-weight: var(--font-main-weight);
}
:host(.ok) button {
color: var(--theme-blue);
}
:host(.warning) button {
color: var(--theme-red);
}
:host(.chamfer) button {
border-radius: var(--base-border-radius);
}
:host(.cancel) button {
color: var(--font-heading-black);
background-color: var(--bg-gray-button);
}
:host(.confirm) button {
color: var(--font-main-white);
background-color: var(--theme-blue);
}
:host(.auxiliary) button {
display: flex;
color: var(--font-auxiliary-black);
}
:host(.floatright) button {
min-width: 50px;
color: var(--font-heading-black);
background-color: var(--bg-gray-button);
}
:host([type='icononly']) button::before,
:host([type='iconlabel']) button::before {
font-family: 'gaia-icons';
content: attr(data-icon);
text-align: center;
color: var(--icon-regular);
}
:host([type='iconlabel']) button::before {
padding: 0 10px;
}
:host(.auxiliary) button a {
display: flex;
align-items: center;
margin: auto;
}
`,
]
}
@property({type: String}) type = 'base'
@property({type: String}) variant = 'accent'
@ -46,83 +140,26 @@ export class StarButton extends LitElement {
@property({type: String}) iconcolor = ''
getBaseButton(): HTMLTemplateResult {
if (this.hasAttribute('disabled')) {
return html`
<button class="disabled ${this.variant} ${this.size} ${this.treatment}">
return html`
<button>
<a>
<slot name="asset"></slot>
${this.label}
</button>
`
} else {
return html`
<button class="${this.variant} ${this.size} ${this.treatment}">
${this.label}
</button>
`
}
</a>
</button>
`
}
getIconLabelButton(): HTMLTemplateResult {
const colorstyle = this.iconcolor
? html`
<style>
button::before {
color: ${this.iconcolor} !important;
}
</style>
`
: nothing
if (this.hasAttribute('disabled')) {
return html`
<button
class="disabled hasicon ${this.variant} ${this.size} ${this
.treatment}"
data-icon=${this.icon}
>
${colorstyle} ${this.label}
</button>
`
} else {
return html`
<button
class="hasicon ${this.variant} ${this.size} ${this.treatment}"
data-icon=${this.icon}
>
${colorstyle} ${this.label}
</button>
`
}
return html`
<button data-icon=${this.icon}>${this.label}</button>
`
}
getIconOnlyButton(): HTMLTemplateResult {
const colorstyle = this.iconcolor
? html`
<style>
button::before {
color: ${this.iconcolor} !important;
}
</style>
`
: nothing
if (this.hasAttribute('disabled')) {
return html`
<button
class="icononly disabled ${this.variant} ${this.size} ${this
.treatment}"
data-icon=${this.icon}
>
${colorstyle}
</button>
`
} else {
return html`
<button
class="icononly ${this.variant} ${this.size} ${this.treatment}"
data-icon=${this.icon}
>
${colorstyle}
</button>
`
}
return html`
<button data-icon=${this.icon}></button>
`
}
getConfirmButton(): HTMLTemplateResult {
return html`

View File

@ -0,0 +1 @@
export * from './button.js'

View File

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

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts", "../base/base-style.ts"]
}

View File

@ -6,7 +6,7 @@ import {
nothing,
} from 'lit'
import {customElement, property} from 'lit/decorators.js'
import {sharedStyles} from './card-styles'
import {sharedStyles} from './card-styles.js'
export enum CardType {
BASE = 'base',

View File

@ -0,0 +1 @@
export * from './card.js'

View File

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

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts"]
}

View File

@ -1,6 +1,6 @@
import {html, LitElement, CSSResultArray} from 'lit'
import {customElement, property} from 'lit/decorators.js'
import {sharedStyles} from './confirm-style'
import {sharedStyles} from './confirm-style.js'
@customElement('star-confirm')
export class StarConfirm extends LitElement {
public static override get styles(): CSSResultArray {

View File

@ -0,0 +1 @@
export * from './confirm.js'

View File

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

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts"]
}

View File

@ -0,0 +1,14 @@
# 数字密码-digicipher
工作职责:
- 由0-9数字组成的数字密码
- 默认密码为 `123456`
- 点击数字反馈,输入成功上滑,输入错误抖动反馈
## 使用
```
<star-digicipher></star-digicipher>
```

View File

@ -0,0 +1,171 @@
import {css, CSSResult} from 'lit'
export const sharedStyles: CSSResult = css`
body {
margin: 0;
padding: 0;
user-select: none;
}
p,
button,
i,
h2,
.cancel,
.delete {
font-family: 'OPPOSans';
margin-top: 0;
color: #292929;
}
span {
position: relative;
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
margin-right: 20px;
background: #000000;
opacity: 0.2;
}
p {
position: absolute;
font-family: 'OPPOSans';
font-style: normal;
font-weight: 400;
color: #292929;
}
#zero {
position: absolute;
left: 44.15%;
top: 70%;
}
button {
position: relative;
width: 70px;
height: 70px;
border-radius: 50%;
border: none;
/*button背景无色*/
background: rgba(0, 0, 0, 0);
display: inline-block;
font-size: 35px;
}
/*按钮点击的效果*/
button::before {
content: '';
display: none;
position: absolute;
top: 2px;
left: 1px;
width: 70px;
height: 70px;
border-radius: 50%;
background-color: #ffffff;
opacity: 0.35;
}
.block::before {
display: block;
}
#slideUp {
position: absolute;
height: 100%;
width: 100%;
}
.topText {
font-size: 20px;
height: 26.5px;
line-height: 26.5px;
width: 80px;
left: calc(50% - 80px / 2 + 3px);
top: calc(50% - 26.5px / 2 - 168.75px);
}
.spanContainer {
position: absolute;
left: 206px;
top: 349.5px;
}
.grid {
position: absolute;
display: grid;
grid-template-areas: '1 2 3 ' '4 5 6' '7 8 9' '. 0 .';
grid-gap: 20px;
margin: 404px 176px;
}
.cancel,
.delete {
position: absolute;
font-family: 'OPPOSans';
font-style: normal;
font-weight: 400;
color: #292929;
width: 36px;
height: 23.5px;
line-height: 23.5px;
font-size: 18px;
}
.cancel {
left: calc(50% - 36px / 2 - 90px);
top: calc(50% - 23.5px / 2 + 231.75px);
}
.delete {
left: calc(50% - 36px / 2 + 90px);
top: calc(50% - 23.5px / 2 + 231.75px);
}
.cancel:hover,
.delete:hover {
cursor: pointer;
}
.cancel:active,
.delete:active {
color: #777;
transition: color 0.5s;
}
/*抖动反馈*/
@keyframes errtips {
10% {
transform: translateY(2px);
}
20% {
transform: translateY(-2px);
}
30% {
transform: translateY(2px);
}
40% {
transform: translateY(2px);
}
50% {
transform: translateY(-2px);
}
60% {
transform: translateY(2px);
}
70% {
transform: translateY(-2px);
}
80% {
transform: translateY(2px);
}
90% {
transform: translateY(-2px);
}
100% {
transform: translateY(0);
}
}
/*密码输入正确后动效*/
@keyframes suctip {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-1000px);
}
}
`

View File

@ -0,0 +1,152 @@
import {html, LitElement, CSSResultArray} from 'lit'
import {customElement, property, query, queryAll} from 'lit/decorators.js'
import {sharedStyles} from './digicipher-style'
@customElement('star-digicipher')
export class StarLockNumber extends LitElement {
public static override get styles(): CSSResultArray {
return [sharedStyles]
}
@query('#slideUp') slideUp!: HTMLDivElement
@queryAll('button') buttons!: NodeListOf<HTMLButtonElement>
@query('zero') zero!: HTMLButtonElement
@queryAll('span') span!: NodeListOf<HTMLSpanElement>
@query('spanContainer') spanContainer!: HTMLDivElement
@query('#parent') parent!: HTMLDivElement
@query('.delete') _delete!: HTMLParagraphElement
@query('.cancel') cancel!: HTMLParagraphElement
@query('.topText') topText!: HTMLParagraphElement
@query('.screen') screen!: HTMLDivElement
@property({type: Number}) clicks = 0
@property({type: Number}) _number = 0
@property({type: Number}) clickNumber = 0
@property({type: String}) color = ''
@property({type: String}) opacity = ''
@property({type: String}) guess = ''
@property({type: String}) passwd = '123456'
render() {
return html`
<div id="slideUp">
<p class="topText"></p>
<div class="spanContainer">
<span id="sOne"></span>
<span id="sTwo"></span>
<span id="sThree"></span>
<span id="sFour"></span>
<span id="sFive"></span>
<span id="sSix"></span>
</div>
<div
id="parent"
@touchstart=${this.touchStart}
@touchend=${this.touchEnd}
>
<button class="0" id="zero" data-num="0">0</button>
<div class="grid">
<button data-num="1">1</button>
<button data-num="2">2</button>
<button data-num="3">3</button>
<button data-num="4">4</button>
<button data-num="5">5</button>
<button data-num="6">6</button>
<button data-num="7">7</button>
<button data-num="8">8</button>
<button data-num="9">9</button>
</div>
<p class="cancel" id="lockCancel"></p>
<p class="delete"></p>
</div>
</div>
`
}
touchStart(e: TouchEvent) {
e.preventDefault()
// console.log('e.target', (e.target as HTMLElement).dataset.num)
// console.log('click', this.clickNumber)
// 点击数字,圆点变色并输出
if ((e.target as Element).tagName === 'BUTTON') {
this.clickNumber = Number((e.target as HTMLElement).dataset.num)
this.makeZero()
//点击反馈
this.changeNumberBgColor()
if (this.clicks < 6) {
//圆点变化
this.changeBgColor('#333333', this.clicks, 1)
this.clicks += 1
this.guess += (e.target as HTMLElement).dataset.num
console.log('输入后为:', this.guess)
}
//密码错误
if (this.clicks == 6 && this.guess !== this.passwd) {
console.log('密码错误')
// 抖动反馈
for (let i = 0; i < 10; i++) {
this.buttons[i].style.setProperty('animation', 'errtips .5s')
}
//清空密码且删除抖动反馈
for (let i = 0; i < 6; i++) {
this.changeBgColor('#000000', i, 0.2)
}
this.guess = ''
this.clicks = 0
}
} else if ((e.target as Element).className === 'delete') {
if (this.clicks == 0) {
console.log('不可再删除')
} else {
this.clicks -= 1
this.changeBgColor('#000000', this.clicks, 0.2)
this.guess = this.guess.slice(0, -1)
console.log('删除后为:', this.guess)
}
} else if ((e.target as Element).className === 'cancel') {
//点击取消,返回锁屏
console.log('返回锁屏')
// this.makeZero()
for (let i = 0; i < 6; i++) {
this.changeBgColor('#000000', i, 0.2)
}
this.guess = ''
this.clicks = 0
}
if (this.guess === this.passwd) {
for (let j = 0; j < 10; j++) {
this.buttons[j].removeAttribute('style')
}
console.log('密码正确')
// this.slideUp.removeAttribute('style')
for (let i = 0; i < 6; i++) {
this.changeBgColor('#000000', i, 0.2)
}
this.guess = ''
this.clicks = 0
this.slideUp.style.setProperty('animation', 'suctip .6s')
}
}
touchEnd(e: TouchEvent) {
if ((e.target as Element).tagName === 'BUTTON') {
this.removeNumberBgColor()
}
}
changeBgColor(color: string, _number: number, opacity: number) {
this.span[_number].style.backgroundColor = color
this.span[_number].style.opacity = String(opacity)
}
removeNumberBgColor() {
this.buttons[this.clickNumber].classList.remove('block')
}
changeNumberBgColor() {
this.buttons[this.clickNumber].classList.add('block')
}
makeZero() {
//抖动、滑动属性清零
this.slideUp.removeAttribute('style')
for (let j = 0; j < 10; j++) {
this.buttons[j].removeAttribute('style')
}
}
}

View File

@ -0,0 +1,44 @@
# 程序坞组件
为主屏应用图标提供固定位置,方便用户快速开启应用
## 基本用法
在`HTML`文件下添加该`container`文件即可使用:
```html
<head>
<script src="dock/dock.js"></script>
</head>
<body>
<star-dock></star-container>
</body>
```
之后可以在`js`中添加子节点:
```js
const dock = document.querySelector('star-dock')
dock.appendContainerChild(element)
```
删除子节点
```js
const dock = document.querySelector('star-dock')
dock.removeContainerChild(element)
```
## 事件监听
当图标拖拽离开程序坞时,将会向外发送 `out-of-dock` 事件,再拖动回来时会发送 `return-dock`
事件内容为:
```js
detail = {
element: HTMLElement, // 拖拽中的元素
centerX: number, // 拖拽元素的水平中心位置
centerY: number, // 拖拽元素的垂直中心位置
}
```

View File

@ -0,0 +1,93 @@
import StarDock from './dock'
export default class DockChild {
manager!: StarDock
_element!: HTMLElement
_master!: HTMLElement
_container!: HTMLElement
// 静态位置
_lastMasterTop: number | null = null
_lastMasterLeft: number | null = null
_lastElementOrder: string | null = null
_lastElementDisplay: string | null = null
_lastElementHeight: number | null = null
_lastElementWidth: number | null = null
_lastElementTop: number | null = null
_lastElementLeft: number | null = null
_lastMasterWidth: number | null = null
_lastMasterHeight: number | null = null
// 图标中心位置
center: {x: number; y: number} = {
x: 0,
y: 0,
}
// 状态计时器
removed: number | undefined = undefined
added: number | undefined = undefined
constructor(_element: HTMLElement, manager: StarDock) {
this._element = _element
this.manager = manager
}
get master() {
if (!this._master) {
const master = document.createElement('div')
master.classList.add('dock-child-master')
master.appendChild(this.container)
this._master = master
}
return this._master
}
get container() {
if (!this._container) {
const container = document.createElement('div')
container.classList.add('dock-child-container')
container.appendChild(this._element)
this._container = container
}
return this._container
}
get element() {
return this._element
}
set element(node: HTMLElement) {
if (this._element) {
this.container.replaceChild(node, this._element)
}
this._element = node
}
set order(value: number) {
this.master.style.order = String(value)
}
get order() {
return Array.from(this.manager.container.children).indexOf(this.master)
}
synchroniseContainer() {
let master = this.master
let container = this.container
let top = master.offsetTop
let left = master.offsetLeft
this._lastMasterTop = top
this._lastMasterLeft = left
this._lastElementLeft = this._element?.offsetLeft!
this._lastElementHeight = this._element?.offsetHeight!
this._lastMasterWidth = this._master.offsetWidth
this._lastMasterHeight = this._master.offsetHeight
this.center.x = left + this._lastMasterWidth / 2
this.center.y = top + this._lastMasterHeight / 2
!this.container.classList.contains('dragging') &&
(container.style.transform = 'translate(' + left + 'px, ' + top + 'px)')
}
}

734
src/components/dock/dock.ts Normal file
View File

@ -0,0 +1,734 @@
import {html, css, LitElement, CSSResultGroup} from 'lit'
import {customElement, query} from 'lit/decorators.js'
import DockChild from './dock-child'
import customStyle from './style'
interface DragAndDrop {
// Whether drag-and-drop is enabled
enabled: boolean
// The time, in ms, to wait before initiating a drag-and-drop from a
// long-press
delay: number
lastMoveEventTime: number
// Timeout used to initiate drag-and-drop actions
timeout: number | undefined
// The child that was tapped/clicked
child: any
// Whether a drag is active
active: boolean
// The start point of the drag action
start: {
pageX: number
pageY: number
clientX: number
clientY: number
translateX?: number
translateY?: number
}
// The last point of the drag action
last: {
pageX: number
pageY: number
clientX: number
clientY: number
timeStamp: number
offsetHeight: number
offsetWidth: number
offsetX: number
offsetY: number
}
// Timeout used to send drag-move events
moveTimeout: number | undefined
top: number
left: number
// 中心坐标
center: {
x: number
y: number
}
}
const DND_MOVE_THROTTLE = 50
const DND_THRESHOLD = 5
const DEFAULT_DND_TIMEOUT = 300
const STATE_CHANGE_TIMEOUT = 100
@customElement('star-dock')
export default class StarDock extends LitElement {
@query('#container') container!: HTMLElement
_children: DockChild[] = []
_sortMode: Boolean = false
_dragInElement: HTMLElement | undefined
_dragChild: DockChild | undefined
_gridSize!: number
distance!: number
_containerOffset: {[position: string]: number} = {
top: 0,
left: 0,
}
_dnd: DragAndDrop = {
enabled: true,
active: false,
child: undefined,
timeout: undefined,
moveTimeout: undefined,
lastMoveEventTime: -1,
delay: DEFAULT_DND_TIMEOUT,
top: 0,
left: 0,
center: {
x: 0,
y: 0,
},
last: {
pageX: 0,
pageY: 0,
clientX: 0,
clientY: 0,
timeStamp: 0,
offsetHeight: 0,
offsetWidth: 0,
offsetX: 0,
offsetY: 0,
},
start: {
pageX: 0,
pageY: 0,
clientX: 0,
clientY: 0,
translateX: 0,
translateY: 0,
},
}
appendContainerChild = (
element: HTMLElement,
order?: number,
callback?: Function
) => {
const child =
this.getChildByElement(element) || new DockChild(element, this)
this._children.push(child)
this.container.appendChild(child.master)
if (typeof order == 'number') {
child.order = order
}
this.changeState(child, 'added', callback)
}
removeContainerChild = (element: HTMLElement, callback?: Function) => {
const target = this.getChildByElement(element)
if (!target) return null
this._children = this._children.filter((child) => child !== target)
this.changeState(target, 'removed', callback)
target.master.remove()
return target
}
realRemoveChild = (element: HTMLElement) => {
element
}
realInsertBefore = (element: HTMLElement, reference: HTMLElement) => {
element.style.order = reference.style.order
this.container.insertBefore(element, reference)
}
realInsertAfter = (element: HTMLElement, reference: HTMLElement) => {
element.style.order = reference.style.order
if (reference.nextSibling) {
this.container.insertBefore(element, reference.nextElementSibling)
} else {
this.container.appendChild(element)
}
return element
}
/**
*
* @param mode record为根据记录的order归位current为根据所在位置归位
*/
synchronise(mode: 'record' | 'current' = 'current') {
for (const child of this._children) {
if (mode == 'current') {
child.master.style.order = String(child.order)
} else if (+child.master.style.order !== child.order) {
const insertedMaster =
this.container.children[+child.master.style.order]
if (insertedMaster) {
this.container.insertBefore(child.master, insertedMaster)
}
}
child.synchroniseContainer()
}
this.reorderChild()
if (this._children.length) {
this._gridSize = this._children[0].master.offsetWidth
}
}
reorderChild() {
let children: DockChild[] = []
let _children = [...this._children]
const childrenElements = [...this.container.children]
for (const childElement of childrenElements) {
let child!: DockChild
_children = _children.filter((item) => {
if (item.master == childElement) {
child = item
return false
}
return true
})
children.push(child)
}
this._children = children
}
getChildByElement = (element: HTMLElement) => {
if (!element) return undefined
let children = [...this._children]
for (const child of children) {
if (
child._element === element ||
child.master === element ||
child.container === element
) {
return child
}
}
return undefined
}
dropPosition: 'outter' | 'inner' = 'inner'
handleEvent(event: TouchEvent) {
switch (event.type) {
case 'touchstart':
case 'mousedown':
if (this._dnd.active || this._dnd.timeout) {
break
}
if (event instanceof MouseEvent) {
this._dnd.start.pageX = event.pageX
this._dnd.start.pageY = event.pageY
this._dnd.start.clientX = event.clientX
this._dnd.start.clientY = event.clientY
} else if (event instanceof TouchEvent) {
this._dnd.start.pageX = event.touches[0].pageX
this._dnd.start.pageY = event.touches[0].pageY
this._dnd.start.clientX = event.touches[0].clientX
this._dnd.start.clientY = event.touches[0].clientY
}
this._dnd.last.pageX = this._dnd.start.pageX
this._dnd.last.pageY = this._dnd.start.pageY
this._dnd.last.clientX = this._dnd.start.clientX
this._dnd.last.clientY = this._dnd.start.clientY
this._dnd.last.timeStamp = event.timeStamp
let target = event.target as HTMLElement //gaia-app-icon
// Find the child
let children = [...this._children]
for (let child of children) {
if (
child.master === target ||
child.master.compareDocumentPosition(target) & 16
) {
this._dnd.child = child
break
}
}
if (!this._dnd.child) {
return
}
if (this._dnd.delay > 0) {
this._dnd.timeout = window.setTimeout(() => {
this._dnd.timeout = undefined
this.startDrag()
}, this._dnd.delay)
} else {
this.startDrag()
}
break
case 'touchmove':
case 'mousemove':
let pageX: number, pageY: number, clientX, clientY
if (event instanceof MouseEvent) {
pageX = event.pageX
pageY = event.pageY
clientX = event.clientX
clientY = event.clientY
} else {
pageX = (event as TouchEvent).touches[0].pageX
pageY = (event as TouchEvent).touches[0].pageY
clientX = (event as TouchEvent).touches[0].clientX
clientY = (event as TouchEvent).touches[0].clientY
}
this.distance = pageX - this._dnd.last.pageX
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()
}
if (this._dnd.active) {
const centerX =
this._dnd.center.x + (this._dnd.last.pageX - this._dnd.start.pageX)
const centerY =
this._dnd.center.y + (this._dnd.last.pageY - this._dnd.start.pageY)
const gridHeight = this._dnd.child.master.offsetHeight
const gridWidth = this._dnd.child.master.offsetWidth
if (centerY < this.offsetTop) {
this.dropPosition = 'outter'
this.dispatchEvent(
new CustomEvent('out-of-dock', {
detail: {
target: this._dnd.child.element,
centerX,
centerY,
gridHeight,
gridWidth,
},
composed: true,
})
)
} else if (
this.dropPosition == 'outter' &&
centerY > this.offsetTop
) {
this.dropPosition = 'inner'
this.dispatchEvent(
new CustomEvent('drag-return-dock', {
detail: this._dnd.child.element,
composed: true,
})
)
}
}
break
case 'touchcancel':
this.cancelDrag()
break
case 'touchend':
case 'mouseup':
if (this._dnd.active) {
event.preventDefault()
}
this.endDrag()
break
case 'contextmenu':
if (this._dnd.active || this._dnd.timeout) {
event.stopImmediatePropagation()
}
break
}
}
get sortMode() {
return this._sortMode
}
set sortMode(value) {
if (value) {
this._dnd.delay = 0
} else {
this._dnd.delay = DEFAULT_DND_TIMEOUT
}
this._sortMode = value
}
/**
* dock dock
* @param info
* @returns
*/
dragIn = (info: {
element: HTMLElement | DockChild
centerX: number
centerY: number
gridHeight: number
gridWidth: number
}) => {
const {element, centerX, centerY} = info
const dropChild = this.getChildFromPoint(centerX, centerY)
let child =
element instanceof DockChild ? element : this.getChildByElement(element)
if (!child) {
this._dragInElement = element as HTMLElement
this._dragChild = new DockChild(element as HTMLElement, this)
this._dragChild.container.classList.add('dragging')
this._children.push(this._dragChild)
child = this._dragChild
}
child.container.style.transform =
'translate(' +
(centerX - this._gridSize / 2) +
'px, ' +
(centerY - this._gridSize / 2) +
'px)'
if (!dropChild) {
return false
}
if (dropChild == this._dragChild) {
} else if (dropChild instanceof DockChild) {
if (centerX < dropChild.center.x) {
this.realInsertBefore(this._dragChild?.master!, dropChild.master)
} else {
this.realInsertAfter(this._dragChild?.master!, dropChild.master)
}
} else if (dropChild === this.container) {
if (this._children.length && this._children[0].center.x > centerX) {
if (this.container.firstElementChild == this._dragChild!.master)
return true
this.realInsertBefore(
this._dragChild?.master!,
this._children[0].master
)
} else {
if (this.container.lastElementChild == this._dragChild!.master)
return true
this._dragChild!.order = this._children.length
this.container.appendChild(this._dragChild?.master!)
}
}
this.synchronise()
return true
}
/**
*
* @param element element
* @returns
*/
dragOut = (element: HTMLElement) => {
let child: DockChild | undefined
if (this._dragInElement == element) {
child = this._dragChild
this._dragChild = undefined
this._dragInElement = undefined
} else {
child = this.getChildByElement(element)
}
if (child) {
child.master.remove()
this._children = this._children.filter((item) => item !== child)
this.synchronise()
return true
}
return false
}
startDrag = () => {
this.dataset.dragging = 'true'
const child = this._dnd.child
this._dragChild = this._dnd.child
this._dnd.active = true
this._dragChild?.container.classList.add('dragging')
this._dnd.start.translateX = child.master.offsetLeft
this._dnd.start.translateY = child.master.offsetTop
this._dnd.center.x = child._lastMasterLeft + child.master.offsetWidth / 2
this._dnd.center.y = child._lastMasterTop + child.master.offsetHeight / 2
if (
!this.dispatchEvent(
new CustomEvent('dock-drag-start', {
cancelable: true,
detail: {
target: child.element,
pageX: this._dnd.start.pageX,
pageY: this._dnd.start.pageY,
clientX: this._dnd.start.clientX,
clientY: this._dnd.start.clientY,
},
composed: true,
})
)
) {
return
}
this._dnd.active = true
this._dnd.child.container.classList.add('dragging')
}
continueDrag() {
if (!this._dnd.active) {
return
}
let left =
(this._dnd.start.translateX as number) +
(this._dnd.last.pageX - this._dnd.start.pageX)
let top =
(this._dnd.start.translateY as number) +
(this._dnd.last.pageY - this._dnd.start.pageY)
this._dnd.left = left
this._dnd.top = top
if (this._dnd.moveTimeout === undefined) {
let delay = Math.max(
0,
DND_MOVE_THROTTLE -
(this._dnd.last.timeStamp - this._dnd.lastMoveEventTime)
)
this._dnd.moveTimeout = window.setTimeout(() => {
this._dnd.moveTimeout = undefined
this._dnd.lastMoveEventTime = this._dnd.last.timeStamp
this.dispatchEvent(
new CustomEvent('dock-drag-move', {
detail: {
target: this._dnd.child.element,
pageX: this._dnd.last.pageX,
pageY: this._dnd.last.pageY,
clientX: this._dnd.last.clientX,
clientY: this._dnd.last.clientY,
},
composed: true,
})
)
}, delay)
}
this.dragIn({
element: this._dnd.child,
centerX:
this._dnd.center.x + (this._dnd.last.pageX - this._dnd.start.pageX),
centerY:
this._dnd.center.y + (this._dnd.last.pageY - this._dnd.start.pageY),
gridHeight: this._dnd.child.master.offsetHeight,
gridWidth: this._dnd.child.master.offsetWidth,
})
}
endDrag = () => {
if (this._dnd.active) {
const centerX =
this._dnd.center.x + (this._dnd.last.pageX - this._dnd.start.pageX)
const centerY =
this._dnd.center.y + (this._dnd.last.pageY - this._dnd.start.pageY)
const gridHeight = this._dnd.child.master.offsetHeight
const gridWidth = this._dnd.child.master.offsetWidth
this.dispatchEvent(
new CustomEvent('dock-drag-end', {
detail: {
target: this._dnd.child.element,
centerX,
centerY,
gridHeight,
gridWidth,
},
composed: true,
})
)
}
this.cancelDrag()
}
cancelDrag = () => {
this.dataset.dragging = 'false'
if (this._dnd.active) {
this._dnd.active = false
this._dnd.child.container.classList.remove('dragging')
}
this.synchronise()
}
/**
*
*/
getElementInfo = (element: HTMLElement) => {
element
}
/**
*
*/
getChildFromPoint = (x: number, y: number) => {
let _children = [...this._children]
let target
if (y > this._containerOffset.top && y < this._containerOffset.top + 140) {
target = this.container
for (const child of _children) {
if (
child.master.parentElement && // 此处防止用户操作过快导致图标丢失问题
x > (child._lastMasterLeft ?? child.master.offsetLeft) &&
x <
(child._lastMasterLeft ?? child.master.offsetLeft) + this._gridSize
) {
target = child
break
}
}
}
return target
}
protected firstUpdated(): void {
this.container.addEventListener('touchstart', this)
this.container.addEventListener('click', this)
this.container.addEventListener('touchmove', this)
this.container.addEventListener('touchend', this)
this.container.addEventListener('touchcancel', this)
this.resize()
}
resize() {
this._containerOffset.top = this.container.offsetTop
this._containerOffset.left = this.container.offsetLeft
}
changeState(
child: DockChild,
state: 'added' | 'removed',
callback?: Function
) {
// Check that the child is still attached to this parent (can happen if
// the child is removed while frozen).
if (
(child.master.parentElement as HTMLElement).parentNode !== this.shadowRoot
) {
return
}
// Check for a redundant state change.
if (child.container.classList.contains(state)) {
return
}
let animStart = (e: AnimationEvent) => {
if (!e.animationName.endsWith(state)) {
return
}
child.container.removeEventListener('animationstart', animStart)
window.clearTimeout(child[state])
delete child[state]
// let self = this;
child.container.addEventListener('animationend', function animEnd() {
child.container.removeEventListener('animationend', animEnd)
child.container.classList.remove(state)
if (callback) {
callback()
}
})
}
child.container.addEventListener('animationstart', animStart)
child.container.classList.add(state)
child[state] = window.window.setTimeout(() => {
delete child[state]
child.container.removeEventListener('animationstart', animStart)
child.container.classList.remove(state)
if (callback) {
callback()
}
}, STATE_CHANGE_TIMEOUT)
}
protected render() {
return html`
<div id="container"></div>
`
}
static styles?: CSSResultGroup | undefined = [
customStyle,
css`
:host {
// position: relative;
display: flex;
flex: 1;
margin-bottom: var(--dock-margin-bottom);
width: 100%;
height: var(--dock-container-height);
}
#container {
display: flex;
justify-content: center;
margin: auto auto 0;
min-width: var(--dock-min-width, 100%);
max-width: 100%;
height: var(--dock-container-height);
}
.dock-child-master {
max-width: var(--dock-grid-width, 92px);
max-height: var(--dock-grid-width, 92px);
flex: 1;
}
.dock-child-container {
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: var(--icon-size);
height: var(--icon-size);
}
.dock-child-container:not(.dragging):not(.added) {
transition: transform 0.2s;
}
.dock-child-container.dragging {
z-index: 1;
}
`,
]
}
declare global {
interface HTMLElementTagNameMap {
'star-dock': StarDock
}
}

View File

@ -0,0 +1,17 @@
import {css} from 'lit'
/**
* dock
*/
export default css`
:host {
/** dock 与屏幕底部距离 */
--dock-margin-bottom: var(--dock-bottom, 30px);
/** dock 最小宽度 */
// --dock-min-width: 760px;
--dock-min-width: 100%;
/** dock 高度 */
--dock-container-height: var(--dock-height, 140px);
/** dock 图标宽度 */
--dock-grid-width: var(--icon-size, 100px);
}
`

View File

@ -4,6 +4,8 @@ export default css`
:host {
position: relative;
display: block;
margin-top: var(--container-margin-top);
margin-left: var(--container-margin-left);
width: 100%;
height: 100%;
@ -29,13 +31,26 @@ export default css`
::slotted(.gaia-container-page) {
display: grid;
grid-template-columns: repeat(4, 25%);
grid-template-rows: repeat(6, 16.66%);
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-auto-flow: row dense;
grid-auto-rows: 33%;
height: 100%;
transform: opacity 0.1s;
width: calc(100% - var(--container-margin-left) * 2);
}
::slotted(.gaia-container-page.shadow) {
position: absolute;
grid-template-rows: repeat(
var(--columns, 4),
calc(100% / var(--columns, 4))
);
grid-template-columns: repeat(var(--rows, 6), calc(100% / var(--rows, 6)));
z-index: -1;
}
::slotted(.gaia-container-child) {

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,14 @@ export enum STATUS {
OPEN_FORDER = 1 << 5, // 开启文件夹状态
}
/**
*
*/
export enum DragInType {
PAGES,
COMPONENT,
}
export interface DragAndDrop {
// Whether drag-and-drop is enabled
enabled: boolean
@ -86,15 +94,21 @@ export interface DragAndDrop {
// 最后一个悬浮经过的元素
lastDropChild: any
pagination: number
pagination: number | undefined
top: number
left: number
// 中心坐标
// 定位坐标
gridPosition: {
x: number
y: number
}
// 中心坐标
center: {
x: number
y: number
}
}
export interface Container extends HTMLElement {

View File

@ -333,7 +333,7 @@ export default class ExchangeStrategy {
if (gridId === undefined) {
ergodic(-1 * direction)
}
return gridId !== undefined ? [[gridId]] : gridId
return gridId !== undefined ? [[gridId]] : undefined
}
const place = () => {
@ -522,12 +522,14 @@ export default class ExchangeStrategy {
gridId: number,
pagination: number,
mode: 'place' | 'move',
direction: [boolean, boolean]
direction: [boolean, boolean],
forceDrop: boolean
): {
canPlace: boolean
placedRecorder?: PlacedRecorder
childCoordinate?: GaiaContainer['childCoordinate']
} {
forceDrop
const {column: mColumn} = this.manager
// 子节点右下角单元格所在的网格ID
const edge_bottom_right =
@ -567,6 +569,7 @@ export default class ExchangeStrategy {
// 放置该子节点
this.placeChild(child, gridId, pagination)
this.placedRecorder[pagination] = {[gridId]: child}
// 尝试移动并放置被挤出去的子节点
try {

View File

@ -1,5 +1,5 @@
import GaiaContainer from './container'
import {Coordinate} from './contianer-interface'
import {Coordinate, DragInType} from './contianer-interface'
/**
* Grid
*
@ -23,7 +23,7 @@ const defaultCoordinate: Coordinate = {
type anchorType = 'recorder' | 'current'
export default class GaiaContainerChild {
_element: HTMLElement | null
_element: HTMLElement | undefined
_container: HTMLElement | null = null
_master: HTMLElement | null = null
isWidget: boolean
@ -53,9 +53,11 @@ export default class GaiaContainerChild {
curGridId: number = -1
// 中心位置
center: {x: number; y: number} = {x: 0, y: 0}
// 影子容器,用于判断旋转屏幕后能否容纳该组件
_shadowContainer!: HTMLElement
constructor(
element: HTMLElement | null,
element: HTMLElement | undefined,
row: number = 1,
column: number = 1,
anchorCoordinate: Coordinate | undefined,
@ -106,6 +108,11 @@ export default class GaiaContainerChild {
}
}
if (this.manager.dragInType == DragInType.COMPONENT) {
// 跨组件放置节点时,该节点所在的页码应为当前页码
return this.manager.pagination
}
throw new Error(`Can not find pagination`)
}
@ -124,7 +131,14 @@ export default class GaiaContainerChild {
}
get element() {
return this._element
return this._element!
}
set element(node: HTMLElement) {
if (this._element) {
this.container.replaceChild(node, this._element)
}
this._element = node
}
get isStatic() {
@ -238,6 +252,16 @@ export default class GaiaContainerChild {
return this._container
}
get shadowContainer() {
if (!this._shadowContainer) {
const container = document.createElement('div')
container.style.gridRowStart = `span ${this.row}`
container.style.gridColumnStart = `span ${this.column}`
this._shadowContainer = container
}
return this._shadowContainer
}
changeSize(container = this.container) {
const {height, width} = this.master.getBoundingClientRect()
container.style.height = height + 'px'
@ -331,7 +355,16 @@ export default class GaiaContainerChild {
? this.manager.getGridIdByCoordinate(left, top, this.pagination)
: this.manager.getFolderGridIdByCoordinate(left, top, this.pagination)
if (gridId !== this.curGridId) {
this.manager.recordCoordinate(this, this.pagination, gridId)
// this.manager.recordCoordinate(this, this.pagination, gridId)
if (!this.manager.recordCoordinate(this, this.pagination, gridId)) {
/* 未能成功记录,记录位置已有其他子节点,需要清空位置记录并重新归位 */
this.loosen()
setTimeout(() => {
this.manager.freshChildCoordinate()
this.manager.synchronise()
}, 10)
return false
}
this.preGridId = this.curGridId
this.curGridId = gridId
}
@ -341,9 +374,11 @@ export default class GaiaContainerChild {
this._lastMasterLeft = left
this._lastElementLeft = this.element?.offsetLeft!
this._lastElementHeight = this.element?.offsetHeight!
!isActive &&
!this.container.classList.contains('dragging') &&
(container.style.transform = 'translate(' + left + 'px, ' + top + 'px)')
}
!isActive &&
!this.container.classList.contains('dragging') &&
(container.style.transform = 'translate(' + left + 'px, ' + top + 'px)')
return true
}
}

View File

@ -32,7 +32,7 @@ export default class GaiaContainerFolder extends GaiaContainerChild {
gridWidth: number = 0
constructor(manager: GaiaContainer, name?: string) {
super(null, 1, 1, undefined, manager)
super(undefined, 1, 1, undefined, manager)
this.name = this.checkAndGetFolderName(name)
this._id = `folder-${new Date().getTime()}`
this.init()
@ -56,7 +56,9 @@ export default class GaiaContainerFolder extends GaiaContainerChild {
// NOTE: 避免同步 synchroniseContainer 产生不必要的动画
this.container.style.setProperty('transition', 'unset')
this.synchroniseContainer()
setTimeout(() => this.container.style.removeProperty('transition'))
window.setTimeout(() =>
this.container.style.removeProperty('transition')
)
},
{once: true}
)
@ -254,7 +256,7 @@ export default class GaiaContainerFolder extends GaiaContainerChild {
}
this.container.style.setProperty('--folder-element-left', '0px')
this.container.style.setProperty('--folder-element-top', '0px')
this.openTimer = setTimeout(() => {
this.openTimer = window.setTimeout(() => {
this.master.classList.remove('openning')
this.master.classList.add('opened')
let element = this.suspendElement.shift()
@ -343,7 +345,7 @@ export default class GaiaContainerFolder extends GaiaContainerChild {
this.master.classList.add('destroying') // 文件夹背景缩小消失
// nextTick用以配合 originXXX 形成动画
setTimeout(() => {
window.setTimeout(() => {
this.showIconsSubtitle(this._children[0].element!)
this.element.style.height = targetHeight + 'px'
this.element.style.width = targetWidth + 'px'
@ -367,7 +369,9 @@ export default class GaiaContainerFolder extends GaiaContainerChild {
})
)
setTimeout(() => childContainer.style.removeProperty('transition'))
window.setTimeout(() =>
childContainer.style.removeProperty('transition')
)
},
{once: true}
)
@ -375,6 +379,7 @@ export default class GaiaContainerFolder extends GaiaContainerChild {
handleEvent(evt: TouchEvent) {
switch (evt.type) {
// @ts-ignore
case 'touchend':
if (this._status && evt.target === this.container) {
this.close()
@ -457,7 +462,7 @@ export default class GaiaContainerFolder extends GaiaContainerChild {
position: unset !important;
}
::slotted(.folder.openning) .gaia-container-folder {
position: raletive;
position: relative;
}
::slotted(.folder.initializing) .gaia-container-child {
position: unset !important;

View File

@ -5,6 +5,7 @@ class GaiaContainerPage {
// 等待被移除的页面,仅在编辑、拖拽时出现,若结束前两种状态时仍然没有子节点,则删除
_suspending: HTMLElement | null = null
_manager: GaiaContainer
_shadowPagesMap: WeakMap<HTMLElement, HTMLElement> = new WeakMap()
observerCallback: MutationCallback
constructor(manager: GaiaContainer) {
this._manager = manager
@ -18,7 +19,10 @@ class GaiaContainerPage {
this.observerCallback = (mutations: MutationRecord[]) => {
for (const mutation of mutations) {
if (!(mutation.target as HTMLElement).children.length) {
if (
mutation.removedNodes.length &&
!(mutation.target as HTMLElement).children.length
) {
const page = mutation.target as HTMLElement
const container = page.parentElement as any
@ -37,6 +41,7 @@ class GaiaContainerPage {
} else {
this.deletePage(page)
}
this._manager.resetView('touchend')
}
container && callback()
}
@ -60,12 +65,29 @@ class GaiaContainerPage {
const pagination = `${this._pages.length}`
div.className = `gaia-container-page`
div.style.setProperty('--pagination', pagination)
// 影子页面,用于检测旋转屏幕后能否仍容纳当前页面的子节点
const shadowPage = div.cloneNode() as HTMLElement
shadowPage.classList.add('shadow')
this._shadowPagesMap.set(div, shadowPage)
this._pages.push(div)
div.dataset.page = `${this._pages.length - 1}`
this.observe(div)
this._manager.childCoordinate[this._pages.length - 1] = {}
return div
this._manager.dispatchEvent(
new CustomEvent('page-change', {
detail: {
addIndex: this._pages.indexOf(div),
},
composed: true,
})
)
return {
page: div,
shadowPage,
}
}
get editMode() {
@ -90,6 +112,14 @@ class GaiaContainerPage {
return
}
delete this._pages[index]
this._manager.dispatchEvent(
new CustomEvent('page-change', {
detail: {
deleteIndex: index,
},
composed: true,
})
)
if (index > -1) {
page?.remove?.()
let flag = false
@ -101,7 +131,7 @@ class GaiaContainerPage {
}
if (i == index) flag = true
coordinates[i] = this._manager.childCoordinate[i - +flag]
return
return i !== index
})
this._manager.childCoordinate = coordinates
}
@ -117,6 +147,10 @@ class GaiaContainerPage {
callback(this._pages[i], i, this._pages)
}
}
indexOf = (page: HTMLElement) => {
return this._pages.indexOf(page)
}
}
export default GaiaContainerPage

View File

@ -53,7 +53,7 @@ class GestureManager {
// TBD暂停翻页动画再划动手指时会出现速度计算异常
if (Math.abs(velocity) > this.velocity) {
clearTimeout(this.swipeTimer)
this.swipeTimer = setTimeout(
this.swipeTimer = window.setTimeout(
() => (this.swipeTimer = undefined),
this.duration
)

View File

@ -2,8 +2,5 @@ import {css} from 'lit'
export default css`
:host {
/* 图标大小 */
--icon-size: 108px;
--icon-size: 50%;
}
`

View File

@ -0,0 +1 @@
export * from './indicator-page-point.js'

View File

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

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts"]
}

View File

@ -0,0 +1 @@
export * from './li.js'

View File

@ -1,7 +1,15 @@
import {html, css, LitElement, HTMLTemplateResult, nothing} from 'lit'
import {
html,
css,
CSSResultArray,
LitElement,
HTMLTemplateResult,
nothing,
} from 'lit'
import {customElement, property} from 'lit/decorators.js'
import '../bubble/bubble'
import '../switch/switch'
import {baseStyles} from '../base/base-style.js'
import '../bubble/bubble.js'
import '../switch/switch.js'
export enum LiType {
BASE = 'base',
@ -277,92 +285,98 @@ export class StarLi extends LitElement {
return nothing
}
}
static styles = css`
:host {
width: inherit;
}
li {
width: inherit;
display: flex;
min-height: var(--li-base-height);
line-height: var(--li-base-height);
padding-inline-start: var(--li-left-padding);
padding-inline-end: var(
--li-right-padding
); /* right-arrow须与最右侧文字对齐 */
}
/* right-arrow须与最右侧文字对齐 */
/* li.hashref {
public static override get styles(): CSSResultArray {
return [
baseStyles,
css`
:host {
width: inherit;
border-radius: var(--base-border-radius);
}
li {
width: inherit;
display: flex;
border-radius: var(--base-border-radius);
min-height: var(--li-base-height);
line-height: var(--li-base-height);
padding-inline-start: var(--li-left-padding);
padding-inline-end: var(
--li-right-padding
); /* right-arrow须与最右侧文字对齐 */
}
/* right-arrow须与最右侧文字对齐 */
/* li.hashref {
padding-inline-end: 0;
} */
a {
display: flex;
text-decoration: none;
color: #000;
width: 100%;
}
a.hasicon::before,
a.hashref::after {
flex: 1;
font-size: 25px;
min-width: 25px;
max-width: 25px;
font-family: 'gaia-icons';
}
a.hasicon::before {
color: #657073;
text-align: left;
content: attr(data-icon);
padding-inline-end: var(--li-right-padding);
}
a.hashref::after {
color: #a5acae;
text-align: right;
content: 'right-light';
}
input {
width: 100vw;
max-width: 500px;
padding: 0;
border: 0;
height: inherit;
outline: none;
box-sizing: border-box;
vertical-align: top;
border-radius: 6px;
background-color: transparent;
font-size: 16px;
}
span.infokey,
span.label {
flex: 1;
text-align: left;
}
span.infovalue {
/* flex: 1; */ /* 利用自动挤压 */
text-align: right;
color: #aaa;
}
span.onlyread {
color: #aaa;
font-size: clamp(0.55rem, 2.3vw, 1.2rem);
}
span.text {
flex: 8;
text-align: left;
}
span.bubble {
flex: 1;
height: inherit;
background-color: red;
}
span.next {
flex: 1;
text-align: right;
color: #aaa;
}
`
a {
display: flex;
text-decoration: none;
color: #000;
width: 100%;
}
a.hasicon::before,
a.hashref::after {
flex: 1;
font-size: 25px;
min-width: 25px;
max-width: 25px;
font-family: 'gaia-icons';
}
a.hasicon::before {
color: #657073;
text-align: left;
content: attr(data-icon);
padding-inline-end: var(--li-right-padding);
}
a.hashref::after {
color: #a5acae;
text-align: right;
content: 'right-light';
}
input {
width: 100vw;
max-width: 500px;
padding: 0;
border: 0;
height: inherit;
outline: none;
box-sizing: border-box;
vertical-align: top;
border-radius: 6px;
background-color: transparent;
font-size: 16px;
}
span.infokey,
span.label {
flex: 1;
text-align: left;
}
span.infovalue {
/* flex: 1; */ /* 利用自动挤压 */
text-align: right;
color: #aaa;
}
span.onlyread {
color: #aaa;
font-size: clamp(0.55rem, 2.3vw, 1.2rem);
}
span.text {
flex: 8;
text-align: left;
}
span.bubble {
flex: 1;
height: inherit;
background-color: red;
}
span.next {
flex: 1;
text-align: right;
color: #aaa;
}
`,
]
}
}
declare global {

View File

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

View File

@ -0,0 +1,13 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": [
"*.ts",
"../base/base-style.js",
"../bubble/bubble.js",
"../switch/switch.js"
]
}

View File

@ -3,28 +3,43 @@
## 介绍
### overflowmenu溢出菜单。
现有overflowmenu包含一个绑定点击事件的star-button按钮通过在响应函数closeoverflowmenu控制溢出菜单内容的显示与隐藏。
后续改进结合active-overlay组件通过调用overlay-stack类控制溢出菜单的显示与隐藏
## 新需求(主页面要求——罗 9.5
1. 外部颜色控制(思路:使用自定义 css 样式,如: --test-colorXXX p{color --test-color},通过修改自定义 css 样式的值达到从外部修改组件颜色)
2. 弹出菜单时的越界判断,包括主、副屏切换时的图标定位以及旋转屏幕时的定位
思路:
1首先获取 button 在屏幕显示的 left、right、top 和 bottom 值以及 menu 的 width 和 height
2对于右侧边界right >= width ? true 则 menu 的 left = button 的 left : false 则 menu 的 right = button 的 right
3对于下边界bottom >= height ? true 则 menu 的 top = button 的 bottom false 则 menu 的 bottom = button 的 top
3. 外部控制接口,事件还是属性(暂定)
4. 弹出的菜单绑定在父节点上以供调用,减少重复使用(思路:后续通过 overlay 组件实现)
## 问题(9.6)
1. 首次点击最右侧的按钮是获取到的菜单宽度和高度与实际不符:(该问题已消失,但不知道为何消失)
2. 点击空白处无法关闭菜单栏(解决方法:将点击事件绑定在父容器中)
## 新要求:(9.7)
1将不需要修改的“var”变量声明变成“const”(已修改)
2变量命名要直观且有解释已修改变量命名规范并添加对应注释
3点击一个按钮后其余按钮应关闭方法同1
4可以将 slot 增加名称从而将 div 以删除
5定位方式修改为相对定位将将 fixed 改为 relative达到适应效果
6控制菜单栏宽度菜单栏中 star-ul 中的 ul 标签负责扩充大小,修改其 width 值
```typescript
//现有方案
closeoverflowmenu(e: any) {
// 获取点击事件所在的标签名字
const tagName = e.target.tagName.toLowerCase()
// 判断是否点击的star-overflowmenu标签
if (tagName == 'star-overflowmenu') {
this.state++
}
// 如果点在空白处则关闭菜单
if (tagName != 'star-overflowmenu') {
// 获取所有的star-overflowmenu
var menulist = this.shadowRoot!.querySelectorAll('star-overflowmenu')
for (var i = 0; i < menulist.length; i++) {
menulist[i].open = true
var menu = menulist[i].renderRoot.querySelector(
'#menuitem'
) as HTMLElement
menu.style.display = 'none'
this.state = 0
}
}
// 通过state判断是否已有展开的菜单若已有则关闭菜单
if (this.state > 1) {
var menulist = this.shadowRoot!.querySelectorAll('star-overflowmenu')
for (var i = 0; i < menulist.length; i++) {
menulist[i].open = true
var menu = menulist[i].renderRoot.querySelector(
'#menuitem'
) as HTMLElement
menu.style.display = 'none'
this.state = 0
}
}
}
```

View File

@ -0,0 +1 @@
export * from './overflowmenu.js'

View File

@ -1,7 +1,7 @@
import {LitElement, html, HTMLTemplateResult, CSSResultArray} from 'lit'
import {customElement, property, queryAssignedElements} from 'lit/decorators.js'
import '../button/button'
import {sharedStyles} from './overflowmenustyle'
import '../button/button.js'
import {sharedStyles} from './overflowmenustyle.js'
@customElement('star-overflowmenu')
export class StarOverflowMenu extends LitElement {

View File

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

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts", "../button/button.js"]
}

View File

@ -1,5 +1,76 @@
# 全局 overlay
# Adobe SP组件库——overlay
## 类型包括:
介绍Adobe的overlay组件是一个可以用于全局调用的叠加层。
- 置于底部的 overlay内可填充 ul
## 交互类型
- type TriggerInteractions =
| 'click'
| 'custom',
| 'hover'
| 'modal'
overlay可有多种触发类型各类型对应情况如下
>click将打开一个overlay该overlay将在下一次单击时立即关闭该overlay不在overlay内的元素上。
>custom允许从外部对显示流程进行定制。
>hover一旦指针离开overlay层所连接的触发器就会关闭overlay层。
>modal模态形式将仅在其内容中捕获标签顺序。
## overlay中主要用到的方法
```typescript
Overlay.open(
(owner: HTMLElement),
(interaction: TriggerInteractions),
(overlayElement: HTMLElement),
(options: OverlayOptions) //
);
```
Overlay.open() 是一个异步方法它返回一个用于关闭overlay的函数。
>owner:HTMLElement 代表要打开叠加层的元素
>interaction:TriggerInteractions overlay的触发交互类型
>overlayElement:HTMLElement 将要放入overlay中的element元素
>options:OverlayOptions overlay定制选项
## 作用
- 置于底部的overlay内可填充ul,其他组件可通过调用overlay显示信息
# 组件交互
- 可与button、menu、popover、picker等联合使用
# overlay场景、应有接口
- 弹出框、溢出菜单、picker、警告框、主页面应用图标长按显示信息框等
- 接口position显示位置top、right、left、bottom、interaction type交互方式click、custom、hover、modal、replace、overlayoptions显示配置delay延迟出现overlayplacement自定义位置offset偏移量
# overlay包含内容
> overlay.ts工厂类包含异步函数open()其通过调用open()和close()函数实现overlay的打开和关闭
>> open(OverlayOptions)其中OverlayOptions为overlay的一些配置参数open应有方法两个主要方法updatePosition()和reparentChildren()
>>> updatePosition()方法实现open过程的overlay显示位置定位
>>> reparentChildren()方法实现组件中content和overlay显示位置的转换
>> close()关闭overlay主要分为两步关闭overlay将overlay的content替换回原位置
>>> 移除overlayremoveoverlay节点
>>> reparentChildren替换元素
# overlay使用
- 首先获取响应点击事件的节点元素:
```typescript
const targetNode = e.target as HTMLElement
```
- 获取被点击节点父节点:
```typescript
const originalNode = targetNode?.parentElement as HTMLElement
```
- 获取要显示在overlay中的内容
```typescript
const content = targetNode?.nextElementSibling as HTMLElement
```
- 构造响应函数时通过调用overlayStack中的openOverlay方法创建activeoverlauy
```typescript
this.overlayStack.openOverlay(originalNode, targetNode, content)
```

View File

@ -0,0 +1,119 @@
import {LitElement, html, TemplateResult} from 'lit'
import {customElement, property} from 'lit/decorators.js'
import {OverlayOpenDetail, TriggerInteractions} from './overlay-types'
@customElement('star-activeoverlay')
export class ActiveOverlay extends LitElement {
// 根节点(占位符所表示的元素的父节点)
public root?: HTMLElement
// 被点击的节点
public targetNode?: HTMLElement
// 被替换后用以保存要复原的节点集合
public restoreContent?: HTMLElement
// 显示位置策略
@property({reflect: true})
public placement?: String
public constructor() {
super()
}
// 调用初始化函数
private open(openDetail: OverlayOpenDetail): void {
this.extractDetail(openDetail)
}
// 初始化函数
private extractDetail(detail: OverlayOpenDetail): void {
this.placement = detail.placement
this.offset = detail.offset
this.skidding = detail.skidding || 0
this.root = detail.root
}
private stealOverlayContent(element: HTMLElement) {}
// 位置更新函数
public updatePosition = () => {
// 设置最大显示宽度和高度
const availableWidth = 200
const availableHeight = 200
// 显示内容content宽度和高度——用于越界后的定位计算右下、右、下
const contentwidth = this.restoreContent?.offsetWidth as number
const contentheight = this.restoreContent?.offsetHeight as number
// 获取网页宽度——用于越界判断
const bodywidth = document.documentElement.clientWidth
const bodyheight = document.documentElement.clientHeight
// 被点击的节点
const targetnode = this.targetNode as HTMLElement
// 获取被点击节点位置——用于越界判断和定位
const targetNodePosition = targetnode.getBoundingClientRect()
const targettop = Number(targetNodePosition?.top)
const targetbottom = Number(targetNodePosition?.bottom)
const targetleft = Number(targetNodePosition?.left)
const targetright = Number(targetNodePosition?.right)
// 设置样式
this.style.position = 'relative'
this.style.zIndex = '1'
this.style.maxWidth = availableWidth + 'px'
this.style.maxHeight = availableHeight + 'px'
// 边界判断
const rightline = targetright + contentwidth > bodywidth ? true : false // 右侧越界条件
const bottomline =
targetbottom + availableHeight > bodyheight ? true : false //下方越界条件
// 右下角边界
if (rightline && bottomline) {
this.style.left = targetleft - (contentwidth - targetnode.offsetWidth) + 'px'
this.style.top = targettop - targetnode.offsetHeight + 'px'
return
} else if (rightline) {
// 右侧边界
this.style.left = targetleft - (contentwidth - targetnode.offsetWidth) + 'px'
this.style.top = targettop + targetnode.offsetHeight + 'px'
return
} else if (bottomline) {
// 下侧边界
this.style.left = targetleft + 'px'
this.style.top = targettop - contentheight + 'px'
return
} else {
// 正常情况
this.style.left = targetleft + 'px'
this.style.top = targettop + targetnode.offsetHeight + 'px'
return
}
}
private onSlotChange(): void {
this.updatePosition()
}
public render(): TemplateResult {
const content = html`
<div>
<slot @slotchange=${this.onSlotChange}></slot>
</div>
`
return content
}
// 创建overlay
public static create(
root?: HTMLElement,
targetnode?: HTMLElement,
content?: HTMLElement
): ActiveOverlay {
const activeoverlay = new ActiveOverlay()
// 初始化参数
activeoverlay.root = root
activeoverlay.targetNode = targetnode
activeoverlay.restoreContent = content
return activeoverlay
}
}
declare global {
interface HTMLElementTagNameMap {
'star-activeoverlay': ActiveOverlay
}
}

View File

@ -0,0 +1,44 @@
import {ActiveOverlay} from './active-overlay'
export class OverlayStack {
public overlays: ActiveOverlay[] = []
public isOpen: Boolean = false
public openOverlay(root?: HTMLElement, targetnode?: HTMLElement, content?: HTMLElement) {
// 创建activeoverlay对象
const activeOverlay = ActiveOverlay.create(root, targetnode, content)
// 开启状态
this.isOpen = true
// 为overlay添加显示内容
activeOverlay.appendChild(content as HTMLElement)
// 创建注释节点模板——用于替换要展示在overlay中的元素
const placeholderTemplate: Comment = document.createComment(
'placeholder for reparented element'
)
// 占位
activeOverlay.root?.appendChild(placeholderTemplate)
// 将activeoverlay添加到body底部
document.body.append(activeOverlay)
// 将activeoverlay添加到已打开overlay数组中
this.overlays.push(activeOverlay)
}
/**
* closeOverlay
*/
public closeOverlay(): void {
// 提取要关闭的overlay
const closeactiveoverlay = this.overlays.pop() as unknown as ActiveOverlay
// 获取根节点
const srcroot = closeactiveoverlay.root
// 获取注释节点
const placeholder = srcroot?.lastChild as Node
// 获取overlay中的内容
const content = closeactiveoverlay.restoreContent as HTMLElement
// 替换子节点
srcroot?.replaceChild(content, placeholder)
// 从body中移除activeoverlay节点
document.body.removeChild(closeactiveoverlay)
this.isOpen = false
}
}

View File

@ -0,0 +1,58 @@
// 定义overlay各种参数类型、接口
// click用于普通弹窗longpress可用于主界面图标长按显示详情页hover可用于解释框的显示
// custom、inline、replace和modal尚未理解用途暂定
export type TriggerInteractions =
| 'click'
| 'longpress'
| 'hover'
| 'custom'
| 'replace'
| 'inline'
| 'modal'
export type thememode ='light' | 'dark'
// overlay配置信息
export type OverlayOptions = {
root?: HTMLElement
mode?: String
// delayed?: boolean
// placementadobe通过轻量前段工具包floating-ui中的FloatingUIPlacement进行动态定位浮动元素
// 出现位置
placement?: String
offset?: number
// receivesFocus?: 'auto'
// notImmediatelyClosable?: boolean
// abortPromise?: Promise<boolean>
// 为没有元素触发的覆盖提供一个虚拟触发
// virtualTrigger?: VirtualTrigger
}
// export interface OverlayOpenDetail {
// content: HTMLElement;
// contentTip?: HTMLElement;
// delayed: boolean;
// offset: number;
// skidding?: number;
// placement?: Placement;
// receivesFocus?: 'auto';
// virtualTrigger?: VirtualTrigger;
// trigger: HTMLElement;
// root?: HTMLElement;
// interaction: TriggerInteractions;
// theme: ThemeData;
// notImmediatelyClosable?: boolean;
// abortPromise?: Promise<boolean>;
// }
export interface OverlayOpenDetail {
content: HTMLElement // 显示内容
offset: number // 偏移
skidding?: number // 滑动
placement?: String //显示位置
// virtualTrigger?: VirtualTrigger // 虚拟触发
trigger: HTMLElement // 触发
root?: HTMLElement // 根节点
interaction: TriggerInteractions // 交互
}

View File

@ -0,0 +1,83 @@
import { OverlayStack } from './overlay-stack'
import { OverlayOptions, TriggerInteractions } from './overlay-types'
export interface OverlayDisplayQueryDetail {
overlayRootName?: string
overlayRootElement?: HTMLElement
overlayContentTipElement?: HTMLElement
}
export class Overlay {
// 基础属性
private isOpen = false
private overlayElement: HTMLElement
private owner: HTMLElement
private interaction: TriggerInteractions
private static overlayStack = new OverlayStack()
/**
*
* @param owner overlay显示位置的父元素节点
* @param interaction overlay显示的交互类型
* @param overlayElement overlay的节点
*/
constructor(
owner: HTMLElement,
interaction: TriggerInteractions,
overlayElement: HTMLElement
) {
this.owner = owner
this.overlayElement = overlayElement
this.interaction = interaction
}
public static async open(
owner: HTMLElement,
interaction: TriggerInteractions,
overlayElement: HTMLElement,
options: OverlayOptions
): Promise<() => void> {
const overlay = new Overlay(owner, interaction, overlayElement)
await overlay.open(options)
return (): void => {
overlay.close()
}
}
public static update(): void {
// 自定义事件
const overlayUpdateEvent = new CustomEvent('star-update-overlays', {
bubbles: true,
composed: true,
cancelable: true,
})
// 触发事件
document.dispatchEvent(overlayUpdateEvent)
}
public async open({
offset = 0,
placement = 'top',
root,
}: OverlayOptions): Promise<boolean> {
/* c8 ignore next */
if (this.isOpen) return true
await Overlay.overlayStack.openOverlay({
content: this.overlayElement,
offset: offset,
placement: placement,
trigger: this.owner,
interaction: this.interaction,
root,
})
this.isOpen = true
return true
}
// 关闭overlay
public close(): void {
Overlay.overlayStack.closeOverlay(this.overlayElement)
}
}

View File

@ -0,0 +1 @@
export * from './picker.js'

View File

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

View File

@ -2,7 +2,7 @@
import {html, LitElement, CSSResultArray} from 'lit'
import {customElement, property, state} from 'lit/decorators.js'
import {styleMap} from 'lit/directives/style-map.js'
import {sharedStyles} from './picker-styles'
import {sharedStyles} from './picker-styles.js'
interface StarPickerOption {
value: string

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts"]
}

View File

@ -1,28 +1,29 @@
# 提示输入弹窗-Prompt
# star-prompt
参考UI 设计
星光组件--prompt 组件(9 月 12 日)
## 内容排布
# 介绍
- 括号中的内容为可选项
1. 浅色模式
从上到下:
```
标题
(子标题)
输入框
输入状态提示 外部链接<slot>
按钮1 按钮2
```html demo
<star-prompt></star-prompt>
```
特点:
2. 深色模式
- 支持模态模式
- 支持非模态模式
```html demo
<star-prompt deep></star-prompt>
```
## 关联组件
3. 密码模式
- button
- input
- 外部链接 slot
```html demo
<star-prompt password></star-prompt>
```
4. 深色密码模式
```html demo
<star-prompt deep password></star-prompt>
```

View File

@ -0,0 +1 @@
export * from './prompt.js'

View File

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

View File

@ -0,0 +1,272 @@
import {css, CSSResult} from 'lit'
export const sharedStyles: CSSResult = css`
:host {
--deep--color: linear-gradient(101.98deg, #4e5161 1.12%, #363a47 96.75%);
}
.cover {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.popBox {
width: inherit;
-webkit-border-radius: 0.5em;
-moz-border-radius: 0.5em;
border-radius: 0.5em;
text-align: center;
padding: 3%;
background: linear-gradient(
134.78deg,
#f7f5f7 2.34%,
#fafafa 34.11%,
#e1e4f2 100%
);
z-index: 101;
font-family: Microsoft YaHei, Verdana, Arial, Helvetica, sans-serif;
font-size: 15px;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
-o-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
animation: dialogSlipToUP 500ms ease 1 forwards;
}
.title {
text-align: left;
margin-left: 1%;
}
.container {
position: relative;
background-color: transparent;
margin-top: 10%;
}
.input {
width: inherit;
height: 30px;
background-color: #ffffff;
box-shadow: 0 0 0px 1000px white inset;
border: 2px solid #e6e8f5;
border-radius: 6px;
padding-left: 4%;
padding-bottom: 2%;
padding-top: 1.5%;
font-family: Verdana;
font-weight: bold;
font-size: 12px;
color: rgba(38, 38, 38, 0.45);
outline: none;
letter-spacing: 2px;
}
.input:focus {
border: 2px solid #1d98f0;
}
.text {
background-color: red;
}
.eye {
position: absolute;
top: 35%;
right: 5%;
background-color: transparent;
}
.show::before {
content: '';
position: absolute;
left: 80%;
right: 0%;
top: 30%;
bottom: 30%;
}
@keyframes dialogSlipToUP {
0% {
opacity: 0.3;
}
100% {
transform: translate(-50%, -100%);
opacity: 1;
}
}
.location {
text-align: right;
margin-top: 3.5%;
}
.info {
text-align: right;
color: #292929;
font-size: 13px;
opacity: 0.7;
}
.cancel {
font-family: Microsoft YaHei, Verdana, Arial, Helvetica, sans-serif;
font-style: normal;
text-align: center;
color: #292929;
margin-right: 20%;
border-color: transparent;
background-color: transparent;
padding-left: 0;
padding-right: 0;
}
.sure {
font-family: Microsoft YaHei, Verdana, Arial, Helvetica, sans-serif;
font-style: normal;
text-align: center;
color: #1d98f0;
margin-left: 20%;
border-color: transparent;
background-color: transparent;
padding-left: 0;
padding-right: 0;
}
.vertical {
border-color: transparent;
background-color: transparent;
color: #cfd8e8;
}
.drop {
display: none;
}
.group {
margin-top: 20%;
}
.wifi {
line-height: 18.2px;
cursor: pointer;
background: rgba(51, 51, 51, 0.06);
color: #4d4d4d;
text-align: center;
font-weight: 500;
font-size: 14px;
padding: 10px 45px 14px;
margin-right: 0%;
border: none;
border-radius: 18px;
}
.blue {
line-height: 18.2px;
cursor: pointer;
background: #1d98f0;
color: #f0f0f0;
text-align: center;
font-weight: 500;
font-size: 14px;
padding: 10px 45px 14px;
margin-right: 0%;
border: none;
border-radius: 18px;
}
/*深色模式*/
:host([deep]) .popBox {
background: var(--deep--color);
color: #f0f0f0;
}
:host([deep]) .input {
background: rgba(98, 93, 103, 0.4);
box-shadow: 0 0 0px 1000px rgba(98, 93, 103, 0.4) inset;
border: 2px solid #2e3038;
border-radius: 4px;
color: rgba(240, 240, 240, 0.45);
}
:host([deep]) .input:focus {
border: 2px solid #1d98f0;
}
:host([deep]) .cancel {
color: #f0f0f0;
}
:host([deep]) .vertical {
color: #585a66;
}
:host([deep]) .container {
background-color: transparent;
}
:host([deep]) .eye {
background-color: transparent;
}
:host([deep]) .drop {
display: block;
}
:host([deep]) .info {
color: #e0e0e0;
opacity: 0.7;
}
:host([deep]) .wifi {
background: rgba(228, 228, 228, 0.1);
color: #e0e0e0;
}
/*WIFI弹窗*/
:host([wifi]) .popBox {
width: 512px;
height: 700px;
}
:host([wifi]) .title {
width: 150px;
height: 26px;
font-weight: 400;
font-size: 26px;
line-height: 26px;
letter-spacing: 1px;
}
:host([wifi]) .input {
width: 486px;
height: 60.5px;
font-size: 26px;
line-height: 26px;
letter-spacing: 1px;
}
:host([wifi]) .info {
font-weight: 400;
font-size: 24px;
line-height: 26px;
letter-spacing: 1px;
}
:host([wifi]) .sure {
width: 200px;
height: 64px;
left: 272px;
top: 596px;
border-radius: 34px;
font-size: 26px;
font-weight: 400;
line-height: 26px;
}
:host([wifi]) .cancel {
width: 200px;
height: 64px;
left: 48px;
top: 596px;
border-radius: 34px;
font-size: 26px;
font-weight: 400;
line-height: 26px;
}
:host([wifi]) .group {
margin-top: 75%;
}
`

View File

@ -1,19 +1,132 @@
import {html, css, LitElement} from 'lit'
import {customElement, property, state} from 'lit/decorators.js'
import {html, LitElement, CSSResultArray} from 'lit'
import {customElement, property, queryAssignedElements} from 'lit/decorators.js'
import {sharedStyles} from './prompt-styles.js'
import '../button/button.js'
@customElement('star-prompt')
export class StarPrompt extends LitElement {
@property()
foo = ''
@state()
bar = ''
render() {
return html``
public static override get styles(): CSSResultArray {
return [sharedStyles]
}
static styles = css``
@property({type: Boolean}) open = false
@queryAssignedElements({flatten: true}) _evenEl: any
@property({type: Boolean}) modal = false
@property({type: Boolean}) deep = false
@property({type: Boolean}) password = false
@property({type: Boolean}) visible = false
@property({type: String}) label = '内容'
@property({type: String}) text = ''
@property({type: Boolean}) wifi = false
@property({type: String}) bone = '取消'
@property({type: String}) btwo = '确定'
@property({type: String}) placeholder = '密码'
_getElement() {
if (this.open == true) {
this._evenEl[0].style.display = 'block'
this._evenEl[1].style.display = 'block'
this.open = false
} else {
this._evenEl[0].style.display = 'none'
this._evenEl[1].style.display = 'none'
this.open = true
}
}
_showpassword() {
var popBox = this._evenEl[1] as HTMLElement
var passwd = popBox.querySelector('.input') as HTMLInputElement
if (this.password == true) {
if (passwd.type == 'password') {
passwd.type = 'text'
this.visible = true
} else {
passwd.type = 'password'
this.visible = false
}
}
}
protected firstUpdated(): void {
this._getElement()
}
render() {
return html`
<button @click=${this._getElement}>Enter</button>
<slot>
<div class="cover"></div>
<div class="popBox">
<h3 class="title">${this.label}</h3>
<div class="container">
${this.password == false
? html`
<input
type="text"
name="hasReason"
value="${this.placeholder}"
class="input"
/>
`
: html`
<input type="password" name="hasReason" class="input" />
<div @click=${this._showpassword} class="show">
${this.visible == true
? html`
<img src="src/assets/eye.svg" class="eye" />
<div class="drop">
<img src="src/assets/eye_deep.svg" class="eye" />
</div>
`
: html`
<img src="src/assets/close_eye.svg" class="eye" />
<div class="drop">
<img
src="src/assets/close_eye_deep.svg"
class="eye"
/>
</div>
`}
</div>
`}
</div>
<div class="location">
<span class="info">${this.text}</span>
</div>
<div class="group">
${this.wifi == false
? html`
<button class="cancel" @click="${this._getElement}">
</button>
<button class="sure" @click="${this._getElement}">
</button>
`
: html`
<button class="cancel wifi" @click="${this._getElement}">
${this.bone}
</button>
<button class="sure blue" @click="${this._getElement}">
${this.btwo}
</button>
`}
</div>
</div>
</slot>
`
}
}
declare global {

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts", "../button/button.js"]
}

View File

@ -0,0 +1,2 @@
export * from './radio.js'
export * from './radio-group.js'

View File

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

View File

@ -1,8 +1,8 @@
import {LitElement, html, CSSResultArray, PropertyValues} from 'lit'
import {customElement, property, queryAssignedNodes} from 'lit/decorators.js'
import './radio'
import {StarRadio} from './radio'
import {sharedStyles} from './radio-style'
import './radio.js'
import {StarRadio} from './radio.js'
import {sharedStyles} from './radio-style.js'
@customElement('star-radio-group')
export class StarRadioGroup extends LitElement {
public static override get styles(): CSSResultArray {

View File

@ -1,6 +1,6 @@
import {LitElement, html, CSSResultArray} from 'lit'
import {customElement, property} from 'lit/decorators.js'
import {sharedStyles} from './radio-style'
import {sharedStyles} from './radio-style.js'
@customElement('star-radio')
export class StarRadio extends LitElement {
public static override get styles(): CSSResultArray {

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts"]
}

View File

@ -0,0 +1 @@
export * from './section.js'

View File

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

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts"]
}

View File

@ -48,21 +48,43 @@
6. `vertical` --- 垂直 slider
```
<star-slider vertical></star-slider>
<star-slider vertical disabled></star-slider>
<star-slider vertical coverWidth="50%"></star-slider>
```
7. `vHeight="300px"`代表垂直 slider 的长度 默认`vHeight="200px"`
7. 左侧图标|滑块|右侧图标
```
<star-slider vertical vHeight="300px"></star-slider>
<star-slider vertical disabled vHeight="300px"></star-slider>
<star-slider vertical coverWidth="50%" vHeight="100px"></star-slider>
```
8. 左侧图标|行滑块|右侧图标
- 可根据需求调节 `slider` 位置,例如 : `style="margin-left:10px"`
- `slot="l-icon"` 表示图标在`slider`左侧
- `slot="r-icon"` 表示图标在`slider`右侧
```
<star-slider>
<p class="left" data-icon="brightness"></p>
<div slot="l-icon" data-icon="brightness"></div>
</star-slider>
<star-slider>
<div slot="r-icon" data-icon="brightness"></div>
</star-slider>
```
1. 列滑块 - 下侧图标
- `slot="icon"` 表示图标在slider下部
```
<star-slider vertical coverWidth="100px">
<div slot="icon" data-icon="alarm"></div>
</star-slider>
```
## 后续需解决的问题:
- tick 属性中小球不能完全覆盖 step
- vertical 属性变化太快
- 后续用flex布局重新调整图标位置

View File

@ -0,0 +1 @@
export * from './slider.js'

View File

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

View File

@ -4,28 +4,31 @@ export const sharedStyles: CSSResult = css`
--cover-width: 0px;
--dot-move: 0px;
--vWidth: 8px;
--vHeight: 200px;
}
.content {
height: 2px;
margin: 50px;
margin: 0px 50px;
position: relative;
top: 50%;
transform: translateY(-50%);
padding: 8px;
/*border: 1px solid skyblue;*/
border-radius: 5px;
}
.v-content {
width: 2px;
margin: 0px 2px;
position: relative;
padding: 200px 10px;
/*border: 1px solid skyblue;*/
left: 50%;
top: 10px;
transform: translate(-50%);
width: 2px;
padding: 0 10px var(--vHeight);
border-radius: 5px;
}
.v-sliderBar {
position: absolute;
width: var(--vWidth);
height: 80%;
height: 100%;
left: calc(50% - var(--vWidth) / 2);
top: 0px;
background: rgba(0, 0, 0, 0.08);
@ -105,28 +108,53 @@ export const sharedStyles: CSSResult = css`
}
.step {
position: absolute;
left: calc(var(--i) * 99.3%);
left: calc(var(--i) * 100%);
top: calc(50% - 10px / 2);
width: 3px;
height: 10px;
background-color: #d5d5d5;
border-radius: 3px;
}
::slotted(span)::before {
/*
::slotted(.icon)::before {
font-size: 27px;
font-family: 'gaia-icons';
content: attr(data-icon);
text-align: center;
position: relative;
top: 357px;
}*/
::slotted([slot='icon']) {
position: absolute;
left: -2px;
top: 100%;
}
::slotted(p)::before {
font-size: 27px;
::slotted([slot='icon'])::before {
font-size: 25px;
font-family: 'gaia-icons';
content: attr(data-icon);
}
::slotted([slot='l-icon']) {
position: absolute;
left: -33px;
top: -6px;
}
::slotted([slot='l-icon'])::before {
font-size: 25px;
font-family: 'gaia-icons';
content: attr(data-icon);
}
::slotted([slot='r-icon']) {
position: absolute;
right: -33px;
top: -6px;
}
::slotted([slot='r-icon'])::before {
font-size: 25px;
font-family: 'gaia-icons';
content: attr(data-icon);
text-align: center;
position: relative;
top: 74px;
left: 5px;
}
`

View File

@ -1,10 +1,11 @@
import {html, LitElement, CSSResultArray, PropertyValueMap} from 'lit'
import {customElement, property, query} from 'lit/decorators.js'
import {sharedStyles} from './slider-styles'
import {sharedStyles} from './slider-styles.js'
@customElement('star-slider')
export class StarSlider extends LitElement {
_coverWidth: string = ''
_vHeight: string = ''
public static override get styles(): CSSResultArray {
return [sharedStyles]
}
@ -43,11 +44,19 @@ export class StarSlider extends LitElement {
this._coverWidth = value
this.style.setProperty('--dot-move', this._coverWidth)
}
@property({type: String})
get vHeight() {
console.log('this._vHeight', this._vHeight)
return this._vHeight
}
set vHeight(value: string) {
this.style.setProperty('--vHeight', value)
this._vHeight = value
}
render() {
if (!this.vertical) {
return html`
<slot></slot>
<div
class="content"
id="content"
@ -55,6 +64,8 @@ export class StarSlider extends LitElement {
@touchend=${this.touchEnd}
@touchmove=${this.touchMove}
>
<slot name="l-icon"></slot>
<slot name="r-icon"></slot>
<div class="sliderBar">
<div class="progress"></div>
<div class="dot"></div>
@ -63,13 +74,13 @@ export class StarSlider extends LitElement {
`
} else {
return html`
<slot></slot>
<div
class="v-content"
@touchstart=${this.touchStartVertical}
@touchend=${this.touchEndVertical}
@touchmove=${this.touchMoveVertical}
>
<slot name="icon"></slot>
<div class="v-sliderBar">
<div class="v-progress"></div>
</div>
@ -80,11 +91,11 @@ export class StarSlider extends LitElement {
protected firstUpdated(
_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>
): void {
if (this.vertical) {
this.touchStart = this.touchStartVertical
this.touchEnd = this.touchEndVertical
this.touchMove = this.touchMoveVertical
}
// if (this.vertical) {
// this.touchStart = this.touchStartVertical
// this.touchEnd = this.touchEndVertical
// this.touchMove = this.touchMoveVertical
// }
if (this.tick) {
var tickStep = 100 / parseInt(this.step)
for (let i = 0; i <= tickStep; i++) {
@ -99,11 +110,13 @@ export class StarSlider extends LitElement {
private touchStart(evt: TouchEvent) {
if (!this.disabled) {
this.touchX = evt.touches[0].clientX //手指触摸的 x 坐标
// 黑色覆盖部分
this.barX =
this.touchX -
this.sliderBar.getBoundingClientRect().left -
this.dot.offsetWidth * 0.5
// this.barWidth = this.sliderBar.offsetWidth
this.barWidth = this.sliderBar.offsetWidth - this.dot.offsetWidth
if (this.barX < 0) {
this.barX = 0
@ -188,22 +201,31 @@ export class StarSlider extends LitElement {
}
}
}
private touchEnd(_: TouchEvent) {
private touchEnd(evt: TouchEvent) {
if (this.tick) {
return console.log(10 * Math.round(parseInt(this.endValue) / 10) + '')
return 10 * Math.round(parseInt(this.endValue) / 10) + ''
} else {
return console.log(this.endValue)
return this.endValue
}
}
private touchStartVertical(evt: TouchEvent) {
if (!this.disabled) {
this.startY = evt.touches[0].clientY //手指点下的初始 Y 坐标
this.barWidth = this.vSliderBar.offsetHeight //总长度
this.dotL = this.barWidth - this.vProgress.offsetTop //黑条长度
this.dotL = this.vSliderBar.getBoundingClientRect().bottom - this.startY //点击后的黑条长度
//按压音量条变宽
this.vSliderBar.style.setProperty('--vWidth', '16px')
this.vProgress.style.setProperty('--vWidth', '16px')
//点击跳转
this.proportion = (this.dotL / this.barWidth) * 100
this.endValue = Math.ceil(this.proportion) + ''
this.vProgress.style.setProperty(
'height',
(this.barWidth * Math.ceil(this.proportion)) / 100 + 'px'
)
}
}
private touchMoveVertical(evt: TouchEvent) {
@ -233,7 +255,7 @@ export class StarSlider extends LitElement {
if (!this.disabled) {
this.vProgress.style.setProperty('--vWidth', '8px')
this.vSliderBar.style.setProperty('--vWidth', '8px')
return console.log(this.endValue)
return this.endValue
}
}
}

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts"]
}

Some files were not shown because too many files have changed in this diff Show More