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 (
+
+ )
+}
+
+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 (
-
+
{
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]}]({characterImage()})
-
-
-
-
-
-
- {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]}]({summonImage()})
-
-
-
+
+
{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]}]({`${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/awakening/${gridAwakening.type.slug}.png`})
{
}
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')}
-
-
-

+
+
+
+

+
{createPrimaryAxSkillString()}
{props.gridWeapon.ax &&
props.gridWeapon.ax[1].modifier &&
props.gridWeapon.ax[1].strength ? (
-
-

+
+
+

+
{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]}]({weaponImage()})
-
-
-
- {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 &&