merge: sync dev changes
This commit is contained in:
commit
92a2be2b65
21 files changed
+2332
-985
No files matched your search
@@ -115,14 +115,22 @@ const getMaxVisibleMetrics = (cellHeight: number, size: SizeConfig): number => {
|
||||
return Math.max(1, Math.floor(available / size.rowHeight));
|
||||
};
|
||||
|
||||
const MIN_CELL_WIDTH = 180;
|
||||
const MIN_CELL_WIDTH = 140;
|
||||
const MIN_CELL_HEIGHT = 80;
|
||||
|
||||
const getColCount = (width: number, height: number, itemCount: number): number => {
|
||||
const getColCount = (width: number, _height: number, itemCount: number): number => {
|
||||
if (itemCount <= 1) return 1;
|
||||
const maxCols = Math.min(itemCount, Math.max(1, Math.floor(width / MIN_CELL_WIDTH)));
|
||||
const aspectRatio = width / Math.max(height, MIN_CELL_HEIGHT);
|
||||
return Math.min(maxCols, Math.max(1, Math.ceil(Math.sqrt(itemCount * aspectRatio))));
|
||||
|
||||
let best = 1;
|
||||
for (let c = 1; c <= maxCols; c++) {
|
||||
const emptyCells = (c - (itemCount % c)) % c;
|
||||
const bestEmpty = (best - (itemCount % best)) % best;
|
||||
if (emptyCells < bestEmpty || (emptyCells === bestEmpty && c > best)) {
|
||||
best = c;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
};
|
||||
|
||||
interface MetricRowProps {
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -8,28 +8,37 @@ import { createWidgetDefinition } from "../definition";
|
||||
import { optionsBuilder } from "../options";
|
||||
|
||||
const columnsList = [
|
||||
"id",
|
||||
"actions",
|
||||
"added",
|
||||
"category",
|
||||
"downSpeed",
|
||||
"index",
|
||||
"integration",
|
||||
"name",
|
||||
"progress",
|
||||
"size",
|
||||
"downSpeed",
|
||||
"upSpeed",
|
||||
"time",
|
||||
"state",
|
||||
"added",
|
||||
"ratio",
|
||||
"received",
|
||||
"sent",
|
||||
"size",
|
||||
"state",
|
||||
"time",
|
||||
"category",
|
||||
"integration",
|
||||
"index",
|
||||
"type",
|
||||
"upSpeed",
|
||||
] as const satisfies (keyof ExtendedDownloadClientItem)[];
|
||||
const sortingExclusion = ["actions", "id", "state"] as const satisfies readonly (typeof columnsList)[number][];
|
||||
const columnsSort = columnsList.filter((column) =>
|
||||
sortingExclusion.every((exclusion) => exclusion !== column),
|
||||
) as Exclude<typeof columnsList, (typeof sortingExclusion)[number]>;
|
||||
|
||||
const sortColumns = [
|
||||
"name",
|
||||
"progress",
|
||||
"size",
|
||||
"downSpeed",
|
||||
"upSpeed",
|
||||
"time",
|
||||
"added",
|
||||
"ratio",
|
||||
"received",
|
||||
"sent",
|
||||
"index",
|
||||
"type",
|
||||
] as const satisfies readonly (typeof columnsList)[number][];
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("downloads", {
|
||||
icon: IconDownload,
|
||||
@@ -46,19 +55,16 @@ export const { definition, componentLoader } = createWidgetDefinition("downloads
|
||||
return optionsBuilder.from(
|
||||
(factory) => ({
|
||||
columns: factory.multiSelect({
|
||||
defaultValue: ["integration", "name", "progress", "time", "actions"],
|
||||
defaultValue: ["name", "progress", "downSpeed", "time", "state"],
|
||||
options: columnsList.map((value) => ({
|
||||
value,
|
||||
label: (t) => t(`widget.downloads.items.${value}.columnTitle`),
|
||||
})),
|
||||
searchable: true,
|
||||
}),
|
||||
enableRowSorting: factory.switch({
|
||||
defaultValue: false,
|
||||
}),
|
||||
defaultSort: factory.select({
|
||||
defaultValue: "type",
|
||||
options: columnsSort.map((value) => ({
|
||||
defaultValue: "progress",
|
||||
options: sortColumns.map((value) => ({
|
||||
value,
|
||||
label: (t) => t(`widget.downloads.items.${value}.columnTitle`),
|
||||
})),
|
||||
@@ -76,7 +82,6 @@ export const { definition, componentLoader } = createWidgetDefinition("downloads
|
||||
defaultValue: true,
|
||||
}),
|
||||
activeTorrentThreshold: factory.number({
|
||||
//in KiB/s
|
||||
validate: z.number().min(0),
|
||||
defaultValue: 0,
|
||||
step: 1,
|
||||
@@ -96,14 +101,12 @@ export const { definition, componentLoader } = createWidgetDefinition("downloads
|
||||
validate: z.number().min(1),
|
||||
withDescription: true,
|
||||
}),
|
||||
columnOrder: factory.text({ defaultValue: "" }),
|
||||
columnWidths: factory.text({ defaultValue: "" }),
|
||||
}),
|
||||
{
|
||||
defaultSort: {
|
||||
shouldHide: (options) => !options.enableRowSorting,
|
||||
},
|
||||
descendingDefaultSort: {
|
||||
shouldHide: (options) => !options.enableRowSorting,
|
||||
},
|
||||
columnOrder: { shouldHide: () => true },
|
||||
columnWidths: { shouldHide: () => true },
|
||||
showCompletedUsenet: {
|
||||
shouldHide: (_, integrationKinds) =>
|
||||
!getIntegrationKindsByCategory("usenet").some((kinds) => integrationKinds.includes(kinds)),
|
||||
|
||||
@@ -1,12 +1,52 @@
|
||||
/* Make the MantineReactTable transparent so the board card's opacity-controlled
|
||||
background shows through. MRT defaults to var(--mantine-color-body) which is opaque. */
|
||||
.downloads-widget-table,
|
||||
.downloads-widget-table .mantine-Table-table,
|
||||
.downloads-widget-table .mantine-Table-thead,
|
||||
.downloads-widget-table .mantine-Table-tbody,
|
||||
.downloads-widget-table .mantine-Table-tfoot,
|
||||
.downloads-widget-table .mantine-Table-tr,
|
||||
.downloads-widget-table th,
|
||||
.downloads-widget-table td {
|
||||
/* Make the DataTable transparent so the board card's opacity-controlled
|
||||
background shows through. The mantine-datatable defaults to
|
||||
var(--mantine-color-body) which is opaque. */
|
||||
.downloads-table,
|
||||
.downloads-table .mantine-datatable-table,
|
||||
.downloads-table .mantine-datatable-table thead,
|
||||
.downloads-table .mantine-datatable-table tbody,
|
||||
.downloads-table .mantine-datatable-table tfoot,
|
||||
.downloads-table th,
|
||||
.downloads-table td {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.downloads-table .mantine-datatable-table tr {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.downloads-table .mantine-datatable-table tbody tr:hover {
|
||||
background-color: color-mix(in srgb, var(--mantine-color-default-hover) 40%, transparent) !important;
|
||||
}
|
||||
|
||||
.downloads-table th {
|
||||
white-space: nowrap;
|
||||
background-color: color-mix(in srgb, var(--mantine-color-body) 60%, transparent) !important;
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.downloads-table td {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.downloads-table td .mantine-Text-root,
|
||||
.downloads-table td .mantine-Group-root {
|
||||
white-space: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.downloads-table .mantine-datatable-header-cell-sortable-icon {
|
||||
opacity: 0;
|
||||
transition: opacity 150ms;
|
||||
}
|
||||
|
||||
.downloads-table th:hover .mantine-datatable-header-cell-sortable-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Row expansion styling */
|
||||
.downloads-table .mantine-datatable-row-expansion-cell {
|
||||
background-color: color-mix(in srgb, var(--mantine-color-body) 40%, transparent) !important;
|
||||
}
|
||||
Reference in new issue
Block a user