Some random tweaks, plus alert component updates

This commit is contained in:
Alex Humphries 2026-01-16 09:00:04 -05:00
parent b1ec2a298d
commit 253044d502
8 changed files with 250 additions and 178 deletions

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="21" viewBox="0 0 20 21">
<path fill="#E86421" fill-rule="nonzero" d="M10 .5c5.523 0 10 4.477 10 10s-4.477 10-10 10-10-4.477-10-10S4.477.5 10 .5zm.043 13.6a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm.77-9.2h-1.54l-.088.009a.502.502 0 0 0-.299.193.66.66 0 0 0-.125.47l.747 6.806.017.096c.065.249.263.425.495.426l.084-.008c.22-.042.396-.246.427-.51l.793-6.805.004-.102a.651.651 0 0 0-.127-.37.489.489 0 0 0-.388-.205z"/>
</svg>

After

Width:  |  Height:  |  Size: 474 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="9" viewBox="0 0 15 9">
<path fill="#E86421" fill-rule="nonzero" d="M7.5 0a.806.806 0 0 0-.593.265L.246 7.455a.957.957 0 0 0 0 1.28.796.796 0 0 0 1.185 0l6.07-6.55 6.068 6.55a.796.796 0 0 0 1.186 0 .957.957 0 0 0 0-1.28L8.093.265A.806.806 0 0 0 7.5 0"/>
</svg>

After

Width:  |  Height:  |  Size: 323 B

View file

@ -5,6 +5,7 @@ function processZipCodeResults(request) {
containsMilitaryBase: serviceZipValidationResponse.containsMilitaryBase, containsMilitaryBase: serviceZipValidationResponse.containsMilitaryBase,
isValid: serviceZipValidationResponse.isValid, isValid: serviceZipValidationResponse.isValid,
isServiceable: serviceZipValidationResponse.isServiceable, isServiceable: serviceZipValidationResponse.isServiceable,
city: serviceZipValidationResponse.city,
state: serviceZipValidationResponse.state, state: serviceZipValidationResponse.state,
zipCodeCtu: serviceZipValidationResponse.zipCodeCtu zipCodeCtu: serviceZipValidationResponse.zipCodeCtu
})).catch(() => ({ })).catch(() => ({

View file

@ -3,15 +3,13 @@
name="fade" name="fade"
mode="out-in"> mode="out-in">
<div <div
v-if="isDisplayed"
class="appointment-type-question" class="appointment-type-question"
aria-live="polite"> aria-live="polite">
<buttonQuestion <buttonQuestion
ref="buttonQuestion" ref="buttonQuestion"
v-model="selectedValues" v-model="selectedValues"
customButtonQuestionId="appointmentTypeQuestion" customButtonQuestionId="appointmentTypeQuestion"
:questionText="questionText" :answers="answersFromCms"
:answers="answersToDisplay"
:groupName="groupName" :groupName="groupName"
:suppressError="suppressError" :suppressError="suppressError"
:validationRules="validationRules" :validationRules="validationRules"
@ -37,12 +35,9 @@ export default {
modelValue: String, modelValue: String,
groupName: String, groupName: String,
isAvailable: Boolean, isAvailable: Boolean,
isDisplayed: Boolean,
suppressError: Boolean, suppressError: Boolean,
validationRules: String, validationRules: String,
cmsWidgetName: String, cmsWidgetName: String
isServiceableMobile: Boolean,
isServiceableInshop: Boolean
}, },
emits: ['update:modelValue'], emits: ['update:modelValue'],
computed: { computed: {
@ -51,21 +46,8 @@ export default {
}, },
answersFromCms() { answersFromCms() {
const retCms = this.getCmsContent(this.cmsWidgetName, 'Answers'); const retCms = this.getCmsContent(this.cmsWidgetName, 'Answers');
if (retCms && retCms.length > 0 && this.isMobileFeeHidden) {
return retCms.map((x) => (x.Name === AppointmentTypeStrings.MOBILE ? { ...x, SubText: x.SubText.replace('*', '') } : x));
}
return retCms; return retCms;
}, },
answersToDisplay() {
const shouldShowMobile = this.isServiceableMobile;
const shouldShowInshop = this.isServiceableInshop;
return this.answersFromCms
? this.answersFromCms.filter((answer) => (
(answer.Name === AppointmentTypeStrings.IN_SHOP && shouldShowInshop)
|| (answer.Name === AppointmentTypeStrings.MOBILE && shouldShowMobile)
))
: [];
},
selectedValues: { selectedValues: {
get() { get() {
return this.modelValue; return this.modelValue;
@ -73,46 +55,13 @@ export default {
set(newValue) { set(newValue) {
this.$emit('update:modelValue', newValue); this.$emit('update:modelValue', newValue);
} }
},
isITAC() {
return useMainStore().isITAC;
},
isItacOrNoComp() {
return this.isITAC || useMainStore().isNoComp;
},
isMobileFeeHidden() {
return this.getSettingValue(experimentSettings.ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_HIDDEN) === 'true';
},
isMobileOnly() {
return this.isServiceableMobile && !this.isServiceableInshop;
} }
}, },
watch: {
answersToDisplay: {
handler(newValue) {
// If there is only one option to display and that option is 'Mobile' then select it
if (
newValue.length === 1
&& newValue.findIndex((answer) => (answer.Name === AppointmentTypeStrings.MOBILE)) !== -1
) {
this.selectedValues = AppointmentTypeStrings.MOBILE;
}
},
immediate: true
},
isMobileOnly: {
handler(newValue) {
if (newValue) {
this.selectedValues = AppointmentTypeStrings.MOBILE;
}
}
}
}
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.question-text) { .appointment-type-question {
font-weight: 600; margin-bottom: 1.25rem;
} }
</style> </style>

View file

@ -13,18 +13,18 @@
<siteSubHeader <siteSubHeader
cmsWidgetName="SiteSubHeaderWidget" cmsWidgetName="SiteSubHeaderWidget"
class="subheader" /> class="subheader" />
<alert
v-if="displayMilitaryZipAlert"
ref="alertMilitaryBaseZip"
class="my-5"
cmsWidgetName="AlertMilitaryBaseZipWidget"
alertClass="alert-warning" />
<alert <alert
v-if="displayServiceableMobileOnly" v-if="displayServiceableMobileOnly"
ref="alertMobileOnly" ref="alertMobileOnly"
class="my-5" class="my-5"
cmsWidgetName="AlertMobileOnlyWidget" cmsWidgetName="AlertMobileOnlyWidget"
alertClass="alert-warning" /> alertClass="alert-warning" />
<alert
v-if="displayServiceableInshopOnly"
ref="alertInshopOnly"
cmsWidgetName="AlertInshopOnlyWidget"
:isCollapsible="true"
alertClass="alert-warning" />
<alert <alert
v-if="displayRecalibrationWarning" v-if="displayRecalibrationWarning"
ref="alertRecalNoMobile" ref="alertRecalNoMobile"
@ -32,16 +32,11 @@
cmsWidgetName="AlertRecalNoMobileWidget" cmsWidgetName="AlertRecalNoMobileWidget"
alertClass="alert-warning" alertClass="alert-warning"
@text-link-clicked="openModalAction" /> @text-link-clicked="openModalAction" />
<alert
v-if="displayServiceableInshopOnly"
ref="alertInshopOnly"
class="my-5"
cmsWidgetName="AlertInshopOnlyWidget"
alertClass="alert-warning" />
<alert <alert
v-if="displayNoShopsAlert" v-if="displayNoShopsAlert"
ref="alertNoShops" ref="alertNoShops"
class="my-5" class="my-5"
:isCollapsible="true"
cmsWidgetName="AlertNoShopsWidget" cmsWidgetName="AlertNoShopsWidget"
alertClass="alert-warning" /> alertClass="alert-warning" />
<alert <alert
@ -51,28 +46,43 @@
cmsWidgetName="AlertBigTruckNoShopsWidget" cmsWidgetName="AlertBigTruckNoShopsWidget"
alertClass="alert-warning" /> alertClass="alert-warning" />
<div class="appointment-type"> <div class="appointment-type">
<div class="appointment-type-question-text d-flex">
<span class="w-100">{{ appointmentQuestionText }}</span>
</div>
<appointmentTypeQuestion <appointmentTypeQuestion
v-show="isAppointmentTypeDisplayed" v-if="showMobileOption"
ref="appointmentTypeQuestion" ref="appointmentTypeQuestion"
v-model="selectedAppointmentType" v-model="selectedAppointmentType"
:isServiceableMobile="isServiceableMobile"
:isServiceableInshop="isServiceableInshop"
:isDisplayed="isAppointmentTypeDisplayed"
groupName="appointmentTypeQuestion" groupName="appointmentTypeQuestion"
cmsWidgetName="AppointmentTypeQuestionWidget" cmsWidgetName="AppointmentTypeQuestionWidget"
validationRules="option-required" /> validationRules="option-required" />
</div> </div>
<shopAddress <div
v-if="isInshop" v-if="isInshop">
v-model="selectedProvider" <shopAddress
:serviceZipcode="zipCode" v-model="selectedProvider"
:isDisplayed="isInshop" :serviceZipcode="zipCode"
:selectedAppointmentType="selectedAppointmentType" :selectedAppointmentType="selectedAppointmentType"
modalWidgetName="ChangeLocationModalWidget" modalWidgetName="ChangeLocationModalWidget"
cmsWidgetName="ShopAddressWidget" cmsWidgetName="ShopAddressWidget"
@zip-updated="handleInShopZipUpdated" /> @zip-updated="handleInShopZipUpdated" />
</div>
<div <div
v-if="isMobile"> v-if="isMobile">
<div class="expandable-link-container">
<a
v-if="displayMilitaryZipAlert && !militaryBaseWarningExpanded"
href="#"
class="expandable-link"
@click.prevent="militaryBaseWarningExpanded = true">
{{ militaryBaseWarningLinkText }}
</a>
<div
v-if="displayMilitaryZipAlert && militaryBaseWarningExpanded"
class="expandable-link-text">
{{ militaryBaseWarningText }}
</div>
</div>
<serviceZipQuestion <serviceZipQuestion
ref="mobileServiceZipCodeQuestion" ref="mobileServiceZipCodeQuestion"
v-model="mobileZipCode" v-model="mobileZipCode"
@ -104,7 +114,7 @@
class="mt-5" class="mt-5"
cmsWidgetName="SiteFooterWidget" cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled=" :isForwardActionDisabled="
!meta.valid || displayNoShopsAlert !meta.valid || displayNoShopsAlert || displayBigTruckNoShops
" "
@backClicked="navigateBack(this, navigateBackScenario)" @backClicked="navigateBack(this, navigateBackScenario)"
@forwardClicked="forwardButtonAction" /> @forwardClicked="forwardButtonAction" />
@ -118,7 +128,6 @@
import { AppointmentTypeStrings } from '@/constants/schedule-constants.js'; import { AppointmentTypeStrings } from '@/constants/schedule-constants.js';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper'; import settleAllPromises from '@/helpers/layout-helper';
import { required } from '@/helpers/validation-rules';
import errorMessages from '@/constants/error-messages'; import errorMessages from '@/constants/error-messages';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import { import {
@ -237,6 +246,7 @@ export default {
mobileZipCode: '', mobileZipCode: '',
mobileZipError: '', mobileZipError: '',
showMobileOption: false, showMobileOption: false,
militaryBaseWarningExpanded: false,
RECAL_MODAL_REF_NAME, RECAL_MODAL_REF_NAME,
SITE_FOOTER_REF_NAME, SITE_FOOTER_REF_NAME,
errorMessages errorMessages
@ -277,9 +287,6 @@ export default {
|| this.selectedAppointmentType === 'Dropoff' || this.selectedAppointmentType === 'Dropoff'
); );
}, },
isAppointmentTypeDisplayed() {
return this.zipCode && !this.displayNoShopsAlert && this.showMobileOption;
},
isMobile() { isMobile() {
return this.selectedAppointmentType === AppointmentTypeStrings.MOBILE return this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
}, },
@ -328,6 +335,15 @@ export default {
mobileZipPlaceholder() { mobileZipPlaceholder() {
return this.getCmsContent('MobileZipPlaceHolderWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT); return this.getCmsContent('MobileZipPlaceHolderWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
}, },
militaryBaseWarningLinkText() {
return this.getCmsContent('AlertMilitaryBaseZipWidget', widgetFields.ALERT_WIDGET.HEADLINE_TEXT);
},
militaryBaseWarningText() {
return this.getCmsContent('AlertMilitaryBaseZipWidget', widgetFields.ALERT_WIDGET.BODY_TEXT);
},
appointmentQuestionText() {
return this.getCmsContent('AppointmentTypeQuestionWidget', widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT);
}
}, },
methods: { methods: {
arePagePrerequisitesValid() { arePagePrerequisitesValid() {
@ -424,6 +440,9 @@ export default {
if (serviceabilityDetails) { if (serviceabilityDetails) {
this.setServiceabilityDetails(serviceabilityDetails); this.setServiceabilityDetails(serviceabilityDetails);
this.showMobileOption = this.isServiceableMobile; this.showMobileOption = this.isServiceableMobile;
if (!this.showMobileOption) {
this.selectedAppointmentType = AppointmentTypeStrings.IN_SHOP;
}
} }
if (mobileFeePart) { if (mobileFeePart) {
@ -564,10 +583,30 @@ $page-side-padding: 1.5rem;
.form-test-error { .form-test-error {
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
} }
.appointment-type-question-text {
color: $black;
font-weight: 600;
margin-bottom: 1rem;
font-size: 1rem;
line-height: 1.625rem;
}
.mobile-service-zip-question { .mobile-service-zip-question {
:deep(.form-test-error span) { :deep(.form-test-error span) {
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
} }
} }
.expandable-link-container {
margin-bottom: 1rem;
}
.expandable-link {
font-style: italic;
font-weight: $font-weight-bold;
text-decoration: none;
color: $heritage-blue-primary;
line-height: 1.375rem;
&:hover {
text-decoration: underline;
}
}
} }
</style> </style>

View file

@ -3,7 +3,6 @@
name="fade" name="fade"
mode="out-in"> mode="out-in">
<div <div
v-if="isDisplayed"
class="shop-address" class="shop-address"
aria-live="polite"> aria-live="polite">
<div class="address-header">{{ questionText }}</div> <div class="address-header">{{ questionText }}</div>
@ -122,7 +121,6 @@ export default {
serviceZipcode: String, serviceZipcode: String,
cmsWidgetName: String, cmsWidgetName: String,
validationRules: String, validationRules: String,
isDisplayed: Boolean,
modalWidgetName: String, modalWidgetName: String,
selectedAppointmentType: String, selectedAppointmentType: String,
}, },
@ -229,11 +227,6 @@ export default {
}, },
async searchRadiusInMiles() { async searchRadiusInMiles() {
await this.updateShops(); await this.updateShops();
},
nearbyShops(newShops) {
if (!newShops.find(shop => shop.providerNumber === this.internalProviderNumber)) {
this.internalProviderNumber = '';
}
} }
}, },
methods: { methods: {
@ -250,6 +243,10 @@ export default {
this.errorMessage = errorMessages.ZIP_CODE_NOT_SERVICED_FOR_VEHICLE; this.errorMessage = errorMessages.ZIP_CODE_NOT_SERVICED_FOR_VEHICLE;
} }
else { else {
if (!result.find(shop => shop.providerNumber === this.internalProviderNumber)) {
this.internalProviderNumber = '';
await this.$nextTick();
}
this.nearbyShops = result; this.nearbyShops = result;
this.searchRadiusInMiles = this.searchRadiusArray[currentSearchIndex].Name; this.searchRadiusInMiles = this.searchRadiusArray[currentSearchIndex].Name;
} }

View file

@ -210,6 +210,9 @@ $alert-bg-scale: -90%;
$alert-border-scale: -100%; $alert-border-scale: -100%;
$alert-color-scale: 40%; $alert-color-scale: 40%;
$alert-yellow-bg: #fef6e8;
$alert-yellow-color: #e86421;
//Modal animation //Modal animation
// This affects all [Bootstrap] modals // This affects all [Bootstrap] modals
$modal-fade-transform: translate(0, 100%); $modal-fade-transform: translate(0, 100%);

View file

@ -1,64 +1,84 @@
<template> <template>
<div <div
class="alert fade show text-center mb-0 py-2 px-4" class="alert fade show"
role="alert" role="alert"
:class="[ :class="[
isDismissible ? 'alert-dismissible' : '', isDismissible ? 'alert-dismissible' : '',
alertClass, alertClass,
cssClassNameForCmsWidget, cssClassNameForCmsWidget,
]"> ]">
<p class="m-0 fw-bold alert-heading"> <div class="alert-header">
{{ alertHeadline }} <svg class="alert-icon" xmlns="http://www.w3.org/2000/svg" width="20" height="21" viewBox="0 0 20 21">
</p> <path fill-rule="nonzero" d="M10 .5c5.523 0 10 4.477 10 10s-4.477 10-10 10-10-4.477-10-10S4.477.5 10 .5zm.043 13.6a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm.77-9.2h-1.54l-.088.009a.502.502 0 0 0-.299.193.66.66 0 0 0-.125.47l.747 6.806.017.096c.065.249.263.425.495.426l.084-.008c.22-.042.396-.246.427-.51l.793-6.805.004-.102a.651.651 0 0 0-.127-.37.489.489 0 0 0-.388-.205z"/>
<template
v-for="paragraph in splitAlertCopyForParagraphTag"
:key="paragraph">
<p
v-if="!doesCopyContainRouterLink(paragraph) && !doesCopyContainTextLink(paragraph)"
class="m-0 text-body small"
v-html="paragraph"></p>
<p
v-else
class="m-0 text-body small">
<template v-if="doesCopyContainRouterLink(paragraph)">
<textBlock
:customText="paragraph"
class="mb-1"
marginTopSizeOverride="0" />
</template>
<template
v-for="copy in splitCopyOnCMSPlaceHolder(paragraph)"
v-else
:key="copy">
<span v-if="doesCopyContainTextLink(copy)">
<textLink
linkType="text"
:text="getRouterLinkDisplayTextFromCopy(copy)"
href="#!"
:data-bs-target="'#' + getRouterLinkRouteFromCopy(copy)"
@click-event="
$emit('textLinkClicked', getRouterLinkRouteFromCopy(copy))
" />
</span>
<span
v-else
v-html="copy"></span>
</template>
</p>
</template>
<button
type="button"
class="btn-close p-2"
data-bs-dismiss="alert"
aria-label="Close">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 23.7 23.7"
xml:space="preserve">
<path
d="m23.24 2.7-9.15 9.15L23.24 21a1.581 1.581 0 0 1-1.12 2.7c-.42 0-.82-.16-1.12-.46l-9.15-9.15-9.15 9.15c-.3.3-.7.46-1.12.46A1.581 1.581 0 0 1 .46 21l8.47-8.47.68-.68L.46 2.7c-.62-.62-.62-1.62 0-2.24.62-.62 1.62-.62 2.24 0l8.47 8.47.68.68L21 .46a1.57 1.57 0 0 1 2.23 0c.63.62.63 1.62.01 2.24z" />
</svg> </svg>
</button> <span class="m-0 fw-bold alert-header-text">
{{ alertHeadline }}
</span>
<button
v-if="isCollapsible"
class="btn-collapse"
type="button"
@click="toggleCollapse">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="9" viewBox="0 0 15 9"
class="btn-collapse-icon"
:class="{ 'rotated': !collapsed }">
<path fill-rule="nonzero" d="M7.5 0a.806.806 0 0 0-.593.265L.246 7.455a.957.957 0 0 0 0 1.28.796.796 0 0 0 1.185 0l6.07-6.55 6.068 6.55a.796.796 0 0 0 1.186 0 .957.957 0 0 0 0-1.28L8.093.265A.806.806 0 0 0 7.5 0"/>
</svg>
</button>
<button
v-if="isDismissible"
type="button"
class="btn-close p-2"
data-bs-dismiss="alert"
aria-label="Close">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 23.7 23.7"
xml:space="preserve">
<path
d="m23.24 2.7-9.15 9.15L23.24 21a1.581 1.581 0 0 1-1.12 2.7c-.42 0-.82-.16-1.12-.46l-9.15-9.15-9.15 9.15c-.3.3-.7.46-1.12.46A1.581 1.581 0 0 1 .46 21l8.47-8.47.68-.68L.46 2.7c-.62-.62-.62-1.62 0-2.24.62-.62 1.62-.62 2.24 0l8.47 8.47.68.68L21 .46a1.57 1.57 0 0 1 2.23 0c.63.62.63 1.62.01 2.24z" />
</svg>
</button>
</div>
<div class="alert-body"
:id="collapseId">
<template
v-for="paragraph in splitAlertCopyForParagraphTag"
:key="paragraph">
<p
v-if="!doesCopyContainRouterLink(paragraph) && !doesCopyContainTextLink(paragraph)"
class="m-0 text-body small"
v-html="paragraph"></p>
<p
v-else
class="m-0 text-body small">
<template v-if="doesCopyContainRouterLink(paragraph)">
<textBlock
:customText="paragraph"
class="mb-1"
marginTopSizeOverride="0" />
</template>
<template
v-for="copy in splitCopyOnCMSPlaceHolder(paragraph)"
v-else
:key="copy">
<span v-if="doesCopyContainTextLink(copy)">
<textLink
linkType="text"
:text="getRouterLinkDisplayTextFromCopy(copy)"
href="#!"
:data-bs-target="'#' + getRouterLinkRouteFromCopy(copy)"
@click-event="
$emit('textLinkClicked', getRouterLinkRouteFromCopy(copy))
" />
</span>
<span
v-else
v-html="copy"></span>
</template>
</p>
</template>
</div>
</div> </div>
</template> </template>
@ -74,6 +94,7 @@ import {
import applicationConfig from '@/constants/application-config'; import applicationConfig from '@/constants/application-config';
import textBlock from '@/digital-components/text-block/text-block.vue'; import textBlock from '@/digital-components/text-block/text-block.vue';
import textLink from '@/ux-components/text-link/text-link.vue'; import textLink from '@/ux-components/text-link/text-link.vue';
import { Collapse } from 'bootstrap';
export default { export default {
// eslint-disable-next-line vue/multi-word-component-names // eslint-disable-next-line vue/multi-word-component-names
@ -84,13 +105,14 @@ export default {
}, },
props: { props: {
isDismissible: Boolean, isDismissible: Boolean,
isCollapsible: Boolean,
/* /*
alertClass class names: alertClass class names:
alert-success (green) alert-success (green)
alert-danger (red) alert-danger (red)
alert-warning (yellow) alert-warning (yellow)
alert-info (blue) alert-info (blue)
*/ */
alertClass: String, alertClass: String,
cmsWidgetName: { cmsWidgetName: {
type: String, type: String,
@ -106,7 +128,14 @@ export default {
shouldScrollToOnMount: { shouldScrollToOnMount: {
type: Boolean, type: Boolean,
default: true default: true
} },
startCollapsed: Boolean
},
data() {
return {
collapsed: this.startCollapsed || false,
collapseElement: null,
};
}, },
computed: { computed: {
pageQueryString() { pageQueryString() {
@ -124,10 +153,17 @@ export default {
}, },
splitAlertCopyForParagraphTag() { splitAlertCopyForParagraphTag() {
return splitCMSCopyOnParagraphTag(this.alertCopy); return splitCMSCopyOnParagraphTag(this.alertCopy);
} },
collapseId() {
return this.isCollapsible
? `${this.cmsWidgetName}-collapse`
: null;
},
}, },
mounted() { mounted() {
this.ensureAlertIsInViewPort(); this.ensureAlertIsInViewPort();
this.collapseElement = Collapse.getOrCreateInstance(document.getElementById(this.collapseId));
}, },
methods: { methods: {
doesCopyContainRouterLink, doesCopyContainRouterLink,
@ -152,37 +188,81 @@ export default {
<= (window.innerHeight - footerHeight <= (window.innerHeight - footerHeight
|| document.documentElement.clientHeight - footerHeight) || document.documentElement.clientHeight - footerHeight)
); );
} },
toggleCollapse() {
this.collapsed = !this.collapsed;
if (this.collapsed) {
this.collapseElement.hide();
} else {
this.collapseElement.show();
}
},
} }
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.alert { .alert {
border: 1px solid;
padding: 0rem;
margin-bottom: 2rem;
.alert-header {
display: flex;
align-items: center;
justify-content: center;
flex-direction: row;
padding: .75rem 1rem .75rem 1rem;
font-weight: 600;
color: $black;
}
.alert-icon {
min-width: 1rem;
max-height: 1rem;
}
.alert-header-text {
flex-grow: 1;
padding: 0rem .625rem;
}
.btn-collapse {
border: none;
background: none;
min-width: 1rem;
max-height: 1rem;
padding: 0;
}
.btn-collapse-icon {
height: 100%;
width: 100%;
transition: transform 0.3s;
&.rotated {
transform: rotate(180deg);
}
}
a { a {
text-decoration: none; text-decoration: none;
} }
border-color: transparent; border-color: transparent;
button {
display: none;
}
.btn-close { .btn-close {
background: none; background: none;
opacity: 1; opacity: 1;
width: 0.75rem; width: 0.75rem;
height: 0.75rem; height: 0.75rem;
top: 2px;
right: 2px;
} }
&.alert-dismissible { .alert-body {
button { margin: 0 1rem;
display: flex; padding: .5rem 1rem .75rem 1rem;
top: 2px; border-top: 1px solid;
right: 2px; color: $darker-gray;
} line-height: 26px;
font-weight: 400;
} }
&.alert-info { &.alert-info {
background-color: $blue-100; background-color: $blue-100;
.alert-heading { border-color: $blue-200;
color: $blue-700; .alert-body {
border-top-color: $blue-200;
} }
svg { svg {
fill: $blue-700; fill: $blue-700;
@ -192,8 +272,9 @@ export default {
} }
&.alert-danger { &.alert-danger {
background-color: $red-100; background-color: $red-100;
.alert-heading { border-color: $red-200;
color: $red-600; .alert-body {
border-top-color: $red-200;
} }
svg { svg {
fill: $red-600; fill: $red-600;
@ -202,20 +283,20 @@ export default {
} }
} }
&.alert-warning { &.alert-warning {
background-color: $yellow-100; background-color: $alert-yellow-bg;
.alert-heading { border-color: $alert-yellow-color;
color: $yellow-600; .alert-body {
border-top-color: $alert-yellow-color;
} }
svg { svg {
fill: $yellow-600; fill: $alert-yellow-color;
width: 1rem;
height: 1rem;
} }
} }
&.alert-success { &.alert-success {
background-color: $green-100; background-color: $green-100;
.alert-heading { border-color: $green-200;
color: $green-700; .alert-body {
border-top-color: $green-200;
} }
svg { svg {
fill: $green-700; fill: $green-700;
@ -223,9 +304,5 @@ export default {
height: 1rem; height: 1rem;
} }
} }
& p {
font-size: 0.875rem;
margin-bottom: 0.25rem !important;
}
} }
</style> </style>