@progressive-development/pd-page 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/PdMenu.js ADDED
@@ -0,0 +1,244 @@
1
+ /* eslint-disable lit-a11y/click-events-have-key-events */
2
+ /**
3
+ * @license
4
+ * Copyright (c) 2021 PD Progressive Development UG. All rights reserved.
5
+ */
6
+
7
+ import { LitElement, html, css } from 'lit';
8
+
9
+ import '@progressive-development/pd-icon/pd-icon.js';
10
+
11
+ /**
12
+ * An example element.
13
+ *
14
+ * @slot - This element has a slot
15
+ * @csspart button - The button
16
+ */
17
+ export class PdMenu extends LitElement {
18
+ /**
19
+ * Fired when route menu item clicked
20
+ * @event route-event
21
+ */
22
+
23
+ static get styles() {
24
+ return css`
25
+ :host {
26
+ --my-height: var(--squi-teaser-height, 80px);
27
+
28
+ --my-bg-color: var(--squi-menu-bg-color, #177e89);
29
+ --my-header-text-color: var(--squi-test, white);
30
+
31
+ --my-background: var(--squi-teaser-image, url('/images/hero_1.svg'));
32
+
33
+ display: flex;
34
+ background-color: var(--my-bg-color);
35
+ height: var(--my-height);
36
+ width: 100%;
37
+
38
+ box-shadow: 3px 3px 5px grey;
39
+ }
40
+
41
+ ul {
42
+ padding-left: 0px;
43
+ display: flex;
44
+ justify-content: flex-start;
45
+ align-items: flex-start;
46
+ max-width: 1170px;
47
+ margin: 0 auto;
48
+ list-style: none;
49
+ margin-top: 0px;
50
+ height: 100%;
51
+ }
52
+
53
+ li {
54
+ display: flex;
55
+ align-items: center;
56
+ padding: 0rem 1.1rem;
57
+ cursor: pointer;
58
+ height: 100%;
59
+ }
60
+
61
+ .item {
62
+ color: #fefefe;
63
+ font-family: Oswald, sans-serif;
64
+ font-size: 1.2rem;
65
+
66
+ --squi-icon-fill: var(--my-header-text-color);
67
+ }
68
+ .item.active {
69
+ color: #ffc857;
70
+ }
71
+ .item:hover {
72
+ color: #ffc857;
73
+ /*border-bottom: 1px solid #FFC857;*/
74
+ /* Hack? => Set also Icon to hover color, else they react different
75
+ (hover on text => icon not with hover color...)
76
+ This is also the reason why icon-fill is defined for item, not for topMenuItem
77
+ Erkennbar: Farbe Icon leicht unterschiedlich zu Farbe Text nach hover icon.
78
+ */
79
+ --squi-icon-fill: #ffc857;
80
+ }
81
+
82
+ .logo {
83
+ max-width: 8rem;
84
+ width: 8rem; /* wird sonst im Chrome nicht angezeigt*/
85
+ }
86
+
87
+ .topItemLogo {
88
+ --squi-icon-size: 1.6rem;
89
+ --icon-transition: none;
90
+ pointer-events: none;
91
+ }
92
+
93
+ .topMenu {
94
+ margin-top: -15px;
95
+ }
96
+
97
+ /* Size Elements for small width */
98
+ @media (max-width: 440px) {
99
+ .item {
100
+ display: none;
101
+ }
102
+ }
103
+ `;
104
+ }
105
+
106
+ static get properties() {
107
+ return {
108
+ logo: { type: Object },
109
+ menuItems: { type: Array },
110
+ topMenuItems: { type: Array },
111
+ teaserClosed: { type: Boolean }, // TODO: Definiert um scroll position anzugleichen, unabhängiger machen...
112
+ _activeSecIndex: { type: Number },
113
+ };
114
+ }
115
+
116
+ constructor() {
117
+ super();
118
+ this.logo = {};
119
+ this.menuItems = [];
120
+ this.topMenuItems = [];
121
+ this.teaserClosed = false;
122
+
123
+ this._activeSecIndex = 0;
124
+ }
125
+
126
+ firstUpdated() {
127
+ const doSomething = scrollPos => {
128
+ let activeSecIndex = -1;
129
+ let distance = scrollPos > 300 ? 5000 : 300; // start value, define when first item is active
130
+ this.menuItems.forEach((item, index) => {
131
+ if (item.ref) {
132
+ let distTmp = item.ref.getBoundingClientRect().top;
133
+ distTmp = Math.abs(distTmp);
134
+ if (item.ref && distTmp < distance) {
135
+ activeSecIndex = index;
136
+ distance = distTmp;
137
+ }
138
+ }
139
+ });
140
+ this._activeSecIndex = activeSecIndex >= 0 ? activeSecIndex + 1 : 0;
141
+ };
142
+
143
+ let ticking = false;
144
+ document.addEventListener('scroll', () => {
145
+ const lastKnownScrollPosition = window.scrollY;
146
+ if (!ticking) {
147
+ window.requestAnimationFrame(() => {
148
+ doSomething(lastKnownScrollPosition);
149
+ ticking = false;
150
+ });
151
+ ticking = true;
152
+ }
153
+ });
154
+ }
155
+
156
+ render() {
157
+ return html`
158
+ <ul>
159
+ ${this.logo && (this.logo.src || this.logo.svg)
160
+ ? html`
161
+ <li @click="${PdMenu._scrollToTop}">
162
+ ${this.logo.src
163
+ ? html` <img src="${this.logo.src}" alt="" /> `
164
+ : this.logo.svg}
165
+ </li>
166
+ `
167
+ : ''}
168
+ ${this.menuItems.map(
169
+ (item, index) => html`
170
+ <li
171
+ class="item ${this._activeSecIndex === index + 1 ? 'active' : ''}"
172
+ data-sec="${item.sec}"
173
+ data-route="${item.route}"
174
+ @click="${this._menuItemClicked}"
175
+ >
176
+ ${item.name}
177
+ </li>
178
+ `
179
+ )}
180
+ </ul>
181
+
182
+ <ul class="topMenu">
183
+ ${this.topMenuItems.map(
184
+ topItem => html`
185
+ <li
186
+ class="item"
187
+ data-sec="${topItem.sec}"
188
+ data-route="${topItem.route}"
189
+ @click="${this._menuItemClicked}"
190
+ >
191
+ ${topItem.icon
192
+ ? html`<squi-icon
193
+ class="topItemLogo"
194
+ icon="${topItem.icon}"
195
+ ></squi-icon>`
196
+ : ''}
197
+ ${topItem.name}
198
+ </li>
199
+ `
200
+ )}
201
+ </ul>
202
+ `;
203
+ }
204
+
205
+ _menuItemClicked(e) {
206
+ const secParam = e.target.dataset.sec;
207
+ const routeParam = e.target.dataset.route;
208
+ if (secParam !== 'undefined') {
209
+ this._scrollToContent(secParam);
210
+ } else if (routeParam !== 'undefined') {
211
+ this.dispatchEvent(
212
+ new CustomEvent('route-event', {
213
+ detail: {
214
+ route: routeParam,
215
+ },
216
+ })
217
+ );
218
+ }
219
+ }
220
+
221
+ static _scrollToTop() {
222
+ window.scrollTo({
223
+ top: 0,
224
+ left: 0,
225
+ behavior: 'smooth',
226
+ });
227
+ }
228
+
229
+ _scrollToContent(section) {
230
+ // check reference
231
+ const selMenuItem =
232
+ this.menuItems.filter(item => item.sec === section)[0] || {};
233
+ const el = selMenuItem.ref;
234
+ if (el) {
235
+ const rect = el.getBoundingClientRect();
236
+ // https://www.mediaevent.de/javascript/scroll.html
237
+ window.scrollBy({
238
+ top: rect.top - (this.teaserClosed ? 0 : 350),
239
+ left: 0,
240
+ behavior: 'smooth',
241
+ });
242
+ }
243
+ }
244
+ }
@@ -0,0 +1,272 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 PD Progressive Development UG. All rights reserved.
4
+ */
5
+
6
+ import { LitElement, html, css } from 'lit';
7
+
8
+ import '@progressive-development/pd-icon/pd-icon.js';
9
+
10
+ /**
11
+ * An example element.
12
+ *
13
+ * @slot - This element has a slot
14
+ * @csspart button - The button
15
+ */
16
+ export class PdTeaser extends LitElement {
17
+ /**
18
+ * Fired when free date clicked => At the moment only for freeDates
19
+ * @event close-teaser
20
+ */
21
+
22
+ static get styles() {
23
+ return css`
24
+ :host {
25
+
26
+ --my-height: var(--squi-teaser-height, 420px);
27
+
28
+ --my-header-background-color: var(--squi-test, #084c61);
29
+ --my-header-text-color: var(--squi-test, white);
30
+
31
+ --my-footer-background-color: var(--squi-test, #177e89);
32
+
33
+ --my-background: var(--squi-teaser-image, url('/images/hero_1.svg'));
34
+
35
+ display: block;
36
+ background-color: #084c61;
37
+
38
+ }
39
+
40
+ /* Layout Grid for the Wizard Component */
41
+ .teaser {
42
+ display: grid;
43
+ grid-template-columns: minmax(10px, 200px) auto;
44
+ grid-template-rows: var(--my-height);
45
+ grid-template-areas:
46
+ ". content"
47
+ }
48
+
49
+ /* Layout Grid for the Wizard Component */
50
+ .teaser-flex {
51
+ display: flex;
52
+ justify-content: left;
53
+ height: var(--my-height);
54
+ }
55
+ .in-active {
56
+ /* ToDo Ausblenden */
57
+ display: none;
58
+ }
59
+
60
+ .active {
61
+ /* ToDo Einblenden */
62
+ }
63
+
64
+ .previous {
65
+ position: absolute;
66
+ top: calc(var(--my-height) / 2);
67
+ left: 10px;
68
+ z-index: 1;
69
+ --squi-icon-fill: white;
70
+ }
71
+
72
+ .next {
73
+ position: absolute;
74
+ top: calc(var(--my-height) / 2);
75
+ right: 10px;
76
+ z-index: 1;
77
+ --squi-icon-fill: white;
78
+ }
79
+
80
+ .content {
81
+ /*grid-area: content; */
82
+ flex-grow: 4;
83
+ overflow: hidden;
84
+ }
85
+
86
+ .slide-rigth {
87
+ animation-duration:1s;
88
+ animation-name: slideFromLeft;
89
+ }
90
+
91
+ .slide-left {
92
+ animation-duration:1s;
93
+ animation-name: slideFromRigth;
94
+ }
95
+
96
+ @keyframes slideFromRigth {
97
+ from {
98
+ margin-right: 100%;
99
+ }
100
+
101
+ to {
102
+ margin-right: 0%;
103
+ }
104
+ }
105
+
106
+ @keyframes slideFromLeft {
107
+ from {
108
+ margin-left: 100%;
109
+ }
110
+
111
+ to {
112
+ margin-left: 0%;
113
+ }
114
+ }
115
+
116
+ .not-visible {
117
+ display: none;
118
+ }
119
+
120
+ ::slotted(*) {
121
+
122
+ }
123
+
124
+ /* Size Elements for small width */
125
+ @media (max-width: 1400px) {
126
+ :host {
127
+ --my-height: 350px;
128
+ }
129
+
130
+
131
+ /* Size Elements for small width */
132
+ @media (max-width: 900px) {
133
+ :host {
134
+ --my-height: 300px;
135
+ }
136
+ }
137
+
138
+ /* Size Elements for small width */
139
+ @media (max-width: 600px) {
140
+ :host {
141
+ --my-height: 270px;
142
+ }
143
+ }
144
+
145
+
146
+ /* Size Elements for small width */
147
+ @media (max-width: 350px) {
148
+ :host {
149
+ --my-height: 220px;
150
+ }
151
+ }
152
+
153
+ /* Size Elements for small width */
154
+ @media (max-width: 320px) {
155
+ :host {
156
+ --my-height: 250px;
157
+ }
158
+ }
159
+
160
+ `;
161
+ }
162
+
163
+ static get properties() {
164
+ return {
165
+ teaserObjects: { type: Array },
166
+ resizeWidth: { type: String },
167
+ _hideContent: { type: Boolean },
168
+ _currentNumber: { type: Number },
169
+ _slideDirection: { type: String },
170
+ _visible: { type: Boolean },
171
+ };
172
+ }
173
+
174
+ constructor() {
175
+ super();
176
+ this.teaserObjects = [];
177
+ this.resizeWidth = '1232px';
178
+ this._hideContent = false;
179
+ this._currentNumber = 0;
180
+
181
+ this._slideDirection = 'slide-rigth';
182
+ this._visible = true;
183
+ }
184
+
185
+ firstUpdated() {
186
+ // dummy um content zu wechseln
187
+ // window.setTimeout(() => this._nextContent(), 6000);
188
+
189
+ const doSomething = scrollPos => {
190
+ if (scrollPos <= 50) {
191
+ this._visible = true;
192
+ } else {
193
+ this._visible = false;
194
+ }
195
+ };
196
+
197
+ let ticking = false;
198
+ document.addEventListener('scroll', () => {
199
+ const lastKnownScrollPosition = window.scrollY;
200
+ if (!ticking) {
201
+ window.requestAnimationFrame(() => {
202
+ doSomething(lastKnownScrollPosition);
203
+ ticking = false;
204
+ });
205
+ ticking = true;
206
+ }
207
+ });
208
+ }
209
+
210
+ updated(changedProps) {
211
+ if (changedProps.has('_visible')) {
212
+ if (
213
+ (changedProps.get('_visible') === true && this._visible === false) ||
214
+ (changedProps.get('_visible') === false && this._visible === true)
215
+ )
216
+ this.dispatchEvent(
217
+ new CustomEvent('close-teaser', {
218
+ detail: {
219
+ value: this._visible,
220
+ },
221
+ })
222
+ );
223
+ }
224
+ }
225
+
226
+ render() {
227
+ return html`
228
+ <div class="teaser-flex ${this._visible ? '' : 'in-active'}">
229
+ <squi-icon
230
+ icon="previousArrow"
231
+ class="previous"
232
+ @click="${this._prevContent}"
233
+ ></squi-icon>
234
+ <squi-icon
235
+ icon="nextArrow"
236
+ class="next"
237
+ @click="${this._nextContent}"
238
+ ></squi-icon>
239
+
240
+ ${this.teaserObjects.map(
241
+ (teaserObj, index) => html`
242
+ <div
243
+ class="content ${this._currentNumber === index
244
+ ? this._slideDirection
245
+ : 'not-visible'}"
246
+ >
247
+ <slot name="${teaserObj.name}"></slot>
248
+ </div>
249
+ `
250
+ )}
251
+ </div>
252
+ `;
253
+ }
254
+
255
+ _prevContent() {
256
+ this._slideDirection = 'slide-left';
257
+ if (this._currentNumber === 0) {
258
+ this._currentNumber = this.teaserObjects.length - 1;
259
+ } else {
260
+ this._currentNumber -= 1;
261
+ }
262
+ }
263
+
264
+ _nextContent() {
265
+ this._slideDirection = 'slide-rigth';
266
+ if (this._currentNumber === this.teaserObjects.length - 1) {
267
+ this._currentNumber = 0;
268
+ } else {
269
+ this._currentNumber += 1;
270
+ }
271
+ }
272
+ }
@@ -0,0 +1,216 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 PD Progressive Development UG. All rights reserved.
4
+ */
5
+
6
+ import { LitElement, html, css } from 'lit';
7
+
8
+ /**
9
+ * An example element.
10
+ *
11
+ * @slot - This element has a slot
12
+ * @csspart button - The button
13
+ */
14
+ export class PdTeaserContent extends LitElement {
15
+ /**
16
+ * Fired when free date clicked => At the moment only for freeDates
17
+ * @event book-date
18
+ */
19
+
20
+ static get styles() {
21
+ return css`
22
+ :host {
23
+ --my-background: var(--squi-teaser-image, url('/images/hero_1.svg'));
24
+ --my-background-size: var(--squi-teaser-image-size, auto);
25
+ --my-background-position: var(--squi-teaser-image-position, 100% 50%);
26
+
27
+ display: grid;
28
+ grid-template-columns: repeat(15, 1fr);
29
+ grid-template-rows: 1fr 1fr 1fr 1fr 1fr;
30
+ grid-template-areas:
31
+ '. . . . . . . . . . . . . . .'
32
+ '. . t1 t1 t1 t1 t1 t1 . . . . . . .'
33
+ '. . t1 t1 t1 t1 t1 t1 . . . . . . .'
34
+ '. . t1 t1 t1 t1 t1 t1 . . . . . . .'
35
+ '. . . . . . . . . . . . . . .';
36
+
37
+ width: 100%;
38
+ height: 100%;
39
+ background: var(--my-background) no-repeat scroll;
40
+ background-position: var(--my-background-position);
41
+ background-size: var(--my-background-size);
42
+ }
43
+
44
+ .t1 {
45
+ grid-area: t1;
46
+ /*background-color: grey;*/
47
+ }
48
+
49
+ .slide-rigth {
50
+ animation-duration: 1s;
51
+ animation-name: slideFromRigth;
52
+ }
53
+
54
+ @keyframes slideFromRigth {
55
+ from {
56
+ margin-left: 100%;
57
+ width: 300%;
58
+ }
59
+
60
+ to {
61
+ margin-left: 0%;
62
+ width: 100%;
63
+ }
64
+ }
65
+
66
+ @keyframes slideFromLeft {
67
+ from {
68
+ margin-left: 100%;
69
+ width: 300%;
70
+ }
71
+
72
+ to {
73
+ margin-left: 0%;
74
+ width: 100%;
75
+ }
76
+ }
77
+
78
+ h1 {
79
+ color: #fefefe;
80
+ font-size: 2.2rem;
81
+ font-family: Oswald, sans-serif;
82
+ line-height: 1.4;
83
+ margin-top: 0;
84
+ margin-bottom: 0.5rem;
85
+ }
86
+
87
+ h1::after {
88
+ content: ' ';
89
+ display: block;
90
+ width: 2.5rem;
91
+ height: 0.125rem;
92
+ background: #fefefe;
93
+ margin: 1rem 0;
94
+ opacity: 0.5;
95
+ }
96
+
97
+ p {
98
+ color: #fefefe;
99
+ font-size: 1.5rem;
100
+ font-family: Montserrat, sans-serif;
101
+ line-height: 1.5;
102
+ margin-top: 0;
103
+ margin-bottom: 1rem;
104
+ }
105
+
106
+ ::slotted(*) {
107
+ width: 100%;
108
+ height: 100%;
109
+ }
110
+
111
+ @media (max-width: 1400px) {
112
+ :host {
113
+ grid-template-areas:
114
+ '. . . . . . . . . . . . . . .'
115
+ '. t1 t1 t1 t1 t1 t1 t1 . . . . . . .'
116
+ '. t1 t1 t1 t1 t1 t1 t1 . . . . . . .'
117
+ '. t1 t1 t1 t1 t1 t1 t1 . . . . . . .'
118
+ '. . . . . . . . . . . . . . .';
119
+ }
120
+ h1 {
121
+ font-size: 1.8rem;
122
+ line-height: 1.2;
123
+ }
124
+ p {
125
+ font-size: 1.3rem;
126
+ line-height: 1.4;
127
+ }
128
+ }
129
+
130
+ /* Size Elements for small width */
131
+ @media (max-width: 900px) {
132
+ :host {
133
+ grid-template-areas:
134
+ '. . . . . . . . . . . . . . .'
135
+ '. t1 t1 t1 t1 t1 t1 t1 t1 t1 . . . . .'
136
+ '. t1 t1 t1 t1 t1 t1 t1 t1 t1 . . . . .'
137
+ '. t1 t1 t1 t1 t1 t1 t1 t1 t1 . . . . .'
138
+ '. . . . . . . . . . . . . . .';
139
+ }
140
+ h1 {
141
+ font-size: 1.7rem;
142
+ line-height: 1.1;
143
+ }
144
+ p {
145
+ font-size: 1.2rem;
146
+ line-height: 1.3;
147
+ }
148
+ }
149
+
150
+ /* Size Elements for small width */
151
+ @media (max-width: 600px) {
152
+ :host {
153
+ grid-template-areas:
154
+ '. . . . . . . . . . . . . . .'
155
+ '. . t1 t1 t1 t1 t1 t1 t1 t1 t1 . . . .'
156
+ '. . t1 t1 t1 t1 t1 t1 t1 t1 t1 . . . .'
157
+ '. . t1 t1 t1 t1 t1 t1 t1 t1 t1 . . . .'
158
+ '. . . . . . . . . . . . . . .';
159
+ }
160
+ h1 {
161
+ font-size: 1.3rem;
162
+ line-height: 1;
163
+ }
164
+ p {
165
+ font-size: 1rem;
166
+ line-height: 1;
167
+ }
168
+ }
169
+
170
+ /* Size Elements for small width */
171
+ @media (max-width: 350px) {
172
+ :host {
173
+ grid-template-areas:
174
+ '. . . . . . . . . . . . . . .'
175
+ '. . t1 t1 t1 t1 t1 t1 t1 t1 t1 . . . .'
176
+ '. . t1 t1 t1 t1 t1 t1 t1 t1 t1 . . . .'
177
+ '. . t1 t1 t1 t1 t1 t1 t1 t1 t1 . . . .'
178
+ '. . . . . . . . . . . . . . .';
179
+ }
180
+
181
+ h1 {
182
+ font-size: 1.1rem;
183
+ line-height: 1;
184
+ }
185
+ p {
186
+ font-size: 0.9rem;
187
+ line-height: 1;
188
+ }
189
+ }
190
+ `;
191
+ }
192
+
193
+ static get properties() {
194
+ return {
195
+ primaryTxt: { type: String },
196
+ secondaryTxt: { type: String },
197
+ };
198
+ }
199
+
200
+ constructor() {
201
+ super();
202
+ this.primaryTxt = '';
203
+ this.secondaryTxt = '';
204
+ }
205
+
206
+ render() {
207
+ return html`
208
+ <div class="t1">
209
+ <h1>${this.primaryTxt}</h1>
210
+ <p>${this.secondaryTxt}</p>
211
+ </div>
212
+
213
+ <slot></slot>
214
+ `;
215
+ }
216
+ }