webc.site 0.1.16 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/Scroll.js +1 -1
- package/Scroll.js.map +3 -3
- package/importmap/genDoc.md +9 -0
- package/importmap/x/On.js +13 -0
- package/importmap/x/On.md +8 -0
- package/importmap/x/a.js +23 -0
- package/importmap/x/a.md +3 -0
- package/importmap/x/delayRoute.js +17 -0
- package/importmap/x/delayRoute.md +11 -0
- package/importmap/x/dom.js +3 -0
- package/importmap/x/dom.md +7 -0
- package/importmap/x/package.json +22 -0
- package/importmap/x/rmWait.js +2 -0
- package/importmap/x/rmWait.md +3 -0
- package/importmap/x/route.js +59 -0
- package/importmap/x/route.md +37 -0
- package/importmap/x/selfA.js +13 -0
- package/importmap/x/selfA.md +6 -0
- package/package.json +1 -1
- package/x.js +1 -1
- package/x.js.map +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# 人工智能驱动的界面开发流程笔记
|
|
2
|
+
|
|
3
|
+
## 纯 web 组件,支持无样式
|
|
4
|
+
|
|
5
|
+
纯 web 组件,可适配全部前端框架。
|
|
6
|
+
|
|
7
|
+
组件样式和组件逻辑完全拆分。
|
|
8
|
+
|
|
9
|
+
可只引用组件的逻辑,然后自己写样式。
|
|
10
|
+
|
|
11
|
+
同时支持无打包直接引用的使用方式,及配合 vite 等构建器打包的构建。
|
|
12
|
+
|
|
13
|
+
## 初衷
|
|
14
|
+
|
|
15
|
+
人工智能开发前端,比较大的问题是调试。
|
|
16
|
+
|
|
17
|
+
虽然[谷歌反重力](https://antigravity.google) 之类的开发工具,有打开浏览器调试能力,但因为交互流程比较深、需要登录才能访问、需要后台准备数据等等,人工智能全自动浏览器调试流程经常被阻塞,无法继续。
|
|
18
|
+
|
|
19
|
+
为了加速开发,我建议的方案是:
|
|
20
|
+
|
|
21
|
+
不在组件中直接调用后端接口读取数据,而是用异步回调的函数的方式,暴露给上层。
|
|
22
|
+
|
|
23
|
+
这样,就可以在 `Demo.svelte` 用假数据来展示组件的不同状态.
|
|
24
|
+
|
|
25
|
+
不再对后端数据状态有依赖。不需要登录,不需要在调试的之前,去后端准备数据。
|
|
26
|
+
|
|
27
|
+
也方便调整样式之后,查看在不同状态下,组件是否呈现有问题。
|
|
28
|
+
|
|
29
|
+
具体方案,可以参考我的演示前端库 [webc-zh](https://github.com/webc-zh/webc-zh.github.io)。
|
|
30
|
+
|
|
31
|
+
组件库在线浏览 [GitHub Page](https://webc-zh.github.io)
|
|
32
|
+
|
|
33
|
+
这里我把前端组件,都拆分为独立的组件文件夹,每个文件夹包含了所有需要的资源(比如 svg 等)。
|
|
34
|
+
|
|
35
|
+
如此做的好处是,可以类似[shadcn](https://ui.shadcn.com) 一样,实现按需添加。
|
|
36
|
+
|
|
37
|
+
比如, `./comDev.sh com/scroll`,就可以对滚动条进行单独的开发,调试。
|
|
38
|
+
|
|
39
|
+
调试默认会打开文件下的 `Demo.svelte` 作为调试入口。
|
|
40
|
+
|
|
41
|
+
完整的开发提示词,可以参考 [.agents/skills/com/SKILL.md](.agents/skills/com/SKILL.md)
|
|
42
|
+
|
|
43
|
+
谷歌反重力中 `/com ` 即可使用。
|
|
44
|
+
|
|
45
|
+

|
package/Scroll.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { On as A, D as I, newEl as H } from "./x.js";(()=>{let{round:h,max:b,min:D}=Math,a=(r,l,...p)=>{let c=H(r);if(l)c.setAttribute("part",l);return c.append(...p),c},k=(r,l,p)=>{let c=r.toLowerCase(),f=l.toLowerCase(),_="client"+r,y="scroll"+r,d="scroll"+l,w="client"+p;return(
|
|
1
|
+
import { On as A, D as I, newEl as H } from "./x.js";(()=>{let{round:h,max:b,min:D}=Math,a=(r,l,...p)=>{let c=H(r);if(l)c.setAttribute("part",l);return c.append(...p),c},k=(r,l,p)=>{let c=r.toLowerCase(),f=l.toLowerCase(),_="client"+r,y="scroll"+r,d="scroll"+l,w="client"+p;return(s)=>{let C,m,g,v=-1,P=s.firstElementChild,u=a("i","si"),o=a("b","bar",u),T=(e=u[_])=>{let t=s[_],i=P[y];return[i-t,b(1,t-e-6),e,t,i]},E=(e)=>{if(!o.parentNode)return;let[t,i]=T(e),n=b(0,D(s[d],t));if(v!=-1&&v!=n)o.style.opacity=1,clearTimeout(C),C=setTimeout(()=>o.style.opacity=0,1000);v=n,u.style[f]=3+h(i*n/t)+"px"},G=(e)=>{if(m)return;let t=I.body;t.setPointerCapture(e.pointerId),t.classList.add("drag"),o.part.add("drag");let i=e[w],n=()=>{t.classList.remove("drag"),o.part.remove("drag"),x(),m=null},x=A(t,{pointermove:(R)=>{let[z,B]=T();s[d]+=h(z*(R[w]-i)/B),i=R[w]},pointerup:n,lostpointercapture:n});m=n},S=(e)=>{let t=o.getBoundingClientRect(),i=t[f],[n,x,R]=T();s[d]=h(n*b(D((e[w]-i-3-R/2)/x,1),0)),G(e)},N=[A(o,{pointerdown:S}),A(u,{pointerdown:(e)=>{e.stopPropagation(),G(e)}}),A(s,{scroll:E.bind(null,void 0)})],L=new ResizeObserver(()=>{clearTimeout(g),g=setTimeout(()=>{let[,,,e,t]=T();if(e<t){if(o.parentNode!=s)s.appendChild(o);let n=b(16,h(e*e/t));u.style[c]=n+"px",E(n)}else if(o.parentNode)o.remove()},200)}),X=()=>{if(clearTimeout(C),clearTimeout(g),N.forEach((e)=>e()),m)m();if(L.disconnect(),o.parentNode)o.remove()};return o.style.opacity=0,[s,P].forEach((e)=>L.observe(e)),X}};[["v","Height","Top","Y","flex-direction:column;width:100%;min-height:100%"],["h","Width","Left","X","min-width:100%;width:max-content;height:100%"]].map(([r,l,p,c,f])=>{let _=k(l,p,c);customElements.define(r+"-scroll",class extends HTMLElement{connectedCallback(){let y=a("b","",a("slot")),d=a("b","scroll",y);y.style.cssText="display:flex;"+f,this.attachShadow({mode:"open"}).appendChild(d),this._unbind=_(d)}disconnectedCallback(){this._unbind?.()}})})})();
|
|
2
2
|
|
|
3
3
|
|
package/Scroll.js.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../com/Scroll/Scroll.js"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { On } from \"x/On.js\";\nimport { D, newEl } from \"x/dom.js\";\n\n(() => {\n const { round, max, min } = Math,\n PART = \"part\",\n BAR = \"bar\",\n SI = \"si\",\n DRAG = \"drag\",\n PX = \"px\",\n mk = (tag, part, ...kids) => {\n const e = newEl(tag);\n if (part) e.setAttribute(PART, part);\n e.append(...kids);\n return e;\n },\n mkScroll = (size, pos, axis) => {\n const style_size = size.toLowerCase(),\n style_pos = pos.toLowerCase(),\n client_size = \"client\" + size,\n scroll_size = \"scroll\" + size,\n scroll_pos = \"scroll\" + pos,\n client_pos = \"client\" + axis;\n return (ct) => {\n let timer_bar,\n ptr_unbind,\n timer_resize,\n pre_st = -1;\n const m = ct.firstElementChild,\n si = mk(\"i\", SI),\n bar = mk(\"b\", BAR, si),\n getGeo = (sih = si[client_size]) => {\n const ch = ct[client_size],\n sh = m[scroll_size];\n return [sh - ch, max(1, ch - sih - 6), sih, ch, sh];\n },\n updateTop = (h) => {\n if (!bar.parentNode) return;\n const [ds, db] = getGeo(h),\n st = max(0, min(ct[scroll_pos], ds));\n if (pre_st
|
|
5
|
+
"import { On } from \"x/On.js\";\nimport { D, newEl } from \"x/dom.js\";\n\n(() => {\n const { round, max, min } = Math,\n PART = \"part\",\n BAR = \"bar\",\n SI = \"si\",\n DRAG = \"drag\",\n PX = \"px\",\n mk = (tag, part, ...kids) => {\n const e = newEl(tag);\n if (part) e.setAttribute(PART, part);\n e.append(...kids);\n return e;\n },\n mkScroll = (size, pos, axis) => {\n const style_size = size.toLowerCase(),\n style_pos = pos.toLowerCase(),\n client_size = \"client\" + size,\n scroll_size = \"scroll\" + size,\n scroll_pos = \"scroll\" + pos,\n client_pos = \"client\" + axis;\n return (ct) => {\n let timer_bar,\n ptr_unbind,\n timer_resize,\n pre_st = -1;\n const m = ct.firstElementChild,\n si = mk(\"i\", SI),\n bar = mk(\"b\", BAR, si),\n getGeo = (sih = si[client_size]) => {\n const ch = ct[client_size],\n sh = m[scroll_size];\n return [sh - ch, max(1, ch - sih - 6), sih, ch, sh];\n },\n updateTop = (h) => {\n if (!bar.parentNode) return;\n const [ds, db] = getGeo(h),\n st = max(0, min(ct[scroll_pos], ds));\n if (pre_st != -1 && pre_st != st) {\n bar.style.opacity = 1;\n clearTimeout(timer_bar);\n timer_bar = setTimeout(() => (bar.style.opacity = 0), 1e3);\n }\n pre_st = st;\n si.style[style_pos] = 3 + round((db * st) / ds) + PX;\n },\n onDown = (e) => {\n if (ptr_unbind) return;\n const bd = D.body;\n bd.setPointerCapture(e.pointerId);\n bd.classList.add(DRAG);\n bar.part.add(DRAG);\n let pre = e[client_pos];\n const detach = () => {\n bd.classList.remove(DRAG);\n bar.part.remove(DRAG);\n un_ptr();\n ptr_unbind = null;\n },\n un_ptr = On(bd, {\n pointermove: (e) => {\n const [ds, db] = getGeo();\n ct[scroll_pos] += round((ds * (e[client_pos] - pre)) / db);\n pre = e[client_pos];\n },\n pointerup: detach,\n lostpointercapture: detach,\n });\n ptr_unbind = detach;\n },\n onClick = (e) => {\n const rect = bar.getBoundingClientRect(),\n top = rect[style_pos],\n [ds, db, sih] = getGeo();\n ct[scroll_pos] = round(ds * max(min((e[client_pos] - top - 3 - sih / 2) / db, 1), 0));\n onDown(e);\n },\n unbind = [\n On(bar, { pointerdown: onClick }),\n On(si, {\n pointerdown: (e) => {\n e.stopPropagation();\n onDown(e);\n },\n }),\n On(ct, { scroll: updateTop.bind(null, undefined) }),\n ],\n ob = new ResizeObserver(() => {\n clearTimeout(timer_resize);\n timer_resize = setTimeout(() => {\n const [, , , ch, sh] = getGeo(),\n is_turn = ch < sh;\n if (is_turn) {\n if (bar.parentNode != ct) ct.appendChild(bar);\n const h = max(16, round((ch * ch) / sh));\n si.style[style_size] = h + PX;\n updateTop(h);\n } else if (bar.parentNode) {\n bar.remove();\n }\n }, 200);\n }),\n destroy = () => {\n clearTimeout(timer_bar);\n clearTimeout(timer_resize);\n unbind.forEach((f) => f());\n if (ptr_unbind) ptr_unbind();\n ob.disconnect();\n if (bar.parentNode) bar.remove();\n };\n bar.style.opacity = 0;\n [ct, m].forEach((i) => ob.observe(i));\n return destroy;\n };\n };\n\n [\n [\"v\", \"Height\", \"Top\", \"Y\", \"flex-direction:column;width:100%;min-height:100%\"],\n [\"h\", \"Width\", \"Left\", \"X\", \"min-width:100%;width:max-content;height:100%\"],\n ].map(([prefix, size, pos, axis, css]) => {\n const initScroll = mkScroll(size, pos, axis);\n customElements.define(\n prefix + \"-scroll\",\n class extends HTMLElement {\n connectedCallback() {\n const content = mk(\"b\", \"\", mk(\"slot\")),\n wrapper = mk(\"b\", \"scroll\", content);\n content.style.cssText = \"display:flex;\" + css;\n this.attachShadow({ mode: \"open\" }).appendChild(wrapper);\n this._unbind = initScroll(wrapper);\n }\n disconnectedCallback() {\n this._unbind?.();\n }\n },\n );\n });\n})();\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "AAAA,aAAS,gBACT,YAAS,WAAG,kBAEX,IAAM,CACL,IAAQ,QAAO,MAAK,OAAQ,KAM1B,EAAK,CAAC,EAAK,KAAS,IAAS,CAC3B,IAAM,EAAI,EAAM,CAAG,EACnB,GAAI,EAAM,EAAE,aAPP,OAO0B,CAAI,EAEnC,OADA,EAAE,OAAO,GAAG,CAAI,EACT,GAET,EAAW,CAAC,EAAM,EAAK,IAAS,CAC9B,IAAM,EAAa,EAAK,YAAY,EAClC,EAAY,EAAI,YAAY,EAC5B,EAAc,SAAW,EACzB,EAAc,SAAW,EACzB,EAAa,SAAW,EACxB,EAAa,SAAW,EAC1B,MAAO,CAAC,IAAO,CACb,IAAI,EACF,EACA,EACA,EAAS,GACL,EAAI,EAAG,kBACX,EAAK,EAAG,IAtBT,IAsBgB,EACf,EAAM,EAAG,IAxBT,MAwBmB,CAAE,EACrB,EAAS,CAAC,EAAM,EAAG,KAAiB,CAClC,IAAM,EAAK,EAAG,GACZ,EAAK,EAAE,GACT,MAAO,CAAC,EAAK,EAAI,EAAI,EAAG,EAAK,EAAM,CAAC,EAAG,EAAK,EAAI,CAAE,GAEpD,EAAY,CAAC,IAAM,CACjB,GAAI,CAAC,EAAI,WAAY,OACrB,IAAO,EAAI,GAAM,EAAO,CAAC,EACvB,EAAK,EAAI,EAAG,EAAI,EAAG,GAAa,CAAE,CAAC,EACrC,GAAI,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "5DD6B8D33029FF4A64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const On = (elem, dict) => {
|
|
2
|
+
let event, func;
|
|
3
|
+
for (event in dict) {
|
|
4
|
+
func = dict[event];
|
|
5
|
+
elem.addEventListener(event, func);
|
|
6
|
+
}
|
|
7
|
+
return () => {
|
|
8
|
+
for (event in dict) {
|
|
9
|
+
func = dict[event];
|
|
10
|
+
elem.removeEventListener(event, func);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
};
|
package/importmap/x/a.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { goto, selfA, B } from "../../x.js";
|
|
2
|
+
B.addEventListener("click", (e) => {
|
|
3
|
+
var href, name, p;
|
|
4
|
+
p = e.target;
|
|
5
|
+
while (p) {
|
|
6
|
+
({ nodeName: name } = p);
|
|
7
|
+
if (name === "A") {
|
|
8
|
+
({ href } = p);
|
|
9
|
+
if (href) {
|
|
10
|
+
href = selfA(p, e);
|
|
11
|
+
if (href !== void 0) {
|
|
12
|
+
goto(href);
|
|
13
|
+
} else if (!p.target) {
|
|
14
|
+
p.target = "_blank";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
break;
|
|
18
|
+
} else if (name === "BODY") {
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
p = p.parentNode;
|
|
22
|
+
}
|
|
23
|
+
});
|
package/importmap/x/a.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { route } from "./route.js";
|
|
2
|
+
|
|
3
|
+
// 避免 onMount 之前,route 被触发,导致重复加载数据
|
|
4
|
+
export const delayRoute = (loadUrl) => {
|
|
5
|
+
let t;
|
|
6
|
+
const unbind = route((url, preUrl) => {
|
|
7
|
+
t = setTimeout(() => {
|
|
8
|
+
loadUrl(url, preUrl);
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
return () => {
|
|
12
|
+
unbind();
|
|
13
|
+
clearTimeout(t);
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default delayRoute;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@3-/x",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"keywords": [],
|
|
6
|
+
"homepage": "https://webc-zh.github.io",
|
|
7
|
+
"license": "MulanPSL-2.0",
|
|
8
|
+
"author": "i18n.site@gmail.com",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/webc-zh/webc-zh.github.io.git"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"./*"
|
|
15
|
+
],
|
|
16
|
+
"type": "module",
|
|
17
|
+
"exports": {
|
|
18
|
+
"./*": "./*"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {},
|
|
21
|
+
"devDependencies": {}
|
|
22
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { On } from "../../x.js";
|
|
2
|
+
export const nowUrl = () => location.pathname.slice(1),
|
|
3
|
+
[route, setPre, preUrl, refresh, removeSlash, split, setUrl, goto] = (() => {
|
|
4
|
+
let PRE = nowUrl(),
|
|
5
|
+
HOOK = [];
|
|
6
|
+
if (location.hash) PRE += location.hash;
|
|
7
|
+
|
|
8
|
+
const HASH = "#",
|
|
9
|
+
route = (hook) => {
|
|
10
|
+
HOOK.push(hook);
|
|
11
|
+
hook(nowUrl());
|
|
12
|
+
return () => {
|
|
13
|
+
HOOK = HOOK.filter((f) => f !== hook);
|
|
14
|
+
};
|
|
15
|
+
},
|
|
16
|
+
setPre = (url) => {
|
|
17
|
+
PRE = url;
|
|
18
|
+
},
|
|
19
|
+
preUrl = () => PRE,
|
|
20
|
+
refresh = (url) => {
|
|
21
|
+
url = url || nowUrl();
|
|
22
|
+
for (const f of HOOK) f(url, PRE);
|
|
23
|
+
setPre(url);
|
|
24
|
+
},
|
|
25
|
+
removeSlash = (url) => (url[0] === "/" ? url.slice(1) : url),
|
|
26
|
+
split = (str, s) => {
|
|
27
|
+
const p = str.indexOf(s);
|
|
28
|
+
return p >= 0 ? [str.slice(0, p), str.slice(p + 1)] : [str, ""];
|
|
29
|
+
},
|
|
30
|
+
setUrl = (url) => {
|
|
31
|
+
url = removeSlash(url);
|
|
32
|
+
if (url !== PRE) {
|
|
33
|
+
const [path, hash] = split(url, HASH),
|
|
34
|
+
[p] = split(PRE, HASH);
|
|
35
|
+
setPre(url);
|
|
36
|
+
if (path !== p) {
|
|
37
|
+
history.pushState(null, "", "/" + url);
|
|
38
|
+
return 1;
|
|
39
|
+
}
|
|
40
|
+
if (location.hash.slice(1) !== hash) {
|
|
41
|
+
location.hash = hash;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
window.dispatchEvent(new HashChangeEvent("hashchange"));
|
|
46
|
+
},
|
|
47
|
+
goto = (url) => {
|
|
48
|
+
if (setUrl(url)) refresh(url);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
On(window, {
|
|
52
|
+
popstate: () => {
|
|
53
|
+
const url = nowUrl();
|
|
54
|
+
if (url !== split(PRE, HASH)[0]) refresh(url);
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return [route, setPre, preUrl, refresh, removeSlash, split, setUrl, goto];
|
|
59
|
+
})();
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# 路由管理与跳转
|
|
2
|
+
|
|
3
|
+
- `nowUrl()`
|
|
4
|
+
- 返回值:当前 URL 路径(不含首部斜杠)。
|
|
5
|
+
|
|
6
|
+
- `route(hook)`
|
|
7
|
+
- `hook`: 路由变化时执行的回调函数。格式:
|
|
8
|
+
- 参数:
|
|
9
|
+
- `url`: 字符串,新 URL 路径。
|
|
10
|
+
- `preUrl`: 字符串(可选),旧 URL 路径。
|
|
11
|
+
- 返回值:无。
|
|
12
|
+
- 返回值:取消订阅的函数,格式为 `() => void`。
|
|
13
|
+
|
|
14
|
+
- `setPre(url)`
|
|
15
|
+
- `url`: 字符串,新的前一次 URL 路径。
|
|
16
|
+
|
|
17
|
+
- `preUrl()`
|
|
18
|
+
- 返回值:前一次的 URL 路径。
|
|
19
|
+
|
|
20
|
+
- `refresh(url)`
|
|
21
|
+
- `url`: 字符串(可选),要触发回调的 URL 路径,默认是当前 URL。
|
|
22
|
+
|
|
23
|
+
- `removeSlash(url)`
|
|
24
|
+
- `url`: 字符串。
|
|
25
|
+
- 返回值:移除首部斜杠后的字符串。
|
|
26
|
+
|
|
27
|
+
- `split(str, s)`
|
|
28
|
+
- `str`: 待拆分字符串。
|
|
29
|
+
- `s`: 分隔符。
|
|
30
|
+
- 返回值:包含两个元素的数组 `[前部, 后部]`。
|
|
31
|
+
|
|
32
|
+
- `setUrl(url)`
|
|
33
|
+
- `url`: 目标 URL 路径。
|
|
34
|
+
- 返回值:若路径改变返回 `1`,若仅 hash 改变不返回值。
|
|
35
|
+
|
|
36
|
+
- `goto(url)`
|
|
37
|
+
- `url`: 目标 URL 路径。
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// 判断A标签的href是否为当前网站的, 如果是, 返回url, 以实现不刷新跳转
|
|
2
|
+
export const selfA = (p, e) => {
|
|
3
|
+
var hash, url;
|
|
4
|
+
if (p.host === location.host) {
|
|
5
|
+
({ hash } = p);
|
|
6
|
+
url = p.pathname.slice(1) + p.search;
|
|
7
|
+
if (hash) {
|
|
8
|
+
url += hash;
|
|
9
|
+
}
|
|
10
|
+
e.preventDefault();
|
|
11
|
+
return url;
|
|
12
|
+
}
|
|
13
|
+
};
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"webc.site","version":"0.1.
|
|
1
|
+
{"name":"webc.site","version":"0.1.19","description":"","keywords":[],"homepage":"https://webc-zh.github.io","license":"MulanPSL-2.0","author":"i18n.site@gmail.com","repository":{"type":"git","url":"git+https://github.com/webc-zh/webc-zh.github.io.git"},"files":["./*"],"type":"module","exports":{"./*":"./*"},"scripts":{},"devDependencies":{}}
|
package/x.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=(e,t)=>{let n,r;for(n in t)r=t[n],e.addEventListener(n,r);return()=>{for(n in t)r=t[n],e.removeEventListener(n,r)}},t=
|
|
1
|
+
const e=(e,t)=>{let n,r;for(n in t)r=t[n],e.addEventListener(n,r);return()=>{for(n in t)r=t[n],e.removeEventListener(n,r)}},t=()=>location.pathname.slice(1),[n,r,i,a,o,s,c,l]=(()=>{let n=t(),r=[];location.hash&&(n+=location.hash);let i=e=>(r.push(e),e(t()),()=>{r=r.filter(t=>t!==e)}),a=e=>{n=e},o=()=>n,s=e=>{e||=t();for(let t of r)t(e,n);a(e)},c=e=>e[0]===`/`?e.slice(1):e,l=(e,t)=>{let n=e.indexOf(t);return n>=0?[e.slice(0,n),e.slice(n+1)]:[e,``]},u=e=>{if(e=c(e),e!==n){let[t,r]=l(e,`#`),[i]=l(n,`#`);if(a(e),t!==i)return history.pushState(null,``,`/`+e),1;if(location.hash.slice(1)!==r){location.hash=r;return}}window.dispatchEvent(new HashChangeEvent(`hashchange`))};return e(window,{popstate:()=>{let e=t();e!==l(n,`#`)[0]&&s(e)}}),[i,a,o,s,c,l,u,e=>{u(e)&&s(e)}]})(),u=(e,t)=>{var n,r;if(e.host===location.host)return{hash:n}=e,r=e.pathname.slice(1)+e.search,n&&(r+=n),t.preventDefault(),r},d=document,f=d.body,p=d.createElement.bind(d);export{f as B,d as D,e as On,l as goto,p as newEl,t as nowUrl,i as preUrl,a as refresh,o as removeSlash,n as route,u as selfA,r as setPre,c as setUrl,s as split};
|
package/x.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"x.js","names":[],"sources":["../../importmap/x/On.js","../../importmap/x/dom.js"],"sourcesContent":["export const On = (elem, dict) => {\n let event, func;\n for (event in dict) {\n func = dict[event];\n elem.addEventListener(event, func);\n }\n return () => {\n for (event in dict) {\n func = dict[event];\n elem.removeEventListener(event, func);\n }\n };\n};\n","export const D = document,\n B = D.body,\n newEl = D.createElement.bind(D);\n"],"mappings":"AAAA,MAAa,GAAM,EAAM,IAAS,CAChC,IAAI,EAAO,EACX,IAAK,KAAS,EACZ,EAAO,EAAK,GACZ,EAAK,iBAAiB,EAAO,CAAI,EAEnC,UAAa,CACX,IAAK,KAAS,EACZ,EAAO,EAAK,GACZ,EAAK,oBAAoB,EAAO,CAAI,CAExC,CACF,ECZa,EAAI,SACf,EAAI,EAAE,KACN,EAAQ,EAAE,cAAc,KAAK,CAAC"}
|
|
1
|
+
{"version":3,"file":"x.js","names":[],"sources":["../../importmap/x/On.js","../../importmap/x/route.js","../../importmap/x/selfA.js","../../importmap/x/dom.js"],"sourcesContent":["export const On = (elem, dict) => {\n let event, func;\n for (event in dict) {\n func = dict[event];\n elem.addEventListener(event, func);\n }\n return () => {\n for (event in dict) {\n func = dict[event];\n elem.removeEventListener(event, func);\n }\n };\n};\n","import { On } from \"x/On.js\";\n\nexport const nowUrl = () => location.pathname.slice(1),\n [route, setPre, preUrl, refresh, removeSlash, split, setUrl, goto] = (() => {\n let PRE = nowUrl(),\n HOOK = [];\n if (location.hash) PRE += location.hash;\n\n const HASH = \"#\",\n route = (hook) => {\n HOOK.push(hook);\n hook(nowUrl());\n return () => {\n HOOK = HOOK.filter((f) => f !== hook);\n };\n },\n setPre = (url) => {\n PRE = url;\n },\n preUrl = () => PRE,\n refresh = (url) => {\n url = url || nowUrl();\n for (const f of HOOK) f(url, PRE);\n setPre(url);\n },\n removeSlash = (url) => (url[0] === \"/\" ? url.slice(1) : url),\n split = (str, s) => {\n const p = str.indexOf(s);\n return p >= 0 ? [str.slice(0, p), str.slice(p + 1)] : [str, \"\"];\n },\n setUrl = (url) => {\n url = removeSlash(url);\n if (url !== PRE) {\n const [path, hash] = split(url, HASH),\n [p] = split(PRE, HASH);\n setPre(url);\n if (path !== p) {\n history.pushState(null, \"\", \"/\" + url);\n return 1;\n }\n if (location.hash.slice(1) !== hash) {\n location.hash = hash;\n return;\n }\n }\n window.dispatchEvent(new HashChangeEvent(\"hashchange\"));\n },\n goto = (url) => {\n if (setUrl(url)) refresh(url);\n };\n\n On(window, {\n popstate: () => {\n const url = nowUrl();\n if (url !== split(PRE, HASH)[0]) refresh(url);\n },\n });\n\n return [route, setPre, preUrl, refresh, removeSlash, split, setUrl, goto];\n })();\n","// 判断A标签的href是否为当前网站的, 如果是, 返回url, 以实现不刷新跳转\nexport const selfA = (p, e) => {\n var hash, url;\n if (p.host === location.host) {\n ({ hash } = p);\n url = p.pathname.slice(1) + p.search;\n if (hash) {\n url += hash;\n }\n e.preventDefault();\n return url;\n }\n};\n","export const D = document,\n B = D.body,\n newEl = D.createElement.bind(D);\n"],"mappings":"AAAA,MAAa,GAAM,EAAM,IAAS,CAChC,IAAI,EAAO,EACX,IAAK,KAAS,EACZ,EAAO,EAAK,GACZ,EAAK,iBAAiB,EAAO,CAAI,EAEnC,UAAa,CACX,IAAK,KAAS,EACZ,EAAO,EAAK,GACZ,EAAK,oBAAoB,EAAO,CAAI,CAExC,CACF,ECVa,MAAe,SAAS,SAAS,MAAM,CAAC,EACnD,CAAC,EAAO,EAAQ,EAAQ,EAAS,EAAa,EAAO,EAAQ,QAAe,CAC1E,IAAI,EAAM,EAAO,EACf,EAAO,CAAC,EACN,SAAS,OAAM,GAAO,SAAS,MAEnC,IACE,EAAS,IACP,EAAK,KAAK,CAAI,EACd,EAAK,EAAO,CAAC,MACA,CACX,EAAO,EAAK,OAAQ,GAAM,IAAM,CAAI,CACtC,GAEF,EAAU,GAAQ,CAChB,EAAM,CACR,EACA,MAAe,EACf,EAAW,GAAQ,CACjB,IAAa,EAAO,EACpB,IAAK,IAAM,KAAK,EAAM,EAAE,EAAK,CAAG,EAChC,EAAO,CAAG,CACZ,EACA,EAAe,GAAS,EAAI,KAAO,IAAM,EAAI,MAAM,CAAC,EAAI,EACxD,GAAS,EAAK,IAAM,CAClB,IAAM,EAAI,EAAI,QAAQ,CAAC,EACvB,OAAO,GAAK,EAAI,CAAC,EAAI,MAAM,EAAG,CAAC,EAAG,EAAI,MAAM,EAAI,CAAC,CAAC,EAAI,CAAC,EAAK,EAAE,CAChE,EACA,EAAU,GAAQ,CAEhB,GADA,EAAM,EAAY,CAAG,EACjB,IAAQ,EAAK,CACf,GAAM,CAAC,EAAM,GAAQ,EAAM,EAAK,GAAI,EAClC,CAAC,GAAK,EAAM,EAAK,GAAI,EAEvB,GADA,EAAO,CAAG,EACN,IAAS,EAEX,OADA,QAAQ,UAAU,KAAM,GAAI,IAAM,CAAG,EAC9B,EAET,GAAI,SAAS,KAAK,MAAM,CAAC,IAAM,EAAM,CACnC,SAAS,KAAO,EAChB,MACF,CACF,CACA,OAAO,cAAc,IAAI,gBAAgB,YAAY,CAAC,CACxD,EAYF,OAPA,EAAG,OAAQ,CACT,aAAgB,CACd,IAAM,EAAM,EAAO,EACf,IAAQ,EAAM,EAAK,GAAI,EAAE,IAAI,EAAQ,CAAG,CAC9C,CACF,CAAC,EAEM,CAAC,EAAO,EAAQ,EAAQ,EAAS,EAAa,EAAO,EAXlD,GAAQ,CACV,EAAO,CAAG,GAAG,EAAQ,CAAG,CAC9B,CASsE,CAC1E,GAAG,EC1DQ,GAAS,EAAG,IAAM,CAC7B,IAAI,EAAM,EACV,GAAI,EAAE,OAAS,SAAS,KAOtB,MANC,SAAW,EACZ,EAAM,EAAE,SAAS,MAAM,CAAC,EAAI,EAAE,OAC1B,IACF,GAAO,GAET,EAAE,eAAe,EACV,CAEX,ECZa,EAAI,SACf,EAAI,EAAE,KACN,EAAQ,EAAE,cAAc,KAAK,CAAC"}
|