diff --git a/client/ui/preference/Preference.tsx b/client/ui/preference/Preference.tsx new file mode 100644 index 0000000..b3811d7 --- /dev/null +++ b/client/ui/preference/Preference.tsx @@ -0,0 +1,13 @@ +import { $ } from 'mdui/jq' +import { Switch } from 'mdui' +import React from 'react' +import useEventListener from '../useEventListener.ts' + +export default function Preference({ title, icon, disabled, description, ...props } = { + disabled: false, +}) { + return + {title} + {description && {description}} + +} \ No newline at end of file diff --git a/client/ui/preference/PreferenceHeader.tsx b/client/ui/preference/PreferenceHeader.tsx new file mode 100644 index 0000000..c6ca694 --- /dev/null +++ b/client/ui/preference/PreferenceHeader.tsx @@ -0,0 +1,3 @@ +export default function PreferenceHeader({ title }) { + return {title} +} \ No newline at end of file diff --git a/client/ui/preference/PreferenceLayout.tsx b/client/ui/preference/PreferenceLayout.tsx new file mode 100644 index 0000000..a34a5ad --- /dev/null +++ b/client/ui/preference/PreferenceLayout.tsx @@ -0,0 +1,8 @@ +export default function PreferenceLayout({ children, ...props }) { + return + {children} + +} \ No newline at end of file diff --git a/client/ui/preference/PreferenceStore.ts b/client/ui/preference/PreferenceStore.ts new file mode 100644 index 0000000..5f2a8b5 --- /dev/null +++ b/client/ui/preference/PreferenceStore.ts @@ -0,0 +1,23 @@ +import React from 'react' + +export default class PreferenceStore { + constructor() { + const _ = React.useState<{ [key: string]: unknown }>({}) + this.value = _[0] + this.setter = _[1] + } + // 创建一个用于子选项的更新函数 + updater(key: string) { + return (value: unknown) => { + const newValue = JSON.parse(JSON.stringify({ + ...this.value, + [key]: value, + })) + this.setter(newValue) + this.onUpdate?.(newValue) + } + } + setOnUpdate(onUpdate) { + this.onUpdate = onUpdate + } +} diff --git a/client/ui/preference/SelectPreference.tsx b/client/ui/preference/SelectPreference.tsx new file mode 100644 index 0000000..f01a2be --- /dev/null +++ b/client/ui/preference/SelectPreference.tsx @@ -0,0 +1,38 @@ +import { $ } from 'mdui/jq' +import React from 'react' +import { Dropdown } from 'mdui' +import useEventListener from '../useEventListener.ts' + +// value as { [id: string]: string } +export default function SelectPreference({ title, icon, updater, selections, defaultCheckedId, disabled } = { + disabled: false, +}) { + const [ checkedId, setCheckedId ] = React.useState(defaultCheckedId) + + const dropDownRef = React.useRef(null) + const [isDropDownOpen, setDropDownOpen] = React.useState(false) + + useEventListener(dropDownRef, 'closed', (e) => { + setDropDownOpen(false) + }) + + return setDropDownOpen(!isDropDownOpen)}> + + { title } + { + e.stopPropagation() + setDropDownOpen(false) + }}> + { + Object.keys(selections).map((id) => + { + setCheckedId(id) + updater(id) + }}>{selections[id]} + ) + } + + + { selections[checkedId] } + +} \ No newline at end of file diff --git a/client/ui/preference/SwitchPreference.tsx b/client/ui/preference/SwitchPreference.tsx new file mode 100644 index 0000000..69bb271 --- /dev/null +++ b/client/ui/preference/SwitchPreference.tsx @@ -0,0 +1,19 @@ +import { $ } from 'mdui/jq' +import { Switch } from 'mdui' +import React from 'react' +import useEventListener from '../useEventListener.ts' + +export default function SwitchPreference({ title, icon, updater, disabled, description } = { + disabled: false, +}) { + const switchRef = React.useRef(null) + + return { + switchRef.current!.checked = !switchRef.current!.checked + updater(switchRef.current!.checked) + }}> + {title} + {description && {description}} + e.preventDefault()}> + +} \ No newline at end of file diff --git a/client/ui/preference/TextFieldPreference.tsx b/client/ui/preference/TextFieldPreference.tsx new file mode 100644 index 0000000..ac96e5d --- /dev/null +++ b/client/ui/preference/TextFieldPreference.tsx @@ -0,0 +1,30 @@ +import { $ } from 'mdui/jq' +import React from 'react' +import { TextField, prompt } from 'mdui' +import useEventListener from '../useEventListener.ts' + +export default function TextFieldPreference({ title, icon, description, updater, defaultValue, disabled } = { + disabled: false, +}) { + const [ text, setText ] = React.useState(defaultValue) + + return { + prompt({ + headline: title, + confirmText: "确定", + cancelText: "取消", + onConfirm: (value) => { + setText(value) + updater(value) + }, + onCancel: () => {}, + textFieldOptions: { + label: description, + value: text, + }, + }) + }}> + {title} + {description && {description}} + +} \ No newline at end of file