diff --git a/src/components/Creator/CreatorArea/Blocks/Block/Block.module.scss b/src/components/Creator/CreatorArea/Blocks/Block/Block.module.scss index 01c75a6..de2aaeb 100644 --- a/src/components/Creator/CreatorArea/Blocks/Block/Block.module.scss +++ b/src/components/Creator/CreatorArea/Blocks/Block/Block.module.scss @@ -1,16 +1,9 @@ .singleBlock { position: relative; box-sizing: border-box; - animation: none !important; - animation-delay: initial !important; - animation-direction: initial !important; display: flex; margin: 10px 0; - --animation: none; - --animation-delay: initial; - --animation-direction: initial; - &[style*="align-items: stretch"] { .singleBlock { width: 100%; @@ -21,10 +14,13 @@ &:hover, &.hovered { outline: 2px solid #09c; + animation: none !important; } + &.minimized { //pointer-events: none; filter: none !important; + animation: none !important; height: 40px !important; overflow: hidden; border: none !important; diff --git a/src/components/Creator/LeftPanel/StylesPanel/Animations/Animations.tsx b/src/components/Creator/LeftPanel/StylesPanel/Animations/Animations.tsx new file mode 100644 index 0000000..157c155 --- /dev/null +++ b/src/components/Creator/LeftPanel/StylesPanel/Animations/Animations.tsx @@ -0,0 +1,165 @@ +import styles from "@/components/Creator/LeftPanel/StylesPanel/StylesPanel.module.scss"; +import {Option, Select} from "@/components/construction/Select"; +import {useEffect, useState} from "react"; +import {getInheritedStyleWith} from "@/helpers/block-styles"; +import {useSelector} from "react-redux"; +import Icon from "@/components/construction/Icon/Icon"; +import SingleAnimation from "@/components/Creator/LeftPanel/StylesPanel/Animations/SingleAnimation/SingleAnimation"; + +type ChangeValue = { + animations: string[]; + durations: string[]; + delays: string[]; + directions: string[]; + iterations: string[]; +} + +interface Props { + onChange: (value: string | null, property: string) => void +} + +const allAnimationsNames: [id: string, name: string][] = [ + ['none', 'Brak'], + ['beat', 'Pulsowanie'], + ['beat-fade', 'Pulsowanie z wygaszaniem'], + ['bounce', 'Podskok'], + ['fade', 'Wygaszanie'], + ['flip', 'Odwracanie'], + ['shake', 'Potrząsanie'], + ['spin', 'Obrót'], +]; +export default function (props: Props) { + const selectedBlock = useSelector((state: any) => state.structure.selectedBlock); + const rwd = useSelector((state: any) => state.structure.rwdMode); + const styleState = useSelector((state: any) => state.structure.styleState); + const [animations, setAnimations] = useState([]); + const [durations, setDurations] = useState([]); + const [delays, setDelays] = useState([]); + const [directions, setDirections] = useState([]); + const [iterations, setIterations] = useState([]); + + const changed = (value: ChangeValue) => { + setIterations([...value.iterations]); + setDirections([...value.directions]); + setDelays([...value.delays]); + setDurations([...value.durations]); + setAnimations([...value.animations]); + console.log({value}) + if (value.animations.includes('none')) { + props.onChange('', 'animationIterationCount'); + props.onChange('', 'animationDirection'); + props.onChange('', 'animationDelay'); + props.onChange('', 'animationDuration'); + props.onChange('none', 'animationName'); + return; + } + props.onChange(value.iterations.join(', '), 'animationIterationCount'); + props.onChange(value.directions.join(', '), 'animationDirection'); + props.onChange(value.delays.join(', '), 'animationDelay'); + props.onChange(value.durations.join(', '), 'animationDuration'); + props.onChange(value.animations.join(', '), 'animationName'); + } + const splitValue = value => (value || '').split(',').map(val => val.trim()).filter(val => val.length > 0); + useEffect(() => { + const style = getInheritedStyleWith( + selectedBlock.styles, + rwd, styleState, + ['animationName', 'animationDuration', 'animationDelay', 'animationDirection', 'animationIterationCount'], + ) as any; + setIterations(splitValue(style.animationIterationCount)); + setDirections(splitValue(style.animationDirection)); + setDelays(splitValue(style.animationDelay)); + setDurations(splitValue(style.animationDuration)); + setAnimations(splitValue(style.animationName)); + }, [selectedBlock, rwd, styleState]) + + const addAnimation = (animationId: string) => { + if (!animationId) { + return; + } + if (animationId === 'none') { + setIterations([]); + setDirections([]); + setDelays([]); + setDurations([]); + setAnimations(['none']); + changed({animations: ['none'], durations: [], delays: [], directions: [], iterations: []}) + return; + } + iterations.push('infinite'); + directions.push('normal'); + delays.push('0s'); + durations.push('1s'); + if (animations.includes('none')) { + animations.length = 0; + } + animations.push(animationId); + changed({ + animations, + durations, + delays, + directions, + iterations, + }); + } + const removeFilter = index => { + iterations.splice(index, 1); + directions.splice(index, 1); + delays.splice(index, 1); + durations.splice(index, 1); + animations.splice(index, 1); + changed({ + animations, + durations, + delays, + directions, + iterations, + }); + } + const getAnimationName =animationId=>allAnimationsNames.find(([id,name])=>id===animationId)?.[1]||''; + const getAnimationsList = () => { + return animations.map((id, index) => { + return (
+ changedAnimation(index, e)}/> + removeFilter(index)}/> +
) + } + ) + } + + const changedAnimation = (index: number, [name, duration, delay, direction, iteration]) => { + iterations[index] = iteration; + directions[index] = direction; + delays[index] = delay; + durations[index] = duration; + changed({ + animations, + durations, + delays, + directions, + iterations, + }); + } + + return ( +
+
+ +
+ + {getAnimationsList()} + +
+ ) +} diff --git a/src/components/Creator/LeftPanel/StylesPanel/Animations/SingleAnimation/SingleAnimation.tsx b/src/components/Creator/LeftPanel/StylesPanel/Animations/SingleAnimation/SingleAnimation.tsx new file mode 100644 index 0000000..b851e3e --- /dev/null +++ b/src/components/Creator/LeftPanel/StylesPanel/Animations/SingleAnimation/SingleAnimation.tsx @@ -0,0 +1,86 @@ +import styles from "@/components/Creator/LeftPanel/StylesPanel/StylesPanel.module.scss"; +import InputWithUnits from "@/components/construction/InputWithUnits/InputWithUnits"; +import {Units} from "@/types/units"; +import {useState} from "react"; +import {Option, Select} from "@/components/construction/Select"; + +type ValueType = [name: string, duration: string, delay: string, direction: string, iteration: string]; + +interface Props { + label: string; + name: string; + duration: string; + delay: string; + direction: string; + iteration: string; + onChange: (value: ValueType) => void +} + +export default function (props: Props) { + const [duration, setDuration] = useState(props.duration) + const [delay, setDelay] = useState(props.delay) + const [direction, setDirection] = useState(props.direction) + const [iteration, setIteration] = useState(props.iteration) + const timeUnits: Units[] = ['s', 'ms']; + + const changeDuration = (val: string) => { + setDuration(val); + props.onChange([props.name, val, delay, direction, iteration]) + } + const changeDelay = (val: string) => { + setDelay(val); + props.onChange([props.name, duration, val, direction, iteration]) + } + const changeDirection = (val: string) => { + setDirection(val); + props.onChange([props.name, duration, delay, val, iteration]) + } + const changeIteration = (val: string) => { + setIteration(val); + props.onChange([props.name, duration, delay, direction, val]) + } + return ( +
+ {props.label} + {props.name !== 'none' + ? <> +
+
+ +
+
+ +
+
+
+
+ +
+
+ + +
+
+ : ''} +
+ ) +} diff --git a/src/components/Creator/LeftPanel/StylesPanel/Filter/Filter.tsx b/src/components/Creator/LeftPanel/StylesPanel/Filter/Filter.tsx index 358eee6..9f12d6d 100644 --- a/src/components/Creator/LeftPanel/StylesPanel/Filter/Filter.tsx +++ b/src/components/Creator/LeftPanel/StylesPanel/Filter/Filter.tsx @@ -66,16 +66,16 @@ export default function (props: Props) { } const addFilterUnits = value => { return [...value].map(([id, val]) => { - if(id === 'drop-shadow' ){ - return [id, val.map((v,index)=>{ - if(index===3){ + if (id === 'drop-shadow') { + return [id, val.map((v, index) => { + if (index === 3) { return v; } return `${parseInt(v)}px` }).join(' ')] } const [, unit] = filterDefaultUnits.find(([f_id, _unit]) => f_id === id)! - return [id, `${val}${unit}`] + return [id, `${val}${unit}`] }); } const mapFiltersToArray = (value: string): SelectedFilter[] => { @@ -110,6 +110,9 @@ export default function (props: Props) { }, [selectedBlock, rwd, styleState]) const addFilter = (filterId: string) => { + if (!filterId) { + return; + } const [, defaultValue] = filtersDefaultValues.find(([id, _]) => id === filterId); const newFilter: SelectedFilter = [filterId, defaultValue]; setSelectedFilters([...selectedFilters, newFilter]); diff --git a/src/components/Creator/LeftPanel/StylesPanel/StylesPanel.tsx b/src/components/Creator/LeftPanel/StylesPanel/StylesPanel.tsx index 78ca2db..d4d2bbf 100644 --- a/src/components/Creator/LeftPanel/StylesPanel/StylesPanel.tsx +++ b/src/components/Creator/LeftPanel/StylesPanel/StylesPanel.tsx @@ -20,6 +20,7 @@ import Text from "@/components/Creator/LeftPanel/StylesPanel/Text/Text"; import TextShadow from "@/components/Creator/LeftPanel/StylesPanel/TextShadow/TextShadow"; import Background from "@/components/Creator/LeftPanel/StylesPanel/Background/Background"; import Filter from "@/components/Creator/LeftPanel/StylesPanel/Filter/Filter"; +import Animations from "@/components/Creator/LeftPanel/StylesPanel/Animations/Animations"; export default function () { const selectedBlock = useSelector((state: any) => state.structure.selectedBlock); @@ -54,7 +55,7 @@ export default function () { ['margin', ], ['padding', ], ['filter', ], - // ['animations', ], + ['animations', ], ] const canShow = ([id,c]) => { return shouldShowStyleForBlockType(selectedBlock.type, id); diff --git a/src/components/construction/InputWithUnits/InputWithUnits.tsx b/src/components/construction/InputWithUnits/InputWithUnits.tsx index 02f4dbb..b6fee05 100644 --- a/src/components/construction/InputWithUnits/InputWithUnits.tsx +++ b/src/components/construction/InputWithUnits/InputWithUnits.tsx @@ -20,7 +20,7 @@ interface Props { onChange: (value: string) => void; } -const ALL_UNITS = ['px', 'pt', 'pc', 'in', 'mm', 'cm', '%', 'rem', 'em', 'vw', 'vh', 'vmin', 'vmax']; +const ALL_UNITS: Units[] = ['px', 'pt', 'pc', 'in', 'mm', 'cm', '%', 'rem', 'em', 'vw', 'vh', 'vmin', 'vmax', 'deg', 'ms', 's']; export default function (props: Props) { const propsValue = String(props.value || ''); const [inputValue, setInputValue] = useState(''); diff --git a/src/helpers/block-styles.ts b/src/helpers/block-styles.ts index 1b81684..984cc50 100644 --- a/src/helpers/block-styles.ts +++ b/src/helpers/block-styles.ts @@ -39,15 +39,6 @@ export function getInheritedStyle(rwd: RWD_MODES, styleState: STYLE_STATE_NAMES, } } - if (finalStyles['animation']) { - finalStyles['--animation'] = finalStyles['animation']; - } - if (finalStyles['animationDelay']) { - finalStyles['--animation-delay'] = finalStyles['animationDelay']; - } - if (finalStyles['animationDirection']) { - finalStyles['--animation-direction'] = finalStyles['animationDirection']; - } return finalStyles; } diff --git a/src/styles/animations.css b/src/styles/animations.css new file mode 100644 index 0000000..3892cf7 --- /dev/null +++ b/src/styles/animations.css @@ -0,0 +1,189 @@ +@-webkit-keyframes beat { + 0%, 90% { + transform: scale(1) + } + 45% { + transform: scale(1.25) + } +} + +@keyframes beat { + 0%, 90% { + transform: scale(1) + } + 45% { + transform: scale(1.25) + } +} + +@-webkit-keyframes bounce { + 0% { + transform: scale(1) translateY(0) + } + 10% { + transform: scale(1.1, .9) translateY(0) + } + 30% { + transform: scale(.9, 1.1) translateY(-.5em) + } + 50% { + transform: scale(1.05, .95) translateY(0) + } + 57% { + transform: scale(1) translateY(-.125em) + } + 64% { + transform: scale(1) translateY(0) + } + to { + transform: scale(1) translateY(0) + } +} + +@keyframes bounce { + 0% { + transform: scale(1) translateY(0) + } + 10% { + transform: scale(1.1, .9) translateY(0) + } + 30% { + transform: scale(.9, 1.1) translateY(-.5em) + } + 50% { + transform: scale(1.05, .95) translateY(0) + } + 57% { + transform: scale(1) translateY(-.125em) + } + 64% { + transform: scale(1) translateY(0) + } + to { + transform: scale(1) translateY(0) + } +} + +@-webkit-keyframes fade { + 50% { + opacity: .4 + } +} + +@keyframes fade { + 50% { + opacity: .4 + } +} + +@-webkit-keyframes beat-fade { + 0%, to { + opacity: .4; + transform: scale(1) + } + 50% { + opacity: 1; + transform: scale(1.125) + } +} + +@keyframes beat-fade { + 0%, to { + opacity: .4; + transform: scale(1) + } + 50% { + opacity: 1; + transform: scale(1.125) + } +} + +@-webkit-keyframes flip { + 50% { + transform: rotate3d(0, 1, 0, -180deg) + } +} + +@keyframes flip { + 50% { + transform: rotate3d(0, 1, 0, -180deg) + } +} + +@-webkit-keyframes shake { + 0% { + transform: rotate(-15deg) + } + 4% { + transform: rotate(15deg) + } + 8%, 24% { + transform: rotate(-18deg) + } + 12%, 28% { + transform: rotate(18deg) + } + 16% { + transform: rotate(-22deg) + } + 20% { + transform: rotate(22deg) + } + 32% { + transform: rotate(-12deg) + } + 36% { + transform: rotate(12deg) + } + 40%, to { + transform: rotate(0deg) + } +} + +@keyframes shake { + 0% { + transform: rotate(-15deg) + } + 4% { + transform: rotate(15deg) + } + 8%, 24% { + transform: rotate(-18deg) + } + 12%, 28% { + transform: rotate(18deg) + } + 16% { + transform: rotate(-22deg) + } + 20% { + transform: rotate(22deg) + } + 32% { + transform: rotate(-12deg) + } + 36% { + transform: rotate(12deg) + } + 40%, to { + transform: rotate(0deg) + } +} + +@-webkit-keyframes spin { + 0% { + transform: rotate(0deg) + } + to { + transform: rotate(1turn) + } +} + +@keyframes spin { + 0% { + transform: rotate(0deg) + } + to { + transform: rotate(1turn) + } +} diff --git a/src/styles/globals.css b/src/styles/globals.css index 0630c39..dcb03fe 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -1,7 +1,7 @@ @import "icons-set.styles.css"; @import "table.css"; @import "react-tabs.css"; - +@import "animations.css"; * { box-sizing: border-box; diff --git a/src/types/units.ts b/src/types/units.ts index 1b0edc0..d71c380 100644 --- a/src/types/units.ts +++ b/src/types/units.ts @@ -13,3 +13,5 @@ export declare type Units = | 'vmin' | 'vmax' | 'deg' + | 's' + | 'ms'