diff --git a/docs/custom-formkit-input/README.md b/docs/custom-formkit-input/README.md new file mode 100644 index 000000000..b5cc4958e --- /dev/null +++ b/docs/custom-formkit-input/README.md @@ -0,0 +1,45 @@ +# 自定义 FormKit 输入组件 + +## 原由 + +目前不管是在 Console 中,还是在插件 / 主题设置表单中,都有可能选择系统当中的资源,所以可以通过自定义 FormKit 组件的方式提供常用的选择器。 + +## 使用方式 + +目前已提供以下类型: + +- `menuCheckbox`:选择一组菜单 +- `menuRadio`:选择一个菜单 +- `menuItemSelect`:选择菜单项 +- `postSelect`:选择文章 +- `singlePageSelect`:选择自定义页面 +- `categorySelect`:选择分类 +- `categoryCheckbox`:选择多个分类 +- `tagSelect`:选择标签 +- `tagCheckbox`:选择多个标签 + +在 Vue 单组件中使用: + +```vue + + + +``` + +在 FormKit Schema 中使用(插件 / 主题设置表单定义): + +```yaml +- $formkit: menuRadio + name: menus + label: 底部菜单组 +``` diff --git a/src/formkit/formkit.config.ts b/src/formkit/formkit.config.ts index ff0e9e681..e98f40bb4 100644 --- a/src/formkit/formkit.config.ts +++ b/src/formkit/formkit.config.ts @@ -4,6 +4,15 @@ import { createAutoAnimatePlugin } from "@formkit/addons"; import { zh } from "@formkit/i18n"; import type { DefaultConfigOptions } from "@formkit/vue"; import { form } from "./inputs/form"; +import { menuCheckbox } from "./inputs/menu-checkbox"; +import { menuRadio } from "./inputs/menu-radio"; +import { menuItemSelect } from "./inputs/menu-item-select"; +import { postSelect } from "./inputs/post-select"; +import { singlePageSelect } from "./inputs/singlePage-select"; +import { categorySelect } from "./inputs/category-select"; +import { tagSelect } from "./inputs/tag-select"; +import { categoryCheckbox } from "./inputs/category-checkbox"; +import { tagCheckbox } from "./inputs/tag-checkbox"; const config: DefaultConfigOptions = { config: { @@ -12,6 +21,15 @@ const config: DefaultConfigOptions = { plugins: [createAutoAnimatePlugin()], inputs: { form, + menuCheckbox, + menuRadio, + menuItemSelect, + postSelect, + categorySelect, + tagSelect, + singlePageSelect, + categoryCheckbox, + tagCheckbox, }, locales: { zh }, locale: "zh", diff --git a/src/formkit/inputs/category-checkbox.ts b/src/formkit/inputs/category-checkbox.ts new file mode 100644 index 000000000..6df15cd39 --- /dev/null +++ b/src/formkit/inputs/category-checkbox.ts @@ -0,0 +1,28 @@ +import { apiClient } from "@/utils/api-client"; +import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core"; +import { checkbox, checkboxes, defaultIcon } from "@formkit/inputs"; + +function optionsHandler(node: FormKitNode) { + node.on("created", async () => { + const { data } = + await apiClient.extension.category.listcontentHaloRunV1alpha1Category(); + + node.props.options = data.items.map((category) => { + return { + value: category.metadata.name, + label: category.spec.displayName, + }; + }); + }); +} + +export const categoryCheckbox: FormKitTypeDefinition = { + ...checkbox, + props: ["onValue", "offValue"], + forceTypeProp: "checkbox", + features: [ + optionsHandler, + checkboxes, + defaultIcon("decorator", "checkboxDecorator"), + ], +}; diff --git a/src/formkit/inputs/category-select.ts b/src/formkit/inputs/category-select.ts new file mode 100644 index 000000000..35a428694 --- /dev/null +++ b/src/formkit/inputs/category-select.ts @@ -0,0 +1,24 @@ +import { apiClient } from "@/utils/api-client"; +import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core"; +import { select, selects, defaultIcon } from "@formkit/inputs"; + +function optionsHandler(node: FormKitNode) { + node.on("created", async () => { + const { data } = + await apiClient.extension.category.listcontentHaloRunV1alpha1Category(); + + node.props.options = data.items.map((category) => { + return { + value: category.metadata.name, + label: category.spec.displayName, + }; + }); + }); +} + +export const categorySelect: FormKitTypeDefinition = { + ...select, + props: ["placeholder"], + forceTypeProp: "select", + features: [optionsHandler, selects, defaultIcon("select", "select")], +}; diff --git a/src/formkit/inputs/form.ts b/src/formkit/inputs/form.ts index 99ad1f37a..5145e9dd1 100644 --- a/src/formkit/inputs/form.ts +++ b/src/formkit/inputs/form.ts @@ -31,6 +31,7 @@ export const form: FormKitTypeDefinition = { "submitBehavior", "incompleteMessage", ], + forceTypeProp: "form", /** * Additional features that should be added to your input */ diff --git a/src/formkit/inputs/menu-checkbox.ts b/src/formkit/inputs/menu-checkbox.ts new file mode 100644 index 000000000..6ab0d3fd1 --- /dev/null +++ b/src/formkit/inputs/menu-checkbox.ts @@ -0,0 +1,27 @@ +import { apiClient } from "@/utils/api-client"; +import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core"; +import { checkbox, checkboxes, defaultIcon } from "@formkit/inputs"; + +function optionsHandler(node: FormKitNode) { + node.on("created", async () => { + const { data } = await apiClient.extension.menu.listv1alpha1Menu(); + + node.props.options = data.items.map((menu) => { + return { + value: menu.metadata.name, + label: menu.spec.displayName, + }; + }); + }); +} + +export const menuCheckbox: FormKitTypeDefinition = { + ...checkbox, + props: ["onValue", "offValue"], + forceTypeProp: "checkbox", + features: [ + optionsHandler, + checkboxes, + defaultIcon("decorator", "checkboxDecorator"), + ], +}; diff --git a/src/formkit/inputs/menu-item-select.ts b/src/formkit/inputs/menu-item-select.ts new file mode 100644 index 000000000..e06f13b46 --- /dev/null +++ b/src/formkit/inputs/menu-item-select.ts @@ -0,0 +1,25 @@ +import { apiClient } from "@/utils/api-client"; +import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core"; +import { select, selects, defaultIcon } from "@formkit/inputs"; + +function optionsHandler(node: FormKitNode) { + node.on("created", async () => { + const { data } = await apiClient.extension.menuItem.listv1alpha1MenuItem({ + fieldSelector: [`name=(${node.props.menuItems.join(",")})`], + }); + + node.props.options = data.items.map((menuItem) => { + return { + value: menuItem.metadata.name, + label: menuItem.status?.displayName, + }; + }); + }); +} + +export const menuItemSelect: FormKitTypeDefinition = { + ...select, + props: ["placeholder", "menuItems"], + forceTypeProp: "select", + features: [optionsHandler, selects, defaultIcon("select", "select")], +}; diff --git a/src/formkit/inputs/menu-radio.ts b/src/formkit/inputs/menu-radio.ts new file mode 100644 index 000000000..166a28a86 --- /dev/null +++ b/src/formkit/inputs/menu-radio.ts @@ -0,0 +1,27 @@ +import { apiClient } from "@/utils/api-client"; +import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core"; +import { radio, radios, defaultIcon } from "@formkit/inputs"; + +function optionsHandler(node: FormKitNode) { + node.on("created", async () => { + const { data } = await apiClient.extension.menu.listv1alpha1Menu(); + + node.props.options = data.items.map((menu) => { + return { + value: menu.metadata.name, + label: menu.spec.displayName, + }; + }); + }); +} + +export const menuRadio: FormKitTypeDefinition = { + ...radio, + props: ["onValue", "offValue"], + forceTypeProp: "radio", + features: [ + optionsHandler, + radios, + defaultIcon("decorator", "radioDecorator"), + ], +}; diff --git a/src/formkit/inputs/post-select.ts b/src/formkit/inputs/post-select.ts new file mode 100644 index 000000000..9258a4a9e --- /dev/null +++ b/src/formkit/inputs/post-select.ts @@ -0,0 +1,24 @@ +import { apiClient } from "@/utils/api-client"; +import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core"; +import { select, selects, defaultIcon } from "@formkit/inputs"; + +function optionsHandler(node: FormKitNode) { + node.on("created", async () => { + const { data } = + await apiClient.extension.post.listcontentHaloRunV1alpha1Post(); + + node.props.options = data.items.map((post) => { + return { + value: post.metadata.name, + label: post.spec.title, + }; + }); + }); +} + +export const postSelect: FormKitTypeDefinition = { + ...select, + props: ["placeholder"], + forceTypeProp: "select", + features: [optionsHandler, selects, defaultIcon("select", "select")], +}; diff --git a/src/formkit/inputs/singlePage-select.ts b/src/formkit/inputs/singlePage-select.ts new file mode 100644 index 000000000..738c3d8fa --- /dev/null +++ b/src/formkit/inputs/singlePage-select.ts @@ -0,0 +1,24 @@ +import { apiClient } from "@/utils/api-client"; +import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core"; +import { select, selects, defaultIcon } from "@formkit/inputs"; + +function optionsHandler(node: FormKitNode) { + node.on("created", async () => { + const { data } = + await apiClient.extension.singlePage.listcontentHaloRunV1alpha1SinglePage(); + + node.props.options = data.items.map((singlePage) => { + return { + value: singlePage.metadata.name, + label: singlePage.spec.title, + }; + }); + }); +} + +export const singlePageSelect: FormKitTypeDefinition = { + ...select, + props: ["placeholder"], + forceTypeProp: "select", + features: [optionsHandler, selects, defaultIcon("select", "select")], +}; diff --git a/src/formkit/inputs/tag-checkbox.ts b/src/formkit/inputs/tag-checkbox.ts new file mode 100644 index 000000000..138b4b401 --- /dev/null +++ b/src/formkit/inputs/tag-checkbox.ts @@ -0,0 +1,28 @@ +import { apiClient } from "@/utils/api-client"; +import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core"; +import { checkbox, checkboxes, defaultIcon } from "@formkit/inputs"; + +function optionsHandler(node: FormKitNode) { + node.on("created", async () => { + const { data } = + await apiClient.extension.tag.listcontentHaloRunV1alpha1Tag(); + + node.props.options = data.items.map((tag) => { + return { + value: tag.metadata.name, + label: tag.spec.displayName, + }; + }); + }); +} + +export const tagCheckbox: FormKitTypeDefinition = { + ...checkbox, + props: ["onValue", "offValue"], + forceTypeProp: "checkbox", + features: [ + optionsHandler, + checkboxes, + defaultIcon("decorator", "checkboxDecorator"), + ], +}; diff --git a/src/formkit/inputs/tag-select.ts b/src/formkit/inputs/tag-select.ts new file mode 100644 index 000000000..c09ea09c2 --- /dev/null +++ b/src/formkit/inputs/tag-select.ts @@ -0,0 +1,24 @@ +import { apiClient } from "@/utils/api-client"; +import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core"; +import { select, selects, defaultIcon } from "@formkit/inputs"; + +function optionsHandler(node: FormKitNode) { + node.on("created", async () => { + const { data } = + await apiClient.extension.tag.listcontentHaloRunV1alpha1Tag(); + + node.props.options = data.items.map((tag) => { + return { + value: tag.metadata.name, + label: tag.spec.displayName, + }; + }); + }); +} + +export const tagSelect: FormKitTypeDefinition = { + ...select, + props: ["placeholder"], + forceTypeProp: "select", + features: [optionsHandler, selects, defaultIcon("select", "select")], +}; diff --git a/src/modules/contents/posts/components/PostSettingModal.vue b/src/modules/contents/posts/components/PostSettingModal.vue index 1340a8a53..a53b73c23 100644 --- a/src/modules/contents/posts/components/PostSettingModal.vue +++ b/src/modules/contents/posts/components/PostSettingModal.vue @@ -1,10 +1,8 @@