diff --git a/packages/client/src/components/widgets.vue b/packages/client/src/components/widgets.vue index 12f712925..ccde5fbe5 100644 --- a/packages/client/src/components/widgets.vue +++ b/packages/client/src/components/widgets.vue @@ -10,7 +10,7 @@ {{ $ts.close }} @@ -18,7 +18,7 @@
- +
@@ -28,7 +28,7 @@ diff --git a/packages/client/src/scripts/form.ts b/packages/client/src/scripts/form.ts index 7bf6cec45..7f321cc0a 100644 --- a/packages/client/src/scripts/form.ts +++ b/packages/client/src/scripts/form.ts @@ -21,11 +21,39 @@ export type FormItem = { default: string | null; hidden?: boolean; enum: string[]; +} | { + label?: string; + type: 'radio'; + default: unknown | null; + hidden?: boolean; + options: { + label: string; + value: unknown; + }[]; +} | { + label?: string; + type: 'object'; + default: Record | null; + hidden: true; } | { label?: string; type: 'array'; default: unknown[] | null; - hidden?: boolean; + hidden: true; }; export type Form = Record; + +type GetItemType = + Item['type'] extends 'string' ? string : + Item['type'] extends 'number' ? number : + Item['type'] extends 'boolean' ? boolean : + Item['type'] extends 'radio' ? unknown : + Item['type'] extends 'enum' ? string : + Item['type'] extends 'array' ? unknown[] : + Item['type'] extends 'object' ? Record + : never; + +export type GetFormResultType = { + [P in keyof F]: GetItemType; +}; diff --git a/packages/client/src/widgets/activity.vue b/packages/client/src/widgets/activity.vue index d322f4758..acbbb7a97 100644 --- a/packages/client/src/widgets/activity.vue +++ b/packages/client/src/widgets/activity.vue @@ -1,82 +1,89 @@ - diff --git a/packages/client/src/widgets/aichan.vue b/packages/client/src/widgets/aichan.vue index 891b7454d..03e394b97 100644 --- a/packages/client/src/widgets/aichan.vue +++ b/packages/client/src/widgets/aichan.vue @@ -1,51 +1,65 @@ - diff --git a/packages/client/src/widgets/aiscript.vue b/packages/client/src/widgets/aiscript.vue index 46c5094ee..0a5c0d614 100644 --- a/packages/client/src/widgets/aiscript.vue +++ b/packages/client/src/widgets/aiscript.vue @@ -1,9 +1,9 @@ - diff --git a/packages/client/src/widgets/button.vue b/packages/client/src/widgets/button.vue index e98570862..a33afd6e7 100644 --- a/packages/client/src/widgets/button.vue +++ b/packages/client/src/widgets/button.vue @@ -1,90 +1,99 @@ - diff --git a/packages/client/src/widgets/calendar.vue b/packages/client/src/widgets/calendar.vue index c8b52d7af..d16d3424b 100644 --- a/packages/client/src/widgets/calendar.vue +++ b/packages/client/src/widgets/calendar.vue @@ -1,5 +1,5 @@ - diff --git a/packages/client/src/widgets/clock.vue b/packages/client/src/widgets/clock.vue index 6ca7ecd43..6acb10d74 100644 --- a/packages/client/src/widgets/clock.vue +++ b/packages/client/src/widgets/clock.vue @@ -1,45 +1,56 @@ - diff --git a/packages/client/src/widgets/define.ts b/packages/client/src/widgets/define.ts deleted file mode 100644 index 08a346d97..000000000 --- a/packages/client/src/widgets/define.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { defineComponent } from 'vue'; -import { throttle } from 'throttle-debounce'; -import { Form } from '@/scripts/form'; -import * as os from '@/os'; - -export default function (data: { - name: string; - props?: () => T; -}) { - return defineComponent({ - props: { - widget: { - type: Object, - required: false - }, - settingCallback: { - required: false - } - }, - - emits: ['updateProps'], - - data() { - return { - props: this.widget ? JSON.parse(JSON.stringify(this.widget.data)) : {}, - save: throttle(3000, () => { - this.$emit('updateProps', this.props); - }), - }; - }, - - computed: { - id(): string { - return this.widget ? this.widget.id : null; - }, - }, - - created() { - this.mergeProps(); - - this.$watch('props', () => { - this.mergeProps(); - }, { deep: true }); - - if (this.settingCallback) this.settingCallback(this.setting); - }, - - methods: { - mergeProps() { - if (data.props) { - const defaultProps = data.props(); - for (const prop of Object.keys(defaultProps)) { - if (this.props.hasOwnProperty(prop)) continue; - this.props[prop] = defaultProps[prop].default; - } - } - }, - - async setting() { - const form = data.props(); - for (const item of Object.keys(form)) { - form[item].default = this.props[item]; - } - const { canceled, result } = await os.form(data.name, form); - if (canceled) return; - - for (const key of Object.keys(result)) { - this.props[key] = result[key]; - } - - this.save(); - }, - } - }); -} diff --git a/packages/client/src/widgets/digital-clock.vue b/packages/client/src/widgets/digital-clock.vue index fbf632d2d..637b0368b 100644 --- a/packages/client/src/widgets/digital-clock.vue +++ b/packages/client/src/widgets/digital-clock.vue @@ -1,73 +1,84 @@ - diff --git a/packages/client/src/widgets/federation.vue b/packages/client/src/widgets/federation.vue index 736a91c52..5d53b683b 100644 --- a/packages/client/src/widgets/federation.vue +++ b/packages/client/src/widgets/federation.vue @@ -1,5 +1,5 @@ - diff --git a/packages/client/src/widgets/job-queue.vue b/packages/client/src/widgets/job-queue.vue index 1b7c71de6..4a2a3cf23 100644 --- a/packages/client/src/widgets/job-queue.vue +++ b/packages/client/src/widgets/job-queue.vue @@ -1,134 +1,146 @@ - diff --git a/packages/client/src/widgets/memo.vue b/packages/client/src/widgets/memo.vue index 9b51ada22..3dfc6eb5f 100644 --- a/packages/client/src/widgets/memo.vue +++ b/packages/client/src/widgets/memo.vue @@ -1,5 +1,5 @@ - diff --git a/packages/client/src/widgets/notifications.vue b/packages/client/src/widgets/notifications.vue index 568705b66..8cf29c927 100644 --- a/packages/client/src/widgets/notifications.vue +++ b/packages/client/src/widgets/notifications.vue @@ -1,65 +1,68 @@ - diff --git a/packages/client/src/widgets/online-users.vue b/packages/client/src/widgets/online-users.vue index 5b889f481..2d4768869 100644 --- a/packages/client/src/widgets/online-users.vue +++ b/packages/client/src/widgets/online-users.vue @@ -1,48 +1,60 @@ - diff --git a/packages/client/src/widgets/photos.vue b/packages/client/src/widgets/photos.vue index 7a0b54027..8f948dc64 100644 --- a/packages/client/src/widgets/photos.vue +++ b/packages/client/src/widgets/photos.vue @@ -1,5 +1,5 @@ - diff --git a/packages/client/src/widgets/post-form.vue b/packages/client/src/widgets/post-form.vue index 6de0574cc..51aa8fcf6 100644 --- a/packages/client/src/widgets/post-form.vue +++ b/packages/client/src/widgets/post-form.vue @@ -2,22 +2,34 @@ - diff --git a/packages/client/src/widgets/rss.vue b/packages/client/src/widgets/rss.vue index b2dc77854..aa8205458 100644 --- a/packages/client/src/widgets/rss.vue +++ b/packages/client/src/widgets/rss.vue @@ -1,7 +1,7 @@ - diff --git a/packages/client/src/widgets/server-metric/index.vue b/packages/client/src/widgets/server-metric/index.vue index 107b75090..2caa73fa7 100644 --- a/packages/client/src/widgets/server-metric/index.vue +++ b/packages/client/src/widgets/server-metric/index.vue @@ -1,21 +1,22 @@ - diff --git a/packages/client/src/widgets/slideshow.vue b/packages/client/src/widgets/slideshow.vue index 0909bda67..ac0c6c9e0 100644 --- a/packages/client/src/widgets/slideshow.vue +++ b/packages/client/src/widgets/slideshow.vue @@ -1,126 +1,116 @@ - diff --git a/packages/client/src/widgets/timeline.vue b/packages/client/src/widgets/timeline.vue index aee6a35b1..fa700cc8e 100644 --- a/packages/client/src/widgets/timeline.vue +++ b/packages/client/src/widgets/timeline.vue @@ -1,116 +1,129 @@ - diff --git a/packages/client/src/widgets/trends.vue b/packages/client/src/widgets/trends.vue index ffad93c02..3905daa67 100644 --- a/packages/client/src/widgets/trends.vue +++ b/packages/client/src/widgets/trends.vue @@ -1,5 +1,5 @@ - diff --git a/packages/client/src/widgets/widget.ts b/packages/client/src/widgets/widget.ts new file mode 100644 index 000000000..81239bfb3 --- /dev/null +++ b/packages/client/src/widgets/widget.ts @@ -0,0 +1,71 @@ +import { reactive, watch } from 'vue'; +import { throttle } from 'throttle-debounce'; +import { Form, GetFormResultType } from '@/scripts/form'; +import * as os from '@/os'; + +export type Widget

> = { + id: string; + data: Partial

; +}; + +export type WidgetComponentProps

> = { + widget?: Widget

; +}; + +export type WidgetComponentEmits

> = { + (e: 'updateProps', props: P); +}; + +export type WidgetComponentExpose = { + name: string; + id: string | null; + configure: () => void; +}; + +export const useWidgetPropsManager = >( + name: string, + propsDef: F, + props: Readonly>>, + emit: WidgetComponentEmits>, +): { + widgetProps: GetFormResultType; + save: () => void; + configure: () => void; +} => { + const widgetProps = reactive(props.widget ? JSON.parse(JSON.stringify(props.widget.data)) : {}); + + const mergeProps = () => { + for (const prop of Object.keys(propsDef)) { + if (widgetProps.hasOwnProperty(prop)) continue; + widgetProps[prop] = propsDef[prop].default; + } + }; + watch(widgetProps, () => { + mergeProps(); + }, { deep: true, immediate: true, }); + + const save = throttle(3000, () => { + emit('updateProps', widgetProps) + }); + + const configure = async () => { + const form = JSON.parse(JSON.stringify(propsDef)); + for (const item of Object.keys(form)) { + form[item].default = widgetProps[item]; + } + const { canceled, result } = await os.form(name, form); + if (canceled) return; + + for (const key of Object.keys(result)) { + widgetProps[key] = result[key]; + } + + save(); + }; + + return { + widgetProps, + save, + configure, + }; +};