修改为python + gtk开发

master
yutent 2023-08-31 18:57:09 +08:00
parent 1f8f16fb36
commit 4a80a18cc3
23 changed files with 1171 additions and 22 deletions

9
.gitignore vendored
View File

@ -7,10 +7,5 @@
.Trashes
build
build/**
node_modules
node_modules/**
package-lock.json
__pycache__
*.txt

12
debian/control vendored Normal file
View File

@ -0,0 +1,12 @@
Package: hosts-switch
Version: 3.0.0
Section: develop
Architecture: all
Priority: optional
Maintainer: Yutent <yutent.io@gmail.com>
Installed-Size: 0
Depends: python3-webengine-gtk3
Homepage: https://git.wkit.fun/appcat/hosts-switch/
Author: yutent
Description: 一个hosts绑定切换工具
提供了一个类似域名DNS解析的操作界面.

View File

@ -1,15 +0,0 @@
{
"name": "hosts-switch",
"version": "2.0.0",
"description": "Hosts切换器",
"main": "src/main.js",
"scripts": {
"start": "electron ."
},
"author": {
"name": "yutent",
"email": "yutent.io@gmail.com"
},
"homepage": "https://yutent.me",
"license": "MIT"
}

7
test.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
export RUN_ENV='development'
./usr/lib/hosts-switch/hosts-switch.py

3
usr/bin/hosts-switch Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
/usr/lib/hosts-switch/hosts-switch.py

View File

@ -0,0 +1,64 @@
#!/usr/bin/python3
import gi, os, sys
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GLib, Gio, GObject, GdkPixbuf
from webengine.gtk3 import WebEngine, create_setting, create_hmr_server
from window import Window
APP_ID = 'fun.wkit.hosts-switch'
__dir__ = os.path.dirname(os.path.realpath(__file__))
web_root = os.path.join(__dir__, './webapp')
class Application(Gtk.Application):
def __init__(self):
Gtk.Application.__init__(self, application_id = APP_ID)
self.window = Window()
web = WebEngine(self.window)
setting = create_setting({"devtools": True})
hmr = create_hmr_server()
web.set_root(web_root)
web.use(setting).use(hmr)
web.connect('quit', self.quit_all)
web.load()
self.window.add(web)
def do_activate(self):
self.set_app_menu(None)
self.set_menubar(None)
self.add_window(self.window)
self.window.show_all()
def quit_all(self):
self.remove_window(self.window)
if __name__ == "__main__":
try:
app = Application()
app.run(sys.argv)
except Exception as err:
print(err)
pass

View File

@ -0,0 +1,45 @@
/**
* {}
* @author yutent<yutent.io@gmail.com>
* @date 2023/07/20 14:19:13
*/
import 'es.shim'
import { html, css, Component } from 'wkit'
import { createApp, createRouter } from 'wkitd'
import './components/home.js'
createApp({
data: {
input: '',
img: '',
content: ''
},
styles: [
css`
:host {
display: flex;
width: 100%;
height: 100vh;
}
.app {
display: flex;
width: 100%;
}
router-view {
flex: 1;
}
`
],
methods: {
quit() {
native.quit()
}
},
render() {
return html` <wc-home></wc-home> `
}
})
.use(router)
.mount()

View File

@ -0,0 +1,68 @@
/**
* {}
* @author yutent<yutent.io@gmail.com>
* @date 2023/08/08 18:19:17
*/
import { html, css, Component } from 'wkit'
import 'ui/icon/index.js'
import 'ui/space/index.js'
import 'ui/form/input.js'
import 'ui/form/switch.js'
import 'ui/form/button.js'
class Home extends Component {
static props = {
foo: ''
}
static styles = [
css`
:host {
flex: 1;
}
.main {
width: 100%;
height: 100%;
padding: 32px;
color: var(--color-dark-1);
background: #f0f0f0;
}
wc-input {
flex: 1;
}
wc-button {
width: 100%;
}
.card {
width: 100%;
padding: 12px;
margin: 0 auto 24px;
border: 0;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.075);
background: #fff;
}
legend {
-webkit-touch-callout: none;
user-select: none;
color: var(--color-dark-1);
font-weight: bold;
}
`
]
render() {
return html`
<main class="main">
<fieldset class="card">
<legend>镜像地址</legend>
</fieldset>
</main>
`
}
}
Home.reg('home')

View File

@ -0,0 +1,82 @@
@charset "UTF-8";
/**
*
* @authors yutent (yutent.io@gmail.com)
* @date 2014-10-10 00:45:09
*
* CSS
*
* ,
*
*
* 1 display float position overflow z-index /
* 2 width height margin padding border
* 3 line-height font-size vertical-align text-align user-select outline ....
* 4 color background opacity cursor ...
* 5 content list-style quotes ...
*
*/
* {margin: 0;padding: 0;vertical-align: baseline;box-sizing: border-box;}
::before, ::after {box-sizing: border-box;}
/* HTML5 display-role reset for older browsers */
article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section,content {display: block;}
img {border: 0;display: inline-block;}
ol,ul {list-style: none;}
blockquote, q {quotes: none;}
blockquote::before, blockquote::after, q::before, q::after {content: '';content: none;}
table {border-collapse: collapse;border-spacing: 0;}
a:focus,input,textarea,button:focus,input:focus,textarea:focus {outline: none;}
::-moz-focus-inner {border: none;outline: none;}
body {font-family: 'Helvetica Neue', Arial, 'WenQuanYi Micro Hei', 'PingFang SC', 'Hiragino Sans GB', 'Segoe UI', 'Microsoft Yahei', sans-serif;-webkit-font-smoothing: antialiased;text-size-adjust: 100%;-webkit-tap-highlight-color: transparent;}
code, pre, samp {font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;white-space:pre-wrap;}
[anot],[\:repeat],[\:if] {visibility: hidden;}
.noselect {-webkit-touch-callout: none;-webkit-user-select: none;-moz-user-select: none;user-select: none;}
.noselect img, .noselect a {-webkit-user-drag: none;}
.text-ell {overflow: hidden;white-space: nowrap;text-overflow: ellipsis;}
.text-thin {-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;}
:root {
/* primary */
--color-teal-a: rgba(72, 201, 176, 0.35);
--color-teal-1: rgb(72, 201, 176);
--color-teal-2: rgb(26, 188, 156);
--color-teal-3: rgb(22, 160, 133);
/* success */
--color-green-a: rgba(70, 221, 126, 0.35);
--color-green-1: rgb(70, 221, 126);
--color-green-2: rgb(47, 208, 105);
--color-green-3: rgb(26, 196, 88);
/* info */
--color-blue-a: rgba(100, 181, 246, 0.35);
--color-blue-1: rgb(100, 181, 246);
--color-blue-2: rgb(66, 165, 245);
--color-blue-3: rgb(33, 150, 243);
/* danger */
--color-red-a: rgba(252, 118, 97, 0.35);
--color-red-1: #fc7661;
--color-red-2: #ff5f45;
--color-red-3: #f33e22;
/* warning */
--color-orange-a: rgba(254, 174, 117, 0.35);
--color-orange-1: #feae75;
--color-orange-2: #fd964b;
--color-orange-3: #f97316;
/* default1 */
--color-plain-a: rgba(150, 204, 248, 0.35);
--color-plain-1: rgb(242, 245, 252);
--color-plain-2: rgb(232, 235, 244);
--color-plain-3: rgb(218, 225, 233);
/* default2 */
--color-grey-a: rgba(206, 214, 224, 0.35);
--color-grey-1: rgb(206, 214, 224);
--color-grey-2: rgb(164, 176, 190);
--color-grey-3: rgb(134, 144, 155);
/* inverse */
--color-dark-a: rgba(100, 116, 139, 0.35);
--color-dark-1: #64748B;
--color-dark-2: #475569;
--color-dark-3: #2c3441;
}

View File

@ -0,0 +1,35 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<link rel="stylesheet" href="/css/reset.css">
<style>
html,body {
width:100%;
height: 100%;
line-height: 1.5;
font-size: 14px;
cursor:default;
}
a {color:inherit;text-decoration: none;}
</style>
<script type="importmap">
{
"imports":{
"es.shim":"app:///lib/es.shim.js",
"wkit":"app:///lib/wkit.js",
"wkitd":"app:///lib/wkitd.js",
"fetch":"app:///lib/fetch.js",
"crypto":"app:///lib/crypto.js",
"ui/":"app:///lib/ui/"
}
}
</script>
<script type="module" src="/app.js"></script>
</head>
<body class="noselect">
<wc-app></wc-app>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,16 @@
import { css, html, Component } from "wkit";
class Card extends Component {
static props = {
header: ""
};
static styles = css`:host{display:flex;border-radius:3px}.card-box{display:flex;flex-direction:column;position:relative;width:100%;border:1px solid var(--color-plain-2);border-radius:inherit;background:#fff;color:var(--color-dark-1);transition:box-shadow .2s ease-in-out;box-shadow:0 0 12px rgba(0,0,0,.12)}.card-box .header{display:flex;align-items:center;justify-content:space-between;width:100%;min-height:52px;padding:var(--card-padding, 8px 16px);border-bottom:1px solid var(--color-plain-2);font-size:16px;user-select:none}.card-box .content{flex:1;min-height:64px;padding:var(--card-padding, 8px 16px);font-size:14px;color:var(--color-dark-1)}:host([shadow=never]) .card-box,:host([shadow=hover]) .card-box{box-shadow:none}:host([shadow=hover]:hover) .card-box{box-shadow:0 0 12px rgba(0,0,0,.12)}`;
render() {
return html`
<div class="card-box">
<div class="header"><slot name="header">${this.header}</slot></div>
<div class="content"><slot></slot></div>
</div>
`;
}
}
Card.reg("card");

View File

@ -0,0 +1,64 @@
import { css, html, Component, nextTick, styleMap } from "wkit";
import "../icon/index.js";
class Button extends Component {
static props = {
icon: "",
autofocus: false,
loading: {
type: Boolean,
observer(val) {
if (val) {
this.cacheIcon = this.icon;
this.icon = "loading";
} else {
this.icon = this.cacheIcon === void 0 ? this.icon : this.cacheIcon;
}
}
},
disabled: false,
lazy: "num!0"
// 并发拦截时间, 单位毫秒
};
static styles = [
// 基础样式
css`:host{overflow:hidden;display:inline-flex;min-width:108px;height:32px;border:0;border-radius:3px;user-select:none;-moz-user-select:none;color:var(--color-dark-1);font-size:14px;cursor:pointer;transition:box-shadow .15s linear}:host button{display:flex;justify-content:center;align-items:center;width:100%;min-width:1px;height:inherit;padding:var(--wc-button-padding, 0 4px);line-height:1;border:1px solid var(--wc-button-border-color, var(--color-grey-2));border-radius:inherit;white-space:nowrap;background:var(--wc-button-background, #fff);font-size:inherit;font-family:inherit;outline:none;color:var(--wc-button-color, var(--color-dark-1));cursor:inherit;transition:background .15s linear,color .15s linear}:host button::-moz-focus-inner{border:none}:host button:hover{color:var(--wc-button-color-hover, var(--color-grey-3));border-color:var(--wc-button-border-color-hover, var(--color-grey-3));background:var(--wc-button-background-hover, var(--wc-button-background, #fff))}:host button:active{color:var(--wc-button-color-active, var(--color-dark-2));background:var(--wc-button-background-active, var(--wc-button-background, #fff))}:host button:disabled{color:var(--wc-button-color-disabled, var(--color-dark-1));background:var(--wc-button-background-disabled, var(--wc-button-background, #fff))}:host .icon{margin-right:4px;--wc-icon-size: var(--wc-button-icon-size, 14px)}:host([solid]) button{border:0;color:#fff;background:var(--color-dark-1)}:host([solid]) button:hover{background:var(--color-grey-3)}:host([solid]) button:active{background:var(--color-dark-2)}:host([solid]) button:disabled{background:var(--color-dark-1)}:host(:focus-within){box-shadow:0 0 0 2px var(--color-plain-a)}:host(:empty) button .icon{margin-right:0}`,
// 尺寸
css`:host([size=s]){min-width:52px;height:20px;font-size:12px}:host([size=s]) .icon{--wc-icon-size: var(--wc-button-icon-size, 12px)}:host([size=s][circle]){width:20px;height:20px}:host([size=m]){min-width:72px;height:24px;font-size:12px}:host([size=m]) .icon{--wc-icon-size: var(--wc-button-icon-size, 12px)}:host([size=m][circle]){width:24px;height:24px}:host([size=xl]){min-width:132px;height:36px;font-size:14px}:host([size=xl]) .icon{--wc-icon-size: var(--wc-button-icon-size, 14px)}:host([size=xl][circle]){width:36px;height:36px}:host([size=xxl]){min-width:160px;height:44px;font-size:14px}:host([size=xxl]) .icon{--wc-icon-size: var(--wc-button-icon-size, 14px)}:host([size=xxl][circle]){width:44px;height:44px}:host([dashed]) button{border-style:dashed}:host([round]){border-radius:32px}:host([circle]){min-width:0;width:32px;height:32px;border-radius:50%}:host([circle]) button{padding:0}:host([circle]) .icon{margin-right:0}:host([circle]) slot{display:none}`,
// 配色
css`:host([type=primary]) button{color:var(--color-teal-2);border-color:var(--color-teal-1)}:host([type=primary]) button:hover{color:var(--color-teal-1);border-color:var(--color-teal-2);background:var(--wc-button-background, #fff)}:host([type=primary]) button:active{color:var(--color-teal-3);background:var(--wc-button-background, #fff)}:host([type=primary]) button:disabled{color:var(--color-teal-2);background:var(--wc-button-background, #fff)}:host([type=primary]):host([solid]) button{border:0;color:#fff;background:var(--color-teal-2)}:host([type=primary]):host([solid]) button:hover{background:var(--color-teal-1)}:host([type=primary]):host([solid]) button:active{background:var(--color-teal-3)}:host([type=primary]):host([solid]) button:disabled{background:var(--color-teal-2)}:host([type=primary]):host(:focus-within){box-shadow:0 0 0 2px var(--color-teal-a)}:host([type=info]) button{color:var(--color-blue-2);border-color:var(--color-blue-1)}:host([type=info]) button:hover{color:var(--color-blue-1);border-color:var(--color-blue-2);background:var(--wc-button-background, #fff)}:host([type=info]) button:active{color:var(--color-blue-3);background:var(--wc-button-background, #fff)}:host([type=info]) button:disabled{color:var(--color-blue-2);background:var(--wc-button-background, #fff)}:host([type=info]):host([solid]) button{border:0;color:#fff;background:var(--color-blue-2)}:host([type=info]):host([solid]) button:hover{background:var(--color-blue-1)}:host([type=info]):host([solid]) button:active{background:var(--color-blue-3)}:host([type=info]):host([solid]) button:disabled{background:var(--color-blue-2)}:host([type=info]):host(:focus-within){box-shadow:0 0 0 2px var(--color-blue-a)}:host([type=success]) button{color:var(--color-green-2);border-color:var(--color-green-1)}:host([type=success]) button:hover{color:var(--color-green-1);border-color:var(--color-green-2);background:var(--wc-button-background, #fff)}:host([type=success]) button:active{color:var(--color-green-3);background:var(--wc-button-background, #fff)}:host([type=success]) button:disabled{color:var(--color-green-2);background:var(--wc-button-background, #fff)}:host([type=success]):host([solid]) button{border:0;color:#fff;background:var(--color-green-2)}:host([type=success]):host([solid]) button:hover{background:var(--color-green-1)}:host([type=success]):host([solid]) button:active{background:var(--color-green-3)}:host([type=success]):host([solid]) button:disabled{background:var(--color-green-2)}:host([type=success]):host(:focus-within){box-shadow:0 0 0 2px var(--color-green-a)}:host([type=warning]) button{color:var(--color-orange-2);border-color:var(--color-orange-1)}:host([type=warning]) button:hover{color:var(--color-orange-1);border-color:var(--color-orange-2);background:var(--wc-button-background, #fff)}:host([type=warning]) button:active{color:var(--color-orange-3);background:var(--wc-button-background, #fff)}:host([type=warning]) button:disabled{color:var(--color-orange-2);background:var(--wc-button-background, #fff)}:host([type=warning]):host([solid]) button{border:0;color:#fff;background:var(--color-orange-2)}:host([type=warning]):host([solid]) button:hover{background:var(--color-orange-1)}:host([type=warning]):host([solid]) button:active{background:var(--color-orange-3)}:host([type=warning]):host([solid]) button:disabled{background:var(--color-orange-2)}:host([type=warning]):host(:focus-within){box-shadow:0 0 0 2px var(--color-orange-a)}:host([type=danger]) button{color:var(--color-red-2);border-color:var(--color-red-1)}:host([type=danger]) button:hover{color:var(--color-red-1);border-color:var(--color-red-2);background:var(--wc-button-background, #fff)}:host([type=danger]) button:active{color:var(--color-red-3);background:var(--wc-button-background, #fff)}:host([type=danger]) button:disabled{color:var(--color-red-2);background:var(--wc-button-background, #fff)}:host([type=danger]):host([solid]) button{border:0;color:#fff;background:var(--color-red-2)}:host([type=danger]):host([solid]) button:hover{background:var(--color-red-1)}:host([type=danger]):host([solid]) button:active{background:var(--color-red-3)}:host([type=danger]):host([solid]) button:disabled{background:var(--color-red-2)}:host([type=danger]):host(:focus-within){box-shadow:0 0 0 2px var(--color-red-a)}`,
// 状态
css`:host([loading]),:host([disabled]){cursor:not-allowed;opacity:.6}`
];
created() {
this.stamp = 0;
this._clickFn = this.$on(
"click",
(ev) => {
let { loading, disabled, lazy } = this;
let now = Date.now();
if (loading || disabled) {
return ev.stopPropagation();
}
if (lazy > 0 && now - this.stamp < lazy) {
return ev.stopPropagation();
}
this.stamp = now;
},
true
);
}
mounted() {
if (this.autofocus) {
nextTick((_) => this.$refs.btn.focus());
}
}
render() {
return html`
<button ref="btn" disabled=${this.disabled || this.loading}>
<wc-icon class="icon" name=${this.icon}></wc-icon>
<slot ref="cont"></slot>
</button>
`;
}
}
Button.reg("button");

View File

@ -0,0 +1,171 @@
import { nextTick, css, html, Component, classMap, outsideClick } from "wkit";
import "../icon/index.js";
const ANIMATION = {
duration: 100,
custom: [
{ transform: "scaleY(0)", opacity: 0 },
{ transform: "scaleY(1)", opacity: 1 }
]
};
class Input extends Component {
static props = {
readOnly: false,
autofocus: false,
disabled: false,
clearable: false,
icon: "",
placeholder: "",
maxlength: { type: Number, default: null },
minlength: { type: Number, default: null },
value: "str!",
lazy: "num!0"
// 并发拦截时间, 单位毫秒
};
#list = [];
#selectIndex = -1;
#listShowing = false;
#stamp = 0;
static styles = [
css`:host{position:relative;display:inline-flex;min-width:188px;height:32px;user-select:none;-moz-user-select:none;color:var(--color-dark-1);border-radius:3px;cursor:text;transition:box-shadow .15s linear}.label{flex:1;display:flex;justify-content:center;align-items:center;height:100%;font-size:14px;border:1px solid var(--wc-input-border-color, var(--color-grey-2));border-radius:inherit;background:var(--bg-color, #fff);color:inherit;cursor:inherit}.label input{flex:1;min-width:36px;width:0;height:100%;padding:0 8px;border:0;border-radius:inherit;font:inherit;color:inherit;background:none;outline:none;box-shadow:none;cursor:inherit}.label input::placeholder{color:var(--color-grey-1)}.label .close{--wc-icon-size: 18px;margin:0 8px 0 4px;padding:4px;border-radius:50%;color:var(--color-grey-2);cursor:pointer;transition:background .15s linear}.label .close:hover{background:var(--color-plain-1)}.label .icon{--wc-icon-size: 16px;margin:0 8px 0 4px;color:var(--color-grey-2)}.suggestion{overflow:hidden;position:absolute;z-index:1;left:0;top:calc(100% + 4px);width:100%;padding:4px 0;border-radius:4px;box-shadow:0 2px 5px rgba(0,0,0,.15);transform-origin:top}.suggestion .list{width:100%;background:#fff}.suggestion.hide{display:none}.suggestion li{overflow:hidden;width:100%;height:30px;line-height:30px;padding:0 8px;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.suggestion li:hover,.suggestion li[focus]{background:var(--color-plain-2)}:host([round]){border-radius:26px}:host([round]) .label input{padding:0 10px}:host(:focus-within){box-shadow:0 0 0 2px var(--color-plain-a)}:host([disabled]){pointer-events:none;cursor:not-allowed}:host([disabled]) .label{border-color:var(--color-grey-1);background:var(--color-plain-1);opacity:.6}:host([readonly]){cursor:default}`,
//尺寸
css`:host([size=m]){min-width:128px;height:24px;font-size:12px}:host([size=m]) .label{height:24px;font-size:12px}:host([size=m]) .icon{--wc-icon-size: 12px}:host([size=m][circle]){width:24px;height:24px}:host([size=xl]){min-width:224px;height:36px;font-size:14px}:host([size=xl]) .label{height:36px;font-size:14px}:host([size=xl]) .icon{--wc-icon-size: 14px}:host([size=xl][circle]){width:36px;height:36px}:host([size=xxl]){min-width:288px;height:44px;font-size:14px}:host([size=xxl]) .label{height:44px;font-size:14px}:host([size=xxl]) .icon{--wc-icon-size: 14px}:host([size=xxl][circle]){width:44px;height:44px}`
];
renderClear() {
return html`<wc-icon class="close" name="close" @click=${this.clear} />`;
}
render() {
let classes = classMap({
suggestion: true,
hide: !this.#list.length
});
return html`
<div class="label">
<slot name="prepend">
<wc-icon class="icon" name=${this.icon}></wc-icon>
</slot>
<input
ref="input"
@input=${this.handleInput}
@change=${this.handleChange}
@keydown=${this.handleKeyDown}
@focus=${this.handleFocus}
placeholder=${this.placeholder}
maxlength=${this.maxlength}
minlength=${this.minlength}
disabled=${this.disabled}
readonly=${this.readOnly}
autofocus=${this.autofocus}
:value=${this.value}
/>
${this.clearable && this.value ? this.renderClear() : ""}
<slot name="append"></slot>
<div class=${classes} ref="suggestion" #animation=${ANIMATION}>
<div ref="scroller" class="scroller">
<ul class="list" @click=${this.handleClickItem} ref="list">
${this.#list.map(
(li, idx) => html`<li
focus=${this.#selectIndex === idx ? true : null}
index=${idx}
>
${li.value}
</li>`
)}
</ul>
</div>
</div>
</div>
`;
}
handleInput(e) {
let { lazy } = this;
this.value = e.currentTarget.value;
if (lazy && Date.now() - this.#stamp < lazy) {
return;
}
this.#stamp = Date.now();
this.emitFetchSuggest();
}
handleClickItem(e) {
let index = e.target.getAttribute("index");
this.#selectIndex = index;
this.emitSelect();
}
clear() {
this.$refs.input.value = "";
this.value = "";
this.$emit("change");
this.$emit("input");
}
handleChange() {
this.$emit("change");
}
handleKeyDown(e) {
let { lazy, minlength, value } = this;
if (e.keyCode === 13) {
e.preventDefault();
if (this.#selectIndex > -1 && this.#listShowing) {
return this.emitSelect();
}
if (lazy && Date.now() - this.#stamp < lazy) {
return;
}
this.#stamp = Date.now();
if (minlength && value.length < minlength) {
return;
}
return this.$emit("submit");
}
if (e.keyCode === 38 || e.keyCode === 40) {
e.preventDefault();
let step = e.keyCode === 38 ? -1 : 1;
this.#selectIndex += step;
if (this.#selectIndex < 0) {
this.#selectIndex = 0;
}
if (this.#selectIndex > this.#list.length - 1) {
this.#selectIndex = this.#list.length - 1;
}
this.$requestUpdate();
}
}
// 触发列表选择
emitSelect() {
let item = this.#list[this.#selectIndex];
this.value = item.value;
this.$refs.suggestion.$animate(true);
this.#listShowing = false;
this.$requestUpdate();
this.$emit("change");
this.$emit("input");
this.$emit("select", {
index: this.#selectIndex,
value: item
});
}
emitFetchSuggest() {
this.$emit("fetch-suggest", {
value: this.value,
send: (list) => {
this.#list = list.slice(0, 10);
this.#selectIndex = -1;
this.$requestUpdate();
}
});
}
handleFocus() {
if (!this.#listShowing) {
this.#listShowing = true;
this.$refs.suggestion.$animate();
}
}
mounted() {
if (this.autofocus) {
nextTick((_) => this.$refs.input.focus());
}
outsideClick(this, () => {
this.#listShowing = false;
this.$refs.suggestion.$animate(true);
});
}
}
Input.reg("input");

View File

@ -0,0 +1,61 @@
import { nextTick, css, html, Component, classMap } from "wkit";
class Switch extends Component {
static props = {
value: {
type: Boolean,
default: false
},
inactiveText: "",
activeText: "",
inlineText: false,
disabled: false,
readonly: false
};
static styles = [
css`:host{display:inline-flex;align-items:center;font-size:14px;cursor:pointer}:host label{display:flex;justify-content:center;align-items:center;min-width:32px;padding-right:16px;line-height:1;-moz-user-select:none;user-select:none;white-space:nowrap;cursor:inherit;outline:none;color:var(--color-dark-1)}:host .dot{display:flex;align-items:center;justify-content:space-between;min-width:36px;height:18px;padding:0 4px;margin-right:5px;line-height:14px;border-radius:16px;background:var(--color-plain-3);transition:box-shadow .2s ease,background .2s ease}:host .dot::before{display:block;width:14px;height:14px;border-radius:50%;background:#fff;content:""}:host .dot::after{display:flex;padding:0 2px;font-size:12px;content:attr(st);color:#fff}:host .dot.open{flex-direction:row-reverse;background:var(--color-teal-1)}`,
css`:host(:focus-within) .dot{box-shadow:0 0 0 2px var(--color-plain-a)}`,
// 尺寸
css`:host([size=m]){height:24px;font-size:12px}:host([size=m]) .dot{min-width:30px;height:16px;line-height:12px}:host([size=m]) .dot::before{width:12px;height:12px}:host([size=xl]){height:36px;font-size:14px}:host([size=xl]) .dot{min-width:35px;height:18px;line-height:14px}:host([size=xl]) .dot::before{width:14px;height:14px}:host([size=xxl]){height:44px;font-size:14px}:host([size=xxl]) .dot{min-width:35px;height:18px;line-height:14px}:host([size=xxl]) .dot::before{width:14px;height:14px}`,
// 配色
css`:host([type=primary]) .dot.open{background:var(--color-teal-1)}:host([type=primary]):host(:focus-within) .dot{box-shadow:0 0 0 2px var(--color-teal-a)}:host([type=info]) .dot.open{background:var(--color-blue-1)}:host([type=info]):host(:focus-within) .dot{box-shadow:0 0 0 2px var(--color-blue-a)}:host([type=success]) .dot.open{background:var(--color-green-1)}:host([type=success]):host(:focus-within) .dot{box-shadow:0 0 0 2px var(--color-green-a)}:host([type=warning]) .dot.open{background:var(--color-orange-1)}:host([type=warning]):host(:focus-within) .dot{box-shadow:0 0 0 2px var(--color-orange-a)}:host([type=danger]) .dot.open{background:var(--color-red-1)}:host([type=danger]):host(:focus-within) .dot{box-shadow:0 0 0 2px var(--color-red-a)}`,
// 状态
css`:host([readonly]),:host([disabled]){cursor:not-allowed;opacity:.6}:host([readonly]){cursor:default}`
];
toggleCheck(ev) {
if (this.disabled || this.readOnly) {
return;
}
ev.stopPropagation();
this.value = !this.value;
let data = {
value: this.value
};
this.$emit("input");
this.$emit("change", data);
}
handleClick(ev) {
if (ev.type === "click" || ev.keyCode === 32) {
ev.preventDefault();
this.toggleCheck(ev);
}
}
mounted() {
}
render() {
let classes = classMap({ dot: true, open: this.value });
return html` <label
tabindex=${this.disabled || this.readOnly ? "none" : 0}
@click=${this.handleClick}
@keydown=${this.handleClick}
>
<span
class=${classes}
st=${this.inlineText ? this.value ? this.activeText : this.inactiveText : ""}
></span>
<slot
>${!this.inlineText ? this.value ? this.activeText : this.inactiveText : ""}</slot
>
</label>`;
}
}
Switch.reg("switch");

View File

@ -0,0 +1,31 @@
import { css, svg, html, Component } from "wkit";
import SVG_DICT from "./svg.js";
let dict = SVG_DICT;
if (window.EXT_SVG_DICT) {
Object.assign(dict, EXT_SVG_DICT);
}
class Icon extends Component {
static props = {
name: {
type: String,
default: null,
observer(val) {
if (val === "") {
this.name = null;
}
}
}
};
static styles = css`:host{display:inline-flex;width:var(--wc-icon-size, 32px);height:var(--wc-icon-size, 32px)}:host(:not([name])){display:none}.icon{display:block;width:100%;height:100%;color:inherit;fill:currentColor}.icon.loading{animation:load 1.5s linear infinite}.icon circle{stroke:currentColor;animation:circle 1.5s ease-in-out infinite}:host([size=s]){width:20px;height:20px}:host([size=m]){width:24px;height:24px}:host([size=l]){width:32px;height:32px}:host([size=xl]){width:36px;height:36px}:host([size=xxl]){width:44px;height:44px}@keyframes circle{0%{stroke-dasharray:0,3812px;stroke-dashoffset:0}50%{stroke-dasharray:1906px,3812px;stroke-dashoffset:-287px}100%{stroke-dasharray:1906px,3812px;stroke-dashoffset:-2393px}}@keyframes load{to{transform:rotate(360deg)}}`;
render() {
return html`
<svg
class="icon ${this.name === "loading" ? "loading" : ""}"
viewBox="0 0 1024 1024"
>
${this.name === "loading" ? svg`<circle class="circle" cx="512" cy="512" r="384" fill="none" stroke-width="80" />` : svg`<path d="${dict[this.name]}" />`}
</svg>
`;
}
}
Icon.reg("icon");

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,327 @@
import { css, html, Component, bind, styleMap } from "wkit";
import "../form/input.js";
let uniqueInstance = null;
let toastInstance = null;
const LANG_TITLE = "\u63D0\u793A";
const LANG_BTNS = ["\u53D6\u6D88", "\u786E\u5B9A"];
const UNIQUE_TYPES = ["alert", "confirm", "prompt"];
const BUILDIN_TYPES = UNIQUE_TYPES.concat(["toast"]);
class Layer extends Component {
static animation = {};
static props = {
type: {
type: String,
default: null,
observer(v) {
this.#wrapped = !BUILDIN_TYPES.includes(v);
}
},
left: { type: String, attribute: false },
right: { type: String, attribute: false },
top: { type: String, attribute: false },
bottom: { type: String, attribute: false },
background: { type: String, attribute: false },
maskColor: { type: String, attribute: false },
mask: false,
maskClose: false,
title: { type: String, default: "", attribute: false },
content: { type: String, default: "", attribute: false },
btns: []
};
static styles = [
css`:host{display:none;justify-content:center;align-items:center;position:fixed;z-index:65534;left:0;top:0;width:100%;height:0}:host([type]){display:flex}:host([type=toast]) .layer,:host([type=common]) .layer{position:absolute}.noselect{-webkit-touch-callout:none;user-select:none}.noselect img,.noselect a{-webkit-user-drag:none}`,
css`.layer{flex:0 auto;position:relative;z-index:65535;border-radius:3px;color:#666;font-size:14px;background:rgba(255,255,255,.8);box-shadow:0 5px 20px rgba(0,0,0,.3);transition:opacity .2s ease-in-out,left .2s ease-in-out,right .2s ease-in-out,top .2s ease-in-out,bottom .2s ease-in-out}.layer:active{z-index:65536}`,
/* 弹层样式 */
css`.layer__title{display:flex;justify-content:space-between;align-items:center;width:100%;height:60px;padding:15px;font-size:16px;color:var(--color-dark-2)}.layer__title wc-icon{--wc-icon-size: 14px}.layer__title wc-icon:hover{color:var(--color-red-1)}.layer__content{display:flex;position:relative;width:100%;height:auto;min-height:50px;word-break:break-all;word-wrap:break-word}::slotted(.layer__content__input){flex:1}::slotted(.layer__content__toast){flex-shrink:0;flex:1;display:flex;align-items:center;width:300px;min-height:40px;margin-bottom:15px !important;padding:0 10px !important;border-radius:3px;font-weight:normal;text-indent:8px;--wc-icon-size: 16px;color:var(--color-dark-1);box-shadow:0 2px 12px rgba(0,0,0,.1)}::slotted(.layer__content__toast+.layer__content__toast){margin-top:30px}::slotted(.layer__content__toast.style-info){border:1px solid #ebeef5;background:#edf2fc;color:var(--color-grey-3)}::slotted(.layer__content__toast.style-success){border:1px solid #e1f3d8;background:#f0f9eb;color:var(--color-green-3)}::slotted(.layer__content__toast.style-warning){border:1px solid #faebb4;background:#faecd8;color:var(--color-red-1)}::slotted(.layer__content__toast.style-error){border:1px solid #f5c4c4;background:#fde2e2;color:var(--color-red-1)}.layer__ctrl{display:flex;justify-content:flex-end;width:100%;height:60px;padding:15px;line-height:30px;font-size:14px;color:#454545;text-align:right}.layer__ctrl button{min-width:64px;height:30px;padding:0 10px;margin:0 5px;border:1px solid var(--color-plain-3);border-radius:3px;white-space:nowrap;background:#fff;font-size:inherit;font-family:inherit;outline:none;color:inherit}.layer__ctrl button:hover{background:var(--color-plain-1)}.layer__ctrl button:active{border-color:var(--color-grey-1)}.layer__ctrl button:focus{box-shadow:0 0 0 2px var(--color-plain-a)}.layer__ctrl button:last-child{color:#fff;background:var(--color-teal-2);border-color:rgba(0,0,0,0)}.layer__ctrl button:last-child:hover{background:var(--color-teal-1)}.layer__ctrl button:last-child:active{background:var(--color-teal-3)}.layer__ctrl button:last-child:focus{box-shadow:0 0 0 2px var(--color-teal-a)}.layer__ctrl button::-moz-focus-inner{border:none}`,
css`:host([mask]){height:100%;background:rgba(0,0,0,.2)}:host([type=alert]) .layer,:host([type=confirm]) .layer,:host([type=prompt]) .layer{max-width:600px;min-width:300px;background:#fff}:host([type=alert]) .layer__content,:host([type=confirm]) .layer__content,:host([type=prompt]) .layer__content{padding:0 15px}:host([type=toast]) .layer{box-shadow:none;background:none}:host([type=toast]) .layer__content{flex-direction:column;min-height:40px}:host([blurry]) .layer{backdrop-filter:blur(5px)}`
];
#wrapped = false;
#resolve = null;
#reject = null;
constructor() {
super();
this.promise = new Promise((resolve, reject) => {
this.#resolve = resolve;
this.#reject = reject;
});
this.promise.host = this;
}
#intercept(value) {
if (this.intercept) {
this.intercept(value, (_) => {
delete this.intercept;
this.#resolve(value);
this.$animate(true);
this.$refs.box.$animate(true).then((_2) => this.close());
});
} else {
this.#resolve(value);
this.$animate(true);
this.$refs.box.$animate(true).then((_) => this.close());
}
}
#play() {
switch (this.type) {
case "toast":
let elem = this.lastElementChild;
elem._anim = elem.animate(
[
{ marginTop: "-30px", opacity: 0 },
{ marginTop: "0", opacity: 1 }
],
{
duration: 200,
fill: "forwards"
}
);
setTimeout(() => {
elem._anim.reverse();
elem._anim.onfinish = (_) => {
elem.remove();
if (this.children.length === 0) {
this.close();
toastInstance = null;
}
};
}, 3e3);
break;
default:
this.$animate();
this.$refs.box.$animate();
break;
}
}
mounted() {
if (this.type === "prompt") {
this.$refs.input = this.firstElementChild;
bind(this.$refs.input, "submit", (ev) => {
this.#intercept(ev.target.value);
});
} else if (this.type === "toast") {
this.style.display = "";
}
if (this.mask) {
this.$on("click", (ev) => {
let path = ev.composedPath();
if (path[0] === ev.currentTarget) {
if (UNIQUE_TYPES.includes(this.type)) {
return;
}
if (this.maskClose) {
if (this.#wrapped === false) {
this.#reject();
}
this.$refs.box.$animate(true).then((_) => this.close());
}
}
});
if (this.maskColor) {
this.style.backgroundColor = this.maskColor;
}
}
if (this.background) {
this.$refs.box.style.backgroundColor = this.background;
}
this.#play();
}
updated() {
this.#play();
}
moveTo(obj = {}) {
var css2 = "";
for (var k in obj) {
css2 += `${k}:${obj[k]};`;
}
this.$refs.box.style.cssText += css2;
}
show() {
if (this.#wrapped) {
this.type = "common";
}
}
/**
* 关闭实例
*/
close() {
if (this.#wrapped) {
this.type = null;
this.$emit("close");
} else {
if (UNIQUE_TYPES.includes(this.type)) {
uniqueInstance = null;
}
this.$emit("close");
this.remove();
}
}
// 按钮的点击事件
handleBtnClick(ev) {
if (ev.target.tagName === "BUTTON") {
let idx = +ev.target.dataset.idx || 0;
switch (this.type) {
case "alert":
this.#intercept(null);
break;
case "confirm":
case "prompt":
if (idx === 0) {
this.#reject();
this.$animate(true);
this.$refs.box.$animate(true).then((_) => this.close());
} else {
let value = this.type === "prompt" ? this.$refs.input.value : null;
this.#intercept(value);
}
break;
default:
this.#intercept(idx);
break;
}
}
}
render() {
let { type, mask, left, right, top, bottom } = this;
let styles = "";
if (type === "common" && mask === false) {
top = top || 0;
}
styles = styleMap({ left, right, top, bottom });
return html`
<div
ref="box"
class="layer"
#animation=${{ type: "micro-bounce" }}
style=${styles}
>
<div
class="layer__title noselect"
style=${styleMap({ display: !!this.title ? "" : "none" })}
>
${this.title}
</div>
<div class="layer__content">
<slot></slot>
</div>
<div
class="layer__ctrl noselect"
style=${styleMap({ display: this.btns.length ? "" : "none" })}
@click=${this.handleBtnClick}
>
${this.btns.map((s, i) => html`<button data-idx=${i}>${s}</button>`)}
</div>
</div>
`;
}
}
function layer(opt = {}) {
let { type = "common", content = "" } = opt;
let layDom = type === "toast" ? toastInstance || document.createElement("wc-layer") : document.createElement("wc-layer");
let alreadyInTree = type === "toast" && !!toastInstance;
layDom.type = opt.type;
if (type === "toast") {
toastInstance = layDom;
layDom.top = "20px";
} else {
if (opt.btns && opt.btns.length) {
layDom.btns = opt.btns;
}
if (opt.intercept && typeof opt.intercept === "function") {
layDom.intercept = opt.intercept;
}
layDom.mask = opt.mask;
layDom.title = opt.title;
if (UNIQUE_TYPES.includes(type)) {
if (uniqueInstance) {
uniqueInstance.$animate(true).then((_) => {
uniqueInstance.close();
uniqueInstance = layDom;
});
} else {
uniqueInstance = layDom;
}
}
}
if (alreadyInTree) {
let tmp = document.createElement("template");
tmp.innerHTML = content;
layDom.appendChild(tmp.content.cloneNode(true));
layDom.updated();
} else {
layDom.innerHTML = content;
document.body.appendChild(layDom);
}
return layDom.promise;
}
layer.alert = function(content, title = LANG_TITLE, btns = LANG_BTNS.slice(1)) {
if (typeof title === "object") {
btns = title;
title = LANG_TITLE;
}
return this({
type: "alert",
title,
content,
mask: true,
btns
});
};
layer.confirm = function(content, title = LANG_TITLE, btns = LANG_BTNS.concat()) {
if (typeof title === "object") {
btns = title;
title = LANG_TITLE;
}
return this({
type: "confirm",
title,
content,
mask: true,
btns
});
};
layer.prompt = function(title = LANG_TITLE, defaultValue = "", intercept) {
if (typeof defaultValue === "function") {
intercept = defaultValue;
defaultValue = "";
}
if (!intercept) {
intercept = function(val, done) {
if (val) {
done();
}
};
}
return this({
type: "prompt",
title,
content: `<wc-input autofocus class="layer__content__input" value="${defaultValue}"></wc-input>`,
mask: true,
intercept,
btns: LANG_BTNS.concat()
});
};
layer.toast = function(txt, type = "info") {
var ico = type;
switch (type) {
case "info":
case "warning":
break;
case "error":
ico = "deny";
break;
case "success":
ico = "get";
break;
default:
ico = "info";
}
return this({
content: `
<div class="layer__content__toast style-${type}">
<wc-icon name="${ico}"></wc-icon>
<span class="toast-txt">${txt}</span>
</div>`,
type: "toast"
});
};
Layer.reg("layer");
window.layer = layer;

View File

@ -0,0 +1,8 @@
import { css, html, Component } from "wkit";
class Space extends Component {
static styles = css`:host{display:block}.container{display:flex;flex-wrap:wrap;align-items:center;width:100%;padding:6px 0;gap:12px}:host([vertical]) .container{flex-direction:column}:host([justify]) .container{justify-content:space-between}:host([gap=s]) .container{padding:2px 0;gap:4px}:host([gap=m]) .container{padding:4px 0;gap:8px}:host([gap=l]) .container{padding:6px 0;gap:12px}:host([gap=xl]) .container{padding:8px 0;gap:16px}:host([gap=xxl]) .container{padding:10px 0;gap:20px}:host([gap=xxxl]) .container{padding:12px 0;gap:24px}`;
render() {
return html`<div class="container"><slot /></div>`;
}
}
Space.reg("space");

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,54 @@
var G=Object.defineProperty;var Z=(i,e,t)=>e in i?G(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t;var d=(i,e,t)=>(Z(i,typeof e!="symbol"?e+"":e,t),t),q=(i,e,t)=>{if(!e.has(i))throw TypeError("Cannot "+t)};var E=(i,e,t)=>(q(i,e,"read from private field"),t?t.call(i):e.get(i)),m=(i,e,t)=>{if(e.has(i))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(i):e.set(i,t)},T=(i,e,t,o)=>(q(i,e,"write to private field"),o?o.call(i,t):e.set(i,t),t);var C=(i,e,t)=>(q(i,e,"access private method"),t);import"wkit";var c=Symbol("router"),h=Symbol("router-view"),y=Symbol("store"),x=new Set;var P=class extends WeakMap{broadcast(){for(let e of x)e.$requestUpdate()}assign(e){x.add(e)}deassign(e){x.add(e)}},F=new P;Object.defineProperty(window,"wkitd",{get(){return F},set(i){console.error("Can not set readonly property wkitd of window")},enumerable:!1});import{html as K,css as oe,Component as ie}from"wkit";var J=encodeURIComponent,W=decodeURIComponent;function w(){}function U(i,e,t){var o;if(Array.isArray(e))e.forEach(function(r,s){o=i?`${i}[${Array.isArray(r)?s:""}]`:s,typeof r=="object"?U(o,r,t):t(o,r)});else for(let r in e)o=i?`${i}[${r}]`:r,typeof e[r]=="object"?U(o,e[r],t):t(o,e[r])}function H(i=""){let e=new URLSearchParams(i),t=Object.create(null);for(let[o,r]of e.entries()){let s=W(o),n=W(r),a=0;if(/(\w+)\[(\w*?)\]/.test(s)){let u=RegExp.$1,l=RegExp.$2;s=u,!l||+l==+l?(n=[n],a|=2):(a|=1,n={[l]:n})}t[s]?a&2?t[s]=t[s].concat(n):a&1?Object.assign(t[s],n):(Array.isArray(t[n])||(t[s]=[t[s]]),t[s].push(n)):t[s]=n}return t}function k(i={}){if(i===null)return"";if(typeof i=="string"||typeof i=="number"||typeof i=="boolean")return i;let e=[];return typeof i=="object"&&U("",i,function(o,r){e.push(o+"="+J(r))}),e.join("&")}import{Component as te}from"wkit";import{bind as V}from"wkit";var Y=/^(#!|#)[\/]+?/,B=/(\/[^/]*)(:[A-Za-z0-9_]+)(\?)?/g,v="hash",L="history",O=class{type=v;#e=new Map;#s=new Set;#n=new Map;#t=!1;#r=Object.create(null);#o;constructor(e=v){this.type=e,V(window,"popstate",this.#i.bind(this))}get route(){return this.#r}get views(){return Array.from(this.#s)}#i(e){this.#t&&this.#p()}#h(e){if(e.path==="!")e.regexp=null;else{let t=[],o;if(e.path.includes("?")&&e.path.at(-1)!=="?")throw new SyntaxError(`The exp "?" can only be used in the last.
${JSON.stringify(e)}
`);o=e.path.replace(B,function(r,s,n,a){return t.push(n.slice(1)),s==="/"&&(s="/?"),s+"([A-Za-z0-9_]+)"+a}),o="^"+o+"$",e.regexp=new RegExp(o),e.vars=t}return e}#a(e){if(e.path!=="!"&&e.path[0]!=="/"){console.error('route path must start with "/"');return}e.path=e.path.replace(/^[\/]+|[\/]+$|\s+/g,"/"),this.#e.set(e.path,this.#h(e)),this.#s.add(e.name)}#p(){let e=this.type===v,t=window.wkitd.get(h),o=location.hash,r=e?location.hash:location.href.replace(location.origin,"").replace(o,""),s;if(r.includes("?")&&([r,s]=r.split("?")),r=r.replace(Y,"/"),!(!t||r===this.#r.path)){for(let[n,a]of this.#e){let u=r.match(a.regexp);if(u){let l=Object.create(null);for(let b=1;b<u.length;b++)l[[a.vars[b-1]]]=u[b];let A={path:r,name:a.name,params:l,query:H(s)};return this.#o?this.#o(this.route,A,()=>{this.#l(A)}):this.#l(A)}}if(this.#e.get("!")){let n=this.#e.get("!");t.current=n.name,this.#r={path:r,name:n.name,params:{},query:{}}}}}#l(e){let t=window.wkitd.get(h);t.current=e.name,this.#r=e,this.#c()}#c(){for(let[e,t]of this.#n)t.call(e,this.route)}init(){this.#t=!0,this.#i()}rsync(e,t){this.#n.set(e,t),this.#t&&this.#c()}beforeEach(e=w){this.#o=e}addRoute(e){Array.isArray(e)?e.forEach(t=>{this.#a(t)}):this.#a(e),this.#t&&this.#i()}go(e=0){history.go(e)}back(){this.go(-1)}forward(){this.go(1)}push(e={path:"",query:{}},t=!1){let o="",r="";typeof e=="string"?o=e.trim():(r=k(e.query||""),o=e.path+(r?`?${r}`:"")),!(!o&&o===location.hash.slice(1))&&(this.type===v?t?location.replace(o.replace(/^\//,"#/")):location.hash=o:(t?window.history.replaceState({path:o},null,o+r):window.history.pushState({path:o},null,o+r),this.#p()))}replace(e={path:"",query:{}}){this.push(e,!0)}};function M(){return()=>new O}function Q(){return()=>new O(L)}import{Component as j,html as ee,css as D,raw as I}from"wkit";var $,_=class extends j{constructor(){super(...arguments);m(this,$,[])}created(){window.wkitd.set(h,this)}sync(t){T(this,$,t)}render(){let t={immediate:!0,custom:[{transform:"translateX(-32px)",opacity:0},{transform:"translateX(0)",opacity:1}]};if(this.keepAlive){let o=E(this,$).map(r=>[this.transition?`<${r} ref="${r}" :__keep_alive__="%s" #animation="%s" style="%s"></${r}>`:`<${r} ref="${r}" :__keep_alive__="%s" style=%s></${r}>`,[this.current===r,{...t,immediate:this.current===r},this.current===r?"":"display:none"]]);return I(o.map(r=>r[0]).join(""),o.map(r=>r[1]).flat())}else if(this.current)return this.transition?I(`<${this.current} #animation="%s"></${this.current}>`,[t]):I(`<${this.current}></${this.current}>`)}};$=new WeakMap,d(_,"props",{keepAlive:!1,transition:!1,current:{type:String,default:"",attribute:!1,observer(t,o){this.keepAlive&&t&&(o&&this.$refs[o]&&this.$refs[o].deactivated(),this.$refs[t]?.$requestUpdate(),this.$refs[t]?.$animate(),this.$refs[t]?.activated())}}}),d(_,"styles",D`
:host {
display: block;
}
`);var f,R,N,S,X,g=class extends j{constructor(){super(...arguments);m(this,R);m(this,S);m(this,f,"")}mounted(){this.$router.rsync(this,t=>{this.classList.toggle("active",t.path===this.to.path)})}render(){return T(this,f,C(this,S,X).call(this)),ee`<a title=${E(this,f)} @click=${C(this,R,N)}>
<slot></slot
></a>`}};f=new WeakMap,R=new WeakSet,N=function(){let t=this.$router.type,{path:o}=this.to;this.disabled||(t==="hash"?location.hash=E(this,f):this.$router.push(this.to))},S=new WeakSet,X=function(){let t=this.$router.type,{path:o="",query:r={}}=this.to,s=typeof r=="string"?r.replaceAll("?",""):k(r);return o=o.replace(/^\//,""),s&&(o+="?"+s),"/"+o},d(g,"props",{to:Object,disabled:!1}),d(g,"styles",D`
:host {
display: inline-flex;
align-items: center;
-webkit-user-select: none;
user-select: none;
}
a {
display: flex;
align-items: center;
width: 100%;
height: 100%;
color: inherit;
text-decoration: inherit;
cursor: pointer;
}
:host([disabled]) a {
opacity: 0.6;
cursor: not-allowed;
}
`);customElements.get("router-view")||customElements.define("router-view",_);customElements.get("router-link")||customElements.define("router-link",g);function ke({history:i=M(),routes:e=[]}={}){let t=i();window.wkitd.set(c,t),t.addRoute(e);function o(){Object.defineProperty(te.prototype,"$router",{get(){return window.wkitd.get(c)},set(r){console.error("Can not set readonly property $router of Component")},enumerable:!1})}return o.beforeEach=t.beforeEach.bind(t),o}import{Component as z}from"wkit";function re(i={}){let e=!1;return function(){Object.defineProperty(z.prototype,"$store",{get(){return window.wkitd.get(y)},set(t){if(e)return console.error("Can not set readonly property $store of Component");window.wkitd.set(y,new Proxy(t,{set(o,r,s){return o[r]=s,window.wkitd.broadcast(),!0}})),e=!0},enumerable:!1}),z.prototype.$store=i}}var p=class extends ie{};function Pe({data:i={},styles:e=[],methods:t={},mounted:o=w,render:r}={}){return new function(){p.props=i,p.styles=e,Object.assign(p.prototype,t,{mounted:o}),this.use=function(s=w,...n){return s.apply(p.prototype,n),this},this.mount=function(){let s=window.wkitd.get(c);r?p.prototype.render=r:s?p.prototype.render=function(){return K`<router-view></router-view>`}:(p.styles=oe`
:host {
font-family: monospace;
color: #647889;
}
.code {
margin: 16px 0;
background: #f7f8fb;
}
`,p.prototype.render=function(){return K`
<h1>It works!!!</h1>
<cite>
If you don't use router, you may define the
<b>render</b> property.
</cite>
<div class="code">
<pre><code> createApp({</code></pre>
<pre><code> render() {</code></pre>
<pre><code> return html\`&lt;wc-home&gt;&lt;/wc-home&gt;\`</code></pre>
<pre><code> }</code></pre>
<pre><code> })</code></pre>
<pre><code> .mount()</code></pre>
</div>
`}),s&&(p.prototype.mounted=function(...n){let a=window.wkitd.get(h);if(a)a.sync(s.views),s.init(),o.call(this,...n);else throw new Error('<router-view /> not found, "Router" works Unexpected.')}),p.reg("app")}}}function Ue(){return window.wkitd.get(y)}function Ie(){return window.wkitd.get(c)}function We(){return window.wkitd.get(c)?.route}export{Pe as createApp,ke as createRouter,re as createStore,M as createWebHashHistory,Q as createWebHistory,We as getCurrentPage,Ie as getRouter,Ue as getStore};

View File

@ -0,0 +1,20 @@
#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class Window(Gtk.Window):
def __init__(self, title = 'Untitled window', width = 760, height = 480):
Gtk.Window.__init__(self, title = title)
self.set_default_size(width, height)
self.resize(width, height)
def toggle_visible(self, icon):
if self.is_visible():
self.hide()
else:
self.present()