diff --git a/packages/app/src/components/PagePanels/index.jsx b/packages/app/src/components/PagePanels/index.jsx new file mode 100644 index 00000000..f4dd415b --- /dev/null +++ b/packages/app/src/components/PagePanels/index.jsx @@ -0,0 +1,177 @@ +import React from "react" +import classnames from "classnames" +import * as antd from "antd" + +import { createIconRender } from "components/Icons" + +import "./index.less" + +export const Panel = (props) => { + return
+ {props.children} +
+} + +export class PagePanelWithNavMenu extends React.Component { + state = { + // if defaultTab is not set, try to get it from query, if not, use the first tab + activeTab: this.props.defaultTab ?? new URLSearchParams(window.location.search).get("type") ?? Object.keys(this.props.tabs)[0], + } + + primaryPanelRef = React.createRef() + + renderActiveTab() { + const tab = this.props.tabs[this.state.activeTab] + + if (!tab) { + if (this.props.onNotFound) { + return this.props.onNotFound() + } + + return + } + + return React.createElement(tab.component) + } + + replaceQueryTypeToCurrentTab = () => { + app.history.replace(`${window.location.pathname}?type=${this.state.activeTab}`) + } + + handleTabChange = async (key) => { + if (this.state.activeTab === key) return + + if (this.props.transition) { + // set to primary panel fade-opacity-leave class + this.primaryPanelRef.current.classList.add("fade-opacity-leave") + + // remove fade-opacity-leave class after animation + setTimeout(() => { + this.primaryPanelRef.current.classList.remove("fade-opacity-leave") + }, 300) + + await new Promise(resolve => setTimeout(resolve, 200)) + } + + if (this.props.onTabChange) { + this.props.onTabChange(key) + } + + this.setState({ activeTab: key }) + + if (this.props.useSetQueryType) { + this.replaceQueryTypeToCurrentTab() + } + } + + render() { + const panels = [ + { + children: + }, + { + props: { + ref: this.primaryPanelRef, + className: this.props.transition ? "fade-opacity-enter" : undefined, + }, + children: this.renderActiveTab() + }, + ] + + if (this.props.extraPanel) { + panels.push(this.props.extraPanel) + } + + return + } +} + +export default class PagePanels extends React.Component { + generateGridStyle = () => { + switch (this.props.panels.length) { + case 1: { + return { + gridTemplateColumns: "1fr", + } + } + case 2: { + return { + gridTemplateColumns: "1fr 3fr", + } + } + case 3: { + return { + gridTemplateColumns: "1fr 1fr 1fr", + } + } + } + } + + render() { + if (!this.props.panels) { + return null + } + + return
+ { + this.props.panels[0] && + } + { + this.props.panels[1] && + } + { + this.props.panels[2] && + } +
+ } +} \ No newline at end of file diff --git a/packages/app/src/components/PagePanels/index.less b/packages/app/src/components/PagePanels/index.less new file mode 100644 index 00000000..cbe5ca6b --- /dev/null +++ b/packages/app/src/components/PagePanels/index.less @@ -0,0 +1,82 @@ +.pagePanels { + display: grid; + + grid-template-columns: 1fr 1fr 1fr; + grid-template-rows: 1fr; + grid-column-gap: 20px; + grid-row-gap: 0px; + + width: 100%; + + .panel { + position: sticky; + top: 0; + + height: fit-content; + + display: flex; + flex-direction: column; + + align-items: center; + + &.full { + height: 100%; + } + + &.left { + .card { + background-color: var(--background-color-accent); + + .ant-menu { + .ant-menu-item-selected { + background-color: var(--background-color-primary) !important; + } + + .ant-menu-item-disabled { + .ant-menu-title-content { + svg { + color: var(--disabled-color) !important; + } + + color: var(--disabled-color) !important; + } + } + } + } + } + } + + .card { + display: flex; + flex-direction: column; + + background-color: var(--background-color-accent); + border-radius: 12px; + padding: 20px; + + margin-bottom: 20px; + width: 20vw; + + h1, + h2 { + width: fit-content; + margin: 0; + } + + .header { + display: flex; + flex-direction: row; + + justify-content: space-between; + align-items: center; + + width: 100%; + + margin-bottom: 10px; + } + } + + &.card:last-child { + margin-bottom: 0; + } +} \ No newline at end of file