Fix shadows for static and mod modals
This commit is contained in:
parent
c9315ab397
commit
7ad9032e86
12 changed files with 139 additions and 75 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
gap: 0;
|
gap: 0;
|
||||||
padding-bottom: $unit;
|
padding-bottom: $unit;
|
||||||
|
|
||||||
& > div:not(.DialogHeader) {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $unit-2x;
|
gap: $unit-2x;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import './index.scss'
|
||||||
|
|
||||||
const AboutModal = () => {
|
const AboutModal = () => {
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
|
const headerRef = React.createRef<HTMLDivElement>()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog>
|
<Dialog>
|
||||||
|
|
@ -29,11 +30,20 @@ const AboutModal = () => {
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
className="About"
|
className="About"
|
||||||
title={t('menu.about')}
|
headerref={headerRef}
|
||||||
onOpenAutoFocus={(event) => event.preventDefault()}
|
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||||
onEscapeKeyDown={() => {}}
|
onEscapeKeyDown={() => {}}
|
||||||
>
|
>
|
||||||
<div className="sections">
|
<div className="DialogHeader" ref={headerRef}>
|
||||||
|
<DialogTitle className="DialogTitle">{t('menu.about')}</DialogTitle>
|
||||||
|
<DialogClose className="DialogClose" asChild>
|
||||||
|
<span>
|
||||||
|
<CrossIcon />
|
||||||
|
</span>
|
||||||
|
</DialogClose>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="content">
|
||||||
<section>
|
<section>
|
||||||
<p>
|
<p>
|
||||||
Granblue.team is a tool to save and share team comps for{' '}
|
Granblue.team is a tool to save and share team comps for{' '}
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,9 @@ const AccountModal = (props: Props) => {
|
||||||
const [languageOpen, setLanguageOpen] = useState(false)
|
const [languageOpen, setLanguageOpen] = useState(false)
|
||||||
const [themeOpen, setThemeOpen] = useState(false)
|
const [themeOpen, setThemeOpen] = useState(false)
|
||||||
|
|
||||||
|
// Refs
|
||||||
|
const headerRef = React.createRef<HTMLDivElement>()
|
||||||
|
|
||||||
// UI management
|
// UI management
|
||||||
function openChange(open: boolean) {
|
function openChange(open: boolean) {
|
||||||
setOpen(open)
|
setOpen(open)
|
||||||
|
|
@ -286,10 +289,11 @@ const AccountModal = (props: Props) => {
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
className="Account"
|
className="Account"
|
||||||
|
headerref={headerRef}
|
||||||
onOpenAutoFocus={(event: Event) => {}}
|
onOpenAutoFocus={(event: Event) => {}}
|
||||||
onEscapeKeyDown={onEscapeKeyDown}
|
onEscapeKeyDown={onEscapeKeyDown}
|
||||||
>
|
>
|
||||||
<div className="DialogHeader">
|
<div className="DialogHeader" ref={headerRef}>
|
||||||
<div className="DialogTop">
|
<div className="DialogTop">
|
||||||
<DialogTitle className="SubTitle">
|
<DialogTitle className="SubTitle">
|
||||||
{t('modals.settings.title')}
|
{t('modals.settings.title')}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
.Changelog.DialogContent {
|
.Changelog.DialogContent {
|
||||||
gap: 0;
|
gap: 0;
|
||||||
|
|
||||||
& > div:not(.DialogHeader) {
|
.updates {
|
||||||
padding: 0 $unit-4x;
|
padding: 0 $unit-4x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import './index.scss'
|
||||||
|
|
||||||
const ChangelogModal = () => {
|
const ChangelogModal = () => {
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
|
const headerRef = React.createRef<HTMLDivElement>()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog>
|
<Dialog>
|
||||||
|
|
@ -27,9 +28,21 @@ const ChangelogModal = () => {
|
||||||
<DialogContent
|
<DialogContent
|
||||||
className="Changelog"
|
className="Changelog"
|
||||||
title={t('menu.changelog')}
|
title={t('menu.changelog')}
|
||||||
|
headerref={headerRef}
|
||||||
onOpenAutoFocus={(event) => event.preventDefault()}
|
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||||
onEscapeKeyDown={() => {}}
|
onEscapeKeyDown={() => {}}
|
||||||
>
|
>
|
||||||
|
<div className="DialogHeader" ref={headerRef}>
|
||||||
|
<DialogTitle className="DialogTitle">
|
||||||
|
{t('menu.changelog')}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogClose className="DialogClose" asChild>
|
||||||
|
<span>
|
||||||
|
<CrossIcon />
|
||||||
|
</span>
|
||||||
|
</DialogClose>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="updates">
|
<div className="updates">
|
||||||
<section className="version" data-version="1.0">
|
<section className="version" data-version="1.0">
|
||||||
<div className="top">
|
<div className="top">
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $unit-4x;
|
gap: $unit-4x;
|
||||||
padding: 0 $unit-4x;
|
padding: 0 $unit-4x $unit-2x;
|
||||||
|
|
||||||
section {
|
section {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -81,45 +81,23 @@ const CharacterModal = ({
|
||||||
|
|
||||||
// UI state
|
// UI state
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const [scrolled, setScrolled] = useState(false)
|
|
||||||
const [formValid, setFormValid] = useState(false)
|
const [formValid, setFormValid] = useState(false)
|
||||||
|
|
||||||
|
// Refs
|
||||||
|
const headerRef = React.createRef<HTMLDivElement>()
|
||||||
|
const footerRef = React.createRef<HTMLDivElement>()
|
||||||
|
|
||||||
// Classes
|
// Classes
|
||||||
const headerClasses = classNames({
|
const headerClasses = classNames({
|
||||||
DialogHeader: true,
|
DialogHeader: true,
|
||||||
Short: true,
|
Short: true,
|
||||||
Scrolled: scrolled,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Callbacks and Hooks
|
// Callbacks and Hooks
|
||||||
const onScroll = useCallback((event: Event) => {
|
|
||||||
// const dialogContent = event.target as HTMLDivElement
|
|
||||||
// const { scrollTop } = dialogContent
|
|
||||||
// if (scrollTop > 150) {
|
|
||||||
// console.log(scrollTop, scrollTop % 5)
|
|
||||||
// if (scrollTop > 20) setScrolled(true)
|
|
||||||
// else setScrolled(false)
|
|
||||||
// console.log('scrollTop', scrollTop)
|
|
||||||
// }
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setOpen(modalOpen)
|
setOpen(modalOpen)
|
||||||
}, [modalOpen])
|
}, [modalOpen])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
//add eventlistener to window
|
|
||||||
// const dialogContent = document.querySelector('.DialogContent')
|
|
||||||
// if (dialogContent) {
|
|
||||||
// dialogContent.addEventListener('scroll', onScroll, { passive: true })
|
|
||||||
// // remove event on unmount to prevent a memory leak with the cleanup
|
|
||||||
// return () => {
|
|
||||||
// // what does passive do?
|
|
||||||
// dialogContent.removeEventListener('scroll', onScroll)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
// Character properties: Perpetuity
|
// Character properties: Perpetuity
|
||||||
const [perpetuity, setPerpetuity] = useState(false)
|
const [perpetuity, setPerpetuity] = useState(false)
|
||||||
|
|
||||||
|
|
@ -309,10 +287,12 @@ const CharacterModal = ({
|
||||||
<DialogTrigger asChild>{children}</DialogTrigger>
|
<DialogTrigger asChild>{children}</DialogTrigger>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
className="Character"
|
className="Character"
|
||||||
|
headerref={headerRef}
|
||||||
|
footerref={footerRef}
|
||||||
onOpenAutoFocus={(event) => event.preventDefault()}
|
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||||
onEscapeKeyDown={() => {}}
|
onEscapeKeyDown={() => {}}
|
||||||
>
|
>
|
||||||
<div className={headerClasses}>
|
<div className={headerClasses} ref={headerRef}>
|
||||||
<img
|
<img
|
||||||
alt={gridCharacter.object.name[locale]}
|
alt={gridCharacter.object.name[locale]}
|
||||||
className="DialogImage"
|
className="DialogImage"
|
||||||
|
|
@ -339,7 +319,7 @@ const CharacterModal = ({
|
||||||
{earringSelect()}
|
{earringSelect()}
|
||||||
{awakeningSelect()}
|
{awakeningSelect()}
|
||||||
</div>
|
</div>
|
||||||
<div className="DialogFooter">
|
<div className="DialogFooter" ref={footerRef}>
|
||||||
<Button
|
<Button
|
||||||
contained={true}
|
contained={true}
|
||||||
onClick={updateCharacter}
|
onClick={updateCharacter}
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,8 @@
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
background: var(--dialog-bg);
|
background: var(--dialog-bg);
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.16);
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.24);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: ($unit * 1.5) ($unit * $multiplier) $unit-3x;
|
padding: ($unit * 1.5) ($unit * $multiplier) $unit-3x;
|
||||||
|
|
@ -204,7 +206,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $unit * 2;
|
gap: $unit-2x;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,17 @@ import React, { useEffect } from 'react'
|
||||||
import * as DialogPrimitive from '@radix-ui/react-dialog'
|
import * as DialogPrimitive from '@radix-ui/react-dialog'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import { DialogClose, DialogTitle } from '~components/Dialog'
|
|
||||||
import Overlay from '~components/Overlay'
|
import Overlay from '~components/Overlay'
|
||||||
|
|
||||||
import CrossIcon from '~public/icons/Cross.svg'
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
import debounce from 'lodash.debounce'
|
||||||
|
|
||||||
interface Props
|
interface Props
|
||||||
extends React.DetailedHTMLProps<
|
extends React.DetailedHTMLProps<
|
||||||
React.DialogHTMLAttributes<HTMLDivElement>,
|
React.DialogHTMLAttributes<HTMLDivElement>,
|
||||||
HTMLDivElement
|
HTMLDivElement
|
||||||
> {
|
> {
|
||||||
header?: React.ReactNode
|
headerref: React.RefObject<HTMLDivElement>
|
||||||
title?: string
|
footerref?: React.RefObject<HTMLDivElement>
|
||||||
onEscapeKeyDown: (event: KeyboardEvent) => void
|
onEscapeKeyDown: (event: KeyboardEvent) => void
|
||||||
onOpenAutoFocus: (event: Event) => void
|
onOpenAutoFocus: (event: Event) => void
|
||||||
}
|
}
|
||||||
|
|
@ -28,45 +26,91 @@ const DialogContent = React.forwardRef<HTMLDivElement, Props>(function dialog(
|
||||||
DialogContent: true,
|
DialogContent: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Refs
|
|
||||||
const headerRef = React.createRef<HTMLDivElement>()
|
|
||||||
const containerRef = React.createRef<HTMLDivElement>()
|
|
||||||
|
|
||||||
// Elements
|
|
||||||
const genericHeader = (
|
|
||||||
<div className="DialogHeader" ref={headerRef}>
|
|
||||||
<DialogTitle className="DialogTitle">
|
|
||||||
{props.title ? props.title : ''}
|
|
||||||
</DialogTitle>
|
|
||||||
<DialogClose className="DialogClose" asChild>
|
|
||||||
<span>
|
|
||||||
<CrossIcon />
|
|
||||||
</span>
|
|
||||||
</DialogClose>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
// Handlers
|
// Handlers
|
||||||
function handleScroll(event: React.UIEvent<HTMLDivElement, UIEvent>) {
|
function handleScroll(event: React.UIEvent<HTMLDivElement, UIEvent>) {
|
||||||
const headerElement = headerRef.current
|
const scrollTop = event.currentTarget.scrollTop
|
||||||
const scrollTop = event.currentTarget?.scrollTop
|
const scrollHeight = event.currentTarget.scrollHeight
|
||||||
|
const clientHeight = event.currentTarget.clientHeight
|
||||||
|
|
||||||
|
if (props.headerref && props.headerref.current)
|
||||||
|
manipulateHeaderShadow(props.headerref.current, scrollTop)
|
||||||
|
|
||||||
|
if (props.footerref && props.footerref.current)
|
||||||
|
manipulateFooterShadow(
|
||||||
|
props.footerref.current,
|
||||||
|
scrollTop,
|
||||||
|
scrollHeight,
|
||||||
|
clientHeight
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function manipulateHeaderShadow(header: HTMLDivElement, scrollTop: number) {
|
||||||
const boxShadowBase = '0 2px 8px'
|
const boxShadowBase = '0 2px 8px'
|
||||||
const maxValue = 50
|
const maxValue = 50
|
||||||
|
|
||||||
if (headerElement && scrollTop >= 0) {
|
if (scrollTop >= 0) {
|
||||||
const input = scrollTop > maxValue ? maxValue : scrollTop
|
const input = scrollTop > maxValue ? maxValue : scrollTop
|
||||||
|
|
||||||
const boxShadowOpacity = mapRange(input, 0, maxValue, 0.0, 0.16)
|
const boxShadowOpacity = mapRange(input, 0, maxValue, 0.0, 0.16)
|
||||||
const borderOpacity = mapRange(input, 0, maxValue, 0.0, 0.24)
|
const borderOpacity = mapRange(input, 0, maxValue, 0.0, 0.24)
|
||||||
console.log(
|
|
||||||
`Scroll top: ${scrollTop}, interpolated opacity: ${boxShadowOpacity}`
|
|
||||||
)
|
|
||||||
|
|
||||||
headerElement.style.boxShadow = `${boxShadowBase} rgba(0, 0, 0, ${boxShadowOpacity})`
|
header.style.boxShadow = `${boxShadowBase} rgba(0, 0, 0, ${boxShadowOpacity})`
|
||||||
headerElement.style.borderBottomColor = `rgba(0, 0, 0, ${borderOpacity})`
|
header.style.borderBottomColor = `rgba(0, 0, 0, ${borderOpacity})`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function manipulateFooterShadow(
|
||||||
|
footer: HTMLDivElement,
|
||||||
|
scrollTop: number,
|
||||||
|
scrollHeight: number,
|
||||||
|
clientHeight: number
|
||||||
|
) {
|
||||||
|
const boxShadowBase = '0 -2px 8px'
|
||||||
|
const minValue = scrollHeight - 200
|
||||||
|
const currentScroll = scrollTop + clientHeight
|
||||||
|
|
||||||
|
if (currentScroll >= minValue) {
|
||||||
|
const input = currentScroll < minValue ? minValue : currentScroll
|
||||||
|
|
||||||
|
const boxShadowOpacity = mapRange(
|
||||||
|
input,
|
||||||
|
minValue,
|
||||||
|
scrollHeight,
|
||||||
|
0.16,
|
||||||
|
0.0
|
||||||
|
)
|
||||||
|
const borderOpacity = mapRange(input, minValue, scrollHeight, 0.24, 0.0)
|
||||||
|
|
||||||
|
footer.style.boxShadow = `${boxShadowBase} rgba(0, 0, 0, ${boxShadowOpacity})`
|
||||||
|
footer.style.borderTopColor = `rgba(0, 0, 0, ${borderOpacity})`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const calculateFooterShadow = debounce(() => {
|
||||||
|
const boxShadowBase = '0 -2px 8px'
|
||||||
|
const scrollable = document.querySelector('.Scrollable')
|
||||||
|
const footer = props.footerref
|
||||||
|
|
||||||
|
if (footer && footer.current) {
|
||||||
|
if (scrollable && scrollable.clientHeight >= scrollable.scrollHeight) {
|
||||||
|
footer.current.style.boxShadow = `${boxShadowBase} rgba(0, 0, 0, 0)`
|
||||||
|
footer.current.style.borderTopColor = `rgba(0, 0, 0, 0)`
|
||||||
|
} else {
|
||||||
|
footer.current.style.boxShadow = `${boxShadowBase} rgba(0, 0, 0, 0.16)`
|
||||||
|
footer.current.style.borderTopColor = `rgba(0, 0, 0, 0.24)`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener('resize', calculateFooterShadow)
|
||||||
|
calculateFooterShadow()
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', calculateFooterShadow)
|
||||||
|
}
|
||||||
|
}, [calculateFooterShadow])
|
||||||
|
|
||||||
function mapRange(
|
function mapRange(
|
||||||
value: number,
|
value: number,
|
||||||
low1: number,
|
low1: number,
|
||||||
|
|
@ -87,12 +131,7 @@ const DialogContent = React.forwardRef<HTMLDivElement, Props>(function dialog(
|
||||||
onEscapeKeyDown={props.onEscapeKeyDown}
|
onEscapeKeyDown={props.onEscapeKeyDown}
|
||||||
ref={forwardedRef}
|
ref={forwardedRef}
|
||||||
>
|
>
|
||||||
{props.title ? genericHeader : ''}
|
<div className="Scrollable" onScroll={handleScroll}>
|
||||||
<div
|
|
||||||
className="Scrollable"
|
|
||||||
ref={containerRef}
|
|
||||||
onScroll={handleScroll}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</DialogPrimitive.Content>
|
</DialogPrimitive.Content>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& > div:not(.DialogHeader) {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $unit-2x;
|
gap: $unit-2x;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import './index.scss'
|
||||||
|
|
||||||
const RoadmapModal = () => {
|
const RoadmapModal = () => {
|
||||||
const { t } = useTranslation('roadmap')
|
const { t } = useTranslation('roadmap')
|
||||||
|
const headerRef = React.createRef<HTMLDivElement>()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog>
|
<Dialog>
|
||||||
|
|
@ -28,10 +29,20 @@ const RoadmapModal = () => {
|
||||||
<DialogContent
|
<DialogContent
|
||||||
className="Roadmap"
|
className="Roadmap"
|
||||||
title={t('title')}
|
title={t('title')}
|
||||||
|
headerref={headerRef}
|
||||||
onOpenAutoFocus={(event) => event.preventDefault()}
|
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||||
onEscapeKeyDown={() => {}}
|
onEscapeKeyDown={() => {}}
|
||||||
>
|
>
|
||||||
<div>
|
<div className="DialogHeader" ref={headerRef}>
|
||||||
|
<DialogTitle className="DialogTitle">{t('title')}</DialogTitle>
|
||||||
|
<DialogClose className="DialogClose" asChild>
|
||||||
|
<span>
|
||||||
|
<CrossIcon />
|
||||||
|
</span>
|
||||||
|
</DialogClose>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="content">
|
||||||
<section className="notes">
|
<section className="notes">
|
||||||
<p>{t('blurb')}</p>
|
<p>{t('blurb')}</p>
|
||||||
<p>{t('link.intro')}</p>
|
<p>{t('link.intro')}</p>
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,10 @@ const WeaponModal = ({
|
||||||
const [ax2Open, setAx2Open] = useState(false)
|
const [ax2Open, setAx2Open] = useState(false)
|
||||||
const [awakeningOpen, setAwakeningOpen] = useState(false)
|
const [awakeningOpen, setAwakeningOpen] = useState(false)
|
||||||
|
|
||||||
|
// Refs
|
||||||
|
const headerRef = React.createRef<HTMLDivElement>()
|
||||||
|
const footerRef = React.createRef<HTMLDivElement>()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setOpen(modalOpen)
|
setOpen(modalOpen)
|
||||||
}, [modalOpen])
|
}, [modalOpen])
|
||||||
|
|
@ -350,10 +354,11 @@ const WeaponModal = ({
|
||||||
<DialogTrigger asChild>{children}</DialogTrigger>
|
<DialogTrigger asChild>{children}</DialogTrigger>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
className="Weapon"
|
className="Weapon"
|
||||||
|
headerref={headerRef}
|
||||||
onOpenAutoFocus={(event) => event.preventDefault()}
|
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||||
onEscapeKeyDown={onEscapeKeyDown}
|
onEscapeKeyDown={onEscapeKeyDown}
|
||||||
>
|
>
|
||||||
<div className="DialogHeader Short">
|
<div className="DialogHeader Short" ref={headerRef}>
|
||||||
<img
|
<img
|
||||||
alt={gridWeapon.object.name[locale]}
|
alt={gridWeapon.object.name[locale]}
|
||||||
className="DialogImage"
|
className="DialogImage"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue