diff --git a/components/HovercardHeader/index.module.scss b/components/HovercardHeader/index.module.scss new file mode 100644 index 00000000..dcc1117a --- /dev/null +++ b/components/HovercardHeader/index.module.scss @@ -0,0 +1,57 @@ +.root { + display: flex; + flex-direction: column; + gap: calc($unit / 2); + + .title { + align-items: center; + display: flex; + flex-direction: row; + gap: $unit * 2; + + h4 { + flex-grow: 1; + font-size: $font-medium; + line-height: 1.2; + min-width: 140px; + } + + img { + height: auto; + width: 100px; + } + + .image { + position: relative; + + .perpetuity { + position: absolute; + background-image: url('/icons/perpetuity/filled.svg'); + background-size: $unit-3x $unit-3x; + z-index: 20; + top: $unit-half * -1; + right: $unit-3x; + width: $unit-3x; + height: $unit-3x; + } + } + } + + .subInfo { + align-items: center; + display: flex; + flex-direction: row; + gap: $unit * 2; + + .icons { + display: flex; + flex-direction: row; + flex-grow: 1; + gap: $unit; + } + + .UncapIndicator { + min-width: 100px; + } + } +} diff --git a/components/HovercardHeader/index.tsx b/components/HovercardHeader/index.tsx new file mode 100644 index 00000000..e749b0a5 --- /dev/null +++ b/components/HovercardHeader/index.tsx @@ -0,0 +1,150 @@ +import { useRouter } from 'next/router' + +import UncapIndicator from '~components/uncap/UncapIndicator' +import WeaponLabelIcon from '~components/weapon/WeaponLabelIcon' + +import styles from './index.module.scss' + +interface Props { + gridObject: GridCharacter | GridSummon | GridWeapon + object: Character | Summon | Weapon + type: 'character' | 'summon' | 'weapon' +} + +const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light'] +const Proficiency = [ + 'none', + 'sword', + 'dagger', + 'axe', + 'spear', + 'bow', + 'staff', + 'fist', + 'harp', + 'gun', + 'katana', +] + +const HovercardHeader = ({ gridObject, object, type, ...props }: Props) => { + const router = useRouter() + const locale = + router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' + + const overlay = () => { + if (type === 'character') { + const gridCharacter = gridObject as GridCharacter + if (gridCharacter.perpetuity) return + } else if (type === 'summon') { + const gridSummon = gridObject as GridSummon + if (gridSummon.quick_summon) return + } + } + + const characterImage = () => { + const gridCharacter = gridObject as GridCharacter + const character = object as Character + + // Change the image based on the uncap level + let suffix = '01' + if (gridCharacter.uncap_level == 6) suffix = '04' + else if (gridCharacter.uncap_level == 5) suffix = '03' + else if (gridCharacter.uncap_level > 2) suffix = '02' + + return `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/chara-grid/${character.granblue_id}_${suffix}.jpg` + } + + const summonImage = () => { + const summon = object as Summon + const gridSummon = gridObject as GridSummon + + const upgradedSummons = [ + '2040094000', + '2040100000', + '2040080000', + '2040098000', + '2040090000', + '2040084000', + '2040003000', + '2040056000', + ] + + let suffix = '' + if ( + upgradedSummons.indexOf(summon.granblue_id.toString()) != -1 && + gridSummon.uncap_level == 5 + ) { + suffix = '_02' + } else if ( + gridSummon.object.uncap.xlb && + gridSummon.transcendence_step > 0 + ) { + suffix = '_03' + } + + // Generate the correct source for the summon + return `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/summon-grid/${summon.granblue_id}${suffix}.jpg` + } + + const weaponImage = () => { + const gridWeapon = gridObject as GridWeapon + const weapon = object as Weapon + + if (gridWeapon.object.element == 0 && gridWeapon.element) + return `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapon.granblue_id}_${gridWeapon.element}.jpg` + else + return `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapon.granblue_id}.jpg` + } + + const image = () => { + switch (type) { + case 'character': + return characterImage() + case 'summon': + return summonImage() + case 'weapon': + return weaponImage() + } + } + + return ( +
+
+

{object.name[locale]}

+
+ {overlay()} + {object.name[locale]} +
+
+
+
+ + {'proficiency' in object && Array.isArray(object.proficiency) && ( + + )} + {'proficiency' in object && !Array.isArray(object.proficiency) && ( + + )} + {'proficiency' in object && + Array.isArray(object.proficiency) && + object.proficiency.length > 1 && ( + + )} +
+ +
+
+ ) +} + +export default HovercardHeader diff --git a/components/character/CharacterHovercard/index.module.scss b/components/character/CharacterHovercard/index.module.scss index 1f1045dc..e351b017 100644 --- a/components/character/CharacterHovercard/index.module.scss +++ b/components/character/CharacterHovercard/index.module.scss @@ -1,20 +1,5 @@ -.Character.HovercardContent { - .title .Image { - position: relative; - - .Perpetuity { - position: absolute; - background-image: url('/icons/perpetuity/filled.svg'); - background-size: $unit-3x $unit-3x; - z-index: 20; - top: $unit-half * -1; - right: $unit-3x; - width: $unit-3x; - height: $unit-3x; - } - } - - .Mastery { +.content { + .mastery { display: flex; flex-direction: column; gap: $unit; @@ -24,7 +9,7 @@ flex-direction: column; gap: $unit-half; - .ExtendedMastery { + .extendedMastery { align-items: center; display: flex; gap: $unit-half; @@ -40,7 +25,7 @@ } } - .Awakening { + .awakening { display: flex; flex-direction: column; gap: $unit; diff --git a/components/character/CharacterHovercard/index.tsx b/components/character/CharacterHovercard/index.tsx index e0c165a2..52e90630 100644 --- a/components/character/CharacterHovercard/index.tsx +++ b/components/character/CharacterHovercard/index.tsx @@ -19,6 +19,7 @@ import { import { ExtendedMastery } from '~types' import styles from './index.module.scss' +import HovercardHeader from '~components/HovercardHeader' interface Props { gridCharacter: GridCharacter @@ -33,20 +34,6 @@ const CharacterHovercard = (props: Props) => { router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light'] - const Proficiency = [ - 'none', - 'sword', - 'dagger', - 'axe', - 'spear', - 'bow', - 'staff', - 'fist', - 'harp', - 'gun', - 'katana', - ] - const tintElement = Element[props.gridCharacter.object.element] function goTo() { @@ -56,30 +43,6 @@ const CharacterHovercard = (props: Props) => { window.open(url, '_blank') } - const perpetuity = () => { - if (props.gridCharacter && props.gridCharacter.perpetuity) { - return - } - } - - function characterImage() { - let imgSrc = '' - - if (props.gridCharacter) { - const character = props.gridCharacter.object - - // Change the image based on the uncap level - let suffix = '01' - if (props.gridCharacter.uncap_level == 6) suffix = '04' - else if (props.gridCharacter.uncap_level == 5) suffix = '03' - else if (props.gridCharacter.uncap_level > 2) suffix = '02' - - imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/chara-grid/${character.granblue_id}_${suffix}.jpg` - } - - return imgSrc - } - function masteryElement(dictionary: ItemSkill[], mastery: ExtendedMastery) { const canonicalMastery = dictionary.find( (item) => item.id === mastery.modifier @@ -87,7 +50,7 @@ const CharacterHovercard = (props: Props) => { if (canonicalMastery) { return ( -
  • +
  • {canonicalMastery.name[locale]} { const overMasterySection = () => { if (props.gridCharacter && props.gridCharacter.over_mastery) { return ( -
    +
    {t('modals.characters.subtitles.ring')}
    @@ -136,7 +99,7 @@ const CharacterHovercard = (props: Props) => { props.gridCharacter.aetherial_mastery.modifier > 0 ) { return ( -
    +
    {t('modals.characters.subtitles.earring')}
    @@ -154,7 +117,7 @@ const CharacterHovercard = (props: Props) => { const permanentMasterySection = () => { if (props.gridCharacter && props.gridCharacter.perpetuity) { return ( -
    +
    {t('modals.characters.subtitles.permanent')}
    @@ -176,7 +139,7 @@ const CharacterHovercard = (props: Props) => { if (gridAwakening) { return ( -
    +
    {t('modals.characters.subtitles.awakening')}
    @@ -200,7 +163,7 @@ const CharacterHovercard = (props: Props) => { className={tintElement} text={t('buttons.wiki')} onClick={goTo} - contained={true} + bound={true} /> ) @@ -209,51 +172,12 @@ const CharacterHovercard = (props: Props) => { {props.children} - -
    -
    -

    {props.gridCharacter.object.name[locale]}

    -
    - {perpetuity()} - {props.gridCharacter.object.name[locale]} -
    -
    -
    -
    - - - {props.gridCharacter.object.proficiency.proficiency2 ? ( - - ) : ( - '' - )} -
    - -
    -
    + + {wikiButton} {awakeningSection()} {overMasterySection()} diff --git a/components/common/Hovercard/index.module.scss b/components/common/Hovercard/index.module.scss index ca747a45..43a8c6b5 100644 --- a/components/common/Hovercard/index.module.scss +++ b/components/common/Hovercard/index.module.scss @@ -1,12 +1,9 @@ -div[data-radix-popper-content-wrapper] { - z-index: 10 !important; -} - -.HovercardContent { +.hovercard { animation: scaleIn $duration-zoom ease-out; transform-origin: var(--radix-hover-card-content-transform-origin); background: var(--dialog-bg); border-radius: $card-corner; + border: 1px solid rgba(0, 0, 0, 0.1); color: var(--text-primary); display: flex; flex-direction: column; @@ -16,77 +13,47 @@ div[data-radix-popper-content-wrapper] { padding: $unit-2x; width: 300px; - .top { - display: flex; - flex-direction: column; - gap: calc($unit / 2); - - .title { - align-items: center; - display: flex; - flex-direction: row; - gap: $unit * 2; - - h4 { - flex-grow: 1; - font-size: $font-medium; - line-height: 1.2; - min-width: 140px; - } - - img { - height: auto; - width: 100px; - } - } - - .subInfo { - align-items: center; - display: flex; - flex-direction: row; - gap: $unit * 2; - - .icons { - display: flex; - flex-direction: row; - flex-grow: 1; - gap: $unit; - } - - .UncapIndicator { - min-width: 100px; - } - } - } - section { - h5 { - font-size: $font-small; - font-weight: $medium; - opacity: 0.7; - - &.wind { - color: $wind-bg-20; + @keyframes scaleIn { + 0% { + opacity: 0; + transform: scale(0); } - - &.fire { - color: $fire-bg-20; + 20% { + opacity: 0.2; + transform: scale(0.4); } - - &.water { - color: $water-bg-20; + 40% { + opacity: 0.4; + transform: scale(0.8); } - - &.earth { - color: $earth-bg-20; + 60% { + opacity: 0.6; + transform: scale(1); } - - &.dark { - color: $dark-bg-10; + 65% { + opacity: 0.65; + transform: scale(1.1); } - - &.light { - color: $light-bg-20; + 70% { + opacity: 0.7; + transform: scale(1); + } + 75% { + opacity: 0.75; + transform: scale(0.98); + } + 80% { + opacity: 0.8; + transform: scale(1.02); + } + 90% { + opacity: 0.9; + transform: scale(0.96); + } + 100% { + opacity: 1; + transform: scale(1); } } } diff --git a/components/common/Hovercard/index.tsx b/components/common/Hovercard/index.tsx index 0f68e43e..3ccffcfa 100644 --- a/components/common/Hovercard/index.tsx +++ b/components/common/Hovercard/index.tsx @@ -14,7 +14,7 @@ export const HovercardContent = ({ ...props }: PropsWithChildren) => { const classes = classNames(props.className, { - HovercardContent: true, + [styles.hovercard]: true, }) return ( diff --git a/components/summon/SummonHovercard/index.tsx b/components/summon/SummonHovercard/index.tsx index 4476cc7d..8672fc96 100644 --- a/components/summon/SummonHovercard/index.tsx +++ b/components/summon/SummonHovercard/index.tsx @@ -8,8 +8,7 @@ import { HovercardTrigger, } from '~components/common/Hovercard' import Button from '~components/common/Button' -import WeaponLabelIcon from '~components/weapon/WeaponLabelIcon' -import UncapIndicator from '~components/uncap/UncapIndicator' +import HovercardHeader from '~components/HovercardHeader' import styles from './index.module.scss' @@ -79,7 +78,7 @@ const SummonHovercard = (props: Props) => { className={tintElement} text={t('buttons.wiki')} onClick={goTo} - contained={true} + bound={true} /> ) @@ -88,31 +87,12 @@ const SummonHovercard = (props: Props) => { {props.children} - -
    -
    -

    {props.gridSummon.object.name[locale]}

    - {props.gridSummon.object.name[locale]} -
    -
    -
    - -
    - -
    -
    + + {wikiButton} diff --git a/components/weapon/WeaponHovercard/index.module.scss b/components/weapon/WeaponHovercard/index.module.scss index 2dd5ba5a..af652470 100644 --- a/components/weapon/WeaponHovercard/index.module.scss +++ b/components/weapon/WeaponHovercard/index.module.scss @@ -1,34 +1,64 @@ -.Weapon.HovercardContent { +.content { + section { + display: flex; + flex-direction: column; + gap: $unit-half; + } + + .awakening { + display: flex; + flex-direction: column; + gap: $unit-half; + } + + .skill { + align-items: center; + display: flex; + gap: $unit-half; + + img { + width: $unit-4x; + } + + strong { + font-weight: $bold; + } + + &.axSkill .axImageWrapper { + display: flex; + align-items: center; + justify-content: center; + width: $unit-4x; + height: $unit-4x; + } + + &.axSkill.secondary .axImageWrapper { + img { + width: $unit-3x; + height: $unit-3x; + } + } + } + .skills { display: flex; - flex-direction: row; + flex-direction: column; justify-content: space-between; padding-right: $unit-2x; - .axSkill { - align-items: center; - display: flex; - flex-direction: row; + &.secondary { + gap: $unit * 1.5; - &.primary img { - height: 64px; - width: 64px; + img { + height: 24px; + width: 24px; } + } - &.secondary { - gap: $unit * 1.5; - - img { - height: 36px; - width: 36px; - } - } - - span { - font-size: $font-small; - font-weight: $medium; - text-align: center; - } + span { + font-size: $font-small; + font-weight: $medium; + text-align: center; } } @@ -38,24 +68,4 @@ font-size: $normal; gap: $unit-half; } - - .awakening { - display: flex; - flex-direction: column; - gap: $unit-half; - - & > div { - align-items: center; - display: flex; - gap: $unit-half; - - img { - width: $unit-4x; - } - - strong { - font-weight: $bold; - } - } - } } diff --git a/components/weapon/WeaponHovercard/index.tsx b/components/weapon/WeaponHovercard/index.tsx index fa4535c2..3b4f0075 100644 --- a/components/weapon/WeaponHovercard/index.tsx +++ b/components/weapon/WeaponHovercard/index.tsx @@ -1,15 +1,15 @@ import React from 'react' import { useRouter } from 'next/router' import { useTranslation } from 'next-i18next' +import classNames from 'classnames' import { Hovercard, HovercardContent, HovercardTrigger, } from '~components/common/Hovercard' +import HovercardHeader from '~components/HovercardHeader' import Button from '~components/common/Button' -import WeaponLabelIcon from '~components/weapon/WeaponLabelIcon' -import UncapIndicator from '~components/uncap/UncapIndicator' import ax from '~data/ax' @@ -148,11 +148,11 @@ const WeaponHovercard = (props: Props) => { if (gridAwakening) { return ( -
    +
    {t('modals.weapon.subtitles.awakening')}
    -
    +
    {gridAwakening.type.name[locale]} { } const keysSection = ( -
    +
    {WeaponKeyNames[props.gridWeapon.object.series] ? (
    {WeaponKeyNames[props.gridWeapon.object.series][locale]} @@ -182,7 +182,7 @@ const WeaponHovercard = (props: Props) => { ? Array.from(Array(props.gridWeapon.weapon_keys.length)).map((x, i) => { return (
    {props.gridWeapon.weapon_keys![i].name[locale]} @@ -194,29 +194,44 @@ const WeaponHovercard = (props: Props) => { ) const axSection = ( -
    +
    {t('modals.weapon.subtitles.ax_skills')}
    -
    -
    - AX1 +
    +
    +
    + AX1 +
    {createPrimaryAxSkillString()}
    {props.gridWeapon.ax && props.gridWeapon.ax[1].modifier && props.gridWeapon.ax[1].strength ? ( -
    - AX2 +
    +
    + AX2 +
    {createSecondaryAxSkillString()}
    ) : ( @@ -231,7 +246,7 @@ const WeaponHovercard = (props: Props) => { className={tintElement} text={t('buttons.wiki')} onClick={goTo} - contained={true} + bound={true} /> ) @@ -240,44 +255,12 @@ const WeaponHovercard = (props: Props) => { {props.children} - -
    -
    -

    {props.gridWeapon.object.name[locale]}

    - {props.gridWeapon.object.name[locale]} -
    -
    -
    - {props.gridWeapon.object.element !== 0 || - (props.gridWeapon.object.element === 0 && - props.gridWeapon.element != null) ? ( - - ) : ( - '' - )} - -
    - -
    -
    - + + {props.gridWeapon.object.ax && props.gridWeapon.ax && props.gridWeapon.ax[0].modifier &&