修改为python + gtk开发
parent
1f8f16fb36
commit
4a80a18cc3
|
@ -7,10 +7,5 @@
|
|||
.Trashes
|
||||
|
||||
|
||||
build
|
||||
build/**
|
||||
|
||||
node_modules
|
||||
node_modules/**
|
||||
|
||||
package-lock.json
|
||||
__pycache__
|
||||
*.txt
|
|
@ -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解析的操作界面.
|
15
package.json
15
package.json
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
export RUN_ENV='development'
|
||||
|
||||
|
||||
./usr/lib/hosts-switch/hosts-switch.py
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
/usr/lib/hosts-switch/hosts-switch.py
|
|
@ -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
|
||||
|
|
@ -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()
|
|
@ -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')
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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");
|
|
@ -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");
|
|
@ -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");
|
|
@ -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");
|
|
@ -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
|
@ -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;
|
|
@ -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
|
@ -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\`<wc-home></wc-home>\`</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};
|
|
@ -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()
|
Loading…
Reference in New Issue