@asd20/ui 3.7.0 → 3.9.0
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
|
@@ -9,15 +9,17 @@
|
|
|
9
9
|
<div class="asd20-site-search__viewport">
|
|
10
10
|
<div class="asd20-site-search__options">
|
|
11
11
|
<!-- Ask a Question -->
|
|
12
|
-
<div
|
|
12
|
+
<div
|
|
13
|
+
class="asd20-site-search__field asd20-site-search__field--question"
|
|
14
|
+
>
|
|
13
15
|
<!-- <label class="asd20-site-search__label">Ask a question</label> -->
|
|
14
16
|
<div class="asd20-site-search__question-row">
|
|
15
17
|
<asd20-search-field
|
|
16
18
|
idTag="-question"
|
|
17
19
|
ref="question"
|
|
18
20
|
v-model="questionText"
|
|
19
|
-
@keyup.enter.stop.prevent="onAskQuestion"
|
|
20
|
-
placeholder="Ask a question"
|
|
21
|
+
@keyup.enter.native.stop.prevent="onAskQuestion"
|
|
22
|
+
placeholder="Ask a question (preview)"
|
|
21
23
|
/>
|
|
22
24
|
<asd20-button
|
|
23
25
|
class="asd20-site-search__ask-button"
|
|
@@ -34,7 +36,7 @@
|
|
|
34
36
|
/>
|
|
35
37
|
</div>
|
|
36
38
|
</div>
|
|
37
|
-
<hr/>
|
|
39
|
+
<hr />
|
|
38
40
|
|
|
39
41
|
<!-- Search by Keyword -->
|
|
40
42
|
<div class="asd20-site-search__field asd20-site-search__field--keyword">
|
|
@@ -74,18 +76,33 @@
|
|
|
74
76
|
|
|
75
77
|
<!-- Answers tab -->
|
|
76
78
|
<div v-show="currentTab === 'Answers'" scrollable>
|
|
79
|
+
<div v-if="aiAnswer" class="disclaimer">
|
|
80
|
+
<p>
|
|
81
|
+
AI generated answers can have errors. Please contact our
|
|
82
|
+
<a href="www.asd20.org/help-desk">Help Desk</a> if you need
|
|
83
|
+
additional information.
|
|
84
|
+
</p>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
77
87
|
<div v-if="aiAnswer" class="asd20-site-search__ai-result">
|
|
78
88
|
<h3>Answer</h3>
|
|
79
89
|
<div class="asd20-site-search__ai-answer" v-html="aiAnswer" />
|
|
80
90
|
|
|
81
|
-
<div
|
|
91
|
+
<div
|
|
92
|
+
v-if="aiGroupedSources.length"
|
|
93
|
+
class="asd20-site-search__ai-sources"
|
|
94
|
+
>
|
|
82
95
|
<h4>Sources</h4>
|
|
83
96
|
<ul>
|
|
84
|
-
<li v-for="
|
|
85
|
-
<strong>Content from: {{
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
97
|
+
<li v-for="group in aiGroupedSources" :key="group.hostLabel">
|
|
98
|
+
<strong>Content from: {{ group.hostLabel }}</strong>
|
|
99
|
+
<ul class="asd20-site-search__ai-source-list">
|
|
100
|
+
<li v-for="src in group.sources" :key="src.url || src.id">
|
|
101
|
+
<a :href="src.url" target="_blank" rel="noreferrer">
|
|
102
|
+
{{ src.title }}
|
|
103
|
+
</a>
|
|
104
|
+
</li>
|
|
105
|
+
</ul>
|
|
89
106
|
</li>
|
|
90
107
|
</ul>
|
|
91
108
|
</div>
|
|
@@ -97,7 +114,6 @@
|
|
|
97
114
|
|
|
98
115
|
<!-- Pages tab -->
|
|
99
116
|
<div v-show="currentTab === 'Pages'" scrollable>
|
|
100
|
-
|
|
101
117
|
<!-- No results -->
|
|
102
118
|
<asd20-notification
|
|
103
119
|
v-if="keywords && _pages.length === 0 && !searchingPages"
|
|
@@ -134,7 +150,9 @@
|
|
|
134
150
|
|
|
135
151
|
<div class="asd20-site-search__suggested" v-if="_groups.length > 0">
|
|
136
152
|
<h3>
|
|
137
|
-
{{
|
|
153
|
+
{{
|
|
154
|
+
_groups.length > 1 ? 'Suggested Contacts:' : 'Suggested Contact:'
|
|
155
|
+
}}
|
|
138
156
|
</h3>
|
|
139
157
|
<asd20-list-item
|
|
140
158
|
v-for="g in _groups"
|
|
@@ -242,7 +260,10 @@ export default {
|
|
|
242
260
|
|
|
243
261
|
props: {
|
|
244
262
|
active: { type: Boolean, default: false },
|
|
245
|
-
organization: {
|
|
263
|
+
organization: {
|
|
264
|
+
type: Object,
|
|
265
|
+
default: () => ({ title: 'Academy District 20' }),
|
|
266
|
+
},
|
|
246
267
|
organizationOptions: { type: Array, default: () => [] },
|
|
247
268
|
},
|
|
248
269
|
|
|
@@ -328,9 +349,39 @@ export default {
|
|
|
328
349
|
aiUiSources() {
|
|
329
350
|
return (this.aiSources || []).map(src => ({
|
|
330
351
|
...src,
|
|
331
|
-
hostLabel:
|
|
352
|
+
hostLabel:
|
|
353
|
+
this.resolveOrgTitleFromUrl(src.url) || this.labelFromUrl(src.url),
|
|
332
354
|
}))
|
|
333
355
|
},
|
|
356
|
+
aiGroupedSources() {
|
|
357
|
+
const groups = new Map()
|
|
358
|
+
this.aiUiSources.forEach(src => {
|
|
359
|
+
const key = src.hostLabel || 'Academy District 20'
|
|
360
|
+
if (!groups.has(key)) {
|
|
361
|
+
groups.set(key, { hostLabel: key, sources: [] })
|
|
362
|
+
}
|
|
363
|
+
const group = groups.get(key)
|
|
364
|
+
const exists = group.sources.find(
|
|
365
|
+
s => (s.url && src.url && s.url === src.url) || (s.id && src.id && s.id === src.id)
|
|
366
|
+
)
|
|
367
|
+
if (!exists) {
|
|
368
|
+
group.sources.push(src)
|
|
369
|
+
}
|
|
370
|
+
})
|
|
371
|
+
const currentOrgTitle =
|
|
372
|
+
(this.organization && this.organization.title) || 'Academy District 20'
|
|
373
|
+
const currentLower = currentOrgTitle.toLowerCase()
|
|
374
|
+
|
|
375
|
+
return Array.from(groups.values()).sort((a, b) => {
|
|
376
|
+
const aIsCurrent =
|
|
377
|
+
(a.hostLabel || '').toLowerCase() === currentLower
|
|
378
|
+
const bIsCurrent =
|
|
379
|
+
(b.hostLabel || '').toLowerCase() === currentLower
|
|
380
|
+
if (aIsCurrent && !bIsCurrent) return -1
|
|
381
|
+
if (bIsCurrent && !aIsCurrent) return 1
|
|
382
|
+
return (a.hostLabel || '').localeCompare(b.hostLabel || '')
|
|
383
|
+
})
|
|
384
|
+
},
|
|
334
385
|
},
|
|
335
386
|
|
|
336
387
|
watch: {
|
|
@@ -430,6 +481,12 @@ export default {
|
|
|
430
481
|
return 'Rampart High School'
|
|
431
482
|
case 'pinecreek':
|
|
432
483
|
return 'Pine Creek High School'
|
|
484
|
+
case 'dcchigh':
|
|
485
|
+
return 'Discovery Canyon Campus High School'
|
|
486
|
+
case 'liberty':
|
|
487
|
+
return 'Liberty High School'
|
|
488
|
+
case 'd20online':
|
|
489
|
+
return 'Academy Online High School'
|
|
433
490
|
// add more mappings as needed
|
|
434
491
|
default:
|
|
435
492
|
return subdomain.charAt(0).toUpperCase() + subdomain.slice(1)
|
|
@@ -442,6 +499,26 @@ export default {
|
|
|
442
499
|
}
|
|
443
500
|
},
|
|
444
501
|
|
|
502
|
+
// Try to resolve the full organization title from organizationOptions by URL
|
|
503
|
+
resolveOrgTitleFromUrl(url) {
|
|
504
|
+
if (!url || !Array.isArray(this.organizationOptions)) return null
|
|
505
|
+
try {
|
|
506
|
+
const host = new URL(url).hostname.toLowerCase()
|
|
507
|
+
const match = this.organizationOptions.find((org) => {
|
|
508
|
+
if (!org || !org.website) return false
|
|
509
|
+
try {
|
|
510
|
+
const orgHost = new URL(org.website).hostname.toLowerCase()
|
|
511
|
+
return host === orgHost || host.endsWith(orgHost)
|
|
512
|
+
} catch {
|
|
513
|
+
return false
|
|
514
|
+
}
|
|
515
|
+
})
|
|
516
|
+
return match && match.title ? match.title : null
|
|
517
|
+
} catch {
|
|
518
|
+
return null
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
|
|
445
522
|
// Called when user clicks Ask or presses Enter in question field
|
|
446
523
|
onAskQuestion() {
|
|
447
524
|
const q = (this.questionText || '').trim()
|
|
@@ -496,15 +573,7 @@ export default {
|
|
|
496
573
|
// If no DOM (e.g., SSR), return raw; client will re-run and sanitize.
|
|
497
574
|
if (typeof window === 'undefined' || !window.document) return rawHtml
|
|
498
575
|
|
|
499
|
-
const allowedTags = new Set([
|
|
500
|
-
'P',
|
|
501
|
-
'UL',
|
|
502
|
-
'OL',
|
|
503
|
-
'LI',
|
|
504
|
-
'STRONG',
|
|
505
|
-
'EM',
|
|
506
|
-
'A',
|
|
507
|
-
])
|
|
576
|
+
const allowedTags = new Set(['P', 'UL', 'OL', 'LI', 'STRONG', 'EM', 'A'])
|
|
508
577
|
const allowedAttrs = {
|
|
509
578
|
A: ['href'],
|
|
510
579
|
}
|
|
@@ -512,9 +581,9 @@ export default {
|
|
|
512
581
|
const container = window.document.createElement('div')
|
|
513
582
|
container.innerHTML = rawHtml
|
|
514
583
|
|
|
515
|
-
const cleanNode =
|
|
584
|
+
const cleanNode = node => {
|
|
516
585
|
const children = Array.from(node.childNodes)
|
|
517
|
-
children.forEach(
|
|
586
|
+
children.forEach(child => {
|
|
518
587
|
if (child.nodeType === 1) {
|
|
519
588
|
const tag = child.tagName.toUpperCase()
|
|
520
589
|
if (!allowedTags.has(tag)) {
|
|
@@ -526,7 +595,7 @@ export default {
|
|
|
526
595
|
}
|
|
527
596
|
|
|
528
597
|
const allowed = allowedAttrs[tag] || []
|
|
529
|
-
Array.from(child.attributes).forEach(
|
|
598
|
+
Array.from(child.attributes).forEach(attr => {
|
|
530
599
|
const name = attr.name.toLowerCase()
|
|
531
600
|
if (!allowed.includes(attr.name)) {
|
|
532
601
|
child.removeAttribute(attr.name)
|
|
@@ -628,6 +697,17 @@ export default {
|
|
|
628
697
|
|
|
629
698
|
&__results {
|
|
630
699
|
flex-grow: 1;
|
|
700
|
+
.disclaimer {
|
|
701
|
+
padding: space(0.5);
|
|
702
|
+
font-size: 0.85rem;
|
|
703
|
+
background: var(--website-page__alternate-background-t25);
|
|
704
|
+
border-bottom: 1px solid var(--color__tertiary);
|
|
705
|
+
|
|
706
|
+
a {
|
|
707
|
+
color: var(--color__primary);
|
|
708
|
+
text-decoration: underline;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
631
711
|
}
|
|
632
712
|
|
|
633
713
|
&__ai-result {
|
|
@@ -638,6 +718,22 @@ export default {
|
|
|
638
718
|
|
|
639
719
|
&__ai-answer {
|
|
640
720
|
margin-bottom: space(0.5);
|
|
721
|
+
|
|
722
|
+
::v-deep ol,
|
|
723
|
+
::v-deep ul {
|
|
724
|
+
display: block !important;
|
|
725
|
+
list-style-position: inside;
|
|
726
|
+
padding-left: 0;
|
|
727
|
+
margin-left: 0;
|
|
728
|
+
flex: 0 0 auto;
|
|
729
|
+
flex-wrap: nowrap;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
::v-deep li {
|
|
733
|
+
display: list-item;
|
|
734
|
+
flex: 0 0 auto;
|
|
735
|
+
width: auto;
|
|
736
|
+
}
|
|
641
737
|
}
|
|
642
738
|
|
|
643
739
|
&__ai-sources {
|
|
@@ -661,6 +757,19 @@ export default {
|
|
|
661
757
|
}
|
|
662
758
|
}
|
|
663
759
|
|
|
760
|
+
&__ai-source-list {
|
|
761
|
+
list-style: disc;
|
|
762
|
+
list-style-position: inside;
|
|
763
|
+
padding-left: 0;
|
|
764
|
+
margin: space(0.25) 0 0.35rem 0;
|
|
765
|
+
|
|
766
|
+
li {
|
|
767
|
+
display: list-item;
|
|
768
|
+
margin: 0;
|
|
769
|
+
padding: 0;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
664
773
|
&__ai-snippet {
|
|
665
774
|
margin: 0;
|
|
666
775
|
opacity: 0.85;
|