@asd20/ui 3.2.1033 → 3.2.1035

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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "*.scss",
6
6
  "*.vue"
7
7
  ],
8
- "version": "3.2.1033",
8
+ "version": "3.2.1035",
9
9
  "private": false,
10
10
  "license": "MIT",
11
11
  "repository": {
@@ -19,9 +19,14 @@
19
19
  <div v-if="shortDescription" class="lead short-description">
20
20
  <span v-html="shortDescription"></span>
21
21
  <a v-if="detailLink" :href="detailLink">{{ detailLinkLabel }}</a>
22
- <span class="external-link" v-if="isAbsoluteUrl(detailLink)">
23
- <asd20-icon name="external" size="sm" />
24
- </span>
22
+ <div class="external-link" v-if="isExternalUrl(detailLink)">
23
+ <asd20-icon
24
+ name="external"
25
+ size="sm"
26
+ aria-hidden="true"
27
+ focusable="false"
28
+ />
29
+ </div>
25
30
  </div>
26
31
  <p
27
32
  v-if="longDescription"
@@ -62,6 +67,148 @@
62
67
  import Asd20Button from '../Asd20Button'
63
68
  import Asd20Icon from '../Asd20Icon'
64
69
 
70
+ export default {
71
+ name: 'Asd20Messaging',
72
+ inheritAttrs: false,
73
+ components: { Asd20Button, Asd20Icon },
74
+ props: {
75
+ images: { type: Array, default: () => [] },
76
+ heading: { type: String, default: '' },
77
+ headingTagName: { type: String, default: 'h2' },
78
+ shortDescription: { type: String, default: '' },
79
+ longDescription: { type: String, default: '' },
80
+ bodyContent: { type: String, default: '' },
81
+ detailLink: { type: String, default: '' },
82
+ detailLinkLabel: { type: String, default: '' },
83
+ callsToAction: { type: Array, default: () => [] },
84
+ fullscreen: { type: Boolean, default: false },
85
+ padded: { type: Boolean, default: false },
86
+
87
+ /**
88
+ * If true, treat "www.asd20.org" the same as "asd20.org" for local/external checks.
89
+ * Leave true unless you specifically want "www." to be considered a separate subdomain.
90
+ */
91
+ treatWwwAsLocal: { type: Boolean, default: true },
92
+ },
93
+
94
+ data () {
95
+ return {
96
+ // SSR-safe: fill on client in mounted()
97
+ currentOrigin: '',
98
+ currentHost: '',
99
+ }
100
+ },
101
+
102
+ mounted () {
103
+ if (typeof window !== 'undefined' && window.location) {
104
+ this.currentOrigin = window.location.origin
105
+ this.currentHost = window.location.hostname
106
+ }
107
+ },
108
+
109
+ computed: {
110
+ hash() {
111
+ return this.heading.toLowerCase().split(' ').join('-')
112
+ },
113
+ classes() {
114
+ return {
115
+ 'asd20-messaging': true,
116
+ 'asd20-messaging--fullscreen': this.fullscreen,
117
+ 'asd20-messaging--padded': this.padded,
118
+ }
119
+ },
120
+ dynamicComponent() {
121
+ return {
122
+ template: `<div>${this.bodyContent}</div>`,
123
+ }
124
+ },
125
+ messageImage() {
126
+ const messageImages = Array.isArray(this.images) ? this.images : []
127
+ const coverImage = messageImages.find(i => i.isCover)
128
+ let messageImageUrl = null
129
+ if (coverImage) {
130
+ const coverImageFiles = coverImage.files || []
131
+ const coverImageFull = coverImageFiles.find(f => f.name === 'full')
132
+ if (coverImageFull && coverImageFull.filename && coverImageFull.filename.includes('headerimage')) {
133
+ messageImageUrl = ''
134
+ } else {
135
+ messageImageUrl = coverImageFull ? coverImageFull.url : (coverImage.url || '')
136
+ }
137
+ }
138
+ return messageImageUrl
139
+ },
140
+ messageImageAlt() {
141
+ const messageImages = Array.isArray(this.images) ? this.images : []
142
+ const coverImage = messageImages.find(i => i.isCover)
143
+ return coverImage?.metadata?.alt || ''
144
+ },
145
+ },
146
+
147
+ methods: {
148
+ normalizeHost (host) {
149
+ if (!host) return ''
150
+ const h = host.toLowerCase()
151
+ return this.treatWwwAsLocal ? h.replace(/^www\./, '') : h
152
+ },
153
+
154
+ isHttpLike (urlObj) {
155
+ // treat only http/https (and protocol-relative via base) as web links
156
+ return urlObj.protocol === 'http:' || urlObj.protocol === 'https:'
157
+ },
158
+
159
+ // "Local" means: relative URL or absolute URL whose hostname matches current hostname
160
+ isLocalUrl (href) {
161
+ if (!href || typeof href !== 'string') return true // nothing to show icon for
162
+ const s = href.trim()
163
+
164
+ // Always consider these "local" (no external icon)
165
+ if (s.startsWith('#') || s.startsWith('mailto:') || s.startsWith('tel:')) return true
166
+
167
+ // Build a URL object using currentOrigin as base so that
168
+ // - relative paths "/academics" resolve to current host
169
+ // - protocol-relative "//liberty.asd20.org" resolves correctly
170
+ // If currentOrigin is empty (SSR), use a dummy base.
171
+ const base = this.currentOrigin || 'http://example.local'
172
+ let u
173
+ try {
174
+ u = new URL(s, base)
175
+ } catch (e) {
176
+ // If it somehow can't be parsed, assume it's local (no icon)
177
+ return true
178
+ }
179
+
180
+ // Not http/https? treat as local (no icon)
181
+ if (!this.isHttpLike(u)) return true
182
+
183
+ // Relative URLs will have the same host as base; absolute will carry their own host.
184
+ const linkHost = this.normalizeHost(u.hostname)
185
+ const currHost = this.normalizeHost(this.currentHost || new URL(base).hostname)
186
+ return linkHost === currHost
187
+ },
188
+
189
+ // External if it's a web URL AND not local
190
+ isExternalUrl (href) {
191
+ if (!href || typeof href !== 'string') return false
192
+ const s = href.trim()
193
+ const base = this.currentOrigin || 'http://example.local'
194
+ let u
195
+ try {
196
+ u = new URL(s, base)
197
+ } catch (e) {
198
+ return false
199
+ }
200
+ if (!this.isHttpLike(u)) return false
201
+ return !this.isLocalUrl(s)
202
+ },
203
+ },
204
+ }
205
+ </script>
206
+
207
+
208
+ <!-- <script>
209
+ import Asd20Button from '../Asd20Button'
210
+ import Asd20Icon from '../Asd20Icon'
211
+
65
212
  export default {
66
213
  name: 'Asd20Messaging',
67
214
  inheritAttrs: false,
@@ -136,7 +283,7 @@ export default {
136
283
  },
137
284
  },
138
285
  }
139
- </script>
286
+ </script> -->
140
287
 
141
288
  <style lang="scss" scoped>
142
289
  @import '../../../design/_variables.scss';
@@ -16,7 +16,7 @@ storiesOf('Organisms - Asd20AppHeader', module).add(
16
16
  () => ({
17
17
  ...wrapper,
18
18
  template: `
19
- <Asd20AppHeader title="App Name" icon="files" version="1.0.0">
19
+ <Asd20AppHeader title="App Name" icon="calendar" version="1.0.0">
20
20
  </Asd20AppHeader>`,
21
21
  }),
22
22
  { info }
@@ -1,31 +1,25 @@
1
1
  <template>
2
2
  <header class="asd20-app-header">
3
- <asd20-button
4
- v-show="!zoomed"
5
- class="back-button"
6
- icon="chevron"
7
- :icon-angle="-90"
8
- size="xs"
9
- :label="backLabel"
10
- transparent
11
- horizontal
12
- text-only
13
- :link="backLink"
14
- ></asd20-button>
15
- <h1>
16
- <div
17
- :class="
18
- zoomed
19
- ? 'asd20-app-header__title asd20-app-header__zoomed'
20
- : 'asd20-app-header__title'
21
- "
22
- >
3
+ <div class="asd20-app-header__title">
4
+ <asd20-button
5
+ class="back-button"
6
+ icon="chevron"
7
+ :icon-angle="-90"
8
+ size="xs"
9
+ :label="backLabel"
10
+ transparent
11
+ horizontal
12
+ text-only
13
+ :link="backLink"
14
+ ></asd20-button>
15
+ <div class="icon-and-title">
23
16
  <asd20-icon v-if="icon" :name="icon" size="md" />
24
- {{ title }}
17
+ <h1>{{ title }}</h1>
25
18
  </div>
26
- <asd20-district-logo link="https://www.asd20.org" />
27
- </h1>
28
- <!-- <span class="version" v-if="version && !zoomed" v-html="version"></span> -->
19
+ </div>
20
+
21
+ <asd20-district-logo link="https://www.asd20.org" />
22
+ <!-- <span class="version" v-if="version" v-html="version"></span> -->
29
23
  <slot />
30
24
  </header>
31
25
  </template>
@@ -45,18 +39,6 @@ export default {
45
39
  backLink: { type: String, default: 'https://www.asd20.org' },
46
40
  backLabel: { type: String, default: 'asd20.org' },
47
41
  },
48
- data: () => ({
49
- zoomed: false,
50
- }),
51
- mounted() {
52
- this.zoomed = window.innerHeight <= 500
53
- window.addEventListener('resize', this.handleResize)
54
- },
55
- methods: {
56
- handleResize() {
57
- this.zoomed = window.innerHeight <= 500
58
- },
59
- },
60
42
  }
61
43
  </script>
62
44
 
@@ -67,84 +49,63 @@ export default {
67
49
  position: relative;
68
50
  z-index: 100;
69
51
  display: flex;
70
- align-items: center;
52
+ align-items: flex-start;
71
53
  flex-shrink: 0;
72
54
  background: var(--color__primary);
73
55
  color: white;
74
- // background: white;
75
- flex-wrap: wrap;
56
+ flex-wrap: nowrap;
76
57
  border-bottom: 1px solid var(--color__tertiary);
77
-
78
58
  &__title {
79
- display: flex;
80
- align-items: center;
81
- flex-shrink: 0;
82
- padding: 0 0 space(0.5) 0;
83
- // width: 100vw;
84
- // border-bottom: 1px solid var(--color__tertiary);
85
- }
86
- &__zoomed,
87
- .asd20-district-logo {
88
- padding: 0 !important;
89
- }
90
-
91
- h1 {
92
- margin: 0;
93
- font-size: 1.5rem;
94
- color: var(--color__on-primary);
95
- flex-grow: 1;
96
- width: 100%;
97
- border-bottom: 1px solid var(--color__tertiary);
98
- display: flex;
99
- align-items: center;
100
- font-family: var(--website-typography__font-family-headlines);
101
- .asd20-icon {
102
- margin: 0 space(0.5);
103
- --line-color: white;
59
+ .icon-and-title {
60
+ display: flex;
61
+ align-items: center;
62
+ flex-shrink: 0;
63
+ padding-bottom: 0.5rem;
64
+ h1 {
65
+ margin: 0;
66
+ font-size: 1.5rem;
67
+ color: var(--color__on-primary);
68
+ flex-grow: 1;
69
+ width: 100%;
70
+ // border-bottom: 1px solid var(--color__tertiary);
71
+ display: flex;
72
+ align-items: center;
73
+ font-family: var(--website-typography__font-family-headlines);
74
+ }
75
+ .asd20-icon {
76
+ margin: 0 space(0.5);
77
+ --line-color: white;
78
+ }
104
79
  }
105
80
  }
106
- .version {
107
- position: absolute;
108
- top: space(3);
109
- right: space(-0.45);
110
- display: block;
111
- font-size: 0.75rem;
112
- font-family: var(--website-typography__font-family-headlines);
113
- color: lightgray;
114
- text-transform: uppercase;
115
- margin-left: space(0.5);
116
- margin-right: space(0.5);
117
- order: 2;
118
- }
119
81
 
120
82
  .asd20-district-logo {
121
83
  margin-left: auto;
122
84
  margin-right: space(1);
123
- height: space(1.5);
124
- padding: space(0.5) 0;
125
- --fill-one: #fff;
126
- --fill-two: #ccc;
127
- // --fill-one: #{asd20-color('brand-blue')};
128
- // --fill-two: #{asd20-color('brand-gray')};
129
- }
130
-
131
- .asd20-button {
132
- margin-left: auto;
133
- margin-right: space(0.5);
134
- order: 3;
135
- border-radius: 0;
85
+ height: 1.5rem;
86
+ padding: 0.75rem 0 0 0;
87
+ &::v-deep svg {
88
+ fill: #fff;
89
+ .district {
90
+ fill: #ccc;
91
+ }
92
+ }
136
93
  }
137
94
 
138
- .asd20-button + .asd20-button {
139
- margin-left: 0;
140
- }
141
- .asd20-button:not(.back-button) {
142
- border-left: 1px solid var(--color__tertiary);
143
- }
95
+ // .version {
96
+ // position: absolute;
97
+ // top: space(3);
98
+ // right: space(-0.45);
99
+ // display: block;
100
+ // font-size: 0.75rem;
101
+ // font-family: var(--website-typography__font-family-headlines);
102
+ // color: lightgray;
103
+ // text-transform: uppercase;
104
+ // margin-left: space(0.5);
105
+ // margin-right: space(0.5);
106
+ // order: 2;
107
+ // }
144
108
 
145
- .asd20-button.asd20-button--transparent {
146
- margin-right: 0;
147
- }
148
109
  .back-button {
149
110
  // width: 100vw;
150
111
  background: var(--color__primary);
@@ -161,38 +122,12 @@ export default {
161
122
  }
162
123
  }
163
124
  }
164
-
165
- @media (max-width: 767px) {
166
- .asd20-app-header::v-deep .asd20-district-logo {
167
- display: none;
168
- }
125
+ @media (min-width: 768px) {
169
126
  .asd20-app-header {
170
- h1 .version {
171
- display: none;
172
- }
173
- .asd20-button:not(.back-button) {
174
- &::v-deep .asd20-button__label {
175
- display: none;
176
- }
177
- }
178
- .asd20-app-header__title {
179
- padding: space(0.125) 0;
180
- &::v-deep .asd20-icon {
181
- margin-right: space(0.125);
182
- }
183
- }
184
- }
185
- }
186
-
187
- @media (max-width: 480px) {
188
- .asd20-app-header {
189
- &__title {
190
- display: flex;
191
- align-items: center;
192
- flex-shrink: 0;
193
- padding: space(0.5) 0;
194
- width: 100vw;
195
- border-bottom: 1px solid var(--color__tertiary);
127
+ align-items: flex-end;
128
+ .asd20-district-logo {
129
+ padding: 0 0 0.25rem 0;
130
+ height: space(1.5);
196
131
  }
197
132
  }
198
133
  }
@@ -48,7 +48,7 @@ $factoids-header-fg: var(--color__primary);
48
48
  font-size: 1.25rem;
49
49
  padding: space(0.5) space(1) space(0.5) space(1);
50
50
  z-index: -1;
51
- border-top: 2px solid var(--color__tertiary);
51
+ // border-top: 2px solid var(--color__tertiary);
52
52
  }
53
53
  }
54
54
 
@@ -56,8 +56,8 @@ $factoids-header-fg: var(--color__primary);
56
56
  .asd20-factoids-section {
57
57
  grid-column: 1 / -1;
58
58
  h2 {
59
- width: calc(100% - #{space(6)});
60
- margin-left: space(6);
59
+ width: calc(100% - #{space(3)});
60
+ margin-left: space(3);
61
61
  }
62
62
  }
63
63
  }
@@ -56,15 +56,6 @@
56
56
  </transition>
57
57
 
58
58
  <transition name="slide">
59
- <!-- <asd20-site-menu
60
- ref="siteMenu"
61
- :class="zoomed ? 'zoomed' : ''"
62
- v-show="menuOpen"
63
- :active="menuOpen"
64
- @update:active="$emit('update:menuOpen', $event)"
65
- :sections="navigation"
66
- v-scroll-lock="menuOpen"
67
- /> -->
68
59
  <asd20-site-menu
69
60
  ref="siteMenu"
70
61
  :class="zoomed ? 'zoomed' : ''"
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <component :is="tag" class="asd20-swiper-feed">
3
- <h2 aria-label="Feed title">
3
+ <h2 class="swiper-title" aria-label="Feed title">
4
4
  <asd20-icon v-if="icon" :name="icon" size="lg" /><span
5
5
  v-html="title"
6
6
  ></span>
@@ -142,9 +142,9 @@ export default {
142
142
  display: flex;
143
143
  flex-direction: column;
144
144
  position: relative;
145
- margin: 0;
146
- padding: space(2) space(2) space(2) 0;
147
- background: var(--website-page__alternate-background-color);
145
+ margin: space(2) 0 space(0.5) 0;
146
+ // padding: space(1) space(2) space(1) 0;
147
+ // background: var(--website-page__alternate-background-color);
148
148
 
149
149
  --color__fade-overlay-left: var(--website-page__background-color);
150
150
  --color__fade-overlay-right: var(--website-page__alternate-background-color);
@@ -157,17 +157,18 @@ export default {
157
157
  display: block;
158
158
  position: absolute;
159
159
  left: 0;
160
- right: space(1);
161
- top: space(1);
162
- bottom: space(0);
163
- background: var(--website-page__background-color);
164
- border-radius: var(--website-shape__radius-m);
165
- border-top-left-radius: 0;
166
- border-bottom-left-radius: 0;
160
+ right: 0;
161
+ top: 30%;
162
+ bottom: 30%;
163
+ background: var(--website-page__alternate-background-color);
164
+ border-radius: 0;
165
+ // border-radius: var(--website-shape__radius-m);
166
+ // border-top-left-radius: 0;
167
+ // border-bottom-left-radius: 0;
167
168
  z-index: 0;
168
169
  }
169
170
 
170
- h2 {
171
+ .swiper-title {
171
172
  display: flex;
172
173
  font-size: 1.5rem;
173
174
  line-height: 1;
@@ -175,6 +176,9 @@ export default {
175
176
  text-align: left;
176
177
  margin: 0 0 0 space(1);
177
178
  align-items: center;
179
+ border-bottom: 3px solid var(--color__accent);
180
+ padding-bottom: space(0.5);
181
+ width: 100%;
178
182
  }
179
183
 
180
184
  .asd20-icon {
@@ -197,6 +201,7 @@ export default {
197
201
  .feed-buttons {
198
202
  display: flex;
199
203
  flex-direction: column;
204
+ padding-bottom: space(0.5);
200
205
  }
201
206
 
202
207
  .asd20-button {
@@ -224,13 +229,14 @@ export default {
224
229
 
225
230
  @media (min-width: 1024px) {
226
231
  .asd20-swiper-feed {
227
- h2 {
228
- margin-left: space(3);
232
+ .swiper-title {
233
+ margin: 0 space(1) 0 space(3);
234
+ width: inherit;
229
235
  }
230
236
 
231
- &::after {
232
- right: space(3);
233
- }
237
+ // &::after {
238
+ // right: space(3);
239
+ // }
234
240
 
235
241
  .asd20-swiper {
236
242
  // margin-left: space(1);
@@ -256,23 +256,23 @@ export default {
256
256
  top: space(2.0375);
257
257
  }
258
258
 
259
- .asd20-feeds-section--top {
260
- // margin-top: space(1);
261
- .asd20-swiper-feed:first-child {
262
- padding-top: space(2);
263
- padding-bottom: space(1);
264
- &::after {
265
- top: space(1);
266
- }
267
- }
268
- .asd20-swiper-feed:last-child {
269
- // margin-top: space(-1);
270
- padding-bottom: space(2);
271
- &::after {
272
- bottom: space(1);
273
- }
274
- }
275
- }
259
+ // .asd20-feeds-section--top {
260
+ // // margin-top: space(1);
261
+ // .asd20-swiper-feed:first-child {
262
+ // padding-top: space(2);
263
+ // padding-bottom: space(1);
264
+ // &::after {
265
+ // top: space(1);
266
+ // }
267
+ // }
268
+ // .asd20-swiper-feed:last-child {
269
+ // // margin-top: space(-1);
270
+ // padding-bottom: space(2);
271
+ // &::after {
272
+ // bottom: space(1);
273
+ // }
274
+ // }
275
+ // }
276
276
  }
277
277
 
278
278
  @media (min-width: 1024px) {
@@ -227,23 +227,23 @@ export default {
227
227
  .asd20-notification-group--inline {
228
228
  margin-top: space(2) !important;
229
229
  }
230
- .asd20-feeds-section {
231
- margin-top: space(1);
232
- .asd20-swiper-feed:first-child {
233
- padding-top: space(2);
234
- padding-bottom: space(1);
235
- &::after {
236
- top: space(1);
237
- }
238
- }
239
- .asd20-swiper-feed:last-child {
240
- // margin-top: space(-1);
241
- padding-bottom: space(2);
242
- &::after {
243
- bottom: space(1);
244
- }
245
- }
246
- }
230
+ // .asd20-feeds-section {
231
+ // margin-top: space(1);
232
+ // .asd20-swiper-feed:first-child {
233
+ // padding-top: space(2);
234
+ // padding-bottom: space(1);
235
+ // &::after {
236
+ // top: space(1);
237
+ // }
238
+ // }
239
+ // .asd20-swiper-feed:last-child {
240
+ // // margin-top: space(-1);
241
+ // padding-bottom: space(2);
242
+ // &::after {
243
+ // bottom: space(1);
244
+ // }
245
+ // }
246
+ // }
247
247
  .intro-message {
248
248
  .primary-messaging-section {
249
249
  justify-content: center;
@@ -231,22 +231,22 @@ export default {
231
231
  .notification-group--inline {
232
232
  margin-bottom: space(1);
233
233
  }
234
- .asd20-feeds-section {
235
- margin-top: space(1);
236
- .asd20-swiper-feed:first-child {
237
- padding-top: space(2);
238
- padding-bottom: space(1);
239
- &::after {
240
- top: space(1);
241
- }
242
- }
243
- .asd20-swiper-feed:last-child {
244
- padding-bottom: space(2);
245
- &::after {
246
- bottom: space(1);
247
- }
248
- }
249
- }
234
+ // .asd20-feeds-section {
235
+ // margin-top: space(1);
236
+ // .asd20-swiper-feed:first-child {
237
+ // padding-top: space(2);
238
+ // padding-bottom: space(1);
239
+ // &::after {
240
+ // top: space(1);
241
+ // }
242
+ // }
243
+ // .asd20-swiper-feed:last-child {
244
+ // padding-bottom: space(2);
245
+ // &::after {
246
+ // bottom: space(1);
247
+ // }
248
+ // }
249
+ // }
250
250
  .asd20-page-content:not(.intro-message) .primary-messaging-section {
251
251
  padding: space(1) space(0);
252
252
  }