feat: add fixed board scaling
This commit is contained in:
1 parent
9d857377c1
commit
ecc1009e23
36 files changed
+8654
-41
No files matched your search
@@ -42,6 +42,8 @@ import {
|
||||
getWidgetIntegrationIssueMessage,
|
||||
getPermissionsWithChildren,
|
||||
getPermissionsWithParents,
|
||||
BOARD_FIXED_ITEM_SIZE_MAX,
|
||||
BOARD_FIXED_ITEM_SIZE_MIN,
|
||||
normalizeBoardLayoutRoles,
|
||||
rootSectionOffsets,
|
||||
widgetDefaultSizes,
|
||||
@@ -1142,8 +1144,7 @@ export const boardRouter = createTRPCRouter({
|
||||
.meta({
|
||||
mcp: {
|
||||
enabled: true,
|
||||
description:
|
||||
"Read the editable visual and behavior settings for one board, including its current custom CSS. Requires modify permission. REQUIRED: id (board ID). Call this before proposing board settings or custom CSS changes",
|
||||
description: `Read the editable visual and behavior settings for one board, including its current custom CSS and board scaling settings. fixedScaling keeps each 1x1 grid item at fixedItemSize pixels instead of fitting the board to the viewport; fixedItemSize is ${BOARD_FIXED_ITEM_SIZE_MIN}-${BOARD_FIXED_ITEM_SIZE_MAX}. Requires modify permission. REQUIRED: id (board ID). Call this before proposing board settings or custom CSS changes`,
|
||||
},
|
||||
})
|
||||
.input(z.object({ id: z.string() }))
|
||||
@@ -1170,6 +1171,8 @@ export const boardRouter = createTRPCRouter({
|
||||
customCss: true,
|
||||
iconColor: true,
|
||||
itemRadius: true,
|
||||
fixedScaling: true,
|
||||
fixedItemSize: true,
|
||||
disableStatus: true,
|
||||
},
|
||||
where: boardWhere,
|
||||
@@ -1526,8 +1529,7 @@ export const boardRouter = createTRPCRouter({
|
||||
openapi: { method: "PATCH", path: "/api/boards/{id}/settings", tags: ["boards"], protect: true },
|
||||
mcp: {
|
||||
enabled: true,
|
||||
description:
|
||||
"Update visual and behavior settings for a board. Requires modify permission. REQUIRED: id (board ID). Optional fields include pageTitle, metaTitle, logoImageUrl, faviconImageUrl, backgroundImageUrl, colors, opacity, customCss, itemRadius, and disableStatus",
|
||||
description: `Update visual and behavior settings for a board. Set fixedScaling to true to keep each 1x1 grid item at fixedItemSize pixels instead of fitting the board to the viewport; fixedItemSize must be ${BOARD_FIXED_ITEM_SIZE_MIN}-${BOARD_FIXED_ITEM_SIZE_MAX}. Requires modify permission. REQUIRED: id (board ID). Optional fields include pageTitle, metaTitle, logoImageUrl, faviconImageUrl, backgroundImageUrl, colors, opacity, customCss, itemRadius, fixedScaling, fixedItemSize, and disableStatus`,
|
||||
},
|
||||
})
|
||||
.input(boardSavePartialSettingsSchema.extend({ id: z.string() }))
|
||||
@@ -1557,6 +1559,10 @@ export const boardRouter = createTRPCRouter({
|
||||
iconColor: input.iconColor,
|
||||
itemRadius: input.itemRadius,
|
||||
|
||||
// scaling settings
|
||||
fixedScaling: input.fixedScaling,
|
||||
fixedItemSize: input.fixedItemSize,
|
||||
|
||||
// custom css
|
||||
customCss: input.customCss,
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
serverSettings,
|
||||
} from "@homarr/db/schema";
|
||||
import {
|
||||
BOARD_FIXED_ITEM_SIZE_DEFAULT,
|
||||
emptySuperJSON,
|
||||
everyoneGroup,
|
||||
extractContainerImageName,
|
||||
@@ -388,6 +389,8 @@ export const onboardRouter = createTRPCRouter({
|
||||
customCss: null,
|
||||
iconColor: null,
|
||||
itemRadius: input.board.itemRadius,
|
||||
fixedScaling: false,
|
||||
fixedItemSize: BOARD_FIXED_ITEM_SIZE_DEFAULT,
|
||||
disableStatus: false,
|
||||
sections: [],
|
||||
layouts: pendingLayouts,
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `board` ADD `fixed_scaling` boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `board` ADD `fixed_item_size` smallint DEFAULT 200 NOT NULL;
|
||||
File diff suppressed because it is too large.
Load diff
@@ -351,6 +351,13 @@
|
||||
"when": 1788763848931,
|
||||
"tag": "0049_add_byte_unit_system",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 50,
|
||||
"version": "5",
|
||||
"when": 1788845117219,
|
||||
"tag": "0050_add_fixed_board_scaling",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE "board" ADD COLUMN "fixed_scaling" boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "board" ADD COLUMN "fixed_item_size" smallint DEFAULT 200 NOT NULL;
|
||||
File diff suppressed because it is too large.
Load diff
@@ -113,6 +113,13 @@
|
||||
"when": 1788763848932,
|
||||
"tag": "0015_add_byte_unit_system",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 16,
|
||||
"version": "7",
|
||||
"when": 1788845119083,
|
||||
"tag": "0016_add_fixed_board_scaling",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `board` ADD `fixed_scaling` integer DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `board` ADD `fixed_item_size` integer DEFAULT 200 NOT NULL;
|
||||
File diff suppressed because it is too large.
Load diff
@@ -337,6 +337,13 @@
|
||||
"when": 1788763848930,
|
||||
"tag": "0047_add_byte_unit_system",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 48,
|
||||
"version": "6",
|
||||
"when": 1788845055278,
|
||||
"tag": "0048_add_fixed_board_scaling",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
backgroundImageAttachments,
|
||||
backgroundImageRepeats,
|
||||
backgroundImageSizes,
|
||||
BOARD_FIXED_ITEM_SIZE_DEFAULT,
|
||||
emptySuperJSON,
|
||||
} from "@homarr/definitions";
|
||||
import type {
|
||||
@@ -301,6 +302,8 @@ export const boards = mysqlTable("board", {
|
||||
customCss: text(),
|
||||
iconColor: text(),
|
||||
itemRadius: text().$type<MantineSize>().default("lg").notNull(),
|
||||
fixedScaling: boolean().default(false).notNull(),
|
||||
fixedItemSize: smallint().default(BOARD_FIXED_ITEM_SIZE_DEFAULT).notNull(),
|
||||
disableStatus: boolean().default(false).notNull(),
|
||||
});
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
backgroundImageAttachments,
|
||||
backgroundImageRepeats,
|
||||
backgroundImageSizes,
|
||||
BOARD_FIXED_ITEM_SIZE_DEFAULT,
|
||||
emptySuperJSON,
|
||||
} from "@homarr/definitions";
|
||||
import type {
|
||||
@@ -299,6 +300,8 @@ export const boards = pgTable("board", {
|
||||
customCss: text(),
|
||||
iconColor: text(),
|
||||
itemRadius: text().$type<MantineSize>().default("lg").notNull(),
|
||||
fixedScaling: boolean().default(false).notNull(),
|
||||
fixedItemSize: smallint().default(BOARD_FIXED_ITEM_SIZE_DEFAULT).notNull(),
|
||||
disableStatus: boolean().default(false).notNull(),
|
||||
});
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
backgroundImageAttachments,
|
||||
backgroundImageRepeats,
|
||||
backgroundImageSizes,
|
||||
BOARD_FIXED_ITEM_SIZE_DEFAULT,
|
||||
emptySuperJSON,
|
||||
} from "@homarr/definitions";
|
||||
import type {
|
||||
@@ -284,6 +285,8 @@ export const boards = sqliteTable("board", {
|
||||
customCss: text(),
|
||||
iconColor: text(),
|
||||
itemRadius: text().$type<MantineSize>().default("lg").notNull(),
|
||||
fixedScaling: int({ mode: "boolean" }).default(false).notNull(),
|
||||
fixedItemSize: int().default(BOARD_FIXED_ITEM_SIZE_DEFAULT).notNull(),
|
||||
disableStatus: int({ mode: "boolean" }).default(false).notNull(),
|
||||
});
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ export const backgroundImageSizes = createDefinition(["cover", "contain"], {
|
||||
});
|
||||
export const layoutRoles = createDefinition(["mobile", "base", "custom"], { defaultValue: "custom" });
|
||||
|
||||
export const BOARD_FIXED_ITEM_SIZE_DEFAULT = 200;
|
||||
export const BOARD_FIXED_ITEM_SIZE_MIN = 100;
|
||||
export const BOARD_FIXED_ITEM_SIZE_MAX = 400;
|
||||
|
||||
export type BackgroundImageAttachment = inferDefinitionType<typeof backgroundImageAttachments>;
|
||||
export type BackgroundImageRepeat = inferDefinitionType<typeof backgroundImageRepeats>;
|
||||
export type BackgroundImageSize = inferDefinitionType<typeof backgroundImageSizes>;
|
||||
|
||||
@@ -5430,6 +5430,16 @@
|
||||
"label": "Disable app status",
|
||||
"description": "Disables the status check for all apps on this board"
|
||||
},
|
||||
"fixedScaling": {
|
||||
"label": "Fixed scaling",
|
||||
"description": "Keep every tile at the selected size. The dashboard is centred when it fits and scrolls when it does not."
|
||||
},
|
||||
"fixedItemSize": {
|
||||
"label": "1 × 1 tile size",
|
||||
"description": "Set the exact visible width and height used for a 1 × 1 tile when fixed scaling is enabled.",
|
||||
"previewLabel": "1 by 1 tile preview at {size} by {size} pixels",
|
||||
"previewValue": "{size} x {size} px"
|
||||
},
|
||||
"columnCount": {
|
||||
"label": "Column count"
|
||||
},
|
||||
@@ -5461,6 +5471,9 @@
|
||||
},
|
||||
"layout": {
|
||||
"title": "Layout",
|
||||
"scaling": {
|
||||
"title": "Scaling"
|
||||
},
|
||||
"responsive": {
|
||||
"title": "Responsive layouts",
|
||||
"description": "Each layout keeps its own widget positions and sizes. Mobile and Base are always available; add custom layouts at any additional breakpoint.",
|
||||
@@ -5607,7 +5620,8 @@
|
||||
"layout": {
|
||||
"field": {
|
||||
"columnCount": {
|
||||
"label": "Column count"
|
||||
"label": "Column count",
|
||||
"description": "Maximum total columns in this layout, including fixed sidebars."
|
||||
},
|
||||
"breakpoint": {
|
||||
"label": "Breakpoint",
|
||||
@@ -8032,6 +8046,7 @@
|
||||
"resetAll": "Reset all changes",
|
||||
"tabs": {
|
||||
"css": "Custom CSS",
|
||||
"layout": "Layout",
|
||||
"appearance": "Appearance",
|
||||
"background": "Background",
|
||||
"general": "General"
|
||||
|
||||
@@ -6,6 +6,8 @@ import {
|
||||
backgroundImageSizes,
|
||||
boardPermissions,
|
||||
layoutRoles,
|
||||
BOARD_FIXED_ITEM_SIZE_MAX,
|
||||
BOARD_FIXED_ITEM_SIZE_MIN,
|
||||
widgetKinds,
|
||||
} from "@homarr/definitions";
|
||||
|
||||
@@ -68,6 +70,8 @@ export const boardSavePartialSettingsSchema = z
|
||||
customCss: z.string().max(16384),
|
||||
iconColor: hexColorNullableSchema,
|
||||
itemRadius: z.union([z.literal("xs"), z.literal("sm"), z.literal("md"), z.literal("lg"), z.literal("xl")]),
|
||||
fixedScaling: z.boolean(),
|
||||
fixedItemSize: z.number().int().min(BOARD_FIXED_ITEM_SIZE_MIN).max(BOARD_FIXED_ITEM_SIZE_MAX),
|
||||
disableStatus: z.boolean(),
|
||||
})
|
||||
.partial();
|
||||
|
||||
Reference in new issue
Block a user