这一大坨玩意我不想写说明了

This commit is contained in:
CrescentLeaf
2025-12-14 16:34:45 +08:00
parent 6a1ae692f9
commit 56f651f084
22 changed files with 653 additions and 41 deletions

View File

@@ -0,0 +1,16 @@
import { ListItem } from "mdui"
interface Args extends React.HTMLAttributes<ListItem> {
title: string
description?: string
icon: string
disabled?: boolean
}
export default function Preference({ title, icon, disabled, description, ...props }: Args) {
// @ts-ignore: 为什么 ...props 要说参数不兼容呢?
return <mdui-list-item disabled={disabled ? true : undefined} rounded icon={icon} {...props}>
{title}
{description && <span slot="description">{description}</span>}
</mdui-list-item>
}

View File

@@ -0,0 +1,5 @@
export default function PreferenceHeader({ title }: {
title: string
}) {
return <mdui-list-subheader>{title}</mdui-list-subheader>
}

View File

@@ -0,0 +1,8 @@
export default function PreferenceLayout({ children, ...props }: React.HTMLAttributes<HTMLElement>) {
return <mdui-list style={{
marginLeft: '15px',
marginRight: '15px',
}} {...props}>
{children}
</mdui-list>
}

View File

@@ -0,0 +1,27 @@
import React from 'react'
export default class PreferenceStore<T extends object> {
declare onUpdate: (value: T, oldvalue: T) => void
declare state: T
declare setState: React.Dispatch<React.SetStateAction<T>>
constructor() {
const _ = React.useState({} as T)
this.state = _[0]
this.setState = _[1]
}
createUpdater() {
return (key: string, value: unknown) => {
const oldvalue = this.state
const newValue = {
...this.state,
[key]: value,
}
this.setState(newValue)
this.onUpdate?.(newValue, oldvalue)
}
}
setOnUpdate(onUpdate: (value: T, oldvalue: T) => void) {
this.onUpdate = onUpdate
}
}

View File

@@ -0,0 +1,6 @@
import React from 'react'
// deno-lint-ignore no-explicit-any
const PreferenceUpdater = React.createContext<(key: string, value: unknown) => void>(null as any)
export default PreferenceUpdater

View File

@@ -0,0 +1,43 @@
import React from 'react'
import { Dropdown } from 'mdui'
import PreferenceUpdater from "./PreferenceUpdater.ts"
import useEventListener from '../../utils/useEventListener.ts'
interface Args extends React.HTMLAttributes<HTMLElement> {
title: string
icon: string
id: string
disabled?: boolean
selections: { [id: string]: string }
state: string
}
export default function SelectPreference({ title, icon, id: preferenceId, selections, state, disabled }: Args) {
const updater = React.useContext(PreferenceUpdater)
const dropDownRef = React.useRef<Dropdown>(null)
const [isDropDownOpen, setDropDownOpen] = React.useState(false)
useEventListener(dropDownRef, 'closed', () => {
setDropDownOpen(false)
})
return <mdui-list-item icon={icon} rounded disabled={disabled ? true : undefined} onClick={() => setDropDownOpen(!isDropDownOpen)}>
<mdui-dropdown ref={dropDownRef} trigger="manual" open={isDropDownOpen}>
<span slot="trigger">{title}</span>
<mdui-menu onClick={(e: MouseEvent) => {
e.stopPropagation()
setDropDownOpen(false)
}}>
{
Object.keys(selections).map((id) =>
// @ts-ignore: selected 确实存在, 但是并不对外公开使用
<mdui-menu-item key={id} selected={state == id ? true : undefined} onClick={() => {
updater(preferenceId, id)
}}>{selections[id]}</mdui-menu-item>
)
}
</mdui-menu>
</mdui-dropdown>
<span slot="description">{selections[state]}</span>
</mdui-list-item>
}

View File

@@ -0,0 +1,30 @@
import { Switch } from 'mdui'
import React from 'react'
import PreferenceUpdater from "./PreferenceUpdater.ts"
interface Args extends React.HTMLAttributes<HTMLElement> {
title: string
id: string
description?: string
icon: string
state: boolean
disabled?: boolean
}
export default function SwitchPreference({ title, icon, id, disabled, description, state }: Args) {
const updater = React.useContext(PreferenceUpdater)
const switchRef = React.useRef<Switch>(null)
React.useEffect(() => {
switchRef.current!.checked = state
}, [state])
return <mdui-list-item disabled={disabled ? true : undefined} rounded icon={icon} onClick={() => {
updater(id, !state)
}}>
{title}
{description && <span slot="description">{description}</span>}
<mdui-switch slot="end-icon" checked-icon="" ref={switchRef} onClick={(e) => e.preventDefault()}></mdui-switch>
</mdui-list-item>
}

View File

@@ -0,0 +1,37 @@
import React from 'react'
import { prompt } from 'mdui'
import PreferenceUpdater from "./PreferenceUpdater.ts"
interface Args extends React.HTMLAttributes<HTMLElement> {
title: string
description?: string
icon: string
id: string
state: string
disabled?: boolean
}
export default function TextFieldPreference({ title, icon, description, id, state, disabled }: Args) {
const updater = React.useContext(PreferenceUpdater)
return <mdui-list-item icon={icon} rounded disabled={disabled ? true : undefined} onClick={() => {
prompt({
headline: title,
confirmText: "确定",
cancelText: "取消",
onConfirm: (value) => {
updater(id, value)
},
onCancel: () => { },
textFieldOptions: {
label: description,
value: state,
},
closeOnEsc: true,
closeOnOverlayClick: true,
})
}}>
{title}
{description && <span slot="description">{description}</span>}
</mdui-list-item>
}