Implement shadow on DialogHeader in static modals
This commit is contained in:
parent
16ed034b16
commit
baeaf4f73d
8 changed files with 108 additions and 35 deletions
|
|
@ -29,19 +29,10 @@ const AboutModal = () => {
|
|||
</DialogTrigger>
|
||||
<DialogContent
|
||||
className="About"
|
||||
title={t('menu.about')}
|
||||
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||
onEscapeKeyDown={() => {}}
|
||||
>
|
||||
<div className="DialogHeader">
|
||||
<DialogTitle className="DialogTitle">{t('menu.about')}</DialogTitle>
|
||||
<DialogClose className="DialogClose" asChild>
|
||||
<span>
|
||||
<CrossIcon />
|
||||
</span>
|
||||
</DialogClose>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="sections">
|
||||
<section>
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
.Changelog.DialogContent {
|
||||
gap: 0;
|
||||
padding-bottom: $unit-4x;
|
||||
|
||||
& > div:not(.DialogHeader) {
|
||||
padding: 0 $unit-4x;
|
||||
|
|
@ -30,6 +29,11 @@
|
|||
display: grid;
|
||||
grid-template-rows: 1fr auto;
|
||||
gap: $unit;
|
||||
|
||||
& > h4 {
|
||||
font-weight: $medium;
|
||||
font-size: $font-regular;
|
||||
}
|
||||
}
|
||||
|
||||
.items {
|
||||
|
|
@ -66,6 +70,7 @@
|
|||
|
||||
li {
|
||||
margin-bottom: $unit-half;
|
||||
font-size: $font-regular;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,20 +26,10 @@ const ChangelogModal = () => {
|
|||
</DialogTrigger>
|
||||
<DialogContent
|
||||
className="Changelog"
|
||||
title={t('menu.changelog')}
|
||||
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||
onEscapeKeyDown={() => {}}
|
||||
>
|
||||
<div className="DialogHeader">
|
||||
<DialogTitle className="DialogTitle">
|
||||
{t('menu.changelog')}
|
||||
</DialogTitle>
|
||||
<DialogClose className="DialogClose" asChild>
|
||||
<span>
|
||||
<CrossIcon />
|
||||
</span>
|
||||
</DialogClose>
|
||||
</div>
|
||||
|
||||
<div className="updates">
|
||||
<section className="version" data-version="1.0">
|
||||
<div className="top">
|
||||
|
|
|
|||
|
|
@ -81,17 +81,45 @@ const CharacterModal = ({
|
|||
|
||||
// UI state
|
||||
const [open, setOpen] = useState(false)
|
||||
const [scrolled, setScrolled] = useState(false)
|
||||
const [formValid, setFormValid] = useState(false)
|
||||
|
||||
// Classes
|
||||
const headerClasses = classNames({
|
||||
DialogHeader: true,
|
||||
Short: true,
|
||||
Scrolled: scrolled,
|
||||
})
|
||||
|
||||
// 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(() => {
|
||||
setOpen(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
|
||||
const [perpetuity, setPerpetuity] = useState(false)
|
||||
|
||||
|
|
|
|||
|
|
@ -49,8 +49,14 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.Scrollable {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.DialogHeader {
|
||||
background: var(--dialog-bg);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $unit-2x;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
import React from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import * as DialogPrimitive from '@radix-ui/react-dialog'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import './index.scss'
|
||||
import { DialogClose, DialogTitle } from '~components/Dialog'
|
||||
import Overlay from '~components/Overlay'
|
||||
|
||||
import CrossIcon from '~public/icons/Cross.svg'
|
||||
import './index.scss'
|
||||
|
||||
interface Props
|
||||
extends React.DetailedHTMLProps<
|
||||
React.DialogHTMLAttributes<HTMLDivElement>,
|
||||
HTMLDivElement
|
||||
> {
|
||||
header?: React.ReactNode
|
||||
title?: string
|
||||
onEscapeKeyDown: (event: KeyboardEvent) => void
|
||||
onOpenAutoFocus: (event: Event) => void
|
||||
}
|
||||
|
|
@ -18,10 +23,60 @@ const DialogContent = React.forwardRef<HTMLDivElement, Props>(function dialog(
|
|||
{ children, ...props },
|
||||
forwardedRef
|
||||
) {
|
||||
// Classes
|
||||
const classes = classNames(props.className, {
|
||||
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
|
||||
function handleScroll(event: React.UIEvent<HTMLDivElement, UIEvent>) {
|
||||
const headerElement = headerRef.current
|
||||
const scrollTop = event.currentTarget?.scrollTop
|
||||
const boxShadowBase = '0 2px 8px'
|
||||
const maxValue = 50
|
||||
|
||||
if (headerElement && scrollTop >= 0) {
|
||||
const input = scrollTop > maxValue ? maxValue : scrollTop
|
||||
|
||||
const boxShadowOpacity = mapRange(input, 0, maxValue, 0.0, 0.16)
|
||||
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})`
|
||||
headerElement.style.borderBottomColor = `rgba(0, 0, 0, ${borderOpacity})`
|
||||
}
|
||||
}
|
||||
|
||||
function mapRange(
|
||||
value: number,
|
||||
low1: number,
|
||||
high1: number,
|
||||
low2: number,
|
||||
high2: number
|
||||
) {
|
||||
return low2 + ((high2 - low2) * (value - low1)) / (high1 - low1)
|
||||
}
|
||||
|
||||
return (
|
||||
<DialogPrimitive.Portal>
|
||||
<dialog className="Dialog">
|
||||
|
|
@ -31,8 +86,15 @@ const DialogContent = React.forwardRef<HTMLDivElement, Props>(function dialog(
|
|||
onOpenAutoFocus={props.onOpenAutoFocus}
|
||||
onEscapeKeyDown={props.onEscapeKeyDown}
|
||||
ref={forwardedRef}
|
||||
>
|
||||
{props.title ? genericHeader : ''}
|
||||
<div
|
||||
className="Scrollable"
|
||||
ref={containerRef}
|
||||
onScroll={handleScroll}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</DialogPrimitive.Content>
|
||||
</dialog>
|
||||
<Overlay visible={true} open={true} />
|
||||
|
|
|
|||
|
|
@ -27,18 +27,10 @@ const RoadmapModal = () => {
|
|||
</DialogTrigger>
|
||||
<DialogContent
|
||||
className="Roadmap"
|
||||
title={t('title')}
|
||||
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||
onEscapeKeyDown={() => {}}
|
||||
>
|
||||
<div className="DialogHeader">
|
||||
<DialogTitle className="DialogTitle">{t('title')}</DialogTitle>
|
||||
<DialogClose className="DialogClose" asChild>
|
||||
<span>
|
||||
<CrossIcon />
|
||||
</span>
|
||||
</DialogClose>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<section className="notes">
|
||||
<p>{t('blurb')}</p>
|
||||
|
|
|
|||
|
|
@ -346,7 +346,6 @@ const WeaponModal = ({
|
|||
}
|
||||
|
||||
return (
|
||||
// TODO: Refactor into Dialog component
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
<DialogTrigger asChild>{children}</DialogTrigger>
|
||||
<DialogContent
|
||||
|
|
|
|||
Loading…
Reference in a new issue