Review feedback
This commit is contained in:
parent
e00300de6c
commit
bf81b8d3df
3 changed files with 218 additions and 28 deletions
|
|
@ -7,6 +7,7 @@
|
|||
@for (tower of page().towers; track tower.id) {
|
||||
<lt-tower
|
||||
cdkDrag
|
||||
[attr.data-tower-id]="tower.id"
|
||||
[cdkDragDisabled]="modalOpen() || mobileDragDisabled()"
|
||||
[tower]="tower"
|
||||
[dateRange]="dateRange()"
|
||||
|
|
|
|||
|
|
@ -39,8 +39,10 @@
|
|||
|
||||
.add-tower-wrapper {
|
||||
@include center-child();
|
||||
|
||||
img.add-tower {
|
||||
height: 48px;
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
height: 32px;
|
||||
}
|
||||
|
|
@ -55,7 +57,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
& > * {
|
||||
&>* {
|
||||
width: 100%;
|
||||
max-width: 200px;
|
||||
box-sizing: border-box;
|
||||
|
|
@ -69,13 +71,12 @@
|
|||
// Mobile: fixed-width towers with horizontal scroll (1.5-column rhythm).
|
||||
@media (max-width: $mobile-width) {
|
||||
--mobile-tower-width: calc(66vw - var(--small-padding));
|
||||
--mobile-tower-side-padding: max(
|
||||
var(--medium-padding),
|
||||
calc((100% - var(--mobile-tower-width)) / 2)
|
||||
);
|
||||
--mobile-tower-side-padding: max(var(--medium-padding),
|
||||
calc((100% - var(--mobile-tower-width)) / 2));
|
||||
|
||||
overflow-x: auto;
|
||||
overflow-y: visible;
|
||||
overflow-y: hidden;
|
||||
touch-action: pan-x;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scroll-snap-type: x mandatory;
|
||||
scroll-padding-inline: var(--mobile-tower-side-padding);
|
||||
|
|
@ -89,7 +90,7 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
& > * {
|
||||
&>* {
|
||||
width: var(--mobile-tower-width) !important;
|
||||
max-width: var(--mobile-tower-width) !important;
|
||||
min-width: var(--mobile-tower-width) !important;
|
||||
|
|
@ -102,19 +103,28 @@
|
|||
.double-slider-container {
|
||||
width: 100%;
|
||||
transition: opacity $long-animation-time;
|
||||
@media (max-height: $min-height) { display: none; }
|
||||
&.transparent { opacity: 0; pointer-events: none; }
|
||||
|
||||
@media (max-height: $min-height) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.transparent {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-delete {
|
||||
@include card();
|
||||
width: 66vw;
|
||||
max-width: 500px;
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
width: 88vw;
|
||||
max-width: 88vw;
|
||||
padding: var(--medium-padding);
|
||||
}
|
||||
|
||||
box-sizing: border-box;
|
||||
padding: var(--large-padding);
|
||||
position: relative;
|
||||
|
|
@ -124,6 +134,7 @@
|
|||
|
||||
.header {
|
||||
@include center-child();
|
||||
|
||||
.exit {
|
||||
position: absolute;
|
||||
right: var(--large-padding);
|
||||
|
|
@ -132,7 +143,9 @@
|
|||
}
|
||||
|
||||
p {
|
||||
strong { font-weight: bold; }
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-buttons {
|
||||
|
|
@ -147,13 +160,19 @@
|
|||
button.danger {
|
||||
color: #b53f3f;
|
||||
border-bottom-color: #b53f3f55;
|
||||
&:after { background-color: #b53f3f; }
|
||||
|
||||
&:after {
|
||||
background-color: #b53f3f;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
flex-direction: column;
|
||||
gap: var(--small-padding);
|
||||
button { width: 100%; }
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -180,4 +199,4 @@
|
|||
transform: translateX(-50%) scale(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,9 @@ import {
|
|||
HostListener,
|
||||
effect,
|
||||
untracked,
|
||||
ElementRef,
|
||||
Injector,
|
||||
afterNextRender,
|
||||
} from '@angular/core';
|
||||
import { Page } from '../../models';
|
||||
import { StoreService } from '../../services/store.service';
|
||||
|
|
@ -69,6 +72,8 @@ export class PageComponent {
|
|||
|
||||
protected readonly store = inject(StoreService);
|
||||
private readonly modalState = inject(ModalStateService);
|
||||
private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);
|
||||
private readonly injector = inject(Injector);
|
||||
/** True while any lt-modal is mounted — used to lock tower drag. */
|
||||
readonly modalOpen = this.modalState.anyOpen;
|
||||
readonly mobileDragDisabled = signal(this.isMobileViewport());
|
||||
|
|
@ -146,7 +151,32 @@ export class PageComponent {
|
|||
|
||||
onAddTower(result: TowerSettingsResult): void {
|
||||
this.showAddTower.set(false);
|
||||
this.store.addTower(this.page().id, result.name, result.base_color);
|
||||
const towerId = this.store.addTower(this.page().id, result.name, result.base_color);
|
||||
this.centerTowerOnMobile(towerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* On mobile the tower row is a horizontal scroll-snap container. Adding a
|
||||
* tower appends it next to the (far-right) "+" button, so without this the
|
||||
* view stays scrolled on the "+" button rather than the new tower. Center
|
||||
* the freshly-created tower once it's painted. No-op on desktop, where the
|
||||
* row is centered and doesn't scroll.
|
||||
*/
|
||||
private centerTowerOnMobile(towerId: string): void {
|
||||
if (!this.isMobileViewport()) return;
|
||||
afterNextRender(
|
||||
() => {
|
||||
const container = this.host.nativeElement.querySelector<HTMLElement>('.towers');
|
||||
const tower = container?.querySelector<HTMLElement>(`[data-tower-id="${towerId}"]`);
|
||||
if (!container || !tower) return;
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const towerRect = tower.getBoundingClientRect();
|
||||
const delta =
|
||||
towerRect.left + towerRect.width / 2 - (containerRect.left + containerRect.width / 2);
|
||||
container.scrollTo({ left: container.scrollLeft + delta, behavior: 'smooth' });
|
||||
},
|
||||
{ injector: this.injector },
|
||||
);
|
||||
}
|
||||
|
||||
onUpdateTower(towerId: string, result: TowerSettingsResult): void {
|
||||
|
|
|
|||
Loading…
Reference in a new issue