From 6fad1bd55f06e30e9339271191581320e80f1744 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Sun, 27 Aug 2023 16:39:46 +0800 Subject: [PATCH] Update settings page --- components/StringRecordsBox.tsx | 183 +++++++++++++++++++++++++++++++ islands/Settings.tsx | 16 +++ static/common.css | 15 +++ translation/en/settings.jsonc | 3 +- translation/zh-cn/settings.jsonc | 3 +- 5 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 components/StringRecordsBox.tsx diff --git a/components/StringRecordsBox.tsx b/components/StringRecordsBox.tsx new file mode 100644 index 0000000..40d285c --- /dev/null +++ b/components/StringRecordsBox.tsx @@ -0,0 +1,183 @@ +import { Component, ContextType, createContext } from "preact"; +import BMd3TextField from "./BMd3TextField.tsx"; +import { MdTonalButton } from "../server/dmodule.ts"; + +type CtxProps = { + set_value: (index: number, key?: string, value?: string) => void; + append: () => void; + delete: (index: number) => void; + sign: string; +}; + +const Ctx = createContext(null); + +type SRProps = { + k?: string; + value?: string; + index: number; + disable?: boolean; +}; + +type SRState = { + k: string; + value: string; +}; + +class StringRecord extends Component { + static contextType = Ctx; + declare context: ContextType; + constructor(props: SRProps) { + super(props); + this.state = { k: props.k || "", value: props.value || "" }; + } + componentWillReceiveProps( + nextProps: Readonly, + nextContext: unknown, + ): void { + this.setState({ k: nextProps.k || "", value: nextProps.value || "" }); + } + render() { + if (!MdTonalButton.value) return null; + const Button = MdTonalButton.value; + return ( +
+ { + this.context?.set_value( + this.props.index, + k, + this.state.value, + ); + this.setState({ k, value: this.state.value }); + }} + /> + {this.context?.sign || "="} + { + this.context?.set_value( + this.props.index, + this.state.k, + v, + ); + this.setState({ k: this.state.k, value: v }); + }} + /> + + +
+ ); + } +} + +type State = { + list: SRProps[]; + append: () => void; + set_value: (index: number, key?: string, value?: string) => void; + delete: (index: number) => void; +}; + +type Props = { + value: Record; + set_value?: (v: Record) => void; + sign?: string; +}; + +export default class StringRecordsBox extends Component { + index = 0; + constructor(props: Props) { + super(props); + const keys = Object.getOwnPropertyNames(props.value); + this.state = { + list: keys.length + ? keys.map((k) => { + return { k: k, value: props.value[k], index: this.index++ }; + }) + : [{ index: this.index++ }], + append: () => { + this.append(); + }, + set_value: (index, key, value) => { + this.set_value(index, key, value); + }, + delete: (index) => { + this.delete(index); + }, + }; + } + append() { + this.state.list.push({ index: this.index++ }); + this.forceUpdate(); + } + delete(index: number) { + const i = this.state.list.findIndex((i) => i.index === index); + if (i === -1) return; + const d = this.state.list.splice(i, 1)[0]; + if (d.k) { + delete this.props.value[d.k]; + if (this.props.set_value) this.props.set_value(this.props.value); + } + this.forceUpdate(); + } + set_value(index: number, key?: string, value?: string) { + const i = this.state.list.findIndex((i) => i.index === index); + let changed = false; + let pkey: string | undefined; + if (i !== -1) { + pkey = this.state.list[i].k; + this.state.list[i] = { index, k: key, value }; + } + console.log(index, i, key, pkey, value); + if (pkey !== undefined && pkey !== "" && pkey !== key) { + delete this.props.value[pkey]; + changed = true; + } + if (key !== undefined) { + if (value !== undefined) this.props.value[key] = value; + else delete this.props.value[key]; + changed = true; + } + if (changed && this.props.set_value) { + this.props.set_value(this.props.value); + } + } + render() { + return ( +
+ { type="text" outlined={true} /> +
+ + { + set_changed((v) => { + v.add("meili_hosts"); + return v; + }); + }} + /> +
diff --git a/static/common.css b/static/common.css index b735114..610aa50 100644 --- a/static/common.css +++ b/static/common.css @@ -362,6 +362,21 @@ div.new_task div.content .text .mdc-text-field { margin-top: 6px; } +div.string-record { + display: inline-flex; + line-height: 56px; +} + +div.string-record > div.b-text-field.md3.text { + margin: 0 5px; +} + +div.string-records-box { + display: inline-grid; + display: -ms-inline-grid; + display: -moz-inline-grid; +} + @media (max-width:1280px) { .settings { margin: 0; diff --git a/translation/en/settings.jsonc b/translation/en/settings.jsonc index 2f99a1b..b12e765 100644 --- a/translation/en/settings.jsonc +++ b/translation/en/settings.jsonc @@ -30,5 +30,6 @@ "thumbnail_method1": "ffmpeg API", "thumbnail_dir": "The folder used to store thumbnails: ", "remove_previous_gallery": "Remove old galleries which replaced by new ones.", - "img_verify_secret": "The secret of image verify: " + "img_verify_secret": "The secret of image verify: ", + "meili_hosts": "Meilie search server host returned by API with specific host: " } diff --git a/translation/zh-cn/settings.jsonc b/translation/zh-cn/settings.jsonc index 07d1b2e..5d0b7d8 100644 --- a/translation/zh-cn/settings.jsonc +++ b/translation/zh-cn/settings.jsonc @@ -30,5 +30,6 @@ "thumbnail_method1": "FFMPEG API", "thumbnail_dir": "存放缩略图的文件夹:", "remove_previous_gallery": "移除被新画廊替代的旧画廊。", - "img_verify_secret": "用于验证图片verify的密钥:" + "img_verify_secret": "用于验证图片verify的密钥:", + "meili_hosts": "为指定域名API将返回专门的Meilisearch服务器主机:" }