Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Snow Falling Animation #3535

Merged
merged 13 commits into from
Dec 23, 2024
2 changes: 2 additions & 0 deletions kyma/environments/dev/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions public/defaultConfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions public/i18n/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
119 changes: 119 additions & 0 deletions src/header/Header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
47 changes: 46 additions & 1 deletion src/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,24 @@ 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 [isMenuOpen, setIsMenuOpen] = useState(false);
const [isSnowOpen, setIsSnowOpen] = useState(
!!localStorage.getItem(SNOW_STORAGE_KEY),
);

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();
Expand All @@ -54,6 +62,7 @@ export function Header() {
isResourceEditedState,
);
const [isFormOpen, setIsFormOpen] = useRecoilState(isFormOpenState);
const [theme] = useRecoilState(themeState);

const shellbarRef = useRef<ShellBarDomRef>(null);
useEffect(() => {
Expand All @@ -65,6 +74,13 @@ export function Header() {
}
}, [shellbarRef]);

useEffect(() => {
if (theme === 'sap_horizon_hcb' || theme === 'sap_horizon_hcw') {
setIsSnowOpen(false);
localStorage.removeItem(SNOW_STORAGE_KEY);
}
}, [theme]);

const inactiveClusterNames = Object.keys(clusters || {}).filter(
name => name !== cluster?.name,
);
Expand All @@ -77,6 +93,16 @@ export function Header() {
return spaces;
};

const handleSnowButtonClick = () => {
if (isSnowOpen) {
setIsSnowOpen(false);
localStorage.removeItem(SNOW_STORAGE_KEY);
} else {
setIsSnowOpen(true);
localStorage.setItem(SNOW_STORAGE_KEY, 'true');
}
};

const clustersList = [
...inactiveClusterNames.map((name, index) => {
return (
Expand Down Expand Up @@ -118,6 +144,15 @@ export function Header() {

return (
<>
{isSnowOpen && (
<div className="snowflakes" aria-hidden="true">
{[...Array(10).keys()].map(key => (
<div key={`snowflake-${key}`} className="snowflake">
</div>
))}
</div>
)}
<ShellBar
className="header"
startButton={
Expand Down Expand Up @@ -168,6 +203,16 @@ export function Header() {
}
onProfileClick={() => setIsMenuOpen(true)}
>
{isSnowEnabled && (
<ShellBarItem
onClick={handleSnowButtonClick}
icon={isSnowOpen ? 'heating-cooling' : 'activate'}
text={isSnowOpen ? t('navigation.snow-stop') : t('navigation.snow')}
title={
isSnowOpen ? t('navigation.snow-stop') : t('navigation.snow')
}
/>
)}
{isFeedbackEnabled && (
<ShellBarItem
onClick={() => window.open(feedbackLink, '_blank')}
Expand Down
Loading