Make custom Hovercard component and migrate
This commit is contained in:
parent
e96c3e7fb8
commit
7e7d89b01d
10 changed files with 388 additions and 304 deletions
|
|
@ -2,8 +2,11 @@ import React from 'react'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
|
||||||
import * as HoverCard from '@radix-ui/react-hover-card'
|
import {
|
||||||
|
Hovercard,
|
||||||
|
HovercardContent,
|
||||||
|
HovercardTrigger,
|
||||||
|
} from '~components/Hovercard'
|
||||||
import WeaponLabelIcon from '~components/WeaponLabelIcon'
|
import WeaponLabelIcon from '~components/WeaponLabelIcon'
|
||||||
import UncapIndicator from '~components/UncapIndicator'
|
import UncapIndicator from '~components/UncapIndicator'
|
||||||
|
|
||||||
|
|
@ -12,6 +15,7 @@ import './index.scss'
|
||||||
interface Props {
|
interface Props {
|
||||||
gridCharacter: GridCharacter
|
gridCharacter: GridCharacter
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
|
onTriggerClick: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KeyNames {
|
interface KeyNames {
|
||||||
|
|
@ -67,58 +71,57 @@ const CharacterHovercard = (props: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HoverCard.Root>
|
<Hovercard openDelay={350}>
|
||||||
<HoverCard.Trigger>{props.children}</HoverCard.Trigger>
|
<HovercardTrigger asChild onClick={props.onTriggerClick}>
|
||||||
<HoverCard.Portal>
|
{props.children}
|
||||||
<HoverCard.Content className="Weapon Hovercard">
|
</HovercardTrigger>
|
||||||
<div className="top">
|
<HovercardContent className="Character">
|
||||||
<div className="title">
|
<div className="top">
|
||||||
<h4>{props.gridCharacter.object.name[locale]}</h4>
|
<div className="title">
|
||||||
<img
|
<h4>{props.gridCharacter.object.name[locale]}</h4>
|
||||||
alt={props.gridCharacter.object.name[locale]}
|
<img
|
||||||
src={characterImage()}
|
alt={props.gridCharacter.object.name[locale]}
|
||||||
|
src={characterImage()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="subInfo">
|
||||||
|
<div className="icons">
|
||||||
|
<WeaponLabelIcon
|
||||||
|
labelType={Element[props.gridCharacter.object.element]}
|
||||||
/>
|
/>
|
||||||
</div>
|
<WeaponLabelIcon
|
||||||
<div className="subInfo">
|
labelType={
|
||||||
<div className="icons">
|
Proficiency[
|
||||||
<WeaponLabelIcon
|
props.gridCharacter.object.proficiency.proficiency1
|
||||||
labelType={Element[props.gridCharacter.object.element]}
|
]
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
{props.gridCharacter.object.proficiency.proficiency2 ? (
|
||||||
<WeaponLabelIcon
|
<WeaponLabelIcon
|
||||||
labelType={
|
labelType={
|
||||||
Proficiency[
|
Proficiency[
|
||||||
props.gridCharacter.object.proficiency.proficiency1
|
props.gridCharacter.object.proficiency.proficiency2
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{props.gridCharacter.object.proficiency.proficiency2 ? (
|
) : (
|
||||||
<WeaponLabelIcon
|
''
|
||||||
labelType={
|
)}
|
||||||
Proficiency[
|
|
||||||
props.gridCharacter.object.proficiency.proficiency2
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<UncapIndicator
|
|
||||||
type="character"
|
|
||||||
ulb={props.gridCharacter.object.uncap.ulb || false}
|
|
||||||
flb={props.gridCharacter.object.uncap.flb || false}
|
|
||||||
special={false}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<UncapIndicator
|
||||||
|
type="character"
|
||||||
|
ulb={props.gridCharacter.object.uncap.ulb || false}
|
||||||
|
flb={props.gridCharacter.object.uncap.flb || false}
|
||||||
|
special={false}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a className={`Button ${tintElement}`} href={wikiUrl} target="_new">
|
<a className={`Button ${tintElement}`} href={wikiUrl} target="_new">
|
||||||
{t('buttons.wiki')}
|
{t('buttons.wiki')}
|
||||||
</a>
|
</a>
|
||||||
<HoverCard.Arrow />
|
</HovercardContent>
|
||||||
</HoverCard.Content>
|
</Hovercard>
|
||||||
</HoverCard.Portal>
|
|
||||||
</HoverCard.Root>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ const CharacterUnit = ({
|
||||||
setDetailsModalOpen(true)
|
setDetailsModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
function openSearchModal(event: MouseEvent<HTMLDivElement>) {
|
function openSearchModal() {
|
||||||
if (editable) setSearchModalOpen(true)
|
if (editable) setSearchModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,33 +286,50 @@ const CharacterUnit = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const image = (
|
const image = () => {
|
||||||
<div
|
let image = (
|
||||||
className="CharacterImage"
|
|
||||||
onClick={openSearchModal}
|
|
||||||
tabIndex={gridCharacter ? gridCharacter.position * 7 : 0}
|
|
||||||
>
|
|
||||||
<img
|
<img
|
||||||
alt={character?.name[locale]}
|
alt={character?.name[locale]}
|
||||||
className="grid_image"
|
className="grid_image"
|
||||||
src={imageUrl}
|
src={imageUrl}
|
||||||
/>
|
/>
|
||||||
{editable ? (
|
)
|
||||||
<span className="icon">
|
|
||||||
<PlusIcon />
|
if (gridCharacter) {
|
||||||
</span>
|
image = (
|
||||||
) : (
|
<CharacterHovercard
|
||||||
''
|
gridCharacter={gridCharacter}
|
||||||
)}
|
onTriggerClick={openSearchModal}
|
||||||
</div>
|
>
|
||||||
)
|
{image}
|
||||||
|
</CharacterHovercard>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="CharacterImage"
|
||||||
|
tabIndex={gridCharacter ? gridCharacter.position * 7 : 0}
|
||||||
|
onClick={openSearchModal}
|
||||||
|
>
|
||||||
|
{image}
|
||||||
|
{editable ? (
|
||||||
|
<span className="icon">
|
||||||
|
<PlusIcon />
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const unitContent = (
|
const unitContent = (
|
||||||
<>
|
<>
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
{contextMenu()}
|
{contextMenu()}
|
||||||
{perpetuity()}
|
{perpetuity()}
|
||||||
{image}
|
{image()}
|
||||||
{gridCharacter && character ? (
|
{gridCharacter && character ? (
|
||||||
<UncapIndicator
|
<UncapIndicator
|
||||||
type="character"
|
type="character"
|
||||||
|
|
@ -335,13 +352,7 @@ const CharacterUnit = ({
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
const unitContentWithHovercard = (
|
return unitContent
|
||||||
<CharacterHovercard gridCharacter={gridCharacter!}>
|
|
||||||
{unitContent}
|
|
||||||
</CharacterHovercard>
|
|
||||||
)
|
|
||||||
|
|
||||||
return gridCharacter && !editable ? unitContentWithHovercard : unitContent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CharacterUnit
|
export default CharacterUnit
|
||||||
|
|
|
||||||
93
components/Hovercard/index.scss
Normal file
93
components/Hovercard/index.scss
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
.HovercardContent {
|
||||||
|
animation: scaleIn $duration-zoom ease-out;
|
||||||
|
transform-origin: var(--radix-hover-card-content-transform-origin);
|
||||||
|
background: var(--dialog-bg);
|
||||||
|
border-radius: $card-corner;
|
||||||
|
color: var(--text-primary);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $unit-2x;
|
||||||
|
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 {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
h5 {
|
||||||
|
font-size: $font-small;
|
||||||
|
font-weight: $medium;
|
||||||
|
opacity: 0.7;
|
||||||
|
|
||||||
|
&.wind {
|
||||||
|
color: $wind-bg-20;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.fire {
|
||||||
|
color: $fire-bg-20;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.water {
|
||||||
|
color: $water-bg-20;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.earth {
|
||||||
|
color: $earth-bg-20;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
color: $dark-bg-10;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.light {
|
||||||
|
color: $light-bg-20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Button {
|
||||||
|
display: block;
|
||||||
|
padding: $unit * 1.5;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
31
components/Hovercard/index.tsx
Normal file
31
components/Hovercard/index.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import React, { PropsWithChildren } from 'react'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
|
import * as HoverCardPrimitive from '@radix-ui/react-hover-card'
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
interface Props extends HoverCardPrimitive.HoverCardContentProps {}
|
||||||
|
|
||||||
|
export const Hovercard = HoverCardPrimitive.Root
|
||||||
|
export const HovercardTrigger = HoverCardPrimitive.Trigger
|
||||||
|
|
||||||
|
export const HovercardContent = ({
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: PropsWithChildren<Props>) => {
|
||||||
|
const classes = classNames(props.className, {
|
||||||
|
HovercardContent: true,
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
<HoverCardPrimitive.Portal>
|
||||||
|
<HoverCardPrimitive.Content
|
||||||
|
{...props}
|
||||||
|
className={classes}
|
||||||
|
sideOffset={4}
|
||||||
|
collisionPadding={{ top: 16, left: 16, right: 16, bottom: 16 }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</HoverCardPrimitive.Content>
|
||||||
|
</HoverCardPrimitive.Portal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -2,8 +2,11 @@ import React from 'react'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
|
||||||
import * as HoverCard from '@radix-ui/react-hover-card'
|
import {
|
||||||
|
Hovercard,
|
||||||
|
HovercardContent,
|
||||||
|
HovercardTrigger,
|
||||||
|
} from '~components/Hovercard'
|
||||||
import WeaponLabelIcon from '~components/WeaponLabelIcon'
|
import WeaponLabelIcon from '~components/WeaponLabelIcon'
|
||||||
import UncapIndicator from '~components/UncapIndicator'
|
import UncapIndicator from '~components/UncapIndicator'
|
||||||
|
|
||||||
|
|
@ -12,6 +15,7 @@ import './index.scss'
|
||||||
interface Props {
|
interface Props {
|
||||||
gridSummon: GridSummon
|
gridSummon: GridSummon
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
|
onTriggerClick: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const SummonHovercard = (props: Props) => {
|
const SummonHovercard = (props: Props) => {
|
||||||
|
|
@ -60,39 +64,38 @@ const SummonHovercard = (props: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HoverCard.Root>
|
<Hovercard openDelay={350}>
|
||||||
<HoverCard.Trigger>{props.children}</HoverCard.Trigger>
|
<HovercardTrigger asChild onClick={props.onTriggerClick}>
|
||||||
<HoverCard.Portal>
|
{props.children}
|
||||||
<HoverCard.Content className="Weapon Hovercard">
|
</HovercardTrigger>
|
||||||
<div className="top">
|
<HovercardContent className="Summon">
|
||||||
<div className="title">
|
<div className="top">
|
||||||
<h4>{props.gridSummon.object.name[locale]}</h4>
|
<div className="title">
|
||||||
<img
|
<h4>{props.gridSummon.object.name[locale]}</h4>
|
||||||
alt={props.gridSummon.object.name[locale]}
|
<img
|
||||||
src={summonImage()}
|
alt={props.gridSummon.object.name[locale]}
|
||||||
/>
|
src={summonImage()}
|
||||||
</div>
|
/>
|
||||||
<div className="subInfo">
|
|
||||||
<div className="icons">
|
|
||||||
<WeaponLabelIcon
|
|
||||||
labelType={Element[props.gridSummon.object.element]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<UncapIndicator
|
|
||||||
type="summon"
|
|
||||||
ulb={props.gridSummon.object.uncap.ulb || false}
|
|
||||||
flb={props.gridSummon.object.uncap.flb || false}
|
|
||||||
special={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<a className={`Button ${tintElement}`} href={wikiUrl} target="_new">
|
<div className="subInfo">
|
||||||
{t('buttons.wiki')}
|
<div className="icons">
|
||||||
</a>
|
<WeaponLabelIcon
|
||||||
<HoverCard.Arrow />
|
labelType={Element[props.gridSummon.object.element]}
|
||||||
</HoverCard.Content>
|
/>
|
||||||
</HoverCard.Portal>
|
</div>
|
||||||
</HoverCard.Root>
|
<UncapIndicator
|
||||||
|
type="summon"
|
||||||
|
ulb={props.gridSummon.object.uncap.ulb || false}
|
||||||
|
flb={props.gridSummon.object.uncap.flb || false}
|
||||||
|
special={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a className={`Button ${tintElement}`} href={wikiUrl} target="_new">
|
||||||
|
{t('buttons.wiki')}
|
||||||
|
</a>
|
||||||
|
</HovercardContent>
|
||||||
|
</Hovercard>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ const SummonUnit = ({
|
||||||
})
|
})
|
||||||
|
|
||||||
// Methods: Open layer
|
// Methods: Open layer
|
||||||
function openSearchModal(event: MouseEvent<HTMLDivElement>) {
|
function openSearchModal() {
|
||||||
if (editable) setSearchModalOpen(true)
|
if (editable) setSearchModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,8 +223,8 @@ const SummonUnit = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods: Core element rendering
|
// Methods: Core element rendering
|
||||||
const image = (
|
const image = () => {
|
||||||
<div className="SummonImage" onClick={openSearchModal}>
|
let image = (
|
||||||
<img
|
<img
|
||||||
alt={summon?.name[locale]}
|
alt={summon?.name[locale]}
|
||||||
className={classNames({
|
className={classNames({
|
||||||
|
|
@ -233,21 +233,38 @@ const SummonUnit = ({
|
||||||
})}
|
})}
|
||||||
src={imageUrl !== '' ? imageUrl : placeholderImageUrl()}
|
src={imageUrl !== '' ? imageUrl : placeholderImageUrl()}
|
||||||
/>
|
/>
|
||||||
{editable ? (
|
)
|
||||||
<span className="icon">
|
|
||||||
<PlusIcon />
|
if (gridSummon) {
|
||||||
</span>
|
image = (
|
||||||
) : (
|
<SummonHovercard
|
||||||
''
|
gridSummon={gridSummon}
|
||||||
)}
|
onTriggerClick={openSearchModal}
|
||||||
</div>
|
>
|
||||||
)
|
{image}
|
||||||
|
</SummonHovercard>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="SummonImage" onClick={openSearchModal}>
|
||||||
|
{image}
|
||||||
|
{editable ? (
|
||||||
|
<span className="icon">
|
||||||
|
<PlusIcon />
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const unitContent = (
|
const unitContent = (
|
||||||
<>
|
<>
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
{contextMenu()}
|
{contextMenu()}
|
||||||
{image}
|
{image()}
|
||||||
{gridSummon ? (
|
{gridSummon ? (
|
||||||
<UncapIndicator
|
<UncapIndicator
|
||||||
type="summon"
|
type="summon"
|
||||||
|
|
@ -271,11 +288,7 @@ const SummonUnit = ({
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
const unitContentWithHovercard = (
|
return unitContent
|
||||||
<SummonHovercard gridSummon={gridSummon!}>{unitContent}</SummonHovercard>
|
|
||||||
)
|
|
||||||
|
|
||||||
return gridSummon && !editable ? unitContentWithHovercard : unitContent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SummonUnit
|
export default SummonUnit
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
.Weapon.Hovercard {
|
.Weapon.HovercardContent {
|
||||||
.skills {
|
.skills {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@ import React from 'react'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
|
||||||
import * as HoverCard from '@radix-ui/react-hover-card'
|
import {
|
||||||
|
Hovercard,
|
||||||
|
HovercardContent,
|
||||||
|
HovercardTrigger,
|
||||||
|
} from '~components/Hovercard'
|
||||||
import WeaponLabelIcon from '~components/WeaponLabelIcon'
|
import WeaponLabelIcon from '~components/WeaponLabelIcon'
|
||||||
import UncapIndicator from '~components/UncapIndicator'
|
import UncapIndicator from '~components/UncapIndicator'
|
||||||
|
|
||||||
|
|
@ -14,6 +17,7 @@ import './index.scss'
|
||||||
interface Props {
|
interface Props {
|
||||||
gridWeapon: GridWeapon
|
gridWeapon: GridWeapon
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
|
onTriggerClick: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KeyNames {
|
interface KeyNames {
|
||||||
|
|
@ -26,10 +30,11 @@ interface KeyNames {
|
||||||
|
|
||||||
const WeaponHovercard = (props: Props) => {
|
const WeaponHovercard = (props: Props) => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { t } = useTranslation('common')
|
|
||||||
const locale =
|
const locale =
|
||||||
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
|
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
|
||||||
|
|
||||||
|
const { t } = useTranslation('common')
|
||||||
|
|
||||||
const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light']
|
const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light']
|
||||||
const Proficiency = [
|
const Proficiency = [
|
||||||
'none',
|
'none',
|
||||||
|
|
@ -67,6 +72,7 @@ const WeaponHovercard = (props: Props) => {
|
||||||
props.gridWeapon.object.element == 0 && props.gridWeapon.element
|
props.gridWeapon.object.element == 0 && props.gridWeapon.element
|
||||||
? Element[props.gridWeapon.element]
|
? Element[props.gridWeapon.element]
|
||||||
: Element[props.gridWeapon.object.element]
|
: Element[props.gridWeapon.object.element]
|
||||||
|
|
||||||
const wikiUrl = `https://gbf.wiki/${props.gridWeapon.object.name.en.replaceAll(
|
const wikiUrl = `https://gbf.wiki/${props.gridWeapon.object.name.en.replaceAll(
|
||||||
' ',
|
' ',
|
||||||
'_'
|
'_'
|
||||||
|
|
@ -189,64 +195,62 @@ const WeaponHovercard = (props: Props) => {
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HoverCard.Root>
|
<Hovercard openDelay={350}>
|
||||||
<HoverCard.Trigger>{props.children}</HoverCard.Trigger>
|
<HovercardTrigger asChild onClick={props.onTriggerClick}>
|
||||||
<HoverCard.Portal>
|
{props.children}
|
||||||
<HoverCard.Content className="Weapon Hovercard" side={hovercardSide()}>
|
</HovercardTrigger>
|
||||||
<div className="top">
|
<HovercardContent className="Weapon" side={hovercardSide()}>
|
||||||
<div className="title">
|
<div className="top">
|
||||||
<h4>{props.gridWeapon.object.name[locale]}</h4>
|
<div className="title">
|
||||||
<img
|
<h4>{props.gridWeapon.object.name[locale]}</h4>
|
||||||
alt={props.gridWeapon.object.name[locale]}
|
<img
|
||||||
src={weaponImage()}
|
alt={props.gridWeapon.object.name[locale]}
|
||||||
/>
|
src={weaponImage()}
|
||||||
</div>
|
/>
|
||||||
<div className="subInfo">
|
|
||||||
<div className="icons">
|
|
||||||
{props.gridWeapon.object.element !== 0 ||
|
|
||||||
(props.gridWeapon.object.element === 0 &&
|
|
||||||
props.gridWeapon.element != null) ? (
|
|
||||||
<WeaponLabelIcon
|
|
||||||
labelType={
|
|
||||||
props.gridWeapon.object.element === 0 &&
|
|
||||||
props.gridWeapon.element !== 0
|
|
||||||
? Element[props.gridWeapon.element]
|
|
||||||
: Element[props.gridWeapon.object.element]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
<WeaponLabelIcon
|
|
||||||
labelType={Proficiency[props.gridWeapon.object.proficiency]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<UncapIndicator
|
|
||||||
type="weapon"
|
|
||||||
ulb={props.gridWeapon.object.uncap.ulb || false}
|
|
||||||
flb={props.gridWeapon.object.uncap.flb || false}
|
|
||||||
special={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="subInfo">
|
||||||
|
<div className="icons">
|
||||||
|
{props.gridWeapon.object.element !== 0 ||
|
||||||
|
(props.gridWeapon.object.element === 0 &&
|
||||||
|
props.gridWeapon.element != null) ? (
|
||||||
|
<WeaponLabelIcon
|
||||||
|
labelType={
|
||||||
|
props.gridWeapon.object.element === 0 &&
|
||||||
|
props.gridWeapon.element !== 0
|
||||||
|
? Element[props.gridWeapon.element]
|
||||||
|
: Element[props.gridWeapon.object.element]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
<WeaponLabelIcon
|
||||||
|
labelType={Proficiency[props.gridWeapon.object.proficiency]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<UncapIndicator
|
||||||
|
type="weapon"
|
||||||
|
ulb={props.gridWeapon.object.uncap.ulb || false}
|
||||||
|
flb={props.gridWeapon.object.uncap.flb || false}
|
||||||
|
special={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{props.gridWeapon.object.ax &&
|
{props.gridWeapon.object.ax &&
|
||||||
props.gridWeapon.ax &&
|
props.gridWeapon.ax &&
|
||||||
props.gridWeapon.ax[0].modifier &&
|
props.gridWeapon.ax[0].modifier &&
|
||||||
props.gridWeapon.ax[0].strength
|
props.gridWeapon.ax[0].strength
|
||||||
? axSection
|
? axSection
|
||||||
: ''}
|
: ''}
|
||||||
{props.gridWeapon.weapon_keys &&
|
{props.gridWeapon.weapon_keys && props.gridWeapon.weapon_keys.length > 0
|
||||||
props.gridWeapon.weapon_keys.length > 0
|
? keysSection
|
||||||
? keysSection
|
: ''}
|
||||||
: ''}
|
<a className={`Button ${tintElement}`} href={wikiUrl} target="_new">
|
||||||
<a className={`Button ${tintElement}`} href={wikiUrl} target="_new">
|
{t('buttons.wiki')}
|
||||||
{t('buttons.wiki')}
|
</a>
|
||||||
</a>
|
</HovercardContent>
|
||||||
<HoverCard.Arrow />
|
</Hovercard>
|
||||||
</HoverCard.Content>
|
|
||||||
</HoverCard.Portal>
|
|
||||||
</HoverCard.Root>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ const WeaponUnit = ({
|
||||||
setDetailsModalOpen(true)
|
setDetailsModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
function openSearchModal(event: MouseEvent<HTMLDivElement>) {
|
function openSearchModal() {
|
||||||
if (editable) setSearchModalOpen(true)
|
if (editable) setSearchModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -509,17 +509,8 @@ const WeaponUnit = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods: Core element rendering
|
// Methods: Core element rendering
|
||||||
const image = (
|
const image = () => {
|
||||||
<div className="WeaponImage" onClick={openSearchModal}>
|
const image = (
|
||||||
<div className="Modifiers">
|
|
||||||
{awakeningImage()}
|
|
||||||
<div className="Skills">
|
|
||||||
{axImages()}
|
|
||||||
{telumaImages()}
|
|
||||||
{opusImages()}
|
|
||||||
{ultimaImages()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<img
|
<img
|
||||||
alt={weapon?.name[locale]}
|
alt={weapon?.name[locale]}
|
||||||
className={classNames({
|
className={classNames({
|
||||||
|
|
@ -528,21 +519,44 @@ const WeaponUnit = ({
|
||||||
})}
|
})}
|
||||||
src={imageUrl !== '' ? imageUrl : placeholderImageUrl()}
|
src={imageUrl !== '' ? imageUrl : placeholderImageUrl()}
|
||||||
/>
|
/>
|
||||||
{editable ? (
|
)
|
||||||
<span className="icon">
|
|
||||||
<PlusIcon />
|
const content = (
|
||||||
</span>
|
<div className="WeaponImage" onClick={openSearchModal}>
|
||||||
) : (
|
<div className="Modifiers">
|
||||||
''
|
{awakeningImage()}
|
||||||
)}
|
<div className="Skills">
|
||||||
</div>
|
{axImages()}
|
||||||
)
|
{telumaImages()}
|
||||||
|
{opusImages()}
|
||||||
|
{ultimaImages()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{image}
|
||||||
|
{editable ? (
|
||||||
|
<span className="icon">
|
||||||
|
<PlusIcon />
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
return gridWeapon ? (
|
||||||
|
<WeaponHovercard gridWeapon={gridWeapon} onTriggerClick={openSearchModal}>
|
||||||
|
{content}
|
||||||
|
</WeaponHovercard>
|
||||||
|
) : (
|
||||||
|
content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const unitContent = (
|
const unitContent = (
|
||||||
<>
|
<>
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
{contextMenu()}
|
{contextMenu()}
|
||||||
{image}
|
{image()}
|
||||||
{gridWeapon && weapon ? (
|
{gridWeapon && weapon ? (
|
||||||
<UncapIndicator
|
<UncapIndicator
|
||||||
type="weapon"
|
type="weapon"
|
||||||
|
|
@ -562,11 +576,7 @@ const WeaponUnit = ({
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
const unitContentWithHovercard = (
|
return unitContent
|
||||||
<WeaponHovercard gridWeapon={gridWeapon!}>{unitContent}</WeaponHovercard>
|
|
||||||
)
|
|
||||||
|
|
||||||
return gridWeapon && !editable ? unitContentWithHovercard : unitContent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WeaponUnit
|
export default WeaponUnit
|
||||||
|
|
|
||||||
|
|
@ -200,98 +200,6 @@ select {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.Hovercard {
|
|
||||||
background: #222;
|
|
||||||
border-radius: $unit;
|
|
||||||
color: $grey-100;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: $unit * 2;
|
|
||||||
padding: $unit * 2;
|
|
||||||
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 {
|
|
||||||
width: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
section {
|
|
||||||
h5 {
|
|
||||||
font-size: $font-small;
|
|
||||||
font-weight: $medium;
|
|
||||||
opacity: 0.7;
|
|
||||||
|
|
||||||
&.wind {
|
|
||||||
color: $wind-bg-20;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fire {
|
|
||||||
color: $fire-bg-20;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.water {
|
|
||||||
color: $water-bg-20;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.earth {
|
|
||||||
color: $earth-bg-20;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.dark {
|
|
||||||
color: $dark-bg-10;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.light {
|
|
||||||
color: $light-bg-20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a.Button {
|
|
||||||
display: block;
|
|
||||||
padding: $unit * 1.5;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Teams,
|
#Teams,
|
||||||
#Profile {
|
#Profile {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -447,17 +355,25 @@ i.tag {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
}
|
}
|
||||||
70% {
|
65% {
|
||||||
opacity: 0.8;
|
opacity: 0.65;
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
}
|
}
|
||||||
|
70% {
|
||||||
|
opacity: 0.7;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
opacity: 0.75;
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
80% {
|
80% {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
transform: scale(1);
|
transform: scale(1.02);
|
||||||
}
|
}
|
||||||
90% {
|
90% {
|
||||||
opacity: 0.8;
|
opacity: 0.9;
|
||||||
transform: scale(0.95);
|
transform: scale(0.96);
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue