diff --git a/packages/definitions/src/widget.ts b/packages/definitions/src/widget.ts index 7682d5ab1..e5cf6227f 100644 --- a/packages/definitions/src/widget.ts +++ b/packages/definitions/src/widget.ts @@ -12,5 +12,6 @@ export const widgetKinds = [ "mediaServer", "calendar", "rssFeed", + "bookmarks" ] as const; export type WidgetKind = (typeof widgetKinds)[number]; diff --git a/packages/translation/src/lang/en.ts b/packages/translation/src/lang/en.ts index f3decae3b..9efbcc3c0 100644 --- a/packages/translation/src/lang/en.ts +++ b/packages/translation/src/lang/en.ts @@ -745,6 +745,15 @@ export default { }, }, }, + bookmarks: { + name: "Bookmarks", + description: "Displays a static list of strings or links", + option: { + title: { + label: "Title", + } + } + }, dnsHoleSummary: { name: "DNS Hole Summary", description: "Displays the summary of your DNS Hole", diff --git a/packages/widgets/src/_inputs/index.ts b/packages/widgets/src/_inputs/index.ts index 09303c8b7..2046f07ac 100644 --- a/packages/widgets/src/_inputs/index.ts +++ b/packages/widgets/src/_inputs/index.ts @@ -8,6 +8,7 @@ import { WidgetSelectInput } from "./widget-select-input"; import { WidgetSliderInput } from "./widget-slider-input"; import { WidgetSwitchInput } from "./widget-switch-input"; import { WidgetTextInput } from "./widget-text-input"; +import {WidgetOrderedObjectListInput} from "./widget-ordered-object-list-input"; const mapping = { text: WidgetTextInput, @@ -19,6 +20,7 @@ const mapping = { slider: WidgetSliderInput, switch: WidgetSwitchInput, app: WidgetAppInput, + orderedObjectList: WidgetOrderedObjectListInput } satisfies Record; export const getInputForType = (type: TType) => { diff --git a/packages/widgets/src/_inputs/widget-ordered-object-list-input.tsx b/packages/widgets/src/_inputs/widget-ordered-object-list-input.tsx new file mode 100644 index 000000000..88f7952c4 --- /dev/null +++ b/packages/widgets/src/_inputs/widget-ordered-object-list-input.tsx @@ -0,0 +1,8 @@ +import type {CommonWidgetInputProps} from "./common"; + +export const WidgetOrderedObjectListInput = ({ property, kind, options }: CommonWidgetInputProps<"orderedObjectList">) => { + return
+ {JSON.stringify(options)} + AAAA! +
+} \ No newline at end of file diff --git a/packages/widgets/src/bookmarks/bookmark-item.ts b/packages/widgets/src/bookmarks/bookmark-item.ts new file mode 100644 index 000000000..70d52b8af --- /dev/null +++ b/packages/widgets/src/bookmarks/bookmark-item.ts @@ -0,0 +1 @@ +export interface BookmarkItem {} \ No newline at end of file diff --git a/packages/widgets/src/bookmarks/component.tsx b/packages/widgets/src/bookmarks/component.tsx new file mode 100644 index 000000000..d8dde247d --- /dev/null +++ b/packages/widgets/src/bookmarks/component.tsx @@ -0,0 +1,15 @@ +"use client"; + +import {Code, Stack, Title} from "@mantine/core"; +import type {WidgetComponentProps} from "../definition"; + +export default function BookmarksWidget({options}: WidgetComponentProps<"bookmarks">) { + return + + {options.title} + + + {JSON.stringify(options)} + + +} \ No newline at end of file diff --git a/packages/widgets/src/bookmarks/index.tsx b/packages/widgets/src/bookmarks/index.tsx new file mode 100644 index 000000000..766c7f02f --- /dev/null +++ b/packages/widgets/src/bookmarks/index.tsx @@ -0,0 +1,19 @@ +import {IconClock} from "@tabler/icons-react"; + +import {createWidgetDefinition} from "../definition"; +import {optionsBuilder} from "../options"; +import type {BookmarkItem} from "./bookmark-item"; + +export const {definition, componentLoader} = createWidgetDefinition("bookmarks", { + icon: IconClock, + options: optionsBuilder.from( + (factory) => ({ + title: factory.text(), + items: factory.orderedObjectList({ + itemComponent: (bookmarkItem) => { + return Bookmark: {JSON.stringify(bookmarkItem)} + } + }) + }), + ), +}).withDynamicImport(() => import("./component")); diff --git a/packages/widgets/src/index.tsx b/packages/widgets/src/index.tsx index cbc229559..5fce3472b 100644 --- a/packages/widgets/src/index.tsx +++ b/packages/widgets/src/index.tsx @@ -20,6 +20,7 @@ import * as smartHomeEntityState from "./smart-home/entity-state"; import * as smartHomeExecuteAutomation from "./smart-home/execute-automation"; import * as video from "./video"; import * as weather from "./weather"; +import * as bookmarks from "./bookmarks"; export { reduceWidgetOptionsWithDefaultValues } from "./options"; @@ -43,6 +44,7 @@ export const widgetImports = { mediaServer, calendar, rssFeed, + bookmarks } satisfies WidgetImportRecord; export type WidgetImports = typeof widgetImports; diff --git a/packages/widgets/src/options.ts b/packages/widgets/src/options.ts index abe108dfb..bb86cf979 100644 --- a/packages/widgets/src/options.ts +++ b/packages/widgets/src/options.ts @@ -5,6 +5,7 @@ import { z } from "@homarr/validation"; import { widgetImports } from "."; import type { inferSelectOptionValue, SelectOption } from "./_inputs/widget-select-input"; +import React from "react"; interface CommonInput { defaultValue?: TType; @@ -109,6 +110,11 @@ const optionsFactory = { defaultValue: "", withDescription: input?.withDescription ?? false, }), + orderedObjectList: (input?: (Omit, "defaultValue"> & { itemComponent: (item: TItem) => React.ReactNode })) => ({ + type: "orderedObjectList" as const, + defaultValue: [], + itemComponent: input?.itemComponent ?? null, + }), }; type WidgetOptionFactory = typeof optionsFactory;