import { Alert, Box, Button, Card, Flex, Group, Image, ScrollArea, Divider, Stack, Switch, Text, TextInput, Title, createStyles, useMantineTheme, } from '@mantine/core'; import { useForm } from '@mantine/form'; import { IconAlertTriangle, IconBookmark, IconLink, IconPlaylistX, IconTrash, IconTypography, } from '@tabler/icons-react'; import { useTranslation } from 'next-i18next'; import { useEffect } from 'react'; import { v4 } from 'uuid'; import { z } from 'zod'; import React from 'react'; import { useEditModeStore } from '../../components/Dashboard/Views/useEditModeStore'; import { IconSelector } from '../../components/IconSelector/IconSelector'; import { defineWidget } from '../helper'; import { IDraggableEditableListInputValue, IWidget } from '../widgets'; interface BookmarkItem { id: string; name: string; href: string; iconUrl: string; openNewTab: boolean; hideHostname: boolean; hideIcon: boolean; } const definition = defineWidget({ id: 'bookmark', icon: IconBookmark, options: { name: { type: 'text', defaultValue: '', info: true, infoLink: "https://homarr.dev/docs/widgets/bookmarks/", }, items: { type: 'draggable-editable-list', defaultValue: [], getLabel(data) { return data.name; }, create() { return { id: v4(), name: 'Homarr Documentation', href: 'https://homarr.dev', iconUrl: '/imgs/logo/logo.png', openNewTab: false, hideHostname: false, hideIcon: false, }; }, itemComponent({ data, onChange, delete: deleteData }) { const { t } = useTranslation('modules/bookmark'); const form = useForm({ initialValues: data, validate: { name: (value) => { const validation = z.string().min(1).max(100).safeParse(value); if (validation.success) { return undefined; } return t('item.validation.length100'); }, href: (value) => { if (!z.string().min(1).max(200).safeParse(value).success) { return t('item.validation.length200'); } if (!z.string().url().safeParse(value).success) { return t('item.validation.invalidLink'); } return undefined; }, iconUrl: (value) => { if (z.string().min(1).max(400).safeParse(value).success) { return undefined; } return t('item.validation.length400'); }, }, validateInputOnChange: true, validateInputOnBlur: true, }); useEffect(() => { if (!form.isValid()) { return; } onChange({ ...form.values, openNewTab: form.values.openNewTab }); }, [form.values]); return (
} {...form.getInputProps('name')} label={t('item.name')} withAsterisk /> } {...form.getInputProps('href')} label={t('item.url')} withAsterisk /> { form.setFieldValue('iconUrl', value ?? ''); }} /> {!form.isValid() && ( }> {t('item.validation.errorMsg')} )}
); }, } satisfies IDraggableEditableListInputValue, layout: { type: 'select', data: [ { value: 'autoGrid', }, { value: 'horizontal', }, { value: 'vertical', }, ], defaultValue: 'autoGrid', }, }, gridstack: { minWidth: 1, minHeight: 1, maxWidth: 24, maxHeight: 24, }, component: BookmarkWidgetTile, }); export type IBookmarkWidget = IWidget<(typeof definition)['id'], typeof definition>; interface BookmarkWidgetTileProps { widget: IBookmarkWidget; } function BookmarkWidgetTile({ widget }: BookmarkWidgetTileProps) { const { classes } = useStyles(); const { enabled: isEditModeEnabled } = useEditModeStore(); const { fn, colors, colorScheme } = useMantineTheme(); const { t } = useTranslation('modules/bookmark'); if (widget.properties.items.length === 0) { return ( {t('card.noneFound.title')} {t('card.noneFound.text')} ); } switch (widget.properties.layout) { case 'autoGrid': return ( {widget.properties.name} {widget.properties.items.map((item: BookmarkItem, index) => ( ))} ); case 'horizontal': case 'vertical': return ( {widget.properties.name} {widget.properties.items.map((item: BookmarkItem, index) => ( <> ); default: return null; } } const BookmarkItemContent = ({ item }: { item: BookmarkItem }) => { const { colorScheme } = useMantineTheme(); return ( {item.name} )}; const useStyles = createStyles(() => ({ grid: { display: 'grid', gap: 10, gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))', }, autoGridItem: { flex: '1 1 auto', }, })); export default definition;