Add TranscendenceStar and TranscendenceFragment
`TranscendenceStar` is a new star capable of displaying `TranscendenceFragment`s depending on the `GridCharacter` stage
This commit is contained in:
parent
d618d44429
commit
9c757c2c5b
4 changed files with 314 additions and 0 deletions
83
components/TranscendenceFragment/index.scss
Normal file
83
components/TranscendenceFragment/index.scss
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
.Fragment {
|
||||||
|
$degrees: 72deg;
|
||||||
|
|
||||||
|
$origWidth: 29px;
|
||||||
|
$origHeight: 54px;
|
||||||
|
|
||||||
|
$scaledWidth: 12px;
|
||||||
|
$scaledHeight: calc(($scaledWidth / $origWidth) * $origHeight);
|
||||||
|
|
||||||
|
$scale: 1.2;
|
||||||
|
|
||||||
|
@include hidpiImage(
|
||||||
|
'/icons/transcendence/interactive/interactive-piece',
|
||||||
|
png,
|
||||||
|
$scaledWidth,
|
||||||
|
$scaledHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
z-index: 32;
|
||||||
|
|
||||||
|
aspect-ratio: 29 / 54;
|
||||||
|
height: $scaledHeight;
|
||||||
|
width: $scaledWidth;
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Visible {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Stage1 {
|
||||||
|
top: 3px;
|
||||||
|
left: 18px;
|
||||||
|
|
||||||
|
// &:hover {
|
||||||
|
// transform: scale($scale, $scale) translateY(-2px);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Stage2 {
|
||||||
|
top: 10px;
|
||||||
|
left: 27px;
|
||||||
|
transform: rotate($degrees);
|
||||||
|
|
||||||
|
// &:hover {
|
||||||
|
// transform: rotate($degrees) scale($scale, $scale) translateY(-2px);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Stage3 {
|
||||||
|
top: 21px;
|
||||||
|
left: 24px;
|
||||||
|
transform: rotate($degrees * 2);
|
||||||
|
|
||||||
|
// &:hover {
|
||||||
|
// transform: rotate($degrees * 2) scale($scale, $scale) translateY(-1px);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Stage4 {
|
||||||
|
top: 21px;
|
||||||
|
left: 12px;
|
||||||
|
transform: rotate($degrees * 3);
|
||||||
|
|
||||||
|
// &:hover {
|
||||||
|
// transform: rotate($degrees * 3) scale($scale, $scale) translateY(-1px);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Stage5 {
|
||||||
|
top: 10px;
|
||||||
|
left: 8px;
|
||||||
|
transform: rotate($degrees * 4);
|
||||||
|
|
||||||
|
// &:hover {
|
||||||
|
// transform: rotate($degrees * 4) scale($scale, $scale) translateY(-1px);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
49
components/TranscendenceFragment/index.tsx
Normal file
49
components/TranscendenceFragment/index.tsx
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
import React from 'react'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
stage: number
|
||||||
|
interactive: boolean
|
||||||
|
visible: boolean
|
||||||
|
onClick?: (index: number) => void
|
||||||
|
onHover?: (index: number) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const TranscendenceFragment = ({
|
||||||
|
interactive,
|
||||||
|
stage,
|
||||||
|
visible,
|
||||||
|
onClick,
|
||||||
|
onHover,
|
||||||
|
}: Props) => {
|
||||||
|
const classes = classnames({
|
||||||
|
Fragment: true,
|
||||||
|
Visible: visible,
|
||||||
|
Stage1: stage === 1,
|
||||||
|
Stage2: stage === 2,
|
||||||
|
Stage3: stage === 3,
|
||||||
|
Stage4: stage === 4,
|
||||||
|
Stage5: stage === 5,
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
if (interactive && onClick) onClick(stage)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleHover() {
|
||||||
|
if (interactive && onHover) onHover(stage)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<i className={classes} onClick={handleClick} onMouseOver={handleHover} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
TranscendenceFragment.defaultProps = {
|
||||||
|
interactive: false,
|
||||||
|
visible: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TranscendenceFragment
|
||||||
79
components/TranscendenceStar/index.scss
Normal file
79
components/TranscendenceStar/index.scss
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
.TranscendenceStar {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&.Immutable {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Figure {
|
||||||
|
$size: 18px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 54px 54px;
|
||||||
|
display: block;
|
||||||
|
height: $size;
|
||||||
|
width: $size;
|
||||||
|
|
||||||
|
&.Interactive.Base {
|
||||||
|
$size: $unit-6x;
|
||||||
|
|
||||||
|
@include hidpiImage(
|
||||||
|
'/icons/transcendence/interactive/interactive-base',
|
||||||
|
png,
|
||||||
|
$size,
|
||||||
|
$size
|
||||||
|
);
|
||||||
|
|
||||||
|
height: $size;
|
||||||
|
width: $size;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Stage1 {
|
||||||
|
background-image: url('/icons/transcendence/1/step-1@3x.png');
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-image: url('/icons/transcendence/1/step-1-hover@3x.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Stage2 {
|
||||||
|
background-image: url('/icons/transcendence/2/step-2@3x.png');
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-image: url('/icons/transcendence/2/step-2-hover@3x.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Stage3 {
|
||||||
|
background-image: url('/icons/transcendence/3/step-3@3x.png');
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-image: url('/icons/transcendence/3/step-3-hover@3x.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Stage4 {
|
||||||
|
background-image: url('/icons/transcendence/4/step-4@3x.png');
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-image: url('/icons/transcendence/4/step-4-hover@3x.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Stage5 {
|
||||||
|
background-image: url('/icons/transcendence/5/step-5@3x.png');
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-image: url('/icons/transcendence/5/step-5-hover@3x.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
103
components/TranscendenceStar/index.tsx
Normal file
103
components/TranscendenceStar/index.tsx
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
import TranscendenceFragment from '~components/TranscendenceFragment'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
className?: string
|
||||||
|
stage: number
|
||||||
|
editable: boolean
|
||||||
|
interactive: boolean
|
||||||
|
onClick?: () => void
|
||||||
|
onFragmentClick?: (newStage: number) => void
|
||||||
|
onFragmentHover?: (newStage: number) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const NUM_FRAGMENTS = 5
|
||||||
|
|
||||||
|
const TranscendenceStar = ({
|
||||||
|
className,
|
||||||
|
interactive,
|
||||||
|
stage,
|
||||||
|
editable,
|
||||||
|
onClick,
|
||||||
|
onFragmentClick,
|
||||||
|
onFragmentHover,
|
||||||
|
}: Props) => {
|
||||||
|
const [visibleStage, setVisibleStage] = useState(0)
|
||||||
|
const [currentStage, setCurrentStage] = useState(0)
|
||||||
|
|
||||||
|
// Classes
|
||||||
|
const starClasses = classnames({
|
||||||
|
TranscendenceStar: true,
|
||||||
|
Immutable: !editable,
|
||||||
|
})
|
||||||
|
|
||||||
|
const baseImageClasses = classnames(className, {
|
||||||
|
Figure: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setVisibleStage(stage)
|
||||||
|
setCurrentStage(stage)
|
||||||
|
}, [stage])
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
if (onClick) {
|
||||||
|
onClick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFragmentClick(index: number) {
|
||||||
|
let newStage = index
|
||||||
|
if (index === currentStage) newStage = 0
|
||||||
|
|
||||||
|
setVisibleStage(newStage)
|
||||||
|
setCurrentStage(newStage)
|
||||||
|
if (onFragmentClick) onFragmentClick(newStage)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFragmentHover(index: number) {
|
||||||
|
setVisibleStage(index)
|
||||||
|
if (onFragmentHover) onFragmentHover(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseLeave() {
|
||||||
|
setVisibleStage(currentStage)
|
||||||
|
if (onFragmentHover) onFragmentHover(currentStage)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
className={starClasses}
|
||||||
|
onClick={interactive ? handleClick : () => {}}
|
||||||
|
onMouseLeave={interactive ? handleMouseLeave : () => {}}
|
||||||
|
>
|
||||||
|
<div className="Fragments">
|
||||||
|
{[...Array(NUM_FRAGMENTS)].map((e, i) => {
|
||||||
|
const loopStage = i + 1
|
||||||
|
return (
|
||||||
|
<TranscendenceFragment
|
||||||
|
key={`fragment_${loopStage}`}
|
||||||
|
stage={loopStage}
|
||||||
|
visible={loopStage <= visibleStage}
|
||||||
|
interactive={interactive}
|
||||||
|
onClick={interactive ? handleFragmentClick : () => {}}
|
||||||
|
onHover={interactive ? handleFragmentHover : () => {}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<i className={baseImageClasses} />
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
TranscendenceStar.defaultProps = {
|
||||||
|
stage: 0,
|
||||||
|
editable: false,
|
||||||
|
interactive: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TranscendenceStar
|
||||||
Loading…
Reference in a new issue