.
This commit is contained in:
parent
f74ee43cb4
commit
e2a60e71a3
30 changed files with 585 additions and 33 deletions
|
|
@ -27,7 +27,11 @@ import { getColorOfTag } from '../../utils/color';
|
|||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@include gravitate();
|
||||
cursor: pointer;
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
@include gravitate();
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
|
|
|
|||
|
|
@ -177,6 +177,11 @@ interface EditedValue {
|
|||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
scroll-behavior: smooth;
|
||||
scroll-snap-type: x mandatory;
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
padding: 0 7.5vw;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 0;
|
||||
|
|
@ -192,8 +197,12 @@ interface EditedValue {
|
|||
flex: 0 0 auto;
|
||||
width: 66vw;
|
||||
max-width: 400px;
|
||||
scroll-snap-align: center;
|
||||
@media (max-width: $mobile-width) {
|
||||
width: 300px;
|
||||
width: 85vw;
|
||||
max-width: 85vw;
|
||||
padding: var(--medium-padding);
|
||||
margin: calc(var(--medium-padding) / 2);
|
||||
opacity: 1 !important;
|
||||
}
|
||||
box-sizing: border-box;
|
||||
|
|
@ -246,6 +255,10 @@ interface EditedValue {
|
|||
opacity: 0 !important;
|
||||
width: 60vw;
|
||||
max-width: 60vw;
|
||||
@media (max-width: $mobile-width) {
|
||||
width: 7.5vw;
|
||||
max-width: 7.5vw;
|
||||
}
|
||||
box-shadow: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
|
@ -256,7 +269,7 @@ interface EditedValue {
|
|||
|
||||
.exit {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
@include exit();
|
||||
}
|
||||
|
||||
|
|
@ -291,6 +304,13 @@ interface EditedValue {
|
|||
transform: translateY(-50%) translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
lt-select-add, lt-toggle {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
|
@ -389,10 +409,13 @@ export class BlockEditComponent implements AfterViewInit {
|
|||
|
||||
formatDate(ts: number): string {
|
||||
const d = new Date(ts * 1000);
|
||||
return d.toLocaleDateString(undefined, {
|
||||
// e.g. "May 28, 2026, 14:32"
|
||||
return d.toLocaleString(undefined, {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,14 @@ import { ModalStateService } from '../../services/modal-state.service';
|
|||
styles: `
|
||||
@import '../../../library/main';
|
||||
|
||||
/* lt-modal host must not occupy a flex slot in its parent — section.modal
|
||||
is position:fixed, but the host element itself would otherwise take a
|
||||
slot and push siblings around when it mounts/unmounts.
|
||||
display: contents removes the host box without affecting descendants. */
|
||||
:host {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
section.modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
|
|
|||
|
|
@ -111,7 +111,11 @@ const UUIDV4_RE =
|
|||
@include card();
|
||||
width: 66vw;
|
||||
max-width: 480px;
|
||||
@media (max-width: $mobile-width) { width: 300px; }
|
||||
@media (max-width: $mobile-width) {
|
||||
width: 88vw;
|
||||
max-width: 88vw;
|
||||
padding: var(--medium-padding);
|
||||
}
|
||||
box-sizing: border-box;
|
||||
padding: var(--large-padding);
|
||||
position: relative;
|
||||
|
|
@ -171,6 +175,13 @@ const UUIDV4_RE =
|
|||
button {
|
||||
margin: 0;
|
||||
flex: 0 0 auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
flex-wrap: wrap;
|
||||
input { width: 100%; }
|
||||
button { margin-left: auto; }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,7 @@ export interface TowerSettingsResult {
|
|||
imports: [ReactiveFormsModule, ColorPickerComponent],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: `
|
||||
<div class="header">
|
||||
<div class="exit" (click)="close.emit()" role="button" aria-label="Close"></div>
|
||||
<h2>{{ tower() ? 'Tower settings' : 'New tower' }}</h2>
|
||||
</div>
|
||||
<div class="exit" (click)="close.emit()" role="button" aria-label="Close"></div>
|
||||
|
||||
<form [formGroup]="form" (ngSubmit)="onSubmit()">
|
||||
<input
|
||||
|
|
@ -32,12 +29,15 @@ export interface TowerSettingsResult {
|
|||
name="towerName"
|
||||
type="text"
|
||||
formControlName="name"
|
||||
placeholder="Tower name…"
|
||||
[placeholder]="tower() ? 'Tower name…' : 'New tower'"
|
||||
maxlength="200"
|
||||
autocomplete="off"
|
||||
class="title-input"
|
||||
/>
|
||||
|
||||
<lt-color-picker [color]="currentColor" (colorChange)="onColorChange($event)" />
|
||||
<div class="picker-row">
|
||||
<lt-color-picker [color]="currentColor" (colorChange)="onColorChange($event)" />
|
||||
</div>
|
||||
|
||||
<button type="submit" [disabled]="form.invalid">
|
||||
{{ tower() ? 'Save' : 'Create tower' }}
|
||||
|
|
@ -55,26 +55,41 @@ export interface TowerSettingsResult {
|
|||
@include card();
|
||||
width: 66vw;
|
||||
max-width: 400px;
|
||||
@media (max-width: $mobile-width) { width: 300px; }
|
||||
@media (max-width: $mobile-width) {
|
||||
width: 88vw;
|
||||
max-width: 88vw;
|
||||
padding: var(--medium-padding);
|
||||
}
|
||||
box-sizing: border-box;
|
||||
padding: var(--large-padding);
|
||||
padding-top: calc(var(--large-padding) + var(--medium-padding));
|
||||
position: relative;
|
||||
box-shadow: $shadow;
|
||||
@include inner-spacing(var(--large-padding));
|
||||
display: block;
|
||||
|
||||
.header {
|
||||
@include center-child();
|
||||
|
||||
.exit {
|
||||
position: absolute;
|
||||
left: var(--large-padding);
|
||||
@include exit();
|
||||
}
|
||||
.exit {
|
||||
position: absolute;
|
||||
top: var(--medium-padding);
|
||||
right: var(--medium-padding);
|
||||
@include exit();
|
||||
}
|
||||
|
||||
input[type='text'] {
|
||||
form {
|
||||
@include inner-spacing(var(--large-padding));
|
||||
}
|
||||
|
||||
.title-input {
|
||||
@include title-text();
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
// Generous gap between the name input and the color picker — the picker
|
||||
// is a substantial control and crowding it against the title looks busy.
|
||||
.picker-row {
|
||||
padding-top: var(--medium-padding);
|
||||
}
|
||||
|
||||
button {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,9 @@
|
|||
&:not(:nth-last-child(1)) {
|
||||
margin-right: var(--medium-padding);
|
||||
@media (max-width: $mobile-width) {
|
||||
margin-right: var(--small-padding);
|
||||
// Was --small-padding (7.5px) — too tight to read as a real gap
|
||||
// between white tower cards on the cream-pink background.
|
||||
margin-right: var(--medium-padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -76,6 +78,35 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile: fixed-width towers with horizontal scroll (1.5-column rhythm).
|
||||
// This block is declared AFTER the @for loop so it wins the specificity race
|
||||
// without needing !important on every property — only the width triples need it
|
||||
// to beat the per-child-count selectors generated above.
|
||||
@media (max-width: $mobile-width) {
|
||||
overflow-x: auto;
|
||||
overflow-y: visible;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scroll-snap-type: x mandatory;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
// Side padding lets the first and last tower scroll fully into view.
|
||||
padding: 0 var(--medium-padding);
|
||||
max-width: 100%;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Override the @for width-calc rules above.
|
||||
& > * {
|
||||
width: calc(66vw - var(--small-padding)) !important;
|
||||
max-width: calc(66vw - var(--small-padding)) !important;
|
||||
min-width: calc(66vw - var(--small-padding)) !important;
|
||||
scroll-snap-align: start;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.double-slider-container {
|
||||
|
|
@ -89,7 +120,11 @@
|
|||
@include card();
|
||||
width: 66vw;
|
||||
max-width: 500px;
|
||||
@media (max-width: $mobile-width) { width: 300px; }
|
||||
@media (max-width: $mobile-width) {
|
||||
width: 88vw;
|
||||
max-width: 88vw;
|
||||
padding: var(--medium-padding);
|
||||
}
|
||||
box-sizing: border-box;
|
||||
padding: var(--large-padding);
|
||||
position: relative;
|
||||
|
|
@ -101,7 +136,7 @@
|
|||
@include center-child();
|
||||
.exit {
|
||||
position: absolute;
|
||||
left: var(--large-padding);
|
||||
right: var(--large-padding);
|
||||
@include exit();
|
||||
}
|
||||
}
|
||||
|
|
@ -115,11 +150,21 @@
|
|||
justify-content: center;
|
||||
gap: var(--large-padding);
|
||||
|
||||
button {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
button.danger {
|
||||
color: #b53f3f;
|
||||
border-bottom-color: #b53f3f55;
|
||||
&:after { background-color: #b53f3f; }
|
||||
}
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
flex-direction: column;
|
||||
gap: var(--small-padding);
|
||||
button { width: 100%; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,14 +11,23 @@
|
|||
|
||||
.select-add-container {
|
||||
width: 250px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
@media (max-width: $mobile-width) {
|
||||
width: 80vw;
|
||||
max-width: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
.page-container {
|
||||
flex: 1 0 auto;
|
||||
// Generous breathing room between the page selector dropdown and the
|
||||
// towers — the dropdown can open downward without crowding the towers.
|
||||
padding-top: var(--large-padding);
|
||||
@media (max-width: $mobile-width) {
|
||||
padding-top: var(--medium-padding);
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
|
|
@ -27,5 +36,10 @@
|
|||
&.transparent {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
margin-top: var(--medium-padding);
|
||||
font-size: var(--medium-font-size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,11 @@ export interface DoubleSliderRange<T> {
|
|||
position: relative;
|
||||
margin: calc(#{$slider-size} / 2) auto 0 auto;
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
max-width: 90vw;
|
||||
margin-top: calc(#{$slider-size} / 2);
|
||||
}
|
||||
|
||||
label { display: none; }
|
||||
|
||||
input[type='range'] {
|
||||
|
|
@ -145,6 +150,12 @@ export interface DoubleSliderRange<T> {
|
|||
transition: transform $long-animation-time;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
font-size: var(--small-font-size);
|
||||
margin-top: $slider-size;
|
||||
span { margin-top: 10px; }
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
|
|
|
|||
|
|
@ -92,6 +92,10 @@ import { getColorOfTag } from '../../utils/color';
|
|||
align-items: center;
|
||||
gap: var(--small-padding);
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
gap: calc(var(--small-padding) / 2);
|
||||
}
|
||||
|
||||
&:hover p {
|
||||
@media (min-width: $mobile-width) {
|
||||
color: inherit !important;
|
||||
|
|
|
|||
|
|
@ -166,6 +166,11 @@ interface StyledBlock extends Block {
|
|||
|
||||
@include inner-spacing(var(--medium-padding));
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
@include inner-spacing(var(--small-padding));
|
||||
padding: var(--small-padding);
|
||||
}
|
||||
|
||||
width: 100%;
|
||||
|
||||
:before {
|
||||
|
|
@ -191,6 +196,11 @@ interface StyledBlock extends Block {
|
|||
display: block;
|
||||
width: 100%;
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
min-height: 44px;
|
||||
max-height: 25vh;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-height: 100%;
|
||||
overflow-y: auto;
|
||||
|
|
@ -261,6 +271,10 @@ interface StyledBlock extends Block {
|
|||
@media (min-width: $mobile-width) {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,11 @@ import { Component, ChangeDetectionStrategy, output } from '@angular/core';
|
|||
@include card();
|
||||
width: 66vw;
|
||||
max-width: 480px;
|
||||
@media (max-width: $mobile-width) { width: 300px; }
|
||||
@media (max-width: $mobile-width) {
|
||||
width: 88vw;
|
||||
max-width: 88vw;
|
||||
padding: var(--medium-padding);
|
||||
}
|
||||
box-sizing: border-box;
|
||||
padding: var(--large-padding);
|
||||
position: relative;
|
||||
|
|
@ -72,6 +76,10 @@ import { Component, ChangeDetectionStrategy, output } from '@angular/core';
|
|||
gap: var(--large-padding);
|
||||
margin-top: var(--large-padding);
|
||||
|
||||
button {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
button.primary {
|
||||
color: $accent-color;
|
||||
border-bottom-color: rgba($accent-color, 0.33);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue