@@ -18,10 +18,45 @@
*ngIf="associatedDateSeries | async as associatedDateSeries; else loading"
@chipTransition
[disabled]="disabled"
- (click)="$event.stopPropagation(); onClick($event)"
+ (click)="$event.stopPropagation(); editModal.present()"
>
{{ label | translate }}
+
+
+
+
+
+
+
+
+
+
+ {{
+ 'schedule.toCalendar.reviewModal.DOWNLOAD'
+ | translate
+ | titlecase
+ }}
+
+
+
+
+
+
diff --git a/src/app/modules/data/chips/data/add-event-action-chip.scss b/src/app/modules/data/chips/data/add-event-action-chip.scss
index 04f80941..bc4eccb8 100644
--- a/src/app/modules/data/chips/data/add-event-action-chip.scss
+++ b/src/app/modules/data/chips/data/add-event-action-chip.scss
@@ -1,3 +1,19 @@
+/*!
+ * Copyright (C) 2022 StApps
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+@import "src/theme/common/ion-content-parallax";
+
:host {
display: block;
padding: var(--spacing-sm);
@@ -17,3 +33,14 @@
grid-column-start: 1;
grid-row-start: 1;
}
+
+.modal-content {
+ --background: var(--ion-color-primary);
+ --color: var(--ion-color-primary-contrast);
+
+ @include ion-content-parallax($content-size: 160px)
+}
+
+ion-footer > ion-toolbar {
+ --border-color: var(--ion-color-light-shade);
+}
diff --git a/src/app/modules/data/chips/edit-event-selection.component.ts b/src/app/modules/data/chips/edit-event-selection.component.ts
new file mode 100644
index 00000000..89c5af88
--- /dev/null
+++ b/src/app/modules/data/chips/edit-event-selection.component.ts
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2022 StApps
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+import {
+ ChangeDetectorRef,
+ Component,
+ EventEmitter,
+ Input,
+ OnInit,
+ Output,
+} from '@angular/core';
+import {ModalController, PopoverController} from '@ionic/angular';
+import {SCDateSeries} from '@openstapps/core';
+import {
+ DateSeriesRelevantData,
+ ScheduleProvider,
+ toDateSeriesRelevantData,
+} from '../../calendar/schedule.provider';
+import {CalendarService} from '../../calendar/calendar.service';
+import {ThingTranslatePipe} from '../../../translation/thing-translate.pipe';
+import {groupBy, groupByProperty} from '../../../_helpers/collections/group-by';
+import {mapValues} from '../../../_helpers/collections/map-values';
+import {stringSortBy} from '../../../_helpers/collections/string-sort';
+import {uniqBy} from '../../../_helpers/collections/uniq';
+import {differenceBy} from '../../../_helpers/collections/difference';
+import {SelectionValue, TreeNode} from './tree-node';
+
+/**
+ * Shows a horizontal list of action chips
+ */
+@Component({
+ selector: 'stapps-edit-event-selection',
+ templateUrl: 'edit-event-selection.html',
+ styleUrls: ['edit-event-selection.scss'],
+})
+export class EditEventSelectionComponent implements OnInit {
+ /**
+ * The item the action belongs to
+ */
+ @Input() items: SCDateSeries[];
+
+ /**
+ * Selection of the item
+ */
+ selection: TreeNode>;
+
+ /**
+ * Uuids
+ */
+ partialDateSeries: DateSeriesRelevantData[];
+
+ @Output()
+ modified = new EventEmitter();
+
+ constructor(
+ readonly ref: ChangeDetectorRef,
+ readonly scheduleProvider: ScheduleProvider,
+ readonly popoverController: PopoverController,
+ readonly calendar: CalendarService,
+ readonly modalController: ModalController,
+ readonly thingTranslatePipe: ThingTranslatePipe,
+ ) {}
+
+ ngOnInit() {
+ this.partialDateSeries = this.scheduleProvider.partialEvents$.value;
+ this.reset();
+ }
+
+ private getSelection(): {
+ selected: DateSeriesRelevantData[];
+ unselected: DateSeriesRelevantData[];
+ } {
+ const selection = mapValues(
+ groupByProperty(
+ this.selection.children.flatMap(it => it.children),
+ 'selected',
+ ),
+ value => value.map(it => toDateSeriesRelevantData(it.item)),
+ );
+
+ return {selected: selection.true ?? [], unselected: selection.false ?? []};
+ }
+
+ getModifiedEvents(): DateSeriesRelevantData[] {
+ const {selected, unselected} = this.getSelection();
+
+ return uniqBy(
+ [
+ ...differenceBy(this.partialDateSeries, unselected, it => it.uid),
+ ...selected,
+ ],
+ it => it.uid,
+ );
+ }
+
+ reset() {
+ this.selection = new TreeNode(
+ Object.values(
+ groupBy(
+ this.items
+ .map(item => ({
+ selected: this.partialDateSeries.some(it => it.uid === item.uid),
+ item: item,
+ }))
+ .sort(stringSortBy(it => it.item.repeatFrequency)),
+ it => it.item.repeatFrequency,
+ ),
+ ).map(item => new TreeNode(item, this.ref)),
+ this.ref,
+ );
+ }
+
+ /**
+ * Save selection
+ */
+ save() {
+ this.scheduleProvider.partialEvents$.next(this.getModifiedEvents());
+ }
+}
diff --git a/src/app/modules/data/chips/edit-event-selection.html b/src/app/modules/data/chips/edit-event-selection.html
new file mode 100644
index 00000000..d7bd5696
--- /dev/null
+++ b/src/app/modules/data/chips/edit-event-selection.html
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+ 1; else single_event"
+ class="ion-text-wrap"
+ >
+ {{ date.item.duration | amDuration: 'hours' }}
+ {{ 'data.chips.add_events.popover.AT' | translate }}
+ {{ date.item.dates[0] | amDateFormat: 'HH:mm ddd' }}
+ {{ 'data.chips.add_events.popover.UNTIL' | translate }}
+ {{ date.item.dates[date.item.dates.length - 1] | amDateFormat: 'll' }}
+
+
+
+ {{ date.item.duration | amDuration: 'hours' }}
+ {{ 'data.chips.add_events.popover.AT' | translate }}
+ {{
+ date.item.dates[date.item.dates.length - 1]
+ | amDateFormat: 'll, HH:mm'
+ }}
+
+
+
+
+
+
diff --git a/src/app/modules/data/chips/edit-event-selection.scss b/src/app/modules/data/chips/edit-event-selection.scss
new file mode 100644
index 00000000..a9285207
--- /dev/null
+++ b/src/app/modules/data/chips/edit-event-selection.scss
@@ -0,0 +1,45 @@
+/*!
+ * Copyright (C) 2022 StApps
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+ion-item-divider.ios > ion-checkbox {
+ margin-right: 8px;
+}
+
+
+.list-header {
+ --padding-start: 0;
+ --background: var(--ion-color-primary-shade);
+
+ > ion-list-header {
+ --color: var(--ion-color-primary-contrast);
+ --background: none;
+ }
+
+ > ion-checkbox {
+ --background: none;
+ --border-color: rgba(var(--ion-color-primary-contrast-rgb), 0.77);
+ --background-checked: var(--ion-color-primary-contrast);
+ --border-color-checked: var(--ion-color-primary-contrast);
+ --checkmark-color: var(--ion-color-primary)
+ }
+}
+
+:host > .list-header {
+ --background: none;
+}
+
+ion-list.md {
+ padding-top: 0;
+}
diff --git a/src/app/modules/data/chips/tree-node.ts b/src/app/modules/data/chips/tree-node.ts
new file mode 100644
index 00000000..07239bd4
--- /dev/null
+++ b/src/app/modules/data/chips/tree-node.ts
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2022 StApps
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+import {ChangeDetectorRef} from '@angular/core';
+import {SCDateSeries} from '@openstapps/core';
+
+export enum Selection {
+ ON = 2,
+ PARTIAL = 1,
+ OFF = 1,
+}
+
+/**
+ * A tree
+ *
+ * The generic is to preserve type safety of how deep the tree goes.
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export class TreeNode | SelectionValue> {
+ /**
+ * Value of this node
+ */
+ checked: boolean;
+
+ /**
+ * If items are partially selected
+ */
+ indeterminate: boolean;
+
+ /**
+ * Parent of this node
+ */
+ parent?: TreeNode>;
+
+ constructor(readonly children: T[], readonly ref: ChangeDetectorRef) {
+ this.updateParents();
+ this.accumulateApplyValues();
+ }
+
+ /**
+ * Accumulate values of children to set current value
+ */
+ private accumulateApplyValues() {
+ const selections: number[] = this.children.map(it =>
+ it instanceof TreeNode
+ ? it.checked
+ ? Selection.ON
+ : it.indeterminate
+ ? Selection.PARTIAL
+ : Selection.OFF
+ : (it as SelectionValue).selected
+ ? Selection.ON
+ : Selection.OFF,
+ );
+
+ this.checked = selections.every(it => it === Selection.ON);
+ this.indeterminate = this.checked
+ ? false
+ : selections.some(it => it > Selection.OFF);
+ }
+
+ /**
+ * Apply the value of this node to all child nodes
+ */
+ private applyValueDownwards() {
+ for (const child of this.children) {
+ if (child instanceof TreeNode) {
+ child.checked = this.checked;
+ child.indeterminate = false;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (child as TreeNode).applyValueDownwards();
+ } else {
+ (child as SelectionValue).selected = this.checked;
+ }
+ }
+ }
+
+ /**
+ * Set all children's parent to this
+ */
+ private updateParents() {
+ for (const child of this.children) {
+ if (child instanceof TreeNode) {
+ child.parent = this as TreeNode>;
+ }
+ }
+ }
+
+ /**
+ * Update values to all parents upwards
+ */
+ private updateValueUpwards() {
+ this.parent?.accumulateApplyValues();
+ this.parent?.updateValueUpwards();
+ }
+
+ /**
+ * Click on this node
+ */
+ click() {
+ this.checked = !this.checked;
+ this.indeterminate = false;
+ this.applyValueDownwards();
+ this.updateValueUpwards();
+ }
+
+ /**
+ * Notify that a child's value has changed
+ */
+ notifyChildChanged() {
+ this.accumulateApplyValues();
+ this.updateValueUpwards();
+ }
+}
+
+export interface SelectionValue {
+ /**
+ * Item that was selected
+ */
+ item: SCDateSeries;
+
+ /**
+ * Selection
+ */
+ selected: boolean;
+}
diff --git a/src/app/modules/data/data.module.ts b/src/app/modules/data/data.module.ts
index b83c4ba5..0784c78a 100644
--- a/src/app/modules/data/data.module.ts
+++ b/src/app/modules/data/data.module.ts
@@ -1,16 +1,16 @@
/*
* Copyright (C) 2022 StApps
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, version 3.
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 3.
*
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see .
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
*/
import {ScrollingModule} from '@angular/cdk/scrolling';
import {CommonModule} from '@angular/common';
@@ -26,7 +26,7 @@ import {MenuModule} from '../menu/menu.module';
import {ScheduleProvider} from '../calendar/schedule.provider';
import {StorageModule} from '../storage/storage.module';
import {ActionChipListComponent} from './chips/action-chip-list.component';
-import {AddEventPopoverComponent} from './chips/add-event-popover.component';
+import {EditEventSelectionComponent} from './chips/edit-event-selection.component';
import {AddEventActionChipComponent} from './chips/data/add-event-action-chip.component';
import {LocateActionChipComponent} from './chips/data/locate-action-chip.component';
import {DataFacetsProvider} from './data-facets.provider';
@@ -99,7 +99,7 @@ import {ExternalLinkComponent} from './elements/external-link.component';
declarations: [
ActionChipListComponent,
AddEventActionChipComponent,
- AddEventPopoverComponent,
+ EditEventSelectionComponent,
AddressDetailComponent,
ArticleDetailContentComponent,
ArticleListItemComponent,
diff --git a/src/app/util/edit-modal.component.ts b/src/app/util/edit-modal.component.ts
new file mode 100644
index 00000000..364e841b
--- /dev/null
+++ b/src/app/util/edit-modal.component.ts
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 StApps
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+import {
+ Component,
+ ContentChild,
+ EventEmitter,
+ Input,
+ OnInit,
+ Output,
+ TemplateRef,
+ ViewChild,
+} from '@angular/core';
+import {
+ ActionSheetController,
+ AlertController,
+ Config,
+ IonModal,
+ IonRouterOutlet,
+ ModalController,
+} from '@ionic/angular';
+import {
+ pendingChangesActionSheet,
+ PendingChangesRole,
+} from './pending-changes-action-sheet';
+import {TranslatePipe} from '@ngx-translate/core';
+
+@Component({
+ selector: 'stapps-edit-modal',
+ templateUrl: 'edit-modal.html',
+})
+export class EditModalComponent implements OnInit {
+ @ContentChild(TemplateRef) content: TemplateRef;
+
+ @ViewChild('modal') modal: IonModal;
+
+ @Input() pendingChanges = false;
+
+ @Output() save = new EventEmitter();
+
+ presentingElement: HTMLElement;
+
+ constructor(
+ readonly modalController: ModalController,
+ readonly routerOutlet: IonRouterOutlet,
+ readonly alertController: AlertController,
+ readonly actionSheetController: ActionSheetController,
+ readonly translatePipe: TranslatePipe,
+ readonly config: Config,
+ ) {}
+
+ async ngOnInit() {
+ this.presentingElement =
+ (await this.modalController.getTop()) || this.routerOutlet.nativeEl;
+ }
+
+ present() {
+ this.modal.present();
+ this.pendingChanges = false;
+ }
+
+ dismiss(skipChanges = false) {
+ this.pendingChanges = skipChanges ? false : this.pendingChanges;
+ setTimeout(() => this.modal.dismiss());
+ }
+
+ canDismissModal = async () => {
+ const alert =
+ this.config.get('mode') === 'ios'
+ ? await this.actionSheetController.create(
+ pendingChangesActionSheet(this.translatePipe),
+ )
+ : await this.alertController.create(
+ pendingChangesActionSheet(this.translatePipe, false),
+ );
+ alert.present().then();
+
+ const {role} = await alert.onWillDismiss();
+ if (role === PendingChangesRole.SAVE) {
+ this.save.emit();
+ }
+
+ return role !== 'backdrop' && role !== PendingChangesRole.CANCEL;
+ };
+}
diff --git a/src/app/util/edit-modal.html b/src/app/util/edit-modal.html
new file mode 100644
index 00000000..8958243f
--- /dev/null
+++ b/src/app/util/edit-modal.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+ {{ 'modal.TITLE_EDIT' | translate }}
+
+ {{
+ 'modal.DISMISS_CONFIRM' | translate
+ }}
+
+
+ {{
+ 'modal.DISMISS_CANCEL' | translate
+ }}
+
+
+
+
+
+
diff --git a/src/app/util/pending-changes-action-sheet.ts b/src/app/util/pending-changes-action-sheet.ts
new file mode 100644
index 00000000..681b1afa
--- /dev/null
+++ b/src/app/util/pending-changes-action-sheet.ts
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 StApps
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+import {TranslatePipe} from '@ngx-translate/core';
+import {ActionSheetOptions, AlertOptions} from '@ionic/angular';
+
+export enum PendingChangesRole {
+ SAVE = 'save',
+ DISCARD = 'discard',
+ CANCEL = 'cancel',
+}
+
+/**
+ *
+ */
+export function pendingChangesActionSheet(
+ translatePipe: TranslatePipe,
+ includeSaveOption = true,
+): ActionSheetOptions & AlertOptions {
+ return {
+ header: translatePipe.transform('modal.dismiss_warn_pending_changes.TITLE'),
+ buttons: [
+ ...(includeSaveOption
+ ? [
+ {
+ text: translatePipe.transform(
+ 'modal.dismiss_warn_pending_changes.SAVE',
+ ),
+ role: PendingChangesRole.SAVE,
+ },
+ ]
+ : []),
+ {
+ text: translatePipe.transform(
+ 'modal.dismiss_warn_pending_changes.CANCEL',
+ ),
+ role: PendingChangesRole.CANCEL,
+ },
+ {
+ text: translatePipe.transform(
+ 'modal.dismiss_warn_pending_changes.DISCARD',
+ ),
+ role: PendingChangesRole.DISCARD,
+ },
+ ],
+ };
+}
diff --git a/src/app/util/util.module.ts b/src/app/util/util.module.ts
index ae9126b4..0e696d25 100644
--- a/src/app/util/util.module.ts
+++ b/src/app/util/util.module.ts
@@ -1,16 +1,16 @@
/*
* Copyright (C) 2022 StApps
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, version 3.
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 3.
*
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see .
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
*/
import {NgModule} from '@angular/core';
@@ -21,8 +21,13 @@ import {DateFromIndexPipe} from './date-from-index.pipe';
import {DaytimeKeyPipe} from './daytime-key.pipe';
import {LazyPipe} from './lazy.pipe';
import {NextDateInListPipe} from './next-date-in-list.pipe';
+import {EditModalComponent} from './edit-modal.component';
+import {BrowserModule} from '@angular/platform-browser';
+import {IonicModule} from '@ionic/angular';
+import {TranslateModule} from '@ngx-translate/core';
@NgModule({
+ imports: [BrowserModule, IonicModule, TranslateModule],
declarations: [
ArrayLastPipe,
DateIsThisPipe,
@@ -31,6 +36,7 @@ import {NextDateInListPipe} from './next-date-in-list.pipe';
DateFromIndexPipe,
DaytimeKeyPipe,
NextDateInListPipe,
+ EditModalComponent,
],
exports: [
ArrayLastPipe,
@@ -40,6 +46,7 @@ import {NextDateInListPipe} from './next-date-in-list.pipe';
DateFromIndexPipe,
DaytimeKeyPipe,
NextDateInListPipe,
+ EditModalComponent,
],
})
export class UtilModule {}
diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json
index 103e0da4..9f15d564 100644
--- a/src/assets/i18n/de.json
+++ b/src/assets/i18n/de.json
@@ -11,6 +11,13 @@
"DISMISS_CANCEL": "Abbrechen",
"DISMISS_CONFIRM": "Bestätigen",
"DISMISS": "Schließen",
+ "TITLE_EDIT": "Bearbeiten",
+ "dismiss_warn_pending_changes": {
+ "TITLE": "Ausstehende Änderungen",
+ "SAVE": "Speichern",
+ "DISCARD": "Verwerfen",
+ "CANCEL": "Abbrechen"
+ },
"settings": "Einstellungen"
},
"app": {
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 6cbf1883..078960e7 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -11,6 +11,13 @@
"DISMISS_CANCEL": "Cancel",
"DISMISS_CONFIRM": "Confirm",
"DISMISS": "Close",
+ "TITLE_EDIT": "Edit",
+ "dismiss_warn_pending_changes": {
+ "TITLE": "Pending changes",
+ "SAVE": "Save",
+ "DISCARD": "Discard",
+ "CANCEL": "Cancel"
+ },
"settings": "Settings"
},
"app": {
diff --git a/src/theme/common/_ion-content-parallax.scss b/src/theme/common/_ion-content-parallax.scss
index c3845589..4e26f1d0 100644
--- a/src/theme/common/_ion-content-parallax.scss
+++ b/src/theme/common/_ion-content-parallax.scss
@@ -17,14 +17,15 @@
$parallax-background: var(--ion-color-primary),
$background: var(--ion-color-light),
$parallax-strength: 2,
- $overscroll-padding: 50vh,
- $content-size: 0px,
+ $overscroll-padding: 720px,
+ $content-size: 230px,
) {
&::part(background) {
background: $background;
}
&::part(scroll) {
perspective: 2px;
+ perspective-origin: center top;
}
> div {
transform-style: preserve-3d;
@@ -35,13 +36,21 @@
position: absolute;
top: 0;
right: 0;
- height: calc(#{$content-size} + #{$parallax-strength} * #{$overscroll-padding});
- width: 200%;
+ left: 0;
+
+ $height: calc($content-size + $overscroll-padding);
+ $translateY: calc($overscroll-padding * $parallax-strength);
+ $translateZ: calc(-1px * $parallax-strength);
+ $transform-origin: calc($parallax-strength * $parallax-strength * $overscroll-padding);
+
+ height: $height;
+ width: 150%;
+ transform-origin: 50% $transform-origin;
transform:
- translateY(calc(-#{$overscroll-padding} * #{$parallax-strength}))
- translateZ(calc(-1px * #{$parallax-strength}))
- scale(1.5);
+ translate3d(0px, $translateY, $translateZ)
+ scale($parallax-strength);
z-index: -1;
+
background: $parallax-background;
}
}