diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-05-18 11:44:37 +0200 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2022-05-18 11:44:37 +0200 |
| commit | 54883bb5c36cf21462a421605a709fdd6f04b150 (patch) | |
| tree | bb67a6c9ce824c52c3bae732a32f192a32969f64 | |
| parent | f347cc1e4ae32289198d698f05f84119a708b599 (diff) | |
chore: add branding animation
| -rw-r--r-- | src/components/molecules/images/flipping-logo.tsx | 20 | ||||
| -rw-r--r-- | src/components/molecules/layout/branding.module.scss | 125 | ||||
| -rw-r--r-- | src/components/molecules/layout/branding.tsx | 26 | ||||
| -rw-r--r-- | src/components/organisms/toolbar/toolbar-items.module.scss | 1 | ||||
| -rw-r--r-- | src/components/organisms/toolbar/toolbar.module.scss | 16 | ||||
| -rw-r--r-- | src/utils/hooks/use-styles.tsx | 29 |
6 files changed, 171 insertions, 46 deletions
diff --git a/src/components/molecules/images/flipping-logo.tsx b/src/components/molecules/images/flipping-logo.tsx index 47e54ab..1099d53 100644 --- a/src/components/molecules/images/flipping-logo.tsx +++ b/src/components/molecules/images/flipping-logo.tsx @@ -1,6 +1,6 @@ import Logo, { type LogoProps } from '@components/atoms/images/logo'; import Image, { type ImageProps } from 'next/image'; -import { FC } from 'react'; +import { ForwardedRef, forwardRef, ForwardRefRenderFunction } from 'react'; import styles from './flipping-logo.module.scss'; export type FlippingLogoProps = { @@ -27,15 +27,15 @@ export type FlippingLogoProps = { * * Render a logo and a photo with a flipping effect. */ -const FlippingLogo: FC<FlippingLogoProps> = ({ - className = '', - altText, - logoTitle, - photo, - ...props -}) => { +const FlippingLogo: ForwardRefRenderFunction< + HTMLDivElement, + FlippingLogoProps +> = ( + { className = '', altText, logoTitle, photo, ...props }, + ref: ForwardedRef<HTMLDivElement> +) => { return ( - <div className={`${styles.logo} ${className}`}> + <div className={`${styles.logo} ${className}`} ref={ref}> <div className={styles.logo__front}> <Image src={photo} @@ -52,4 +52,4 @@ const FlippingLogo: FC<FlippingLogoProps> = ({ ); }; -export default FlippingLogo; +export default forwardRef(FlippingLogo); diff --git a/src/components/molecules/layout/branding.module.scss b/src/components/molecules/layout/branding.module.scss index aa18002..6121fa1 100644 --- a/src/components/molecules/layout/branding.module.scss +++ b/src/components/molecules/layout/branding.module.scss @@ -1,48 +1,105 @@ @use "@styles/abstracts/functions" as fun; +@use "@styles/abstracts/mixins" as mix; + +@mixin typing-animation { + --typing-animation: none; + + width: fit-content; + position: relative; + overflow: hidden; + + &::after { + content: "|"; + display: block; + width: 100%; + height: 100%; + position: absolute; + top: 0; + right: 0; + background: var(--color-bg); + color: var(--color-primary-darker); + font-weight: 400; + text-align: left; + visibility: hidden; + transform: translateX(100%); + transform-origin: right; + animation: var(--typing-animation); + + :global { + animation: var(--typing-animation); + } + } +} .wrapper { + --logo-size: #{clamp(fun.convert-px(90), 12vw, fun.convert-px(100))}; + display: grid; - grid-template-columns: - var(--logo-size, fun.convert-px(100)) - minmax(0, 1fr); - grid-template-rows: 1fr min-content; - align-items: center; - column-gap: var(--spacing-sm); -} + grid-template-columns: minmax(0, 1fr); + justify-items: center; + width: 100%; -.logo { - grid-row: span 2; -} + @include mix.media("screen") { + @include mix.dimensions("2xs") { + grid-template-columns: + var(--logo-size, fun.convert-px(100)) + minmax(0, 1fr); + grid-template-rows: 1fr min-content; + align-items: center; + justify-items: left; + column-gap: var(--spacing-sm); + width: unset; + } + } -.title { - font-size: var(--font-size-2xl); -} + .logo { + grid-row: span 2; + margin-bottom: var(--spacing-sm); -.baseline { - color: var(--color-fg-light); -} + @include mix.media("screen") { + @include mix.dimensions("2xs") { + margin-bottom: 0; + } + } + } + + .title { + font-size: clamp(var(--font-size-xl), 8vw, var(--font-size-2xl)); + text-align: center; -.link { - background: linear-gradient( - to top, - var(--color-primary-light) fun.convert-px(5), - transparent fun.convert-px(5) - ) - left / 0 100% no-repeat; - text-decoration: none; - transition: all 0.6s ease-out 0s; - - &:hover, - &:focus { - background-size: 100% 100%; + @include typing-animation; } - &:focus { - color: var(--color-primary-light); + .baseline { + color: var(--color-fg-light); + font-size: var(--font-size-lg); + text-align: center; + + @include typing-animation; } - &:active { - background-size: 0 100%; - color: var(--color-primary-dark); + .link { + background: linear-gradient( + to top, + var(--color-primary-light) fun.convert-px(5), + transparent fun.convert-px(5) + ) + left / 0 100% no-repeat; + text-decoration: none; + transition: all 0.6s ease-out 0s; + + &:hover, + &:focus { + background-size: 100% 100%; + } + + &:focus { + color: var(--color-primary-light); + } + + &:active { + background-size: 0 100%; + color: var(--color-primary-dark); + } } } diff --git a/src/components/molecules/layout/branding.tsx b/src/components/molecules/layout/branding.tsx index 423c54f..9a82a74 100644 --- a/src/components/molecules/layout/branding.tsx +++ b/src/components/molecules/layout/branding.tsx @@ -1,6 +1,7 @@ import Heading from '@components/atoms/headings/heading'; +import useStyles from '@utils/hooks/use-styles'; import Link from 'next/link'; -import { FC } from 'react'; +import { FC, useRef } from 'react'; import { useIntl } from 'react-intl'; import FlippingLogo, { type FlippingLogoProps } from '../images/flipping-logo'; import styles from './branding.module.scss'; @@ -37,6 +38,9 @@ const Branding: FC<BrandingProps> = ({ withLink = false, ...props }) => { + const baselineRef = useRef<HTMLParagraphElement>(null); + const logoRef = useRef<HTMLDivElement>(null); + const titleRef = useRef<HTMLHeadingElement | HTMLParagraphElement>(null); const intl = useIntl(); const altText = intl.formatMessage( { @@ -55,6 +59,23 @@ const Branding: FC<BrandingProps> = ({ { website: title } ); + useStyles({ + property: '--typing-animation', + styles: 'blink 0.7s ease-in-out 0s 2, typing 4.3s linear 0s 1', + target: titleRef, + }); + useStyles({ + property: '--typing-animation', + styles: + 'hide-text 4.25s linear 0s 1, blink 0.8s ease-in-out 4.25s 2, typing 3.8s linear 4.25s 1', + target: baselineRef, + }); + useStyles({ + property: 'animation', + styles: 'flip-logo 9s ease-in 0s 1', + target: logoRef, + }); + return ( <div className={styles.wrapper}> <FlippingLogo @@ -62,6 +83,7 @@ const Branding: FC<BrandingProps> = ({ altText={altText} logoTitle={logoTitle} photo={photo} + ref={logoRef} {...props} /> <Heading @@ -69,6 +91,7 @@ const Branding: FC<BrandingProps> = ({ level={1} withMargin={false} className={styles.title} + ref={titleRef} > {withLink ? ( <Link href="/"> @@ -84,6 +107,7 @@ const Branding: FC<BrandingProps> = ({ level={4} withMargin={false} className={styles.baseline} + ref={baselineRef} > {baseline} </Heading> diff --git a/src/components/organisms/toolbar/toolbar-items.module.scss b/src/components/organisms/toolbar/toolbar-items.module.scss index fd526d6..c970b71 100644 --- a/src/components/organisms/toolbar/toolbar-items.module.scss +++ b/src/components/organisms/toolbar/toolbar-items.module.scss @@ -26,6 +26,7 @@ @include mix.media("screen") { @include mix.dimensions(null, "sm") { + position: fixed; left: 0; right: 0; } diff --git a/src/components/organisms/toolbar/toolbar.module.scss b/src/components/organisms/toolbar/toolbar.module.scss index cda9b37..4bcabcb 100644 --- a/src/components/organisms/toolbar/toolbar.module.scss +++ b/src/components/organisms/toolbar/toolbar.module.scss @@ -23,6 +23,18 @@ box-shadow: 0 fun.convert-px(-2) fun.convert-px(3) fun.convert-px(-1) var(--color-shadow-dark); + :global { + animation: slide-in-from-bottom 0.8s ease-in-out 0s 1; + } + + @include mix.media("screen") { + @include mix.dimensions("sm") { + :global { + animation: slide-in-from-top 1s ease-in-out 0s 1; + } + } + } + .modal { &--search, &--settings { @@ -52,8 +64,10 @@ } .tooltip { + padding: calc(var(--title-height) / 2 + var(--spacing-2xs)) + var(--spacing-2xs) var(--spacing-2xs); top: unset; - bottom: calc(100% + var(--spacing-xs)); + bottom: calc(100% + var(--spacing-2xs)); transform-origin: bottom right; } } diff --git a/src/utils/hooks/use-styles.tsx b/src/utils/hooks/use-styles.tsx new file mode 100644 index 0000000..d47e9fb --- /dev/null +++ b/src/utils/hooks/use-styles.tsx @@ -0,0 +1,29 @@ +import { RefObject, useEffect } from 'react'; + +export type UseStylesProps = { + /** + * A property name or a CSS variable. + */ + property: string; + /** + * The styles. + */ + styles: string; + /** + * A targeted element reference. + */ + target: RefObject<HTMLElement>; +}; + +/** + * Add styles to an element using a React reference. + * + * @param {UseStylesProps} props - An object with property, styles and target. + */ +const useStyles = ({ property, styles, target }: UseStylesProps) => { + useEffect(() => { + if (target.current) target.current.style.setProperty(property, styles); + }, [property, styles, target]); +}; + +export default useStyles; |
