fix: Size the expanded dialog and grid columns to their content (#2611)
- Closes #2607
This commit is contained in:
@@ -21,31 +21,31 @@ export class StyleManager {
|
||||
const card = this._api.getCardElementManager().getElement();
|
||||
const view = this._api.getViewManager().getView();
|
||||
|
||||
// A grid shows several media items at once, so no single item describes it.
|
||||
const isSingleMediaView = !view?.isGrid() && !!view?.isAnyMediaView();
|
||||
|
||||
// When a new media loads, set the aspect ratio for when the card is
|
||||
// expanded/popped-up. This is based exclusively on last media content,
|
||||
// as dimension configuration does not apply in fullscreen or expanded mode.
|
||||
const lastKnown = this._api.getMediaLoadedInfoManager().getLastKnown();
|
||||
card.style.setProperty(
|
||||
'--advanced-camera-card-expand-aspect-ratio',
|
||||
view?.isAnyMediaView() && lastKnown
|
||||
isSingleMediaView && lastKnown
|
||||
? `${lastKnown.width} / ${lastKnown.height}`
|
||||
: 'unset',
|
||||
);
|
||||
// Non-media may have no intrinsic dimensions (or multiple media items in a
|
||||
// grid) and so we need to explicit request the dialog to use all available
|
||||
// space.
|
||||
const isGrid = view?.isGrid();
|
||||
// Non-media and grids have no intrinsic width, so the dialog is asked to
|
||||
// use all the width available.
|
||||
card.style.setProperty(
|
||||
'--advanced-camera-card-expand-width',
|
||||
!isGrid && view?.isAnyMediaView()
|
||||
? 'none'
|
||||
: 'var(--advanced-camera-card-expand-max-width)',
|
||||
isSingleMediaView ? 'none' : 'var(--advanced-camera-card-expand-max-width)',
|
||||
);
|
||||
// Non-media (e.g. the gallery) has no intrinsic height and fills the
|
||||
// dialog. Media sizes the dialog to itself, up to the maximum height. A
|
||||
// grid is media: it is as tall as the items it packs.
|
||||
card.style.setProperty(
|
||||
'--advanced-camera-card-expand-height',
|
||||
!isGrid && view?.isAnyMediaView()
|
||||
? 'none'
|
||||
: 'var(--advanced-camera-card-expand-max-height)',
|
||||
view?.isAnyMediaView() ? 'none' : 'var(--advanced-camera-card-expand-max-height)',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -416,7 +416,7 @@ export class MediaGridController {
|
||||
Math.floor(this._hostWidth / MEDIA_GRID_DEFAULT_IDEAL_CELL_WIDTH),
|
||||
);
|
||||
if (idealColumns > 1) {
|
||||
return idealColumns;
|
||||
return this._clampColumnsToDemand(idealColumns);
|
||||
}
|
||||
|
||||
// If not, get a multi-column view using the minimum cell width.
|
||||
@@ -425,7 +425,49 @@ export class MediaGridController {
|
||||
);
|
||||
|
||||
// Last result use at least 1 column.
|
||||
return Math.max(1, minColumns);
|
||||
return this._clampColumnsToDemand(Math.max(1, minColumns));
|
||||
}
|
||||
|
||||
private _clampColumnsToDemand(columns: number): number {
|
||||
// Extra columns sit empty and make every item narrower than it needs to be.
|
||||
// At least 1 column is used, as the grid may be empty.
|
||||
return Math.max(1, Math.min(columns, this._getDemandedColumns()));
|
||||
}
|
||||
|
||||
// The number of columns the grid items need: one or more per item, plus room
|
||||
// for any one of them to be selected.
|
||||
private _getDemandedColumns(): number {
|
||||
let demand = 0;
|
||||
let selectionAllowance = 0;
|
||||
|
||||
for (const element of this._gridContents.values()) {
|
||||
const attribute = Number(element.getAttribute(this._widthFactorAttribute));
|
||||
|
||||
// An absent or invalid attribute means the item is one column wide.
|
||||
const widthFactor = attribute > 0 ? attribute : 1;
|
||||
|
||||
// Width factors may be fractional, but an item occupies whole columns:
|
||||
// two half-width items need two columns, not one.
|
||||
const columns = Math.ceil(widthFactor);
|
||||
demand += columns;
|
||||
|
||||
selectionAllowance = Math.max(
|
||||
selectionAllowance,
|
||||
Math.ceil(widthFactor * this._getSelectedWidthFactor()) - columns,
|
||||
);
|
||||
}
|
||||
|
||||
// The space a selection needs is reserved for any item, so that selecting
|
||||
// one does not change the column count and resize the whole grid. A lone
|
||||
// item cannot be wider than the grid, so it needs no reservation.
|
||||
return demand + (this._gridContents.size > 1 ? selectionAllowance : 0);
|
||||
}
|
||||
|
||||
private _getSelectedWidthFactor(): number {
|
||||
return (
|
||||
this._displayConfig?.grid_selected_width_factor ??
|
||||
MEDIA_GRID_DEFAULT_SELECTED_WIDTH_FACTOR
|
||||
);
|
||||
}
|
||||
|
||||
private _setColumnSizeStyles(): void {
|
||||
@@ -436,10 +478,7 @@ export class MediaGridController {
|
||||
|
||||
this._host.style.setProperty(
|
||||
'--advanced-camera-card-grid-selected-width-factor',
|
||||
`${
|
||||
this._displayConfig?.grid_selected_width_factor ??
|
||||
MEDIA_GRID_DEFAULT_SELECTED_WIDTH_FACTOR
|
||||
}`,
|
||||
`${this._getSelectedWidthFactor()}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+18
-2
@@ -90,6 +90,10 @@ div.main::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Styling that must win over theme styling uses the `#ha-card` id selector
|
||||
// instead of this element selector, which a theme can match with the same
|
||||
// specificity and beat on order (e.g. a `ha-card { background: ... }` rule
|
||||
// injected by card-mod).
|
||||
ha-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -125,8 +129,6 @@ ha-card {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// Need to use an id selector here to overcome theme styling that may
|
||||
// incorrectly apply to ha-card style.
|
||||
:host(:fullscreen) #ha-card {
|
||||
@include fullscreen-ha-card;
|
||||
}
|
||||
@@ -178,6 +180,20 @@ web-dialog::part(dialog) {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
// The card renders inside the dialog when expanded, leaving the opaque
|
||||
// background on `:host` behind in the dashboard. Without the background, a view
|
||||
// that does not fill the dialog (e.g. the timeline) shows the dashboard through
|
||||
// the gap.
|
||||
//
|
||||
// The card is a flex item of the dialog, and a flex item is by default at least
|
||||
// as tall as its own content. A view taller than the dialog is allowed to be
|
||||
// (e.g. a grid of many cameras) would overflow it, so the minimum is removed
|
||||
// and the card shrinks to the dialog instead, leaving the view to scroll.
|
||||
:host([expanded]) #ha-card {
|
||||
background-color: var(--advanced-camera-card-background);
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/*******************
|
||||
* Menu hover styles
|
||||
*******************/
|
||||
|
||||
Reference in New Issue
Block a user