@asd20/ui 3.2.1033 → 3.2.1034
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 +1 -1
- package/src/components/atoms/Asd20Messaging/index.vue +151 -4
- package/src/components/organisms/Asd20AppHeader/index.stories.js +1 -1
- package/src/components/organisms/Asd20AppHeader/index.vue +66 -131
- package/src/components/organisms/Asd20SiteNavigation/index.vue +0 -9
- package/src/data/page-queries/landing-page-query-result.json +1664 -1505
package/package.json
CHANGED
|
@@ -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
|
-
<
|
|
23
|
-
<asd20-icon
|
|
24
|
-
|
|
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="
|
|
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-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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:
|
|
52
|
+
align-items: flex-start;
|
|
71
53
|
flex-shrink: 0;
|
|
72
54
|
background: var(--color__primary);
|
|
73
55
|
color: white;
|
|
74
|
-
|
|
75
|
-
flex-wrap: wrap;
|
|
56
|
+
flex-wrap: nowrap;
|
|
76
57
|
border-bottom: 1px solid var(--color__tertiary);
|
|
77
|
-
|
|
78
58
|
&__title {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
}
|
|
@@ -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' : ''"
|