mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 10:34:17 +00:00
rewrite draggable drawers
This commit is contained in:
parent
ddbdcab831
commit
d5c6a40208
@ -105,6 +105,7 @@
|
|||||||
"rxjs": "^7.5.5",
|
"rxjs": "^7.5.5",
|
||||||
"store": "^2.0.12",
|
"store": "^2.0.12",
|
||||||
"ua-parser-js": "^1.0.36",
|
"ua-parser-js": "^1.0.36",
|
||||||
|
"vaul": "^0.9.2",
|
||||||
"vite": "^5.2.11"
|
"vite": "^5.2.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -115,4 +116,4 @@
|
|||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"typescript": "^4.3.5"
|
"typescript": "^4.3.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
493
packages/app/src/layouts/components/draggableDrawer/index.jsx
Executable file → Normal file
493
packages/app/src/layouts/components/draggableDrawer/index.jsx
Executable file → Normal file
@ -1,16 +1,9 @@
|
|||||||
// © Jack Hanford https://github.com/hanford/react-drag-drawer
|
import React from "react"
|
||||||
import React, { Component } from "react"
|
import { Drawer } from "vaul"
|
||||||
import { createPortal } from "react-dom"
|
|
||||||
import { Motion, spring, presets } from "react-motion"
|
|
||||||
import classnames from "classnames"
|
|
||||||
import PropTypes from "prop-types"
|
|
||||||
import Observer from "react-intersection-observer"
|
|
||||||
import { css } from "@emotion/css"
|
|
||||||
|
|
||||||
import "./index.less"
|
import "./index.less"
|
||||||
|
|
||||||
// TODO: Finish me pleassse
|
export class DraggableDrawerController extends React.Component {
|
||||||
export class DraggableDrawerController extends Component {
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
@ -20,7 +13,7 @@ export class DraggableDrawerController extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
drawers: []
|
drawers: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,38 +21,59 @@ export class DraggableDrawerController extends Component {
|
|||||||
app.layout.draggable = this.interface
|
app.layout.draggable = this.interface
|
||||||
}
|
}
|
||||||
|
|
||||||
open = (id, render, options = {}) => {
|
async handleDrawerOnClosed(drawer) {
|
||||||
this.setState({
|
if (!drawer) {
|
||||||
drawers: [
|
return false
|
||||||
...this.state.drawers,
|
}
|
||||||
{
|
|
||||||
id: id,
|
if (typeof drawer.options.onClosed === "function") {
|
||||||
locked: options.defaultLocked ?? false,
|
await drawer.options.onClosed()
|
||||||
render: <DraggableDrawer
|
}
|
||||||
onRequestClose={this.close.bind(this, id)}
|
|
||||||
close={this.close.bind(this, id)}
|
this.destroy(drawer.id)
|
||||||
open={true}
|
|
||||||
destroyOnClose={true}
|
|
||||||
{...options.props ?? {}}
|
|
||||||
>
|
|
||||||
{React.createElement(render)}
|
|
||||||
</DraggableDrawer>,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close = (id) => {
|
open = (id, render, options = {}) => {
|
||||||
|
let drawerObj = {
|
||||||
|
id: id,
|
||||||
|
render: render,
|
||||||
|
options: options
|
||||||
|
}
|
||||||
|
|
||||||
|
const win = app.cores.window_mng.render(
|
||||||
|
id,
|
||||||
|
<DraggableDrawer
|
||||||
|
onClosed={() => this.handleDrawerOnClosed(drawerObj)}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
React.createElement(render, {
|
||||||
|
...options.componentProps,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</DraggableDrawer>
|
||||||
|
)
|
||||||
|
|
||||||
|
drawerObj.winId = win.id
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
drawers: [...this.state.drawers, drawerObj],
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy = (id) => {
|
||||||
const drawerIndex = this.state.drawers.findIndex((drawer) => drawer.id === id)
|
const drawerIndex = this.state.drawers.findIndex((drawer) => drawer.id === id)
|
||||||
|
|
||||||
if (drawerIndex === -1) {
|
if (drawerIndex === -1) {
|
||||||
console.error("Drawer not found")
|
console.error(`Drawer [${id}] not found`)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const drawer = this.state.drawers[drawerIndex]
|
const drawer = this.state.drawers[drawerIndex]
|
||||||
|
|
||||||
if (drawer.locked === true){
|
if (drawer.locked === true) {
|
||||||
|
console.error(`Drawer [${drawer.id}] is locked`)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,397 +82,58 @@ export class DraggableDrawerController extends Component {
|
|||||||
drawers.splice(drawerIndex, 1)
|
drawers.splice(drawerIndex, 1)
|
||||||
|
|
||||||
this.setState({ drawers: drawers })
|
this.setState({ drawers: drawers })
|
||||||
|
|
||||||
|
app.cores.window_mng.close(drawer.winId)
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return this.state.drawers.map((drawer) => drawer.render)
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class DraggableDrawer extends Component {
|
export const DraggableDrawer = (props) => {
|
||||||
static propTypes = {
|
const [isOpen, setIsOpen] = React.useState(true)
|
||||||
open: PropTypes.bool.isRequired,
|
|
||||||
children: PropTypes.oneOfType([
|
|
||||||
PropTypes.object,
|
|
||||||
PropTypes.array,
|
|
||||||
PropTypes.element
|
|
||||||
]),
|
|
||||||
onRequestClose: PropTypes.func,
|
|
||||||
onDrag: PropTypes.func,
|
|
||||||
onOpen: PropTypes.func,
|
|
||||||
inViewportChange: PropTypes.func,
|
|
||||||
allowClose: PropTypes.bool,
|
|
||||||
notifyWillClose: PropTypes.func,
|
|
||||||
modalElementClass: PropTypes.oneOfType([
|
|
||||||
PropTypes.object,
|
|
||||||
PropTypes.string
|
|
||||||
]),
|
|
||||||
containerOpacity: PropTypes.number,
|
|
||||||
getContainerRef: PropTypes.func,
|
|
||||||
getModalRef: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
static defaultProps = {
|
async function handleOnOpenChanged(to) {
|
||||||
notifyWillClose: () => { },
|
if (to === true) {
|
||||||
onOpen: () => { },
|
return to
|
||||||
onDrag: () => { },
|
|
||||||
inViewportChange: () => { },
|
|
||||||
onRequestClose: () => { },
|
|
||||||
getContainerRef: () => { },
|
|
||||||
getModalRef: () => { },
|
|
||||||
containerOpacity: 0.6,
|
|
||||||
parentElement: document.body,
|
|
||||||
allowClose: true,
|
|
||||||
dontApplyListeners: false,
|
|
||||||
modalElementClass: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
state = {
|
|
||||||
ignore: false,
|
|
||||||
onRange: false,
|
|
||||||
open: this.props.open,
|
|
||||||
thumb: 0,
|
|
||||||
start: 0,
|
|
||||||
position: 0,
|
|
||||||
touching: false,
|
|
||||||
listenersAttached: false,
|
|
||||||
useBackgroundColorValues: null,
|
|
||||||
}
|
|
||||||
|
|
||||||
DESKTOP_MODE = false
|
|
||||||
ALLOW_DRAWER_TRANSFORM = true
|
|
||||||
|
|
||||||
MAX_NEGATIVE_SCROLL = -50
|
|
||||||
PX_TO_CLOSE_FROM_BOTTOM = 200
|
|
||||||
|
|
||||||
interface = {
|
|
||||||
setBackgroundColorValues: (values) => {
|
|
||||||
this.setState({ useBackgroundColorValues: values })
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
app.currentDragger = this.interface
|
|
||||||
|
|
||||||
this.DESKTOP_MODE = !app.isMobile
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
delete app.currentDragger
|
|
||||||
|
|
||||||
this.removeListeners()
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps, nextState) {
|
|
||||||
// in the process of closing the drawer
|
|
||||||
if (!this.props.open && prevProps.open) {
|
|
||||||
this.removeListeners()
|
|
||||||
|
|
||||||
setTimeout(this.setState({ open: false }), 300)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.drawer) {
|
setIsOpen(false)
|
||||||
this.setNegativeScroll(this.drawer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// in the process of opening the drawer
|
if (typeof props.onClosed === "function") {
|
||||||
if (this.props.open && !prevProps.open) {
|
|
||||||
this.props.onOpen()
|
|
||||||
|
|
||||||
this.setState({ open: true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attachListeners = (drawer) => {
|
|
||||||
const { dontApplyListeners, getModalRef } = this.props
|
|
||||||
const { listenersAttached } = this.state
|
|
||||||
|
|
||||||
// only attach listeners once as this function gets called every re-render
|
|
||||||
if (!drawer || listenersAttached || dontApplyListeners) return
|
|
||||||
|
|
||||||
this.drawer = drawer
|
|
||||||
|
|
||||||
getModalRef(drawer)
|
|
||||||
|
|
||||||
this.drawer.addEventListener("touchend", this.release)
|
|
||||||
this.drawer.addEventListener("touchmove", this.drag)
|
|
||||||
this.drawer.addEventListener("touchstart", this.tap)
|
|
||||||
|
|
||||||
let position = 0
|
|
||||||
|
|
||||||
this.setState({ listenersAttached: true, position }, () => {
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// trigger reflow so webkit browsers calculate height properly 😔
|
props.onClosed()
|
||||||
// https://bugs.webkit.org/show_bug.cgi?id=184905
|
}, 350)
|
||||||
this.drawer.style.display = "none"
|
|
||||||
void this.drawer.offsetHeight
|
|
||||||
this.drawer.style.display = ""
|
|
||||||
}, 300)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
isThumbInDraggerRange = (event) => {
|
|
||||||
return (event.touches[0].clientY - this.drawer.getBoundingClientRect().top)
|
|
||||||
}
|
|
||||||
|
|
||||||
removeListeners = () => {
|
|
||||||
if (!this.drawer) {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.drawer.removeEventListener("touchend", this.release)
|
return to
|
||||||
this.drawer.removeEventListener("touchmove", this.drag)
|
|
||||||
this.drawer.removeEventListener("touchstart", this.tap)
|
|
||||||
|
|
||||||
this.setState({ listenersAttached: false })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tap = (event) => {
|
return <Drawer.Root
|
||||||
const { pageY } = event.touches[0]
|
open={isOpen}
|
||||||
|
onOpenChange={handleOnOpenChanged}
|
||||||
|
>
|
||||||
|
<Drawer.Portal>
|
||||||
|
<Drawer.Overlay
|
||||||
|
className="app-drawer-overlay"
|
||||||
|
/>
|
||||||
|
|
||||||
if (!this.isThumbInDraggerRange(event)) {
|
<Drawer.Content
|
||||||
return false
|
className="app-drawer-content"
|
||||||
}
|
onInteractOutside={() => {
|
||||||
|
setIsOpen(false)
|
||||||
const inDraggerArea = !!event.target.closest("#dragger-area")
|
|
||||||
|
|
||||||
const start = pageY
|
|
||||||
|
|
||||||
// reset NEW_POSITION and MOVING_POSITION
|
|
||||||
this.NEW_POSITION = 0
|
|
||||||
this.MOVING_POSITION = 0
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
ignore: !inDraggerArea,
|
|
||||||
onRange: this.isThumbInDraggerRange(event),
|
|
||||||
thumb: start,
|
|
||||||
start: start,
|
|
||||||
touching: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
drag = (event) => {
|
|
||||||
if (this.state.ignore) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
const { thumb, position } = this.state
|
|
||||||
const { pageY } = event.touches[0]
|
|
||||||
|
|
||||||
const movingPosition = pageY
|
|
||||||
const delta = movingPosition - thumb
|
|
||||||
const newPosition = position + delta
|
|
||||||
|
|
||||||
if (this.ALLOW_DRAWER_TRANSFORM) {
|
|
||||||
// allow to drag negative scroll
|
|
||||||
if (newPosition < this.MAX_NEGATIVE_SCROLL) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.onDrag({ newPosition })
|
|
||||||
|
|
||||||
this.MOVING_POSITION = movingPosition
|
|
||||||
this.NEW_POSITION = newPosition
|
|
||||||
|
|
||||||
if (this.shouldWeCloseDrawer()) {
|
|
||||||
this.props.notifyWillClose(true)
|
|
||||||
} else {
|
|
||||||
this.props.notifyWillClose(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
thumb: movingPosition,
|
|
||||||
position: newPosition,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
release = () => {
|
|
||||||
this.setState({ touching: false })
|
|
||||||
|
|
||||||
if (this.shouldWeCloseDrawer() && this.state.onRange) {
|
|
||||||
this.props.onRequestClose(this)
|
|
||||||
} else {
|
|
||||||
let newPosition = 0
|
|
||||||
|
|
||||||
this.setState({ position: newPosition })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setNegativeScroll = (element) => {
|
|
||||||
const size = this.getElementSize()
|
|
||||||
|
|
||||||
this.NEGATIVE_SCROLL = size - element.scrollHeight - this.MAX_NEGATIVE_SCROLL
|
|
||||||
}
|
|
||||||
|
|
||||||
hideDrawer = () => {
|
|
||||||
const { allowClose } = this.props
|
|
||||||
|
|
||||||
let defaultPosition = 0
|
|
||||||
|
|
||||||
if (allowClose === false) {
|
|
||||||
// if we aren't going to allow close, let's animate back to the default position
|
|
||||||
return this.setState({
|
|
||||||
position: defaultPosition,
|
|
||||||
thumb: 0,
|
|
||||||
touching: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
open: false,
|
|
||||||
position: defaultPosition,
|
|
||||||
touching: false
|
|
||||||
})
|
|
||||||
|
|
||||||
// cleanup
|
|
||||||
this.removeListeners()
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldWeCloseDrawer = () => {
|
|
||||||
if (this.MOVING_POSITION === 0) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const containerHeight = this.getElementSize()
|
|
||||||
const closeThreshold = containerHeight - this.PX_TO_CLOSE_FROM_BOTTOM
|
|
||||||
|
|
||||||
return (
|
|
||||||
this.NEW_POSITION >= 0 &&
|
|
||||||
this.MOVING_POSITION >= closeThreshold
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
getDrawerTransform = (value) => {
|
|
||||||
return { transform: `translate3d(0, ${value}px, 0)` }
|
|
||||||
}
|
|
||||||
|
|
||||||
getElementSize = () => {
|
|
||||||
return window.innerHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
getPosition() {
|
|
||||||
const { position } = this.state
|
|
||||||
|
|
||||||
return position
|
|
||||||
}
|
|
||||||
|
|
||||||
inViewportChange = (inView) => {
|
|
||||||
this.props.inViewportChange(inView)
|
|
||||||
|
|
||||||
this.ALLOW_DRAWER_TRANSFORM = inView
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickOutside = (event) => {
|
|
||||||
if (!this.props.allowClose) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if is clicking outside main component
|
|
||||||
if (this.drawer && event.target?.className) {
|
|
||||||
if (event.target.className.includes("ant-cascader") || event.target.className.includes("ant-select")) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.drawer.contains(event.target)) {
|
|
||||||
this.props.onRequestClose(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
preventDefault = (event) => event.preventDefault()
|
|
||||||
stopPropagation = (event) => event.stopPropagation()
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
containerOpacity,
|
|
||||||
id,
|
|
||||||
getContainerRef,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
const open = this.state.open && this.props.open
|
|
||||||
|
|
||||||
const { touching } = this.state
|
|
||||||
|
|
||||||
const springPreset = { damping: 20, stiffness: 300 }
|
|
||||||
const animationSpring = touching ? springPreset : presets.stiff
|
|
||||||
const hiddenPosition = this.getElementSize()
|
|
||||||
const position = this.getPosition(hiddenPosition)
|
|
||||||
|
|
||||||
let containerStyle = {
|
|
||||||
backgroundColor: `rgba(55, 56, 56, ${open ? containerOpacity : 0})`,
|
|
||||||
"--body-background": this.state.useBackgroundColorValues ? `rgba(${this.state.useBackgroundColorValues}, 1)` : "var(--background-color-primary)",
|
|
||||||
}
|
|
||||||
|
|
||||||
return createPortal(
|
|
||||||
<Motion
|
|
||||||
style={{
|
|
||||||
translate: spring(open ? position : hiddenPosition, animationSpring)
|
|
||||||
}}
|
|
||||||
defaultStyle={{
|
|
||||||
translate: hiddenPosition
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ translate }) => {
|
<Drawer.Handle
|
||||||
return (
|
className="app-drawer-handle"
|
||||||
<div
|
/>
|
||||||
id={id}
|
{
|
||||||
style={containerStyle}
|
React.cloneElement(props.children, {
|
||||||
onMouseDown={this.onClickOutside}
|
close: () => setIsOpen(false),
|
||||||
ref={getContainerRef}
|
})
|
||||||
className={classnames(
|
}
|
||||||
"draggable-drawer",
|
</Drawer.Content>
|
||||||
{
|
</Drawer.Portal>
|
||||||
["fill-end"]: this.props.fillEnd
|
</Drawer.Root>
|
||||||
}
|
}
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Observer
|
|
||||||
className={HaveWeScrolled}
|
|
||||||
onChange={this.inViewportChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className="draggable-drawer_body"
|
|
||||||
onClick={this.stopPropagation}
|
|
||||||
style={{
|
|
||||||
...this.props.bodyStyle,
|
|
||||||
...this.getDrawerTransform(translate),
|
|
||||||
}}
|
|
||||||
ref={this.attachListeners}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="dragger-area"
|
|
||||||
id="dragger-area"
|
|
||||||
dragger
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="dragger-indicator"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className="draggable-drawer_body_background"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="draggable-drawer_content">
|
|
||||||
{this.props.children}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</Motion>,
|
|
||||||
this.props.parentElement
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const HaveWeScrolled = css`
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
height: 1px;
|
|
||||||
width: 100%;
|
|
||||||
`
|
|
160
packages/app/src/layouts/components/draggableDrawer/index.less
Executable file → Normal file
160
packages/app/src/layouts/components/draggableDrawer/index.less
Executable file → Normal file
@ -1,146 +1,44 @@
|
|||||||
@body_border_radius: 24px;
|
.app-drawer-overlay {
|
||||||
|
position: fixed;
|
||||||
|
|
||||||
.draggable-drawer {
|
top: 0;
|
||||||
position: fixed;
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
top: 0;
|
z-index: 450;
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
|
|
||||||
display: flex;
|
background-color: rgba(var(--bg_color_1), 0.4);
|
||||||
justify-content: center;
|
backdrop-filter: blur(1px);
|
||||||
|
}
|
||||||
|
|
||||||
align-items: center;
|
.app-drawer-content {
|
||||||
|
position: fixed;
|
||||||
|
|
||||||
z-index: 50;
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
transition: background-color 0.2s linear;
|
z-index: 550;
|
||||||
|
|
||||||
overflow-y: hidden;
|
display: flex;
|
||||||
overscroll-behavior: none;
|
flex-direction: column;
|
||||||
|
|
||||||
box-sizing: border-box;
|
height: fit-content;
|
||||||
|
max-height: 90%;
|
||||||
|
min-height: 300px;
|
||||||
|
|
||||||
.draggable-drawer_body_background {
|
max-width: 550px;
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
position: absolute;
|
padding: 20px 10px 10px 10px;
|
||||||
|
|
||||||
z-index: 50;
|
gap: 10px;
|
||||||
|
|
||||||
top: 0;
|
border-radius: 24px 24px 0 0;
|
||||||
left: 0;
|
|
||||||
|
|
||||||
width: 100%;
|
background-color: var(--background-color-accent);
|
||||||
height: 100%;
|
}
|
||||||
|
|
||||||
border-top-left-radius: @body_border_radius;
|
.app-drawer-handle {
|
||||||
border-top-right-radius: @body_border_radius;
|
background-color: var(--background-color-contrast);
|
||||||
|
|
||||||
transition: all 150ms ease-in-out;
|
|
||||||
|
|
||||||
background-color: var(--body-background);
|
|
||||||
|
|
||||||
opacity: 0.4;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: "";
|
|
||||||
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
height: 120px;
|
|
||||||
|
|
||||||
z-index: 45;
|
|
||||||
|
|
||||||
background-color: var(--body-background);
|
|
||||||
|
|
||||||
transform: translateY(95%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.draggable-drawer_body {
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
z-index: 55;
|
|
||||||
|
|
||||||
bottom: 0px;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
max-width: 700px;
|
|
||||||
|
|
||||||
height: fit-content;
|
|
||||||
max-height: 90%;
|
|
||||||
|
|
||||||
background-color: var(--background-color-primary);
|
|
||||||
|
|
||||||
padding: 30px 10px 10px 10px;
|
|
||||||
|
|
||||||
border-top-left-radius: @body_border_radius;
|
|
||||||
border-top-right-radius: @body_border_radius;
|
|
||||||
|
|
||||||
.dragger-area {
|
|
||||||
width: 100%;
|
|
||||||
height: 50px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
top: 10px;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
z-index: 55;
|
|
||||||
|
|
||||||
.dragger-indicator {
|
|
||||||
background-color: var(--background-color-contrast);
|
|
||||||
|
|
||||||
width: 100px;
|
|
||||||
height: 8px;
|
|
||||||
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.draggable-drawer_content {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
z-index: 100;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: "";
|
|
||||||
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
height: 120px;
|
|
||||||
|
|
||||||
z-index: 45;
|
|
||||||
|
|
||||||
background-color: var(--background-color-primary);
|
|
||||||
|
|
||||||
transform: translateY(95%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user