mirror of
https://github.com/bestnite/sub2clash.git
synced 2025-10-25 16:51:01 +00:00
refactor(frontend): Extract short link UI into dedicated component
This commit is contained in:
@@ -7,6 +7,7 @@ import { base64EncodeUnicode, base64decodeUnicode } from "./utils.js";
|
||||
import "./components/rule-provider-input.js";
|
||||
import "./components/rule-input.js";
|
||||
import "./components/rename-input.js";
|
||||
import "./components/short-link-input-group.js";
|
||||
|
||||
@customElement("sub2clash-app")
|
||||
export class Sub2clashApp extends LitElement {
|
||||
@@ -145,6 +146,7 @@ export class Sub2clashApp extends LitElement {
|
||||
// 设置返回的短链ID和密码
|
||||
this.shortLinkID = response.data.id;
|
||||
this.shortLinkPasswd = response.data.password;
|
||||
this.showDialog("成功", "生成短链成功");
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response && error.response.data) {
|
||||
@@ -183,11 +185,11 @@ export class Sub2clashApp extends LitElement {
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
this.showDialog("成功", "更新成功");
|
||||
this.showDialog("成功", "更新短链成功");
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response && error.response.status === 401) {
|
||||
this.showDialog("", "密码错误");
|
||||
this.showDialog("", "短链不存在或密码错误");
|
||||
} else if (error.response && error.response.data) {
|
||||
this.showDialog("", "更新短链失败:" + error.response.data);
|
||||
} else {
|
||||
@@ -214,7 +216,7 @@ export class Sub2clashApp extends LitElement {
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
this.showDialog("成功", "删除成功");
|
||||
this.showDialog("成功", "删除短链成功");
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response && error.response.status === 401) {
|
||||
@@ -609,8 +611,7 @@ export class Sub2clashApp extends LitElement {
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset mb-8">
|
||||
<legend
|
||||
class="fieldset-legend text-2xl font-semibold mb-4 text-center">
|
||||
<legend class="fieldset-legend text-2xl font-semibold mb-4">
|
||||
输出配置
|
||||
</legend>
|
||||
|
||||
@@ -637,55 +638,19 @@ export class Sub2clashApp extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-control mb-2">
|
||||
<div class="join w-full">
|
||||
<input
|
||||
class="input input-bordered w-1/2 join-item"
|
||||
type="text"
|
||||
placeholder="ID(可选)"
|
||||
.value="${this.shortLinkID}"
|
||||
@change="${(e: Event) => {
|
||||
this.shortLinkID = (e.target as HTMLInputElement).value;
|
||||
}}" />
|
||||
<input
|
||||
class="input input-bordered w-1/2 join-item"
|
||||
type="text"
|
||||
placeholder="密码"
|
||||
.value="${this.shortLinkPasswd}"
|
||||
@change="${(e: Event) => {
|
||||
this.shortLinkPasswd = (e.target as HTMLInputElement).value;
|
||||
}}" />
|
||||
<button
|
||||
class="btn btn-primary join-item"
|
||||
type="button"
|
||||
@click="${this.generateShortLink}">
|
||||
生成短链
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary join-item"
|
||||
@click="${this.updateShortLink}"
|
||||
type="button">
|
||||
更新短链
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary join-item"
|
||||
@click="${this.deleteShortLink}"
|
||||
type="button">
|
||||
删除短链
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary join-item"
|
||||
type="button"
|
||||
@click="${(e: Event) => {
|
||||
this.copyToClipboard(
|
||||
`${window.location.origin}${window.location.pathname}s/${this.shortLinkID}?password=${this.shortLinkPasswd}`,
|
||||
e.target as HTMLButtonElement
|
||||
);
|
||||
}}">
|
||||
复制短链
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<short-link-input-group
|
||||
.id="${this.shortLinkID}"
|
||||
.passwd="${this.shortLinkPasswd}"
|
||||
@id-change="${(e: Event) => {
|
||||
this.shortLinkID = (e.target as HTMLInputElement).value;
|
||||
}}"
|
||||
@passwd-change="${(e: Event) => {
|
||||
this.shortLinkPasswd = (e.target as HTMLInputElement).value;
|
||||
}}"
|
||||
@generate-btn-click="${this.generateShortLink}"
|
||||
@update-btn-click="${this.updateShortLink}"
|
||||
@delete-btn-click="${this.deleteShortLink}">
|
||||
</short-link-input-group>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
180
server/frontend/src/components/short-link-input-group.ts
Normal file
180
server/frontend/src/components/short-link-input-group.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
import { html, LitElement, unsafeCSS } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import globalStyles from "../index.css?inline";
|
||||
|
||||
@customElement("short-link-input-group")
|
||||
export class ShortLinkInputGroup extends LitElement {
|
||||
static styles = unsafeCSS(globalStyles);
|
||||
|
||||
@property()
|
||||
id: string = "";
|
||||
|
||||
@property({ type: Number })
|
||||
_screenSizeLevel: number = 0;
|
||||
|
||||
@property()
|
||||
passwd: string = "";
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
window.addEventListener("resize", this._checkScreenSize);
|
||||
this._checkScreenSize(); // Initial check
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
window.removeEventListener("resize", this._checkScreenSize);
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
|
||||
_checkScreenSize = () => {
|
||||
const width = window.innerWidth;
|
||||
if (width < 365) {
|
||||
this._screenSizeLevel = 0; // sm
|
||||
} else if (width < 640) {
|
||||
this._screenSizeLevel = 1; // md
|
||||
} else {
|
||||
this._screenSizeLevel = 2; // other
|
||||
}
|
||||
};
|
||||
|
||||
async copyToClipboard(content: string, e: HTMLButtonElement) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(content);
|
||||
let text = e.textContent;
|
||||
e.addEventListener("mouseout", function () {
|
||||
e.textContent = text;
|
||||
});
|
||||
e.textContent = "复制成功";
|
||||
} catch (err) {
|
||||
console.error("复制到剪贴板失败:", err);
|
||||
}
|
||||
}
|
||||
|
||||
idInputTemplate() {
|
||||
return html`<input
|
||||
class="input input-bordered w-1/2 join-item"
|
||||
type="text"
|
||||
placeholder="ID(可选)"
|
||||
.value="${this.id}"
|
||||
@change="${(e: Event) => {
|
||||
this.id = (e.target as HTMLInputElement).value;
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("id-change", {
|
||||
detail: this.id,
|
||||
})
|
||||
);
|
||||
}}" />`;
|
||||
}
|
||||
|
||||
passwdInputTemplate() {
|
||||
return html`<input
|
||||
class="input input-bordered w-1/2 join-item"
|
||||
type="text"
|
||||
placeholder="密码"
|
||||
.value="${this.passwd}"
|
||||
@change="${(e: Event) => {
|
||||
this.passwd = (e.target as HTMLInputElement).value;
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("passwd-change", {
|
||||
detail: this.passwd,
|
||||
})
|
||||
);
|
||||
}}" />`;
|
||||
}
|
||||
|
||||
generateBtnTemplate(extraClass: string = "") {
|
||||
return html`<button
|
||||
class="btn btn-primary join-item ${extraClass}"
|
||||
type="button"
|
||||
@click="${(e: Event) => {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("generate-btn-click", { detail: e })
|
||||
);
|
||||
}}">
|
||||
生成短链
|
||||
</button>`;
|
||||
}
|
||||
|
||||
updateBtnTemplate(extraClass: string = "") {
|
||||
return html`<button
|
||||
class="btn btn-primary join-item ${extraClass}"
|
||||
@click="${(e: Event) => {
|
||||
this.dispatchEvent(new CustomEvent("update-btn-click", { detail: e }));
|
||||
}}"
|
||||
type="button">
|
||||
更新短链
|
||||
</button>`;
|
||||
}
|
||||
|
||||
deleteBtnTemplate(extraClass: string = "") {
|
||||
return html`<button
|
||||
class="btn btn-primary join-item ${extraClass}"
|
||||
@click="${(e: Event) => {
|
||||
this.dispatchEvent(new CustomEvent("delete-btn-click", { detail: e }));
|
||||
}}"
|
||||
type="button">
|
||||
删除短链
|
||||
</button>`;
|
||||
}
|
||||
|
||||
copyBtnTemplate(extraClass: string = "") {
|
||||
return html`<button
|
||||
class="btn btn-primary join-item ${extraClass}"
|
||||
type="button"
|
||||
@click="${(e: Event) => {
|
||||
this.copyToClipboard(
|
||||
`${window.location.origin}${window.location.pathname}s/${this.id}?password=${this.passwd}`,
|
||||
e.target as HTMLButtonElement
|
||||
);
|
||||
}}">
|
||||
复制短链
|
||||
</button>`;
|
||||
}
|
||||
|
||||
render() {
|
||||
const sm = html`<div class="form-control mb-2">
|
||||
<div class="join w-full mb-1">
|
||||
${this.idInputTemplate()} ${this.passwdInputTemplate()}
|
||||
</div>
|
||||
<div class="join w-full mb-1">
|
||||
${this.generateBtnTemplate("w-1/2")} ${this.updateBtnTemplate("w-1/2")}
|
||||
</div>
|
||||
<div class="join w-full">
|
||||
${this.deleteBtnTemplate("w-1/2")} ${this.copyBtnTemplate("w-1/2")}
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
const md = html`<div class="form-control mb-2">
|
||||
<div class="join w-full mb-1">
|
||||
${this.idInputTemplate()} ${this.passwdInputTemplate()}
|
||||
</div>
|
||||
<div class="join w-full">
|
||||
${this.generateBtnTemplate("w-1/4")} ${this.updateBtnTemplate("w-1/4")}
|
||||
${this.deleteBtnTemplate("w-1/4")} ${this.copyBtnTemplate("w-1/4")}
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
const other = html`<div class="form-control mb-2">
|
||||
<div class="join w-full">
|
||||
${this.idInputTemplate()} ${this.passwdInputTemplate()}
|
||||
${this.generateBtnTemplate()} ${this.updateBtnTemplate()}
|
||||
${this.deleteBtnTemplate()} ${this.copyBtnTemplate()}
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
switch (this._screenSizeLevel) {
|
||||
case 0:
|
||||
return sm;
|
||||
case 1:
|
||||
return md;
|
||||
default:
|
||||
return other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"short-link-input-group": ShortLinkInputGroup;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user