diff --git a/kyma/environments/dev/config.yaml b/kyma/environments/dev/config.yaml index a29e6a3976..a03344a0c0 100644 --- a/kyma/environments/dev/config.yaml +++ b/kyma/environments/dev/config.yaml @@ -99,3 +99,5 @@ config: link: https://sapinsights.eu.qualtrics.com/jfe/form/SV_d3UPNymSgUHAb9Y?product=SAP%20BTP,%20Kyma%20Runtime&product_filter=Kyma COLUMN_LAYOUT: isEnabled: true + SNOW: + isEnabled: true diff --git a/kyma/environments/prod/config.yaml b/kyma/environments/prod/config.yaml index 2b239ac776..e117e3bebd 100644 --- a/kyma/environments/prod/config.yaml +++ b/kyma/environments/prod/config.yaml @@ -99,3 +99,5 @@ config: link: https://sapinsights.eu.qualtrics.com/jfe/form/SV_2gcfdw3EYYOIz5A?product=SAP%20BTP,%20Kyma%20Runtime&product_filter=Kyma COLUMN_LAYOUT: isEnabled: true + SNOW: + isEnabled: false diff --git a/kyma/environments/stage/config.yaml b/kyma/environments/stage/config.yaml index a1bf90088b..7e559b4e66 100644 --- a/kyma/environments/stage/config.yaml +++ b/kyma/environments/stage/config.yaml @@ -97,3 +97,5 @@ config: link: https://sapinsights.eu.qualtrics.com/jfe/form/SV_d3UPNymSgUHAb9Y?product=SAP%20BTP,%20Kyma%20Runtime&product_filter=Kyma COLUMN_LAYOUT: isEnabled: true + SNOW: + isEnabled: true diff --git a/public/defaultConfig.yaml b/public/defaultConfig.yaml index a59bdaad55..e02dedec9e 100644 --- a/public/defaultConfig.yaml +++ b/public/defaultConfig.yaml @@ -78,3 +78,5 @@ config: FEEDBACK: isEnabled: true link: https://sapinsights.eu.qualtrics.com/jfe/form/SV_d3UPNymSgUHAb9Y?product=SAP%20BTP,%20Kyma%20Runtime&product_filter=Kyma + SNOW: + isEnabled: true diff --git a/public/i18n/en.yaml b/public/i18n/en.yaml index a1aa4b7362..d6842cd054 100644 --- a/public/i18n/en.yaml +++ b/public/i18n/en.yaml @@ -838,6 +838,8 @@ namespaces: navigation: all-namespaces: All Namespaces feedback: Feedback + snow: Let it snow + snow-stop: Stop the snow menu: get-help: Get Help give-feedback: Give Feedback diff --git a/src/header/Header.scss b/src/header/Header.scss index 540416ab80..22289771ac 100644 --- a/src/header/Header.scss +++ b/src/header/Header.scss @@ -9,3 +9,122 @@ ui5-shellbar.header::part(root) { border-radius: 0.5rem; box-shadow: var(--sapContainer_Shadow1); } + +.snowflake { + color: #fff; + font-size: 1em; + font-family: Arial; + text-shadow: 0 0 1px #000; +} + +@-webkit-keyframes snowflakes-fall { + 0% { + top: -10%; + } + 100% { + top: 100%; + } +} +@-webkit-keyframes snowflakes-shake { + 0% { + -webkit-transform: translateX(0px); + transform: translateX(0px); + } + 50% { + -webkit-transform: translateX(80px); + transform: translateX(80px); + } + 100% { + -webkit-transform: translateX(0px); + transform: translateX(0px); + } +} +@keyframes snowflakes-fall { + 0% { + top: -10%; + } + 100% { + top: 100%; + } +} +@keyframes snowflakes-shake { + 0% { + transform: translateX(0px); + } + 50% { + transform: translateX(80px); + } + 100% { + transform: translateX(0px); + } +} +.snowflake { + position: fixed; + top: -10%; + z-index: 9999; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: default; + -webkit-animation-name: snowflakes-fall, snowflakes-shake; + -webkit-animation-duration: 10s, 3s; + -webkit-animation-timing-function: linear, ease-in-out; + -webkit-animation-iteration-count: infinite, infinite; + -webkit-animation-play-state: running, running; + animation-name: snowflakes-fall, snowflakes-shake; + animation-duration: 10s, 3s; + animation-timing-function: linear, ease-in-out; + animation-iteration-count: infinite, infinite; + animation-play-state: running, running; +} +.snowflake:nth-of-type(0) { + left: 1%; + -webkit-animation-delay: 0s, 0s; + animation-delay: 0s, 0s; +} +.snowflake:nth-of-type(1) { + left: 10%; + -webkit-animation-delay: 1s, 1s; + animation-delay: 1s, 1s; +} +.snowflake:nth-of-type(2) { + left: 20%; + -webkit-animation-delay: 6s, 0.5s; + animation-delay: 6s, 0.5s; +} +.snowflake:nth-of-type(3) { + left: 30%; + -webkit-animation-delay: 4s, 2s; + animation-delay: 4s, 2s; +} +.snowflake:nth-of-type(4) { + left: 40%; + -webkit-animation-delay: 2s, 2s; + animation-delay: 2s, 2s; +} +.snowflake:nth-of-type(5) { + left: 50%; + -webkit-animation-delay: 8s, 3s; + animation-delay: 8s, 3s; +} +.snowflake:nth-of-type(6) { + left: 60%; + -webkit-animation-delay: 6s, 2s; + animation-delay: 6s, 2s; +} +.snowflake:nth-of-type(7) { + left: 70%; + -webkit-animation-delay: 2.5s, 1s; + animation-delay: 2.5s, 1s; +} +.snowflake:nth-of-type(8) { + left: 80%; + -webkit-animation-delay: 1s, 0s; + animation-delay: 1s, 0s; +} +.snowflake:nth-of-type(9) { + left: 90%; + -webkit-animation-delay: 3s, 1.5s; + animation-delay: 3s, 1.5s; +} diff --git a/src/header/Header.tsx b/src/header/Header.tsx index 08c54b2dea..0a62412346 100644 --- a/src/header/Header.tsx +++ b/src/header/Header.tsx @@ -32,16 +32,29 @@ import './Header.scss'; import { isResourceEditedState } from 'state/resourceEditedAtom'; import { isFormOpenState } from 'state/formOpenAtom'; import { handleActionIfFormOpen } from 'shared/components/UnsavedMessageBox/helpers'; +import { configFeaturesNames } from 'state/types'; +import { themeState } from 'state/preferences/themeAtom'; + +const SNOW_STORAGE_KEY = 'snow-animation'; export function Header() { useAvailableNamespaces(); + const localStorageSnowEnabled = () => { + const snowStorage = localStorage.getItem(SNOW_STORAGE_KEY); + if (snowStorage && typeof JSON.parse(snowStorage) === 'boolean') { + return JSON.parse(snowStorage); + } + return true; + }; const [isMenuOpen, setIsMenuOpen] = useState(false); + const [isSnowOpen, setIsSnowOpen] = useState(localStorageSnowEnabled()); const { t } = useTranslation(); const navigate = useNavigate(); const { isEnabled: isFeedbackEnabled, link: feedbackLink } = useFeature( - 'FEEDBACK', + configFeaturesNames.FEEDBACK, ); + const { isEnabled: isSnowEnabled } = useFeature(configFeaturesNames.SNOW); const { githubLink, busolaVersion } = useGetBusolaVersionDetails(); const legalLinks = useGetLegalLinks(); @@ -54,6 +67,7 @@ export function Header() { isResourceEditedState, ); const [isFormOpen, setIsFormOpen] = useRecoilState(isFormOpenState); + const [theme] = useRecoilState(themeState); const shellbarRef = useRef(null); useEffect(() => { @@ -65,6 +79,13 @@ export function Header() { } }, [shellbarRef]); + useEffect(() => { + if (theme === 'sap_horizon_hcb' || theme === 'sap_horizon_hcw') { + setIsSnowOpen(false); + localStorage.setItem(SNOW_STORAGE_KEY, JSON.stringify(false)); + } + }, [theme]); + const inactiveClusterNames = Object.keys(clusters || {}).filter( name => name !== cluster?.name, ); @@ -77,6 +98,16 @@ export function Header() { return spaces; }; + const handleSnowButtonClick = () => { + if (isSnowOpen) { + setIsSnowOpen(false); + localStorage.setItem(SNOW_STORAGE_KEY, JSON.stringify(false)); + } else { + setIsSnowOpen(true); + localStorage.setItem(SNOW_STORAGE_KEY, JSON.stringify(true)); + } + }; + const clustersList = [ ...inactiveClusterNames.map((name, index) => { return ( @@ -118,6 +149,15 @@ export function Header() { return ( <> + {isSnowOpen && isSnowEnabled && ( + + )} setIsMenuOpen(true)} > + {isSnowEnabled && ( + + )} {isFeedbackEnabled && ( window.open(feedbackLink, '_blank')}