fix conflict
This commit is contained in:
commit
8bed4c0ed1
|
@ -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
|
|
@ -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
|
||||
|
|
26
index.html
26
index.html
|
@ -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>
|
||||
|
|
22
package.json
22
package.json
|
@ -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/*"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './svg-icon.js'
|
|
@ -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"
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "./"
|
||||
},
|
||||
"include": ["*.ts", "icons/*.ts"]
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
`
|
|
@ -0,0 +1,2 @@
|
|||
export * from './star-base-element.js'
|
||||
export * from './base-style.js'
|
|
@ -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"
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts", "../../lib/gesture/gesture-detector.ts"]
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './blur.js'
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts"]
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './bubble.js'
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts"]
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './buttongroup.js'
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts"]
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './button.js'
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts", "../base/base-style.ts"]
|
||||
}
|
|
@ -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',
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './card.js'
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts"]
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './confirm.js'
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts"]
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
# 数字密码-digicipher
|
||||
|
||||
工作职责:
|
||||
|
||||
- 由0-9数字组成的数字密码
|
||||
- 默认密码为 `123456`
|
||||
- 点击数字反馈,输入成功上滑,输入错误抖动反馈
|
||||
|
||||
## 使用
|
||||
|
||||
```
|
||||
<star-digicipher></star-digicipher>
|
||||
```
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
`
|
|
@ -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')
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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, // 拖拽元素的垂直中心位置
|
||||
}
|
||||
```
|
|
@ -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)')
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
`
|
|
@ -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
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -2,8 +2,5 @@ import {css} from 'lit'
|
|||
|
||||
export default css`
|
||||
:host {
|
||||
/* 图标大小 */
|
||||
--icon-size: 108px;
|
||||
--icon-size: 50%;
|
||||
}
|
||||
`
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './indicator-page-point.js'
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts"]
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './li.js'
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": [
|
||||
"*.ts",
|
||||
"../base/base-style.js",
|
||||
"../bubble/bubble.js",
|
||||
"../switch/switch.js"
|
||||
]
|
||||
}
|
|
@ -3,28 +3,43 @@
|
|||
## 介绍
|
||||
|
||||
### overflowmenu:溢出菜单。
|
||||
现有overflowmenu包含一个绑定点击事件的star-button按钮,通过在响应函数closeoverflowmenu控制溢出菜单内容的显示与隐藏。
|
||||
|
||||
后续改进:结合active-overlay组件,通过调用overlay-stack类控制溢出菜单的显示与隐藏
|
||||
|
||||
## 新需求(主页面要求——罗 9.5)
|
||||
|
||||
1. 外部颜色控制(思路:使用自定义 css 样式,如: --test-color:XXX 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
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
|
@ -0,0 +1 @@
|
|||
export * from './overflowmenu.js'
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts", "../button/button.js"]
|
||||
}
|
|
@ -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:延迟出现overlay;placement:自定义位置;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替换回原位置
|
||||
>>> 移除overlay,removeoverlay节点
|
||||
>>> 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)
|
||||
```
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
// placement:adobe通过轻量前段工具包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 // 交互
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './picker.js'
|
|
@ -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"
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts"]
|
||||
}
|
|
@ -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>
|
||||
```
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './prompt.js'
|
|
@ -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"
|
||||
}
|
|
@ -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%;
|
||||
}
|
||||
`
|
|
@ -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 {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts", "../button/button.js"]
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * from './radio.js'
|
||||
export * from './radio-group.js'
|
|
@ -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"
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts"]
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './section.js'
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "../../"
|
||||
},
|
||||
"include": ["*.ts"]
|
||||
}
|
|
@ -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布局重新调整图标位置
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './slider.js'
|
|
@ -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"
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
`
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue