feat: add tile border radius (#2338)

* feat: add tile border radius

* fix: inconsistent mantine-core version

* fix: lockfile

---------

Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
This commit is contained in:
Manuel
2025-02-18 21:53:45 +01:00
committed by GitHub
parent 8e71b882db
commit 7705bc44ae
18 changed files with 3629 additions and 5 deletions

View File

@@ -10,6 +10,7 @@ import {
Group, Group,
InputWrapper, InputWrapper,
isLightColor, isLightColor,
Select,
Slider, Slider,
Stack, Stack,
Text, Text,
@@ -39,6 +40,7 @@ export const ColorSettingsContent = ({ board }: Props) => {
primaryColor: board.primaryColor, primaryColor: board.primaryColor,
secondaryColor: board.secondaryColor, secondaryColor: board.secondaryColor,
opacity: board.opacity, opacity: board.opacity,
itemRadius: board.itemRadius,
}, },
}); });
const [showPreview, { toggle }] = useDisclosure(false); const [showPreview, { toggle }] = useDisclosure(false);
@@ -98,6 +100,20 @@ export const ColorSettingsContent = ({ board }: Props) => {
/> />
</InputWrapper> </InputWrapper>
</Grid.Col> </Grid.Col>
<Grid.Col span={{ sm: 12, md: 6 }}>
<Select
label={t("board.field.itemRadius.label")}
description={t("board.field.itemRadius.description")}
data={[
{ label: t("board.field.itemRadius.option.xs"), value: "xs" },
{ label: t("board.field.itemRadius.option.sm"), value: "sm" },
{ label: t("board.field.itemRadius.option.md"), value: "md" },
{ label: t("board.field.itemRadius.option.lg"), value: "lg" },
{ label: t("board.field.itemRadius.option.xl"), value: "xl" },
]}
{...form.getInputProps("itemRadius")}
/>
</Grid.Col>
</Grid> </Grid>
<Group justify="end"> <Group justify="end">
<Button type="submit" loading={isPending} color="teal"> <Button type="submit" loading={isPending} color="teal">

View File

@@ -23,10 +23,10 @@ import type { TablerIcon } from "@homarr/ui";
import { getBoardPermissionsAsync } from "~/components/board/permissions/server"; import { getBoardPermissionsAsync } from "~/components/board/permissions/server";
import { ActiveTabAccordion } from "../../../../../components/active-tab-accordion"; import { ActiveTabAccordion } from "../../../../../components/active-tab-accordion";
import { ColorSettingsContent } from "./_appereance";
import { BackgroundSettingsContent } from "./_background"; import { BackgroundSettingsContent } from "./_background";
import { BehaviorSettingsContent } from "./_behavior"; import { BehaviorSettingsContent } from "./_behavior";
import { BoardAccessSettings } from "./_board-access"; import { BoardAccessSettings } from "./_board-access";
import { ColorSettingsContent } from "./_colors";
import { CustomCssSettingsContent } from "./_customCss"; import { CustomCssSettingsContent } from "./_customCss";
import { DangerZoneSettingsContent } from "./_danger"; import { DangerZoneSettingsContent } from "./_danger";
import { GeneralSettingsContent } from "./_general"; import { GeneralSettingsContent } from "./_general";
@@ -91,7 +91,7 @@ export default async function BoardSettingsPage(props: Props) {
<AccordionItemFor value="background" icon={IconPhoto}> <AccordionItemFor value="background" icon={IconPhoto}>
<BackgroundSettingsContent board={board} /> <BackgroundSettingsContent board={board} />
</AccordionItemFor> </AccordionItemFor>
<AccordionItemFor value="color" icon={IconBrush}> <AccordionItemFor value="appearance" icon={IconBrush}>
<ColorSettingsContent board={board} /> <ColorSettingsContent board={board} />
</AccordionItemFor> </AccordionItemFor>
<AccordionItemFor value="customCss" icon={IconFileTypeCss}> <AccordionItemFor value="customCss" icon={IconFileTypeCss}>

View File

@@ -33,6 +33,7 @@ export const BoardItemContent = ({ item }: BoardItemContentProps) => {
"grid-stack-item-content", "grid-stack-item-content",
item.advancedOptions.customCssClasses.join(" "), item.advancedOptions.customCssClasses.join(" "),
)} )}
radius={board.itemRadius}
withBorder withBorder
styles={{ styles={{
root: { root: {

View File

@@ -27,7 +27,13 @@ export const BoardCategorySection = ({ section }: Props) => {
}); });
return ( return (
<Card style={{ "--opacity": board.opacity / 100 }} withBorder p={0} className={classes.itemCard}> <Card
style={{ "--opacity": board.opacity / 100 }}
radius={board.itemRadius}
withBorder
p={0}
className={classes.itemCard}
>
<Stack> <Stack>
<Group wrap="nowrap" gap="sm"> <Group wrap="nowrap" gap="sm">
<UnstyledButton w="100%" p="sm" onClick={toggle}> <UnstyledButton w="100%" p="sm" onClick={toggle}>

View File

@@ -26,6 +26,7 @@ export const BoardDynamicSection = ({ section }: Props) => {
overflow: "hidden", overflow: "hidden",
}, },
}} }}
radius={board.itemRadius}
p={0} p={0}
> >
<GridStack section={section} className="min-row" /> <GridStack section={section} className="min-row" />

View File

@@ -517,6 +517,7 @@ export const boardRouter = createTRPCRouter({
// layout settings // layout settings
columnCount: input.columnCount, columnCount: input.columnCount,
itemRadius: input.itemRadius,
// Behavior settings // Behavior settings
disableStatus: input.disableStatus, disableStatus: input.disableStatus,

View File

@@ -0,0 +1 @@
ALTER TABLE `board` ADD `item_radius` text DEFAULT ('lg') NOT NULL;

File diff suppressed because it is too large Load Diff

View File

@@ -183,6 +183,13 @@
"when": 1739469710187, "when": 1739469710187,
"tag": "0025_add-group-home-board-settings", "tag": "0025_add-group-home-board-settings",
"breakpoints": true "breakpoints": true
},
{
"idx": 26,
"version": "5",
"when": 1739907771355,
"tag": "0026_add-border-radius",
"breakpoints": true
} }
] ]
} }

View File

@@ -0,0 +1 @@
ALTER TABLE `board` ADD `item_radius` text DEFAULT 'lg' NOT NULL;

File diff suppressed because it is too large Load Diff

View File

@@ -183,6 +183,13 @@
"when": 1739468826756, "when": 1739468826756,
"tag": "0025_add-group-home-board-settings", "tag": "0025_add-group-home-board-settings",
"breakpoints": true "breakpoints": true
},
{
"idx": 26,
"version": "6",
"when": 1739907755789,
"tag": "0026_add-border-radius",
"breakpoints": true
} }
] ]
} }

View File

@@ -42,6 +42,7 @@
"@homarr/definitions": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0",
"@homarr/log": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0",
"@homarr/server-settings": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0",
"@mantine/core": "^7.17.0",
"@paralleldrive/cuid2": "^2.2.2", "@paralleldrive/cuid2": "^2.2.2",
"@t3-oss/env-nextjs": "^0.12.0", "@t3-oss/env-nextjs": "^0.12.0",
"@testcontainers/mysql": "^10.18.0", "@testcontainers/mysql": "^10.18.0",

View File

@@ -1,4 +1,5 @@
import type { AdapterAccount } from "@auth/core/adapters"; import type { AdapterAccount } from "@auth/core/adapters";
import type { MantineSize } from "@mantine/core";
import type { DayOfWeek } from "@mantine/dates"; import type { DayOfWeek } from "@mantine/dates";
import { relations } from "drizzle-orm"; import { relations } from "drizzle-orm";
import type { AnyMySqlColumn } from "drizzle-orm/mysql-core"; import type { AnyMySqlColumn } from "drizzle-orm/mysql-core";
@@ -280,6 +281,7 @@ export const boards = mysqlTable("board", {
opacity: int().default(100).notNull(), opacity: int().default(100).notNull(),
customCss: text(), customCss: text(),
columnCount: int().default(10).notNull(), columnCount: int().default(10).notNull(),
itemRadius: text().$type<MantineSize>().default("lg").notNull(),
disableStatus: boolean().default(false).notNull(), disableStatus: boolean().default(false).notNull(),
}); });

View File

@@ -1,4 +1,5 @@
import type { AdapterAccount } from "@auth/core/adapters"; import type { AdapterAccount } from "@auth/core/adapters";
import type { MantineSize } from "@mantine/core";
import type { DayOfWeek } from "@mantine/dates"; import type { DayOfWeek } from "@mantine/dates";
import { relations, sql } from "drizzle-orm"; import { relations, sql } from "drizzle-orm";
import type { AnySQLiteColumn } from "drizzle-orm/sqlite-core"; import type { AnySQLiteColumn } from "drizzle-orm/sqlite-core";
@@ -265,6 +266,7 @@ export const boards = sqliteTable("board", {
opacity: int().default(100).notNull(), opacity: int().default(100).notNull(),
customCss: text(), customCss: text(),
columnCount: int().default(10).notNull(), columnCount: int().default(10).notNull(),
itemRadius: text().$type<MantineSize>().default("lg").notNull(),
disableStatus: int({ mode: "boolean" }).default(false).notNull(), disableStatus: int({ mode: "boolean" }).default(false).notNull(),
}); });

View File

@@ -2096,6 +2096,17 @@
"columnCount": { "columnCount": {
"label": "Column count" "label": "Column count"
}, },
"itemRadius": {
"label": "Item radius",
"description": "Changes the roundness of tiles on your board",
"option": {
"xs": "Very small",
"sm": "Small",
"md": "Medium",
"lg": "Large",
"xl": "Very large"
}
},
"name": { "name": {
"label": "Name" "label": "Name"
}, },
@@ -2120,8 +2131,8 @@
"background": { "background": {
"title": "Background" "title": "Background"
}, },
"color": { "appearance": {
"title": "Colors" "title": "Appearance"
}, },
"customCss": { "customCss": {
"title": "Custom css" "title": "Custom css"

View File

@@ -58,6 +58,7 @@ const savePartialSettingsSchema = z
opacity: z.number().min(0).max(100), opacity: z.number().min(0).max(100),
customCss: z.string().max(16384), customCss: z.string().max(16384),
columnCount: z.number().min(1).max(24), columnCount: z.number().min(1).max(24),
itemRadius: z.union([z.literal("xs"), z.literal("sm"), z.literal("md"), z.literal("lg"), z.literal("xl")]),
disableStatus: z.boolean(), disableStatus: z.boolean(),
}) })
.partial(); .partial();

3
pnpm-lock.yaml generated
View File

@@ -1002,6 +1002,9 @@ importers:
'@homarr/server-settings': '@homarr/server-settings':
specifier: workspace:^0.1.0 specifier: workspace:^0.1.0
version: link:../server-settings version: link:../server-settings
'@mantine/core':
specifier: ^7.17.0
version: 7.17.0(@mantine/hooks@7.17.0(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@paralleldrive/cuid2': '@paralleldrive/cuid2':
specifier: ^2.2.2 specifier: ^2.2.2
version: 2.2.2 version: 2.2.2